http.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. // Copyright 2017 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. package simulations
  17. import (
  18. "bufio"
  19. "bytes"
  20. "context"
  21. "encoding/json"
  22. "errors"
  23. "fmt"
  24. "html"
  25. "io"
  26. "net/http"
  27. "strconv"
  28. "strings"
  29. "sync"
  30. "github.com/ethereum/go-ethereum/event"
  31. "github.com/ethereum/go-ethereum/p2p"
  32. "github.com/ethereum/go-ethereum/p2p/enode"
  33. "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
  34. "github.com/ethereum/go-ethereum/rpc"
  35. "github.com/gorilla/websocket"
  36. "github.com/julienschmidt/httprouter"
  37. )
  38. // DefaultClient is the default simulation API client which expects the API
  39. // to be running at http://localhost:8888
  40. var DefaultClient = NewClient("http://localhost:8888")
  41. // Client is a client for the simulation HTTP API which supports creating
  42. // and managing simulation networks
  43. type Client struct {
  44. URL string
  45. client *http.Client
  46. }
  47. // NewClient returns a new simulation API client
  48. func NewClient(url string) *Client {
  49. return &Client{
  50. URL: url,
  51. client: http.DefaultClient,
  52. }
  53. }
  54. // GetNetwork returns details of the network
  55. func (c *Client) GetNetwork() (*Network, error) {
  56. network := &Network{}
  57. return network, c.Get("/", network)
  58. }
  59. // StartNetwork starts all existing nodes in the simulation network
  60. func (c *Client) StartNetwork() error {
  61. return c.Post("/start", nil, nil)
  62. }
  63. // StopNetwork stops all existing nodes in a simulation network
  64. func (c *Client) StopNetwork() error {
  65. return c.Post("/stop", nil, nil)
  66. }
  67. // CreateSnapshot creates a network snapshot
  68. func (c *Client) CreateSnapshot() (*Snapshot, error) {
  69. snap := &Snapshot{}
  70. return snap, c.Get("/snapshot", snap)
  71. }
  72. // LoadSnapshot loads a snapshot into the network
  73. func (c *Client) LoadSnapshot(snap *Snapshot) error {
  74. return c.Post("/snapshot", snap, nil)
  75. }
  76. // SubscribeOpts is a collection of options to use when subscribing to network
  77. // events
  78. type SubscribeOpts struct {
  79. // Current instructs the server to send events for existing nodes and
  80. // connections first
  81. Current bool
  82. // Filter instructs the server to only send a subset of message events
  83. Filter string
  84. }
  85. // SubscribeNetwork subscribes to network events which are sent from the server
  86. // as a server-sent-events stream, optionally receiving events for existing
  87. // nodes and connections and filtering message events
  88. func (c *Client) SubscribeNetwork(events chan *Event, opts SubscribeOpts) (event.Subscription, error) {
  89. url := fmt.Sprintf("%s/events?current=%t&filter=%s", c.URL, opts.Current, opts.Filter)
  90. req, err := http.NewRequest("GET", url, nil)
  91. if err != nil {
  92. return nil, err
  93. }
  94. req.Header.Set("Accept", "text/event-stream")
  95. res, err := c.client.Do(req)
  96. if err != nil {
  97. return nil, err
  98. }
  99. if res.StatusCode != http.StatusOK {
  100. response, _ := io.ReadAll(res.Body)
  101. res.Body.Close()
  102. return nil, fmt.Errorf("unexpected HTTP status: %s: %s", res.Status, response)
  103. }
  104. // define a producer function to pass to event.Subscription
  105. // which reads server-sent events from res.Body and sends
  106. // them to the events channel
  107. producer := func(stop <-chan struct{}) error {
  108. defer res.Body.Close()
  109. // read lines from res.Body in a goroutine so that we are
  110. // always reading from the stop channel
  111. lines := make(chan string)
  112. errC := make(chan error, 1)
  113. go func() {
  114. s := bufio.NewScanner(res.Body)
  115. for s.Scan() {
  116. select {
  117. case lines <- s.Text():
  118. case <-stop:
  119. return
  120. }
  121. }
  122. errC <- s.Err()
  123. }()
  124. // detect any lines which start with "data:", decode the data
  125. // into an event and send it to the events channel
  126. for {
  127. select {
  128. case line := <-lines:
  129. if !strings.HasPrefix(line, "data:") {
  130. continue
  131. }
  132. data := strings.TrimSpace(strings.TrimPrefix(line, "data:"))
  133. event := &Event{}
  134. if err := json.Unmarshal([]byte(data), event); err != nil {
  135. return fmt.Errorf("error decoding SSE event: %s", err)
  136. }
  137. select {
  138. case events <- event:
  139. case <-stop:
  140. return nil
  141. }
  142. case err := <-errC:
  143. return err
  144. case <-stop:
  145. return nil
  146. }
  147. }
  148. }
  149. return event.NewSubscription(producer), nil
  150. }
  151. // GetNodes returns all nodes which exist in the network
  152. func (c *Client) GetNodes() ([]*p2p.NodeInfo, error) {
  153. var nodes []*p2p.NodeInfo
  154. return nodes, c.Get("/nodes", &nodes)
  155. }
  156. // CreateNode creates a node in the network using the given configuration
  157. func (c *Client) CreateNode(config *adapters.NodeConfig) (*p2p.NodeInfo, error) {
  158. node := &p2p.NodeInfo{}
  159. return node, c.Post("/nodes", config, node)
  160. }
  161. // GetNode returns details of a node
  162. func (c *Client) GetNode(nodeID string) (*p2p.NodeInfo, error) {
  163. node := &p2p.NodeInfo{}
  164. return node, c.Get(fmt.Sprintf("/nodes/%s", nodeID), node)
  165. }
  166. // StartNode starts a node
  167. func (c *Client) StartNode(nodeID string) error {
  168. return c.Post(fmt.Sprintf("/nodes/%s/start", nodeID), nil, nil)
  169. }
  170. // StopNode stops a node
  171. func (c *Client) StopNode(nodeID string) error {
  172. return c.Post(fmt.Sprintf("/nodes/%s/stop", nodeID), nil, nil)
  173. }
  174. // ConnectNode connects a node to a peer node
  175. func (c *Client) ConnectNode(nodeID, peerID string) error {
  176. return c.Post(fmt.Sprintf("/nodes/%s/conn/%s", nodeID, peerID), nil, nil)
  177. }
  178. // DisconnectNode disconnects a node from a peer node
  179. func (c *Client) DisconnectNode(nodeID, peerID string) error {
  180. return c.Delete(fmt.Sprintf("/nodes/%s/conn/%s", nodeID, peerID))
  181. }
  182. // RPCClient returns an RPC client connected to a node
  183. func (c *Client) RPCClient(ctx context.Context, nodeID string) (*rpc.Client, error) {
  184. baseURL := strings.Replace(c.URL, "http", "ws", 1)
  185. return rpc.DialWebsocket(ctx, fmt.Sprintf("%s/nodes/%s/rpc", baseURL, nodeID), "")
  186. }
  187. // Get performs a HTTP GET request decoding the resulting JSON response
  188. // into "out"
  189. func (c *Client) Get(path string, out interface{}) error {
  190. return c.Send("GET", path, nil, out)
  191. }
  192. // Post performs a HTTP POST request sending "in" as the JSON body and
  193. // decoding the resulting JSON response into "out"
  194. func (c *Client) Post(path string, in, out interface{}) error {
  195. return c.Send("POST", path, in, out)
  196. }
  197. // Delete performs a HTTP DELETE request
  198. func (c *Client) Delete(path string) error {
  199. return c.Send("DELETE", path, nil, nil)
  200. }
  201. // Send performs a HTTP request, sending "in" as the JSON request body and
  202. // decoding the JSON response into "out"
  203. func (c *Client) Send(method, path string, in, out interface{}) error {
  204. var body []byte
  205. if in != nil {
  206. var err error
  207. body, err = json.Marshal(in)
  208. if err != nil {
  209. return err
  210. }
  211. }
  212. req, err := http.NewRequest(method, c.URL+path, bytes.NewReader(body))
  213. if err != nil {
  214. return err
  215. }
  216. req.Header.Set("Content-Type", "application/json")
  217. req.Header.Set("Accept", "application/json")
  218. res, err := c.client.Do(req)
  219. if err != nil {
  220. return err
  221. }
  222. defer res.Body.Close()
  223. if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated {
  224. response, _ := io.ReadAll(res.Body)
  225. return fmt.Errorf("unexpected HTTP status: %s: %s", res.Status, response)
  226. }
  227. if out != nil {
  228. if err := json.NewDecoder(res.Body).Decode(out); err != nil {
  229. return err
  230. }
  231. }
  232. return nil
  233. }
  234. // Server is an HTTP server providing an API to manage a simulation network
  235. type Server struct {
  236. router *httprouter.Router
  237. network *Network
  238. mockerStop chan struct{} // when set, stops the current mocker
  239. mockerMtx sync.Mutex // synchronises access to the mockerStop field
  240. }
  241. // NewServer returns a new simulation API server
  242. func NewServer(network *Network) *Server {
  243. s := &Server{
  244. router: httprouter.New(),
  245. network: network,
  246. }
  247. s.OPTIONS("/", s.Options)
  248. s.GET("/", s.GetNetwork)
  249. s.POST("/start", s.StartNetwork)
  250. s.POST("/stop", s.StopNetwork)
  251. s.POST("/mocker/start", s.StartMocker)
  252. s.POST("/mocker/stop", s.StopMocker)
  253. s.GET("/mocker", s.GetMockers)
  254. s.POST("/reset", s.ResetNetwork)
  255. s.GET("/events", s.StreamNetworkEvents)
  256. s.GET("/snapshot", s.CreateSnapshot)
  257. s.POST("/snapshot", s.LoadSnapshot)
  258. s.POST("/nodes", s.CreateNode)
  259. s.GET("/nodes", s.GetNodes)
  260. s.GET("/nodes/:nodeid", s.GetNode)
  261. s.POST("/nodes/:nodeid/start", s.StartNode)
  262. s.POST("/nodes/:nodeid/stop", s.StopNode)
  263. s.POST("/nodes/:nodeid/conn/:peerid", s.ConnectNode)
  264. s.DELETE("/nodes/:nodeid/conn/:peerid", s.DisconnectNode)
  265. s.GET("/nodes/:nodeid/rpc", s.NodeRPC)
  266. return s
  267. }
  268. // GetNetwork returns details of the network
  269. func (s *Server) GetNetwork(w http.ResponseWriter, req *http.Request) {
  270. s.JSON(w, http.StatusOK, s.network)
  271. }
  272. // StartNetwork starts all nodes in the network
  273. func (s *Server) StartNetwork(w http.ResponseWriter, req *http.Request) {
  274. if err := s.network.StartAll(); err != nil {
  275. http.Error(w, err.Error(), http.StatusInternalServerError)
  276. return
  277. }
  278. w.WriteHeader(http.StatusOK)
  279. }
  280. // StopNetwork stops all nodes in the network
  281. func (s *Server) StopNetwork(w http.ResponseWriter, req *http.Request) {
  282. if err := s.network.StopAll(); err != nil {
  283. http.Error(w, err.Error(), http.StatusInternalServerError)
  284. return
  285. }
  286. w.WriteHeader(http.StatusOK)
  287. }
  288. // StartMocker starts the mocker node simulation
  289. func (s *Server) StartMocker(w http.ResponseWriter, req *http.Request) {
  290. s.mockerMtx.Lock()
  291. defer s.mockerMtx.Unlock()
  292. if s.mockerStop != nil {
  293. http.Error(w, "mocker already running", http.StatusInternalServerError)
  294. return
  295. }
  296. mockerType := req.FormValue("mocker-type")
  297. mockerFn := LookupMocker(mockerType)
  298. if mockerFn == nil {
  299. http.Error(w, fmt.Sprintf("unknown mocker type %q", html.EscapeString(mockerType)), http.StatusBadRequest)
  300. return
  301. }
  302. nodeCount, err := strconv.Atoi(req.FormValue("node-count"))
  303. if err != nil {
  304. http.Error(w, "invalid node-count provided", http.StatusBadRequest)
  305. return
  306. }
  307. s.mockerStop = make(chan struct{})
  308. go mockerFn(s.network, s.mockerStop, nodeCount)
  309. w.WriteHeader(http.StatusOK)
  310. }
  311. // StopMocker stops the mocker node simulation
  312. func (s *Server) StopMocker(w http.ResponseWriter, req *http.Request) {
  313. s.mockerMtx.Lock()
  314. defer s.mockerMtx.Unlock()
  315. if s.mockerStop == nil {
  316. http.Error(w, "stop channel not initialized", http.StatusInternalServerError)
  317. return
  318. }
  319. close(s.mockerStop)
  320. s.mockerStop = nil
  321. w.WriteHeader(http.StatusOK)
  322. }
  323. // GetMockerList returns a list of available mockers
  324. func (s *Server) GetMockers(w http.ResponseWriter, req *http.Request) {
  325. list := GetMockerList()
  326. s.JSON(w, http.StatusOK, list)
  327. }
  328. // ResetNetwork resets all properties of a network to its initial (empty) state
  329. func (s *Server) ResetNetwork(w http.ResponseWriter, req *http.Request) {
  330. s.network.Reset()
  331. w.WriteHeader(http.StatusOK)
  332. }
  333. // StreamNetworkEvents streams network events as a server-sent-events stream
  334. func (s *Server) StreamNetworkEvents(w http.ResponseWriter, req *http.Request) {
  335. events := make(chan *Event)
  336. sub := s.network.events.Subscribe(events)
  337. defer sub.Unsubscribe()
  338. // write writes the given event and data to the stream like:
  339. //
  340. // event: <event>
  341. // data: <data>
  342. //
  343. write := func(event, data string) {
  344. fmt.Fprintf(w, "event: %s\n", event)
  345. fmt.Fprintf(w, "data: %s\n\n", data)
  346. if fw, ok := w.(http.Flusher); ok {
  347. fw.Flush()
  348. }
  349. }
  350. writeEvent := func(event *Event) error {
  351. data, err := json.Marshal(event)
  352. if err != nil {
  353. return err
  354. }
  355. write("network", string(data))
  356. return nil
  357. }
  358. writeErr := func(err error) {
  359. write("error", err.Error())
  360. }
  361. // check if filtering has been requested
  362. var filters MsgFilters
  363. if filterParam := req.URL.Query().Get("filter"); filterParam != "" {
  364. var err error
  365. filters, err = NewMsgFilters(filterParam)
  366. if err != nil {
  367. http.Error(w, err.Error(), http.StatusBadRequest)
  368. return
  369. }
  370. }
  371. w.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
  372. w.WriteHeader(http.StatusOK)
  373. fmt.Fprintf(w, "\n\n")
  374. if fw, ok := w.(http.Flusher); ok {
  375. fw.Flush()
  376. }
  377. // optionally send the existing nodes and connections
  378. if req.URL.Query().Get("current") == "true" {
  379. snap, err := s.network.Snapshot()
  380. if err != nil {
  381. writeErr(err)
  382. return
  383. }
  384. for _, node := range snap.Nodes {
  385. event := NewEvent(&node.Node)
  386. if err := writeEvent(event); err != nil {
  387. writeErr(err)
  388. return
  389. }
  390. }
  391. for _, conn := range snap.Conns {
  392. conn := conn
  393. event := NewEvent(&conn)
  394. if err := writeEvent(event); err != nil {
  395. writeErr(err)
  396. return
  397. }
  398. }
  399. }
  400. clientGone := req.Context().Done()
  401. for {
  402. select {
  403. case event := <-events:
  404. // only send message events which match the filters
  405. if event.Msg != nil && !filters.Match(event.Msg) {
  406. continue
  407. }
  408. if err := writeEvent(event); err != nil {
  409. writeErr(err)
  410. return
  411. }
  412. case <-clientGone:
  413. return
  414. }
  415. }
  416. }
  417. // NewMsgFilters constructs a collection of message filters from a URL query
  418. // parameter.
  419. //
  420. // The parameter is expected to be a dash-separated list of individual filters,
  421. // each having the format '<proto>:<codes>', where <proto> is the name of a
  422. // protocol and <codes> is a comma-separated list of message codes.
  423. //
  424. // A message code of '*' or '-1' is considered a wildcard and matches any code.
  425. func NewMsgFilters(filterParam string) (MsgFilters, error) {
  426. filters := make(MsgFilters)
  427. for _, filter := range strings.Split(filterParam, "-") {
  428. protoCodes := strings.SplitN(filter, ":", 2)
  429. if len(protoCodes) != 2 || protoCodes[0] == "" || protoCodes[1] == "" {
  430. return nil, fmt.Errorf("invalid message filter: %s", filter)
  431. }
  432. proto := protoCodes[0]
  433. for _, code := range strings.Split(protoCodes[1], ",") {
  434. if code == "*" || code == "-1" {
  435. filters[MsgFilter{Proto: proto, Code: -1}] = struct{}{}
  436. continue
  437. }
  438. n, err := strconv.ParseUint(code, 10, 64)
  439. if err != nil {
  440. return nil, fmt.Errorf("invalid message code: %s", code)
  441. }
  442. filters[MsgFilter{Proto: proto, Code: int64(n)}] = struct{}{}
  443. }
  444. }
  445. return filters, nil
  446. }
  447. // MsgFilters is a collection of filters which are used to filter message
  448. // events
  449. type MsgFilters map[MsgFilter]struct{}
  450. // Match checks if the given message matches any of the filters
  451. func (m MsgFilters) Match(msg *Msg) bool {
  452. // check if there is a wildcard filter for the message's protocol
  453. if _, ok := m[MsgFilter{Proto: msg.Protocol, Code: -1}]; ok {
  454. return true
  455. }
  456. // check if there is a filter for the message's protocol and code
  457. if _, ok := m[MsgFilter{Proto: msg.Protocol, Code: int64(msg.Code)}]; ok {
  458. return true
  459. }
  460. return false
  461. }
  462. // MsgFilter is used to filter message events based on protocol and message
  463. // code
  464. type MsgFilter struct {
  465. // Proto is matched against a message's protocol
  466. Proto string
  467. // Code is matched against a message's code, with -1 matching all codes
  468. Code int64
  469. }
  470. // CreateSnapshot creates a network snapshot
  471. func (s *Server) CreateSnapshot(w http.ResponseWriter, req *http.Request) {
  472. snap, err := s.network.Snapshot()
  473. if err != nil {
  474. http.Error(w, err.Error(), http.StatusInternalServerError)
  475. return
  476. }
  477. s.JSON(w, http.StatusOK, snap)
  478. }
  479. // LoadSnapshot loads a snapshot into the network
  480. func (s *Server) LoadSnapshot(w http.ResponseWriter, req *http.Request) {
  481. snap := &Snapshot{}
  482. if err := json.NewDecoder(req.Body).Decode(snap); err != nil {
  483. http.Error(w, err.Error(), http.StatusBadRequest)
  484. return
  485. }
  486. if err := s.network.Load(snap); err != nil {
  487. http.Error(w, err.Error(), http.StatusInternalServerError)
  488. return
  489. }
  490. s.JSON(w, http.StatusOK, s.network)
  491. }
  492. // CreateNode creates a node in the network using the given configuration
  493. func (s *Server) CreateNode(w http.ResponseWriter, req *http.Request) {
  494. config := &adapters.NodeConfig{}
  495. err := json.NewDecoder(req.Body).Decode(config)
  496. if err != nil && !errors.Is(err, io.EOF) {
  497. http.Error(w, err.Error(), http.StatusBadRequest)
  498. return
  499. }
  500. node, err := s.network.NewNodeWithConfig(config)
  501. if err != nil {
  502. http.Error(w, err.Error(), http.StatusInternalServerError)
  503. return
  504. }
  505. s.JSON(w, http.StatusCreated, node.NodeInfo())
  506. }
  507. // GetNodes returns all nodes which exist in the network
  508. func (s *Server) GetNodes(w http.ResponseWriter, req *http.Request) {
  509. nodes := s.network.GetNodes()
  510. infos := make([]*p2p.NodeInfo, len(nodes))
  511. for i, node := range nodes {
  512. infos[i] = node.NodeInfo()
  513. }
  514. s.JSON(w, http.StatusOK, infos)
  515. }
  516. // GetNode returns details of a node
  517. func (s *Server) GetNode(w http.ResponseWriter, req *http.Request) {
  518. node := req.Context().Value("node").(*Node)
  519. s.JSON(w, http.StatusOK, node.NodeInfo())
  520. }
  521. // StartNode starts a node
  522. func (s *Server) StartNode(w http.ResponseWriter, req *http.Request) {
  523. node := req.Context().Value("node").(*Node)
  524. if err := s.network.Start(node.ID()); err != nil {
  525. http.Error(w, err.Error(), http.StatusInternalServerError)
  526. return
  527. }
  528. s.JSON(w, http.StatusOK, node.NodeInfo())
  529. }
  530. // StopNode stops a node
  531. func (s *Server) StopNode(w http.ResponseWriter, req *http.Request) {
  532. node := req.Context().Value("node").(*Node)
  533. if err := s.network.Stop(node.ID()); err != nil {
  534. http.Error(w, err.Error(), http.StatusInternalServerError)
  535. return
  536. }
  537. s.JSON(w, http.StatusOK, node.NodeInfo())
  538. }
  539. // ConnectNode connects a node to a peer node
  540. func (s *Server) ConnectNode(w http.ResponseWriter, req *http.Request) {
  541. node := req.Context().Value("node").(*Node)
  542. peer := req.Context().Value("peer").(*Node)
  543. if err := s.network.Connect(node.ID(), peer.ID()); err != nil {
  544. http.Error(w, err.Error(), http.StatusInternalServerError)
  545. return
  546. }
  547. s.JSON(w, http.StatusOK, node.NodeInfo())
  548. }
  549. // DisconnectNode disconnects a node from a peer node
  550. func (s *Server) DisconnectNode(w http.ResponseWriter, req *http.Request) {
  551. node := req.Context().Value("node").(*Node)
  552. peer := req.Context().Value("peer").(*Node)
  553. if err := s.network.Disconnect(node.ID(), peer.ID()); err != nil {
  554. http.Error(w, err.Error(), http.StatusInternalServerError)
  555. return
  556. }
  557. s.JSON(w, http.StatusOK, node.NodeInfo())
  558. }
  559. // Options responds to the OPTIONS HTTP method by returning a 200 OK response
  560. // with the "Access-Control-Allow-Headers" header set to "Content-Type"
  561. func (s *Server) Options(w http.ResponseWriter, req *http.Request) {
  562. w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
  563. w.WriteHeader(http.StatusOK)
  564. }
  565. var wsUpgrade = websocket.Upgrader{
  566. CheckOrigin: func(*http.Request) bool { return true },
  567. }
  568. // NodeRPC forwards RPC requests to a node in the network via a WebSocket
  569. // connection
  570. func (s *Server) NodeRPC(w http.ResponseWriter, req *http.Request) {
  571. conn, err := wsUpgrade.Upgrade(w, req, nil)
  572. if err != nil {
  573. return
  574. }
  575. defer conn.Close()
  576. node := req.Context().Value("node").(*Node)
  577. node.ServeRPC(conn)
  578. }
  579. // ServeHTTP implements the http.Handler interface by delegating to the
  580. // underlying httprouter.Router
  581. func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  582. s.router.ServeHTTP(w, req)
  583. }
  584. // GET registers a handler for GET requests to a particular path
  585. func (s *Server) GET(path string, handle http.HandlerFunc) {
  586. s.router.GET(path, s.wrapHandler(handle))
  587. }
  588. // POST registers a handler for POST requests to a particular path
  589. func (s *Server) POST(path string, handle http.HandlerFunc) {
  590. s.router.POST(path, s.wrapHandler(handle))
  591. }
  592. // DELETE registers a handler for DELETE requests to a particular path
  593. func (s *Server) DELETE(path string, handle http.HandlerFunc) {
  594. s.router.DELETE(path, s.wrapHandler(handle))
  595. }
  596. // OPTIONS registers a handler for OPTIONS requests to a particular path
  597. func (s *Server) OPTIONS(path string, handle http.HandlerFunc) {
  598. s.router.OPTIONS("/*path", s.wrapHandler(handle))
  599. }
  600. // JSON sends "data" as a JSON HTTP response
  601. func (s *Server) JSON(w http.ResponseWriter, status int, data interface{}) {
  602. w.Header().Set("Content-Type", "application/json")
  603. w.WriteHeader(status)
  604. json.NewEncoder(w).Encode(data)
  605. }
  606. // wrapHandler returns an httprouter.Handle which wraps an http.HandlerFunc by
  607. // populating request.Context with any objects from the URL params
  608. func (s *Server) wrapHandler(handler http.HandlerFunc) httprouter.Handle {
  609. return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
  610. w.Header().Set("Access-Control-Allow-Origin", "*")
  611. w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
  612. ctx := req.Context()
  613. if id := params.ByName("nodeid"); id != "" {
  614. var nodeID enode.ID
  615. var node *Node
  616. if nodeID.UnmarshalText([]byte(id)) == nil {
  617. node = s.network.GetNode(nodeID)
  618. } else {
  619. node = s.network.GetNodeByName(id)
  620. }
  621. if node == nil {
  622. http.NotFound(w, req)
  623. return
  624. }
  625. ctx = context.WithValue(ctx, "node", node)
  626. }
  627. if id := params.ByName("peerid"); id != "" {
  628. var peerID enode.ID
  629. var peer *Node
  630. if peerID.UnmarshalText([]byte(id)) == nil {
  631. peer = s.network.GetNode(peerID)
  632. } else {
  633. peer = s.network.GetNodeByName(id)
  634. }
  635. if peer == nil {
  636. http.NotFound(w, req)
  637. return
  638. }
  639. ctx = context.WithValue(ctx, "peer", peer)
  640. }
  641. handler(w, req.WithContext(ctx))
  642. }
  643. }