http.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package rpc
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "net/http"
  8. "github.com/ethereum/go-ethereum/logger"
  9. "github.com/ethereum/go-ethereum/logger/glog"
  10. "github.com/ethereum/go-ethereum/xeth"
  11. "github.com/rs/cors"
  12. )
  13. var rpclistener *stoppableTCPListener
  14. const (
  15. jsonrpcver = "2.0"
  16. maxSizeReqLength = 1024 * 1024 // 1MB
  17. )
  18. func Start(pipe *xeth.XEth, config RpcConfig) error {
  19. if rpclistener != nil {
  20. if fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort) != rpclistener.Addr().String() {
  21. return fmt.Errorf("RPC service already running on %s ", rpclistener.Addr().String())
  22. }
  23. return nil // RPC service already running on given host/port
  24. }
  25. l, err := newStoppableTCPListener(fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort))
  26. if err != nil {
  27. glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", config.ListenAddress, config.ListenPort, err)
  28. return err
  29. }
  30. rpclistener = l
  31. var handler http.Handler
  32. if len(config.CorsDomain) > 0 {
  33. var opts cors.Options
  34. opts.AllowedMethods = []string{"POST"}
  35. opts.AllowedOrigins = []string{config.CorsDomain}
  36. c := cors.New(opts)
  37. handler = newStoppableHandler(c.Handler(JSONRPC(pipe)), l.stop)
  38. } else {
  39. handler = newStoppableHandler(JSONRPC(pipe), l.stop)
  40. }
  41. go http.Serve(l, handler)
  42. return nil
  43. }
  44. func Stop() error {
  45. if rpclistener != nil {
  46. rpclistener.Stop()
  47. rpclistener = nil
  48. }
  49. return nil
  50. }
  51. // JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
  52. func JSONRPC(pipe *xeth.XEth) http.Handler {
  53. api := NewEthereumApi(pipe)
  54. return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  55. w.Header().Set("Content-Type", "application/json")
  56. // Limit request size to resist DoS
  57. if req.ContentLength > maxSizeReqLength {
  58. jsonerr := &RpcErrorObject{-32700, "Request too large"}
  59. send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
  60. return
  61. }
  62. // Read request body
  63. defer req.Body.Close()
  64. body, err := ioutil.ReadAll(req.Body)
  65. if err != nil {
  66. jsonerr := &RpcErrorObject{-32700, "Could not read request body"}
  67. send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
  68. }
  69. // Try to parse the request as a single
  70. var reqSingle RpcRequest
  71. if err := json.Unmarshal(body, &reqSingle); err == nil {
  72. response := RpcResponse(api, &reqSingle)
  73. send(w, &response)
  74. return
  75. }
  76. // Try to parse the request to batch
  77. var reqBatch []RpcRequest
  78. if err := json.Unmarshal(body, &reqBatch); err == nil {
  79. // Build response batch
  80. resBatch := make([]*interface{}, len(reqBatch))
  81. for i, request := range reqBatch {
  82. response := RpcResponse(api, &request)
  83. resBatch[i] = response
  84. }
  85. send(w, resBatch)
  86. return
  87. }
  88. // Not a batch or single request, error
  89. jsonerr := &RpcErrorObject{-32600, "Could not decode request"}
  90. send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
  91. })
  92. }
  93. func RpcResponse(api *EthereumApi, request *RpcRequest) *interface{} {
  94. var reply, response interface{}
  95. reserr := api.GetRequestReply(request, &reply)
  96. switch reserr.(type) {
  97. case nil:
  98. response = &RpcSuccessResponse{Jsonrpc: jsonrpcver, Id: request.Id, Result: reply}
  99. case *NotImplementedError:
  100. jsonerr := &RpcErrorObject{-32601, reserr.Error()}
  101. response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
  102. case *DecodeParamError, *InsufficientParamsError, *ValidationError, *InvalidTypeError:
  103. jsonerr := &RpcErrorObject{-32602, reserr.Error()}
  104. response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
  105. default:
  106. jsonerr := &RpcErrorObject{-32603, reserr.Error()}
  107. response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
  108. }
  109. glog.V(logger.Detail).Infof("Generated response: %T %s", response, response)
  110. return &response
  111. }
  112. func send(writer io.Writer, v interface{}) (n int, err error) {
  113. var payload []byte
  114. payload, err = json.MarshalIndent(v, "", "\t")
  115. if err != nil {
  116. glog.V(logger.Error).Infoln("Error marshalling JSON", err)
  117. return 0, err
  118. }
  119. glog.V(logger.Detail).Infof("Sending payload: %s", payload)
  120. return writer.Write(payload)
  121. }