http.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. package rpc
  17. import (
  18. "bytes"
  19. "encoding/json"
  20. "fmt"
  21. "io"
  22. "io/ioutil"
  23. "net/http"
  24. "net/url"
  25. "strings"
  26. "github.com/rs/cors"
  27. )
  28. const (
  29. maxHTTPRequestContentLength = 1024 * 128
  30. )
  31. // httpClient connects to a geth RPC server over HTTP.
  32. type httpClient struct {
  33. endpoint *url.URL // HTTP-RPC server endpoint
  34. httpClient http.Client // reuse connection
  35. lastRes []byte // HTTP requests are synchronous, store last response
  36. }
  37. // NewHTTPClient create a new RPC clients that connection to a geth RPC server
  38. // over HTTP.
  39. func NewHTTPClient(endpoint string) (Client, error) {
  40. url, err := url.Parse(endpoint)
  41. if err != nil {
  42. return nil, err
  43. }
  44. return &httpClient{endpoint: url}, nil
  45. }
  46. // Send will serialize the given msg to JSON and sends it to the RPC server.
  47. // Since HTTP is synchronous the response is stored until Recv is called.
  48. func (client *httpClient) Send(msg interface{}) error {
  49. var body []byte
  50. var err error
  51. client.lastRes = nil
  52. if body, err = json.Marshal(msg); err != nil {
  53. return err
  54. }
  55. resp, err := client.httpClient.Post(client.endpoint.String(), "application/json", bytes.NewReader(body))
  56. if err != nil {
  57. return err
  58. }
  59. defer resp.Body.Close()
  60. if resp.StatusCode == http.StatusOK {
  61. client.lastRes, err = ioutil.ReadAll(resp.Body)
  62. return err
  63. }
  64. return fmt.Errorf("request failed: %s", resp.Status)
  65. }
  66. // Recv will try to deserialize the last received response into the given msg.
  67. func (client *httpClient) Recv(msg interface{}) error {
  68. return json.Unmarshal(client.lastRes, &msg)
  69. }
  70. // Close is not necessary for httpClient
  71. func (client *httpClient) Close() {
  72. }
  73. // SupportedModules will return the collection of offered RPC modules.
  74. func (client *httpClient) SupportedModules() (map[string]string, error) {
  75. return SupportedModules(client)
  76. }
  77. // httpReadWriteNopCloser wraps a io.Reader and io.Writer with a NOP Close method.
  78. type httpReadWriteNopCloser struct {
  79. io.Reader
  80. io.Writer
  81. }
  82. // Close does nothing and returns always nil
  83. func (t *httpReadWriteNopCloser) Close() error {
  84. return nil
  85. }
  86. // newJSONHTTPHandler creates a HTTP handler that will parse incoming JSON requests,
  87. // send the request to the given API provider and sends the response back to the caller.
  88. func newJSONHTTPHandler(srv *Server) http.HandlerFunc {
  89. return func(w http.ResponseWriter, r *http.Request) {
  90. if r.ContentLength > maxHTTPRequestContentLength {
  91. http.Error(w,
  92. fmt.Sprintf("content length too large (%d>%d)", r.ContentLength, maxHTTPRequestContentLength),
  93. http.StatusRequestEntityTooLarge)
  94. return
  95. }
  96. w.Header().Set("content-type", "application/json")
  97. // create a codec that reads direct from the request body until
  98. // EOF and writes the response to w and order the server to process
  99. // a single request.
  100. codec := NewJSONCodec(&httpReadWriteNopCloser{r.Body, w})
  101. defer codec.Close()
  102. srv.ServeSingleRequest(codec, OptionMethodInvocation)
  103. }
  104. }
  105. // NewHTTPServer creates a new HTTP RPC server around an API provider.
  106. func NewHTTPServer(corsString string, srv *Server) *http.Server {
  107. var allowedOrigins []string
  108. for _, domain := range strings.Split(corsString, ",") {
  109. allowedOrigins = append(allowedOrigins, strings.TrimSpace(domain))
  110. }
  111. c := cors.New(cors.Options{
  112. AllowedOrigins: allowedOrigins,
  113. AllowedMethods: []string{"POST", "GET"},
  114. })
  115. handler := c.Handler(newJSONHTTPHandler(srv))
  116. return &http.Server{
  117. Handler: handler,
  118. }
  119. }