github.com/decred/politeia@v1.4.0/util/net.go (about)

     1  // Copyright (c) 2017-2021 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package util
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/tls"
    10  	"crypto/x509"
    11  	"fmt"
    12  	"io"
    13  	"net"
    14  	"net/http"
    15  	"os"
    16  	"time"
    17  
    18  	pdv1 "github.com/decred/politeia/politeiad/api/v1"
    19  	"github.com/gorilla/schema"
    20  )
    21  
    22  // NormalizeAddress returns addr with the passed default port appended if
    23  // there is not already a port specified.
    24  func NormalizeAddress(addr, defaultPort string) string {
    25  	_, _, err := net.SplitHostPort(addr)
    26  	if err != nil {
    27  		return net.JoinHostPort(addr, defaultPort)
    28  	}
    29  	return addr
    30  }
    31  
    32  // NewHTTPClient returns a new http Client.
    33  func NewHTTPClient(skipVerify bool, certPath string) (*http.Client, error) {
    34  	tlsConfig := &tls.Config{
    35  		InsecureSkipVerify: skipVerify,
    36  	}
    37  
    38  	if !skipVerify && certPath != "" {
    39  		cert, err := os.ReadFile(certPath)
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  		certPool, err := x509.SystemCertPool()
    44  		if err != nil {
    45  			fmt.Printf("WARN: unable to get system cert pool: %v\n", err)
    46  			certPool = x509.NewCertPool()
    47  		}
    48  		certPool.AppendCertsFromPEM(cert)
    49  		tlsConfig.RootCAs = certPool
    50  	}
    51  
    52  	return &http.Client{
    53  		Timeout: 2 * time.Minute,
    54  		Transport: &http.Transport{
    55  			IdleConnTimeout:       2 * time.Minute,
    56  			ResponseHeaderTimeout: 2 * time.Minute,
    57  			TLSClientConfig:       tlsConfig,
    58  		}}, nil
    59  }
    60  
    61  // ConvertBodyToByteArray converts a response body into a byte array
    62  // and optionally prints it to stdout.
    63  func ConvertBodyToByteArray(r io.Reader, print bool) []byte {
    64  	var mw io.Writer
    65  	var body bytes.Buffer
    66  	if print {
    67  		mw = io.MultiWriter(&body, os.Stdout)
    68  	} else {
    69  		mw = io.MultiWriter(&body)
    70  	}
    71  	io.Copy(mw, r)
    72  	if print {
    73  		fmt.Printf("\n")
    74  	}
    75  
    76  	return body.Bytes()
    77  }
    78  
    79  // ParseGetParams parses the query params from the GET request into a struct.
    80  // This method requires the struct type to be defined with `schema` tags.
    81  func ParseGetParams(r *http.Request, dst interface{}) error {
    82  	err := r.ParseForm()
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	return schema.NewDecoder().Decode(dst, r.Form)
    88  }
    89  
    90  // RespBody returns the response body as a byte slice.
    91  func RespBody(r *http.Response) []byte {
    92  	var mw io.Writer
    93  	var body bytes.Buffer
    94  	mw = io.MultiWriter(&body)
    95  	io.Copy(mw, r.Body)
    96  	return body.Bytes()
    97  }
    98  
    99  // RemoteAddr returns a string of the remote address, i.e. the address that
   100  // sent the request.
   101  func RemoteAddr(r *http.Request) string {
   102  	via := r.RemoteAddr
   103  	xff := r.Header.Get(pdv1.Forward)
   104  	if xff != "" {
   105  		return fmt.Sprintf("%v via %v", xff, r.RemoteAddr)
   106  	}
   107  	return via
   108  }