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  }