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 }