91
net/urlx/url.go
Normal file
91
net/urlx/url.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package urlx
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"git.cloudyne.io/go/hiscaler-gox/isx"
|
||||
)
|
||||
|
||||
type URL struct {
|
||||
Path string // URL path
|
||||
URL *url.URL // A url.URL represents
|
||||
Invalid bool // Path is a valid url
|
||||
values url.Values // Query values
|
||||
}
|
||||
|
||||
func NewURL(path string) *URL {
|
||||
u := &URL{
|
||||
Path: path,
|
||||
Invalid: false,
|
||||
values: url.Values{},
|
||||
}
|
||||
if v, err := url.Parse(u.Path); err == nil {
|
||||
u.URL = v
|
||||
u.Invalid = true
|
||||
if values, err := url.ParseQuery(v.RawQuery); err == nil {
|
||||
u.values = values
|
||||
}
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func (u URL) GetValue(key, defaultValue string) string {
|
||||
v := u.values.Get(key)
|
||||
if v == "" {
|
||||
v = defaultValue
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (u URL) SetValue(key, value string) URL {
|
||||
u.values.Set(key, value)
|
||||
return u
|
||||
}
|
||||
|
||||
func (u URL) AddValue(key, value string) URL {
|
||||
u.values.Add(key, value)
|
||||
return u
|
||||
}
|
||||
|
||||
func (u URL) DelKey(key string) URL {
|
||||
u.values.Del(key)
|
||||
return u
|
||||
}
|
||||
|
||||
func (u URL) HasKey(key string) bool {
|
||||
return u.values.Has(key)
|
||||
}
|
||||
|
||||
func (u URL) String() string {
|
||||
s := u.URL.String()
|
||||
rawQuery := u.URL.RawQuery
|
||||
if rawQuery == "" {
|
||||
if len(u.values) > 0 {
|
||||
s += "?" + u.values.Encode()
|
||||
}
|
||||
} else {
|
||||
s = strings.Replace(s, rawQuery, u.values.Encode(), 1)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// IsAbsolute 是否为绝对地址
|
||||
func IsAbsolute(s string) bool {
|
||||
if strings.HasPrefix(s, "//") {
|
||||
s = "http:" + s
|
||||
}
|
||||
if isx.HttpURL(s) {
|
||||
if u, err := url.Parse(s); err == nil {
|
||||
if u.IsAbs() && len(u.Host) > 2 && strings.Index(u.Host, ".") > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRelative 是否为相对地址
|
||||
func IsRelative(url string) bool {
|
||||
return !IsAbsolute(url)
|
||||
}
|
||||
88
net/urlx/url_test.go
Normal file
88
net/urlx/url_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package urlx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestURL_AddValue(t *testing.T) {
|
||||
type testCase struct {
|
||||
Number int
|
||||
Path string
|
||||
Values map[string]string
|
||||
Except string
|
||||
}
|
||||
testCases := []testCase{
|
||||
{1, "https://www.example.com/a/b/c/1.txt?a=1&b=2", map[string]string{"a": "11", "b": "22"}, "https://www.example.com/a/b/c/1.txt?a=11&b=22"},
|
||||
{1, "https://www.example.com/a/b/c/1.txt?a=1&b=2&c=3", map[string]string{"a": "11", "c": "33"}, "https://www.example.com/a/b/c/1.txt?a=11&b=2&c=33"},
|
||||
{2, "https://www.example.com/a/b/c/1.txt?a=1&b=2#abc", map[string]string{"a": "11"}, "https://www.example.com/a/b/c/1.txt?a=11&b=2#abc"},
|
||||
{3, "https://www.example.com/a/b/c/1.txt?a=1&b=2#abc", map[string]string{"A": "11"}, "https://www.example.com/a/b/c/1.txt?A=11&a=1&b=2#abc"},
|
||||
{4, "https://www.example.com/a/b/c/1.txt?b=1&a=2#abc", map[string]string{"A": "11"}, "https://www.example.com/a/b/c/1.txt?A=11&a=2&b=1#abc"},
|
||||
{5, "https://www.example.com", map[string]string{"A": "11"}, "https://www.example.com?A=11"},
|
||||
{6, "https://www.example.com/", map[string]string{"A": "11"}, "https://www.example.com/?A=11"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
url := NewURL(tc.Path)
|
||||
for k, v := range tc.Values {
|
||||
url.SetValue(k, v)
|
||||
}
|
||||
s := url.String()
|
||||
if s != tc.Except {
|
||||
t.Errorf("%d except: %s, actual: %s", tc.Number, tc.Except, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestURL_DeleteValue(t *testing.T) {
|
||||
type testCase struct {
|
||||
Number int
|
||||
Path string
|
||||
DeleteKeys []string
|
||||
Except string
|
||||
}
|
||||
testCases := []testCase{
|
||||
{1, "https://www.example.com/a/b/c/1.txt?a=1&b=2#abc", []string{"a", "b"}, "https://www.example.com/a/b/c/1.txt?#abc"},
|
||||
{1, "https://www.example.com/a/b/c/1.txt?a=1&b=2#abc", []string{"a"}, "https://www.example.com/a/b/c/1.txt?b=2#abc"},
|
||||
{2, "https://www.example.com/a/b/c/1.txt", []string{"a", "b"}, "https://www.example.com/a/b/c/1.txt"},
|
||||
{2, "https://www/a/b/c/1.txt", []string{"a", "b"}, "https://www/a/b/c/1.txt"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
url := NewURL(tc.Path)
|
||||
for _, v := range tc.DeleteKeys {
|
||||
url.DelKey(v)
|
||||
}
|
||||
s := url.String()
|
||||
if s != tc.Except {
|
||||
t.Errorf("%d except: %s, actual: %s", tc.Number, tc.Except, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsAbsolute(t *testing.T) {
|
||||
testCases := []struct {
|
||||
tag string
|
||||
url string
|
||||
isAbs bool
|
||||
}{
|
||||
{"t0.1", "https://www.a.com", true},
|
||||
{"t0.2", "http://www.a.com", true},
|
||||
{"t0.3", "//www.a.com", true},
|
||||
{"t0.4", "//a.b", true},
|
||||
{"t0.5", "//abc", false},
|
||||
{"t0.6", "//abc...", false},
|
||||
{"t0.7", "//.a.b", false},
|
||||
{"t0.8", "//a.b..", false},
|
||||
|
||||
{"t1.1", "httpa.com", false},
|
||||
{"t1.2", "httpa.com//", false},
|
||||
{"t1.3", "//", false},
|
||||
{"t1.4", "//a", false},
|
||||
{"t1.5", "//....a", false},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
isAbs := IsAbsolute(testCase.url)
|
||||
assert.Equal(t, testCase.isAbs, isAbs, testCase.tag)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user