github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/network/transport/http/http.go (about)

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