github.com/oam-dev/kubevela@v1.9.11/pkg/builtin/http/http.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package http 18 19 import ( 20 "context" 21 "crypto/tls" 22 "crypto/x509" 23 "io" 24 "net/http" 25 "time" 26 27 "cuelang.org/go/cue" 28 "github.com/pkg/errors" 29 30 "github.com/kubevela/workflow/pkg/cue/model/value" 31 32 "github.com/oam-dev/kubevela/pkg/builtin/registry" 33 ) 34 35 func init() { 36 registry.RegisterRunner("http", newHTTPCmd) 37 } 38 39 // HTTPCmd provides methods for http task 40 type HTTPCmd struct{} 41 42 func newHTTPCmd(_ cue.Value) (registry.Runner, error) { 43 return &HTTPCmd{}, nil 44 } 45 46 // Run exec the actual http logic, and res represent the result of http task 47 func (c *HTTPCmd) Run(meta *registry.Meta) (res interface{}, err error) { 48 var header, trailer http.Header 49 var ( 50 method = meta.String("method") 51 u = meta.String("url") 52 ) 53 var ( 54 r io.Reader 55 client = &http.Client{ 56 Transport: http.DefaultTransport, 57 Timeout: time.Second * 3, 58 } 59 ) 60 if obj := meta.Obj.LookupPath(value.FieldPath("request")); obj.Exists() { 61 if v := obj.LookupPath(value.FieldPath("body")); v.Exists() { 62 r, err = v.Reader() 63 if err != nil { 64 return nil, err 65 } 66 } 67 if header, err = parseHeaders(obj, "header"); err != nil { 68 return nil, err 69 } 70 if trailer, err = parseHeaders(obj, "trailer"); err != nil { 71 return nil, err 72 } 73 } 74 if header == nil { 75 header = map[string][]string{} 76 header.Set("Content-Type", "application/json") 77 } 78 if meta.Err != nil { 79 return nil, meta.Err 80 } 81 82 req, err := http.NewRequestWithContext(context.Background(), method, u, r) 83 if err != nil { 84 return nil, err 85 } 86 req.Header = header 87 req.Trailer = trailer 88 89 if tlsConfig := meta.Obj.LookupPath(value.FieldPath("tls_config")); tlsConfig.Exists() { 90 tr := &http.Transport{ 91 TLSClientConfig: &tls.Config{ 92 NextProtos: []string{"http/1.1"}, 93 }, 94 } 95 ca := tlsConfig.LookupPath(value.FieldPath("ca")) 96 if caCrt, err := ca.String(); err != nil { 97 return nil, errors.WithMessage(err, "parse ca") 98 } else { 99 pool := x509.NewCertPool() 100 pool.AppendCertsFromPEM([]byte(caCrt)) 101 tr.TLSClientConfig.RootCAs = pool 102 } 103 104 cert := tlsConfig.LookupPath(value.FieldPath("client_crt")) 105 key := tlsConfig.LookupPath(value.FieldPath("client_key")) 106 if cert.Exists() && key.Exists() { 107 crtData, err := cert.String() 108 if err != nil { 109 return nil, err 110 } 111 keyData, err := key.String() 112 if err != nil { 113 return nil, err 114 } 115 cliCrt, err := tls.X509KeyPair([]byte(crtData), []byte(keyData)) 116 if err != nil { 117 return nil, errors.WithMessage(err, "parse client keypair") 118 } 119 tr.TLSClientConfig.Certificates = []tls.Certificate{cliCrt} 120 } 121 122 client.Transport = tr 123 } 124 resp, err := client.Do(req) 125 if err != nil { 126 return nil, err 127 } 128 //nolint:errcheck 129 defer resp.Body.Close() 130 b, err := io.ReadAll(resp.Body) 131 // parse response body and headers 132 return map[string]interface{}{ 133 "body": string(b), 134 "header": resp.Header, 135 "trailer": resp.Trailer, 136 "statusCode": resp.StatusCode, 137 }, err 138 } 139 140 func parseHeaders(obj cue.Value, label string) (http.Header, error) { 141 m := obj.LookupPath(value.FieldPath(label)) 142 if !m.Exists() { 143 return nil, nil 144 } 145 iter, err := m.Fields() 146 if err != nil { 147 return nil, err 148 } 149 h := http.Header{} 150 for iter.Next() { 151 str, err := iter.Value().String() 152 if err != nil { 153 return nil, err 154 } 155 h.Add(iter.Label(), str) 156 } 157 return h, nil 158 }