all repos

viye @ f47d92e4476f8153e98a5b6fc09bf418afdb2888

my shot at reimplementing xiki

viye/internal/plumbing/http/http.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
add sql tool, 1 month ago
1
package http
2
3
import (
4
	"context"
5
	"errors"
6
	"fmt"
7
	"io"
8
	"net/http"
9
	"strings"
10
11
	"github.com/olexsmir/viye/internal/viye"
12
)
13
14
// get http://localhost
15
//	: Header: Value
16
//	: Header2: value
17
//	: {"json": "body"}
18
19
type Tool struct{}
20
21
func (Tool) Name() string { return "http(get, post, put, patch, delete)" }
22
func (Tool) Match(c *viye.Context) bool {
23
	switch c.Cmd {
24
	case "get", "post", "put", "patch", "delete":
25
		return len(c.Args) > 0 && isURL(c.Args[0])
26
	}
27
	return false
28
}
29
30
func (Tool) Execute(c *viye.Context) (string, error) {
31
	if len(c.Args) < 1 || !isURL(c.Args[0]) {
32
		return "", errors.New("please provide an url")
33
	}
34
35
	headers, body, err := parseBody(c.Body)
36
	if err != nil {
37
		return "", fmt.Errorf("body parsing error: %v", err)
38
	}
39
40
	ctx, cancel := context.WithTimeout(context.Background(), viye.Timeout)
41
	defer cancel()
42
43
	req, err := http.NewRequestWithContext(ctx, cmdToMethod(c.Cmd), c.Args[0], strings.NewReader(body))
44
	if err != nil {
45
		return "", fmt.Errorf("failed to create request: %v", err)
46
	}
47
	for header, value := range headers {
48
		req.Header.Set(header, value)
49
	}
50
51
	resp, err := (&http.Client{Timeout: viye.Timeout}).Do(req)
52
	if err != nil {
53
		return "", fmt.Errorf("failed to make a request: %v", err)
54
	}
55
56
	respBody, _ := io.ReadAll(resp.Body)
57
	out := fmt.Sprintf("%d\t%s", resp.StatusCode, respBody)
58
	return viye.FormatOutput(out), nil
59
}
60
61
func parseBody(inp []string) (headers map[string]string, body string, err error) {
62
	if len(inp) == 0 {
63
		return nil, "", nil
64
	}
65
66
	headers = make(map[string]string)
67
	for _, line := range inp {
68
		key, val, ok := strings.Cut(line, ": ")
69
		if ok {
70
			headers[key] = val
71
		}
72
	}
73
74
	last := inp[len(inp)-1]
75
	if _, _, ok := strings.Cut(last, ": "); !ok {
76
		body = last
77
	}
78
79
	return headers, body, nil
80
}
81
82
func isURL(u string) bool {
83
	return strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://")
84
}
85
86
func cmdToMethod(c string) string {
87
	switch c {
88
	case "get":
89
		return http.MethodGet
90
	case "post":
91
		return http.MethodPost
92
	case "put":
93
		return http.MethodPut
94
	case "patch":
95
		return http.MethodPatch
96
	case "delete":
97
		return http.MethodDelete
98
	default:
99
		panic("unreachable")
100
	}
101
}