github.com/aswedchain/aswed@v1.0.1/node/rpcstack.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "compress/gzip" 21 "context" 22 "fmt" 23 "io" 24 "io/ioutil" 25 "net" 26 "net/http" 27 "sort" 28 "strings" 29 "sync" 30 "sync/atomic" 31 32 "github.com/aswedchain/aswed/log" 33 "github.com/aswedchain/aswed/rpc" 34 "github.com/rs/cors" 35 ) 36 37 // httpConfig is the JSON-RPC/HTTP configuration. 38 type httpConfig struct { 39 Modules []string 40 CorsAllowedOrigins []string 41 Vhosts []string 42 } 43 44 // wsConfig is the JSON-RPC/Websocket configuration 45 type wsConfig struct { 46 Origins []string 47 Modules []string 48 } 49 50 type rpcHandler struct { 51 http.Handler 52 server *rpc.Server 53 } 54 55 type httpServer struct { 56 log log.Logger 57 timeouts rpc.HTTPTimeouts 58 mux http.ServeMux // registered handlers go here 59 60 mu sync.Mutex 61 server *http.Server 62 listener net.Listener // non-nil when server is running 63 64 // HTTP RPC handler things. 65 httpConfig httpConfig 66 httpHandler atomic.Value // *rpcHandler 67 68 // WebSocket handler things. 69 wsConfig wsConfig 70 wsHandler atomic.Value // *rpcHandler 71 72 // These are set by setListenAddr. 73 endpoint string 74 host string 75 port int 76 77 handlerNames map[string]string 78 } 79 80 func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer { 81 h := &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)} 82 h.httpHandler.Store((*rpcHandler)(nil)) 83 h.wsHandler.Store((*rpcHandler)(nil)) 84 return h 85 } 86 87 // setListenAddr configures the listening address of the server. 88 // The address can only be set while the server isn't running. 89 func (h *httpServer) setListenAddr(host string, port int) error { 90 h.mu.Lock() 91 defer h.mu.Unlock() 92 93 if h.listener != nil && (host != h.host || port != h.port) { 94 return fmt.Errorf("HTTP server already running on %s", h.endpoint) 95 } 96 97 h.host, h.port = host, port 98 h.endpoint = fmt.Sprintf("%s:%d", host, port) 99 return nil 100 } 101 102 // listenAddr returns the listening address of the server. 103 func (h *httpServer) listenAddr() string { 104 h.mu.Lock() 105 defer h.mu.Unlock() 106 107 if h.listener != nil { 108 return h.listener.Addr().String() 109 } 110 return h.endpoint 111 } 112 113 // start starts the HTTP server if it is enabled and not already running. 114 func (h *httpServer) start() error { 115 h.mu.Lock() 116 defer h.mu.Unlock() 117 118 if h.endpoint == "" || h.listener != nil { 119 return nil // already running or not configured 120 } 121 122 // Initialize the server. 123 h.server = &http.Server{Handler: h} 124 if h.timeouts != (rpc.HTTPTimeouts{}) { 125 CheckTimeouts(&h.timeouts) 126 h.server.ReadTimeout = h.timeouts.ReadTimeout 127 h.server.WriteTimeout = h.timeouts.WriteTimeout 128 h.server.IdleTimeout = h.timeouts.IdleTimeout 129 } 130 131 // Start the server. 132 listener, err := net.Listen("tcp", h.endpoint) 133 if err != nil { 134 // If the server fails to start, we need to clear out the RPC and WS 135 // configuration so they can be configured another time. 136 h.disableRPC() 137 h.disableWS() 138 return err 139 } 140 h.listener = listener 141 go h.server.Serve(listener) 142 143 // if server is websocket only, return after logging 144 if h.wsAllowed() && !h.rpcAllowed() { 145 h.log.Info("WebSocket enabled", "url", fmt.Sprintf("ws://%v", listener.Addr())) 146 return nil 147 } 148 // Log http endpoint. 149 h.log.Info("HTTP server started", 150 "endpoint", listener.Addr(), 151 "cors", strings.Join(h.httpConfig.CorsAllowedOrigins, ","), 152 "vhosts", strings.Join(h.httpConfig.Vhosts, ","), 153 ) 154 155 // Log all handlers mounted on server. 156 var paths []string 157 for path := range h.handlerNames { 158 paths = append(paths, path) 159 } 160 sort.Strings(paths) 161 logged := make(map[string]bool, len(paths)) 162 for _, path := range paths { 163 name := h.handlerNames[path] 164 if !logged[name] { 165 log.Info(name+" enabled", "url", "http://"+listener.Addr().String()+path) 166 logged[name] = true 167 } 168 } 169 return nil 170 } 171 172 func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 173 rpc := h.httpHandler.Load().(*rpcHandler) 174 if r.RequestURI == "/" { 175 // Serve JSON-RPC on the root path. 176 ws := h.wsHandler.Load().(*rpcHandler) 177 if ws != nil && isWebsocket(r) { 178 ws.ServeHTTP(w, r) 179 return 180 } 181 if rpc != nil { 182 rpc.ServeHTTP(w, r) 183 return 184 } 185 } else if rpc != nil { 186 // Requests to a path below root are handled by the mux, 187 // which has all the handlers registered via Node.RegisterHandler. 188 // These are made available when RPC is enabled. 189 h.mux.ServeHTTP(w, r) 190 return 191 } 192 w.WriteHeader(404) 193 } 194 195 // stop shuts down the HTTP server. 196 func (h *httpServer) stop() { 197 h.mu.Lock() 198 defer h.mu.Unlock() 199 h.doStop() 200 } 201 202 func (h *httpServer) doStop() { 203 if h.listener == nil { 204 return // not running 205 } 206 207 // Shut down the server. 208 httpHandler := h.httpHandler.Load().(*rpcHandler) 209 wsHandler := h.httpHandler.Load().(*rpcHandler) 210 if httpHandler != nil { 211 h.httpHandler.Store((*rpcHandler)(nil)) 212 httpHandler.server.Stop() 213 } 214 if wsHandler != nil { 215 h.wsHandler.Store((*rpcHandler)(nil)) 216 wsHandler.server.Stop() 217 } 218 h.server.Shutdown(context.Background()) 219 h.listener.Close() 220 h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr()) 221 222 // Clear out everything to allow re-configuring it later. 223 h.host, h.port, h.endpoint = "", 0, "" 224 h.server, h.listener = nil, nil 225 } 226 227 // enableRPC turns on JSON-RPC over HTTP on the server. 228 func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error { 229 h.mu.Lock() 230 defer h.mu.Unlock() 231 232 if h.rpcAllowed() { 233 return fmt.Errorf("JSON-RPC over HTTP is already enabled") 234 } 235 236 // Create RPC server and handler. 237 srv := rpc.NewServer() 238 if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil { 239 return err 240 } 241 h.httpConfig = config 242 h.httpHandler.Store(&rpcHandler{ 243 Handler: NewHTTPHandlerStack(srv, config.CorsAllowedOrigins, config.Vhosts), 244 server: srv, 245 }) 246 return nil 247 } 248 249 // disableRPC stops the HTTP RPC handler. This is internal, the caller must hold h.mu. 250 func (h *httpServer) disableRPC() bool { 251 handler := h.httpHandler.Load().(*rpcHandler) 252 if handler != nil { 253 h.httpHandler.Store((*rpcHandler)(nil)) 254 handler.server.Stop() 255 } 256 return handler != nil 257 } 258 259 // enableWS turns on JSON-RPC over WebSocket on the server. 260 func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error { 261 h.mu.Lock() 262 defer h.mu.Unlock() 263 264 if h.wsAllowed() { 265 return fmt.Errorf("JSON-RPC over WebSocket is already enabled") 266 } 267 268 // Create RPC server and handler. 269 srv := rpc.NewServer() 270 if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil { 271 return err 272 } 273 h.wsConfig = config 274 h.wsHandler.Store(&rpcHandler{ 275 Handler: srv.WebsocketHandler(config.Origins), 276 server: srv, 277 }) 278 return nil 279 } 280 281 // stopWS disables JSON-RPC over WebSocket and also stops the server if it only serves WebSocket. 282 func (h *httpServer) stopWS() { 283 h.mu.Lock() 284 defer h.mu.Unlock() 285 286 if h.disableWS() { 287 if !h.rpcAllowed() { 288 h.doStop() 289 } 290 } 291 } 292 293 // disableWS disables the WebSocket handler. This is internal, the caller must hold h.mu. 294 func (h *httpServer) disableWS() bool { 295 ws := h.wsHandler.Load().(*rpcHandler) 296 if ws != nil { 297 h.wsHandler.Store((*rpcHandler)(nil)) 298 ws.server.Stop() 299 } 300 return ws != nil 301 } 302 303 // rpcAllowed returns true when JSON-RPC over HTTP is enabled. 304 func (h *httpServer) rpcAllowed() bool { 305 return h.httpHandler.Load().(*rpcHandler) != nil 306 } 307 308 // wsAllowed returns true when JSON-RPC over WebSocket is enabled. 309 func (h *httpServer) wsAllowed() bool { 310 return h.wsHandler.Load().(*rpcHandler) != nil 311 } 312 313 // isWebsocket checks the header of an http request for a websocket upgrade request. 314 func isWebsocket(r *http.Request) bool { 315 return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" && 316 strings.Contains(strings.ToLower(r.Header.Get("Connection")), "upgrade") 317 } 318 319 // NewHTTPHandlerStack returns wrapped http-related handlers 320 func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string) http.Handler { 321 // Wrap the CORS-handler within a host-handler 322 handler := newCorsHandler(srv, cors) 323 handler = newVHostHandler(vhosts, handler) 324 return newGzipHandler(handler) 325 } 326 327 func newCorsHandler(srv http.Handler, allowedOrigins []string) http.Handler { 328 // disable CORS support if user has not specified a custom CORS configuration 329 if len(allowedOrigins) == 0 { 330 return srv 331 } 332 c := cors.New(cors.Options{ 333 AllowedOrigins: allowedOrigins, 334 AllowedMethods: []string{http.MethodPost, http.MethodGet}, 335 AllowedHeaders: []string{"*"}, 336 MaxAge: 600, 337 }) 338 return c.Handler(srv) 339 } 340 341 // virtualHostHandler is a handler which validates the Host-header of incoming requests. 342 // Using virtual hosts can help prevent DNS rebinding attacks, where a 'random' domain name points to 343 // the service ip address (but without CORS headers). By verifying the targeted virtual host, we can 344 // ensure that it's a destination that the node operator has defined. 345 type virtualHostHandler struct { 346 vhosts map[string]struct{} 347 next http.Handler 348 } 349 350 func newVHostHandler(vhosts []string, next http.Handler) http.Handler { 351 vhostMap := make(map[string]struct{}) 352 for _, allowedHost := range vhosts { 353 vhostMap[strings.ToLower(allowedHost)] = struct{}{} 354 } 355 return &virtualHostHandler{vhostMap, next} 356 } 357 358 // ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler 359 func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 360 // if r.Host is not set, we can continue serving since a browser would set the Host header 361 if r.Host == "" { 362 h.next.ServeHTTP(w, r) 363 return 364 } 365 host, _, err := net.SplitHostPort(r.Host) 366 if err != nil { 367 // Either invalid (too many colons) or no port specified 368 host = r.Host 369 } 370 if ipAddr := net.ParseIP(host); ipAddr != nil { 371 // It's an IP address, we can serve that 372 h.next.ServeHTTP(w, r) 373 return 374 375 } 376 // Not an IP address, but a hostname. Need to validate 377 if _, exist := h.vhosts["*"]; exist { 378 h.next.ServeHTTP(w, r) 379 return 380 } 381 if _, exist := h.vhosts[host]; exist { 382 h.next.ServeHTTP(w, r) 383 return 384 } 385 http.Error(w, "invalid host specified", http.StatusForbidden) 386 } 387 388 var gzPool = sync.Pool{ 389 New: func() interface{} { 390 w := gzip.NewWriter(ioutil.Discard) 391 return w 392 }, 393 } 394 395 type gzipResponseWriter struct { 396 io.Writer 397 http.ResponseWriter 398 } 399 400 func (w *gzipResponseWriter) WriteHeader(status int) { 401 w.Header().Del("Content-Length") 402 w.ResponseWriter.WriteHeader(status) 403 } 404 405 func (w *gzipResponseWriter) Write(b []byte) (int, error) { 406 return w.Writer.Write(b) 407 } 408 409 func newGzipHandler(next http.Handler) http.Handler { 410 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 411 if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { 412 next.ServeHTTP(w, r) 413 return 414 } 415 416 w.Header().Set("Content-Encoding", "gzip") 417 418 gz := gzPool.Get().(*gzip.Writer) 419 defer gzPool.Put(gz) 420 421 gz.Reset(w) 422 defer gz.Close() 423 424 next.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, r) 425 }) 426 } 427 428 type ipcServer struct { 429 log log.Logger 430 endpoint string 431 432 mu sync.Mutex 433 listener net.Listener 434 srv *rpc.Server 435 } 436 437 func newIPCServer(log log.Logger, endpoint string) *ipcServer { 438 return &ipcServer{log: log, endpoint: endpoint} 439 } 440 441 // Start starts the httpServer's http.Server 442 func (is *ipcServer) start(apis []rpc.API) error { 443 is.mu.Lock() 444 defer is.mu.Unlock() 445 446 if is.listener != nil { 447 return nil // already running 448 } 449 listener, srv, err := rpc.StartIPCEndpoint(is.endpoint, apis) 450 if err != nil { 451 return err 452 } 453 is.log.Info("IPC endpoint opened", "url", is.endpoint) 454 is.listener, is.srv = listener, srv 455 return nil 456 } 457 458 func (is *ipcServer) stop() error { 459 is.mu.Lock() 460 defer is.mu.Unlock() 461 462 if is.listener == nil { 463 return nil // not running 464 } 465 err := is.listener.Close() 466 is.srv.Stop() 467 is.listener, is.srv = nil, nil 468 is.log.Info("IPC endpoint closed", "url", is.endpoint) 469 return err 470 } 471 472 // RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules, 473 // and then registers all of the APIs exposed by the services. 474 func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error { 475 if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 { 476 log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available) 477 } 478 // Generate the whitelist based on the allowed modules 479 whitelist := make(map[string]bool) 480 for _, module := range modules { 481 whitelist[module] = true 482 } 483 // Register all the APIs exposed by the services 484 for _, api := range apis { 485 if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { 486 if err := srv.RegisterName(api.Namespace, api.Service); err != nil { 487 return err 488 } 489 } 490 } 491 return nil 492 }