go-micro.dev/v5@v5.12.0/transport/http_socket.go (about)

     1  package transport
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"io"
     7  	"net"
     8  	"net/http"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  type httpTransportSocket struct {
    16  	w http.ResponseWriter
    17  
    18  	// the hijacked when using http 1
    19  	conn net.Conn
    20  	ht   *httpTransport
    21  	r    *http.Request
    22  	rw   *bufio.ReadWriter
    23  
    24  	// for the first request
    25  	ch chan *http.Request
    26  
    27  	// h2 things
    28  	buf *bufio.Reader
    29  	// indicate if socket is closed
    30  	closed chan bool
    31  
    32  	// local/remote ip
    33  	local  string
    34  	remote string
    35  
    36  	mtx sync.RWMutex
    37  }
    38  
    39  func (h *httpTransportSocket) Local() string {
    40  	return h.local
    41  }
    42  
    43  func (h *httpTransportSocket) Remote() string {
    44  	return h.remote
    45  }
    46  
    47  func (h *httpTransportSocket) Recv(msg *Message) error {
    48  	if msg == nil {
    49  		return errors.New("message passed in is nil")
    50  	}
    51  
    52  	if msg.Header == nil {
    53  		msg.Header = make(map[string]string, len(h.r.Header))
    54  	}
    55  
    56  	if h.r.ProtoMajor == 1 {
    57  		return h.recvHTTP1(msg)
    58  	}
    59  
    60  	return h.recvHTTP2(msg)
    61  }
    62  
    63  func (h *httpTransportSocket) Send(msg *Message) error {
    64  	// we need to lock to protect the write
    65  	h.mtx.RLock()
    66  	defer h.mtx.RUnlock()
    67  
    68  	if h.r.ProtoMajor == 1 {
    69  		return h.sendHTTP1(msg)
    70  	}
    71  
    72  	return h.sendHTTP2(msg)
    73  }
    74  
    75  func (h *httpTransportSocket) Close() error {
    76  	h.mtx.Lock()
    77  	defer h.mtx.Unlock()
    78  
    79  	select {
    80  	case <-h.closed:
    81  		return nil
    82  	default:
    83  		// Close the channel
    84  		close(h.closed)
    85  
    86  		// Close the buffer
    87  		if err := h.r.Body.Close(); err != nil {
    88  			return err
    89  		}
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  func (h *httpTransportSocket) error(m *Message) error {
    96  	if h.r.ProtoMajor == 1 {
    97  		rsp := &http.Response{
    98  			Header:        make(http.Header),
    99  			Body:          io.NopCloser(bytes.NewReader(m.Body)),
   100  			Status:        "500 Internal Server Error",
   101  			StatusCode:    http.StatusInternalServerError,
   102  			Proto:         "HTTP/1.1",
   103  			ProtoMajor:    1,
   104  			ProtoMinor:    1,
   105  			ContentLength: int64(len(m.Body)),
   106  		}
   107  
   108  		for k, v := range m.Header {
   109  			rsp.Header.Set(k, v)
   110  		}
   111  
   112  		return rsp.Write(h.conn)
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  func (h *httpTransportSocket) recvHTTP1(msg *Message) error {
   119  	// set timeout if its greater than 0
   120  	if h.ht.opts.Timeout > time.Duration(0) {
   121  		if err := h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout)); err != nil {
   122  			return errors.Wrap(err, "failed to set deadline")
   123  		}
   124  	}
   125  
   126  	var req *http.Request
   127  
   128  	select {
   129  	// get first request
   130  	case req = <-h.ch:
   131  	// read next request
   132  	default:
   133  		rr, err := http.ReadRequest(h.rw.Reader)
   134  		if err != nil {
   135  			return errors.Wrap(err, "failed to read request")
   136  		}
   137  
   138  		req = rr
   139  	}
   140  
   141  	// read body
   142  	b, err := io.ReadAll(req.Body)
   143  	if err != nil {
   144  		return errors.Wrap(err, "failed to read body")
   145  	}
   146  
   147  	// set body
   148  	if err := req.Body.Close(); err != nil {
   149  		return errors.Wrap(err, "failed to close body")
   150  	}
   151  
   152  	msg.Body = b
   153  
   154  	// set headers
   155  	for k, v := range req.Header {
   156  		if len(v) > 0 {
   157  			msg.Header[k] = v[0]
   158  		} else {
   159  			msg.Header[k] = ""
   160  		}
   161  	}
   162  
   163  	// return early early
   164  	return nil
   165  }
   166  
   167  func (h *httpTransportSocket) recvHTTP2(msg *Message) error {
   168  	// only process if the socket is open
   169  	select {
   170  	case <-h.closed:
   171  		return io.EOF
   172  	default:
   173  	}
   174  
   175  	// buffer pool for reuse
   176  	var bufPool = getHTTP2BufPool()
   177  
   178  	// set max buffer size
   179  	s := h.ht.opts.BuffSizeH2
   180  	if s == 0 {
   181  		s = DefaultBufSizeH2
   182  	}
   183  
   184  	buf := bufPool.Get().([]byte)
   185  	if cap(buf) < s {
   186  		buf = make([]byte, s)
   187  	}
   188  	buf = buf[:s]
   189  
   190  	n, err := h.buf.Read(buf)
   191  	if err != nil {
   192  		bufPool.Put(buf)
   193  		return err
   194  	}
   195  
   196  	if n > 0 {
   197  		msg.Body = make([]byte, n)
   198  		copy(msg.Body, buf[:n])
   199  	}
   200  	bufPool.Put(buf)
   201  
   202  	for k, v := range h.r.Header {
   203  		if len(v) > 0 {
   204  			msg.Header[k] = v[0]
   205  		} else {
   206  			msg.Header[k] = ""
   207  		}
   208  	}
   209  
   210  	msg.Header[":path"] = h.r.URL.Path
   211  
   212  	return nil
   213  }
   214  
   215  func (h *httpTransportSocket) sendHTTP1(msg *Message) error {
   216  	// make copy of header
   217  	hdr := make(http.Header)
   218  	for k, v := range h.r.Header {
   219  		hdr[k] = v
   220  	}
   221  
   222  	rsp := &http.Response{
   223  		Header:        hdr,
   224  		Body:          io.NopCloser(bytes.NewReader(msg.Body)),
   225  		Status:        "200 OK",
   226  		StatusCode:    http.StatusOK,
   227  		Proto:         "HTTP/1.1",
   228  		ProtoMajor:    1,
   229  		ProtoMinor:    1,
   230  		ContentLength: int64(len(msg.Body)),
   231  	}
   232  
   233  	for k, v := range msg.Header {
   234  		rsp.Header.Set(k, v)
   235  	}
   236  
   237  	// set timeout if its greater than 0
   238  	if h.ht.opts.Timeout > time.Duration(0) {
   239  		if err := h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout)); err != nil {
   240  			return err
   241  		}
   242  	}
   243  
   244  	return rsp.Write(h.conn)
   245  }
   246  
   247  func (h *httpTransportSocket) sendHTTP2(msg *Message) error {
   248  	// only process if the socket is open
   249  	select {
   250  	case <-h.closed:
   251  		return io.EOF
   252  	default:
   253  	}
   254  
   255  	// set headers
   256  	for k, v := range msg.Header {
   257  		h.w.Header().Set(k, v)
   258  	}
   259  
   260  	// write request
   261  	_, err := h.w.Write(msg.Body)
   262  
   263  	// flush the trailers
   264  	h.w.(http.Flusher).Flush()
   265  
   266  	return err
   267  }