mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-15 01:09:20 +02:00
SplitHTTP: Read and validate HTTP/1.1 responses (#3797)
This commit is contained in:
parent
67c2a29065
commit
a931507dd6
|
@ -28,3 +28,6 @@ errorgen
|
||||||
*.dat
|
*.dat
|
||||||
.vscode
|
.vscode
|
||||||
/build_assets
|
/build_assets
|
||||||
|
|
||||||
|
# Output from dlv test
|
||||||
|
**/debug.*
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue