github.com/chwjbn/xclash@v0.2.0/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, _ := http.NewRequest("GET", u, bytes.NewBuffer(b))
    62  	for key, list := range hc.cfg.Headers {
    63  		req.Header.Set(key, list[rand.Intn(len(list))])
    64  	}
    65  	req.ContentLength = int64(len(b))
    66  	if err := req.Write(hc.Conn); err != nil {
    67  		return 0, err
    68  	}
    69  	hc.whandshake = true
    70  	return len(b), nil
    71  }
    72  
    73  func (hc *httpConn) Close() error {
    74  	return hc.Conn.Close()
    75  }
    76  
    77  func StreamHTTPConn(conn net.Conn, cfg *HTTPConfig) net.Conn {
    78  	return &httpConn{
    79  		Conn: conn,
    80  		cfg:  cfg,
    81  	}
    82  }