github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/transport/http.go (about) 1 package transport 2 3 import ( 4 "bufio" 5 "crypto/tls" 6 "fmt" 7 "net" 8 "net/http" 9 "strconv" 10 "strings" 11 "sync" 12 "time" 13 14 utls "github.com/refraction-networking/utls" 15 vaddr "github.com/volts-dev/volts/internal/addr" 16 vnet "github.com/volts-dev/volts/internal/net" 17 mls "github.com/volts-dev/volts/internal/tls" 18 ) 19 20 // Time wraps time.Time overriddin the json marshal/unmarshal to pass 21 // timestamp as integer 22 type Time struct { 23 time.Time 24 } 25 26 type data struct { 27 Time Time `json:"time"` 28 } 29 30 // A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an 31 // HTTP response or the Cookie header of an HTTP request. 32 // 33 // See https://tools.ietf.org/html/rfc6265 for details. 34 // Stolen from Net/http/cookies 35 type Cookie struct { 36 Name string `json:"name"` 37 Value string `json:"value"` 38 39 Path string `json:"path"` // optional 40 Domain string `json:"domain"` // optional 41 Expires time.Time 42 JSONExpires Time `json:"expires"` // optional 43 RawExpires string `json:"rawExpires"` // for reading cookies only 44 45 // MaxAge=0 means no 'Max-Age' attribute specified. 46 // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' 47 // MaxAge>0 means Max-Age attribute present and given in seconds 48 MaxAge int `json:"maxAge"` 49 Secure bool `json:"secure"` 50 HTTPOnly bool `json:"httpOnly"` 51 SameSite http.SameSite `json:"sameSite"` 52 Raw string 53 Unparsed []string `json:"unparsed"` // Raw text of unparsed attribute-value pairs 54 } 55 56 // UnmarshalJSON implements json.Unmarshaler inferface. 57 func (t *Time) UnmarshalJSON(buf []byte) error { 58 // Try to parse the timestamp integer 59 ts, err := strconv.ParseInt(string(buf), 10, 64) 60 if err == nil { 61 if len(buf) == 19 { 62 t.Time = time.Unix(ts/1e9, ts%1e9) 63 } else { 64 t.Time = time.Unix(ts, 0) 65 } 66 return nil 67 } 68 str := strings.Trim(string(buf), `"`) 69 if str == "null" || str == "" { 70 return nil 71 } 72 // Try to manually parse the data 73 tt, err := ParseDateString(str) 74 if err != nil { 75 return err 76 } 77 t.Time = tt 78 return nil 79 } 80 81 // ParseDateString takes a string and passes it through Approxidate 82 // Parses into a time.Time 83 func ParseDateString(dt string) (time.Time, error) { 84 const layout = "Mon, 02-Jan-2006 15:04:05 MST" 85 86 return time.Parse(layout, dt) 87 } 88 89 type ( 90 HttpTransport struct { 91 sync.Mutex 92 config *Config 93 //dialer proxy.ContextDialer 94 //dialer proxy.Dialer 95 //JA3 string 96 //UserAgent string 97 } 98 ) 99 100 func NewHTTPTransport(opts ...Option) *HttpTransport { 101 return &HttpTransport{ 102 //dialer: proxy.Direct, 103 config: newConfig(opts...), 104 } 105 } 106 107 func (self *HttpTransport) Init(opts ...Option) error { 108 for _, o := range opts { 109 o(self.config) 110 } 111 112 return nil 113 } 114 115 // to make a Dial with server 116 func (self *HttpTransport) Dial(addr string, opts ...DialOption) (IClient, error) { 117 dialCfg := DialConfig{ 118 DialTimeout: self.config.DialTimeout, 119 ReadTimeout: self.config.ReadTimeout, 120 WriteTimeout: self.config.WriteTimeout, 121 } 122 dialCfg.Init(opts...) 123 124 var conn net.Conn 125 var err error 126 127 // TODO: support dial option here rather than using internal config 128 if dialCfg.Secure || self.config.TlsConfig != nil { 129 config := self.config.TlsConfig 130 if config == nil { 131 config = &tls.Config{ 132 InsecureSkipVerify: true, // 跳过认证证书 133 } 134 } 135 136 if dialCfg.Ja3.Ja3 != "" { 137 rawConn, err := dialCfg.dialer.Dial(dialCfg.Network, addr) 138 if err != nil { 139 return nil, err 140 } 141 142 var host string 143 if host, _, err = net.SplitHostPort(addr); err != nil { 144 host = addr 145 } 146 ////////////////// 147 148 spec, err := parseJA3(dialCfg.Ja3.Ja3) 149 if err != nil { 150 return nil, err 151 } 152 153 cnn := utls.UClient(rawConn, &utls.Config{ 154 ServerName: host, 155 MinVersion: tls.VersionTLS12, 156 MaxVersion: tls.VersionTLS12, 157 InsecureSkipVerify: config.InsecureSkipVerify, 158 }, // Default is TLS13 159 utls.HelloChrome_Auto) 160 if err := cnn.ApplyPreset(spec); err != nil { 161 return nil, err 162 } 163 164 if err = cnn.Handshake(); err != nil { 165 _ = cnn.Close() 166 167 if err.Error() == "tls: CurvePreferences includes unsupported curve" { 168 //fix this 169 return nil, fmt.Errorf("conn.Handshake() error for tls 1.3 (please retry request): %+v", err) 170 } 171 return nil, fmt.Errorf("uTlsConn.Handshake() error: %+v", err) 172 } 173 174 conn = cnn 175 } else { 176 //config.NextProtos = []string{"http/1.1"} 177 // conn, err = newConn(func(addr string) (net.Conn, error) { 178 // return tls.DialWithDialer(&net.Dialer{Timeout: self.config.DialTimeout}, "tcp", addr, config) 179 // })(addr) 180 conn, err = tls.DialWithDialer(&net.Dialer{Timeout: dialCfg.DialTimeout}, "tcp", addr, config) 181 } 182 183 } else { 184 conn, err = newConn(func(addr string) (net.Conn, error) { 185 return net.DialTimeout("tcp", addr, dialCfg.DialTimeout) 186 })(addr) 187 } 188 189 if err != nil { 190 return nil, err 191 } 192 193 return &httpTransportClient{ 194 transport: self, 195 config: dialCfg, 196 addr: addr, 197 conn: conn, 198 buff: bufio.NewReader(conn), 199 r: make(chan *http.Request, 1), 200 local: conn.LocalAddr().String(), 201 remote: conn.RemoteAddr().String(), 202 }, nil 203 } 204 205 func (self *HttpTransport) Listen(addr string, opts ...ListenOption) (IListener, error) { 206 var options ListenConfig 207 for _, opt := range opts { 208 opt(&options) 209 } 210 211 var l net.Listener 212 var err error 213 if self.config.EnableACME && self.config.ACMEProvider != nil { 214 // should we check the address to make sure its using :443? 215 //l, err = self.config.ACMEProvider.Listen(self.config.ACMEHosts...) 216 config, err := self.config.ACMEProvider.TLSConfig(self.config.ACMEHosts...) 217 if err != nil { 218 return nil, err 219 } 220 221 fn := func(addr string) (net.Listener, error) { 222 // generate a certificate 223 cert, err := mls.Certificate(self.config.ACMEHosts...) 224 if err != nil { 225 return nil, err 226 } 227 config.Certificates = []tls.Certificate{cert} 228 return tls.Listen("tcp", addr, config) 229 } 230 231 l, err = vnet.Listen(addr, fn) 232 } else if self.config.Secure || self.config.TlsConfig != nil { 233 // TODO: support use of listen options 234 config := self.config.TlsConfig 235 236 fn := func(addr string) (net.Listener, error) { 237 if config == nil { 238 hosts := []string{addr} 239 240 // check if its a valid host:port 241 if host, _, err := net.SplitHostPort(addr); err == nil { 242 if len(host) == 0 { 243 hosts = vaddr.IPs() 244 } else { 245 hosts = []string{host} 246 } 247 } 248 249 // generate a certificate 250 cert, err := mls.Certificate(hosts...) 251 if err != nil { 252 return nil, err 253 } 254 config = &tls.Config{Certificates: []tls.Certificate{cert}} 255 } 256 return tls.Listen("tcp", addr, config) 257 } 258 259 l, err = vnet.Listen(addr, fn) 260 } else { 261 fn := func(addr string) (net.Listener, error) { 262 return net.Listen("tcp", addr) 263 } 264 265 l, err = vnet.Listen(addr, fn) 266 } 267 268 if err != nil { 269 return nil, err 270 } 271 272 self.config.Listener = &httpTransportListener{ 273 transport: self, 274 listener: l, 275 } 276 /* 277 self.config.Listener = &transportListener{ 278 transport: self, 279 listener: l, 280 }*/ 281 return self.config.Listener, nil 282 } 283 284 /* 285 func (h *httpTransport) Request(msg Message, sock *Socket, cde codec.ICodec) IRequest { 286 return nil 287 } 288 289 func (h *httpTransport) Response(sock *Socket, cde codec.ICodec) IResponse { 290 return nil 291 } 292 */ 293 func (self *HttpTransport) Config() *Config { 294 return self.config 295 } 296 297 func (self *HttpTransport) String() string { 298 if self.config.Secure || self.config.TlsConfig != nil { 299 return "HttpsTransport" 300 } 301 return "HttpTransport" 302 } 303 304 func (self *HttpTransport) Protocol() string { 305 if self.config.Secure || self.config.TlsConfig != nil { 306 return "https" 307 } 308 return "http" 309 }