+++ /dev/null
-package main
-
-import (
- "bytes"
- "crypto/tls"
- "crypto/x509"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
-
- "github.com/btcsuite/btcd/btcjson"
- "github.com/btcsuite/go-socks/socks"
-)
-
-// newHTTPClient returns a new HTTP client that is configured according to the
-// proxy and TLS settings in the associated connection configuration.
-func newHTTPClient(cfg *config) (*http.Client, error) {
- // Configure proxy if needed.
- var dial func(network, addr string) (net.Conn, error)
- if cfg.Proxy != "" {
- proxy := &socks.Proxy{
- Addr: cfg.Proxy,
- Username: cfg.ProxyUser,
- Password: cfg.ProxyPass,
- }
- dial = func(network, addr string) (net.Conn, error) {
- c, err := proxy.Dial(network, addr)
- if err != nil {
- return nil, err
- }
- return c, nil
- }
- }
-
- // Configure TLS if needed.
- var tlsConfig *tls.Config
- if !cfg.NoTLS && cfg.RPCCert != "" {
- pem, err := ioutil.ReadFile(cfg.RPCCert)
- if err != nil {
- return nil, err
- }
-
- pool := x509.NewCertPool()
- pool.AppendCertsFromPEM(pem)
- tlsConfig = &tls.Config{
- RootCAs: pool,
- InsecureSkipVerify: cfg.TLSSkipVerify,
- }
- }
-
- // Create and return the new HTTP client potentially configured with a
- // proxy and TLS.
- client := http.Client{
- Transport: &http.Transport{
- Dial: dial,
- TLSClientConfig: tlsConfig,
- },
- }
- return &client, nil
-}
-
-// sendPostRequest sends the marshalled JSON-RPC command using HTTP-POST mode
-// to the server described in the passed config struct. It also attempts to
-// unmarshal the response as a JSON-RPC response and returns either the result
-// field or the error field depending on whether or not there is an error.
-func sendPostRequest(marshalledJSON []byte, cfg *config) ([]byte, error) {
- // Generate a request to the configured RPC server.
- protocol := "http"
- if !cfg.NoTLS {
- protocol = "https"
- }
- url := protocol + "://" + cfg.RPCServer
- bodyReader := bytes.NewReader(marshalledJSON)
- httpRequest, err := http.NewRequest("POST", url, bodyReader)
- if err != nil {
- return nil, err
- }
- httpRequest.Close = true
- httpRequest.Header.Set("Content-Type", "application/json")
-
- // Configure basic access authorization.
- httpRequest.SetBasicAuth(cfg.RPCUser, cfg.RPCPassword)
-
- // Create the new HTTP client that is configured according to the user-
- // specified options and submit the request.
- httpClient, err := newHTTPClient(cfg)
- if err != nil {
- return nil, err
- }
- httpResponse, err := httpClient.Do(httpRequest)
- if err != nil {
- return nil, err
- }
-
- // Read the raw bytes and close the response.
- respBytes, err := ioutil.ReadAll(httpResponse.Body)
- httpResponse.Body.Close()
- if err != nil {
- err = fmt.Errorf("error reading json reply: %v", err)
- return nil, err
- }
-
- // Handle unsuccessful HTTP responses
- if httpResponse.StatusCode < 200 || httpResponse.StatusCode >= 300 {
- // Generate a standard error to return if the server body is
- // empty. This should not happen very often, but it's better
- // than showing nothing in case the target server has a poor
- // implementation.
- if len(respBytes) == 0 {
- return nil, fmt.Errorf("%d %s", httpResponse.StatusCode,
- http.StatusText(httpResponse.StatusCode))
- }
- return nil, fmt.Errorf("%s", respBytes)
- }
-
- // Unmarshal the response.
- var resp btcjson.Response
- if err := json.Unmarshal(respBytes, &resp); err != nil {
- return nil, err
- }
-
- if resp.Error != nil {
- return nil, resp.Error
- }
- return resp.Result, nil
-}