github.com/database64128/shadowsocks-go@v1.7.0/http/server.go (about) 1 package http 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "io" 8 "net/http" 9 "net/url" 10 "strings" 11 "time" 12 13 "github.com/database64128/shadowsocks-go/conn" 14 "github.com/database64128/shadowsocks-go/direct" 15 "github.com/database64128/shadowsocks-go/magic" 16 "github.com/database64128/shadowsocks-go/pipe" 17 "github.com/database64128/shadowsocks-go/zerocopy" 18 "go.uber.org/zap" 19 ) 20 21 // NewHttpStreamServerReadWriter handles a HTTP request from rw and wraps rw into a ReadWriter ready for use. 22 func NewHttpStreamServerReadWriter(rw zerocopy.DirectReadWriteCloser, logger *zap.Logger) (*direct.DirectStreamReadWriter, conn.Addr, error) { 23 rwbr := bufio.NewReader(rw) 24 req, err := magic.ReadRequest(rwbr) 25 if err != nil { 26 return nil, conn.Addr{}, err 27 } 28 29 // Host -> targetAddr 30 targetAddr, err := hostHeaderToAddr(req.Host) 31 if err != nil { 32 send418(rw) 33 return nil, conn.Addr{}, err 34 } 35 36 // Fast-track CONNECT. 37 if req.Method == http.MethodConnect { 38 if _, err = fmt.Fprintf(rw, "HTTP/1.1 200 OK\r\nDate: %s\r\n\r\n", time.Now().UTC().Format(http.TimeFormat)); err != nil { 39 return nil, conn.Addr{}, err 40 } 41 return direct.NewDirectStreamReadWriter(rw), targetAddr, nil 42 } 43 44 // Set up pipes. 45 pl, pr := pipe.NewDuplexPipe() 46 47 // Spin up a goroutine to write processed requests to pl 48 // and read responses from pl. 49 go func() { 50 var rerr, werr error 51 52 plbr := bufio.NewReader(pl) 53 plbw := bufio.NewWriter(pl) 54 rwbw := bufio.NewWriter(rw) 55 56 for { 57 // Delete hop-by-hop headers specified in Connection. 58 connectionHeader := req.Header["Connection"] 59 for i := range connectionHeader { 60 req.Header.Del(connectionHeader[i]) 61 } 62 delete(req.Header, "Connection") 63 64 delete(req.Header, "Proxy-Connection") 65 66 if ce := logger.Check(zap.DebugLevel, "Writing HTTP request"); ce != nil { 67 ce.Write( 68 zap.String("proto", req.Proto), 69 zap.String("method", req.Method), 70 zap.String("url", req.RequestURI), 71 ) 72 } 73 74 // Write request. 75 if werr = req.Write(plbw); werr != nil { 76 werr = fmt.Errorf("failed to write HTTP request: %w", werr) 77 break 78 } 79 80 // Flush request. 81 if werr = plbw.Flush(); werr != nil { 82 werr = fmt.Errorf("failed to flush HTTP request: %w", werr) 83 break 84 } 85 86 var resp *http.Response 87 88 // Read response. 89 resp, rerr = http.ReadResponse(plbr, req) 90 if rerr != nil { 91 rerr = fmt.Errorf("failed to read HTTP response: %w", rerr) 92 break 93 } 94 95 // Add Connection: close if response is 301, 302, or 307, 96 // and Location points to a different host. 97 switch resp.StatusCode { 98 case http.StatusMovedPermanently, http.StatusFound, http.StatusTemporaryRedirect: 99 location := resp.Header["Location"] 100 101 if ce := logger.Check(zap.DebugLevel, "Checking HTTP 3xx response Location header"); ce != nil { 102 ce.Write( 103 zap.String("proto", resp.Proto), 104 zap.String("status", resp.Status), 105 zap.Strings("location", location), 106 ) 107 } 108 109 if len(location) != 1 { 110 break 111 } 112 113 url, err := url.Parse(location[0]) 114 if err != nil { 115 break 116 } 117 118 switch url.Host { 119 case req.Host, "": 120 default: 121 resp.Close = true 122 } 123 } 124 125 if ce := logger.Check(zap.DebugLevel, "Writing HTTP response"); ce != nil { 126 ce.Write( 127 zap.String("proto", resp.Proto), 128 zap.String("status", resp.Status), 129 ) 130 } 131 132 // Write response. 133 if rerr = resp.Write(rwbw); rerr != nil { 134 rerr = fmt.Errorf("failed to write HTTP response: %w", rerr) 135 break 136 } 137 138 // Flush response. 139 if rerr = rwbw.Flush(); rerr != nil { 140 rerr = fmt.Errorf("failed to flush HTTP response: %w", rerr) 141 break 142 } 143 144 // Stop relaying if either client or server indicates that the connection should be closed. 145 // 146 // RFC 7230 section 6.6 says: 147 // The server SHOULD send a "close" connection option in its final response on that connection. 148 // 149 // It's not a "MUST", so we check both. 150 if req.Close || resp.Close { 151 break 152 } 153 154 // Read request. 155 req, werr = magic.ReadRequest(rwbr) 156 if werr != nil { 157 if werr != io.EOF { 158 werr = fmt.Errorf("failed to read HTTP request: %w", werr) 159 } 160 break 161 } 162 } 163 164 pl.CloseReadWithError(rerr) 165 pl.CloseWriteWithError(werr) 166 }() 167 168 // Wrap pr into a direct stream ReadWriter. 169 return direct.NewDirectStreamReadWriter(pr), targetAddr, nil 170 } 171 172 var errEmptyHostHeader = errors.New("empty host header") 173 174 // hostHeaderToAddr parses the Host header into an address. 175 // 176 // Host may be in any of the following forms: 177 // - example.com 178 // - example.com:443 179 // - 1.1.1.1 180 // - 1.1.1.1:443 181 // - [2606:4700:4700::1111] 182 // - [2606:4700:4700::1111]:443 183 func hostHeaderToAddr(host string) (conn.Addr, error) { 184 switch { 185 case len(host) == 0: 186 return conn.Addr{}, errEmptyHostHeader 187 case strings.IndexByte(host, ':') == -1: 188 return conn.AddrFromHostPort(host, 80) 189 case host[0] == '[' && host[len(host)-1] == ']': 190 return conn.AddrFromHostPort(host[1:len(host)-1], 80) 191 default: 192 return conn.ParseAddr(host) 193 } 194 } 195 196 func send418(w io.Writer) error { 197 _, err := fmt.Fprint(w, "HTTP/1.1 418 I'm a teapot\r\n\r\n") 198 return err 199 }