Skip to content

Commit ebbf2b4

Browse files
committed
net/http: add a test to verify form tempfiles are deleted
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 <[email protected]> Run-TryBot: Damien Neil <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent f3c39a8 commit ebbf2b4

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

src/net/http/serve_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"io"
2121
"log"
2222
"math/rand"
23+
"mime/multipart"
2324
"net"
2425
. "net/http"
2526
"net/http/httptest"
@@ -6758,3 +6759,68 @@ func TestProcessing(t *testing.T) {
67586759
t.Errorf("unexpected response; got %q; should start by %q", got, expected)
67596760
}
67606761
}
6762+
6763+
func TestParseFormCleanup_h1(t *testing.T) { testParseFormCleanup(t, h1Mode) }
6764+
func TestParseFormCleanup_h2(t *testing.T) {
6765+
t.Skip("https://go.dev/issue/20253")
6766+
testParseFormCleanup(t, h2Mode)
6767+
}
6768+
6769+
func testParseFormCleanup(t *testing.T, h2 bool) {
6770+
const maxMemory = 1024
6771+
const key = "file"
6772+
6773+
if runtime.GOOS == "windows" {
6774+
// Windows sometimes refuses to remove a file that was just closed.
6775+
t.Skip("https://go.dev/issue/25965")
6776+
}
6777+
6778+
setParallel(t)
6779+
defer afterTest(t)
6780+
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
6781+
r.ParseMultipartForm(maxMemory)
6782+
f, _, err := r.FormFile(key)
6783+
if err != nil {
6784+
t.Errorf("r.FormFile(%q) = %v", key, err)
6785+
return
6786+
}
6787+
of, ok := f.(*os.File)
6788+
if !ok {
6789+
t.Errorf("r.FormFile(%q) returned type %T, want *os.File", key, f)
6790+
return
6791+
}
6792+
w.Write([]byte(of.Name()))
6793+
}))
6794+
defer cst.close()
6795+
6796+
fBuf := new(bytes.Buffer)
6797+
mw := multipart.NewWriter(fBuf)
6798+
mf, err := mw.CreateFormFile(key, "myfile.txt")
6799+
if err != nil {
6800+
t.Fatal(err)
6801+
}
6802+
if _, err := mf.Write(bytes.Repeat([]byte("A"), maxMemory*2)); err != nil {
6803+
t.Fatal(err)
6804+
}
6805+
if err := mw.Close(); err != nil {
6806+
t.Fatal(err)
6807+
}
6808+
req, err := NewRequest("POST", cst.ts.URL, fBuf)
6809+
if err != nil {
6810+
t.Fatal(err)
6811+
}
6812+
req.Header.Set("Content-Type", mw.FormDataContentType())
6813+
res, err := cst.c.Do(req)
6814+
if err != nil {
6815+
t.Fatal(err)
6816+
}
6817+
defer res.Body.Close()
6818+
fname, err := io.ReadAll(res.Body)
6819+
if err != nil {
6820+
t.Fatal(err)
6821+
}
6822+
cst.close()
6823+
if _, err := os.Stat(string(fname)); !errors.Is(err, os.ErrNotExist) {
6824+
t.Errorf("file %q exists after HTTP handler returned", string(fname))
6825+
}
6826+
}

0 commit comments

Comments
 (0)