diff options
Diffstat (limited to 'rpc')
-rw-r--r-- | rpc/client.go | 2 | ||||
-rw-r--r-- | rpc/client_context_go1.4.go | 60 | ||||
-rw-r--r-- | rpc/client_context_go1.5.go | 61 | ||||
-rw-r--r-- | rpc/client_context_go1.6.go | 55 | ||||
-rw-r--r-- | rpc/client_context_go1.7.go | 51 | ||||
-rw-r--r-- | rpc/client_example_test.go | 2 | ||||
-rw-r--r-- | rpc/client_test.go | 6 | ||||
-rw-r--r-- | rpc/http.go | 18 | ||||
-rw-r--r-- | rpc/inproc.go | 3 | ||||
-rw-r--r-- | rpc/ipc.go | 3 | ||||
-rw-r--r-- | rpc/ipc_unix.go | 3 | ||||
-rw-r--r-- | rpc/ipc_windows.go | 2 | ||||
-rw-r--r-- | rpc/server.go | 49 | ||||
-rw-r--r-- | rpc/server_test.go | 3 | ||||
-rw-r--r-- | rpc/subscription.go | 3 | ||||
-rw-r--r-- | rpc/subscription_test.go | 3 | ||||
-rw-r--r-- | rpc/utils.go | 3 | ||||
-rw-r--r-- | rpc/websocket.go | 25 |
18 files changed, 70 insertions, 282 deletions
diff --git a/rpc/client.go b/rpc/client.go index 78a6fe789..2c35ba54a 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -19,6 +19,7 @@ package rpc import ( "bytes" "container/list" + "context" "encoding/json" "errors" "fmt" @@ -31,7 +32,6 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - "golang.org/x/net/context" ) var ( diff --git a/rpc/client_context_go1.4.go b/rpc/client_context_go1.4.go deleted file mode 100644 index ac956a17d..000000000 --- a/rpc/client_context_go1.4.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -// +build !go1.5 - -package rpc - -import ( - "net" - "net/http" - "time" - - "golang.org/x/net/context" -) - -// In older versions of Go (below 1.5), dials cannot be canceled -// via a channel or context. The context deadline can still applied. - -// contextDialer returns a dialer that applies the deadline value from the given context. -func contextDialer(ctx context.Context) *net.Dialer { - dialer := &net.Dialer{KeepAlive: tcpKeepAliveInterval} - if deadline, ok := ctx.Deadline(); ok { - dialer.Deadline = deadline - } else { - dialer.Deadline = time.Now().Add(defaultDialTimeout) - } - return dialer -} - -// dialContext connects to the given address, aborting the dial if ctx is canceled. -func dialContext(ctx context.Context, network, addr string) (net.Conn, error) { - return contextDialer(ctx).Dial(network, addr) -} - -// requestWithContext copies req, adding the cancelation channel and deadline from ctx. -func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) { - // Set Timeout on the client if the context has a deadline. - // Note that there is no default timeout (unlike in contextDialer) because - // the timeout applies to the entire request, including reads from body. - if deadline, ok := ctx.Deadline(); ok { - c2 := *c - c2.Timeout = deadline.Sub(time.Now()) - c = &c2 - } - req2 := *req - return c, &req2 -} diff --git a/rpc/client_context_go1.5.go b/rpc/client_context_go1.5.go deleted file mode 100644 index 4a007d9f8..000000000 --- a/rpc/client_context_go1.5.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -// +build go1.5,!go1.6 - -package rpc - -import ( - "net" - "net/http" - "time" - - "golang.org/x/net/context" -) - -// In Go 1.5, dials cannot be canceled via a channel or context. The context deadline can -// still be applied. Go 1.5 adds the ability to cancel HTTP requests via a channel. - -// contextDialer returns a dialer that applies the deadline value from the given context. -func contextDialer(ctx context.Context) *net.Dialer { - dialer := &net.Dialer{KeepAlive: tcpKeepAliveInterval} - if deadline, ok := ctx.Deadline(); ok { - dialer.Deadline = deadline - } else { - dialer.Deadline = time.Now().Add(defaultDialTimeout) - } - return dialer -} - -// dialContext connects to the given address, aborting the dial if ctx is canceled. -func dialContext(ctx context.Context, network, addr string) (net.Conn, error) { - return contextDialer(ctx).Dial(network, addr) -} - -// requestWithContext copies req, adding the cancelation channel and deadline from ctx. -func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) { - // Set Timeout on the client if the context has a deadline. - // Note that there is no default timeout (unlike in contextDialer) because - // the timeout applies to the entire request, including reads from body. - if deadline, ok := ctx.Deadline(); ok { - c2 := *c - c2.Timeout = deadline.Sub(time.Now()) - c = &c2 - } - req2 := *req - req2.Cancel = ctx.Done() - return c, &req2 -} diff --git a/rpc/client_context_go1.6.go b/rpc/client_context_go1.6.go deleted file mode 100644 index 67777ddc6..000000000 --- a/rpc/client_context_go1.6.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -// +build go1.6,!go1.7 - -package rpc - -import ( - "net" - "net/http" - "time" - - "golang.org/x/net/context" -) - -// In Go 1.6, net.Dialer gained the ability to cancel via a channel. - -// contextDialer returns a dialer that applies the deadline value from the given context. -func contextDialer(ctx context.Context) *net.Dialer { - dialer := &net.Dialer{Cancel: ctx.Done(), KeepAlive: tcpKeepAliveInterval} - if deadline, ok := ctx.Deadline(); ok { - dialer.Deadline = deadline - } else { - dialer.Deadline = time.Now().Add(defaultDialTimeout) - } - return dialer -} - -// dialContext connects to the given address, aborting the dial if ctx is canceled. -func dialContext(ctx context.Context, network, addr string) (net.Conn, error) { - return contextDialer(ctx).Dial(network, addr) -} - -// requestWithContext copies req, adding the cancelation channel and deadline from ctx. -func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) { - // We set Timeout on the client for Go <= 1.5. There - // is no need to do that here because the dial will be canceled - // by package http. - req2 := *req - req2.Cancel = ctx.Done() - return c, &req2 -} diff --git a/rpc/client_context_go1.7.go b/rpc/client_context_go1.7.go deleted file mode 100644 index 56ce12ab8..000000000 --- a/rpc/client_context_go1.7.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -// +build go1.7 - -package rpc - -import ( - "context" - "net" - "net/http" - "time" -) - -// In Go 1.7, context moved into the standard library and support -// for cancelation via context was added to net.Dialer and http.Request. - -// contextDialer returns a dialer that applies the deadline value from the given context. -func contextDialer(ctx context.Context) *net.Dialer { - dialer := &net.Dialer{Cancel: ctx.Done(), KeepAlive: tcpKeepAliveInterval} - if deadline, ok := ctx.Deadline(); ok { - dialer.Deadline = deadline - } else { - dialer.Deadline = time.Now().Add(defaultDialTimeout) - } - return dialer -} - -// dialContext connects to the given address, aborting the dial if ctx is canceled. -func dialContext(ctx context.Context, network, addr string) (net.Conn, error) { - d := &net.Dialer{KeepAlive: tcpKeepAliveInterval} - return d.DialContext(ctx, network, addr) -} - -// requestWithContext copies req, adding the cancelation channel and deadline from ctx. -func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) { - return c, req.WithContext(ctx) -} diff --git a/rpc/client_example_test.go b/rpc/client_example_test.go index 3462b3685..8276a9ead 100644 --- a/rpc/client_example_test.go +++ b/rpc/client_example_test.go @@ -17,12 +17,12 @@ package rpc_test import ( + "context" "fmt" "math/big" "time" "github.com/ethereum/go-ethereum/rpc" - "golang.org/x/net/context" ) // In this example, our client whishes to track the latest 'block number' diff --git a/rpc/client_test.go b/rpc/client_test.go index 407ed9c06..10d74670b 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -17,6 +17,7 @@ package rpc import ( + "context" "fmt" "math/rand" "net" @@ -31,7 +32,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/log" - "golang.org/x/net/context" ) func TestClientRequest(t *testing.T) { @@ -394,7 +394,7 @@ func TestClientReconnect(t *testing.T) { if err != nil { t.Fatal(err) } - go http.Serve(l, srv.WebsocketHandler("*")) + go http.Serve(l, srv.WebsocketHandler([]string{"*"})) return srv, l } @@ -466,7 +466,7 @@ func httpTestClient(srv *Server, transport string, fl *flakeyListener) (*Client, var hs *httptest.Server switch transport { case "ws": - hs = httptest.NewUnstartedServer(srv.WebsocketHandler("*")) + hs = httptest.NewUnstartedServer(srv.WebsocketHandler([]string{"*"})) case "http": hs = httptest.NewUnstartedServer(srv) default: diff --git a/rpc/http.go b/rpc/http.go index 7d4fe5d47..022f9ce8f 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -18,18 +18,17 @@ package rpc import ( "bytes" + "context" "encoding/json" "fmt" "io" "io/ioutil" "net" "net/http" - "strings" "sync" "time" "github.com/rs/cors" - "golang.org/x/net/context" ) const ( @@ -115,11 +114,11 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos if err != nil { return nil, err } - client, req := requestWithContext(hc.client, hc.req, ctx) + req := hc.req.WithContext(ctx) req.Body = ioutil.NopCloser(bytes.NewReader(body)) req.ContentLength = int64(len(body)) - resp, err := client.Do(req) + resp, err := hc.client.Do(req) if err != nil { return nil, err } @@ -140,8 +139,8 @@ func (t *httpReadWriteNopCloser) Close() error { // NewHTTPServer creates a new HTTP RPC server around an API provider. // // Deprecated: Server implements http.Handler -func NewHTTPServer(corsString string, srv *Server) *http.Server { - return &http.Server{Handler: newCorsHandler(srv, corsString)} +func NewHTTPServer(cors []string, srv *Server) *http.Server { + return &http.Server{Handler: newCorsHandler(srv, cors)} } // ServeHTTP serves JSON-RPC requests over HTTP. @@ -162,15 +161,12 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { srv.ServeSingleRequest(codec, OptionMethodInvocation) } -func newCorsHandler(srv *Server, corsString string) http.Handler { - var allowedOrigins []string - for _, domain := range strings.Split(corsString, ",") { - allowedOrigins = append(allowedOrigins, strings.TrimSpace(domain)) - } +func newCorsHandler(srv *Server, allowedOrigins []string) http.Handler { c := cors.New(cors.Options{ AllowedOrigins: allowedOrigins, AllowedMethods: []string{"POST", "GET"}, MaxAge: 600, + AllowedHeaders: []string{"*"}, }) return c.Handler(srv) } diff --git a/rpc/inproc.go b/rpc/inproc.go index f72b97497..595a7ca65 100644 --- a/rpc/inproc.go +++ b/rpc/inproc.go @@ -17,9 +17,8 @@ package rpc import ( + "context" "net" - - "golang.org/x/net/context" ) // NewInProcClient attaches an in-process connection to the given RPC server. diff --git a/rpc/ipc.go b/rpc/ipc.go index 3c86d711c..8de18a56f 100644 --- a/rpc/ipc.go +++ b/rpc/ipc.go @@ -17,12 +17,11 @@ package rpc import ( + "context" "fmt" "net" "github.com/ethereum/go-ethereum/log" - - "golang.org/x/net/context" ) // CreateIPCListener creates an listener, on Unix platforms this is a unix socket, on diff --git a/rpc/ipc_unix.go b/rpc/ipc_unix.go index a25b21627..0851ea61e 100644 --- a/rpc/ipc_unix.go +++ b/rpc/ipc_unix.go @@ -19,11 +19,10 @@ package rpc import ( + "context" "net" "os" "path/filepath" - - "golang.org/x/net/context" ) // ipcListen will create a Unix socket on the given endpoint. diff --git a/rpc/ipc_windows.go b/rpc/ipc_windows.go index 68234d215..ca56a3ce4 100644 --- a/rpc/ipc_windows.go +++ b/rpc/ipc_windows.go @@ -19,10 +19,10 @@ package rpc import ( + "context" "net" "time" - "golang.org/x/net/context" "gopkg.in/natefinch/npipe.v2" ) diff --git a/rpc/server.go b/rpc/server.go index 4f9ce541e..78df37e52 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -17,23 +17,21 @@ package rpc import ( + "context" "fmt" "reflect" "runtime" + "sync" "sync/atomic" "github.com/ethereum/go-ethereum/log" - - "golang.org/x/net/context" "gopkg.in/fatih/set.v0" ) const ( notificationBufferSize = 10000 // max buffered notifications before codec is closed - MetadataApi = "rpc" - DefaultIPCApis = "admin,debug,eth,miner,net,personal,shh,txpool,web3" - DefaultHTTPApis = "eth,net,web3" + MetadataApi = "rpc" ) // CodecOption specifies which type of messages this codec supports @@ -144,6 +142,8 @@ func hasOption(option CodecOption, options []CodecOption) bool { // requests until the codec returns an error when reading a request (in most cases // an EOF). It executes requests in parallel when singleShot is false. func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecOption) error { + var pend sync.WaitGroup + defer func() { if err := recover(); err != nil { const size = 64 << 10 @@ -151,7 +151,6 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO buf = buf[:runtime.Stack(buf, false)] log.Error(fmt.Sprint(string(buf))) } - s.codecsMu.Lock() s.codecs.Remove(codec) s.codecsMu.Unlock() @@ -180,8 +179,13 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO for atomic.LoadInt32(&s.run) == 1 { reqs, batch, err := s.readRequest(codec) if err != nil { - log.Debug(fmt.Sprintf("read error %v\n", err)) - codec.Write(codec.CreateErrorResponse(nil, err)) + // If a parsing error occurred, send an error + if err.Error() != "EOF" { + log.Debug(fmt.Sprintf("read error %v\n", err)) + codec.Write(codec.CreateErrorResponse(nil, err)) + } + // Error or end of stream, wait for requests and tear down + pend.Wait() return nil } @@ -200,20 +204,27 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO } return nil } - - if singleShot && batch { - s.execBatch(ctx, codec, reqs) - return nil - } else if singleShot && !batch { - s.exec(ctx, codec, reqs[0]) + // If a single shot request is executing, run and return immediately + if singleShot { + if batch { + s.execBatch(ctx, codec, reqs) + } else { + s.exec(ctx, codec, reqs[0]) + } return nil - } else if !singleShot && batch { - go s.execBatch(ctx, codec, reqs) - } else { - go s.exec(ctx, codec, reqs[0]) } - } + // For multi-shot connections, start a goroutine to serve and loop back + pend.Add(1) + go func(reqs []*serverRequest, batch bool) { + defer pend.Done() + if batch { + s.execBatch(ctx, codec, reqs) + } else { + s.exec(ctx, codec, reqs[0]) + } + }(reqs, batch) + } return nil } diff --git a/rpc/server_test.go b/rpc/server_test.go index c3c88fab7..90d62f26d 100644 --- a/rpc/server_test.go +++ b/rpc/server_test.go @@ -17,13 +17,12 @@ package rpc import ( + "context" "encoding/json" "net" "reflect" "testing" "time" - - "golang.org/x/net/context" ) type Service struct{} diff --git a/rpc/subscription.go b/rpc/subscription.go index bcdc3cdfc..9ab6af9e1 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -17,10 +17,9 @@ package rpc import ( + "context" "errors" "sync" - - "golang.org/x/net/context" ) var ( diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 00c4e0e35..345b4e5f2 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -17,13 +17,12 @@ package rpc import ( + "context" "encoding/json" "net" "sync" "testing" "time" - - "golang.org/x/net/context" ) type NotificationTestService struct { diff --git a/rpc/utils.go b/rpc/utils.go index c249e9b4a..2506c4833 100644 --- a/rpc/utils.go +++ b/rpc/utils.go @@ -18,6 +18,7 @@ package rpc import ( "bufio" + "context" crand "crypto/rand" "encoding/binary" "encoding/hex" @@ -29,8 +30,6 @@ import ( "time" "unicode" "unicode/utf8" - - "golang.org/x/net/context" ) var ( diff --git a/rpc/websocket.go b/rpc/websocket.go index f4271fda8..5f9593a43 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -17,6 +17,7 @@ package rpc import ( + "context" "crypto/tls" "fmt" "net" @@ -24,10 +25,9 @@ import ( "net/url" "os" "strings" + "time" "github.com/ethereum/go-ethereum/log" - - "golang.org/x/net/context" "golang.org/x/net/websocket" "gopkg.in/fatih/set.v0" ) @@ -36,9 +36,9 @@ import ( // // allowedOrigins should be a comma-separated list of allowed origin URLs. // To allow connections with any origin, pass "*". -func (srv *Server) WebsocketHandler(allowedOrigins string) http.Handler { +func (srv *Server) WebsocketHandler(allowedOrigins []string) http.Handler { return websocket.Server{ - Handshake: wsHandshakeValidator(strings.Split(allowedOrigins, ",")), + Handshake: wsHandshakeValidator(allowedOrigins), Handler: func(conn *websocket.Conn) { srv.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions) }, @@ -48,7 +48,7 @@ func (srv *Server) WebsocketHandler(allowedOrigins string) http.Handler { // NewWSServer creates a new websocket RPC server around an API provider. // // Deprecated: use Server.WebsocketHandler -func NewWSServer(allowedOrigins string, srv *Server) *http.Server { +func NewWSServer(allowedOrigins []string, srv *Server) *http.Server { return &http.Server{Handler: srv.WebsocketHandler(allowedOrigins)} } @@ -150,3 +150,18 @@ func wsDialAddress(location *url.URL) string { } return location.Host } + +func dialContext(ctx context.Context, network, addr string) (net.Conn, error) { + d := &net.Dialer{KeepAlive: tcpKeepAliveInterval} + return d.DialContext(ctx, network, addr) +} + +func contextDialer(ctx context.Context) *net.Dialer { + dialer := &net.Dialer{Cancel: ctx.Done(), KeepAlive: tcpKeepAliveInterval} + if deadline, ok := ctx.Deadline(); ok { + dialer.Deadline = deadline + } else { + dialer.Deadline = time.Now().Add(defaultDialTimeout) + } + return dialer +} |