From 3bb7392f868b4c1307bd572fb48a9d083ed1fa08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Fri, 6 Sep 2024 21:17:27 +0200 Subject: [PATCH] legacy: implement files. --- server/internal/http/legacy/handler.go | 82 ++++++++++++++++++-------- server/internal/http/legacy/session.go | 40 +++++++------ 2 files changed, 82 insertions(+), 40 deletions(-) diff --git a/server/internal/http/legacy/handler.go b/server/internal/http/legacy/handler.go index 89ee0d9f..b61517c7 100644 --- a/server/internal/http/legacy/handler.go +++ b/server/internal/http/legacy/handler.go @@ -6,7 +6,7 @@ import ( "fmt" "io" "net/http" - "strconv" + "net/url" "time" "m1k1o/neko/internal/api" @@ -89,7 +89,7 @@ func (h *LegacyHandler) Route(r types.Router) { defer s.destroy() // dial to the remote backend - connBackend, _, err := DefaultDialer.Dial("ws://"+h.serverAddr+"/api/ws?token="+s.token, nil) + connBackend, _, err := DefaultDialer.Dial("ws://"+h.serverAddr+"/api/ws?token="+url.QueryEscape(s.token), nil) if err != nil { h.logger.Error().Err(err).Msg("couldn't dial to the remote backend") @@ -282,16 +282,65 @@ func (h *LegacyHandler) Route(r types.Router) { return utils.HttpUnauthorized().Msg("bad authorization") } - quality, err := strconv.Atoi(r.URL.Query().Get("quality")) - if err != nil { - quality = 90 - } - - w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - w.Header().Set("Content-Type", "image/jpeg") + quality := r.URL.Query().Get("quality") // get the screenshot - body, err := s.req(http.MethodGet, "/api/room/screen/shot.jpg?quality="+strconv.Itoa(quality), nil) + body, headers, err := s.req(http.MethodGet, "/api/room/screen/shot.jpg?quality="+url.QueryEscape(quality), nil, nil) + if err != nil { + return utils.HttpInternalServerError().WithInternalErr(err) + } + + // copy headers + w.Header().Set("Content-Length", headers.Get("Content-Length")) + w.Header().Set("Content-Type", headers.Get("Content-Type")) + + // copy the body to the response writer + _, err = io.Copy(w, body) + return err + }) + + // allow downloading and uploading files + r.Get("/file", func(w http.ResponseWriter, r *http.Request) error { + s := newSession(h.logger, h.serverAddr) + + // create a new session + username := r.URL.Query().Get("usr") + password := r.URL.Query().Get("pwd") + err := s.create(username, password) + if err != nil { + return utils.HttpForbidden(err.Error()) + } + defer s.destroy() + + filename := r.URL.Query().Get("filename") + + body, headers, err := s.req(http.MethodGet, "/api/filetransfer?filename="+url.QueryEscape(filename), r.Header, nil) + if err != nil { + return utils.HttpInternalServerError().WithInternalErr(err) + } + + // copy headers + w.Header().Set("Content-Length", headers.Get("Content-Length")) + w.Header().Set("Content-Type", headers.Get("Content-Type")) + + // copy the body to the response writer + _, err = io.Copy(w, body) + return err + }) + + r.Post("/file", func(w http.ResponseWriter, r *http.Request) error { + s := newSession(h.logger, h.serverAddr) + + // create a new session + username := r.URL.Query().Get("usr") + password := r.URL.Query().Get("pwd") + err := s.create(username, password) + if err != nil { + return utils.HttpForbidden(err.Error()) + } + defer s.destroy() + + body, _, err := s.req(http.MethodPost, "/api/filetransfer", r.Header, r.Body) if err != nil { return utils.HttpInternalServerError().WithInternalErr(err) } @@ -301,19 +350,6 @@ func (h *LegacyHandler) Route(r types.Router) { return err }) - /* - // allow downloading and uploading files - if webSocketHandler.FileTransferEnabled() { - r.Get("/file", func(w http.ResponseWriter, r *http.Request) error { - return nil - }) - - r.Post("/file", func(w http.ResponseWriter, r *http.Request) error { - return nil - }) - } - */ - r.Get("/health", func(w http.ResponseWriter, r *http.Request) error { _, err := w.Write([]byte("true")) return err diff --git a/server/internal/http/legacy/session.go b/server/internal/http/legacy/session.go index 191523be..f81c064d 100644 --- a/server/internal/http/legacy/session.go +++ b/server/internal/http/legacy/session.go @@ -57,26 +57,23 @@ func newSession(logger zerolog.Logger, serverAddr string) *session { } } -func (s *session) req(method, path string, request any) (io.ReadCloser, error) { - body, err := json.Marshal(request) +func (s *session) req(method, path string, headers http.Header, request io.Reader) (io.ReadCloser, http.Header, error) { + req, err := http.NewRequest(method, "http://"+s.serverAddr+path, request) if err != nil { - return nil, err + return nil, nil, err } - req, err := http.NewRequest(method, "http://"+s.serverAddr+path, bytes.NewReader(body)) - if err != nil { - return nil, err + for k, v := range headers { + req.Header[k] = v } - req.Header.Set("Content-Type", "application/json") - if s.token != "" { req.Header.Set("Authorization", "Bearer "+s.token) } res, err := s.client.Do(req) if err != nil { - return nil, err + return nil, nil, err } if res.StatusCode < 200 || res.StatusCode >= 300 { @@ -88,32 +85,41 @@ func (s *session) req(method, path string, request any) (io.ReadCloser, error) { Message string `json:"message"` } if err := json.Unmarshal(body, &apiErr); err == nil { - return nil, fmt.Errorf("%w: %s", ErrBackendRespone, apiErr.Message) + return nil, nil, fmt.Errorf("%w: %s", ErrBackendRespone, apiErr.Message) } // return raw body if failed to unmarshal - return nil, fmt.Errorf("unexpected status code: %d, body: %s", res.StatusCode, strings.TrimSpace(string(body))) + return nil, nil, fmt.Errorf("unexpected status code: %d, body: %s", res.StatusCode, strings.TrimSpace(string(body))) } - return res.Body, nil + return res.Body, res.Header, nil } func (s *session) apiReq(method, path string, request, response any) error { - body, err := s.req(method, path, request) + reqBody, err := json.Marshal(request) if err != nil { return err } - defer body.Close() - if body == nil { + headers := http.Header{ + "Content-Type": []string{"application/json"}, + } + + resBody, _, err := s.req(method, path, headers, bytes.NewReader(reqBody)) + if err != nil { + return err + } + defer resBody.Close() + + if resBody == nil { return nil } if response == nil { - io.Copy(io.Discard, body) + io.Copy(io.Discard, resBody) return nil } - return json.NewDecoder(body).Decode(response) + return json.NewDecoder(resBody).Decode(response) } // send message to client (in old format)