aboutsummaryrefslogtreecommitdiffstats
path: root/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'rpc')
-rw-r--r--rpc/client.go2
-rw-r--r--rpc/client_context_go1.4.go60
-rw-r--r--rpc/client_context_go1.5.go61
-rw-r--r--rpc/client_context_go1.6.go55
-rw-r--r--rpc/client_context_go1.7.go51
-rw-r--r--rpc/client_example_test.go2
-rw-r--r--rpc/client_test.go6
-rw-r--r--rpc/http.go18
-rw-r--r--rpc/inproc.go3
-rw-r--r--rpc/ipc.go3
-rw-r--r--rpc/ipc_unix.go3
-rw-r--r--rpc/ipc_windows.go2
-rw-r--r--rpc/server.go49
-rw-r--r--rpc/server_test.go3
-rw-r--r--rpc/subscription.go3
-rw-r--r--rpc/subscription_test.go3
-rw-r--r--rpc/utils.go3
-rw-r--r--rpc/websocket.go25
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
+}