You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
2.3 KiB

  1. package jsonrpc
  2. import (
  3. "bytes"
  4. "net/http"
  5. "strings"
  6. "github.com/intel-go/fastjson"
  7. )
  8. const (
  9. // Version is JSON-RPC 2.0.
  10. Version = "2.0"
  11. batchRequestKey = '['
  12. contentTypeKey = "Content-Type"
  13. contentTypeValue = "application/json"
  14. )
  15. type (
  16. // A Request represents a JSON-RPC request received by the server.
  17. Request struct {
  18. ID *fastjson.RawMessage `json:"id"`
  19. Version string `json:"jsonrpc"`
  20. Method string `json:"method"`
  21. Params *fastjson.RawMessage `json:"params"`
  22. }
  23. // A Response represents a JSON-RPC response returned by the server.
  24. Response struct {
  25. ID *fastjson.RawMessage `json:"id,omitempty"`
  26. Version string `json:"jsonrpc"`
  27. Result interface{} `json:"result,omitempty"`
  28. Error *Error `json:"error,omitempty"`
  29. }
  30. )
  31. // ParseRequest parses a HTTP request to JSON-RPC request.
  32. func ParseRequest(r *http.Request) ([]*Request, bool, *Error) {
  33. if !strings.HasPrefix(r.Header.Get(contentTypeKey), contentTypeValue) {
  34. return nil, false, ErrInvalidRequest()
  35. }
  36. buf := bytes.NewBuffer(make([]byte, 0, r.ContentLength))
  37. if _, err := buf.ReadFrom(r.Body); err != nil {
  38. return nil, false, ErrInvalidRequest()
  39. }
  40. defer r.Body.Close()
  41. if buf.Len() == 0 {
  42. return nil, false, ErrInvalidRequest()
  43. }
  44. f, _, err := buf.ReadRune()
  45. if err != nil {
  46. return nil, false, ErrInvalidRequest()
  47. }
  48. if err := buf.UnreadRune(); err != nil {
  49. return nil, false, ErrInvalidRequest()
  50. }
  51. var rs []*Request
  52. if f != batchRequestKey {
  53. var req *Request
  54. if err := fastjson.NewDecoder(buf).Decode(&req); err != nil {
  55. return nil, false, ErrParse()
  56. }
  57. return append(rs, req), false, nil
  58. }
  59. if err := fastjson.NewDecoder(buf).Decode(&rs); err != nil {
  60. return nil, false, ErrParse()
  61. }
  62. return rs, true, nil
  63. }
  64. // NewResponse generates a JSON-RPC response.
  65. func NewResponse(r *Request) *Response {
  66. return &Response{
  67. Version: r.Version,
  68. ID: r.ID,
  69. }
  70. }
  71. // SendResponse writes JSON-RPC response.
  72. func SendResponse(w http.ResponseWriter, resp []*Response, batch bool) error {
  73. w.Header().Set(contentTypeKey, contentTypeValue)
  74. if batch || len(resp) > 1 {
  75. return fastjson.NewEncoder(w).Encode(resp)
  76. } else if len(resp) == 1 {
  77. return fastjson.NewEncoder(w).Encode(resp[0])
  78. }
  79. return nil
  80. }