Allow http1 in v2ray HTTP transport

This commit is contained in:
世界
2022-08-22 22:51:08 +08:00
parent 4005452772
commit a24a2b475a
4 changed files with 130 additions and 27 deletions

View File

@@ -1,6 +1,7 @@
package v2rayhttp
import (
"bufio"
"context"
"crypto/tls"
"io"
@@ -20,20 +21,25 @@ import (
var _ adapter.V2RayClientTransport = (*Client)(nil)
type Client struct {
ctx context.Context
client *http.Client
url *url.URL
host []string
method string
headers http.Header
ctx context.Context
dialer N.Dialer
serverAddr M.Socksaddr
client *http.Client
http2 bool
url *url.URL
host []string
method string
headers http.Header
}
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPOptions, tlsConfig *tls.Config) adapter.V2RayClientTransport {
client := &Client{
ctx: ctx,
host: options.Host,
method: options.Method,
headers: make(http.Header),
ctx: ctx,
dialer: dialer,
serverAddr: serverAddr,
host: options.Host,
method: options.Method,
headers: make(http.Header),
client: &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
@@ -43,6 +49,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
TLSClientConfig: tlsConfig,
},
},
http2: tlsConfig != nil,
}
if client.method == "" {
client.method = "PUT"
@@ -66,13 +73,54 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
}
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
if !c.http2 {
return c.dialHTTP()
} else {
return c.dialHTTP2()
}
}
func (c *Client) dialHTTP() (net.Conn, error) {
conn, err := c.dialer.DialContext(c.ctx, N.NetworkTCP, c.serverAddr)
if err != nil {
return nil, err
}
request := &http.Request{
Method: c.method,
URL: c.url,
ProtoMajor: 1,
Proto: "HTTP/1.1",
Header: c.headers.Clone(),
}
switch hostLen := len(c.host); hostLen {
case 0:
case 1:
request.Host = c.host[0]
default:
request.Host = c.host[rand.Intn(hostLen)]
}
err = request.Write(conn)
if err != nil {
return nil, err
}
reader := bufio.NewReader(conn)
response, err := http.ReadResponse(reader, request)
if err != nil {
return nil, err
}
if response.StatusCode != 200 {
return nil, E.New("unexpected status: ", response.Status)
}
return conn, nil
}
func (c *Client) dialHTTP2() (net.Conn, error) {
pipeInReader, pipeInWriter := io.Pipe()
request := &http.Request{
Method: c.method,
Body: pipeInReader,
URL: c.url,
ProtoMajor: 2,
ProtoMinor: 0,
Proto: "HTTP/2",
Header: c.headers.Clone(),
}

View File

@@ -12,8 +12,6 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -96,22 +94,12 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
}
if h, ok := writer.(http.Hijacker); ok {
conn, reader, err := h.Hijack()
conn, _, err := h.Hijack()
if err != nil {
writer.WriteHeader(http.StatusInternalServerError)
s.badRequest(request, E.Cause(err, "hijack conn"))
return
}
if reader.Available() > 0 {
buffer := buf.NewSize(reader.Available())
_, err = buffer.ReadFullFrom(reader, buffer.FreeLen())
if err != nil {
writer.WriteHeader(http.StatusInternalServerError)
s.badRequest(request, E.Cause(err, "read cached data"))
return
}
conn = bufio.NewCachedConn(conn, buffer)
}
s.handler.NewConnection(request.Context(), conn, M.Metadata{})
} else {
conn := &ServerHTTPConn{