github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/rpc/http.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-wtc library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-wtc library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rpc 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "net" 27 "net/http" 28 "sync" 29 "time" 30 31 "github.com/rs/cors" 32 ) 33 34 const ( 35 maxHTTPRequestContentLength = 1024 * 128 36 ) 37 38 var nullAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0") 39 40 type httpConn struct { 41 client *http.Client 42 req *http.Request 43 closeOnce sync.Once 44 closed chan struct{} 45 } 46 47 // httpConn is treated specially by Client. 48 func (hc *httpConn) LocalAddr() net.Addr { return nullAddr } 49 func (hc *httpConn) RemoteAddr() net.Addr { return nullAddr } 50 func (hc *httpConn) SetReadDeadline(time.Time) error { return nil } 51 func (hc *httpConn) SetWriteDeadline(time.Time) error { return nil } 52 func (hc *httpConn) SetDeadline(time.Time) error { return nil } 53 func (hc *httpConn) Write([]byte) (int, error) { panic("Write called") } 54 55 func (hc *httpConn) Read(b []byte) (int, error) { 56 <-hc.closed 57 return 0, io.EOF 58 } 59 60 func (hc *httpConn) Close() error { 61 hc.closeOnce.Do(func() { close(hc.closed) }) 62 return nil 63 } 64 65 // DialHTTP creates a new RPC clients that connection to an RPC server over HTTP. 66 func DialHTTP(endpoint string) (*Client, error) { 67 req, err := http.NewRequest("POST", endpoint, nil) 68 if err != nil { 69 return nil, err 70 } 71 req.Header.Set("Content-Type", "application/json") 72 req.Header.Set("Accept", "application/json") 73 74 initctx := context.Background() 75 return newClient(initctx, func(context.Context) (net.Conn, error) { 76 return &httpConn{client: new(http.Client), req: req, closed: make(chan struct{})}, nil 77 }) 78 } 79 80 func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}) error { 81 hc := c.writeConn.(*httpConn) 82 respBody, err := hc.doRequest(ctx, msg) 83 if err != nil { 84 return err 85 } 86 defer respBody.Close() 87 var respmsg jsonrpcMessage 88 if err := json.NewDecoder(respBody).Decode(&respmsg); err != nil { 89 return err 90 } 91 op.resp <- &respmsg 92 return nil 93 } 94 95 func (c *Client) sendBatchHTTP(ctx context.Context, op *requestOp, msgs []*jsonrpcMessage) error { 96 hc := c.writeConn.(*httpConn) 97 respBody, err := hc.doRequest(ctx, msgs) 98 if err != nil { 99 return err 100 } 101 defer respBody.Close() 102 var respmsgs []jsonrpcMessage 103 if err := json.NewDecoder(respBody).Decode(&respmsgs); err != nil { 104 return err 105 } 106 for i := 0; i < len(respmsgs); i++ { 107 op.resp <- &respmsgs[i] 108 } 109 return nil 110 } 111 112 func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadCloser, error) { 113 body, err := json.Marshal(msg) 114 if err != nil { 115 return nil, err 116 } 117 req := hc.req.WithContext(ctx) 118 req.Body = ioutil.NopCloser(bytes.NewReader(body)) 119 req.ContentLength = int64(len(body)) 120 121 resp, err := hc.client.Do(req) 122 if err != nil { 123 return nil, err 124 } 125 return resp.Body, nil 126 } 127 128 // httpReadWriteNopCloser wraps a io.Reader and io.Writer with a NOP Close method. 129 type httpReadWriteNopCloser struct { 130 io.Reader 131 io.Writer 132 } 133 134 // Close does nothing and returns always nil 135 func (t *httpReadWriteNopCloser) Close() error { 136 return nil 137 } 138 139 // NewHTTPServer creates a new HTTP RPC server around an API provider. 140 // 141 // Deprecated: Server implements http.Handler 142 func NewHTTPServer(cors []string, srv *Server) *http.Server { 143 return &http.Server{Handler: newCorsHandler(srv, cors)} 144 } 145 146 // ServeHTTP serves JSON-RPC requests over HTTP. 147 func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 148 if r.ContentLength > maxHTTPRequestContentLength { 149 http.Error(w, 150 fmt.Sprintf("content length too large (%d>%d)", r.ContentLength, maxHTTPRequestContentLength), 151 http.StatusRequestEntityTooLarge) 152 return 153 } 154 w.Header().Set("content-type", "application/json") 155 156 // create a codec that reads direct from the request body until 157 // EOF and writes the response to w and order the server to process 158 // a single request. 159 codec := NewJSONCodec(&httpReadWriteNopCloser{r.Body, w}) 160 defer codec.Close() 161 srv.ServeSingleRequest(codec, OptionMethodInvocation) 162 } 163 164 func newCorsHandler(srv *Server, allowedOrigins []string) http.Handler { 165 // disable CORS support if user has not specified a custom CORS configuration 166 if len(allowedOrigins) == 0 { 167 return srv 168 } 169 170 c := cors.New(cors.Options{ 171 AllowedOrigins: allowedOrigins, 172 AllowedMethods: []string{"POST", "GET"}, 173 MaxAge: 600, 174 AllowedHeaders: []string{"*"}, 175 }) 176 return c.Handler(srv) 177 }