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