From ed3f73c9cb20bff3926080810682393f09a3b5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rokas=20Mikalk=C4=97nas?= Date: Thu, 8 Feb 2024 09:04:42 +0200 Subject: [PATCH] Allow to pass url as X-Sendfile header value --- plugin.go | 72 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/plugin.go b/plugin.go index 49443a0..b05c2c0 100644 --- a/plugin.go +++ b/plugin.go @@ -111,35 +111,57 @@ func (p *Plugin) Middleware(next http.Handler) http.Handler { } } - // do not allow paths like ../../resource, security - // only specified folder and resources in it - // see: https://lgtm.com/rules/1510366186013/ - if strings.Contains(path, "..") { - w.WriteHeader(http.StatusForbidden) - return - } + var f io.ReadCloser + var size int64 - // check if the file exists - fs, err := os.Stat(path) - if err != nil { - http.Error(w, "not found", http.StatusNotFound) - return - } + if strings.HasPrefix(path, "http") { + resp, err := http.Get(path) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } - f, err := os.OpenFile(path, os.O_RDONLY, 0) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + defer resp.Body.Close() - defer func() { - _ = f.Close() - }() + if resp.StatusCode != http.StatusOK { + http.Error(w, http.StatusText(resp.StatusCode), resp.StatusCode) + return + } + + f = resp.Body + size = resp.ContentLength + } else { + // do not allow paths like ../../resource, security + // only specified folder and resources in it + // see: https://lgtm.com/rules/1510366186013/ + if strings.Contains(path, "..") { + w.WriteHeader(http.StatusForbidden) + return + } + + // check if the file exists + fs, err := os.Stat(path) + if err != nil { + http.Error(w, "not found", http.StatusNotFound) + return + } + + f, err = os.OpenFile(path, os.O_RDONLY, 0) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + defer func() { + _ = f.Close() + }() + + size = fs.Size() + } - size := fs.Size() var buf []byte // do not allocate large buffer for the small files - if size < int64(bufSize) { + if size > 0 && size < int64(bufSize) { // allocate exact size buf = make([]byte, size) } else { @@ -147,9 +169,8 @@ func (p *Plugin) Middleware(next http.Handler) http.Handler { buf = make([]byte, bufSize) } - off := 0 for { - n, err := f.ReadAt(buf, int64(off)) + n, err := f.Read(buf) if err != nil { if errors.Is(err, io.EOF) { if n > 0 { @@ -176,7 +197,6 @@ func (p *Plugin) Middleware(next http.Handler) http.Handler { if f, ok := w.(http.Flusher); ok { f.Flush() } - off += n } w.Header().Set(ContentTypeKey, ContentTypeVal)