github.com/xxf098/lite-proxy@v0.15.1-0.20230422081941-12c69f323218/tunnel/http/server.go (about) 1 package http 2 3 import ( 4 "context" 5 "errors" 6 "net" 7 8 "bufio" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "net/http" 13 "strings" 14 15 // "github.com/p4gefau1t/trojan-go/common" 16 "github.com/xxf098/lite-proxy/common" 17 "github.com/xxf098/lite-proxy/log" 18 "github.com/xxf098/lite-proxy/tunnel" 19 ) 20 21 type ConnectConn struct { 22 net.Conn 23 metadata *tunnel.Metadata 24 } 25 26 func (c *ConnectConn) Metadata() *tunnel.Metadata { 27 return c.metadata 28 } 29 30 type OtherConn struct { 31 net.Conn 32 metadata *tunnel.Metadata //fixed 33 reqReader *io.PipeReader 34 respWriter *io.PipeWriter 35 ctx context.Context 36 cancel context.CancelFunc 37 } 38 39 func (c *OtherConn) Metadata() *tunnel.Metadata { 40 return c.metadata 41 } 42 43 type Server struct { 44 underlay tunnel.Server 45 connChan chan tunnel.Conn 46 ctx context.Context 47 cancel context.CancelFunc 48 } 49 50 func (s *Server) acceptLoop() { 51 for { 52 conn, err := s.underlay.AcceptConn(&Tunnel{}) 53 if err != nil { 54 select { 55 case <-s.ctx.Done(): 56 log.Error(common.NewError("http closed")) 57 return 58 default: 59 log.Error(common.NewError("http failed to accept connection").Base(err)) 60 continue 61 } 62 } 63 64 go func(conn net.Conn) { 65 reqBufReader := bufio.NewReader(ioutil.NopCloser(conn)) 66 req, err := http.ReadRequest(reqBufReader) 67 if err != nil { 68 log.Error(common.NewError("not a valid http request").Base(err)) 69 return 70 } 71 72 if strings.ToUpper(req.Method) == "CONNECT" { // CONNECT 73 addr, err := tunnel.NewAddressFromAddr("tcp", req.Host) 74 if err != nil { 75 log.Error(common.NewError("invalid http dest address").Base(err)) 76 conn.Close() 77 return 78 } 79 resp := fmt.Sprintf("HTTP/%d.%d 200 Connection established\r\n\r\n", req.ProtoMajor, req.ProtoMinor) 80 _, err = conn.Write([]byte(resp)) 81 if err != nil { 82 log.Error(common.NewError("http failed to respond connect request")) 83 conn.Close() 84 return 85 } 86 s.connChan <- &ConnectConn{ 87 Conn: conn, 88 metadata: &tunnel.Metadata{ 89 Address: addr, 90 }, 91 } 92 } else { // GET, POST, PUT... 93 defer conn.Close() 94 for { 95 reqReader, reqWriter := io.Pipe() 96 respReader, respWriter := io.Pipe() 97 var addr *tunnel.Address 98 if addr, err = tunnel.NewAddressFromAddr("tcp", req.Host); err != nil { 99 addr = tunnel.NewAddressFromHostPort("tcp", req.Host, 80) 100 } 101 log.D("http dest", addr) 102 103 ctx, cancel := context.WithCancel(s.ctx) 104 newConn := &OtherConn{ 105 Conn: conn, 106 metadata: &tunnel.Metadata{ 107 Address: addr, 108 }, 109 ctx: ctx, 110 cancel: cancel, 111 reqReader: reqReader, 112 respWriter: respWriter, 113 } 114 s.connChan <- newConn // pass this http session connection to proxy.RelayConn 115 116 err = req.Write(reqWriter) // write request to the remote 117 if err != nil { 118 log.Error(common.NewError("http failed to write http request").Base(err)) 119 return 120 } 121 122 respBufReader := bufio.NewReader(ioutil.NopCloser(respReader)) // read response from the remote 123 resp, err := http.ReadResponse(respBufReader, req) 124 if err != nil { 125 log.Error(common.NewError("http failed to read http response").Base(err)) 126 return 127 } 128 err = resp.Write(conn) // send the response back to the local 129 if err != nil { 130 log.Error(common.NewError("http failed to write the response back").Base(err)) 131 return 132 } 133 newConn.Close() 134 req.Body.Close() 135 resp.Body.Close() 136 137 req, err = http.ReadRequest(reqBufReader) //read the next http request from local 138 if err != nil { 139 log.Error(common.NewError("http failed to the read request from local").Base(err)) 140 return 141 } 142 } 143 } 144 }(conn) 145 } 146 } 147 148 func (s *Server) AcceptConn(tunnel.Tunnel) (tunnel.Conn, error) { 149 select { 150 case conn := <-s.connChan: 151 return conn, nil 152 case <-s.ctx.Done(): 153 return nil, errors.New("http server closed") 154 } 155 } 156 157 func (s *Server) AcceptPacket(tunnel.Tunnel) (tunnel.PacketConn, error) { 158 <-s.ctx.Done() 159 return nil, errors.New("http server closed") 160 } 161 162 func (s *Server) Close() error { 163 s.cancel() 164 return s.underlay.Close() 165 } 166 167 func NewServer(ctx context.Context, underlay tunnel.Server) (*Server, error) { 168 ctx, cancel := context.WithCancel(ctx) 169 server := &Server{ 170 underlay: underlay, 171 connChan: make(chan tunnel.Conn, 32), 172 ctx: ctx, 173 cancel: cancel, 174 } 175 go server.acceptLoop() 176 log.D("http server created") 177 return server, nil 178 }