good morning!!!!

Skip to content
Snippets Groups Projects
Commit c6f84325 authored by Taylor Gerring's avatar Taylor Gerring
Browse files

Support JSON RPC batch requests

parents 917050dc 8fd243ee
Branches
Tags
No related merge requests found
package rpc package rpc
import ( import (
"encoding/json"
"io/ioutil"
"net/http" "net/http"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
...@@ -16,54 +18,71 @@ const ( ...@@ -16,54 +18,71 @@ const (
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API. // JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler { func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
var json JsonWrapper var jsw JsonWrapper
api := NewEthereumApi(pipe, dataDir) api := NewEthereumApi(pipe, dataDir)
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// TODO this needs to be configurable
w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Origin", "*")
rpchttplogger.DebugDetailln("Handling request") // Limit request size to resist DoS
if req.ContentLength > maxSizeReqLength { if req.ContentLength > maxSizeReqLength {
jsonerr := &RpcErrorObject{-32700, "Request too large"} jsonerr := &RpcErrorObject{-32700, "Request too large"}
json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr}) jsw.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
return return
} }
reqParsed, reqerr := json.ParseRequestBody(req) defer req.Body.Close()
switch reqerr.(type) { body, err := ioutil.ReadAll(req.Body)
case nil: if err != nil {
break jsonerr := &RpcErrorObject{-32700, "Could not read request body"}
case *DecodeParamError, *InsufficientParamsError, *ValidationError: jsw.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
jsonerr := &RpcErrorObject{-32602, reqerr.Error()} }
json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
// Try to parse the request as a single
var reqSingle RpcRequest
if err := json.Unmarshal(body, &reqSingle); err == nil {
response := RpcResponse(api, &reqSingle)
jsw.Send(w, &response)
return return
default: }
jsonerr := &RpcErrorObject{-32700, "Could not parse request"}
json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr}) // Try to parse the request to batch
var reqBatch []RpcRequest
if err := json.Unmarshal(body, &reqBatch); err == nil {
// Build response batch
resBatch := make([]*interface{}, len(reqBatch))
for i, request := range reqBatch {
response := RpcResponse(api, &request)
resBatch[i] = response
}
jsw.Send(w, resBatch)
return return
} }
var response interface{} // Not a batch or single request, error
reserr := api.GetRequestReply(&reqParsed, &response) jsonerr := &RpcErrorObject{-32600, "Could not decode request"}
jsw.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
})
}
func RpcResponse(api *EthereumApi, request *RpcRequest) *interface{} {
var reply, response interface{}
reserr := api.GetRequestReply(request, &reply)
switch reserr.(type) { switch reserr.(type) {
case nil: case nil:
break response = &RpcSuccessResponse{Jsonrpc: jsonrpcver, Id: request.Id, Result: reply}
case *NotImplementedError: case *NotImplementedError:
jsonerr := &RpcErrorObject{-32601, reserr.Error()} jsonerr := &RpcErrorObject{-32601, reserr.Error()}
json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Error: jsonerr}) response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
return
case *DecodeParamError, *InsufficientParamsError, *ValidationError: case *DecodeParamError, *InsufficientParamsError, *ValidationError:
jsonerr := &RpcErrorObject{-32602, reserr.Error()} jsonerr := &RpcErrorObject{-32602, reserr.Error()}
json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Error: jsonerr}) response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
return
default: default:
jsonerr := &RpcErrorObject{-32603, reserr.Error()} jsonerr := &RpcErrorObject{-32603, reserr.Error()}
json.Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Error: jsonerr}) response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
return
} }
rpchttplogger.DebugDetailf("Generated response: %T %s", response, response) rpchttplogger.DebugDetailf("Generated response: %T %s", response, response)
json.Send(w, &RpcSuccessResponse{Jsonrpc: jsonrpcver, Id: reqParsed.Id, Result: response}) return &response
})
} }
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"net/http" // "net/http"
"reflect" "reflect"
"time" "time"
...@@ -106,24 +106,6 @@ func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) ...@@ -106,24 +106,6 @@ func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error)
return writer.Write(payload) return writer.Write(payload)
} }
func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) {
var reqParsed RpcRequest
// Convert JSON to native types
d := json.NewDecoder(req.Body)
defer req.Body.Close()
err := d.Decode(&reqParsed)
if err != nil {
rpclogger.Errorln("Error decoding JSON: ", err)
return reqParsed, err
}
rpclogger.DebugDetailf("Parsed request: %s", reqParsed)
return reqParsed, nil
}
func toHex(b []byte) string { func toHex(b []byte) string {
hex := common.Bytes2Hex(b) hex := common.Bytes2Hex(b)
// Prefer output of "0x0" instead of "0x" // Prefer output of "0x0" instead of "0x"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment