rpcserver: Improve JSON-RPC compatibility

Avoid compatibility issues with software that relies on the behavior of
bitcoind's JSON-RPC implementation.

The JSON-RPC 1.0 spec defines that notifications must have their "id"
set to null and states that notifications do not have a response.

A JSON-RPC 2.0 notification is a request with "json-rpc":"2.0", and
without an "id" member. The specification states that notifications
must not be responded to. JSON-RPC 2.0 permits the null value as a
valid request id, therefore such requests are not notifications.

Bitcoin Core serves requests with "id":null or even an absent "id", and
responds to such requests with "id":null in the response.

Btcd does not respond to any request without and "id" or with "id":null,
regardless the indicated JSON-RPC protocol version.

In order to avoid compatibility issues with software relying on
Core's behavior, this commit implements "quirks mode" as follows:
 - quirks mode can be enabled via configuration (disabled by default)
 - If no JSON-RPC version is indicated in the request, accept and
respond to request with "id":null
 - If no JSON-RPC version is indicated in the request, accept and
respond to requests without an "id" member
 - In both cases above, use "id":null in the response
 - Do not respond to request without an "id" or with "id":null when
JSON-RPC version is indicated in the request (process as notification)
This commit is contained in:
Tibor Bősze 2016-03-02 19:43:50 +01:00 committed by Dave Collins
parent 9799f0e547
commit 6b8a24918e
5 changed files with 46 additions and 6 deletions

View File

@ -107,6 +107,7 @@ type config struct {
RPCMaxClients int `long:"rpcmaxclients" description:"Max number of RPC clients for standard connections"`
RPCMaxWebsockets int `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"`
RPCMaxConcurrentReqs int `long:"rpcmaxconcurrentreqs" description:"Max number of concurrent RPC requests that may be processed concurrently"`
RPCQuirks bool `long:"rpcquirks" description:"Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE: Discouraged unless interoperability issues need to be worked around"`
DisableRPC bool `long:"norpc" description:"Disable built-in RPC server -- NOTE: The RPC server is disabled by default if no rpcuser/rpcpass or rpclimituser/rpclimitpass is specified"`
DisableTLS bool `long:"notls" description:"Disable TLS for the RPC server -- NOTE: This is only allowed if the RPC server is bound to localhost"`
DisableDNSSeed bool `long:"nodnsseed" description:"Disable DNS seeding for peers"`

3
doc.go
View File

@ -50,6 +50,9 @@ Application Options:
--rpcmaxclients= Max number of RPC clients for standard connections
(10)
--rpcmaxwebsockets= Max number of RPC websocket connections (25)
--rpcquirks Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE:
Discouraged unless interoperability issues need to
be worked around
--norpc Disable built-in RPC server -- NOTE: The RPC server
is disabled by default if no rpcuser/rpcpass or
rpclimituser/rpclimitpass is specified

View File

@ -3978,9 +3978,25 @@ func (s *rpcServer) jsonRPCRead(w http.ResponseWriter, r *http.Request, isAdmin
}
}
if jsonErr == nil {
// Requests with no ID (notifications) must not have a response
// per the JSON-RPC spec.
if request.ID == nil {
// The JSON-RPC 1.0 spec defines that notifications must have their "id"
// set to null and states that notifications do not have a response.
//
// A JSON-RPC 2.0 notification is a request with "json-rpc":"2.0", and
// without an "id" member. The specification states that notifications
// must not be responded to. JSON-RPC 2.0 permits the null value as a
// valid request id, therefore such requests are not notifications.
//
// Bitcoin Core serves requests with "id":null or even an absent "id",
// and responds to such requests with "id":null in the response.
//
// Btcd does not respond to any request without and "id" or "id":null,
// regardless the indicated JSON-RPC protocol version unless RPC quirks
// are enabled. With RPC quirks enabled, such requests will be responded
// to if the reqeust does not indicate JSON-RPC version.
//
// RPC quirks can be enabled by the user to avoid compatibility issues
// with software relying on Core's behavior.
if request.ID == nil && !(cfg.RPCQuirks && request.Jsonrpc == "") {
return
}

View File

@ -950,9 +950,25 @@ out:
continue
}
// Requests with no ID (notifications) must not have a response per the
// JSON-RPC spec.
if request.ID == nil {
// The JSON-RPC 1.0 spec defines that notifications must have their "id"
// set to null and states that notifications do not have a response.
//
// A JSON-RPC 2.0 notification is a request with "json-rpc":"2.0", and
// without an "id" member. The specification states that notifications
// must not be responded to. JSON-RPC 2.0 permits the null value as a
// valid request id, therefore such requests are not notifications.
//
// Bitcoin Core serves requests with "id":null or even an absent "id",
// and responds to such requests with "id":null in the response.
//
// Btcd does not respond to any request without and "id" or "id":null,
// regardless the indicated JSON-RPC protocol version unless RPC quirks
// are enabled. With RPC quirks enabled, such requests will be responded
// to if the reqeust does not indicate JSON-RPC version.
//
// RPC quirks can be enabled by the user to avoid compatibility issues
// with software relying on Core's behavior.
if request.ID == nil && !(cfg.RPCQuirks && request.Jsonrpc == "") {
if !c.authenticated {
break out
}

View File

@ -207,6 +207,10 @@
; Specify the maximum number of concurrent RPC websocket clients.
; rpcmaxwebsockets=25
; Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE: Discouraged unless
; interoperability issues need to be worked around
; rpcquirks=1
; Use the following setting to disable the RPC server even if the rpcuser and
; rpcpass are specified above. This allows one to quickly disable the RPC
; server without having to remove credentials from the config file.