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  }