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