Newbie here. I'm trying to build a web server with a RESTful API so that I can test a curl command for file uploads. I was able to create the web server and an endpoint for file uploads.
Here is my upload endpoint:
func Upload(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(MAX_MEMORY); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusForbidden)
}
fmt.Println("Endpoint hit: Upload")
for key, value := range r.MultipartForm.Value {
fmt.Fprintf(w, "%s:%s ", key, value)
log.Printf("%s:%s", key, value)
}
for _, fileHeaders := range r.MultipartForm.File {
for _, fileHeader := range fileHeaders {
file, _ := fileHeader.Open()
path := fmt.Sprintf("files/%s", fileHeader.Filename)
buf, _ := ioutil.ReadAll(file)
ioutil.WriteFile(path, buf, os.ModePerm)
log.Println(http.StatusOK, fmt.Sprintf("file %s has been uploaded", fileHeader.Filename))
}
}
}
This endpoint works with the following curl command:
curl -F 'data=@/path/to/file/foo.tar.gz' localhost:8080/upload
However, this curl command does not:
curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload
curl: (22) The requested URL returned error: 405 Method Not Allowed
I need help creating an endpoint that will accept
curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload
Thank you.
Edit: Here is my routes.go file.
package main
import (
"net/http"
"github.com/gorilla/mux"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes []Route
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(route.HandlerFunc)
}
return router
}
var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
Route{
"Upload",
"POST",
"/upload",
Upload,
},
}
Using curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload
without any additional options that would set the content type, if there are such options (i'm not sure, my curl knowledge is almost non existent), you are sending a request with minimal headers, none of them indicating the type of the content.
For example logging the r.Header
will print something like this:
map[Accept:[*/*] Content-Length:[18] Expect:[100-continue] User-Agent:[curl/7.54.0]]
This means that all that multipart code in your Upload
handler is simply not necessary.
The content of the body is what you want, so you can use io.Copy
to store that body into a file.
func Upload(w http.ResponseWriter, r *http.Request) {
f, err := os.Create("filename")
if err != nil {
panic(err)
}
defer f.Close()
if _, err := io.Copy(f, r.Body); err != nil {
panic(err)
}
if err := f.Sync(); err != nil {
panic(err)
}
fmt.Fprintln(w, "upload done...")
}
Since you're using curl -f -s -S -T ...
the Upload
handler does not know what the name, nor the type, of the file being uploaded is, you will have to generate a random name, or a timestamp name, or whatever in order to be able to create and store more than just one file.
You could also pass some of the file info (name, type) in the query parameters but i'm not sure if that satisfies your requirements. E.g.
curl -f -s -S -T /path/to/file/foo.tar.gz http://localhost:8080/upload?name=foo.tar.gz