]> Cypherpunks repositories - gostls13.git/commitdiff
mime/multipart: add helper to build content-disposition header contents
authorLuca Maltagliati <lmalta95@gmail.com>
Wed, 12 Mar 2025 21:40:12 +0000 (21:40 +0000)
committerGopher Robot <gobot@golang.org>
Wed, 12 Mar 2025 23:20:01 +0000 (16:20 -0700)
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>

api/next/46771.txt [new file with mode: 0644]
doc/next/6-stdlib/99-minor/mime/multipart/46771.md [new file with mode: 0644]
src/mime/multipart/writer.go
src/mime/multipart/writer_test.go

diff --git a/api/next/46771.txt b/api/next/46771.txt
new file mode 100644 (file)
index 0000000..f7aad4b
--- /dev/null
@@ -0,0 +1 @@
+pkg mime/multipart, func FileContentDisposition(string, string) string #46771
diff --git a/doc/next/6-stdlib/99-minor/mime/multipart/46771.md b/doc/next/6-stdlib/99-minor/mime/multipart/46771.md
new file mode 100644 (file)
index 0000000..b8b8641
--- /dev/null
@@ -0,0 +1,2 @@
+The new helper function [FieldContentDisposition] builds multipart
+Content-Disposition header fields.
\ No newline at end of file
index 818970d7a7bcc9e1bad27f172bede2cbb6c5aba7..8806ab960b8f0ab3a92803393005ac2f4403cb1f 100644 (file)
@@ -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)
index 9e0f1314c98350d3d106df99594bda6675ca01f1..4af6d8c597d4329d6f4bf52d6498acd30fbc7f2f 100644 (file)
@@ -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)
+               }
+       }
+}