1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-04 12:52:28 +08:00

feat: add BuildUrl

This commit is contained in:
dudaodong
2025-03-15 14:25:03 +08:00
parent a8a92844f3
commit bf859387f4
2 changed files with 121 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net"
@@ -11,6 +12,7 @@ import (
"net/url"
"os"
"os/exec"
"regexp"
"runtime"
"strings"
"time"
@@ -305,3 +307,62 @@ func IsTelnetConnected(host string, port string) bool {
return true
}
// BuildUrl builds a URL from the given params.
// Play: todo
func BuildUrl(scheme, host, path string, query map[string]string) (string, error) {
if err := validateScheme(scheme); err != nil {
return "", err
}
if path != "" {
if !hostRegex.MatchString(host) {
return "", fmt.Errorf("invalid host: '%s' is not a valid host", host)
}
}
parsedUrl := &url.URL{
Scheme: scheme,
Host: host,
}
if path == "" {
parsedUrl.Path = "/"
} else if !strings.HasPrefix(path, "/") {
path = "/" + path
} else {
parsedUrl.Path = path
}
queryParams := parsedUrl.Query()
for key, value := range query {
queryParams.Add(key, value)
}
parsedUrl.RawQuery = queryParams.Encode()
return parsedUrl.String(), nil
}
// 支持的 Scheme 列表
var supportedSchemes = map[string]bool{
"http": true,
"https": true,
"ftp": true,
"file": true,
"mailto": true,
"ws": true, // WebSocket
"wss": true, // WebSocket Secure
"data": true, // Data URL
}
func validateScheme(scheme string) error {
if _, exists := supportedSchemes[scheme]; !exists {
return fmt.Errorf("invalid scheme: '%s' is not supported", scheme)
}
return nil
}
var hostRegex = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])(\.[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])*$`)
var pathRegex = regexp.MustCompile(`^\/([a-zA-Z0-9%_-]+(?:\/[a-zA-Z0-9%_-]+)*)$`)

View File

@@ -142,3 +142,63 @@ func TestTelnetConnected(t *testing.T) {
result2 := IsTelnetConnected("www.baidu.com", "123")
assert.Equal(false, result2)
}
func TestBuildUrl(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBuildUrl")
tests := []struct {
scheme string
host string
path string
query map[string]string
want string
wantErr bool
}{
{
scheme: "http",
host: "www.test.com",
path: "/path/subpath",
query: map[string]string{"a": "1", "b": "2"},
want: "http://www.test.com/path/subpath?a=1&b=2",
wantErr: false,
},
{
scheme: "http",
host: "www.test.com",
path: "/simple-path",
query: map[string]string{"a": "1", "b": "2"},
want: "http://www.test.com/simple-path?a=1&b=2",
wantErr: false,
},
{
scheme: "https",
host: "www.test. com",
path: "/path",
query: nil,
want: "",
wantErr: true,
},
{
scheme: "https",
host: "www.test.com",
path: "/path with spaces",
query: nil,
want: "https://www.test.com/path%20with%20spaces",
wantErr: false,
},
}
for _, tt := range tests {
got, err := BuildUrl(tt.scheme, tt.host, tt.path, tt.query)
// if (err != nil) != tt.wantErr {
// t.Errorf("BuildUrl() error = %v, wantErr %v", err, tt.wantErr)
// return
// }
assert.Equal(tt.want, got)
assert.Equal(tt.wantErr, err != nil)
}
}