github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/rpc/http.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2015 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package rpc 26 27 import ( 28 "bytes" 29 "context" 30 "encoding/json" 31 "errors" 32 "fmt" 33 "io" 34 "io/ioutil" 35 "mime" 36 "net" 37 "net/http" 38 "strings" 39 "sync" 40 "time" 41 42 "github.com/ethereum/go-ethereum/log" 43 "github.com/rs/cors" 44 ) 45 46 const ( 47 contentType = "application/json" 48 maxRequestContentLength = 1024 * 128 49 ) 50 51 var nullAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0") 52 53 type httpConn struct { 54 client *http.Client 55 req *http.Request 56 closeOnce sync.Once 57 closed chan struct{} 58 } 59 60 //HTTPconn由客户特别处理。 61 func (hc *httpConn) LocalAddr() net.Addr { return nullAddr } 62 func (hc *httpConn) RemoteAddr() net.Addr { return nullAddr } 63 func (hc *httpConn) SetReadDeadline(time.Time) error { return nil } 64 func (hc *httpConn) SetWriteDeadline(time.Time) error { return nil } 65 func (hc *httpConn) SetDeadline(time.Time) error { return nil } 66 func (hc *httpConn) Write([]byte) (int, error) { panic("Write called") } 67 68 func (hc *httpConn) Read(b []byte) (int, error) { 69 <-hc.closed 70 return 0, io.EOF 71 } 72 73 func (hc *httpConn) Close() error { 74 hc.closeOnce.Do(func() { close(hc.closed) }) 75 return nil 76 } 77 78 //httpTimeouts表示HTTP RPC服务器的配置参数。 79 type HTTPTimeouts struct { 80 //readTimeout是读取整个 81 //请求,包括正文。 82 // 83 //因为readTimeout不允许处理程序按请求执行 84 //对每个请求主体可接受的截止日期或 85 //上传率,大多数用户更喜欢使用 86 //读取headerTimeout。两者都用是有效的。 87 ReadTimeout time.Duration 88 89 //WriteTimeout是超时前的最长持续时间 90 //写入响应。每当有新的 91 //请求的头被读取。和readTimeout一样,它没有 92 //让处理程序基于每个请求做出决策。 93 WriteTimeout time.Duration 94 95 //IdleTimeout是等待 96 //启用keep alives时的下一个请求。如果IdleTimeout 97 //为零,使用readTimeout的值。如果两者都是 98 //零,使用readHeaderTimeout。 99 IdleTimeout time.Duration 100 } 101 102 //DefaultHTTPTimeouts表示进一步使用的默认超时值 103 //未提供配置。 104 var DefaultHTTPTimeouts = HTTPTimeouts{ 105 ReadTimeout: 30 * time.Second, 106 WriteTimeout: 30 * time.Second, 107 IdleTimeout: 120 * time.Second, 108 } 109 110 //dialhttpwithclient创建通过HTTP连接到RPC服务器的新RPC客户端 111 //使用提供的HTTP客户端。 112 func DialHTTPWithClient(endpoint string, client *http.Client) (*Client, error) { 113 req, err := http.NewRequest(http.MethodPost, endpoint, nil) 114 if err != nil { 115 return nil, err 116 } 117 req.Header.Set("Content-Type", contentType) 118 req.Header.Set("Accept", contentType) 119 120 initctx := context.Background() 121 return newClient(initctx, func(context.Context) (net.Conn, error) { 122 return &httpConn{client: client, req: req, closed: make(chan struct{})}, nil 123 }) 124 } 125 126 //DialHTTP创建一个新的RPC客户端,通过HTTP连接到一个RPC服务器。 127 func DialHTTP(endpoint string) (*Client, error) { 128 return DialHTTPWithClient(endpoint, new(http.Client)) 129 } 130 131 func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}) error { 132 hc := c.writeConn.(*httpConn) 133 respBody, err := hc.doRequest(ctx, msg) 134 if respBody != nil { 135 defer respBody.Close() 136 } 137 138 if err != nil { 139 if respBody != nil { 140 buf := new(bytes.Buffer) 141 if _, err2 := buf.ReadFrom(respBody); err2 == nil { 142 return fmt.Errorf("%v %v", err, buf.String()) 143 } 144 } 145 return err 146 } 147 var respmsg jsonrpcMessage 148 if err := json.NewDecoder(respBody).Decode(&respmsg); err != nil { 149 return err 150 } 151 op.resp <- &respmsg 152 return nil 153 } 154 155 func (c *Client) sendBatchHTTP(ctx context.Context, op *requestOp, msgs []*jsonrpcMessage) error { 156 hc := c.writeConn.(*httpConn) 157 respBody, err := hc.doRequest(ctx, msgs) 158 if err != nil { 159 return err 160 } 161 defer respBody.Close() 162 var respmsgs []jsonrpcMessage 163 if err := json.NewDecoder(respBody).Decode(&respmsgs); err != nil { 164 return err 165 } 166 for i := 0; i < len(respmsgs); i++ { 167 op.resp <- &respmsgs[i] 168 } 169 return nil 170 } 171 172 func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadCloser, error) { 173 body, err := json.Marshal(msg) 174 if err != nil { 175 return nil, err 176 } 177 req := hc.req.WithContext(ctx) 178 req.Body = ioutil.NopCloser(bytes.NewReader(body)) 179 req.ContentLength = int64(len(body)) 180 181 resp, err := hc.client.Do(req) 182 if err != nil { 183 return nil, err 184 } 185 if resp.StatusCode < 200 || resp.StatusCode >= 300 { 186 return resp.Body, errors.New(resp.Status) 187 } 188 return resp.Body, nil 189 } 190 191 //httpreadwritenocloser使用nop close方法包装IO.reader和IO.writer。 192 type httpReadWriteNopCloser struct { 193 io.Reader 194 io.Writer 195 } 196 197 //CLOSE什么也不做,返回的总是零 198 func (t *httpReadWriteNopCloser) Close() error { 199 return nil 200 } 201 202 //new http server围绕API提供程序创建一个新的HTTP RPC服务器。 203 // 204 //已弃用:服务器实现http.handler 205 func NewHTTPServer(cors []string, vhosts []string, timeouts HTTPTimeouts, srv *Server) *http.Server { 206 //在主机处理程序中包装CORS处理程序 207 handler := newCorsHandler(srv, cors) 208 handler = newVHostHandler(vhosts, handler) 209 210 //确保超时值有意义 211 if timeouts.ReadTimeout < time.Second { 212 log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", DefaultHTTPTimeouts.ReadTimeout) 213 timeouts.ReadTimeout = DefaultHTTPTimeouts.ReadTimeout 214 } 215 if timeouts.WriteTimeout < time.Second { 216 log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", DefaultHTTPTimeouts.WriteTimeout) 217 timeouts.WriteTimeout = DefaultHTTPTimeouts.WriteTimeout 218 } 219 if timeouts.IdleTimeout < time.Second { 220 log.Warn("Sanitizing invalid HTTP idle timeout", "provided", timeouts.IdleTimeout, "updated", DefaultHTTPTimeouts.IdleTimeout) 221 timeouts.IdleTimeout = DefaultHTTPTimeouts.IdleTimeout 222 } 223 //捆绑并启动HTTP服务器 224 return &http.Server{ 225 Handler: handler, 226 ReadTimeout: timeouts.ReadTimeout, 227 WriteTimeout: timeouts.WriteTimeout, 228 IdleTimeout: timeouts.IdleTimeout, 229 } 230 } 231 232 //servehtp通过HTTP服务JSON-RPC请求。 233 func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 234 //允许远程健康检查(AWS)的哑空请求 235 if r.Method == http.MethodGet && r.ContentLength == 0 && r.URL.RawQuery == "" { 236 return 237 } 238 if code, err := validateRequest(r); err != nil { 239 http.Error(w, err.Error(), code) 240 return 241 } 242 //通过所有检查,创建一个直接从请求主体读取的编解码器 243 //直到并将响应写入w,然后命令服务器处理 244 //单一请求。 245 ctx := r.Context() 246 ctx = context.WithValue(ctx, "remote", r.RemoteAddr) 247 ctx = context.WithValue(ctx, "scheme", r.Proto) 248 ctx = context.WithValue(ctx, "local", r.Host) 249 250 body := io.LimitReader(r.Body, maxRequestContentLength) 251 codec := NewJSONCodec(&httpReadWriteNopCloser{body, w}) 252 defer codec.Close() 253 254 w.Header().Set("content-type", contentType) 255 srv.ServeSingleRequest(ctx, codec, OptionMethodInvocation) 256 } 257 258 //validateRequest返回非零响应代码和错误消息,如果 259 //请求无效。 260 func validateRequest(r *http.Request) (int, error) { 261 if r.Method == http.MethodPut || r.Method == http.MethodDelete { 262 return http.StatusMethodNotAllowed, errors.New("method not allowed") 263 } 264 if r.ContentLength > maxRequestContentLength { 265 err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxRequestContentLength) 266 return http.StatusRequestEntityTooLarge, err 267 } 268 mt, _, err := mime.ParseMediaType(r.Header.Get("content-type")) 269 if r.Method != http.MethodOptions && (err != nil || mt != contentType) { 270 err := fmt.Errorf("invalid content type, only %s is supported", contentType) 271 return http.StatusUnsupportedMediaType, err 272 } 273 return 0, nil 274 } 275 276 func newCorsHandler(srv *Server, allowedOrigins []string) http.Handler { 277 //如果用户未指定自定义CORS配置,则禁用CORS支持 278 if len(allowedOrigins) == 0 { 279 return srv 280 } 281 c := cors.New(cors.Options{ 282 AllowedOrigins: allowedOrigins, 283 AllowedMethods: []string{http.MethodPost, http.MethodGet}, 284 MaxAge: 600, 285 AllowedHeaders: []string{"*"}, 286 }) 287 return c.Handler(srv) 288 } 289 290 //virtualHostHandler是验证传入请求的主机头的处理程序。 291 //virtualHostHandler可以防止不使用CORS头的DNS重新绑定攻击, 292 //因为它们是针对RPC API的域请求。相反,我们可以在主机头上看到 293 //使用了哪个域,并根据白名单验证这一点。 294 type virtualHostHandler struct { 295 vhosts map[string]struct{} 296 next http.Handler 297 } 298 299 //servehtp通过http服务json-rpc请求,实现http.handler 300 func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 301 //如果没有设置r.host,我们可以继续服务,因为浏览器会设置主机头 302 if r.Host == "" { 303 h.next.ServeHTTP(w, r) 304 return 305 } 306 host, _, err := net.SplitHostPort(r.Host) 307 if err != nil { 308 //无效(冒号太多)或未指定端口 309 host = r.Host 310 } 311 if ipAddr := net.ParseIP(host); ipAddr != nil { 312 //这是一个IP地址,我们可以提供 313 h.next.ServeHTTP(w, r) 314 return 315 316 } 317 //不是IP地址,而是主机名。需要验证 318 if _, exist := h.vhosts["*"]; exist { 319 h.next.ServeHTTP(w, r) 320 return 321 } 322 if _, exist := h.vhosts[host]; exist { 323 h.next.ServeHTTP(w, r) 324 return 325 } 326 http.Error(w, "invalid host specified", http.StatusForbidden) 327 } 328 329 func newVHostHandler(vhosts []string, next http.Handler) http.Handler { 330 vhostMap := make(map[string]struct{}) 331 for _, allowedHost := range vhosts { 332 vhostMap[strings.ToLower(allowedHost)] = struct{}{} 333 } 334 return &virtualHostHandler{vhostMap, next} 335 }