github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/rpc/http/server.go (about)

     1  /*
     2  	This file is part of go-ethereum
     3  
     4  	go-ethereum is free software: you can redistribute it and/or modify
     5  	it under the terms of the GNU General Public License as published by
     6  	the Free Software Foundation, either version 3 of the License, or
     7  	(at your option) any later version.
     8  
     9  	go-ethereum is distributed in the hope that it will be useful,
    10  	but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12    GNU General Public License for more details.
    13  
    14  	You should have received a copy of the GNU General Public License
    15  	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
    16  */
    17  package rpchttp
    18  
    19  import (
    20  	"fmt"
    21  	"net"
    22  	"net/http"
    23  
    24  	"github.com/jonasnick/go-ethereum/logger"
    25  	"github.com/jonasnick/go-ethereum/rpc"
    26  	"github.com/jonasnick/go-ethereum/xeth"
    27  )
    28  
    29  var rpchttplogger = logger.NewLogger("RPC-HTTP")
    30  var JSON rpc.JsonWrapper
    31  
    32  func NewRpcHttpServer(pipe *xeth.XEth, port int) (*RpcHttpServer, error) {
    33  	sport := fmt.Sprintf("127.0.0.1:%d", port)
    34  	l, err := net.Listen("tcp", sport)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	return &RpcHttpServer{
    40  		listener: l,
    41  		quit:     make(chan bool),
    42  		pipe:     pipe,
    43  		port:     port,
    44  	}, nil
    45  }
    46  
    47  type RpcHttpServer struct {
    48  	quit     chan bool
    49  	listener net.Listener
    50  	pipe     *xeth.XEth
    51  	port     int
    52  }
    53  
    54  func (s *RpcHttpServer) exitHandler() {
    55  out:
    56  	for {
    57  		select {
    58  		case <-s.quit:
    59  			s.listener.Close()
    60  			break out
    61  		}
    62  	}
    63  
    64  	rpchttplogger.Infoln("Shutdown RPC-HTTP server")
    65  }
    66  
    67  func (s *RpcHttpServer) Stop() {
    68  	close(s.quit)
    69  }
    70  
    71  func (s *RpcHttpServer) Start() {
    72  	rpchttplogger.Infof("Starting RPC-HTTP server on port %d", s.port)
    73  	go s.exitHandler()
    74  
    75  	api := rpc.NewEthereumApi(s.pipe)
    76  	h := s.apiHandler(api)
    77  	http.Handle("/", h)
    78  
    79  	err := http.Serve(s.listener, nil)
    80  	// FIX Complains on shutdown due to listner already being closed
    81  	if err != nil {
    82  		rpchttplogger.Errorln("Error on RPC-HTTP interface:", err)
    83  	}
    84  }
    85  
    86  func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler {
    87  	var jsonrpcver string = "2.0"
    88  	fn := func(w http.ResponseWriter, req *http.Request) {
    89  		w.Header().Set("Access-Control-Allow-Origin", "*")
    90  
    91  		rpchttplogger.DebugDetailln("Handling request")
    92  
    93  		reqParsed, reqerr := JSON.ParseRequestBody(req)
    94  		if reqerr != nil {
    95  			jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest}
    96  			JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
    97  			return
    98  		}
    99  
   100  		var response interface{}
   101  		reserr := api.GetRequestReply(&reqParsed, &response)
   102  		if reserr != nil {
   103  			rpchttplogger.Warnln(reserr)
   104  			jsonerr := &rpc.RpcErrorObject{-32603, reserr.Error()}
   105  			JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
   106  			return
   107  		}
   108  
   109  		rpchttplogger.DebugDetailf("Generated response: %T %s", response, response)
   110  		JSON.Send(w, &rpc.RpcSuccessResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Result: response})
   111  	}
   112  
   113  	return http.HandlerFunc(fn)
   114  }