github.com/database64128/shadowsocks-go@v1.10.2-0.20240315062903-143a773533f1/http/client.go (about) 1 package http 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "net/http" 8 9 "github.com/database64128/shadowsocks-go/conn" 10 "github.com/database64128/shadowsocks-go/direct" 11 "github.com/database64128/shadowsocks-go/zerocopy" 12 ) 13 14 var ErrServerSpokeFirst = errors.New("server-speaks-first protocols are not supported by this HTTP proxy client implementation") 15 16 // NewHttpStreamClientReadWriter writes a HTTP/1.1 CONNECT request to rw and wraps rw into a ReadWriter ready for use. 17 func NewHttpStreamClientReadWriter(rw zerocopy.DirectReadWriteCloser, targetAddr conn.Addr) (*direct.DirectStreamReadWriter, error) { 18 targetAddress := targetAddr.String() 19 20 // Write CONNECT. 21 _, err := fmt.Fprintf(rw, "CONNECT %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: shadowsocks-go/0.0.0\r\nProxy-Connection: Keep-Alive\r\n\r\n", targetAddress, targetAddress) 22 if err != nil { 23 return nil, err 24 } 25 26 // Read response. 27 br := bufio.NewReader(rw) 28 resp, err := http.ReadResponse(br, nil) 29 if err != nil { 30 return nil, err 31 } 32 if resp.StatusCode != 200 { 33 return nil, fmt.Errorf("HTTP %s", resp.Status) 34 } 35 36 // Check if server spoke first. 37 if br.Buffered() > 0 { 38 return nil, ErrServerSpokeFirst 39 } 40 41 return direct.NewDirectStreamReadWriter(rw), nil 42 }