github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/rpc/http.go (about)

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