github.com/GuanceCloud/cliutils@v1.1.21/pipeline/ptinput/funcs/fn_http_request.go (about)

     1  package funcs
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io"
     7  	"net"
     8  	"net/http"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/GuanceCloud/platypus/pkg/ast"
    14  	"github.com/GuanceCloud/platypus/pkg/engine/runtime"
    15  	"github.com/GuanceCloud/platypus/pkg/errchain"
    16  )
    17  
    18  var defaultTransport http.RoundTripper = &http.Transport{
    19  	DialContext: ((&net.Dialer{
    20  		Timeout:   30 * time.Second,
    21  		KeepAlive: 30 * time.Second,
    22  	}).DialContext),
    23  	MaxIdleConns:          100,
    24  	IdleConnTimeout:       90 * time.Second,
    25  	TLSHandshakeTimeout:   10 * time.Second,
    26  	ExpectContinueTimeout: 1 * time.Second,
    27  }
    28  
    29  func HTTPRequestChecking(ctx *runtime.Task, funcExpr *ast.CallExpr) *errchain.PlError {
    30  	if err := normalizeFuncArgsDeprecated(funcExpr, []string{
    31  		"method", "url", "headers", "body",
    32  	}, 2); err != nil {
    33  		return runtime.NewRunError(ctx, err.Error(), funcExpr.NamePos)
    34  	}
    35  
    36  	return nil
    37  }
    38  
    39  func HTTPRequest(ctx *runtime.Task, funcExpr *ast.CallExpr) *errchain.PlError {
    40  	// Acquire params
    41  	method, methodType, err := runtime.RunStmt(ctx, funcExpr.Param[0])
    42  	if err != nil {
    43  		return err
    44  	}
    45  	if methodType != ast.String {
    46  		return runtime.NewRunError(ctx, "param data type expect string",
    47  			funcExpr.Param[0].StartPos())
    48  	}
    49  
    50  	url, urlType, err := runtime.RunStmt(ctx, funcExpr.Param[1])
    51  	if err != nil {
    52  		return err
    53  	}
    54  	if urlType != ast.String {
    55  		return runtime.NewRunError(ctx, "param data type expect string",
    56  			funcExpr.Param[1].StartPos())
    57  	}
    58  
    59  	var headers any
    60  	if funcExpr.Param[2] != nil {
    61  		var headersType ast.DType
    62  		headers, headersType, err = runtime.RunStmt(ctx, funcExpr.Param[2])
    63  		if err != nil {
    64  			return err
    65  		}
    66  		if headersType != ast.Map {
    67  			return runtime.NewRunError(ctx, "param data type expect map",
    68  				funcExpr.Param[2].StartPos())
    69  		}
    70  	}
    71  
    72  	var reqBody io.Reader
    73  	if funcExpr.Param[3] != nil {
    74  		val, _, err := runtime.RunStmt(ctx, funcExpr.Param[3])
    75  		if err != nil {
    76  			return err
    77  		}
    78  		reqBody = buildBody(val)
    79  	}
    80  
    81  	// Send HTTP request
    82  	client := &http.Client{
    83  		Transport: defaultTransport,
    84  		Timeout:   time.Duration(10) * time.Second,
    85  	}
    86  
    87  	req, errR := http.NewRequest(method.(string), url.(string), reqBody)
    88  	if errR != nil {
    89  		ctx.Regs.ReturnAppend(nil, ast.Nil)
    90  		return nil
    91  	}
    92  	if headers != nil {
    93  		for k, v := range headers.(map[string]any) {
    94  			if v, ok := v.(string); ok {
    95  				req.Header.Set(k, v)
    96  			}
    97  		}
    98  	}
    99  
   100  	resp, errR := client.Do(req)
   101  	if errR != nil {
   102  		ctx.Regs.ReturnAppend(nil, ast.Nil)
   103  		return nil
   104  	}
   105  
   106  	defer func() { _ = resp.Body.Close() }()
   107  
   108  	body, errR := io.ReadAll(resp.Body)
   109  	if errR != nil {
   110  		ctx.Regs.ReturnAppend(nil, ast.Nil)
   111  		return nil
   112  	}
   113  
   114  	respData := map[string]interface{}{
   115  		"status_code": resp.StatusCode,
   116  		"body":        string(body),
   117  	}
   118  	ctx.Regs.ReturnAppend(respData, ast.Map)
   119  
   120  	return nil
   121  }
   122  
   123  func buildBody(val any) io.Reader {
   124  	switch val := val.(type) {
   125  	case string:
   126  		return strings.NewReader(val)
   127  	case []any:
   128  		if val, err := json.Marshal(val); err == nil {
   129  			return bytes.NewReader(val)
   130  		}
   131  	case map[string]any:
   132  		if val, err := json.Marshal(val); err == nil {
   133  			return bytes.NewReader(val)
   134  		}
   135  	case float64:
   136  		return strings.NewReader(strconv.FormatFloat(val, 'f', -1, 64))
   137  	case int64:
   138  		return strings.NewReader(strconv.FormatInt(val, 10))
   139  	case bool:
   140  		return strings.NewReader(strconv.FormatBool(val))
   141  	default:
   142  	}
   143  	return nil
   144  }