gitee.com/sasukebo/go-micro/v4@v4.7.1/transport/http_transport.go (about)

     1  package transport
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"crypto/tls"
     7  	"errors"
     8  	"io"
     9  	"net"
    10  	"net/http"
    11  	"net/url"
    12  	"sync"
    13  	"time"
    14  
    15  	"golang.org/x/net/http2"
    16  	"golang.org/x/net/http2/h2c"
    17  
    18  	maddr "gitee.com/sasukebo/go-micro/v4/util/addr"
    19  	"gitee.com/sasukebo/go-micro/v4/util/buf"
    20  	mnet "gitee.com/sasukebo/go-micro/v4/util/net"
    21  	mls "gitee.com/sasukebo/go-micro/v4/util/tls"
    22  )
    23  
    24  type httpTransport struct {
    25  	opts Options
    26  }
    27  
    28  type httpTransportClient struct {
    29  	ht       *httpTransport
    30  	addr     string
    31  	conn     net.Conn
    32  	dialOpts DialOptions
    33  	once     sync.Once
    34  
    35  	sync.RWMutex
    36  
    37  	// request must be stored for response processing
    38  	r      chan *http.Request
    39  	bl     []*http.Request
    40  	buff   *bufio.Reader
    41  	closed bool
    42  
    43  	// local/remote ip
    44  	local  string
    45  	remote string
    46  }
    47  
    48  type httpTransportSocket struct {
    49  	ht *httpTransport
    50  	w  http.ResponseWriter
    51  	r  *http.Request
    52  	rw *bufio.ReadWriter
    53  
    54  	mtx sync.RWMutex
    55  
    56  	// the hijacked when using http 1
    57  	conn net.Conn
    58  	// for the first request
    59  	ch chan *http.Request
    60  
    61  	// h2 things
    62  	buf *bufio.Reader
    63  	// indicate if socket is closed
    64  	closed chan bool
    65  
    66  	// local/remote ip
    67  	local  string
    68  	remote string
    69  }
    70  
    71  type httpTransportListener struct {
    72  	ht       *httpTransport
    73  	listener net.Listener
    74  }
    75  
    76  func (h *httpTransportClient) Local() string {
    77  	return h.local
    78  }
    79  
    80  func (h *httpTransportClient) Remote() string {
    81  	return h.remote
    82  }
    83  
    84  func (h *httpTransportClient) Send(m *Message) error {
    85  	header := make(http.Header)
    86  
    87  	for k, v := range m.Header {
    88  		header.Set(k, v)
    89  	}
    90  
    91  	b := buf.New(bytes.NewBuffer(m.Body))
    92  	defer b.Close()
    93  
    94  	req := &http.Request{
    95  		Method: "POST",
    96  		URL: &url.URL{
    97  			Scheme: "http",
    98  			Host:   h.addr,
    99  		},
   100  		Header:        header,
   101  		Body:          b,
   102  		ContentLength: int64(b.Len()),
   103  		Host:          h.addr,
   104  	}
   105  
   106  	h.Lock()
   107  	h.bl = append(h.bl, req)
   108  	select {
   109  	case h.r <- h.bl[0]:
   110  		h.bl = h.bl[1:]
   111  	default:
   112  	}
   113  	h.Unlock()
   114  
   115  	// set timeout if its greater than 0
   116  	if h.ht.opts.Timeout > time.Duration(0) {
   117  		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
   118  	}
   119  
   120  	return req.Write(h.conn)
   121  }
   122  
   123  func (h *httpTransportClient) Recv(m *Message) error {
   124  	if m == nil {
   125  		return errors.New("message passed in is nil")
   126  	}
   127  
   128  	var r *http.Request
   129  	if !h.dialOpts.Stream {
   130  		rc, ok := <-h.r
   131  		if !ok {
   132  			return io.EOF
   133  		}
   134  		r = rc
   135  	}
   136  
   137  	// set timeout if its greater than 0
   138  	if h.ht.opts.Timeout > time.Duration(0) {
   139  		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
   140  	}
   141  
   142  	h.Lock()
   143  	if h.closed {
   144  		h.Unlock()
   145  		return io.EOF
   146  	}
   147  	rsp, err := http.ReadResponse(h.buff, r)
   148  	h.Unlock()
   149  	if err != nil {
   150  		return err
   151  	}
   152  	defer rsp.Body.Close()
   153  
   154  	b, err := io.ReadAll(rsp.Body)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	if rsp.StatusCode != 200 {
   160  		return errors.New(rsp.Status + ": " + string(b))
   161  	}
   162  
   163  	m.Body = b
   164  
   165  	if m.Header == nil {
   166  		m.Header = make(map[string]string, len(rsp.Header))
   167  	}
   168  
   169  	for k, v := range rsp.Header {
   170  		if len(v) > 0 {
   171  			m.Header[k] = v[0]
   172  		} else {
   173  			m.Header[k] = ""
   174  		}
   175  	}
   176  
   177  	return nil
   178  }
   179  
   180  func (h *httpTransportClient) Close() error {
   181  	h.once.Do(func() {
   182  		h.Lock()
   183  		h.buff.Reset(nil)
   184  		h.closed = true
   185  		h.Unlock()
   186  		close(h.r)
   187  	})
   188  	return h.conn.Close()
   189  }
   190  
   191  func (h *httpTransportSocket) Local() string {
   192  	return h.local
   193  }
   194  
   195  func (h *httpTransportSocket) Remote() string {
   196  	return h.remote
   197  }
   198  
   199  func (h *httpTransportSocket) Recv(m *Message) error {
   200  	if m == nil {
   201  		return errors.New("message passed in is nil")
   202  	}
   203  	if m.Header == nil {
   204  		m.Header = make(map[string]string, len(h.r.Header))
   205  	}
   206  
   207  	// process http 1
   208  	if h.r.ProtoMajor == 1 {
   209  		// set timeout if its greater than 0
   210  		if h.ht.opts.Timeout > time.Duration(0) {
   211  			h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
   212  		}
   213  
   214  		var r *http.Request
   215  
   216  		select {
   217  		// get first request
   218  		case r = <-h.ch:
   219  		// read next request
   220  		default:
   221  			rr, err := http.ReadRequest(h.rw.Reader)
   222  			if err != nil {
   223  				return err
   224  			}
   225  			r = rr
   226  		}
   227  
   228  		// read body
   229  		b, err := io.ReadAll(r.Body)
   230  		if err != nil {
   231  			return err
   232  		}
   233  
   234  		// set body
   235  		r.Body.Close()
   236  		m.Body = b
   237  
   238  		// set headers
   239  		for k, v := range r.Header {
   240  			if len(v) > 0 {
   241  				m.Header[k] = v[0]
   242  			} else {
   243  				m.Header[k] = ""
   244  			}
   245  		}
   246  
   247  		// return early early
   248  		return nil
   249  	}
   250  
   251  	// only process if the socket is open
   252  	select {
   253  	case <-h.closed:
   254  		return io.EOF
   255  	default:
   256  		// no op
   257  	}
   258  
   259  	// processing http2 request
   260  	// read streaming body
   261  
   262  	// set max buffer size
   263  	// TODO: adjustable buffer size
   264  	buf := make([]byte, 4*1024*1024)
   265  
   266  	// read the request body
   267  	n, err := h.buf.Read(buf)
   268  	// not an eof error
   269  	if err != nil {
   270  		return err
   271  	}
   272  
   273  	// check if we have data
   274  	if n > 0 {
   275  		m.Body = buf[:n]
   276  	}
   277  
   278  	// set headers
   279  	for k, v := range h.r.Header {
   280  		if len(v) > 0 {
   281  			m.Header[k] = v[0]
   282  		} else {
   283  			m.Header[k] = ""
   284  		}
   285  	}
   286  
   287  	// set path
   288  	m.Header[":path"] = h.r.URL.Path
   289  
   290  	return nil
   291  }
   292  
   293  func (h *httpTransportSocket) Send(m *Message) error {
   294  	if h.r.ProtoMajor == 1 {
   295  		// make copy of header
   296  		hdr := make(http.Header)
   297  		for k, v := range h.r.Header {
   298  			hdr[k] = v
   299  		}
   300  
   301  		rsp := &http.Response{
   302  			Header:        hdr,
   303  			Body:          io.NopCloser(bytes.NewReader(m.Body)),
   304  			Status:        "200 OK",
   305  			StatusCode:    200,
   306  			Proto:         "HTTP/1.1",
   307  			ProtoMajor:    1,
   308  			ProtoMinor:    1,
   309  			ContentLength: int64(len(m.Body)),
   310  		}
   311  
   312  		for k, v := range m.Header {
   313  			rsp.Header.Set(k, v)
   314  		}
   315  
   316  		// set timeout if its greater than 0
   317  		if h.ht.opts.Timeout > time.Duration(0) {
   318  			h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
   319  		}
   320  
   321  		return rsp.Write(h.conn)
   322  	}
   323  
   324  	// only process if the socket is open
   325  	select {
   326  	case <-h.closed:
   327  		return io.EOF
   328  	default:
   329  		// no op
   330  	}
   331  
   332  	// we need to lock to protect the write
   333  	h.mtx.RLock()
   334  	defer h.mtx.RUnlock()
   335  
   336  	// set headers
   337  	for k, v := range m.Header {
   338  		h.w.Header().Set(k, v)
   339  	}
   340  
   341  	// write request
   342  	_, err := h.w.Write(m.Body)
   343  
   344  	// flush the trailers
   345  	h.w.(http.Flusher).Flush()
   346  
   347  	return err
   348  }
   349  
   350  func (h *httpTransportSocket) error(m *Message) error {
   351  	if h.r.ProtoMajor == 1 {
   352  		rsp := &http.Response{
   353  			Header:        make(http.Header),
   354  			Body:          io.NopCloser(bytes.NewReader(m.Body)),
   355  			Status:        "500 Internal Server Error",
   356  			StatusCode:    500,
   357  			Proto:         "HTTP/1.1",
   358  			ProtoMajor:    1,
   359  			ProtoMinor:    1,
   360  			ContentLength: int64(len(m.Body)),
   361  		}
   362  
   363  		for k, v := range m.Header {
   364  			rsp.Header.Set(k, v)
   365  		}
   366  
   367  		return rsp.Write(h.conn)
   368  	}
   369  
   370  	return nil
   371  }
   372  
   373  func (h *httpTransportSocket) Close() error {
   374  	h.mtx.Lock()
   375  	defer h.mtx.Unlock()
   376  	select {
   377  	case <-h.closed:
   378  		return nil
   379  	default:
   380  		// close the channel
   381  		close(h.closed)
   382  
   383  		// close the buffer
   384  		h.r.Body.Close()
   385  
   386  		// close the connection
   387  		if h.r.ProtoMajor == 1 {
   388  			return h.conn.Close()
   389  		}
   390  	}
   391  
   392  	return nil
   393  }
   394  
   395  func (h *httpTransportListener) Addr() string {
   396  	return h.listener.Addr().String()
   397  }
   398  
   399  func (h *httpTransportListener) Close() error {
   400  	return h.listener.Close()
   401  }
   402  
   403  func (h *httpTransportListener) Accept(fn func(Socket)) error {
   404  	// create handler mux
   405  	mux := http.NewServeMux()
   406  
   407  	// register our transport handler
   408  	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
   409  		var buf *bufio.ReadWriter
   410  		var con net.Conn
   411  
   412  		// read a regular request
   413  		if r.ProtoMajor == 1 {
   414  			b, err := io.ReadAll(r.Body)
   415  			if err != nil {
   416  				http.Error(w, err.Error(), http.StatusInternalServerError)
   417  				return
   418  			}
   419  			r.Body = io.NopCloser(bytes.NewReader(b))
   420  			// hijack the conn
   421  			hj, ok := w.(http.Hijacker)
   422  			if !ok {
   423  				// we're screwed
   424  				http.Error(w, "cannot serve conn", http.StatusInternalServerError)
   425  				return
   426  			}
   427  
   428  			conn, bufrw, err := hj.Hijack()
   429  			if err != nil {
   430  				http.Error(w, err.Error(), http.StatusInternalServerError)
   431  				return
   432  			}
   433  			defer conn.Close()
   434  			buf = bufrw
   435  			con = conn
   436  		}
   437  
   438  		// buffered reader
   439  		bufr := bufio.NewReader(r.Body)
   440  
   441  		// save the request
   442  		ch := make(chan *http.Request, 1)
   443  		ch <- r
   444  
   445  		// create a new transport socket
   446  		sock := &httpTransportSocket{
   447  			ht:     h.ht,
   448  			w:      w,
   449  			r:      r,
   450  			rw:     buf,
   451  			buf:    bufr,
   452  			ch:     ch,
   453  			conn:   con,
   454  			local:  h.Addr(),
   455  			remote: r.RemoteAddr,
   456  			closed: make(chan bool),
   457  		}
   458  
   459  		// execute the socket
   460  		fn(sock)
   461  	})
   462  
   463  	// get optional handlers
   464  	if h.ht.opts.Context != nil {
   465  		handlers, ok := h.ht.opts.Context.Value("http_handlers").(map[string]http.Handler)
   466  		if ok {
   467  			for pattern, handler := range handlers {
   468  				mux.Handle(pattern, handler)
   469  			}
   470  		}
   471  	}
   472  
   473  	// default http2 server
   474  	srv := &http.Server{
   475  		Handler: mux,
   476  	}
   477  
   478  	// insecure connection use h2c
   479  	if !(h.ht.opts.Secure || h.ht.opts.TLSConfig != nil) {
   480  		srv.Handler = h2c.NewHandler(mux, &http2.Server{})
   481  	}
   482  
   483  	// begin serving
   484  	return srv.Serve(h.listener)
   485  }
   486  
   487  func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) {
   488  	dopts := DialOptions{
   489  		Timeout: DefaultDialTimeout,
   490  	}
   491  
   492  	for _, opt := range opts {
   493  		opt(&dopts)
   494  	}
   495  
   496  	var conn net.Conn
   497  	var err error
   498  
   499  	// TODO: support dial option here rather than using internal config
   500  	if h.opts.Secure || h.opts.TLSConfig != nil {
   501  		config := h.opts.TLSConfig
   502  		if config == nil {
   503  			config = &tls.Config{
   504  				InsecureSkipVerify: true,
   505  			}
   506  		}
   507  		config.NextProtos = []string{"http/1.1"}
   508  		conn, err = newConn(func(addr string) (net.Conn, error) {
   509  			return tls.DialWithDialer(&net.Dialer{Timeout: dopts.Timeout}, "tcp", addr, config)
   510  		})(addr)
   511  	} else {
   512  		conn, err = newConn(func(addr string) (net.Conn, error) {
   513  			return net.DialTimeout("tcp", addr, dopts.Timeout)
   514  		})(addr)
   515  	}
   516  
   517  	if err != nil {
   518  		return nil, err
   519  	}
   520  
   521  	return &httpTransportClient{
   522  		ht:       h,
   523  		addr:     addr,
   524  		conn:     conn,
   525  		buff:     bufio.NewReader(conn),
   526  		dialOpts: dopts,
   527  		r:        make(chan *http.Request, 1),
   528  		local:    conn.LocalAddr().String(),
   529  		remote:   conn.RemoteAddr().String(),
   530  	}, nil
   531  }
   532  
   533  func (h *httpTransport) Listen(addr string, opts ...ListenOption) (Listener, error) {
   534  	var options ListenOptions
   535  	for _, o := range opts {
   536  		o(&options)
   537  	}
   538  
   539  	var l net.Listener
   540  	var err error
   541  
   542  	// TODO: support use of listen options
   543  	if h.opts.Secure || h.opts.TLSConfig != nil {
   544  		config := h.opts.TLSConfig
   545  
   546  		fn := func(addr string) (net.Listener, error) {
   547  			if config == nil {
   548  				hosts := []string{addr}
   549  
   550  				// check if its a valid host:port
   551  				if host, _, err := net.SplitHostPort(addr); err == nil {
   552  					if len(host) == 0 {
   553  						hosts = maddr.IPs()
   554  					} else {
   555  						hosts = []string{host}
   556  					}
   557  				}
   558  
   559  				// generate a certificate
   560  				cert, err := mls.Certificate(hosts...)
   561  				if err != nil {
   562  					return nil, err
   563  				}
   564  				config = &tls.Config{Certificates: []tls.Certificate{cert}}
   565  			}
   566  			return tls.Listen("tcp", addr, config)
   567  		}
   568  
   569  		l, err = mnet.Listen(addr, fn)
   570  	} else {
   571  		fn := func(addr string) (net.Listener, error) {
   572  			return net.Listen("tcp", addr)
   573  		}
   574  
   575  		l, err = mnet.Listen(addr, fn)
   576  	}
   577  
   578  	if err != nil {
   579  		return nil, err
   580  	}
   581  
   582  	return &httpTransportListener{
   583  		ht:       h,
   584  		listener: l,
   585  	}, nil
   586  }
   587  
   588  func (h *httpTransport) Init(opts ...Option) error {
   589  	for _, o := range opts {
   590  		o(&h.opts)
   591  	}
   592  	return nil
   593  }
   594  
   595  func (h *httpTransport) Options() Options {
   596  	return h.opts
   597  }
   598  
   599  func (h *httpTransport) String() string {
   600  	return "http"
   601  }
   602  
   603  func NewHTTPTransport(opts ...Option) *httpTransport {
   604  	var options Options
   605  	for _, o := range opts {
   606  		o(&options)
   607  	}
   608  	return &httpTransport{opts: options}
   609  }