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 }