aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca Maltagliati <lmalta95@gmail.com>2025-03-12 21:40:12 +0000
committerGopher Robot <gobot@golang.org>2025-03-12 16:20:01 -0700
commitd729053edffdfb17ee947cee8af0d7edc45f6111 (patch)
treeb5b2d20ca584c20e4207323517b6676126359f10 /src
parenta68bf75d3402412a1946fe1df67f57ca923f1507 (diff)
downloadgo-d729053edffdfb17ee947cee8af0d7edc45f6111.tar.xz
mime/multipart: add helper to build content-disposition header contents
This PR adds an helper FileContentDisposition that builds multipart Content-Disposition header contents with field name and file name, escaping quotes and escape characters. The function is then called in the related helper CreateFormFile. The new function allows users to add other custom MIMEHeaders, without having to rewrite the char escaping logic of field name and file name, which is provided by the new helper. Fixes #46771 Change-Id: Ifc82a79583feb6dd609ca1e6024e612fb58c05ce GitHub-Last-Rev: 969f846fa967d2b3eca7a21ee096b299b8a94546 GitHub-Pull-Request: golang/go#63324 Reviewed-on: https://go-review.googlesource.com/c/go/+/531995 Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/mime/multipart/writer.go11
-rw-r--r--src/mime/multipart/writer_test.go19
2 files changed, 27 insertions, 3 deletions
diff --git a/src/mime/multipart/writer.go b/src/mime/multipart/writer.go
index 818970d7a7..8806ab960b 100644
--- a/src/mime/multipart/writer.go
+++ b/src/mime/multipart/writer.go
@@ -135,9 +135,7 @@ func escapeQuotes(s string) string {
// a new form-data header with the provided field name and file name.
func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) {
h := make(textproto.MIMEHeader)
- h.Set("Content-Disposition",
- fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
- escapeQuotes(fieldname), escapeQuotes(filename)))
+ h.Set("Content-Disposition", FileContentDisposition(fieldname, filename))
h.Set("Content-Type", "application/octet-stream")
return w.CreatePart(h)
}
@@ -151,6 +149,13 @@ func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) {
return w.CreatePart(h)
}
+// FileContentDisposition returns the value of a Content-Disposition header
+// with the provided field name and file name.
+func FileContentDisposition(fieldname, filename string) string {
+ return fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
+ escapeQuotes(fieldname), escapeQuotes(filename))
+}
+
// WriteField calls [Writer.CreateFormField] and then writes the given value.
func (w *Writer) WriteField(fieldname, value string) error {
p, err := w.CreateFormField(fieldname)
diff --git a/src/mime/multipart/writer_test.go b/src/mime/multipart/writer_test.go
index 9e0f1314c9..4af6d8c597 100644
--- a/src/mime/multipart/writer_test.go
+++ b/src/mime/multipart/writer_test.go
@@ -172,3 +172,22 @@ func TestSortedHeader(t *testing.T) {
t.Fatalf("\n got: %q\nwant: %q\n", buf.String(), want)
}
}
+
+func TestFileContentDisposition(t *testing.T) {
+ tests := []struct {
+ fieldname string
+ filename string
+ want string
+ }{
+ {"somefield", "somefile.txt", `form-data; name="somefield"; filename="somefile.txt"`},
+ {`field"withquotes"`, "somefile.txt", `form-data; name="field\"withquotes\""; filename="somefile.txt"`},
+ {`somefield`, `somefile"withquotes".txt`, `form-data; name="somefield"; filename="somefile\"withquotes\".txt"`},
+ {`somefield\withbackslash`, "somefile.txt", `form-data; name="somefield\\withbackslash"; filename="somefile.txt"`},
+ {"somefield", `somefile\withbackslash.txt`, `form-data; name="somefield"; filename="somefile\\withbackslash.txt"`},
+ }
+ for i, tt := range tests {
+ if found := FileContentDisposition(tt.fieldname, tt.filename); found != tt.want {
+ t.Errorf(`%d. found: "%s"; want: "%s"`, i, found, tt.want)
+ }
+ }
+}