gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/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 "gitee.com/liuxuezhan/go-micro-v1.18.0/util/addr" 17 "gitee.com/liuxuezhan/go-micro-v1.18.0/util/buf" 18 mnet "gitee.com/liuxuezhan/go-micro-v1.18.0/util/net" 19 mls "gitee.com/liuxuezhan/go-micro-v1.18.0/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) 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 196 if m.Header == nil { 197 m.Header = make(map[string]string) 198 } 199 200 // process http 1 201 if h.r.ProtoMajor == 1 { 202 // set timeout if its greater than 0 203 if h.ht.opts.Timeout > time.Duration(0) { 204 h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout)) 205 } 206 207 var r *http.Request 208 209 select { 210 // get first request 211 case r = <-h.ch: 212 // read next request 213 default: 214 rr, err := http.ReadRequest(h.rw.Reader) 215 if err != nil { 216 return err 217 } 218 r = rr 219 } 220 221 // read body 222 b, err := ioutil.ReadAll(r.Body) 223 if err != nil { 224 return err 225 } 226 227 // set body 228 r.Body.Close() 229 m.Body = b 230 231 // set headers 232 for k, v := range r.Header { 233 if len(v) > 0 { 234 m.Header[k] = v[0] 235 } else { 236 m.Header[k] = "" 237 } 238 } 239 240 // return early early 241 return nil 242 } 243 244 // only process if the socket is open 245 select { 246 case <-h.closed: 247 return io.EOF 248 default: 249 // no op 250 } 251 252 // processing http2 request 253 // read streaming body 254 255 // set max buffer size 256 // TODO: adjustable buffer size 257 buf := make([]byte, 4*1024*1024) 258 259 // read the request body 260 n, err := h.buf.Read(buf) 261 // not an eof error 262 if err != nil { 263 return err 264 } 265 266 // check if we have data 267 if n > 0 { 268 m.Body = buf[:n] 269 } 270 271 // set headers 272 for k, v := range h.r.Header { 273 if len(v) > 0 { 274 m.Header[k] = v[0] 275 } else { 276 m.Header[k] = "" 277 } 278 } 279 280 // set path 281 m.Header[":path"] = h.r.URL.Path 282 283 return nil 284 } 285 286 func (h *httpTransportSocket) Send(m *Message) error { 287 if h.r.ProtoMajor == 1 { 288 // make copy of header 289 hdr := make(http.Header) 290 for k, v := range h.r.Header { 291 hdr[k] = v 292 } 293 294 rsp := &http.Response{ 295 Header: hdr, 296 Body: ioutil.NopCloser(bytes.NewReader(m.Body)), 297 Status: "200 OK", 298 StatusCode: 200, 299 Proto: "HTTP/1.1", 300 ProtoMajor: 1, 301 ProtoMinor: 1, 302 ContentLength: int64(len(m.Body)), 303 } 304 305 for k, v := range m.Header { 306 rsp.Header.Set(k, v) 307 } 308 309 // set timeout if its greater than 0 310 if h.ht.opts.Timeout > time.Duration(0) { 311 h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout)) 312 } 313 314 return rsp.Write(h.conn) 315 } 316 317 // only process if the socket is open 318 select { 319 case <-h.closed: 320 return io.EOF 321 default: 322 // no op 323 } 324 325 // we need to lock to protect the write 326 h.mtx.RLock() 327 defer h.mtx.RUnlock() 328 329 // set headers 330 for k, v := range m.Header { 331 h.w.Header().Set(k, v) 332 } 333 334 // write request 335 _, err := h.w.Write(m.Body) 336 337 // flush the trailers 338 h.w.(http.Flusher).Flush() 339 340 return err 341 } 342 343 func (h *httpTransportSocket) error(m *Message) error { 344 if h.r.ProtoMajor == 1 { 345 rsp := &http.Response{ 346 Header: make(http.Header), 347 Body: ioutil.NopCloser(bytes.NewReader(m.Body)), 348 Status: "500 Internal Server Error", 349 StatusCode: 500, 350 Proto: "HTTP/1.1", 351 ProtoMajor: 1, 352 ProtoMinor: 1, 353 ContentLength: int64(len(m.Body)), 354 } 355 356 for k, v := range m.Header { 357 rsp.Header.Set(k, v) 358 } 359 360 return rsp.Write(h.conn) 361 } 362 363 return nil 364 } 365 366 func (h *httpTransportSocket) Close() error { 367 h.mtx.Lock() 368 defer h.mtx.Unlock() 369 select { 370 case <-h.closed: 371 return nil 372 default: 373 // close the channel 374 close(h.closed) 375 376 // close the buffer 377 h.r.Body.Close() 378 379 // close the connection 380 if h.r.ProtoMajor == 1 { 381 return h.conn.Close() 382 } 383 } 384 385 return nil 386 } 387 388 func (h *httpTransportListener) Addr() string { 389 return h.listener.Addr().String() 390 } 391 392 func (h *httpTransportListener) Close() error { 393 return h.listener.Close() 394 } 395 396 func (h *httpTransportListener) Accept(fn func(Socket)) error { 397 // create handler mux 398 mux := http.NewServeMux() 399 400 // register our transport handler 401 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 402 var buf *bufio.ReadWriter 403 var con net.Conn 404 405 // read a regular request 406 if r.ProtoMajor == 1 { 407 b, err := ioutil.ReadAll(r.Body) 408 if err != nil { 409 http.Error(w, err.Error(), http.StatusInternalServerError) 410 return 411 } 412 r.Body = ioutil.NopCloser(bytes.NewReader(b)) 413 // hijack the conn 414 hj, ok := w.(http.Hijacker) 415 if !ok { 416 // we're screwed 417 http.Error(w, "cannot serve conn", http.StatusInternalServerError) 418 return 419 } 420 421 conn, bufrw, err := hj.Hijack() 422 if err != nil { 423 http.Error(w, err.Error(), http.StatusInternalServerError) 424 return 425 } 426 defer conn.Close() 427 buf = bufrw 428 con = conn 429 } 430 431 // buffered reader 432 bufr := bufio.NewReader(r.Body) 433 434 // save the request 435 ch := make(chan *http.Request, 1) 436 ch <- r 437 438 // create a new transport socket 439 sock := &httpTransportSocket{ 440 ht: h.ht, 441 w: w, 442 r: r, 443 rw: buf, 444 buf: bufr, 445 ch: ch, 446 conn: con, 447 local: h.Addr(), 448 remote: r.RemoteAddr, 449 closed: make(chan bool), 450 } 451 452 // execute the socket 453 fn(sock) 454 }) 455 456 // get optional handlers 457 if h.ht.opts.Context != nil { 458 handlers, ok := h.ht.opts.Context.Value("http_handlers").(map[string]http.Handler) 459 if ok { 460 for pattern, handler := range handlers { 461 mux.Handle(pattern, handler) 462 } 463 } 464 } 465 466 // default http2 server 467 srv := &http.Server{ 468 Handler: mux, 469 } 470 471 // insecure connection use h2c 472 if !(h.ht.opts.Secure || h.ht.opts.TLSConfig != nil) { 473 srv.Handler = h2c.NewHandler(mux, &http2.Server{}) 474 } 475 476 // begin serving 477 return srv.Serve(h.listener) 478 } 479 480 func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) { 481 dopts := DialOptions{ 482 Timeout: DefaultDialTimeout, 483 } 484 485 for _, opt := range opts { 486 opt(&dopts) 487 } 488 489 var conn net.Conn 490 var err error 491 492 // TODO: support dial option here rather than using internal config 493 if h.opts.Secure || h.opts.TLSConfig != nil { 494 config := h.opts.TLSConfig 495 if config == nil { 496 config = &tls.Config{ 497 InsecureSkipVerify: true, 498 } 499 } 500 config.NextProtos = []string{"http/1.1"} 501 conn, err = newConn(func(addr string) (net.Conn, error) { 502 return tls.DialWithDialer(&net.Dialer{Timeout: dopts.Timeout}, "tcp", addr, config) 503 })(addr) 504 } else { 505 conn, err = newConn(func(addr string) (net.Conn, error) { 506 return net.DialTimeout("tcp", addr, dopts.Timeout) 507 })(addr) 508 } 509 510 if err != nil { 511 return nil, err 512 } 513 514 return &httpTransportClient{ 515 ht: h, 516 addr: addr, 517 conn: conn, 518 buff: bufio.NewReader(conn), 519 dialOpts: dopts, 520 r: make(chan *http.Request, 1), 521 local: conn.LocalAddr().String(), 522 remote: conn.RemoteAddr().String(), 523 }, nil 524 } 525 526 func (h *httpTransport) Listen(addr string, opts ...ListenOption) (Listener, error) { 527 var options ListenOptions 528 for _, o := range opts { 529 o(&options) 530 } 531 532 var l net.Listener 533 var err error 534 535 // TODO: support use of listen options 536 if h.opts.Secure || h.opts.TLSConfig != nil { 537 config := h.opts.TLSConfig 538 539 fn := func(addr string) (net.Listener, error) { 540 if config == nil { 541 hosts := []string{addr} 542 543 // check if its a valid host:port 544 if host, _, err := net.SplitHostPort(addr); err == nil { 545 if len(host) == 0 { 546 hosts = maddr.IPs() 547 } else { 548 hosts = []string{host} 549 } 550 } 551 552 // generate a certificate 553 cert, err := mls.Certificate(hosts...) 554 if err != nil { 555 return nil, err 556 } 557 config = &tls.Config{Certificates: []tls.Certificate{cert}} 558 } 559 return tls.Listen("tcp", addr, config) 560 } 561 562 l, err = mnet.Listen(addr, fn) 563 } else { 564 fn := func(addr string) (net.Listener, error) { 565 return net.Listen("tcp", addr) 566 } 567 568 l, err = mnet.Listen(addr, fn) 569 } 570 571 if err != nil { 572 return nil, err 573 } 574 575 return &httpTransportListener{ 576 ht: h, 577 listener: l, 578 }, nil 579 } 580 581 func (h *httpTransport) Init(opts ...Option) error { 582 for _, o := range opts { 583 o(&h.opts) 584 } 585 return nil 586 } 587 588 func (h *httpTransport) Options() Options { 589 return h.opts 590 } 591 592 func (h *httpTransport) String() string { 593 return "http" 594 } 595 596 func newHTTPTransport(opts ...Option) *httpTransport { 597 var options Options 598 for _, o := range opts { 599 o(&options) 600 } 601 return &httpTransport{opts: options} 602 }