summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunwox <me@unwox.com>2025-09-04 19:50:47 +0600
committerunwox <me@unwox.com>2025-09-04 19:50:47 +0600
commit4fb1e3313bd41d2c6a0a1934a74304ebe6c702e9 (patch)
treed7500c070b75bc5ce435002b943bee92ba946653
parent0cd409fe6671f045f4c7931506dc5fd42a5a400c (diff)
implement parsing forms
-rw-r--r--worker.go106
1 files changed, 88 insertions, 18 deletions
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
}