package jsonrpc import ( "bytes" "net/http" "strings" "github.com/intel-go/fastjson" ) const ( // Version is JSON-RPC 2.0. Version = "2.0" batchRequestKey = '[' contentTypeKey = "Content-Type" contentTypeValue = "application/json" ) type ( // A Request represents a JSON-RPC request received by the server. Request struct { ID *fastjson.RawMessage `json:"id"` Version string `json:"jsonrpc"` Method string `json:"method"` Params *fastjson.RawMessage `json:"params"` } // A Response represents a JSON-RPC response returned by the server. Response struct { ID *fastjson.RawMessage `json:"id,omitempty"` Version string `json:"jsonrpc"` Result interface{} `json:"result,omitempty"` Error *Error `json:"error,omitempty"` } ) // ParseRequest parses a HTTP request to JSON-RPC request. func ParseRequest(r *http.Request) ([]*Request, bool, *Error) { if !strings.HasPrefix(r.Header.Get(contentTypeKey), contentTypeValue) { return nil, false, ErrInvalidRequest() } buf := bytes.NewBuffer(make([]byte, 0, r.ContentLength)) if _, err := buf.ReadFrom(r.Body); err != nil { return nil, false, ErrInvalidRequest() } defer r.Body.Close() if buf.Len() == 0 { return nil, false, ErrInvalidRequest() } f, _, err := buf.ReadRune() if err != nil { return nil, false, ErrInvalidRequest() } if err := buf.UnreadRune(); err != nil { return nil, false, ErrInvalidRequest() } var rs []*Request if f != batchRequestKey { var req *Request if err := fastjson.NewDecoder(buf).Decode(&req); err != nil { return nil, false, ErrParse() } return append(rs, req), false, nil } if err := fastjson.NewDecoder(buf).Decode(&rs); err != nil { return nil, false, ErrParse() } return rs, true, nil } // NewResponse generates a JSON-RPC response. func NewResponse(r *Request) *Response { return &Response{ Version: r.Version, ID: r.ID, } } // SendResponse writes JSON-RPC response. func SendResponse(w http.ResponseWriter, resp []*Response, batch bool) error { w.Header().Set(contentTypeKey, contentTypeValue) if batch || len(resp) > 1 { return fastjson.NewEncoder(w).Encode(resp) } else if len(resp) == 1 { return fastjson.NewEncoder(w).Encode(resp[0]) } return nil }