From 4fb1e3313bd41d2c6a0a1934a74304ebe6c702e9 Mon Sep 17 00:00:00 2001 From: unwox Date: Thu, 4 Sep 2025 19:50:47 +0600 Subject: implement parsing forms --- worker.go | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 18 deletions(-) (limited to 'worker.go') diff --git a/worker.go b/worker.go index baf85ff..52e3c46 100644 --- a/worker.go +++ b/worker.go @@ -5,6 +5,8 @@ import ( "io" "log" "net/http" + "os" + "strings" "sync" ) @@ -125,47 +127,115 @@ func (w *Worker) Listen(queue chan *HTTPRequest) { defer w.lua.Unref(ref) if _, ok := w.routes[r.route]; !ok { - r.result <- &HTTPResponse { + r.result <- &HTTPResponse{ Code: 404, Headers: make(map[string]string), Body: "not found", } - log.Println("no corresponding route") return } l.PushTracebackHandler() l.PushFromRef(w.routes[r.route]) + req := r.request res := make(map[string]any) - res["method"] = r.request.Method - res["path"] = r.request.URL.Path + res["method"] = req.Method + res["path"] = req.URL.Path fh := make(map[string]any) - for k := range r.request.Header { - fh[k] = r.request.Header.Get(k) + for k := range req.Header { + fh[k] = req.Header.Get(k) } res["headers"] = fh flatQr := make(map[string]any) - qr := r.request.URL.Query() + qr := req.URL.Query() for k := range qr { flatQr[k] = stringListToAny(qr[k]) } res["query"] = flatQr - body, err := io.ReadAll(r.request.Body) - if err != nil { - r.result <- &HTTPResponse{ - Code: 500, - Headers: make(map[string]string), - Body: "server error", + // if request body is a multipart form: automatically parse it, + // save the files and form values and put them in to the + // request object in the "form" field + // in all other cases just put the body as a string in the + // "body" field + if strings.HasPrefix( + req.Header.Get("Content-Type"), + "multipart/form-data", + ) { + err := req.ParseMultipartForm(0) + if err != nil { + r.result <- &HTTPResponse{ + Code: 400, + Headers: make(map[string]string), + Body: "bad multipart request", + } + return } - log.Println("could not read request body:", err) - return + + form := make(map[string]any) + for k, v := range req.MultipartForm.File { + // for now only take the first value + fh := v[0] + if fh == nil { + continue + } + fd, err := fh.Open() + defer fd.Close() + if err != nil { + r.result <- &HTTPResponse{ + Code: 500, + Headers: make(map[string]string), + Body: "server error", + } + log.Println("could not open multipart file:", err) + return + } + + // assume fd is a file stored on the filesystem. + // if it's not the case: write the file from + // memory to the filesystem. + f, ok := fd.(*os.File) + if !ok { + f, _ = os.CreateTemp(os.TempDir(), "multipart-") + buf := make([]byte, 8192) + for { + nread, _ := fd.Read(buf) + _, _ = f.Write(buf) + if nread < 8192 { + break + } + } + f.Close() + defer os.Remove(f.Name()) + } + record := make(map[string]any) + record["path"] = f.Name() + record["size"] = fh.Size + record["name"] = fh.Filename + form[k] = record + } + for k, v := range req.MultipartForm.Value { + // for now only take the first value + form[k] = v[0] + } + res["form"] = form + } else { + body, err := io.ReadAll(req.Body) + if err != nil { + r.result <- &HTTPResponse{ + Code: 500, + Headers: make(map[string]string), + Body: "server error", + } + log.Println("could not read request body:", err) + return + } + res["body"] = string(body) } - res["body"] = string(body) - err = l.PushObject(res) + err := l.PushObject(res) if err != nil { r.result <- &HTTPResponse{ Code: 500, @@ -203,7 +273,7 @@ func (w *Worker) Listen(queue chan *HTTPRequest) { l.Pop(1) l.PushNil() for l.Next() { - if !l.IsString(-2) || !l.IsString(-2) { + if !l.IsString(-2) || !l.IsString(-1) { l.Pop(1) continue } -- cgit v1.2.3