OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / cmd / btcctl / httpclient.go
1 package main
2
3 import (
4         "bytes"
5         "crypto/tls"
6         "crypto/x509"
7         "encoding/json"
8         "fmt"
9         "io/ioutil"
10         "net"
11         "net/http"
12
13         "github.com/btcsuite/btcd/btcjson"
14         "github.com/btcsuite/go-socks/socks"
15 )
16
17 // newHTTPClient returns a new HTTP client that is configured according to the
18 // proxy and TLS settings in the associated connection configuration.
19 func newHTTPClient(cfg *config) (*http.Client, error) {
20         // Configure proxy if needed.
21         var dial func(network, addr string) (net.Conn, error)
22         if cfg.Proxy != "" {
23                 proxy := &socks.Proxy{
24                         Addr:     cfg.Proxy,
25                         Username: cfg.ProxyUser,
26                         Password: cfg.ProxyPass,
27                 }
28                 dial = func(network, addr string) (net.Conn, error) {
29                         c, err := proxy.Dial(network, addr)
30                         if err != nil {
31                                 return nil, err
32                         }
33                         return c, nil
34                 }
35         }
36
37         // Configure TLS if needed.
38         var tlsConfig *tls.Config
39         if !cfg.NoTLS && cfg.RPCCert != "" {
40                 pem, err := ioutil.ReadFile(cfg.RPCCert)
41                 if err != nil {
42                         return nil, err
43                 }
44
45                 pool := x509.NewCertPool()
46                 pool.AppendCertsFromPEM(pem)
47                 tlsConfig = &tls.Config{
48                         RootCAs:            pool,
49                         InsecureSkipVerify: cfg.TLSSkipVerify,
50                 }
51         }
52
53         // Create and return the new HTTP client potentially configured with a
54         // proxy and TLS.
55         client := http.Client{
56                 Transport: &http.Transport{
57                         Dial:            dial,
58                         TLSClientConfig: tlsConfig,
59                 },
60         }
61         return &client, nil
62 }
63
64 // sendPostRequest sends the marshalled JSON-RPC command using HTTP-POST mode
65 // to the server described in the passed config struct.  It also attempts to
66 // unmarshal the response as a JSON-RPC response and returns either the result
67 // field or the error field depending on whether or not there is an error.
68 func sendPostRequest(marshalledJSON []byte, cfg *config) ([]byte, error) {
69         // Generate a request to the configured RPC server.
70         protocol := "http"
71         if !cfg.NoTLS {
72                 protocol = "https"
73         }
74         url := protocol + "://" + cfg.RPCServer
75         bodyReader := bytes.NewReader(marshalledJSON)
76         httpRequest, err := http.NewRequest("POST", url, bodyReader)
77         if err != nil {
78                 return nil, err
79         }
80         httpRequest.Close = true
81         httpRequest.Header.Set("Content-Type", "application/json")
82
83         // Configure basic access authorization.
84         httpRequest.SetBasicAuth(cfg.RPCUser, cfg.RPCPassword)
85
86         // Create the new HTTP client that is configured according to the user-
87         // specified options and submit the request.
88         httpClient, err := newHTTPClient(cfg)
89         if err != nil {
90                 return nil, err
91         }
92         httpResponse, err := httpClient.Do(httpRequest)
93         if err != nil {
94                 return nil, err
95         }
96
97         // Read the raw bytes and close the response.
98         respBytes, err := ioutil.ReadAll(httpResponse.Body)
99         httpResponse.Body.Close()
100         if err != nil {
101                 err = fmt.Errorf("error reading json reply: %v", err)
102                 return nil, err
103         }
104
105         // Handle unsuccessful HTTP responses
106         if httpResponse.StatusCode < 200 || httpResponse.StatusCode >= 300 {
107                 // Generate a standard error to return if the server body is
108                 // empty.  This should not happen very often, but it's better
109                 // than showing nothing in case the target server has a poor
110                 // implementation.
111                 if len(respBytes) == 0 {
112                         return nil, fmt.Errorf("%d %s", httpResponse.StatusCode,
113                                 http.StatusText(httpResponse.StatusCode))
114                 }
115                 return nil, fmt.Errorf("%s", respBytes)
116         }
117
118         // Unmarshal the response.
119         var resp btcjson.Response
120         if err := json.Unmarshal(respBytes, &resp); err != nil {
121                 return nil, err
122         }
123
124         if resp.Error != nil {
125                 return nil, resp.Error
126         }
127         return resp.Result, nil
128 }