go-micro.dev/v5@v5.12.0/transport/http_listener.go (about) 1 package transport 2 3 import ( 4 "bufio" 5 "bytes" 6 "io" 7 "net" 8 "net/http" 9 "time" 10 11 log "go-micro.dev/v5/logger" 12 13 "golang.org/x/net/http2" 14 "golang.org/x/net/http2/h2c" 15 ) 16 17 type httpTransportListener struct { 18 ht *httpTransport 19 listener net.Listener 20 } 21 22 func (h *httpTransportListener) Addr() string { 23 return h.listener.Addr().String() 24 } 25 26 func (h *httpTransportListener) Close() error { 27 return h.listener.Close() 28 } 29 30 func (h *httpTransportListener) Accept(fn func(Socket)) error { 31 // Create handler mux 32 // TODO: see if we should make a plugin out of the mux 33 mux := http.NewServeMux() 34 35 // Register our transport handler 36 mux.HandleFunc("/", h.newHandler(fn)) 37 38 // Get optional handlers 39 // TODO: This needs to be documented clearer, and examples provided 40 if h.ht.opts.Context != nil { 41 handlers, ok := h.ht.opts.Context.Value("http_handlers").(map[string]http.Handler) 42 if ok { 43 for pattern, handler := range handlers { 44 mux.Handle(pattern, handler) 45 } 46 } 47 } 48 49 // Server ONLY supports HTTP1 + H2C 50 srv := &http.Server{ 51 Handler: mux, 52 ReadHeaderTimeout: time.Second * 5, 53 } 54 55 // insecure connection use h2c 56 if !(h.ht.opts.Secure || h.ht.opts.TLSConfig != nil) { 57 srv.Handler = h2c.NewHandler(mux, &http2.Server{}) 58 } 59 60 return srv.Serve(h.listener) 61 } 62 63 // newHandler creates a new HTTP transport handler passed to the mux. 64 func (h *httpTransportListener) newHandler(serveConn func(Socket)) func(rsp http.ResponseWriter, req *http.Request) { 65 logger := h.ht.opts.Logger 66 67 return func(rsp http.ResponseWriter, req *http.Request) { 68 var ( 69 buf *bufio.ReadWriter 70 con net.Conn 71 ) 72 73 // HTTP1: read a regular request 74 if req.ProtoMajor == 1 { 75 b, err := io.ReadAll(req.Body) 76 if err != nil { 77 http.Error(rsp, err.Error(), http.StatusInternalServerError) 78 return 79 } 80 81 req.Body = io.NopCloser(bytes.NewReader(b)) 82 83 // Hijack the conn 84 // We also don't close the connection here, as it will be closed by 85 // the httpTransportSocket 86 hj, ok := rsp.(http.Hijacker) 87 if !ok { 88 // We're screwed 89 http.Error(rsp, "cannot serve conn", http.StatusInternalServerError) 90 return 91 } 92 93 conn, bufrw, err := hj.Hijack() 94 if err != nil { 95 http.Error(rsp, err.Error(), http.StatusInternalServerError) 96 return 97 } 98 defer func() { 99 if err := conn.Close(); err != nil { 100 logger.Logf(log.ErrorLevel, "Failed to close TCP connection: %v", err) 101 } 102 }() 103 104 buf = bufrw 105 con = conn 106 } 107 108 // Buffered reader 109 bufr := bufio.NewReader(req.Body) 110 111 // Save the request 112 ch := make(chan *http.Request, 1) 113 ch <- req 114 115 // Create a new transport socket 116 sock := &httpTransportSocket{ 117 ht: h.ht, 118 w: rsp, 119 r: req, 120 rw: buf, 121 buf: bufr, 122 ch: ch, 123 conn: con, 124 local: h.Addr(), 125 remote: req.RemoteAddr, 126 closed: make(chan bool), 127 } 128 129 // Execute the socket 130 serveConn(sock) 131 } 132 }