This commit is contained in:
parent
ebd8c61956
commit
0d5e406f90
|
|
@ -3,8 +3,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/chzyer/readline"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/chzyer/readline"
|
||||||
"ucl.lmika.dev/repl"
|
"ucl.lmika.dev/repl"
|
||||||
"ucl.lmika.dev/ucl"
|
"ucl.lmika.dev/ucl"
|
||||||
"ucl.lmika.dev/ucl/builtins"
|
"ucl.lmika.dev/ucl/builtins"
|
||||||
|
|
@ -27,6 +28,7 @@ func main() {
|
||||||
ucl.WithModule(builtins.Lists()),
|
ucl.WithModule(builtins.Lists()),
|
||||||
ucl.WithModule(builtins.Time()),
|
ucl.WithModule(builtins.Time()),
|
||||||
ucl.WithModule(builtins.Fns()),
|
ucl.WithModule(builtins.Fns()),
|
||||||
|
ucl.WithModule(builtins.URLs()),
|
||||||
)
|
)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|
|
||||||
67
ucl/builtins/urls.go
Normal file
67
ucl/builtins/urls.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ucl.lmika.dev/ucl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func URLs() ucl.Module {
|
||||||
|
return ucl.Module{
|
||||||
|
Name: "urls",
|
||||||
|
Builtins: map[string]ucl.BuiltinHandler{
|
||||||
|
"fetch": urlsFetch,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func urlsFetch(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
|
var url string
|
||||||
|
|
||||||
|
if err := args.Bind(&url); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(url, "http:") || strings.HasPrefix(url, "https:") {
|
||||||
|
return urlFetchHTTP(ctx, url, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("unsupported URL scheme")
|
||||||
|
}
|
||||||
|
|
||||||
|
func urlFetchHTTP(ctx context.Context, url string, args ucl.CallArgs) (any, error) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, fmt.Errorf("non-200 status code: %v", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do content negotiation
|
||||||
|
contentType := resp.Header.Get("Content-Type")
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(contentType, "text/"):
|
||||||
|
bts, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: honour encoding
|
||||||
|
return string(bts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("unsupported content type: " + contentType)
|
||||||
|
}
|
||||||
37
ucl/builtins/urls_test.go
Normal file
37
ucl/builtins/urls_test.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package builtins_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"ucl.lmika.dev/ucl"
|
||||||
|
"ucl.lmika.dev/ucl/builtins"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestURLs_Fetch_http(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
eval string
|
||||||
|
want any
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{desc: "fetch 1", eval: `in (urls:fetch "https://www.example.com") "Example Domain"`, want: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
inst := ucl.New(
|
||||||
|
ucl.WithModule(builtins.Strs()),
|
||||||
|
ucl.WithModule(builtins.URLs()),
|
||||||
|
)
|
||||||
|
res, err := inst.EvalString(context.Background(), tt.eval)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue