This updates dcrctl to use version 2 of the dcrjson module and to make use of the new separate type definitions provided by wallet so it continues supporting communication with dcrwallet.
148 lines
3.9 KiB
Go
148 lines
3.9 KiB
Go
// Copyright (c) 2013-2015 The btcsuite developers
|
|
// Copyright (c) 2015-2019 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"net/http"
|
|
|
|
"github.com/decred/dcrd/dcrjson/v2"
|
|
|
|
"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 {
|
|
tlsConfig = &tls.Config{
|
|
InsecureSkipVerify: cfg.TLSSkipVerify,
|
|
}
|
|
if !cfg.TLSSkipVerify && cfg.RPCCert != "" {
|
|
pem, err := ioutil.ReadFile(cfg.RPCCert)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pool := x509.NewCertPool()
|
|
if ok := pool.AppendCertsFromPEM(pem); !ok {
|
|
return nil, fmt.Errorf("invalid certificate file: %v",
|
|
cfg.RPCCert)
|
|
}
|
|
tlsConfig.RootCAs = pool
|
|
}
|
|
}
|
|
|
|
// 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
|
|
if cfg.PrintJSON {
|
|
fmt.Println(string(marshalledJSON))
|
|
}
|
|
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)
|
|
}
|
|
|
|
// If requested, print raw json response.
|
|
if cfg.PrintJSON {
|
|
fmt.Println(string(respBytes))
|
|
}
|
|
|
|
// Unmarshal the response.
|
|
var resp dcrjson.Response
|
|
if err := json.Unmarshal(respBytes, &resp); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if resp.Error != nil {
|
|
return nil, resp.Error
|
|
}
|
|
return resp.Result, nil
|
|
}
|