github.com/xxf098/lite-proxy@v0.15.1-0.20230422081941-12c69f323218/transport/vmess/http.go (about)

     1  package vmess
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"math/rand"
     8  	"net"
     9  	"net/http"
    10  	"net/textproto"
    11  )
    12  
    13  type httpConn struct {
    14  	net.Conn
    15  	cfg        *HTTPConfig
    16  	reader     *bufio.Reader
    17  	whandshake bool
    18  }
    19  
    20  type HTTPConfig struct {
    21  	Method  string
    22  	Host    string
    23  	Path    []string
    24  	Headers map[string][]string
    25  }
    26  
    27  // Read implements net.Conn.Read()
    28  func (hc *httpConn) Read(b []byte) (int, error) {
    29  	if hc.reader != nil {
    30  		n, err := hc.reader.Read(b)
    31  		return n, err
    32  	}
    33  
    34  	reader := textproto.NewConn(hc.Conn)
    35  	// First line: GET /index.html HTTP/1.0
    36  	if _, err := reader.ReadLine(); err != nil {
    37  		return 0, err
    38  	}
    39  
    40  	if _, err := reader.ReadMIMEHeader(); err != nil {
    41  		return 0, err
    42  	}
    43  
    44  	hc.reader = reader.R
    45  	return reader.R.Read(b)
    46  }
    47  
    48  // Write implements io.Writer.
    49  func (hc *httpConn) Write(b []byte) (int, error) {
    50  	if hc.whandshake {
    51  		return hc.Conn.Write(b)
    52  	}
    53  
    54  	path := hc.cfg.Path[rand.Intn(len(hc.cfg.Path))]
    55  	host := hc.cfg.Host
    56  	if header := hc.cfg.Headers["Host"]; len(header) != 0 {
    57  		host = header[rand.Intn(len(header))]
    58  	}
    59  
    60  	u := fmt.Sprintf("http://%s%s", host, path)
    61  	req, err := http.NewRequest("GET", u, bytes.NewBuffer(b))
    62  	if err != nil {
    63  		return 0, err
    64  	}
    65  	for key, list := range hc.cfg.Headers {
    66  		req.Header.Set(key, list[rand.Intn(len(list))])
    67  	}
    68  	req.ContentLength = int64(len(b))
    69  	if err := req.Write(hc.Conn); err != nil {
    70  		return 0, err
    71  	}
    72  	hc.whandshake = true
    73  	return len(b), nil
    74  }
    75  
    76  func (hc *httpConn) Close() error {
    77  	return hc.Conn.Close()
    78  }
    79  
    80  func StreamHTTPConn(conn net.Conn, cfg *HTTPConfig) net.Conn {
    81  	return &httpConn{
    82  		Conn: conn,
    83  		cfg:  cfg,
    84  	}
    85  }