github.com/micro/go-micro/v2@v2.9.1/transport/http_transport.go (about)

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