]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: add a test to verify form tempfiles are deleted
authorDamien Neil <dneil@google.com>
Thu, 11 Aug 2022 22:56:34 +0000 (15:56 -0700)
committerDamien Neil <dneil@google.com>
Fri, 12 Aug 2022 17:25:47 +0000 (17:25 +0000)
The HTTP/1 server deletes multipart form tempfiles after ServeHTTP
returns, but the HTTP/2 server does not. Add a test to verify
cleanup happens in both cases, temporarily disabled for the
HTTP/2 path.

For #20253
Updates #25965

Change-Id: Ib753f2761fe73b29321d9d4337dbb5090fd193c2
Reviewed-on: https://go-review.googlesource.com/c/go/+/423194
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Damien Neil <dneil@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/net/http/serve_test.go

index cb6312d6412118d629babb18584b6c76606fb13a..f956e66c44d44c69928a0e10479a6aa8b0b575af 100644 (file)
@@ -20,6 +20,7 @@ import (
        "io"
        "log"
        "math/rand"
+       "mime/multipart"
        "net"
        . "net/http"
        "net/http/httptest"
@@ -6758,3 +6759,68 @@ func TestProcessing(t *testing.T) {
                t.Errorf("unexpected response; got %q; should start by %q", got, expected)
        }
 }
+
+func TestParseFormCleanup_h1(t *testing.T) { testParseFormCleanup(t, h1Mode) }
+func TestParseFormCleanup_h2(t *testing.T) {
+       t.Skip("https://go.dev/issue/20253")
+       testParseFormCleanup(t, h2Mode)
+}
+
+func testParseFormCleanup(t *testing.T, h2 bool) {
+       const maxMemory = 1024
+       const key = "file"
+
+       if runtime.GOOS == "windows" {
+               // Windows sometimes refuses to remove a file that was just closed.
+               t.Skip("https://go.dev/issue/25965")
+       }
+
+       setParallel(t)
+       defer afterTest(t)
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               r.ParseMultipartForm(maxMemory)
+               f, _, err := r.FormFile(key)
+               if err != nil {
+                       t.Errorf("r.FormFile(%q) = %v", key, err)
+                       return
+               }
+               of, ok := f.(*os.File)
+               if !ok {
+                       t.Errorf("r.FormFile(%q) returned type %T, want *os.File", key, f)
+                       return
+               }
+               w.Write([]byte(of.Name()))
+       }))
+       defer cst.close()
+
+       fBuf := new(bytes.Buffer)
+       mw := multipart.NewWriter(fBuf)
+       mf, err := mw.CreateFormFile(key, "myfile.txt")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if _, err := mf.Write(bytes.Repeat([]byte("A"), maxMemory*2)); err != nil {
+               t.Fatal(err)
+       }
+       if err := mw.Close(); err != nil {
+               t.Fatal(err)
+       }
+       req, err := NewRequest("POST", cst.ts.URL, fBuf)
+       if err != nil {
+               t.Fatal(err)
+       }
+       req.Header.Set("Content-Type", mw.FormDataContentType())
+       res, err := cst.c.Do(req)
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer res.Body.Close()
+       fname, err := io.ReadAll(res.Body)
+       if err != nil {
+               t.Fatal(err)
+       }
+       cst.close()
+       if _, err := os.Stat(string(fname)); !errors.Is(err, os.ErrNotExist) {
+               t.Errorf("file %q exists after HTTP handler returned", string(fname))
+       }
+}