Skip to content

Commit b8844f3

Browse files
fix(net/ghttp): attachment filename support utf8 (#4459)
1 parent 3e2176d commit b8844f3

File tree

5 files changed

+41
-1
lines changed

5 files changed

+41
-1
lines changed

internal/utils/utils_str.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package utils
99
import (
1010
"bytes"
1111
"strings"
12+
"unicode"
1213
)
1314

1415
// DefaultTrimChars are the characters which are stripped by Trim* functions in default.
@@ -167,3 +168,13 @@ func StripSlashes(str string) string {
167168
}
168169
return buf.String()
169170
}
171+
172+
// IsASCII checks whether given string is ASCII characters.
173+
func IsASCII(s string) bool {
174+
for i := 0; i < len(s); i++ {
175+
if s[i] > unicode.MaxASCII {
176+
return false
177+
}
178+
}
179+
return true
180+
}

internal/utils/utils_z_unit_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,13 @@ func Test_IsNumeric(t *testing.T) {
128128
t.Assert(utils.IsNumeric("+.1"), false)
129129
})
130130
}
131+
132+
func TestIsASCII(t *testing.T) {
133+
gtest.C(t, func(t *gtest.T) {
134+
t.AssertEQ(utils.IsASCII("test"), true)
135+
t.AssertEQ(utils.IsASCII("测试"), false)
136+
t.AssertEQ(utils.IsASCII("テスト"), false)
137+
t.AssertEQ(utils.IsASCII("테스트"), false)
138+
t.AssertEQ(utils.IsASCII("😁😭❤️😓"), false)
139+
})
140+
}

net/ghttp/ghttp_response.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"net/url"
1515
"time"
1616

17+
"github.com/gogf/gf/v2/internal/utils"
1718
"github.com/gogf/gf/v2/net/ghttp/internal/response"
1819
"github.com/gogf/gf/v2/net/gtrace"
1920
"github.com/gogf/gf/v2/os/gfile"
@@ -89,7 +90,12 @@ func (r *Response) ServeFileDownload(path string, name ...string) {
8990
}
9091
r.Header().Set("Content-Type", "application/force-download")
9192
r.Header().Set("Accept-Ranges", "bytes")
92-
r.Header().Set("Content-Disposition", fmt.Sprintf(`attachment;filename=%s`, url.QueryEscape(downloadName)))
93+
if utils.IsASCII(downloadName) {
94+
r.Header().Set("Content-Disposition", fmt.Sprintf(`attachment;filename=%s`, url.QueryEscape(downloadName)))
95+
} else {
96+
r.Header().Set("Content-Disposition", fmt.Sprintf(`attachment;filename*=UTF-8''%s`, url.QueryEscape(downloadName)))
97+
}
98+
9399
r.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
94100
r.Server.serveFile(r.Request, serveFile)
95101
}

net/ghttp/ghttp_z_unit_feature_response_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package ghttp_test
99
import (
1010
"fmt"
1111
"net/http"
12+
"net/url"
1213
"strings"
1314
"testing"
1415
"time"
@@ -81,6 +82,17 @@ func Test_Response_ServeFileDownload(t *testing.T) {
8182
client.GetContent(ctx, "/ServeFileDownload", "filePath=files/server.key"),
8283
"BEGIN RSA PRIVATE KEY"),
8384
true)
85+
86+
resp, err := client.Get(ctx, "/ServeFileDownload", "filePath="+srcPath)
87+
t.AssertNil(err)
88+
t.Assert(resp.ReadAllString(), "file1.txt: This file is for uploading unit test case.")
89+
t.Assert(resp.Header.Get("Content-Disposition"), "attachment;filename=file1.txt")
90+
91+
srcPath = gtest.DataPath("upload", "中文.txt")
92+
resp, err = client.Get(ctx, "/ServeFileDownload", "filePath="+srcPath)
93+
t.AssertNil(err)
94+
t.Assert(resp.ReadAllString(), "中文.txt: This file is for uploading unit test case.")
95+
t.Assert(resp.Header.Get("Content-Disposition"), "attachment;filename*=UTF-8''"+url.QueryEscape("中文.txt"))
8496
})
8597
}
8698

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
中文.txt: This file is for uploading unit test case.

0 commit comments

Comments
 (0)