github.com/solo-io/cue@v0.4.7/pkg/tool/http/http.go (about)

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package http
    16  
    17  //go:generate go run gen.go
    18  //go:generate gofmt -s -w .
    19  
    20  import (
    21  	"bytes"
    22  	"io"
    23  	"io/ioutil"
    24  	"net/http"
    25  
    26  	"github.com/solo-io/cue/cue"
    27  	"github.com/solo-io/cue/internal/task"
    28  )
    29  
    30  func init() {
    31  	task.Register("tool/http.Do", newHTTPCmd)
    32  
    33  	// For backwards compatibility.
    34  	task.Register("http", newHTTPCmd)
    35  }
    36  
    37  type httpCmd struct{}
    38  
    39  func newHTTPCmd(v cue.Value) (task.Runner, error) {
    40  	return &httpCmd{}, nil
    41  }
    42  
    43  func (c *httpCmd) Run(ctx *task.Context) (res interface{}, err error) {
    44  	var header, trailer http.Header
    45  	var (
    46  		method = ctx.String("method")
    47  		u      = ctx.String("url")
    48  	)
    49  	var r io.Reader
    50  	if obj := ctx.Obj.Lookup("request"); obj.Exists() {
    51  		if v := obj.Lookup("body"); v.Exists() {
    52  			r, err = v.Reader()
    53  			if err != nil {
    54  				return nil, err
    55  			}
    56  		} else {
    57  			r = bytes.NewReader([]byte(""))
    58  		}
    59  		if header, err = parseHeaders(obj, "header"); err != nil {
    60  			return nil, err
    61  		}
    62  		if trailer, err = parseHeaders(obj, "trailer"); err != nil {
    63  			return nil, err
    64  		}
    65  	}
    66  	if ctx.Err != nil {
    67  		return nil, ctx.Err
    68  	}
    69  
    70  	req, err := http.NewRequest(method, u, r)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	req.Header = header
    75  	req.Trailer = trailer
    76  
    77  	// TODO:
    78  	//  - retry logic
    79  	//  - TLS certs
    80  	resp, err := http.DefaultClient.Do(req)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	defer resp.Body.Close()
    85  	b, err := ioutil.ReadAll(resp.Body)
    86  	// parse response body and headers
    87  	return map[string]interface{}{
    88  		"response": map[string]interface{}{
    89  			"status":     resp.Status,
    90  			"statusCode": resp.StatusCode,
    91  			"body":       string(b),
    92  			"header":     resp.Header,
    93  			"trailer":    resp.Trailer,
    94  		},
    95  	}, err
    96  }
    97  
    98  func parseHeaders(obj cue.Value, label string) (http.Header, error) {
    99  	m := obj.Lookup(label)
   100  	if !m.Exists() {
   101  		return nil, nil
   102  	}
   103  	iter, err := m.Fields()
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	h := http.Header{}
   108  	for iter.Next() {
   109  		str, err := iter.Value().String()
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  		h.Add(iter.Label(), str)
   114  	}
   115  	return h, nil
   116  }