Fix connection reuse in splithttp HTTP/1.1 (#3485)

This commit is contained in:
mmmray 2024-07-01 05:30:34 +02:00 committed by GitHub
parent 079d0bd8a9
commit c6a57b2cc1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,6 +1,7 @@
package splithttp package splithttp
import ( import (
"bytes"
"context" "context"
gotls "crypto/tls" gotls "crypto/tls"
"io" "io"
@ -263,6 +264,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
return return
} }
req.ContentLength = int64(chunk.Len())
req.Header = transportConfiguration.GetRequestHeader() req.Header = transportConfiguration.GetRequestHeader()
if httpClient.isH2 { if httpClient.isH2 {
@ -280,11 +282,19 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
return return
} }
} else { } else {
var err error
var uploadConn any var uploadConn any
for i := 0; i < 5; i++ {
// stringify the entire HTTP/1.1 request so it can be
// safely retried. if instead req.Write is called multiple
// times, the body is already drained after the first
// request
requestBytes := new(bytes.Buffer)
common.Must(req.Write(requestBytes))
for {
uploadConn = httpClient.uploadRawPool.Get() uploadConn = httpClient.uploadRawPool.Get()
if uploadConn == nil { newConnection := uploadConn == nil
if newConnection {
uploadConn, err = httpClient.dialUploadConn(context.WithoutCancel(ctx)) uploadConn, err = httpClient.dialUploadConn(context.WithoutCancel(ctx))
if err != nil { if err != nil {
errors.LogInfoInner(ctx, err, "failed to connect upload") errors.LogInfoInner(ctx, err, "failed to connect upload")
@ -293,17 +303,20 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
} }
} }
err = req.Write(uploadConn.(net.Conn)) _, err = uploadConn.(net.Conn).Write(requestBytes.Bytes())
// if the write failed, we try another connection from
// the pool, until the write on a new connection fails.
// failed writes to a pooled connection are normal when
// the connection has been closed in the meantime.
if err == nil { if err == nil {
break break
} } else if newConnection {
}
if err != nil {
errors.LogInfoInner(ctx, err, "failed to send upload") errors.LogInfoInner(ctx, err, "failed to send upload")
uploadPipeReader.Interrupt() uploadPipeReader.Interrupt()
return return
} }
}
httpClient.uploadRawPool.Put(uploadConn) httpClient.uploadRawPool.Put(uploadConn)
} }