From bb01bea4e276dad359815c682a2dee730737f4dc Mon Sep 17 00:00:00 2001
From: Felix Lange <fjl@twurst.com>
Date: Tue, 12 Jul 2016 17:42:44 +0200
Subject: [PATCH] rpc: fix bad method error for batch requests

If a batch request contained an invalid method, the server would reply
with a non-batch error response. Fix this by tracking an error for each
batch element.
---
 rpc/json.go   | 16 ++++++++--------
 rpc/server.go |  7 ++++++-
 rpc/types.go  |  1 +
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/rpc/json.go b/rpc/json.go
index 151ed546e..ee931bc87 100644
--- a/rpc/json.go
+++ b/rpc/json.go
@@ -182,12 +182,12 @@ func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, RPCError) {
 			method: unsubscribeMethod, params: in.Payload}}, false, nil
 	}
 
-	// regular RPC call
 	elems := strings.Split(in.Method, serviceMethodSeparator)
 	if len(elems) != 2 {
 		return nil, false, &methodNotFoundError{in.Method, ""}
 	}
 
+	// regular RPC call
 	if len(in.Payload) == 0 {
 		return []rpcRequest{rpcRequest{service: elems[0], method: elems[1], id: &in.Id}}, false, nil
 	}
@@ -236,15 +236,15 @@ func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, RPCErro
 			continue
 		}
 
-		elems := strings.Split(r.Method, serviceMethodSeparator)
-		if len(elems) != 2 {
-			return nil, true, &methodNotFoundError{r.Method, ""}
-		}
-
 		if len(r.Payload) == 0 {
-			requests[i] = rpcRequest{service: elems[0], method: elems[1], id: id, params: nil}
+			requests[i] = rpcRequest{id: id, params: nil}
+		} else {
+			requests[i] = rpcRequest{id: id, params: r.Payload}
+		}
+		if elem := strings.Split(r.Method, serviceMethodSeparator); len(elem) == 2 {
+			requests[i].service, requests[i].method = elem[0], elem[1]
 		} else {
-			requests[i] = rpcRequest{service: elems[0], method: elems[1], id: id, params: r.Payload}
+			requests[i].err = &methodNotFoundError{r.Method, ""}
 		}
 	}
 
diff --git a/rpc/server.go b/rpc/server.go
index 80976ed62..a9bdef285 100644
--- a/rpc/server.go
+++ b/rpc/server.go
@@ -180,7 +180,7 @@ 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 {
-			glog.V(logger.Debug).Infof("%v\n", err)
+			glog.V(logger.Debug).Infof("read error %v\n", err)
 			codec.Write(codec.CreateErrorResponse(nil, err))
 			return nil
 		}
@@ -394,6 +394,11 @@ func (s *Server) readRequest(codec ServerCodec) ([]*serverRequest, bool, RPCErro
 		var ok bool
 		var svc *service
 
+		if r.err != nil {
+			requests[i] = &serverRequest{id: r.id, err: r.err}
+			continue
+		}
+
 		if r.isPubSub && r.method == unsubscribeMethod {
 			requests[i] = &serverRequest{id: r.id, isUnsubscribe: true}
 			argTypes := []reflect.Type{reflect.TypeOf("")} // expect subscription id as first arg
diff --git a/rpc/types.go b/rpc/types.go
index a1f36fbd2..460581715 100644
--- a/rpc/types.go
+++ b/rpc/types.go
@@ -88,6 +88,7 @@ type rpcRequest struct {
 	id       interface{}
 	isPubSub bool
 	params   interface{}
+	err      RPCError // invalid batch element
 }
 
 // RPCError implements RPC error, is add support for error codec over regular go errors
-- 
GitLab