github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/transport/http_client.go (about) 1 package transport 2 3 import ( 4 "bufio" 5 "bytes" 6 "errors" 7 "io" 8 "io/ioutil" 9 "net" 10 "net/http" 11 "net/url" 12 "sync" 13 "time" 14 15 "github.com/volts-dev/volts/internal/buf" 16 ) 17 18 type ( 19 httpTransportClient struct { 20 transport *HttpTransport 21 addr string 22 conn net.Conn 23 config DialConfig 24 once sync.Once 25 26 sync.RWMutex 27 28 // request must be stored for response processing 29 r chan *http.Request 30 bl []*http.Request 31 buff *bufio.Reader 32 33 // local/remote ip 34 local string 35 remote string 36 } 37 ) 38 39 func (t *httpTransportClient) Transport() ITransport { 40 return t.transport 41 } 42 43 func (t *httpTransportClient) Conn() net.Conn { 44 return t.conn 45 } 46 47 func (h *httpTransportClient) Local() string { 48 return h.local 49 } 50 51 func (h *httpTransportClient) Remote() string { 52 return h.remote 53 } 54 55 func (h *httpTransportClient) Send(m *Message) error { 56 header := make(http.Header) 57 58 for k, v := range m.Header { 59 header.Set(k, v) 60 } 61 62 b := buf.New(bytes.NewBuffer(m.Body)) 63 defer b.Close() 64 65 req := &http.Request{ 66 Method: "POST", 67 URL: &url.URL{ 68 Scheme: "http", 69 Host: h.addr, 70 }, 71 Header: header, 72 Body: b, 73 ContentLength: int64(b.Len()), 74 Host: h.addr, 75 } 76 77 h.Lock() 78 h.bl = append(h.bl, req) 79 select { 80 case h.r <- h.bl[0]: 81 h.bl = h.bl[1:] 82 default: 83 } 84 h.Unlock() 85 86 // set timeout if its greater than 0 87 if h.transport.config.WriteTimeout > time.Duration(0) { 88 h.conn.SetDeadline(time.Now().Add(h.transport.config.WriteTimeout)) 89 } 90 91 return req.Write(h.conn) 92 } 93 94 func (h *httpTransportClient) Recv(m *Message) error { 95 if m == nil { 96 return errors.New("message passed in is nil") 97 } 98 99 var r *http.Request 100 if !h.config.Stream { 101 rc, ok := <-h.r 102 if !ok { 103 return io.EOF 104 } 105 r = rc 106 } 107 108 // set timeout if its greater than 0 109 if h.transport.config.ReadTimeout > time.Duration(0) { 110 h.conn.SetDeadline(time.Now().Add(h.transport.config.ReadTimeout)) 111 } 112 113 rsp, err := http.ReadResponse(h.buff, r) 114 if err != nil { 115 return err 116 } 117 defer rsp.Body.Close() 118 119 b, err := ioutil.ReadAll(rsp.Body) 120 if err != nil { 121 return err 122 } 123 124 if rsp.StatusCode != 200 { 125 return errors.New(rsp.Status + ": " + string(b)) 126 } 127 128 m.Body = b 129 130 if m.Header == nil { 131 m.Header = make(map[string]string, len(rsp.Header)) 132 } 133 134 for k, v := range rsp.Header { 135 if len(v) > 0 { 136 m.Header[k] = v[0] 137 } else { 138 m.Header[k] = "" 139 } 140 } 141 142 return nil 143 } 144 145 func (h *httpTransportClient) Close() error { 146 h.once.Do(func() { 147 h.Lock() 148 h.buff.Reset(nil) 149 h.Unlock() 150 close(h.r) 151 }) 152 return h.conn.Close() 153 }