rpc: add CORS workaround for RPC
This one enables our RPC to be called from the browser if there is a need. It's insecure and not standards-compliant, thus this behaviour is configurable is not enabled by default. It makes our node with this workaround enabled compatible with neo-mon monitoring. Originally debugged by @anatoly-bogatyrev in #464.
This commit is contained in:
parent
e5205d26a3
commit
b46dd295bc
14 changed files with 72 additions and 22 deletions
|
@ -247,7 +247,7 @@ func startServer(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
server := network.NewServer(serverConfig, chain)
|
server := network.NewServer(serverConfig, chain)
|
||||||
rpcServer := rpc.NewServer(chain, cfg.ApplicationConfiguration.RPCPort, server)
|
rpcServer := rpc.NewServer(chain, cfg.ApplicationConfiguration.RPC, server)
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
monitoring := metrics.NewMetricsService(cfg.ApplicationConfiguration.Monitoring)
|
monitoring := metrics.NewMetricsService(cfg.ApplicationConfiguration.Monitoring)
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,6 @@ type (
|
||||||
// ApplicationConfiguration config specific to the node.
|
// ApplicationConfiguration config specific to the node.
|
||||||
ApplicationConfiguration struct {
|
ApplicationConfiguration struct {
|
||||||
DBConfiguration storage.DBConfiguration `yaml:"DBConfiguration"`
|
DBConfiguration storage.DBConfiguration `yaml:"DBConfiguration"`
|
||||||
RPCPort uint16 `yaml:"RPCPort"`
|
|
||||||
NodePort uint16 `yaml:"NodePort"`
|
NodePort uint16 `yaml:"NodePort"`
|
||||||
Relay bool `yaml:"Relay"`
|
Relay bool `yaml:"Relay"`
|
||||||
DialTimeout time.Duration `yaml:"DialTimeout"`
|
DialTimeout time.Duration `yaml:"DialTimeout"`
|
||||||
|
@ -75,6 +74,15 @@ type (
|
||||||
MaxPeers int `yaml:"MaxPeers"`
|
MaxPeers int `yaml:"MaxPeers"`
|
||||||
MinPeers int `yaml:"MinPeers"`
|
MinPeers int `yaml:"MinPeers"`
|
||||||
Monitoring metrics.PrometheusConfig `yaml:"Monitoring"`
|
Monitoring metrics.PrometheusConfig `yaml:"Monitoring"`
|
||||||
|
RPC RPCConfig `yaml:"RPC"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPCConfig is an RPC service configuration information (to be moved to the rpc package, see #423).
|
||||||
|
RPCConfig struct {
|
||||||
|
Enabled bool `yaml:"Enabled"`
|
||||||
|
EnableCORSWorkaround bool `yaml:"EnableCORSWorkaround"`
|
||||||
|
Address string `yaml:"Address"`
|
||||||
|
Port uint16 `yaml:"Port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetMode describes the mode the blockchain will operate on.
|
// NetMode describes the mode the blockchain will operate on.
|
||||||
|
|
|
@ -42,13 +42,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/mainnet.bolt"
|
# FilePath: "./chains/mainnet.bolt"
|
||||||
RPCPort: 20332
|
|
||||||
NodePort: 20333
|
NodePort: 20333
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 5
|
MinPeers: 5
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20332
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
|
@ -30,13 +30,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
RPCPort: 20336
|
|
||||||
NodePort: 20337
|
NodePort: 20337
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 3
|
MinPeers: 3
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20336
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
|
@ -27,13 +27,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
RPCPort: 20333
|
|
||||||
NodePort: 20334
|
NodePort: 20334
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 3
|
MinPeers: 3
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20333
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
|
@ -27,13 +27,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
RPCPort: 20335
|
|
||||||
NodePort: 20336
|
NodePort: 20336
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 3
|
MinPeers: 3
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20335
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
|
@ -27,13 +27,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
RPCPort: 20334
|
|
||||||
NodePort: 20335
|
NodePort: 20335
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 3
|
MinPeers: 3
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20334
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
|
@ -33,13 +33,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
RPCPort: 20331
|
|
||||||
NodePort: 20332
|
NodePort: 20332
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 3
|
MinPeers: 3
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20331
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
|
@ -42,13 +42,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/testnet.bolt"
|
# FilePath: "./chains/testnet.bolt"
|
||||||
RPCPort: 20332
|
|
||||||
NodePort: 20333
|
NodePort: 20333
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 5
|
MinPeers: 5
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20332
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
|
@ -32,13 +32,16 @@ ApplicationConfiguration:
|
||||||
# DB: 0
|
# DB: 0
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/unit_testnet.bolt"
|
# FilePath: "./chains/unit_testnet.bolt"
|
||||||
RPCPort: 20332
|
|
||||||
NodePort: 20333
|
NodePort: 20333
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
MaxPeers: 50
|
MaxPeers: 50
|
||||||
MinPeers: 1
|
MinPeers: 1
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
Port: 20332
|
||||||
Monitoring:
|
Monitoring:
|
||||||
Enabled: false #since it's not useful for unit tests.
|
Enabled: false #since it's not useful for unit tests.
|
||||||
Port: 2112
|
Port: 2112
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -15,6 +15,8 @@ require (
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.9 // indirect
|
github.com/mattn/go-isatty v0.0.9 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
github.com/mr-tron/base58 v1.1.2
|
github.com/mr-tron/base58 v1.1.2
|
||||||
github.com/nspcc-dev/rfc6979 v0.1.0
|
github.com/nspcc-dev/rfc6979 v0.1.0
|
||||||
github.com/onsi/gomega v1.4.2 // indirect
|
github.com/onsi/gomega v1.4.2 // indirect
|
||||||
|
|
|
@ -21,6 +21,7 @@ type (
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
RawParams json.RawMessage `json:"params,omitempty"`
|
RawParams json.RawMessage `json:"params,omitempty"`
|
||||||
RawID json.RawMessage `json:"id,omitempty"`
|
RawID json.RawMessage `json:"id,omitempty"`
|
||||||
|
enableCORSWorkaround bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response represents a standard JSON-RPC 2.0
|
// Response represents a standard JSON-RPC 2.0
|
||||||
|
@ -34,9 +35,10 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRequest creates a new Request struct.
|
// NewRequest creates a new Request struct.
|
||||||
func NewRequest() *Request {
|
func NewRequest(corsWorkaround bool) *Request {
|
||||||
return &Request{
|
return &Request{
|
||||||
JSONRPC: jsonRPCVersion,
|
JSONRPC: jsonRPCVersion,
|
||||||
|
enableCORSWorkaround: corsWorkaround,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +112,11 @@ func (r Request) WriteResponse(w http.ResponseWriter, result interface{}) {
|
||||||
|
|
||||||
func (r Request) writeServerResponse(w http.ResponseWriter, response Response) {
|
func (r Request) writeServerResponse(w http.ResponseWriter, response Response) {
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
if r.enableCORSWorkaround {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With")
|
||||||
|
}
|
||||||
|
|
||||||
encoder := json.NewEncoder(w)
|
encoder := json.NewEncoder(w)
|
||||||
err := encoder.Encode(response)
|
err := encoder.Encode(response)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto"
|
"github.com/CityOfZion/neo-go/pkg/crypto"
|
||||||
|
@ -24,6 +25,7 @@ type (
|
||||||
Server struct {
|
Server struct {
|
||||||
*http.Server
|
*http.Server
|
||||||
chain core.Blockchainer
|
chain core.Blockchainer
|
||||||
|
config config.RPCConfig
|
||||||
coreServer *network.Server
|
coreServer *network.Server
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -35,12 +37,15 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewServer creates a new Server struct.
|
// NewServer creates a new Server struct.
|
||||||
func NewServer(chain core.Blockchainer, port uint16, coreServer *network.Server) Server {
|
func NewServer(chain core.Blockchainer, conf config.RPCConfig, coreServer *network.Server) Server {
|
||||||
|
httpServer := &http.Server{
|
||||||
|
Addr: conf.Address + ":" + strconv.FormatUint(uint64(conf.Port), 10),
|
||||||
|
}
|
||||||
|
|
||||||
return Server{
|
return Server{
|
||||||
Server: &http.Server{
|
Server: httpServer,
|
||||||
Addr: ":" + strconv.FormatUint(uint64(port), 10),
|
|
||||||
},
|
|
||||||
chain: chain,
|
chain: chain,
|
||||||
|
config: conf,
|
||||||
coreServer: coreServer,
|
coreServer: coreServer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +53,10 @@ func NewServer(chain core.Blockchainer, port uint16, coreServer *network.Server)
|
||||||
// Start creates a new JSON-RPC server
|
// Start creates a new JSON-RPC server
|
||||||
// listening on the configured port.
|
// listening on the configured port.
|
||||||
func (s *Server) Start(errChan chan error) {
|
func (s *Server) Start(errChan chan error) {
|
||||||
|
if !s.config.Enabled {
|
||||||
|
log.Info("RPC server is not enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
s.Handler = http.HandlerFunc(s.requestHandler)
|
s.Handler = http.HandlerFunc(s.requestHandler)
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"endpoint": s.Addr,
|
"endpoint": s.Addr,
|
||||||
|
@ -66,7 +75,7 @@ func (s *Server) Shutdown() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) requestHandler(w http.ResponseWriter, httpRequest *http.Request) {
|
func (s *Server) requestHandler(w http.ResponseWriter, httpRequest *http.Request) {
|
||||||
req := NewRequest()
|
req := NewRequest(s.config.EnableCORSWorkaround)
|
||||||
|
|
||||||
if httpRequest.Method != "POST" {
|
if httpRequest.Method != "POST" {
|
||||||
req.WriteErrorResponse(
|
req.WriteErrorResponse(
|
||||||
|
|
|
@ -167,7 +167,7 @@ func initServerWithInMemoryChain(ctx context.Context, t *testing.T) (*core.Block
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
server := network.NewServer(serverConfig, chain)
|
server := network.NewServer(serverConfig, chain)
|
||||||
rpcServer := NewServer(chain, cfg.ApplicationConfiguration.RPCPort, server)
|
rpcServer := NewServer(chain, cfg.ApplicationConfiguration.RPC, server)
|
||||||
handler := http.HandlerFunc(rpcServer.requestHandler)
|
handler := http.HandlerFunc(rpcServer.requestHandler)
|
||||||
|
|
||||||
return chain, handler
|
return chain, handler
|
||||||
|
|
Loading…
Reference in a new issue