func gethHttpHandler(codec codec.Codec, a shared.EthereumApi) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Header().Set("Content-Type", "application/json") // Limit request size to resist DoS if req.ContentLength > maxHttpSizeReqLength { err := fmt.Errorf("Request too large") response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) httpSend(w, &response) return } defer req.Body.Close() payload, err := ioutil.ReadAll(req.Body) if err != nil { err := fmt.Errorf("Could not read request body") response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) httpSend(w, &response) return } c := codec.New(nil) var rpcReq shared.Request if err = c.Decode(payload, &rpcReq); err == nil { reply, err := a.Execute(&rpcReq) res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) httpSend(w, &res) return } var reqBatch []shared.Request if err = c.Decode(payload, &reqBatch); err == nil { resBatch := make([]*interface{}, len(reqBatch)) resCount := 0 for i, rpcReq := range reqBatch { reply, err := a.Execute(&rpcReq) if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) resCount += 1 } } // make response omitting nil entries resBatch = resBatch[:resCount] httpSend(w, resBatch) return } // invalid request err = fmt.Errorf("Could not decode request") res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err) httpSend(w, res) }) }
func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error { os.Remove(cfg.Endpoint) // in case it still exists from a previous run l, err := Listen(cfg.Endpoint) if err != nil { return err } os.Chmod(cfg.Endpoint, 0600) go func() { for { conn, err := l.Accept() if err != nil { glog.V(logger.Error).Infof("Error accepting ipc connection - %v\n", err) continue } go func(conn net.Conn) { codec := codec.New(conn) for { req, err := codec.ReadRequest() if err == io.EOF { codec.Close() return } else if err != nil { glog.V(logger.Error).Infof("IPC recv err - %v\n", err) codec.Close() return } var rpcResponse interface{} res, err := api.Execute(req) rpcResponse = shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err) err = codec.WriteResponse(rpcResponse) if err != nil { glog.V(logger.Error).Infof("IPC send err - %v\n", err) codec.Close() return } } }(conn) } }() glog.V(logger.Info).Infof("IPC service started (%s)\n", cfg.Endpoint) return nil }
func handle(id int, conn net.Conn, api shared.EthereumApi, c codec.Codec) { codec := c.New(conn) defer func() { if r := recover(); r != nil { glog.Errorf("panic: %v\n", r) } codec.Close() }() for { requests, isBatch, err := codec.ReadRequest() if err == io.EOF { return } else if err != nil { glog.V(logger.Debug).Infof("Closed IPC Conn %06d recv err - %v\n", id, err) return } if isBatch { responses := make([]*interface{}, len(requests)) responseCount := 0 for _, req := range requests { res, err := api.Execute(req) if req.Id != nil { rpcResponse := shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err) responses[responseCount] = rpcResponse responseCount += 1 } } err = codec.WriteResponse(responses[:responseCount]) if err != nil { glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err) return } } else { var rpcResponse interface{} res, err := api.Execute(requests[0]) rpcResponse = shared.NewRpcResponse(requests[0].Id, requests[0].Jsonrpc, res, err) err = codec.WriteResponse(rpcResponse) if err != nil { glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err) return } } } }