13 "github.com/btcsuite/btcd/btcjson"
14 "github.com/btcsuite/go-socks/socks"
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)
23 proxy := &socks.Proxy{
25 Username: cfg.ProxyUser,
26 Password: cfg.ProxyPass,
28 dial = func(network, addr string) (net.Conn, error) {
29 c, err := proxy.Dial(network, addr)
37 // Configure TLS if needed.
38 var tlsConfig *tls.Config
39 if !cfg.NoTLS && cfg.RPCCert != "" {
40 pem, err := ioutil.ReadFile(cfg.RPCCert)
45 pool := x509.NewCertPool()
46 pool.AppendCertsFromPEM(pem)
47 tlsConfig = &tls.Config{
49 InsecureSkipVerify: cfg.TLSSkipVerify,
53 // Create and return the new HTTP client potentially configured with a
55 client := http.Client{
56 Transport: &http.Transport{
58 TLSClientConfig: tlsConfig,
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.
74 url := protocol + "://" + cfg.RPCServer
75 bodyReader := bytes.NewReader(marshalledJSON)
76 httpRequest, err := http.NewRequest("POST", url, bodyReader)
80 httpRequest.Close = true
81 httpRequest.Header.Set("Content-Type", "application/json")
83 // Configure basic access authorization.
84 httpRequest.SetBasicAuth(cfg.RPCUser, cfg.RPCPassword)
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)
92 httpResponse, err := httpClient.Do(httpRequest)
97 // Read the raw bytes and close the response.
98 respBytes, err := ioutil.ReadAll(httpResponse.Body)
99 httpResponse.Body.Close()
101 err = fmt.Errorf("error reading json reply: %v", err)
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
111 if len(respBytes) == 0 {
112 return nil, fmt.Errorf("%d %s", httpResponse.StatusCode,
113 http.StatusText(httpResponse.StatusCode))
115 return nil, fmt.Errorf("%s", respBytes)
118 // Unmarshal the response.
119 var resp btcjson.Response
120 if err := json.Unmarshal(respBytes, &resp); err != nil {
124 if resp.Error != nil {
125 return nil, resp.Error
127 return resp.Result, nil