mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
3 Commits
a8a92844f3
...
8089b71bfd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8089b71bfd | ||
|
|
5b9543255a | ||
|
|
bf859387f4 |
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net"
|
"net"
|
||||||
@@ -11,6 +12,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -305,3 +307,93 @@ func IsTelnetConnected(host string, port string) bool {
|
|||||||
|
|
||||||
return true
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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%_-]+)*)$`)
|
||||||
|
|
||||||
|
var alphaNumericRegex = regexp.MustCompile(`^[a-zA-Z0-9]+$`)
|
||||||
|
|
||||||
|
// AddQueryParams adds query parameters to the given URL.
|
||||||
|
// Play: todoå
|
||||||
|
func AddQueryParams(urlStr string, params map[string]string) (string, error) {
|
||||||
|
parsedUrl, err := url.Parse(urlStr)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
queryParams := parsedUrl.Query()
|
||||||
|
for k, v := range params {
|
||||||
|
if k == "" {
|
||||||
|
return "", errors.New("empty key is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !alphaNumericRegex.MatchString(k) {
|
||||||
|
return "", fmt.Errorf("query parameter key %s must be alphanumeric", k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !alphaNumericRegex.MatchString(v) {
|
||||||
|
return "", fmt.Errorf("query parameter value %s must be alphanumeric", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryParams.Add(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedUrl.RawQuery = queryParams.Encode()
|
||||||
|
|
||||||
|
return parsedUrl.String(), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -142,3 +142,96 @@ func TestTelnetConnected(t *testing.T) {
|
|||||||
result2 := IsTelnetConnected("www.baidu.com", "123")
|
result2 := IsTelnetConnected("www.baidu.com", "123")
|
||||||
assert.Equal(false, result2)
|
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)
|
||||||
|
assert.Equal(tt.want, got)
|
||||||
|
assert.Equal(tt.wantErr, err != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddQueryParams(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAddQueryParams")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
url string
|
||||||
|
query map[string]string
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
url: "http://www.test.com",
|
||||||
|
query: map[string]string{"a": "1", "b": "2"},
|
||||||
|
want: "http://www.test.com?a=1&b=2",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "http://www.test.com",
|
||||||
|
query: map[string]string{},
|
||||||
|
want: "http://www.test.com",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "http://www.test.com",
|
||||||
|
query: map[string]string{"a": "$%"},
|
||||||
|
want: "",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got, err := AddQueryParams(tt.url, tt.query)
|
||||||
|
assert.Equal(tt.want, got)
|
||||||
|
assert.Equal(tt.wantErr, err != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
|
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
|
||||||
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
|
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
|
||||||
|
alphaNumericMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z0-9-]+$`)
|
||||||
numberRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d`)
|
numberRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d`)
|
||||||
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
|
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
|
||||||
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
|
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
|
||||||
@@ -181,6 +182,12 @@ func IsJSON(str string) bool {
|
|||||||
return json.Unmarshal([]byte(str), &js) == nil
|
return json.Unmarshal([]byte(str), &js) == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAlphaNumericStr check if the string is alphanumeric.
|
||||||
|
// Play: todo
|
||||||
|
func IsAlphaNumeric(s string) bool {
|
||||||
|
return alphaNumericMatcher.MatchString(s)
|
||||||
|
}
|
||||||
|
|
||||||
// IsNumberStr check if the string can convert to a number.
|
// IsNumberStr check if the string can convert to a number.
|
||||||
// Play: https://go.dev/play/p/LzaKocSV79u
|
// Play: https://go.dev/play/p/LzaKocSV79u
|
||||||
func IsNumberStr(s string) bool {
|
func IsNumberStr(s string) bool {
|
||||||
|
|||||||
@@ -659,3 +659,21 @@ func TestIsChinaUnionPay(t *testing.T) {
|
|||||||
assert.Equal(true, IsChinaUnionPay("6250941006528599"))
|
assert.Equal(true, IsChinaUnionPay("6250941006528599"))
|
||||||
assert.Equal(false, IsChinaUnionPay("3782822463100007"))
|
assert.Equal(false, IsChinaUnionPay("3782822463100007"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsAlphaNumeric(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestIsAlphaNumeric")
|
||||||
|
|
||||||
|
assert.Equal(true, IsAlphaNumeric("ABC"))
|
||||||
|
assert.Equal(true, IsAlphaNumeric("abc"))
|
||||||
|
assert.Equal(true, IsAlphaNumeric("aBC"))
|
||||||
|
assert.Equal(true, IsAlphaNumeric("1BC"))
|
||||||
|
assert.Equal(true, IsAlphaNumeric("1bc"))
|
||||||
|
assert.Equal(true, IsAlphaNumeric("123"))
|
||||||
|
|
||||||
|
assert.Equal(false, IsAlphaNumeric(""))
|
||||||
|
assert.Equal(false, IsAlphaNumeric("你好"))
|
||||||
|
assert.Equal(false, IsAlphaNumeric("A&"))
|
||||||
|
assert.Equal(false, IsAlphaNumeric("&@#$%^&*"))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user