lotus/lib/jsonrpc/server.go

121 lines
2.2 KiB
Go
Raw Normal View History

2019-07-12 17:12:38 +00:00
package jsonrpc
import (
2019-07-18 17:41:19 +00:00
"context"
2019-07-12 17:12:38 +00:00
"encoding/json"
"io"
"net/http"
2019-07-18 16:51:21 +00:00
"strings"
2019-07-12 17:12:38 +00:00
2019-07-18 17:41:19 +00:00
"github.com/gbrlsnchs/jwt/v3"
2019-07-12 17:12:38 +00:00
"github.com/gorilla/websocket"
2019-07-18 17:41:19 +00:00
"github.com/filecoin-project/go-lotus/api"
2019-07-12 17:12:38 +00:00
)
const (
rpcParseError = -32700
rpcMethodNotFound = -32601
rpcInvalidParams = -32602
)
// RPCServer provides a jsonrpc 2.0 http server handler
type RPCServer struct {
methods handlers
}
// NewServer creates new RPCServer instance
func NewServer() *RPCServer {
return &RPCServer{
methods: map[string]rpcHandler{},
}
}
var upgrader = websocket.Upgrader{}
2019-07-18 17:41:19 +00:00
func (s *RPCServer) handleWS(ctx context.Context, w http.ResponseWriter, r *http.Request) {
2019-07-12 17:12:38 +00:00
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Error(err)
w.WriteHeader(500)
return
}
(&wsConn{
conn: c,
handler: s.methods,
2019-07-18 17:41:19 +00:00
}).handleWsConn(ctx)
2019-07-15 16:32:43 +00:00
if err := c.Close(); err != nil {
log.Error(err)
return
}
2019-07-12 17:12:38 +00:00
}
// TODO: return errors to clients per spec
func (s *RPCServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
2019-07-18 17:41:19 +00:00
ctx := r.Context()
2019-07-18 16:51:21 +00:00
token := r.Header.Get("Authorization")
if token != "" {
if !strings.HasPrefix(token, "Bearer ") {
w.WriteHeader(401)
return
}
token = token[len("Bearer "):]
2019-07-18 17:41:19 +00:00
var payload jwtPayload
if _, err := jwt.Verify([]byte(token), secret, &payload); err != nil {
w.WriteHeader(401)
return
}
2019-07-18 16:51:21 +00:00
2019-07-18 17:41:19 +00:00
ctx = api.WithPerm(ctx, payload.Allow)
2019-07-18 16:51:21 +00:00
}
2019-07-12 17:12:38 +00:00
if r.Header.Get("Connection") == "Upgrade" {
2019-07-18 17:41:19 +00:00
s.handleWS(ctx, w, r)
2019-07-12 17:12:38 +00:00
return
}
2019-07-18 17:41:19 +00:00
s.methods.handleReader(ctx, r.Body, w, rpcError)
2019-07-12 17:12:38 +00:00
}
2019-07-15 16:21:48 +00:00
func rpcError(wf func(func(io.Writer)), req *request, code int, err error) {
wf(func(w io.Writer) {
if hw, ok := w.(http.ResponseWriter); ok {
hw.WriteHeader(500)
}
2019-07-12 17:12:38 +00:00
2019-07-22 18:13:41 +00:00
log.Warnf("rpc error: %s", err)
2019-07-15 16:21:48 +00:00
if req.ID == nil { // notification
return
}
resp := response{
Jsonrpc: "2.0",
ID: *req.ID,
Error: &respError{
Code: code,
Message: err.Error(),
},
}
2019-07-12 17:12:38 +00:00
2019-07-22 18:13:41 +00:00
err = json.NewEncoder(w).Encode(resp)
if err != nil {
log.Warnf("failed to write rpc error: %s", err)
return
}
2019-07-15 16:21:48 +00:00
})
2019-07-12 17:12:38 +00:00
}
// Register registers new RPC handler
//
// Handler is any value with methods defined
func (s *RPCServer) Register(namespace string, handler interface{}) {
s.methods.register(namespace, handler)
}
var _ error = &respError{}