-
Notifications
You must be signed in to change notification settings - Fork 17.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net/http: Request.ParseMultipartForm doesn't read all the body #32935
Comments
The example you've provided runs without error in the Playground. Can you provide a more deterministic example? |
Yes, i can't figure out why. But the problem do occur on my windows 10 pc and ubuntu 18.04 LTS with go1.12.7. |
The playground runs with |
(You may be able to amplify the raciness in the playground by inserting calls to |
Fixes golang#32935 Previously, when ParseMultipartForm reaches final boundary line, there might still be contents (e.g. Trailer) left unread after HTTP request body. This commit fixes it by reading once more upon final boundary line.
Change https://golang.org/cl/185637 mentions this issue: |
I spent a little time on it. This is due to misbehavior of
When this happens, I created a PR by reading once more upon final boundary line to make sure all bytes in HTTP request body are successfully read. |
Thank you for the report and for the PR @Tevic! So even a peek, err := r.bufReader.Peek(1) instead of a whole line seems to solve the problem. Could you please perhaps explain why a peek which isn't meant to advance the reader works just as well as the entire To better understand the problem, could you please perhaps modify this raw request write to show how not doing that read in mime/multipart on the boundary produces the error? package main
import (
"bufio"
"fmt"
"log"
"net"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
)
func main() {
testTrailer := "TestTrailer"
cst := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(1024 * 16)
if err != nil {
log.Fatal("parsing form: ", err)
}
if r.Trailer.Get(testTrailer) == "" {
log.Fatalf("expected Trailer not found: Trailer is empty.")
}
fmt.Printf("r.Trailer: %#v\n", r.Trailer)
w.Write([]byte("Aloha, World!"))
}))
defer cst.Close()
u, _ := url.Parse(cst.URL)
conn, err := net.Dial("tcp", u.Host)
if err != nil {
log.Fatalf("Failed to dial to host: %v", err)
}
defer conn.Close()
reqStr := "" +
"POST / HTTP/1.1\r\nHost: 127.0.0.1:59265\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n" +
"Content-Type: multipart/form-data; boundary=313092f87349b5232f6b6b5bef3f1ba2897ac3b3b8046bbeecc7abb42951\r\n" +
"User-Agent: Go-http-client/1.1\r\n\r\n130\r\n--313092f87349b5232f6b6b5bef3f1ba2897ac3b3b8046bbeecc7abb42951\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"testFile\"\r\nContent-Type: application/octet-stream\r\n\r\n" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\r\n--313092f87349b5232f6b6b5bef3f1ba2897ac3b3b8046bbeecc7abb42951--\r\n\r\n0\r\n" +
"TestTrailer: FooBar\r\nTrailer2: Hello\r\n\r\n"
if _, err := conn.Write([]byte(reqStr)); err != nil {
log.Fatalf("Failed to write request: %v", err)
}
br := bufio.NewReader(conn)
res, err := http.ReadResponse(br, nil)
if err != nil {
log.Fatalf("Failed to read response: %v", err)
}
blob, _ := httputil.DumpResponse(res, true)
println(string(blob))
} if you can concretely show the body that's sent but cause the server's ParseMultipartForm to trip out we can then move on with the CL, thank you! /cc @bradfitz |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?Ubuntu 18.04.2 LTS
go env
OutputWhat did you do?
I send a multipart form request with a trailer, and the server side will parse the form use ParseMultipartForm,after that i get trailer from request. But sometimes it doesn't show up.
This is my example. Two test servers are for comparison. srvReadBody works like a charm while srvParseForm don't.
What did you expect to see?
r.Trailer.Get(testTrailer) != ""
What did you see instead?
Sometimes
r.Trailer.Get(testTrailer) == ""
The code output like:
I've trace the code and the problem is due to this line. When isFinalBoundary match the condition the body may have not been completely read.
go/src/mime/multipart/multipart.go
Line 336 in 39b533e
The text was updated successfully, but these errors were encountered: