github.com/0chain/gosdk@v1.17.11/core/util/httpnet.go (about)

     1  package util
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/url"
    10  	"os"
    11  	"time"
    12  )
    13  
    14  type GetRequest struct {
    15  	*PostRequest
    16  }
    17  
    18  type GetResponse struct {
    19  	*PostResponse
    20  }
    21  
    22  type PostRequest struct {
    23  	req  *http.Request
    24  	ctx  context.Context
    25  	cncl context.CancelFunc
    26  	url  string
    27  }
    28  
    29  type PostResponse struct {
    30  	Url        string
    31  	StatusCode int
    32  	Status     string
    33  	Body       string
    34  }
    35  
    36  type HttpClient interface {
    37  	Do(req *http.Request) (*http.Response, error)
    38  }
    39  
    40  var Client HttpClient
    41  
    42  func getEnvAny(names ...string) string {
    43  	for _, n := range names {
    44  		if val := os.Getenv(n); val != "" {
    45  			return val
    46  		}
    47  	}
    48  	return ""
    49  }
    50  
    51  func (pfe *proxyFromEnv) initialize() {
    52  	pfe.HTTPProxy = getEnvAny("HTTP_PROXY", "http_proxy")
    53  	pfe.HTTPSProxy = getEnvAny("HTTPS_PROXY", "https_proxy")
    54  	pfe.NoProxy = getEnvAny("NO_PROXY", "no_proxy")
    55  
    56  	if pfe.NoProxy != "" {
    57  		return
    58  	}
    59  
    60  	if pfe.HTTPProxy != "" {
    61  		pfe.http, _ = url.Parse(pfe.HTTPProxy)
    62  	}
    63  	if pfe.HTTPSProxy != "" {
    64  		pfe.https, _ = url.Parse(pfe.HTTPSProxy)
    65  	}
    66  }
    67  
    68  type proxyFromEnv struct {
    69  	HTTPProxy  string
    70  	HTTPSProxy string
    71  	NoProxy    string
    72  
    73  	http, https *url.URL
    74  }
    75  
    76  var envProxy proxyFromEnv
    77  
    78  func init() {
    79  	Client = &http.Client{
    80  		Transport: transport,
    81  	}
    82  	envProxy.initialize()
    83  }
    84  
    85  func httpDo(req *http.Request, ctx context.Context, cncl context.CancelFunc, f func(*http.Response, error) error) error {
    86  	c := make(chan error, 1)
    87  	go func() { c <- f(Client.Do(req.WithContext(ctx))) }()
    88  	defer cncl()
    89  	select {
    90  	case <-ctx.Done():
    91  		transport.CancelRequest(req) //nolint
    92  		<-c                          // Wait for f to return.
    93  		return ctx.Err()
    94  	case err := <-c:
    95  		return err
    96  	}
    97  }
    98  
    99  // NewHTTPGetRequest create a GetRequest instance with 60s timeout
   100  func NewHTTPGetRequest(url string) (*GetRequest, error) {
   101  	var ctx, cancel = context.WithTimeout(context.Background(), 60*time.Second)
   102  	go func() {
   103  		//call cancel to avoid memory leak here
   104  		<-ctx.Done()
   105  
   106  		cancel()
   107  
   108  	}()
   109  
   110  	return NewHTTPGetRequestContext(ctx, url)
   111  }
   112  
   113  // NewHTTPGetRequestContext create a GetRequest with context and url
   114  func NewHTTPGetRequestContext(ctx context.Context, url string) (*GetRequest, error) {
   115  
   116  	req, err := http.NewRequest(http.MethodGet, url, nil)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	req.Header.Set("Content-Type", "application/json; charset=utf-8")
   122  	req.Header.Set("Access-Control-Allow-Origin", "*")
   123  
   124  	gr := new(GetRequest)
   125  	gr.PostRequest = &PostRequest{}
   126  	gr.url = url
   127  	gr.req = req
   128  	gr.ctx, gr.cncl = context.WithCancel(ctx)
   129  	return gr, nil
   130  }
   131  
   132  func NewHTTPPostRequest(url string, data interface{}) (*PostRequest, error) {
   133  	pr := &PostRequest{}
   134  	jsonByte, err := json.Marshal(data)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonByte))
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	req.Header.Set("Content-Type", "application/json; charset=utf-8")
   143  	req.Header.Set("Access-Control-Allow-Origin", "*")
   144  	pr.url = url
   145  	pr.req = req
   146  	pr.ctx, pr.cncl = context.WithTimeout(context.Background(), time.Second*60)
   147  	return pr, nil
   148  }
   149  
   150  func (r *GetRequest) Get() (*GetResponse, error) {
   151  	response := &GetResponse{}
   152  	presp, err := r.Post()
   153  	response.PostResponse = presp
   154  	return response, err
   155  }
   156  
   157  func (r *PostRequest) Post() (*PostResponse, error) {
   158  	result := &PostResponse{}
   159  	err := httpDo(r.req, r.ctx, r.cncl, func(resp *http.Response, err error) error {
   160  		if err != nil {
   161  			return err
   162  		}
   163  		if resp.Body != nil {
   164  			defer resp.Body.Close()
   165  		}
   166  
   167  		rspBy, err := ioutil.ReadAll(resp.Body)
   168  		if err != nil {
   169  			return err
   170  		}
   171  		result.Url = r.url
   172  		result.StatusCode = resp.StatusCode
   173  		result.Status = resp.Status
   174  		result.Body = string(rspBy)
   175  		return nil
   176  	})
   177  	return result, err
   178  }