-
Notifications
You must be signed in to change notification settings - Fork 18k
net/http: server waits for maxPostHandlerReadBytes of a chunked request before returning error #25475
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
Comments
What is this server validator ? Why will it fail ? Can you please upload a complete and independent code sample ? |
(CC: @bradfitz, but awaiting more detail) |
I don't really understand this bug. Please post a complete pair of demonstration programs (a client & server), not just snippets. Perhaps that will make it more clear. |
@agnivade What is this server validator ? Why will it fail ? The full code of the server is then uploaded. |
Thank you @everfighter /@winworm for providing the complete code. |
The issue is within your for loop in client.go. You are sleeping for a certain time which is causing the delay. Plus varying your buffer size will also change the response time. Just simply remove the for loop and do a I could not see anything related to Feel free to comment if you disagree with the analysis. |
thank you @agnivade below is some debug info of source code in server.go func (w *response) finishRequest() {
w.handlerDone.setTrue()
if !w.wroteHeader {
w.WriteHeader(StatusOK)
}
**start := time.Now()
w.w.Flush()
fmt.Println("chunkedwriterclose:"+time.Since(start).String())**
putBufioWriter(w.w)
w.cw.close()
w.conn.bufw.Flush()
w.conn.r.abortPendingRead()
// Close the body (regardless of w.closeAfterReply) so we can
// re-use its bufio.Reader later safely.
start = time.Now()
w.reqBody.Close()
fmt.Println("w.reqBody.Close():"+time.Since(start).String())
if w.req.MultipartForm != nil {
w.req.MultipartForm.RemoveAll()
}
} w.w.Flush() will invoke the below method writeHeader(p []byte) func (cw *chunkWriter) writeHeader(p []byte) {
.......
if w.req.ContentLength != 0 && !w.closeAfterReply {
var discard, tooBig bool
switch bdy := w.req.Body.(type) {
case *expectContinueReader:
if bdy.resp.wroteContinue {
discard = true
}
case *body:
bdy.mu.Lock()
switch {
case bdy.closed:
if !bdy.sawEOF {
// Body was closed in handler with non-EOF error.
w.closeAfterReply = true
}
case bdy.unreadDataSizeLocked() >= maxPostHandlerReadBytes:
tooBig = true
default:
discard = true
}
bdy.mu.Unlock()
default:
discard = true
}
if discard {
**_, err := io.CopyN(ioutil.Discard, w.reqBody, maxPostHandlerReadBytes+1)**
switch err {
case nil:
// There must be even more data left over.
tooBig = true
case ErrBodyReadAfterClose:
// Body was already consumed and closed.
case io.EOF:
// The remaining body was just consumed, close it.
err = w.reqBody.Close()
if err != nil {
w.closeAfterReply = true
}
default:
// Some other kind of error occurred, like a read timeout, or
// corrupt chunked encoding. In any case, whatever remains
// on the wire must not be parsed as another HTTP request.
w.closeAfterReply = true
}
}
.......
} io.CopyN(ioutil.Discard, w.reqBody, maxPostHandlerReadBytes+1) this method will cost 8s to read 256k data |
this is the debug result chunkedwriterclose:8.276652351s |
Ok, so if I understand you correctly, you want to sleep for 20ms after every write, but still you want to get the result immediately. I will let @bradfitz decide if he wants to reopen this. |
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (
go version
)?go version go1.10.1 linux/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?GOARCH="amd64"
GOBIN=""
GOCACHE="/home/qhyu/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/qhyu/git/go"
GORACE=""
GOROOT="/home/qhyu/work/installed/go"
GOTMPDIR=""
GOTOOLDIR="/home/qhyu/work/installed/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build281947105=/tmp/go-build -gno-record-gcc-switches"
What did you do?
use go http client to post a request to the go server use chunked protocol,the data send speed is constant
below is the client test code .
What did you expect to see?
when an error occur because of parameters check etc. the response will immediately get .
What did you see instead?
When the server validator fails, because of none request data was consumption, this should return an error code to the client directly, but now as a result, the client will wait for a long period of time (reading maxPostHandlerReadBytes bytes to flush response) to get the error code
The text was updated successfully, but these errors were encountered: