github.com/coltonfike/e2c@v21.1.0+incompatible/rpc/server.go (about) 1 // Copyright 2015 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 rpc 18 19 import ( 20 "context" 21 "io" 22 "net/http" 23 "sync/atomic" 24 25 mapset "github.com/deckarep/golang-set" 26 "github.com/ethereum/go-ethereum/log" 27 "github.com/ethereum/go-ethereum/plugin/security" 28 ) 29 30 const MetadataApi = "rpc" 31 32 // CodecOption specifies which type of messages a codec supports. 33 // 34 // Deprecated: this option is no longer honored by Server. 35 type CodecOption int 36 37 const ( 38 // OptionMethodInvocation is an indication that the codec supports RPC method calls 39 OptionMethodInvocation CodecOption = 1 << iota 40 41 // OptionSubscriptions is an indication that the codec suports RPC notifications 42 OptionSubscriptions = 1 << iota // support pub sub 43 ) 44 45 // Server is an RPC server. 46 type Server struct { 47 services serviceRegistry 48 idgen func() ID 49 run int32 50 codecs mapset.Set 51 52 // Quorum 53 // The implementation would authenticate the token coming from a request 54 authenticationManager security.AuthenticationManager 55 } 56 57 // Quorum 58 // Create a server which is protected by authManager 59 func NewProtectedServer(authManager security.AuthenticationManager) *Server { 60 server := NewServer() 61 if authManager != nil { 62 server.authenticationManager = authManager 63 } 64 return server 65 } 66 67 // NewServer creates a new server instance with no registered handlers. 68 func NewServer() *Server { 69 server := &Server{idgen: randomIDGenerator(), codecs: mapset.NewSet(), run: 1, authenticationManager: security.NewDisabledAuthenticationManager()} 70 // Register the default service providing meta information about the RPC service such 71 // as the services and methods it offers. 72 rpcService := &RPCService{server} 73 server.RegisterName(MetadataApi, rpcService) 74 return server 75 } 76 77 // RegisterName creates a service for the given receiver type under the given name. When no 78 // methods on the given receiver match the criteria to be either a RPC method or a 79 // subscription an error is returned. Otherwise a new service is created and added to the 80 // service collection this server provides to clients. 81 func (s *Server) RegisterName(name string, receiver interface{}) error { 82 return s.services.registerName(name, receiver) 83 } 84 85 // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes 86 // the response back using the given codec. It will block until the codec is closed or the 87 // server is stopped. In either case the codec is closed. 88 // 89 // Note that codec options are no longer supported. 90 func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { 91 defer codec.Close() 92 93 // Don't serve if server is stopped. 94 if atomic.LoadInt32(&s.run) == 0 { 95 return 96 } 97 98 // Add the codec to the set so it can be closed by Stop. 99 s.codecs.Add(codec) 100 defer s.codecs.Remove(codec) 101 102 c := initClient(codec, s.idgen, &s.services) 103 <-codec.Closed() 104 c.Close() 105 } 106 107 // serveSingleRequest reads and processes a single RPC request from the given codec. This 108 // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in 109 // this mode. 110 func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { 111 // Don't serve if server is stopped. 112 if atomic.LoadInt32(&s.run) == 0 { 113 return 114 } 115 116 h := newHandler(ctx, codec, s.idgen, &s.services) 117 h.allowSubscribe = false 118 defer h.close(io.EOF, nil) 119 120 reqs, batch, err := codec.Read() 121 if err != nil { 122 if err != io.EOF { 123 codec.Write(ctx, errorMessage(&invalidMessageError{"parse error"})) 124 } 125 return 126 } 127 if batch { 128 h.handleBatch(reqs) 129 } else { 130 h.handleMsg(reqs[0]) 131 } 132 } 133 134 // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending 135 // requests to finish, then closes all codecs which will cancel pending requests and 136 // subscriptions. 137 func (s *Server) Stop() { 138 if atomic.CompareAndSwapInt32(&s.run, 1, 0) { 139 log.Debug("RPC server shutting down") 140 s.codecs.Each(func(c interface{}) bool { 141 c.(ServerCodec).Close() 142 return true 143 }) 144 } 145 } 146 147 // Quorum 148 // Perform authentication on the HTTP request. Populate security context with necessary information 149 // for subsequent authorization-related activities 150 func (s *Server) authenticateHttpRequest(r *http.Request, cfg securityContextConfigurer) { 151 securityContext := context.Background() 152 defer func() { 153 cfg.Configure(securityContext) 154 }() 155 if isAuthEnabled, err := s.authenticationManager.IsEnabled(context.Background()); err != nil { 156 // this indicates a failure in the plugin. We don't want any subsequent request unchecked 157 log.Error("failure when checking if authentication manager is enabled", "err", err) 158 securityContext = context.WithValue(securityContext, ctxAuthenticationError, &securityError{"internal error"}) 159 return 160 } else if !isAuthEnabled { 161 return 162 } 163 if token, hasToken := extractToken(r); hasToken { 164 if authToken, err := s.authenticationManager.Authenticate(context.Background(), token); err != nil { 165 securityContext = context.WithValue(securityContext, ctxAuthenticationError, &securityError{err.Error()}) 166 } else { 167 securityContext = context.WithValue(securityContext, CtxPreauthenticatedToken, authToken) 168 } 169 } else { 170 securityContext = context.WithValue(securityContext, ctxAuthenticationError, &securityError{"missing access token"}) 171 } 172 } 173 174 // RPCService gives meta information about the server. 175 // e.g. gives information about the loaded modules. 176 type RPCService struct { 177 server *Server 178 } 179 180 // Modules returns the list of RPC services with their version number 181 func (s *RPCService) Modules() map[string]string { 182 s.server.services.mu.Lock() 183 defer s.server.services.mu.Unlock() 184 185 modules := make(map[string]string) 186 for name := range s.server.services.services { 187 modules[name] = "1.0" 188 } 189 return modules 190 }