From dd4300b5211824f9fc89f9466d4d5f466c1ecce7 Mon Sep 17 00:00:00 2001 From: smallnest Date: Tue, 26 Mar 2019 16:30:19 +0800 Subject: [PATCH] #313 support CORS for jsonrpc2 --- Makefile | 6 +++- go.mod | 2 ++ go.sum | 2 ++ server/jsonrpc2.go | 82 +++++++++++++++++++++++++++++++++++++++++++++- server/server.go | 7 ++-- 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 1194d29..6c0fbab 100644 --- a/Makefile +++ b/Makefile @@ -57,4 +57,8 @@ build-all: test: go test -race -tags "reuseport kcp quic zookeeper etcd consul ping utp rudp" ./... - +update-libs: + GIT_TERMINAL_PROMPT=1 GO111MODULE=on go get -u -v . + +mod-tidy: + GIT_TERMINAL_PROMPT=1 GO111MODULE=on go mod tidy diff --git a/go.mod b/go.mod index 2b3cc15..cf24852 100644 --- a/go.mod +++ b/go.mod @@ -73,6 +73,7 @@ require ( github.com/prometheus/common v0.0.0-20190107103113-2998b132700a // indirect github.com/prometheus/procfs v0.0.0-20190104112138-b1a0a9a36d74 // indirect github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 + github.com/rs/cors v1.6.0 github.com/rubyist/circuitbreaker v2.2.1+incompatible github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect @@ -91,6 +92,7 @@ require ( golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect labix.org/v2/mgo v0.0.0-20140701140051-000000000287 // indirect diff --git a/go.sum b/go.sum index 7a40bf8..c39a71b 100644 --- a/go.sum +++ b/go.sum @@ -227,6 +227,8 @@ github.com/prometheus/procfs v0.0.0-20190104112138-b1a0a9a36d74 h1:d1Xoc24yp/pXm github.com/prometheus/procfs v0.0.0-20190104112138-b1a0a9a36d74/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rubyist/circuitbreaker v2.2.1+incompatible h1:KUKd/pV8Geg77+8LNDwdow6rVCAYOp8+kHUyFvL6Mhk= github.com/rubyist/circuitbreaker v2.2.1+incompatible/go.mod h1:Ycs3JgJADPuzJDwffe12k6BZT8hxVi6lFK+gWYJLN4A= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= diff --git a/server/jsonrpc2.go b/server/jsonrpc2.go index d85c118..1c6fab6 100644 --- a/server/jsonrpc2.go +++ b/server/jsonrpc2.go @@ -8,6 +8,7 @@ import ( "net/http" "strings" + "github.com/rs/cors" "github.com/smallnest/rpcx/protocol" ) @@ -96,8 +97,87 @@ func writeResponse(w http.ResponseWriter, res *jsonrpcRespone) { w.Write(data) } +type CORSOptions struct { + // AllowedOrigins is a list of origins a cross-domain request can be executed from. + // If the special "*" value is present in the list, all origins will be allowed. + // An origin may contain a wildcard (*) to replace 0 or more characters + // (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty. + // Only one wildcard can be used per origin. + // Default value is ["*"] + AllowedOrigins []string + // AllowOriginFunc is a custom function to validate the origin. It take the origin + // as argument and returns true if allowed or false otherwise. If this option is + // set, the content of AllowedOrigins is ignored. + AllowOriginFunc func(origin string) bool + // AllowOriginFunc is a custom function to validate the origin. It takes the HTTP Request object and the origin as + // argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins` + // and `AllowOriginFunc` is ignored. + AllowOriginRequestFunc func(r *http.Request, origin string) bool + // AllowedMethods is a list of methods the client is allowed to use with + // cross-domain requests. Default value is simple methods (HEAD, GET and POST). + AllowedMethods []string + // AllowedHeaders is list of non simple headers the client is allowed to use with + // cross-domain requests. + // If the special "*" value is present in the list, all headers will be allowed. + // Default value is [] but "Origin" is always appended to the list. + AllowedHeaders []string + // ExposedHeaders indicates which headers are safe to expose to the API of a CORS + // API specification + ExposedHeaders []string + // MaxAge indicates how long (in seconds) the results of a preflight request + // can be cached + MaxAge int + // AllowCredentials indicates whether the request can include user credentials like + // cookies, HTTP authentication or client side SSL certificates. + AllowCredentials bool + // OptionsPassthrough instructs preflight to let other potential next handlers to + // process the OPTIONS method. Turn this on if your application handles OPTIONS. + OptionsPassthrough bool + // Debugging flag adds additional output to debug server side CORS issues + Debug bool +} + +// AllowAllCORSOptions returns a option that allows access. +func AllowAllCORSOptions() *CORSOptions { + return &CORSOptions{ + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{ + http.MethodHead, + http.MethodGet, + http.MethodPost, + http.MethodPut, + http.MethodPatch, + http.MethodDelete, + }, + AllowedHeaders: []string{"*"}, + AllowCredentials: false, + } +} + +// SetCORS sets CORS options. +// for example: +// +// cors.Options{ +// AllowedOrigins: []string{"foo.com"}, +// AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete}, +// AllowCredentials: true, +// } +// +func (s *Server) SetCORS(options *CORSOptions) { + s.corsOptions = options +} + func (s *Server) startJSONRPC2(ln net.Listener) { newServer := http.NewServeMux() newServer.HandleFunc("/", s.jsonrpcHandler) - go http.Serve(ln, newServer) + + if s.corsOptions != nil { + opt := cors.Options(*s.corsOptions) + c := cors.New(opt) + mux := c.Handler(newServer) + go http.Serve(ln, mux) + } else { + go http.Serve(ln, newServer) + } + } diff --git a/server/server.go b/server/server.go index 962d804..3bedd7d 100644 --- a/server/server.go +++ b/server/server.go @@ -79,10 +79,9 @@ type Server struct { tlsConfig *tls.Config // BlockCrypt for kcp.BlockCrypt options map[string]interface{} - // // use for KCP - // KCPConfig KCPConfig - // // for QUIC - // QUICConfig QUICConfig + + // CORS options + corsOptions *CORSOptions Plugins PluginContainer