mirror of
https://github.com/pgsty/minio.git
synced 2026-07-23 14:10:25 +03:00
WebUI: move from rpc/v2/json to rpc/v2/json2 which has better error response structure.
This commit is contained in:
committed by
Harshavardhana
parent
f98675660b
commit
6ad39cb386
+190
@@ -0,0 +1,190 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Copyright 2012 The Gorilla Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/rpc/v2"
|
||||
)
|
||||
|
||||
var null = json.RawMessage([]byte("null"))
|
||||
var Version = "2.0"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Request and Response
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// serverRequest represents a JSON-RPC request received by the server.
|
||||
type serverRequest struct {
|
||||
// JSON-RPC protocol.
|
||||
Version string `json:"jsonrpc"`
|
||||
|
||||
// A String containing the name of the method to be invoked.
|
||||
Method string `json:"method"`
|
||||
|
||||
// A Structured value to pass as arguments to the method.
|
||||
Params *json.RawMessage `json:"params"`
|
||||
|
||||
// The request id. MUST be a string, number or null.
|
||||
// Our implementation will not do type checking for id.
|
||||
// It will be copied as it is.
|
||||
Id *json.RawMessage `json:"id"`
|
||||
}
|
||||
|
||||
// serverResponse represents a JSON-RPC response returned by the server.
|
||||
type serverResponse struct {
|
||||
// JSON-RPC protocol.
|
||||
Version string `json:"jsonrpc"`
|
||||
|
||||
// The Object that was returned by the invoked method. This must be null
|
||||
// in case there was an error invoking the method.
|
||||
// As per spec the member will be omitted if there was an error.
|
||||
Result interface{} `json:"result,omitempty"`
|
||||
|
||||
// An Error object if there was an error invoking the method. It must be
|
||||
// null if there was no error.
|
||||
// As per spec the member will be omitted if there was no error.
|
||||
Error *Error `json:"error,omitempty"`
|
||||
|
||||
// This must be the same id as the request it is responding to.
|
||||
Id *json.RawMessage `json:"id"`
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Codec
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// NewcustomCodec returns a new JSON Codec based on passed encoder selector.
|
||||
func NewCustomCodec(encSel rpc.EncoderSelector) *Codec {
|
||||
return &Codec{encSel: encSel}
|
||||
}
|
||||
|
||||
// NewCodec returns a new JSON Codec.
|
||||
func NewCodec() *Codec {
|
||||
return NewCustomCodec(rpc.DefaultEncoderSelector)
|
||||
}
|
||||
|
||||
// Codec creates a CodecRequest to process each request.
|
||||
type Codec struct {
|
||||
encSel rpc.EncoderSelector
|
||||
}
|
||||
|
||||
// NewRequest returns a CodecRequest.
|
||||
func (c *Codec) NewRequest(r *http.Request) rpc.CodecRequest {
|
||||
return newCodecRequest(r, c.encSel.Select(r))
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CodecRequest
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// newCodecRequest returns a new CodecRequest.
|
||||
func newCodecRequest(r *http.Request, encoder rpc.Encoder) rpc.CodecRequest {
|
||||
// Decode the request body and check if RPC method is valid.
|
||||
req := new(serverRequest)
|
||||
err := json.NewDecoder(r.Body).Decode(req)
|
||||
if err != nil {
|
||||
err = &Error{
|
||||
Code: E_PARSE,
|
||||
Message: err.Error(),
|
||||
Data: req,
|
||||
}
|
||||
}
|
||||
if req.Version != Version {
|
||||
err = &Error{
|
||||
Code: E_INVALID_REQ,
|
||||
Message: "jsonrpc must be " + Version,
|
||||
Data: req,
|
||||
}
|
||||
}
|
||||
r.Body.Close()
|
||||
return &CodecRequest{request: req, err: err, encoder: encoder}
|
||||
}
|
||||
|
||||
// CodecRequest decodes and encodes a single request.
|
||||
type CodecRequest struct {
|
||||
request *serverRequest
|
||||
err error
|
||||
encoder rpc.Encoder
|
||||
}
|
||||
|
||||
// Method returns the RPC method for the current request.
|
||||
//
|
||||
// The method uses a dotted notation as in "Service.Method".
|
||||
func (c *CodecRequest) Method() (string, error) {
|
||||
if c.err == nil {
|
||||
return c.request.Method, nil
|
||||
}
|
||||
return "", c.err
|
||||
}
|
||||
|
||||
// ReadRe<quest fills the request object for the RPC method.
|
||||
func (c *CodecRequest) ReadRequest(args interface{}) error {
|
||||
if c.err == nil {
|
||||
if c.request.Params != nil {
|
||||
// JSON params structured object. Unmarshal to the args object.
|
||||
err := json.Unmarshal(*c.request.Params, args)
|
||||
if err != nil {
|
||||
c.err = &Error{
|
||||
Code: E_INVALID_REQ,
|
||||
Message: err.Error(),
|
||||
Data: c.request.Params,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c.err = &Error{
|
||||
Code: E_INVALID_REQ,
|
||||
Message: "rpc: method request ill-formed: missing params field",
|
||||
}
|
||||
}
|
||||
}
|
||||
return c.err
|
||||
}
|
||||
|
||||
// WriteResponse encodes the response and writes it to the ResponseWriter.
|
||||
func (c *CodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}) {
|
||||
res := &serverResponse{
|
||||
Version: Version,
|
||||
Result: reply,
|
||||
Id: c.request.Id,
|
||||
}
|
||||
c.writeServerResponse(w, res)
|
||||
}
|
||||
|
||||
func (c *CodecRequest) WriteError(w http.ResponseWriter, status int, err error) {
|
||||
jsonErr, ok := err.(*Error)
|
||||
if !ok {
|
||||
jsonErr = &Error{
|
||||
Code: E_SERVER,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
res := &serverResponse{
|
||||
Version: Version,
|
||||
Error: jsonErr,
|
||||
Id: c.request.Id,
|
||||
}
|
||||
c.writeServerResponse(w, res)
|
||||
}
|
||||
|
||||
func (c *CodecRequest) writeServerResponse(w http.ResponseWriter, res *serverResponse) {
|
||||
// Id is null for notifications and they don't have a response.
|
||||
if c.request.Id != nil {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
encoder := json.NewEncoder(c.encoder.Encode(w))
|
||||
err := encoder.Encode(res)
|
||||
|
||||
// Not sure in which case will this happen. But seems harmless.
|
||||
if err != nil {
|
||||
rpc.WriteError(w, 400, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type EmptyResponse struct {
|
||||
}
|
||||
Reference in New Issue
Block a user