feat attachment filename support utf8 (#3071)

This commit is contained in:
metal A-wing 2022-03-17 03:56:16 +00:00 committed by GitHub
parent 90330e2a76
commit 8860527de6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 2 deletions

View File

@ -6,7 +6,6 @@ package gin
import ( import (
"errors" "errors"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
@ -1018,7 +1017,11 @@ func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
// FileAttachment writes the specified file into the body stream in an efficient way // FileAttachment writes the specified file into the body stream in an efficient way
// On the client side, the file will typically be downloaded with the given filename // On the client side, the file will typically be downloaded with the given filename
func (c *Context) FileAttachment(filepath, filename string) { func (c *Context) FileAttachment(filepath, filename string) {
c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) if isASCII(filename) {
c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`)
} else {
c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
}
http.ServeFile(c.Writer, c.Request, filepath) http.ServeFile(c.Writer, c.Request, filepath)
} }

View File

@ -15,6 +15,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url"
"os" "os"
"reflect" "reflect"
"strings" "strings"
@ -1033,6 +1034,19 @@ func TestContextRenderAttachment(t *testing.T) {
assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.Header().Get("Content-Disposition")) assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.Header().Get("Content-Disposition"))
} }
func TestContextRenderUTF8Attachment(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
newFilename := "new🧡_filename.go"
c.Request, _ = http.NewRequest("GET", "/", nil)
c.FileAttachment("./gin.go", newFilename)
assert.Equal(t, 200, w.Code)
assert.Contains(t, w.Body.String(), "func New() *Engine {")
assert.Equal(t, `attachment; filename*=UTF-8''`+url.QueryEscape(newFilename), w.Header().Get("Content-Disposition"))
}
// TestContextRenderYAML tests that the response is serialized as YAML // TestContextRenderYAML tests that the response is serialized as YAML
// and Content-Type is set to application/x-yaml // and Content-Type is set to application/x-yaml
func TestContextRenderYAML(t *testing.T) { func TestContextRenderYAML(t *testing.T) {

View File

@ -12,6 +12,7 @@ import (
"reflect" "reflect"
"runtime" "runtime"
"strings" "strings"
"unicode"
) )
// BindKey indicates a default bind key. // BindKey indicates a default bind key.
@ -151,3 +152,13 @@ func resolveAddress(addr []string) string {
panic("too many parameters") panic("too many parameters")
} }
} }
// https://stackoverflow.com/questions/53069040/checking-a-string-contains-only-ascii-characters
func isASCII(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] > unicode.MaxASCII {
return false
}
}
return true
}

View File

@ -143,3 +143,8 @@ func TestMarshalXMLforH(t *testing.T) {
e := h.MarshalXML(enc, x) e := h.MarshalXML(enc, x)
assert.Error(t, e) assert.Error(t, e)
} }
func TestIsASCII(t *testing.T) {
assert.Equal(t, isASCII("test"), true)
assert.Equal(t, isASCII("🧡💛💚💙💜"), false)
}