gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/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 "gitee.com/liuxuezhan/go-micro-v1.18.0/util/addr"
    17  	"gitee.com/liuxuezhan/go-micro-v1.18.0/util/buf"
    18  	mnet "gitee.com/liuxuezhan/go-micro-v1.18.0/util/net"
    19  	mls "gitee.com/liuxuezhan/go-micro-v1.18.0/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)
   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  
   196  	if m.Header == nil {
   197  		m.Header = make(map[string]string)
   198  	}
   199  
   200  	// process http 1
   201  	if h.r.ProtoMajor == 1 {
   202  		// set timeout if its greater than 0
   203  		if h.ht.opts.Timeout > time.Duration(0) {
   204  			h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
   205  		}
   206  
   207  		var r *http.Request
   208  
   209  		select {
   210  		// get first request
   211  		case r = <-h.ch:
   212  		// read next request
   213  		default:
   214  			rr, err := http.ReadRequest(h.rw.Reader)
   215  			if err != nil {
   216  				return err
   217  			}
   218  			r = rr
   219  		}
   220  
   221  		// read body
   222  		b, err := ioutil.ReadAll(r.Body)
   223  		if err != nil {
   224  			return err
   225  		}
   226  
   227  		// set body
   228  		r.Body.Close()
   229  		m.Body = b
   230  
   231  		// set headers
   232  		for k, v := range r.Header {
   233  			if len(v) > 0 {
   234  				m.Header[k] = v[0]
   235  			} else {
   236  				m.Header[k] = ""
   237  			}
   238  		}
   239  
   240  		// return early early
   241  		return nil
   242  	}
   243  
   244  	// only process if the socket is open
   245  	select {
   246  	case <-h.closed:
   247  		return io.EOF
   248  	default:
   249  		// no op
   250  	}
   251  
   252  	// processing http2 request
   253  	// read streaming body
   254  
   255  	// set max buffer size
   256  	// TODO: adjustable buffer size
   257  	buf := make([]byte, 4*1024*1024)
   258  
   259  	// read the request body
   260  	n, err := h.buf.Read(buf)
   261  	// not an eof error
   262  	if err != nil {
   263  		return err
   264  	}
   265  
   266  	// check if we have data
   267  	if n > 0 {
   268  		m.Body = buf[:n]
   269  	}
   270  
   271  	// set headers
   272  	for k, v := range h.r.Header {
   273  		if len(v) > 0 {
   274  			m.Header[k] = v[0]
   275  		} else {
   276  			m.Header[k] = ""
   277  		}
   278  	}
   279  
   280  	// set path
   281  	m.Header[":path"] = h.r.URL.Path
   282  
   283  	return nil
   284  }
   285  
   286  func (h *httpTransportSocket) Send(m *Message) error {
   287  	if h.r.ProtoMajor == 1 {
   288  		// make copy of header
   289  		hdr := make(http.Header)
   290  		for k, v := range h.r.Header {
   291  			hdr[k] = v
   292  		}
   293  
   294  		rsp := &http.Response{
   295  			Header:        hdr,
   296  			Body:          ioutil.NopCloser(bytes.NewReader(m.Body)),
   297  			Status:        "200 OK",
   298  			StatusCode:    200,
   299  			Proto:         "HTTP/1.1",
   300  			ProtoMajor:    1,
   301  			ProtoMinor:    1,
   302  			ContentLength: int64(len(m.Body)),
   303  		}
   304  
   305  		for k, v := range m.Header {
   306  			rsp.Header.Set(k, v)
   307  		}
   308  
   309  		// set timeout if its greater than 0
   310  		if h.ht.opts.Timeout > time.Duration(0) {
   311  			h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
   312  		}
   313  
   314  		return rsp.Write(h.conn)
   315  	}
   316  
   317  	// only process if the socket is open
   318  	select {
   319  	case <-h.closed:
   320  		return io.EOF
   321  	default:
   322  		// no op
   323  	}
   324  
   325  	// we need to lock to protect the write
   326  	h.mtx.RLock()
   327  	defer h.mtx.RUnlock()
   328  
   329  	// set headers
   330  	for k, v := range m.Header {
   331  		h.w.Header().Set(k, v)
   332  	}
   333  
   334  	// write request
   335  	_, err := h.w.Write(m.Body)
   336  
   337  	// flush the trailers
   338  	h.w.(http.Flusher).Flush()
   339  
   340  	return err
   341  }
   342  
   343  func (h *httpTransportSocket) error(m *Message) error {
   344  	if h.r.ProtoMajor == 1 {
   345  		rsp := &http.Response{
   346  			Header:        make(http.Header),
   347  			Body:          ioutil.NopCloser(bytes.NewReader(m.Body)),
   348  			Status:        "500 Internal Server Error",
   349  			StatusCode:    500,
   350  			Proto:         "HTTP/1.1",
   351  			ProtoMajor:    1,
   352  			ProtoMinor:    1,
   353  			ContentLength: int64(len(m.Body)),
   354  		}
   355  
   356  		for k, v := range m.Header {
   357  			rsp.Header.Set(k, v)
   358  		}
   359  
   360  		return rsp.Write(h.conn)
   361  	}
   362  
   363  	return nil
   364  }
   365  
   366  func (h *httpTransportSocket) Close() error {
   367  	h.mtx.Lock()
   368  	defer h.mtx.Unlock()
   369  	select {
   370  	case <-h.closed:
   371  		return nil
   372  	default:
   373  		// close the channel
   374  		close(h.closed)
   375  
   376  		// close the buffer
   377  		h.r.Body.Close()
   378  
   379  		// close the connection
   380  		if h.r.ProtoMajor == 1 {
   381  			return h.conn.Close()
   382  		}
   383  	}
   384  
   385  	return nil
   386  }
   387  
   388  func (h *httpTransportListener) Addr() string {
   389  	return h.listener.Addr().String()
   390  }
   391  
   392  func (h *httpTransportListener) Close() error {
   393  	return h.listener.Close()
   394  }
   395  
   396  func (h *httpTransportListener) Accept(fn func(Socket)) error {
   397  	// create handler mux
   398  	mux := http.NewServeMux()
   399  
   400  	// register our transport handler
   401  	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
   402  		var buf *bufio.ReadWriter
   403  		var con net.Conn
   404  
   405  		// read a regular request
   406  		if r.ProtoMajor == 1 {
   407  			b, err := ioutil.ReadAll(r.Body)
   408  			if err != nil {
   409  				http.Error(w, err.Error(), http.StatusInternalServerError)
   410  				return
   411  			}
   412  			r.Body = ioutil.NopCloser(bytes.NewReader(b))
   413  			// hijack the conn
   414  			hj, ok := w.(http.Hijacker)
   415  			if !ok {
   416  				// we're screwed
   417  				http.Error(w, "cannot serve conn", http.StatusInternalServerError)
   418  				return
   419  			}
   420  
   421  			conn, bufrw, err := hj.Hijack()
   422  			if err != nil {
   423  				http.Error(w, err.Error(), http.StatusInternalServerError)
   424  				return
   425  			}
   426  			defer conn.Close()
   427  			buf = bufrw
   428  			con = conn
   429  		}
   430  
   431  		// buffered reader
   432  		bufr := bufio.NewReader(r.Body)
   433  
   434  		// save the request
   435  		ch := make(chan *http.Request, 1)
   436  		ch <- r
   437  
   438  		// create a new transport socket
   439  		sock := &httpTransportSocket{
   440  			ht:     h.ht,
   441  			w:      w,
   442  			r:      r,
   443  			rw:     buf,
   444  			buf:    bufr,
   445  			ch:     ch,
   446  			conn:   con,
   447  			local:  h.Addr(),
   448  			remote: r.RemoteAddr,
   449  			closed: make(chan bool),
   450  		}
   451  
   452  		// execute the socket
   453  		fn(sock)
   454  	})
   455  
   456  	// get optional handlers
   457  	if h.ht.opts.Context != nil {
   458  		handlers, ok := h.ht.opts.Context.Value("http_handlers").(map[string]http.Handler)
   459  		if ok {
   460  			for pattern, handler := range handlers {
   461  				mux.Handle(pattern, handler)
   462  			}
   463  		}
   464  	}
   465  
   466  	// default http2 server
   467  	srv := &http.Server{
   468  		Handler: mux,
   469  	}
   470  
   471  	// insecure connection use h2c
   472  	if !(h.ht.opts.Secure || h.ht.opts.TLSConfig != nil) {
   473  		srv.Handler = h2c.NewHandler(mux, &http2.Server{})
   474  	}
   475  
   476  	// begin serving
   477  	return srv.Serve(h.listener)
   478  }
   479  
   480  func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) {
   481  	dopts := DialOptions{
   482  		Timeout: DefaultDialTimeout,
   483  	}
   484  
   485  	for _, opt := range opts {
   486  		opt(&dopts)
   487  	}
   488  
   489  	var conn net.Conn
   490  	var err error
   491  
   492  	// TODO: support dial option here rather than using internal config
   493  	if h.opts.Secure || h.opts.TLSConfig != nil {
   494  		config := h.opts.TLSConfig
   495  		if config == nil {
   496  			config = &tls.Config{
   497  				InsecureSkipVerify: true,
   498  			}
   499  		}
   500  		config.NextProtos = []string{"http/1.1"}
   501  		conn, err = newConn(func(addr string) (net.Conn, error) {
   502  			return tls.DialWithDialer(&net.Dialer{Timeout: dopts.Timeout}, "tcp", addr, config)
   503  		})(addr)
   504  	} else {
   505  		conn, err = newConn(func(addr string) (net.Conn, error) {
   506  			return net.DialTimeout("tcp", addr, dopts.Timeout)
   507  		})(addr)
   508  	}
   509  
   510  	if err != nil {
   511  		return nil, err
   512  	}
   513  
   514  	return &httpTransportClient{
   515  		ht:       h,
   516  		addr:     addr,
   517  		conn:     conn,
   518  		buff:     bufio.NewReader(conn),
   519  		dialOpts: dopts,
   520  		r:        make(chan *http.Request, 1),
   521  		local:    conn.LocalAddr().String(),
   522  		remote:   conn.RemoteAddr().String(),
   523  	}, nil
   524  }
   525  
   526  func (h *httpTransport) Listen(addr string, opts ...ListenOption) (Listener, error) {
   527  	var options ListenOptions
   528  	for _, o := range opts {
   529  		o(&options)
   530  	}
   531  
   532  	var l net.Listener
   533  	var err error
   534  
   535  	// TODO: support use of listen options
   536  	if h.opts.Secure || h.opts.TLSConfig != nil {
   537  		config := h.opts.TLSConfig
   538  
   539  		fn := func(addr string) (net.Listener, error) {
   540  			if config == nil {
   541  				hosts := []string{addr}
   542  
   543  				// check if its a valid host:port
   544  				if host, _, err := net.SplitHostPort(addr); err == nil {
   545  					if len(host) == 0 {
   546  						hosts = maddr.IPs()
   547  					} else {
   548  						hosts = []string{host}
   549  					}
   550  				}
   551  
   552  				// generate a certificate
   553  				cert, err := mls.Certificate(hosts...)
   554  				if err != nil {
   555  					return nil, err
   556  				}
   557  				config = &tls.Config{Certificates: []tls.Certificate{cert}}
   558  			}
   559  			return tls.Listen("tcp", addr, config)
   560  		}
   561  
   562  		l, err = mnet.Listen(addr, fn)
   563  	} else {
   564  		fn := func(addr string) (net.Listener, error) {
   565  			return net.Listen("tcp", addr)
   566  		}
   567  
   568  		l, err = mnet.Listen(addr, fn)
   569  	}
   570  
   571  	if err != nil {
   572  		return nil, err
   573  	}
   574  
   575  	return &httpTransportListener{
   576  		ht:       h,
   577  		listener: l,
   578  	}, nil
   579  }
   580  
   581  func (h *httpTransport) Init(opts ...Option) error {
   582  	for _, o := range opts {
   583  		o(&h.opts)
   584  	}
   585  	return nil
   586  }
   587  
   588  func (h *httpTransport) Options() Options {
   589  	return h.opts
   590  }
   591  
   592  func (h *httpTransport) String() string {
   593  	return "http"
   594  }
   595  
   596  func newHTTPTransport(opts ...Option) *httpTransport {
   597  	var options Options
   598  	for _, o := range opts {
   599  		o(&options)
   600  	}
   601  	return &httpTransport{opts: options}
   602  }