// // rhimportd // // The Radio Helsinki Rivendell Import Daemon // // // Copyright (C) 2015-2016 Christian Pointner // // This file is part of rhimportd. // // rhimportd is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // rhimportd is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with rhimportd. If not, see . // package main import ( "code.helsinki.at/rhrd-go/rddb" "code.helsinki.at/rhrd-go/rhimport" "encoding/json" "io" "io/ioutil" "net/http" "os" "strings" ) type webUploadResponseData struct { ResponseCode int `json:"RESPONSE_CODE"` ErrorString string `json:"ERROR_STRING"` SourceFile string `json:"SOURCE_FILE"` } func webUploadErrorResponse(w http.ResponseWriter, code int, errStr string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) encoder := json.NewEncoder(w) respdata := webUploadResponseData{code, errStr, ""} encoder.Encode(respdata) } func webUploadResponse(w http.ResponseWriter, file string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) encoder := json.NewEncoder(w) respdata := webUploadResponseData{http.StatusOK, "success", file} encoder.Encode(respdata) } const ( webUploadMaxRequestSize = 2 << 30 // 2GB ) func webUploadHandler(conf *rhimport.Config, db *rddb.DBChan, sessions *rhimport.SessionStoreChan, trusted bool, w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { http.ServeFile(w, r, "./html/upload-form.html") // TODO: hardcoded html-dir... should we print the html directly? return } 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 ist to large: %d > %d", r.ContentLength, webUploadMaxRequestSize) webUploadErrorResponse(w, http.StatusExpectationFailed, "request too large") return } r.Body = http.MaxBytesReader(w, r.Body, webUploadMaxRequestSize) if err := r.ParseMultipartForm(32 << 10); err != nil { rhl.Printf("WebUploadHandler: error while parsing multi-part-form: %v", err) webUploadErrorResponse(w, http.StatusBadRequest, err.Error()) return } username := r.FormValue("LOGIN_NAME") password := r.FormValue("PASSWORD") if username == "" { webUploadErrorResponse(w, http.StatusBadRequest, "missing field LOGIN_NAME") return } if password == "" { webUploadErrorResponse(w, http.StatusBadRequest, "missing field LOGIN_NAME") return } if authenticated, err := db.CheckPassword(username, password); err != nil { rhl.Printf("WebUploadHandler: error checking username/password: %v", err) webUploadErrorResponse(w, http.StatusUnauthorized, err.Error()) return } else if !authenticated { rhl.Printf("WebUploadHandler: invalid username/password") webUploadErrorResponse(w, http.StatusUnauthorized, "invalid username/password") return } src, hdr, err := r.FormFile("FILENAME") if err != nil { rhdl.Printf("WebUploadHandler: error looking for upload file in form: %s", err) webUploadErrorResponse(w, http.StatusBadRequest, err.Error()) return } defer src.Close() rhl.Printf("WebUploadHandler: got request from user '%s', filename='%s'", username, hdr.Filename) // TODO: uploaded files should be deleted after some time... create directory with timestamp as part of the name? dstpath, err := ioutil.TempDir(conf.TempDir, "webupload-"+username+"-") if err != nil { rhl.Printf("WebUploadHandler: error creating temporary directory: %v", err) webUploadErrorResponse(w, http.StatusInternalServerError, err.Error()) return } dstfile := dstpath + "/" + hdr.Filename dst, err := os.OpenFile(dstfile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) if err != nil { rhl.Printf("WebUploadHandler: Unable to create file '%s': %v", dstfile, err) webUploadErrorResponse(w, http.StatusInternalServerError, err.Error()) return } defer dst.Close() io.Copy(dst, src) webUploadResponse(w, "tmp://"+strings.TrimPrefix(dstfile, conf.TempDir)) }