SplitHTTP: Read and validate HTTP/1.1 responses (#3797)

This commit is contained in:
Dmitry Anderson 2024-09-16 14:33:03 +02:00 committed by GitHub
parent 67c2a29065
commit a931507dd6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 44 additions and 6 deletions

3
.gitignore vendored
View file

@ -28,3 +28,6 @@ errorgen
*.dat *.dat
.vscode .vscode
/build_assets /build_assets
# Output from dlv test
**/debug.*

View file

@ -3,6 +3,7 @@ package splithttp
import ( import (
"bytes" "bytes"
"context" "context"
"fmt"
"io" "io"
gonet "net" gonet "net"
"net/http" "net/http"
@ -152,23 +153,39 @@ func (c *DefaultDialerClient) SendUploadRequest(ctx context.Context, url string,
// safely retried. if instead req.Write is called multiple // safely retried. if instead req.Write is called multiple
// times, the body is already drained after the first // times, the body is already drained after the first
// request // request
requestBytes := new(bytes.Buffer) requestBuff := new(bytes.Buffer)
common.Must(req.Write(requestBytes)) common.Must(req.Write(requestBuff))
var uploadConn any var uploadConn any
var h1UploadConn *H1Conn
for { for {
uploadConn = c.uploadRawPool.Get() uploadConn = c.uploadRawPool.Get()
newConnection := uploadConn == nil newConnection := uploadConn == nil
if newConnection { if newConnection {
uploadConn, err = c.dialUploadConn(context.WithoutCancel(ctx)) newConn, err := c.dialUploadConn(context.WithoutCancel(ctx))
if err != nil { if err != nil {
return err return err
} }
h1UploadConn = NewH1Conn(newConn)
uploadConn = h1UploadConn
} else {
h1UploadConn = uploadConn.(*H1Conn)
// TODO: Replace 0 here with a config value later
// Or add some other condition for optimization purposes
if h1UploadConn.UnreadedResponsesCount > 0 {
resp, err := http.ReadResponse(h1UploadConn.RespBufReader, req)
if err != nil {
return fmt.Errorf("error while reading response: %s", err.Error())
}
if resp.StatusCode != 200 {
return fmt.Errorf("got non-200 error response code: %d", resp.StatusCode)
}
}
} }
_, err = uploadConn.(net.Conn).Write(requestBytes.Bytes()) _, err := h1UploadConn.Write(requestBuff.Bytes())
// if the write failed, we try another connection from // if the write failed, we try another connection from
// the pool, until the write on a new connection fails. // the pool, until the write on a new connection fails.
// failed writes to a pooled connection are normal when // failed writes to a pooled connection are normal when

View file

@ -267,7 +267,6 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
&buf.MultiBufferContainer{MultiBuffer: chunk}, &buf.MultiBufferContainer{MultiBuffer: chunk},
int64(chunk.Len()), int64(chunk.Len()),
) )
if err != nil { if err != nil {
errors.LogInfoInner(ctx, err, "failed to send upload") errors.LogInfoInner(ctx, err, "failed to send upload")
uploadPipeReader.Interrupt() uploadPipeReader.Interrupt()

View file

@ -0,0 +1,19 @@
package splithttp
import (
"bufio"
"net"
)
type H1Conn struct {
UnreadedResponsesCount int
RespBufReader *bufio.Reader
net.Conn
}
func NewH1Conn(conn net.Conn) *H1Conn {
return &H1Conn{
RespBufReader: bufio.NewReader(conn),
Conn: conn,
}
}