Skip to content

Commit 28cea1f

Browse files
jyxjjjcodex
andauthored
fix(proxy): preserve proxied download filenames (#2824)
- Override transparent proxy Content-Disposition with the OpenList object name - Add regression coverage for incorrect upstream download headers Signed-off-by: jyxjjj <16695261+jyxjjj@users.noreply.github.com> Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
1 parent 0a9e71a commit 28cea1f

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

‎server/common/proxy.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func Proxy(w http.ResponseWriter, r *http.Request, link *model.Link, file model.
5959
defer res.Body.Close()
6060

6161
maps.Copy(w.Header(), res.Header)
62+
w.Header().Set("Content-Disposition", utils.GenerateContentDisposition(file.GetName()))
6263
w.WriteHeader(res.StatusCode)
6364
if r.Method == http.MethodHead {
6465
return nil

‎server/common/proxy_test.go‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package common
2+
3+
import (
4+
"io"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/OpenListTeam/OpenList/v4/internal/conf"
10+
"github.com/OpenListTeam/OpenList/v4/internal/model"
11+
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
12+
)
13+
14+
func TestProxyOverridesUpstreamContentDisposition(t *testing.T) {
15+
previousConfig := conf.Conf
16+
conf.Conf = conf.DefaultConfig("data")
17+
t.Cleanup(func() {
18+
conf.Conf = previousConfig
19+
})
20+
21+
const content = "archive content"
22+
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
23+
w.Header().Set("Content-Disposition", `attachment; filename="download"`)
24+
w.Header().Set("Content-Type", "application/x-rar-compressed")
25+
w.WriteHeader(http.StatusOK)
26+
_, _ = io.WriteString(w, content)
27+
}))
28+
t.Cleanup(upstream.Close)
29+
30+
file := &model.Object{
31+
Name: "测试文件.rar",
32+
Size: int64(len(content)),
33+
}
34+
link := &model.Link{URL: upstream.URL}
35+
recorder := httptest.NewRecorder()
36+
request := httptest.NewRequest(http.MethodGet, "/sd/example", nil)
37+
38+
err := Proxy(recorder, request, link, file)
39+
if err != nil {
40+
t.Fatalf("Proxy() error = %v", err)
41+
}
42+
if got, want := recorder.Code, http.StatusOK; got != want {
43+
t.Fatalf("status code = %d, want %d", got, want)
44+
}
45+
if got, want := recorder.Header().Get("Content-Disposition"), utils.GenerateContentDisposition(file.GetName()); got != want {
46+
t.Errorf("Content-Disposition = %q, want %q", got, want)
47+
}
48+
if got, want := recorder.Header().Get("Content-Type"), "application/x-rar-compressed"; got != want {
49+
t.Errorf("Content-Type = %q, want %q", got, want)
50+
}
51+
if got, want := recorder.Body.String(), content; got != want {
52+
t.Errorf("body = %q, want %q", got, want)
53+
}
54+
}

0 commit comments

Comments
 (0)