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 }