diff options
author | Christian Pointner <equinox@helsinki.at> | 2016-07-23 16:34:39 (GMT) |
---|---|---|
committer | Christian Pointner <equinox@helsinki.at> | 2016-07-23 16:34:39 (GMT) |
commit | bb9497361b566884a1e4cb6d76a6f539383bd32c (patch) | |
tree | d8dbf2a8fa4e98258ebe5aa6fb36f8e72e018d66 | |
parent | 2f2d09ea5aa99f1c80b12fc4e088ffc2248d690b (diff) |
greatly simplified web uploads
-rw-r--r-- | src/rhimportd/routeWeb.go | 2 | ||||
-rw-r--r-- | src/rhimportd/uploadWeb.go | 93 | ||||
-rw-r--r-- | web-static/socket.html | 4 | ||||
-rw-r--r-- | web-static/upload.html | 11 |
4 files changed, 22 insertions, 88 deletions
diff --git a/src/rhimportd/routeWeb.go b/src/rhimportd/routeWeb.go index 22db1d7..d0582a2 100644 --- a/src/rhimportd/routeWeb.go +++ b/src/rhimportd/routeWeb.go @@ -50,7 +50,7 @@ func StartWebRouter(addr, staticDir string, conf *rhimport.Config, db *rddb.DBCh // http.Handle("/trusted/simple", webHandler{conf, db, sessions, true, webSimpleHandler}) http.Handle("/public/simple", webHandler{conf, db, sessions, false, webSimpleHandler}) http.Handle("/public/socket", webHandler{conf, db, sessions, false, webSocketHandler}) - http.Handle("/public/upload", webHandler{conf, db, sessions, false, webUploadHandler}) + http.Handle("/public/upload/", http.StripPrefix("/public/upload/", webHandler{conf, db, sessions, false, webUploadHandler})) rhl.Println("web-router: listening on", addr) server := &http.Server{Addr: addr, ReadTimeout: 2 * time.Hour, WriteTimeout: 2 * time.Hour} diff --git a/src/rhimportd/uploadWeb.go b/src/rhimportd/uploadWeb.go index 84605e6..9d16e92 100644 --- a/src/rhimportd/uploadWeb.go +++ b/src/rhimportd/uploadWeb.go @@ -25,11 +25,10 @@ package main import ( - "bytes" "encoding/json" "io" - "mime/multipart" "net/http" + "strings" "code.helsinki.at/rhrd-go/rddb" "code.helsinki.at/rhrd-go/rhimport" @@ -56,107 +55,45 @@ func webUploadSuccessResponse(w http.ResponseWriter) { encoder.Encode(respdata) } -const ( - webUploadMaxRequestSize = (2 << 30) - 1 // 2GB, (2 << 30) overflows int on 32-bit systems therefore we use 2GB - 1 Byte -) - -func webUploadParseForm(r *http.Request) (username, sessionid, srcfile string, src *multipart.Part, err error) { - var mpr *multipart.Reader - if mpr, err = r.MultipartReader(); err != nil { - return - } - - for { - var p *multipart.Part - if p, err = mpr.NextPart(); err != nil { - if err == io.EOF { - err = nil - } - return - } - var dstfield *string - switch p.FormName() { - case "LOGIN_NAME": - dstfield = &username - case "SESSION_ID": - dstfield = &sessionid - case "FILENAME": - srcfile = p.FileName() - src = p - return // don't read any fields beyond this point because we would need to load the whole file in order to continue parsing - default: - rhdl.Printf("WebUploadHandler: ingoring unknown form field: '%s'", p.FormName()) - continue - } - - var buf bytes.Buffer - if _, err = io.CopyN(&buf, p, 1<<10); err != nil && err != io.EOF { // 1kB should be enough - return - } - *dstfield = buf.String() - p.Close() - } -} - func webUploadHandler(conf *rhimport.Config, db *rddb.DBChan, sessions *rhimport.SessionStoreChan, trusted bool, w http.ResponseWriter, r *http.Request) { - if r.Method == "GET" { - http.Redirect(w, r, "/static/upload.html", http.StatusTemporaryRedirect) - return - } + rhdl.Printf("WebUploadHandler: got request for %s", r.URL.String()) if r.Method != "POST" { rhl.Printf("WebUploadHandler: got invalid request method") - webUploadErrorResponse(w, http.StatusMethodNotAllowed, "only POST and GET method are allowed") - return - } - - // This is from: stackoverflow.com/questions/26392196 - if r.ContentLength > webUploadMaxRequestSize { - rhl.Printf("WebUploadHandler: request is too large: %d > %d", r.ContentLength, webUploadMaxRequestSize) - webUploadErrorResponse(w, http.StatusExpectationFailed, "request too large") + webUploadErrorResponse(w, http.StatusMethodNotAllowed, "only POST method is allowed") return } - r.Body = http.MaxBytesReader(w, r.Body, webUploadMaxRequestSize) - username, sessionid, srcfile, src, err := webUploadParseForm(r) - if err != nil { - rhl.Printf("WebUploadHandler: error while parsing multipart-form: %v", err) - webUploadErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - if username == "" { - webUploadErrorResponse(w, http.StatusBadRequest, "missing field LOGIN_NAME") - return - } - if sessionid == "" { - webUploadErrorResponse(w, http.StatusBadRequest, "missing field SESSION_ID") - return - } - if srcfile == "" || src == nil { - webUploadErrorResponse(w, http.StatusBadRequest, "missing field FILENAME") + parts := strings.SplitN(r.URL.String(), "/", 2) + if len(parts) != 2 { + rhl.Printf("WebUploadHandler: got invalid request url") + webUploadErrorResponse(w, http.StatusBadRequest, "invalid request URL, should be <username>/<sessionid>") return } + username := parts[0] + sessionid := parts[1] s, _, code, _ := sessions.Get(username, sessionid) if code != http.StatusOK { + rhl.Printf("WebUploadHandler: refusing file upload for '%s/%s': session not found", username, sessionid) webUploadErrorResponse(w, http.StatusUnauthorized, "session not found") return } cancel, attachmentChan := s.AttachUploader() if attachmentChan == nil || cancel == nil { - rhl.Printf("WebUploadHandler: refusing file upload for '%s': session already uploading", srcfile) + rhl.Printf("WebUploadHandler: refusing file upload for '%s/%s': session already uploading", username, sessionid) webUploadErrorResponse(w, http.StatusForbidden, "upload already in progress") return } defer close(attachmentChan) - rhl.Printf("WebUploadHandler: starting upload for file '%s'", srcfile) + rhl.Printf("WebUploadHandler: starting file upload for '%s/%s'", username, sessionid) for { chunk := rhimport.AttachmentChunk{} var data [128 * 1024]byte - n, err := src.Read(data[:]) + n, err := r.Body.Read(data[:]) if n > 0 { chunk.Data = data[:n] if err == io.EOF { @@ -165,14 +102,14 @@ func webUploadHandler(conf *rhimport.Config, db *rddb.DBChan, sessions *rhimport } chunk.Error = err if err == io.EOF { - rhl.Printf("WebUploadHandler: upload for file '%s' finished", srcfile) + rhl.Printf("WebUploadHandler: file upload for '%s/%s' finished", username, sessionid) webUploadSuccessResponse(w) return } select { case <-cancel: - rhl.Printf("WebUploadHandler: upload for file '%s' got canceld", srcfile) + rhl.Printf("WebUploadHandler: file upload for '%s/%s' got canceld", username, sessionid) webUploadErrorResponse(w, http.StatusNoContent, "canceled") return case attachmentChan <- chunk: diff --git a/web-static/socket.html b/web-static/socket.html index 9781e81..6d6236c 100644 --- a/web-static/socket.html +++ b/web-static/socket.html @@ -66,8 +66,10 @@ $('#rawmsg').text(""); this.sock = new WebSocket("ws://localhost:4080/public/socket"); this.sock_onmessage = function (event) { - $('#rawmsg').append(event.data + "\n"); msg = $.parseJSON(event.data) + if (msg.TYPE != "progress") { + $('#rawmsg').append(event.data + "<br />\n"); + } switch (msg.TYPE) { case "ack": $('#sessionid').val(msg.ID); diff --git a/web-static/upload.html b/web-static/upload.html index 39cfa57..21d1c48 100644 --- a/web-static/upload.html +++ b/web-static/upload.html @@ -26,21 +26,16 @@ function upload() { $('#buttonupload').attr('disabled','disabled'); - var cmdData = new FormData(); - cmdData.append("LOGIN_NAME", $('#username').val()); - cmdData.append("SESSION_ID", $('#sessionid').val()); - cmdData.append("FILENAME", $('#file').get(0).files[0]); var command = { type: "POST", - contentType: false, + contentType: "application/octet-stream", + data: $('#file').get(0).files[0], processData: false, - data: cmdData, dataType: 'json', error: function(req, status, err) { result({StatusText: status, ErrorString: err}); }, success: function(data, status, req) { result(data); } }; - $.ajax('/public/upload', command); - + $.ajax('/public/upload/' + $('#username').val() + '/' + $('#sessionid').val(), command); } function result(data) { |