Package url parses URLs and implements query escaping.
- func JoinPath(base string, elem …string) (result string, err error)
- func PathEscape(s string) string
- func PathUnescape(s string) (string, error)
- func QueryEscape(s string) string
- func QueryUnescape(s string) (string, error)
- type Error
-
- func (e *Error) Error() string
- func (e *Error) Temporary() bool
- func (e *Error) Timeout() bool
- func (e *Error) Unwrap() error
- type EscapeError
-
- func (e EscapeError) Error() string
- type InvalidHostError
-
- func (e InvalidHostError) Error() string
- type URL
-
- func Parse(rawURL string) (*URL, error)
- func ParseRequestURI(rawURL string) (*URL, error)
-
- func (u *URL) EscapedFragment() string
- func (u *URL) EscapedPath() string
- func (u *URL) Hostname() string
- func (u *URL) IsAbs() bool
- func (u *URL) JoinPath(elem …string) *URL
- func (u *URL) MarshalBinary() (text []byte, err error)
- func (u *URL) Parse(ref string) (*URL, error)
- func (u *URL) Port() string
- func (u *URL) Query() Values
- func (u *URL) Redacted() string
- func (u *URL) RequestURI() string
- func (u *URL) ResolveReference(ref *URL) *URL
- func (u *URL) String() string
- func (u *URL) UnmarshalBinary(text []byte) error
- type Userinfo
-
- func User(username string) *Userinfo
- func UserPassword(username, password string) *Userinfo
-
- func (u *Userinfo) Password() (string, bool)
- func (u *Userinfo) String() string
- func (u *Userinfo) Username() string
- type Values
-
- func ParseQuery(query string) (Values, error)
-
- func (v Values) Add(key, value string)
- func (v Values) Del(key string)
- func (v Values) Encode() string
- func (v Values) Get(key string) string
- func (v Values) Has(key string) bool
- func (v Values) Set(key, value string)
- ParseQuery
- PathEscape
- PathUnescape
- QueryEscape
- QueryUnescape
- URL
- URL (Roundtrip)
- URL.EscapedFragment
- URL.EscapedPath
- URL.Hostname
- URL.IsAbs
- URL.MarshalBinary
- URL.Parse
- URL.Port
- URL.Query
- URL.Redacted
- URL.RequestURI
- URL.ResolveReference
- URL.String
- URL.UnmarshalBinary
- Values
- Values.Add
- Values.Del
- Values.Encode
- Values.Get
- Values.Has
- Values.Set
This section is empty.
This section is empty.
JoinPath returns a URL string with the provided path elements joined to
the existing path of base and the resulting path cleaned of any ./ or ../ elements.
PathEscape escapes the string so it can be safely placed inside a URL path segment,
replacing special characters (including /) with %XX sequences as needed.
package main import ( "fmt" "net/url" ) func main() { path := url.PathEscape("my/cool+blog&about,stuff") fmt.Println(path) }
Output: my%2Fcool+blog&about%2Cstuff
PathUnescape does the inverse transformation of PathEscape,
converting each 3-byte encoded substring of the form «%AB» into the
hex-decoded byte 0xAB. It returns an error if any % is not followed
by two hexadecimal digits.
PathUnescape is identical to QueryUnescape except that it does not
unescape ‘+’ to ‘ ‘ (space).
package main import ( "fmt" "log" "net/url" ) func main() { escapedPath := "my%2Fcool+blog&about%2Cstuff" path, err := url.PathUnescape(escapedPath) if err != nil { log.Fatal(err) } fmt.Println(path) }
Output: my/cool+blog&about,stuff
QueryEscape escapes the string so it can be safely placed
inside a URL query.
package main import ( "fmt" "net/url" ) func main() { query := url.QueryEscape("my/cool+blog&about,stuff") fmt.Println(query) }
Output: my%2Fcool%2Bblog%26about%2Cstuff
QueryUnescape does the inverse transformation of QueryEscape,
converting each 3-byte encoded substring of the form «%AB» into the
hex-decoded byte 0xAB.
It returns an error if any % is not followed by two hexadecimal
digits.
package main import ( "fmt" "log" "net/url" ) func main() { escapedQuery := "my%2Fcool%2Bblog%26about%2Cstuff" query, err := url.QueryUnescape(escapedQuery) if err != nil { log.Fatal(err) } fmt.Println(query) }
Output: my/cool+blog&about,stuff
Error reports an error and the operation and URL that caused it.
func (e *Error) Temporary() bool
func (e *Error) Timeout() bool
A URL represents a parsed URL (technically, a URI reference).
The general form represented is:
[scheme:][//[userinfo@]host][/]path[?query][#fragment]
URLs that do not start with a slash after the scheme are interpreted as:
scheme:opaque[?query][#fragment]
Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
A consequence is that it is impossible to tell which slashes in the Path were
slashes in the raw URL and which were %2f. This distinction is rarely important,
but when it is, the code should use the EscapedPath method, which preserves
the original encoding of Path.
The RawPath field is an optional field which is only set when the default
encoding of Path is different from the escaped path. See the EscapedPath method
for more details.
URL’s String method uses the EscapedPath method to obtain the path.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("http://bing.com/search?q=dotnet") if err != nil { log.Fatal(err) } u.Scheme = "https" u.Host = "google.com" q := u.Query() q.Set("q", "golang") u.RawQuery = q.Encode() fmt.Println(u) }
Output: https://google.com/search?q=golang
package main import ( "fmt" "log" "net/url" ) func main() { // Parse + String preserve the original encoding. u, err := url.Parse("https://example.com/foo%2fbar") if err != nil { log.Fatal(err) } fmt.Println(u.Path) fmt.Println(u.RawPath) fmt.Println(u.String()) }
Output: /foo/bar /foo%2fbar https://example.com/foo%2fbar
Parse parses a raw url into a URL structure.
The url may be relative (a path, without a host) or absolute
(starting with a scheme). Trying to parse a hostname and path
without a scheme is invalid but may not necessarily return an
error, due to parsing ambiguities.
ParseRequestURI parses a raw url into a URL structure. It assumes that
url was received in an HTTP request, so the url is interpreted
only as an absolute URI or an absolute path.
The string url is assumed not to have a #fragment suffix.
(Web browsers strip #fragment before sending the URL to a web server.)
func (u *URL) EscapedFragment() string
EscapedFragment returns the escaped form of u.Fragment.
In general there are multiple possible escaped forms of any fragment.
EscapedFragment returns u.RawFragment when it is a valid escaping of u.Fragment.
Otherwise EscapedFragment ignores u.RawFragment and computes an escaped
form on its own.
The String method uses EscapedFragment to construct its result.
In general, code should call EscapedFragment instead of
reading u.RawFragment directly.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("http://example.com/#x/y%2Fz") if err != nil { log.Fatal(err) } fmt.Println("Fragment:", u.Fragment) fmt.Println("RawFragment:", u.RawFragment) fmt.Println("EscapedFragment:", u.EscapedFragment()) }
Output: Fragment: x/y/z RawFragment: x/y%2Fz EscapedFragment: x/y%2Fz
EscapedPath returns the escaped form of u.Path.
In general there are multiple possible escaped forms of any path.
EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
Otherwise EscapedPath ignores u.RawPath and computes an escaped
form on its own.
The String and RequestURI methods use EscapedPath to construct
their results.
In general, code should call EscapedPath instead of
reading u.RawPath directly.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("http://example.com/x/y%2Fz") if err != nil { log.Fatal(err) } fmt.Println("Path:", u.Path) fmt.Println("RawPath:", u.RawPath) fmt.Println("EscapedPath:", u.EscapedPath()) }
Output: Path: /x/y/z RawPath: /x/y%2Fz EscapedPath: /x/y%2Fz
Hostname returns u.Host, stripping any valid port number if present.
If the result is enclosed in square brackets, as literal IPv6 addresses are,
the square brackets are removed from the result.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("https://example.org:8000/path") if err != nil { log.Fatal(err) } fmt.Println(u.Hostname()) u, err = url.Parse("https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000") if err != nil { log.Fatal(err) } fmt.Println(u.Hostname()) }
Output: example.org 2001:0db8:85a3:0000:0000:8a2e:0370:7334
func (u *URL) IsAbs() bool
IsAbs reports whether the URL is absolute.
Absolute means that it has a non-empty scheme.
package main import ( "fmt" "net/url" ) func main() { u := url.URL{Host: "example.com", Path: "foo"} fmt.Println(u.IsAbs()) u.Scheme = "http" fmt.Println(u.IsAbs()) }
Output: false true
func (u *URL) JoinPath(elem ...string) *URL
JoinPath returns a new URL with the provided path elements joined to
any existing path and the resulting path cleaned of any ./ or ../ elements.
Any sequences of multiple / characters will be reduced to a single /.
func (u *URL) MarshalBinary() (text []byte, err error)
package main import ( "fmt" "log" "net/url" ) func main() { u, _ := url.Parse("https://example.org") b, err := u.MarshalBinary() if err != nil { log.Fatal(err) } fmt.Printf("%sn", b) }
Output: https://example.org
Parse parses a URL in the context of the receiver. The provided URL
may be relative or absolute. Parse returns nil, err on parse
failure, otherwise its return value is the same as ResolveReference.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("https://example.org") if err != nil { log.Fatal(err) } rel, err := u.Parse("/foo") if err != nil { log.Fatal(err) } fmt.Println(rel) _, err = u.Parse(":foo") if _, ok := err.(*url.Error); !ok { log.Fatal(err) } }
Output: https://example.org/foo
Port returns the port part of u.Host, without the leading colon.
If u.Host doesn’t contain a valid numeric port, Port returns an empty string.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("https://example.org") if err != nil { log.Fatal(err) } fmt.Println(u.Port()) u, err = url.Parse("https://example.org:8080") if err != nil { log.Fatal(err) } fmt.Println(u.Port()) }
Output: 8080
func (u *URL) Query() Values
Query parses RawQuery and returns the corresponding values.
It silently discards malformed value pairs.
To check errors use ParseQuery.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("https://example.org/?a=1&a=2&b=&=3&&&&") if err != nil { log.Fatal(err) } q := u.Query() fmt.Println(q["a"]) fmt.Println(q.Get("b")) fmt.Println(q.Get("")) }
Output: [1 2] 3
Redacted is like String but replaces any password with «xxxxx».
Only the password in u.URL is redacted.
package main import ( "fmt" "net/url" ) func main() { u := &url.URL{ Scheme: "https", User: url.UserPassword("user", "password"), Host: "example.com", Path: "foo/bar", } fmt.Println(u.Redacted()) u.User = url.UserPassword("me", "newerPassword") fmt.Println(u.Redacted()) }
Output: https://user:xxxxx@example.com/foo/bar https://me:xxxxx@example.com/foo/bar
RequestURI returns the encoded path?query or opaque?query
string that would be used in an HTTP request for u.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("https://example.org/path?foo=bar") if err != nil { log.Fatal(err) } fmt.Println(u.RequestURI()) }
Output: /path?foo=bar
func (u *URL) ResolveReference(ref *URL) *URL
ResolveReference resolves a URI reference to an absolute URI from
an absolute base URI u, per RFC 3986 Section 5.2. The URI reference
may be relative or absolute. ResolveReference always returns a new
URL instance, even if the returned URL is identical to either the
base or reference. If ref is an absolute URL, then ResolveReference
ignores base and returns a copy of ref.
package main import ( "fmt" "log" "net/url" ) func main() { u, err := url.Parse("../../..//search?q=dotnet") if err != nil { log.Fatal(err) } base, err := url.Parse("http://example.com/directory/") if err != nil { log.Fatal(err) } fmt.Println(base.ResolveReference(u)) }
Output: http://example.com/search?q=dotnet
String reassembles the URL into a valid URL string.
The general form of the result is one of:
scheme:opaque?query#fragment scheme://userinfo@host/path?query#fragment
If u.Opaque is non-empty, String uses the first form;
otherwise it uses the second form.
Any non-ASCII characters in host are escaped.
To obtain the path, String uses u.EscapedPath().
In the second form, the following rules apply:
- if u.Scheme is empty, scheme: is omitted.
- if u.User is nil, userinfo@ is omitted.
- if u.Host is empty, host/ is omitted.
- if u.Scheme and u.Host are empty and u.User is nil,
the entire scheme://userinfo@host/ is omitted. - if u.Host is non-empty and u.Path begins with a /,
the form host/path does not add its own /. - if u.RawQuery is empty, ?query is omitted.
- if u.Fragment is empty, #fragment is omitted.
package main import ( "fmt" "net/url" ) func main() { u := &url.URL{ Scheme: "https", User: url.UserPassword("me", "pass"), Host: "example.com", Path: "foo/bar", RawQuery: "x=1&y=2", Fragment: "anchor", } fmt.Println(u.String()) u.Opaque = "opaque" fmt.Println(u.String()) }
Output: https://me:pass@example.com/foo/bar?x=1&y=2#anchor https:opaque?x=1&y=2#anchor
package main import ( "fmt" "log" "net/url" ) func main() { u := &url.URL{} err := u.UnmarshalBinary([]byte("https://example.org/foo")) if err != nil { log.Fatal(err) } fmt.Printf("%sn", u) }
Output: https://example.org/foo
The Userinfo type is an immutable encapsulation of username and
password details for a URL. An existing Userinfo value is guaranteed
to have a username set (potentially empty, as allowed by RFC 2396),
and optionally a password.
User returns a Userinfo containing the provided username
and no password set.
func UserPassword(username, password string) *Userinfo
UserPassword returns a Userinfo containing the provided username
and password.
This functionality should only be used with legacy web sites.
RFC 2396 warns that interpreting Userinfo this way
“is NOT RECOMMENDED, because the passing of authentication
information in clear text (such as URI) has proven to be a
security risk in almost every case where it has been used.”
Password returns the password in case it is set, and whether it is set.
String returns the encoded userinfo information in the standard form
of «username[:password]».
Username returns the username.
Values maps a string key to a list of values.
It is typically used for query parameters and form values.
Unlike in the http.Header map, the keys in a Values map
are case-sensitive.
package main import ( "fmt" "net/url" ) func main() { v := url.Values{} v.Set("name", "Ava") v.Add("friend", "Jess") v.Add("friend", "Sarah") v.Add("friend", "Zoe") // v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe" fmt.Println(v.Get("name")) fmt.Println(v.Get("friend")) fmt.Println(v["friend"]) }
Output: Ava Jess [Jess Sarah Zoe]
ParseQuery parses the URL-encoded query string and returns
a map listing the values specified for each key.
ParseQuery always returns a non-nil map containing all the
valid query parameters found; err describes the first decoding error
encountered, if any.
Query is expected to be a list of key=value settings separated by ampersands.
A setting without an equals sign is interpreted as a key set to an empty
value.
Settings containing a non-URL-encoded semicolon are considered invalid.
package main import ( "encoding/json" "fmt" "log" "net/url" "strings" ) func main() { m, err := url.ParseQuery(`x=1&y=2&y=3`) if err != nil { log.Fatal(err) } fmt.Println(toJSON(m)) } func toJSON(m any) string { js, err := json.Marshal(m) if err != nil { log.Fatal(err) } return strings.ReplaceAll(string(js), ",", ", ") }
Output: {"x":["1"], "y":["2", "3"]}
Add adds the value to key. It appends to any existing
values associated with key.
package main import ( "fmt" "net/url" ) func main() { v := url.Values{} v.Add("cat sounds", "meow") v.Add("cat sounds", "mew") v.Add("cat sounds", "mau") fmt.Println(v["cat sounds"]) }
Output: [meow mew mau]
Del deletes the values associated with key.
package main import ( "fmt" "net/url" ) func main() { v := url.Values{} v.Add("cat sounds", "meow") v.Add("cat sounds", "mew") v.Add("cat sounds", "mau") fmt.Println(v["cat sounds"]) v.Del("cat sounds") fmt.Println(v["cat sounds"]) }
Output: [meow mew mau] []
Encode encodes the values into “URL encoded” form
(«bar=baz&foo=quux») sorted by key.
package main import ( "fmt" "net/url" ) func main() { v := url.Values{} v.Add("cat sounds", "meow") v.Add("cat sounds", "mew/") v.Add("cat sounds", "mau$") fmt.Println(v.Encode()) }
Output: cat+sounds=meow&cat+sounds=mew%2F&cat+sounds=mau%24
Get gets the first value associated with the given key.
If there are no values associated with the key, Get returns
the empty string. To access multiple values, use the map
directly.
package main import ( "fmt" "net/url" ) func main() { v := url.Values{} v.Add("cat sounds", "meow") v.Add("cat sounds", "mew") v.Add("cat sounds", "mau") fmt.Printf("%qn", v.Get("cat sounds")) fmt.Printf("%qn", v.Get("dog sounds")) }
Output: "meow" ""
Has checks whether a given key is set.
package main import ( "fmt" "net/url" ) func main() { v := url.Values{} v.Add("cat sounds", "meow") v.Add("cat sounds", "mew") v.Add("cat sounds", "mau") fmt.Println(v.Has("cat sounds")) fmt.Println(v.Has("dog sounds")) }
Output: true false
Set sets the key to value. It replaces any existing
values.
package main import ( "fmt" "net/url" ) func main() { v := url.Values{} v.Add("cat sounds", "meow") v.Add("cat sounds", "mew") v.Add("cat sounds", "mau") fmt.Println(v["cat sounds"]) v.Set("cat sounds", "meow") fmt.Println(v["cat sounds"]) }
Output: [meow mew mau] [meow]
import "net/url"
- Overview
- Index
- Examples
Overview ▸
Overview ▾
Package url parses URLs and implements query escaping.
Index ▸
Index ▾
- func JoinPath(base string, elem …string) (result string, err error)
- func PathEscape(s string) string
- func PathUnescape(s string) (string, error)
- func QueryEscape(s string) string
- func QueryUnescape(s string) (string, error)
- type Error
- func (e *Error) Error() string
- func (e *Error) Temporary() bool
- func (e *Error) Timeout() bool
- func (e *Error) Unwrap() error
- type EscapeError
- func (e EscapeError) Error() string
- type InvalidHostError
- func (e InvalidHostError) Error() string
- type URL
- func Parse(rawURL string) (*URL, error)
- func ParseRequestURI(rawURL string) (*URL, error)
- func (u *URL) EscapedFragment() string
- func (u *URL) EscapedPath() string
- func (u *URL) Hostname() string
- func (u *URL) IsAbs() bool
- func (u *URL) JoinPath(elem …string) *URL
- func (u *URL) MarshalBinary() (text []byte, err error)
- func (u *URL) Parse(ref string) (*URL, error)
- func (u *URL) Port() string
- func (u *URL) Query() Values
- func (u *URL) Redacted() string
- func (u *URL) RequestURI() string
- func (u *URL) ResolveReference(ref *URL) *URL
- func (u *URL) String() string
- func (u *URL) UnmarshalBinary(text []byte) error
- type Userinfo
- func User(username string) *Userinfo
- func UserPassword(username, password string) *Userinfo
- func (u *Userinfo) Password() (string, bool)
- func (u *Userinfo) String() string
- func (u *Userinfo) Username() string
- type Values
- func ParseQuery(query string) (Values, error)
- func (v Values) Add(key, value string)
- func (v Values) Del(key string)
- func (v Values) Encode() string
- func (v Values) Get(key string) string
- func (v Values) Has(key string) bool
- func (v Values) Set(key, value string)
Package files
url.go
func JoinPath
¶
1.19
func JoinPath(base string, elem ...string) (result string, err error)
JoinPath returns a URL string with the provided path elements joined to
the existing path of base and the resulting path cleaned of any ./ or ../ elements.
func PathEscape
¶
1.8
func PathEscape(s string) string
PathEscape escapes the string so it can be safely placed inside a URL path segment,
replacing special characters (including /) with %XX sequences as needed.
▸ Example
▾ Example
my%2Fcool+blog&about%2Cstuff
func PathUnescape
¶
1.8
func PathUnescape(s string) (string, error)
PathUnescape does the inverse transformation of PathEscape,
converting each 3-byte encoded substring of the form «%AB» into the
hex-decoded byte 0xAB. It returns an error if any % is not followed
by two hexadecimal digits.
PathUnescape is identical to QueryUnescape except that it does not
unescape ‘+’ to ‘ ‘ (space).
func QueryEscape
¶
func QueryEscape(s string) string
QueryEscape escapes the string so it can be safely placed
inside a URL query.
▸ Example
▾ Example
my%2Fcool%2Bblog%26about%2Cstuff
func QueryUnescape
¶
func QueryUnescape(s string) (string, error)
QueryUnescape does the inverse transformation of QueryEscape,
converting each 3-byte encoded substring of the form «%AB» into the
hex-decoded byte 0xAB.
It returns an error if any % is not followed by two hexadecimal
digits.
type Error
¶
Error reports an error and the operation and URL that caused it.
type Error struct { Op string URL string Err error }
func (*Error) Error
¶
func (e *Error) Error() string
func (*Error) Temporary
¶
1.6
func (e *Error) Temporary() bool
func (*Error) Timeout
¶
1.6
func (e *Error) Timeout() bool
func (*Error) Unwrap
¶
1.13
func (e *Error) Unwrap() error
type EscapeError
¶
type EscapeError string
func (EscapeError) Error
¶
func (e EscapeError) Error() string
type InvalidHostError
¶
1.6
type InvalidHostError string
func (InvalidHostError) Error
¶
1.6
func (e InvalidHostError) Error() string
type URL
¶
A URL represents a parsed URL (technically, a URI reference).
The general form represented is:
[scheme:][//[userinfo@]host][/]path[?query][#fragment]
URLs that do not start with a slash after the scheme are interpreted as:
scheme:opaque[?query][#fragment]
Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
A consequence is that it is impossible to tell which slashes in the Path were
slashes in the raw URL and which were %2f. This distinction is rarely important,
but when it is, the code should use the EscapedPath method, which preserves
the original encoding of Path.
The RawPath field is an optional field which is only set when the default
encoding of Path is different from the escaped path. See the EscapedPath method
for more details.
URL’s String method uses the EscapedPath method to obtain the path.
type URL struct { Scheme string Opaque string User *Userinfo Host string Path string RawPath string OmitHost bool ForceQuery bool RawQuery string Fragment string RawFragment string }
▸ Example
▾ Example
https://google.com/search?q=golang
▸ Example (Roundtrip)
▾ Example (Roundtrip)
/foo/bar /foo%2fbar https://example.com/foo%2fbar
func Parse
¶
func Parse(rawURL string) (*URL, error)
Parse parses a raw url into a URL structure.
The url may be relative (a path, without a host) or absolute
(starting with a scheme). Trying to parse a hostname and path
without a scheme is invalid but may not necessarily return an
error, due to parsing ambiguities.
func ParseRequestURI
¶
func ParseRequestURI(rawURL string) (*URL, error)
ParseRequestURI parses a raw url into a URL structure. It assumes that
url was received in an HTTP request, so the url is interpreted
only as an absolute URI or an absolute path.
The string url is assumed not to have a #fragment suffix.
(Web browsers strip #fragment before sending the URL to a web server.)
func (*URL) EscapedFragment
¶
1.15
func (u *URL) EscapedFragment() string
EscapedFragment returns the escaped form of u.Fragment.
In general there are multiple possible escaped forms of any fragment.
EscapedFragment returns u.RawFragment when it is a valid escaping of u.Fragment.
Otherwise EscapedFragment ignores u.RawFragment and computes an escaped
form on its own.
The String method uses EscapedFragment to construct its result.
In general, code should call EscapedFragment instead of
reading u.RawFragment directly.
▸ Example
▾ Example
Fragment: x/y/z RawFragment: x/y%2Fz EscapedFragment: x/y%2Fz
func (*URL) EscapedPath
¶
1.5
func (u *URL) EscapedPath() string
EscapedPath returns the escaped form of u.Path.
In general there are multiple possible escaped forms of any path.
EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
Otherwise EscapedPath ignores u.RawPath and computes an escaped
form on its own.
The String and RequestURI methods use EscapedPath to construct
their results.
In general, code should call EscapedPath instead of
reading u.RawPath directly.
▸ Example
▾ Example
Path: /x/y/z RawPath: /x/y%2Fz EscapedPath: /x/y%2Fz
func (*URL) Hostname
¶
1.8
func (u *URL) Hostname() string
Hostname returns u.Host, stripping any valid port number if present.
If the result is enclosed in square brackets, as literal IPv6 addresses are,
the square brackets are removed from the result.
▸ Example
▾ Example
example.org 2001:0db8:85a3:0000:0000:8a2e:0370:7334
func (*URL) IsAbs
¶
func (u *URL) IsAbs() bool
IsAbs reports whether the URL is absolute.
Absolute means that it has a non-empty scheme.
func (*URL) JoinPath
¶
1.19
func (u *URL) JoinPath(elem ...string) *URL
JoinPath returns a new URL with the provided path elements joined to
any existing path and the resulting path cleaned of any ./ or ../ elements.
Any sequences of multiple / characters will be reduced to a single /.
func (*URL) MarshalBinary
¶
1.8
func (u *URL) MarshalBinary() (text []byte, err error)
func (*URL) Parse
¶
func (u *URL) Parse(ref string) (*URL, error)
Parse parses a URL in the context of the receiver. The provided URL
may be relative or absolute. Parse returns nil, err on parse
failure, otherwise its return value is the same as ResolveReference.
func (*URL) Port
¶
1.8
func (u *URL) Port() string
Port returns the port part of u.Host, without the leading colon.
If u.Host doesn’t contain a valid numeric port, Port returns an empty string.
func (*URL) Query
¶
func (u *URL) Query() Values
Query parses RawQuery and returns the corresponding values.
It silently discards malformed value pairs.
To check errors use ParseQuery.
func (*URL) Redacted
¶
1.15
func (u *URL) Redacted() string
Redacted is like String but replaces any password with «xxxxx».
Only the password in u.URL is redacted.
▸ Example
▾ Example
https://user:xxxxx@example.com/foo/bar https://me:xxxxx@example.com/foo/bar
func (*URL) RequestURI
¶
func (u *URL) RequestURI() string
RequestURI returns the encoded path?query or opaque?query
string that would be used in an HTTP request for u.
func (*URL) ResolveReference
¶
func (u *URL) ResolveReference(ref *URL) *URL
ResolveReference resolves a URI reference to an absolute URI from
an absolute base URI u, per RFC 3986 Section 5.2. The URI reference
may be relative or absolute. ResolveReference always returns a new
URL instance, even if the returned URL is identical to either the
base or reference. If ref is an absolute URL, then ResolveReference
ignores base and returns a copy of ref.
▸ Example
▾ Example
http://example.com/search?q=dotnet
func (*URL) String
¶
func (u *URL) String() string
String reassembles the URL into a valid URL string.
The general form of the result is one of:
scheme:opaque?query#fragment scheme://userinfo@host/path?query#fragment
If u.Opaque is non-empty, String uses the first form;
otherwise it uses the second form.
Any non-ASCII characters in host are escaped.
To obtain the path, String uses u.EscapedPath().
In the second form, the following rules apply:
- if u.Scheme is empty, scheme: is omitted.
- if u.User is nil, userinfo@ is omitted.
- if u.Host is empty, host/ is omitted.
- if u.Scheme and u.Host are empty and u.User is nil,
the entire scheme://userinfo@host/ is omitted. - if u.Host is non-empty and u.Path begins with a /,
the form host/path does not add its own /. - if u.RawQuery is empty, ?query is omitted.
- if u.Fragment is empty, #fragment is omitted.
▸ Example
▾ Example
https://me:pass@example.com/foo/bar?x=1&y=2#anchor https:opaque?x=1&y=2#anchor
func (*URL) UnmarshalBinary
¶
1.8
func (u *URL) UnmarshalBinary(text []byte) error
type Userinfo
¶
The Userinfo type is an immutable encapsulation of username and
password details for a URL. An existing Userinfo value is guaranteed
to have a username set (potentially empty, as allowed by RFC 2396),
and optionally a password.
type Userinfo struct { }
func User
¶
func User(username string) *Userinfo
User returns a Userinfo containing the provided username
and no password set.
func UserPassword
¶
func UserPassword(username, password string) *Userinfo
UserPassword returns a Userinfo containing the provided username
and password.
This functionality should only be used with legacy web sites.
RFC 2396 warns that interpreting Userinfo this way
“is NOT RECOMMENDED, because the passing of authentication
information in clear text (such as URI) has proven to be a
security risk in almost every case where it has been used.”
func (*Userinfo) Password
¶
func (u *Userinfo) Password() (string, bool)
Password returns the password in case it is set, and whether it is set.
func (*Userinfo) String
¶
func (u *Userinfo) String() string
String returns the encoded userinfo information in the standard form
of «username[:password]».
func (*Userinfo) Username
¶
func (u *Userinfo) Username() string
Username returns the username.
type Values
¶
Values maps a string key to a list of values.
It is typically used for query parameters and form values.
Unlike in the http.Header map, the keys in a Values map
are case-sensitive.
type Values map[string][]string
▸ Example
▾ Example
Ava Jess [Jess Sarah Zoe]
func ParseQuery
¶
func ParseQuery(query string) (Values, error)
ParseQuery parses the URL-encoded query string and returns
a map listing the values specified for each key.
ParseQuery always returns a non-nil map containing all the
valid query parameters found; err describes the first decoding error
encountered, if any.
Query is expected to be a list of key=value settings separated by ampersands.
A setting without an equals sign is interpreted as a key set to an empty
value.
Settings containing a non-URL-encoded semicolon are considered invalid.
▸ Example
▾ Example
{"x":["1"], "y":["2", "3"]}
func (Values) Add
¶
func (v Values) Add(key, value string)
Add adds the value to key. It appends to any existing
values associated with key.
func (Values) Del
¶
func (v Values) Del(key string)
Del deletes the values associated with key.
func (Values) Encode
¶
func (v Values) Encode() string
Encode encodes the values into “URL encoded” form
(«bar=baz&foo=quux») sorted by key.
▸ Example
▾ Example
cat+sounds=meow&cat+sounds=mew%2F&cat+sounds=mau%24
func (Values) Get
¶
func (v Values) Get(key string) string
Get gets the first value associated with the given key.
If there are no values associated with the key, Get returns
the empty string. To access multiple values, use the map
directly.
func (Values) Has
¶
1.17
func (v Values) Has(key string) bool
Has checks whether a given key is set.
func (Values) Set
¶
func (v Values) Set(key, value string)
Set sets the key to value. It replaces any existing
values.
Package url
import "net/url"
- Overview
- Index
- Examples
Overview ▹
Overview ▾
Package url parses URLs and implements query escaping.
Index ▹
Index ▾
- func PathEscape(s string) string
- func PathUnescape(s string) (string, error)
- func QueryEscape(s string) string
- func QueryUnescape(s string) (string, error)
- type Error
- func (e *Error) Error() string
- func (e *Error) Temporary() bool
- func (e *Error) Timeout() bool
- func (e *Error) Unwrap() error
- type EscapeError
- func (e EscapeError) Error() string
- type InvalidHostError
- func (e InvalidHostError) Error() string
- type URL
- func Parse(rawURL string) (*URL, error)
- func ParseRequestURI(rawURL string) (*URL, error)
- func (u *URL) EscapedFragment() string
- func (u *URL) EscapedPath() string
- func (u *URL) Hostname() string
- func (u *URL) IsAbs() bool
- func (u *URL) MarshalBinary() (text []byte, err error)
- func (u *URL) Parse(ref string) (*URL, error)
- func (u *URL) Port() string
- func (u *URL) Query() Values
- func (u *URL) Redacted() string
- func (u *URL) RequestURI() string
- func (u *URL) ResolveReference(ref *URL) *URL
- func (u *URL) String() string
- func (u *URL) UnmarshalBinary(text []byte) error
- type Userinfo
- func User(username string) *Userinfo
- func UserPassword(username, password string) *Userinfo
- func (u *Userinfo) Password() (string, bool)
- func (u *Userinfo) String() string
- func (u *Userinfo) Username() string
- type Values
- func ParseQuery(query string) (Values, error)
- func (v Values) Add(key, value string)
- func (v Values) Del(key string)
- func (v Values) Encode() string
- func (v Values) Get(key string) string
- func (v Values) Has(key string) bool
- func (v Values) Set(key, value string)
Package files
url.go
func PathEscape
¶
1.8
func PathEscape(s string) string
PathEscape escapes the string so it can be safely placed inside a URL path segment,
replacing special characters (including /) with %XX sequences as needed.
func PathUnescape
¶
1.8
func PathUnescape(s string) (string, error)
PathUnescape does the inverse transformation of PathEscape,
converting each 3-byte encoded substring of the form «%AB» into the
hex-decoded byte 0xAB. It returns an error if any % is not followed
by two hexadecimal digits.
PathUnescape is identical to QueryUnescape except that it does not
unescape ‘+’ to ‘ ‘ (space).
func QueryEscape
¶
func QueryEscape(s string) string
QueryEscape escapes the string so it can be safely placed
inside a URL query.
func QueryUnescape
¶
func QueryUnescape(s string) (string, error)
QueryUnescape does the inverse transformation of QueryEscape,
converting each 3-byte encoded substring of the form «%AB» into the
hex-decoded byte 0xAB.
It returns an error if any % is not followed by two hexadecimal
digits.
type Error
¶
Error reports an error and the operation and URL that caused it.
type Error struct { Op string URL string Err error }
func (*Error) Error
¶
func (e *Error) Error() string
func (*Error) Temporary
¶
1.6
func (e *Error) Temporary() bool
func (*Error) Timeout
¶
1.6
func (e *Error) Timeout() bool
func (*Error) Unwrap
¶
1.13
func (e *Error) Unwrap() error
type EscapeError
¶
type EscapeError string
func (EscapeError) Error
¶
func (e EscapeError) Error() string
type InvalidHostError
¶
1.6
type InvalidHostError string
func (InvalidHostError) Error
¶
1.6
func (e InvalidHostError) Error() string
type URL
¶
A URL represents a parsed URL (technically, a URI reference).
The general form represented is:
[scheme:][//[userinfo@]host][/]path[?query][#fragment]
URLs that do not start with a slash after the scheme are interpreted as:
scheme:opaque[?query][#fragment]
Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
A consequence is that it is impossible to tell which slashes in the Path were
slashes in the raw URL and which were %2f. This distinction is rarely important,
but when it is, the code should use RawPath, an optional field which only gets
set if the default encoding is different from Path.
URL’s String method uses the EscapedPath method to obtain the path. See the
EscapedPath method for more details.
type URL struct { Scheme string Opaque string User *Userinfo Host string Path string RawPath string ForceQuery bool RawQuery string Fragment string RawFragment string }
▹ Example
▾ Example
https://google.com/search?q=golang
▹ Example (Roundtrip)
▾ Example (Roundtrip)
/foo/bar /foo%2fbar https://example.com/foo%2fbar
func Parse
¶
func Parse(rawURL string) (*URL, error)
Parse parses a raw url into a URL structure.
The url may be relative (a path, without a host) or absolute
(starting with a scheme). Trying to parse a hostname and path
without a scheme is invalid but may not necessarily return an
error, due to parsing ambiguities.
func ParseRequestURI
¶
func ParseRequestURI(rawURL string) (*URL, error)
ParseRequestURI parses a raw url into a URL structure. It assumes that
url was received in an HTTP request, so the url is interpreted
only as an absolute URI or an absolute path.
The string url is assumed not to have a #fragment suffix.
(Web browsers strip #fragment before sending the URL to a web server.)
func (*URL) EscapedFragment
¶
1.15
func (u *URL) EscapedFragment() string
EscapedFragment returns the escaped form of u.Fragment.
In general there are multiple possible escaped forms of any fragment.
EscapedFragment returns u.RawFragment when it is a valid escaping of u.Fragment.
Otherwise EscapedFragment ignores u.RawFragment and computes an escaped
form on its own.
The String method uses EscapedFragment to construct its result.
In general, code should call EscapedFragment instead of
reading u.RawFragment directly.
▹ Example
▾ Example
Fragment: x/y/z RawFragment: x/y%2Fz EscapedFragment: x/y%2Fz
func (*URL) EscapedPath
¶
1.5
func (u *URL) EscapedPath() string
EscapedPath returns the escaped form of u.Path.
In general there are multiple possible escaped forms of any path.
EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
Otherwise EscapedPath ignores u.RawPath and computes an escaped
form on its own.
The String and RequestURI methods use EscapedPath to construct
their results.
In general, code should call EscapedPath instead of
reading u.RawPath directly.
▹ Example
▾ Example
Path: /x/y/z RawPath: /x/y%2Fz EscapedPath: /x/y%2Fz
func (*URL) Hostname
¶
1.8
func (u *URL) Hostname() string
Hostname returns u.Host, stripping any valid port number if present.
If the result is enclosed in square brackets, as literal IPv6 addresses are,
the square brackets are removed from the result.
▹ Example
▾ Example
example.org 2001:0db8:85a3:0000:0000:8a2e:0370:7334
func (*URL) IsAbs
¶
func (u *URL) IsAbs() bool
IsAbs reports whether the URL is absolute.
Absolute means that it has a non-empty scheme.
func (*URL) MarshalBinary
¶
1.8
func (u *URL) MarshalBinary() (text []byte, err error)
func (*URL) Parse
¶
func (u *URL) Parse(ref string) (*URL, error)
Parse parses a URL in the context of the receiver. The provided URL
may be relative or absolute. Parse returns nil, err on parse
failure, otherwise its return value is the same as ResolveReference.
func (*URL) Port
¶
1.8
func (u *URL) Port() string
Port returns the port part of u.Host, without the leading colon.
If u.Host doesn’t contain a valid numeric port, Port returns an empty string.
func (*URL) Query
¶
func (u *URL) Query() Values
Query parses RawQuery and returns the corresponding values.
It silently discards malformed value pairs.
To check errors use ParseQuery.
func (*URL) Redacted
¶
1.15
func (u *URL) Redacted() string
Redacted is like String but replaces any password with «xxxxx».
Only the password in u.URL is redacted.
▹ Example
▾ Example
https://user:xxxxx@example.com/foo/bar https://me:xxxxx@example.com/foo/bar
func (*URL) RequestURI
¶
func (u *URL) RequestURI() string
RequestURI returns the encoded path?query or opaque?query
string that would be used in an HTTP request for u.
func (*URL) ResolveReference
¶
func (u *URL) ResolveReference(ref *URL) *URL
ResolveReference resolves a URI reference to an absolute URI from
an absolute base URI u, per RFC 3986 Section 5.2. The URI reference
may be relative or absolute. ResolveReference always returns a new
URL instance, even if the returned URL is identical to either the
base or reference. If ref is an absolute URL, then ResolveReference
ignores base and returns a copy of ref.
▹ Example
▾ Example
http://example.com/search?q=dotnet
func (*URL) String
¶
func (u *URL) String() string
String reassembles the URL into a valid URL string.
The general form of the result is one of:
scheme:opaque?query#fragment scheme://userinfo@host/path?query#fragment
If u.Opaque is non-empty, String uses the first form;
otherwise it uses the second form.
Any non-ASCII characters in host are escaped.
To obtain the path, String uses u.EscapedPath().
In the second form, the following rules apply:
- if u.Scheme is empty, scheme: is omitted. - if u.User is nil, userinfo@ is omitted. - if u.Host is empty, host/ is omitted. - if u.Scheme and u.Host are empty and u.User is nil, the entire scheme://userinfo@host/ is omitted. - if u.Host is non-empty and u.Path begins with a /, the form host/path does not add its own /. - if u.RawQuery is empty, ?query is omitted. - if u.Fragment is empty, #fragment is omitted.
▹ Example
▾ Example
https://me:pass@example.com/foo/bar?x=1&y=2#anchor https:opaque?x=1&y=2#anchor
func (*URL) UnmarshalBinary
¶
1.8
func (u *URL) UnmarshalBinary(text []byte) error
type Userinfo
¶
The Userinfo type is an immutable encapsulation of username and
password details for a URL. An existing Userinfo value is guaranteed
to have a username set (potentially empty, as allowed by RFC 2396),
and optionally a password.
type Userinfo struct { }
func User
¶
func User(username string) *Userinfo
User returns a Userinfo containing the provided username
and no password set.
func UserPassword
¶
func UserPassword(username, password string) *Userinfo
UserPassword returns a Userinfo containing the provided username
and password.
This functionality should only be used with legacy web sites.
RFC 2396 warns that interpreting Userinfo this way
“is NOT RECOMMENDED, because the passing of authentication
information in clear text (such as URI) has proven to be a
security risk in almost every case where it has been used.”
func (*Userinfo) Password
¶
func (u *Userinfo) Password() (string, bool)
Password returns the password in case it is set, and whether it is set.
func (*Userinfo) String
¶
func (u *Userinfo) String() string
String returns the encoded userinfo information in the standard form
of «username[:password]».
func (*Userinfo) Username
¶
func (u *Userinfo) Username() string
Username returns the username.
type Values
¶
Values maps a string key to a list of values.
It is typically used for query parameters and form values.
Unlike in the http.Header map, the keys in a Values map
are case-sensitive.
type Values map[string][]string
▹ Example
▾ Example
Ava Jess [Jess Sarah Zoe]
func ParseQuery
¶
func ParseQuery(query string) (Values, error)
ParseQuery parses the URL-encoded query string and returns
a map listing the values specified for each key.
ParseQuery always returns a non-nil map containing all the
valid query parameters found; err describes the first decoding error
encountered, if any.
Query is expected to be a list of key=value settings separated by ampersands.
A setting without an equals sign is interpreted as a key set to an empty
value.
Settings containing a non-URL-encoded semicolon are considered invalid.
▹ Example
▾ Example
{"x":["1"], "y":["2", "3"]}
func (Values) Add
¶
func (v Values) Add(key, value string)
Add adds the value to key. It appends to any existing
values associated with key.
func (Values) Del
¶
func (v Values) Del(key string)
Del deletes the values associated with key.
func (Values) Encode
¶
func (v Values) Encode() string
Encode encodes the values into “URL encoded” form
(«bar=baz&foo=quux») sorted by key.
func (Values) Get
¶
func (v Values) Get(key string) string
Get gets the first value associated with the given key.
If there are no values associated with the key, Get returns
the empty string. To access multiple values, use the map
directly.
func (Values) Has
¶
1.17
func (v Values) Has(key string) bool
Has checks whether a given key is set.
func (Values) Set
¶
func (v Values) Set(key, value string)
Set sets the key to value. It replaces any existing
values.
Validation is part of every programmer life, especially when working on backend services, validation must be done right. In this blog post we talk about how to properly validate a URL in Go (Golang).
URL stands for Unique Resource Locator, and is a sub-type of URI (even though many people interchangeably use the two terms). A URL is a reference to a web resource, typically seen as a web address (eg https://golang.org/project/)
Below you can see the structure of a URL, which conforms with he structure of a URI
URI = scheme:[//authority]path[?query][#fragment]
authority = [[email protected]]host[:port]
How do you validate a URL in Go (Golang)?
I’ve always been impressed by the number of native packages in the Go standard library. Also this time we have a package that fulfils our needs. The net/url
package https://golang.org/pkg/net/url/
We can use url.ParseRequestURI
in order to validate our URL
func ParseRequestURI(rawurl string) (*URL, error)
The behaviour is described below
ParseRequestURI parses rawurl into a URL structure. It assumes that rawurl was received in an HTTP request, so the rawurl is interpreted only as an absolute URI or an absolute path. The string rawurl is assumed not to have a #fragment suffix. (Web browsers strip #fragment before sending the URL to a web server.)
Caveat: ParseRequestURI vs Parse
There is also another method that is supposed to be used for Parsing URL strings, but there are some caveats. It allows relative URLs making the validation a bit more loose. It’s url.Parse
func Parse(rawurl string) (*URL, error)
As described on the docs
Parse parses rawurl into a URL structure.
The rawurl may be relative (a path, without a host) or absolute (starting with a scheme). Trying to parse a hostname and path without a scheme is invalid but may not necessarily return an error, due to parsing ambiguities.
Parse URL Example
Let’s see now an example on how to parse and validate a URL in Go using ParseRequestURI
package main
import (
"log"
"net/url"
)
func main() {
u, err := url.ParseRequestURI("hi/there?")
log.Printf("hi/there?: err=%+v url=%+vn", err, u)
u, err = url.ParseRequestURI("http://golang.cafe/")
log.Printf("hi/there?: err=%+v url=%+vn", err, u)
u, err = url.ParseRequestURI("http://golang.org/index.html?#page1")
log.Printf("hi/there?: err=%+v url=%+vn", err, u)
u, err = url.ParseRequestURI("golang.org")
log.Printf("hi/there?: err=%+v url=%+vn", err, u)
}
Which outputs the following
2009/11/10 23:00:00 hi/there?: err=parse hi/there?: invalid URI for request url=<nil>
2009/11/10 23:00:00 hi/there?: err=<nil> url=http://golang.cafe/
2009/11/10 23:00:00 hi/there?: err=<nil> url=http://golang.org/index.html?#page1
2009/11/10 23:00:00 hi/there?: err=parse golang.org: invalid URI for request url=<nil>
Overview ?
Overview ?
Package url parses URLs and implements query escaping.
See RFC 3986.
- func QueryEscape(s string) string
- func QueryUnescape(s string) (string, error)
- type Error
- func (e *Error) Error() string
- type EscapeError
- func (e EscapeError) Error() string
- type URL
- func Parse(rawurl string) (url *URL, err error)
- func ParseRequestURI(rawurl string) (url *URL, err error)
- func (u *URL) IsAbs() bool
- func (u *URL) Parse(ref string) (*URL, error)
- func (u *URL) Query() Values
- func (u *URL) RequestURI() string
- func (u *URL) ResolveReference(ref *URL) *URL
- func (u *URL) String() string
- type Userinfo
- func User(username string) *Userinfo
- func UserPassword(username, password string) *Userinfo
- func (u *Userinfo) Password() (string, bool)
- func (u *Userinfo) String() string
- func (u *Userinfo) Username() string
- type Values
- func ParseQuery(query string) (m Values, err error)
- func (v Values) Add(key, value string)
- func (v Values) Del(key string)
- func (v Values) Encode() string
- func (v Values) Get(key string) string
- func (v Values) Set(key, value string)
Examples
- URL
- Values
Package files
url.go
func QueryEscape
func QueryEscape(s string) string
QueryEscape escapes the string so it can be safely placed
inside a URL query.
func QueryUnescape
func QueryUnescape(s string) (string, error)
QueryUnescape does the inverse transformation of QueryEscape, converting
%AB into the byte 0xAB and ‘+’ into ‘ ‘ (space). It returns an error if
any % is not followed by two hexadecimal digits.
type Error
type Error struct { Op string URL string Err error }
Error reports an error and the operation and URL that caused it.
func (*Error) Error
func (e *Error) Error() string
type EscapeError
type EscapeError string
func (EscapeError) Error
func (e EscapeError) Error() string
type URL
type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string Path string RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' }
A URL represents a parsed URL (technically, a URI reference).
The general form represented is:
scheme://[[email protected]]host/path[?query][#fragment]
URLs that do not start with a slash after the scheme are interpreted as:
scheme:opaque[?query][#fragment]
? Example
? Example
Code:
u, err := url.Parse("http://bing.com/search?q=dotnet") if err != nil { log.Fatal(err) } u.Scheme = "https" u.Host = "google.com" q := u.Query() q.Set("q", "golang") u.RawQuery = q.Encode() fmt.Println(u)
Output:
https://google.com/search?q=golang
func Parse
func Parse(rawurl string) (url *URL, err error)
Parse parses rawurl into a URL structure.
The rawurl may be relative or absolute.
func ParseRequestURI
func ParseRequestURI(rawurl string) (url *URL, err error)
ParseRequestURI parses rawurl into a URL structure. It assumes that
rawurl was received in an HTTP request, so the rawurl is interpreted
only as an absolute URI or an absolute path.
The string rawurl is assumed not to have a #fragment suffix.
(Web browsers strip #fragment before sending the URL to a web server.)
func (*URL) IsAbs
func (u *URL) IsAbs() bool
IsAbs returns true if the URL is absolute.
func (*URL) Parse
func (u *URL) Parse(ref string) (*URL, error)
Parse parses a URL in the context of the receiver. The provided URL
may be relative or absolute. Parse returns nil, err on parse
failure, otherwise its return value is the same as ResolveReference.
func (*URL) Query
func (u *URL) Query() Values
Query parses RawQuery and returns the corresponding values.
func (*URL) RequestURI
func (u *URL) RequestURI() string
RequestURI returns the encoded path?query or opaque?query
string that would be used in an HTTP request for u.
func (*URL) ResolveReference
func (u *URL) ResolveReference(ref *URL) *URL
ResolveReference resolves a URI reference to an absolute URI from
an absolute base URI, per RFC 2396 Section 5.2. The URI reference
may be relative or absolute. ResolveReference always returns a new
URL instance, even if the returned URL is identical to either the
base or reference. If ref is an absolute URL, then ResolveReference
ignores base and returns a copy of ref.
func (*URL) String
func (u *URL) String() string
String reassembles the URL into a valid URL string.
type Userinfo
type Userinfo struct {
// contains filtered or unexported fields
}
The Userinfo type is an immutable encapsulation of username and
password details for a URL. An existing Userinfo value is guaranteed
to have a username set (potentially empty, as allowed by RFC 2396),
and optionally a password.
func User
func User(username string) *Userinfo
User returns a Userinfo containing the provided username
and no password set.
func UserPassword
func UserPassword(username, password string) *Userinfo
UserPassword returns a Userinfo containing the provided username
and password.
This functionality should only be used with legacy web sites.
RFC 2396 warns that interpreting Userinfo this way
“is NOT RECOMMENDED, because the passing of authentication
information in clear text (such as URI) has proven to be a
security risk in almost every case where it has been used.”
func (*Userinfo) Password
func (u *Userinfo) Password() (string, bool)
Password returns the password in case it is set, and whether it is set.
func (*Userinfo) String
func (u *Userinfo) String() string
String returns the encoded userinfo information in the standard form
of «username[:password]».
func (*Userinfo) Username
func (u *Userinfo) Username() string
Username returns the username.
type Values
type Values map[string][]string
Values maps a string key to a list of values.
It is typically used for query parameters and form values.
Unlike in the http.Header map, the keys in a Values map
are case-sensitive.
? Example
? Example
Code:
v := url.Values{}
v.Set("name", "Ava")
v.Add("friend", "Jess")
v.Add("friend", "Sarah")
v.Add("friend", "Zoe")
// v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe"
fmt.Println(v.Get("name"))
fmt.Println(v.Get("friend"))
fmt.Println(v["friend"])
Output:
Ava Jess [Jess Sarah Zoe]
func ParseQuery
func ParseQuery(query string) (m Values, err error)
ParseQuery parses the URL-encoded query string and returns
a map listing the values specified for each key.
ParseQuery always returns a non-nil map containing all the
valid query parameters found; err describes the first decoding error
encountered, if any.
func (Values) Add
func (v Values) Add(key, value string)
Add adds the key to value. It appends to any existing
values associated with key.
func (Values) Del
func (v Values) Del(key string)
Del deletes the values associated with key.
func (Values) Encode
func (v Values) Encode() string
Encode encodes the values into “URL encoded” form.
e.g. «foo=bar&bar=baz»
func (Values) Get
func (v Values) Get(key string) string
Get gets the first value associated with the given key.
If there are no values associated with the key, Get returns
the empty string. To access multiple values, use the map
directly.
func (Values) Set
func (v Values) Set(key, value string)
Set sets the key to value. It replaces any existing
values.
Давайте я сразу зайду с козырей. Сколько ошибок в коде этой функции вы можете найти за 60 секунд?
func NewConnectionString(host, path, database, user, password string, debug bool) string {
return fmt.Sprintf(
"proto://%s/%s?userName=%s&password=%s&database=%s&debug=%t",
host, path, database, user, password, debug,
)
}
Все ошибки в этом довольно небольшом коде найти и обезвредить довольно сложно. Я попробую их сейчас сформулировать и скомпоновать в две основные:
- очевидная — перепутаны параметры;
- не очевидная — параметры не экранируются.
Ладно, признавайтесь — наверняка каждый за 60 секунд смог заметить первую ошибку, но не все из вас смогут заметить вторую. Если ваш список ошибок оказался короче, чем мой — тогда прошу под кат.
История проблемы
Не подумайте, что тема высосана из пальца. Хоть и не часто, но она порой всплывает то тут, то там. То при клиент-серверном взаимодействии, когда разработчики не использовали openapi кодогенерацию и писали код вручную. То при генерации ConnectionString для драйвера базы данных. Да мало ли где можно ошибиться с этим дурацким URL?
Какие последствия? Да очень разнообразные, выбирайте на свой вкус:
логические ошибки
В некотором кол-ве случаев, когда параметр содержит недопустимый для query символ, весь URL либо становится полностью невалидным, либо мы получаем искаженный, но рабочий запрос. Если в первом случае мы можем заметить записи в журнале ошибок, то второй случай гораздо хуже — мы не сможем вовремя заметить ошибку. Возможно, даже никогда.
ошибки при внесении изменений
Не поверите, но есть такая история. В какой-то момент, когда разработчик изменял такую функцию, он перепутал местоположение плейсхолдера и параметра. И в такой форме функция существовала довольно долгое время. Почему никто не заметил проблемы? Да потому, что имя пользователя, пароль и наименование базы данных совпадало. А в тот момент, когда в этой схеме обновили уровень безопасности, и пароли стали генерироваться случайным порядком, все сломалось. Понятия не имею, сколько разработчик потратил времени на обнаружение ошибки, но когда я увидел эту функцию, я не заметил ошибки вообще.
нет гарантии корректности на этапе компиляции
Это очень важный пункт. Как мы все знаем, ошибки бывают двух основных видов: run-time и compile-time. Т.е. ошибки времени выполнения и времени компиляции соответственно. Какой вид хуже? Конечно ошибки времени выполнения. Почему? Да потому, что программа уже выполняется, а это значит, что данные уже могли пострадать. Кроме того, такие ошибки нужно сначала обнаружить и локализовать. Если мы вдруг пропустим знак амперсанда между параметрами — никто нам этого не скажет.
сложности экранирования
Поверьте мне на слово — экранировать правильно все части URL строки не так-то просто. Там есть, по крайней мере, три части, правила экранирования символов в которых отличаются. И я знаю не один пример реальных процессов коммерческой разработки, когда в связи с этим было принято решение ограничить допустимые символы для логина и пароля.
query injection
Да. Это почти как SQL injection, только query. Ну да, использование этой уязвимости имеет довольно узкий круг возможностей. Фактически, почти никаких возможностей, если мы не даем пользователю возможность влиять на параметры. Но все же, если отмести всякие контексты, и взглянуть правде в лицо, то это самая настоящая уязвимость.
Вона уже, как много смог описать. Надеюсь, я убедил вас в существовании реальной проблемы. Тогда давайте с ней бороться.
А как правильно?
Пакет net/url является стандартным пакетом языка GO и предоставляет довольно простой и удобный инструмент для формирования URL со всеми прилагающимися плюшками (согласно RFC 3986): гарантия синтаксической правильности, экранирование по всем канонам и проверка литералов на этапе компиляции.
Давайте еще раз посмотрим на “неправильный” код, я немного усложнил его расположением логина и пароля перед именем сервера, как положено по старому стандарту:
func NewSprintfConnectionString(proto, host, path, database, user, password string, debug bool) string {
return fmt.Sprintf("%s://%s:%s@%s%s?database=%s&debug=%t", proto, user, password, host, path, database, debug)
}
А теперь код, который структурирован:
func NewURLConnectionString(proto, host, path, database, user, password string, debug bool) string {
const (
cDataBaseURLParameter = "database"
cDebugURLParameter = "debug"
)
var v = make(url.Values)
v.Set(cDataBaseURLParameter, database)
if debug {
v.Set(cDebugURLParameter, "true")
} else {
v.Set(cDebugURLParameter, "false")
}
var u = url.URL{
Scheme: proto,
Host: host,
Path: path,
User: url.UserPassword(user, password),
RawQuery: v.Encode(),
}
return u.String()
}
Как вы могли заметить, код заметно увеличился. Но стал ли он сложнее? Давайте разберемся.
В верхней части я объявил константы, которые отвечают за наименование параметров. Это не обязательно и кроме того, если вы реализуете какой-то межпроцессный обмен между двумя сервисами вашей системы, возможно, эти константы уже есть. Я их выделил для того, чтобы не было magic-words. Это позволяет видеть мне список всех возможных параметров в одном месте и не дает мне ошибиться при многократном использовании одного и того же имени параметра в коде программы в нескольких местах. Я имею в виду использование cDebugURLParameter дважды — в случае, если мы используем magic-words у нас каждый раз есть риск допустить опечатку.
Следом я создаю и затем наполняю url.Values — структура, которая поможет мне собрать разные параметры query и затем собрать из них экранированную query строку. Обращаю внимание на то, что в такой форме код выходит довольно наглядным — мы видим имя параметра и прямо напротив него значение. Сравните расположение имен и значений в варианте с использованием fmt.Sprintf.
В нижней части литерал url.URL в котором я заполняю необходимые элементы URL строки: протокол, хост, путь и прочее. Обратите внимание на то, как используются параметры user и password. Любые символы в имени пользователя и пароле будут корректно экранированы, мы можем не ограничиваться в каких-то диапазонах, которые потом еще придется контролировать.
Обозримость кода существенно не изменилась — кол-во строк меньше 30, зато по ширине код стал компактнее и приобрел наглядность. Использование литерала url.URL и структуры url.Values позволяет заручиться гарантиями компилятора, что я не нарушу правил расположения амперсанд и других символов. Специальные символы, которые были внесены аргументами функции будут гарантировано экранированы по всем канонам (как я уже и говорил).
Ну и как вишенка на торте — сложность внесения изменений в эту функцию не зависит от количества параметров. Т.е. остается константой. Представьте, что у нас есть 7 параметров, а нам нужно убрать один из них, а затем добавить еще 7. В случае с форматной строкой (fmt.Sprintf), нам нужно быть аккуратными при внесении изменений, а если мы используем net/url, нам нужно добавить константы, которые будут нести имена новых параметров, а затем заполнить параметры с помощью v.Set(cDebugURLParameter, «false»). Что тут может пойти не так?
А что там с производительностью?
Ну да, придется немного добавить горчинки в мой салат. За все нужно платить, и нам придется заплатить за гарантии безопасности нашей URL строки производительностью. Сколько стоит? Давайте проверим. Для начала соберем вот такой бенчмарк:
Посмотреть код бенчмарка
func benchConnectionStringFunction(b *testing.B, fn func(proto, host, path, database, user, password string, debug bool) string) {
for i := 0; i < b.N; i++ {
_ = fn(
"http",
"my-host-name.com",
"/users/preferences/email",
"storage",
"vladimir@yandex.ru",
"foo-bar$100",
false,
)
}
}
func BenchmarkNewSprintfConnectionString(b *testing.B) {
benchConnectionStringFunction(b, NewSprintfConnectionString)
}
func BenchmarkNewURLConnectionString(b *testing.B) {
benchConnectionStringFunction(b, NewURLConnectionString)
}
func BenchmarkNewConcatenateConnectionString(b *testing.B) {
benchConnectionStringFunction(b, NewConcatenateConnectionString)
}
Тут у нас
- NewSprintfConnectionString — это вариант с fmt.Sprintf;
- NewURLConnectionString — это вариант с net/url;
- NewConcatenateConnectionString — это секретный вариант, который я раскрою позже, правда по названию уже можно догадаться в чем секрет.
Принимаем за номинальную производительность первый вариант. Ну так как я его критикую, как довольно простое и довольно неверное решение, считаю, что производительность нужно оценивать относительно этого варианта.
Итак, что там у нас получается?
Время: 435 ns/op
Память: 208 B/op
Аллокаций: 7 allocs/op
Довольно производительный вариант. Немного расстраивает количеством аллокаций, но тут ожидаемо, ведь все параметры для fmt.Sprintf приходят, как interface{} — а это всем известная драма.
Окей. Следующий на разделочной доске вариант с net/url (мой любимый). Сразу скажу, все map — это в любом случае аллокация в памяти, кроме того, если слайс используется вне функции (а в нашем случае у нас url.Values это как раз карта слайсов: map[string][]string), то он тоже приводит к аллокации. Ну и сложные манипуляции со строками внутри реализации url.URL.String() тоже не без аллокаций. Так что (барабанная дробь):
Время: 1237 ns/op
Память: 608 B/op
Аллокаций: 14 allocs/op
Ну на самом деле совсем неплохо, учитывая то, что все переменные (включая аргументы функции) утекли в heap. Мы получили всего троекратное проседание по производительности. Полторы микросекунды на операцию я считаю не такой уж большой платой за качество кода и стабильность процесса разработки. И если бы потребовалось немного затюнить производительность, то я бы обратил внимание на эту функцию, при условии многократного ее выполнения. Но пришел бы к очевидному выводу — проблема производительности при общении с сетью кроется совсем не во времени формирования URL, а на переходах в уровни ядра, времени передачи данных по сети и все связанные с этим накладные расходы. Так что к чему вообще все эти бенчмарки?
Окей, а если мы возьмем совершенно абстрактный случай: нам нужно сформировать множество URL строк из заданных параметров и отправить их в обработку дальше одним большим массивом. Т.е. возьмем случай, когда производительность этой процедуры имеет значение. Тогда давайте глянем на третий бенч:
Время: 416 ns/op
Память: 160 B/op
Аллокаций: 3 allocs/op
Довольно неплохо. Тут радует кол-во аллокаций. Да и по памяти есть существенный выигрыш по сравнению с первой функцией. Ну давайте глянем, что там за секрет.
Обратно в каменный век
Все знают, что один из самых производительных способов собрать строку в GO — это простая операция конкатенации. И вот функция построенная на этом простом принципе:
func NewConcatenateConnectionString(proto, host, path, database, user, password string, debug bool) string {
var appendix = "&debug=false"
if debug {
appendix = "&debug=true"
}
return proto + "://" + url.QueryEscape(user) + ":" + url.QueryEscape(password) + "@" + host + path + "?database=" + url.QueryEscape(database) + appendix
}
Ну да, я зачем-то отступил от своего принципа и отправился обратно в каменный век: потерял возможность экранировать path, допустил некоторые деградации в экранировании user и password (там есть разница экранирования с query). В целом выглядит не очень.
Но давайте взглянем правде в лицо. Допустить ошибку при изменении такой функции все-таки сложнее, чем в функции с использованием fmt.Sprintf не смотря на то, что код этой функции выглядит довольно печально.
Давайте попробуем избавиться от уродства этой функции, добавим в нее немного красоты.
func NewConcatenateConnectionString(proto, host, path, database, user, password string, debug bool) string {
var URL strings.Builder
URL.Grow(128)
URL.WriteString(proto + "://")
if user != "" {
URL.WriteString(url.QueryEscape(user) + ":" + url.QueryEscape(password) + "@")
}
URL.WriteString(host + path)
URL.WriteString("?database=" + url.QueryEscape(database))
if debug {
URL.WriteString("&debug=true")
} else {
URL.WriteString("&debug=false")
}
return URL.String()
}
Удалось вернуть немного наглядности и структурированности: мы снова видим параметр напротив значения: URL.WriteString(«?database=» + url.QueryEscape(database)) за сравнительно небольшую плату. Давайте глянем, какую.
Время: 478 ns/op
Память: 272 B/op
Аллокации: 5 allocs/op
Мне кажется, что этот вариант будет слегка поприличнее, чем вариант с fmt.Sprintf. Но давайте разберем, какие у него есть преимущества и недостатки (в сравнении с эталонным).
1 ый минус: Нет возможности обозреть шаблон итогового URL — я имею в виду, что по сравнению с форматной строкой, которая представляет нам хоть и не очень наглядно, но зато целиком весь URL, который мы можем получить, этот случай имеет просто набор некоторых этапов заполнения строки, из которой в итоге возникнет URL. Довольно слабый минус, вряд ли кому-то захочется видеть пример формируемого URL, а если захочется, его можно вложить в комментарии.
2 ой минус: Все параметры необходимо привести к типу данных строка — обратили внимание на то, как пришлось поступить с параметром debug? А представьте, что придется сделать с целочисленными параметрами! Но в любом случае, тут никто не запрещает использовать fmt.Sprintf внутри вызова URL.WriteString. Так что этот минус еще слабее предыдущего.
1 ый плюс: Более гибкая логика. В варианте с простым fmt.Sprintf мы можем транслировать параметры в URL строку как они есть, а это значит, что готовить их нужно до передачи в функцию. В нашем же случае мы можем дополнять функцию какой-то логикой и даже опускать некоторые параметры, как это сделано с user+password.
2 ой плюс: Стоимость доработок. С увеличением кол-ва параметров сложность не изменяется — мы не будем увеличивать длину форматной строки и все большее время тратить на внимание к правильности очередности имен параметров и их значений. А вот это, на мой взгляд, довольно существенный плюс.
Победитель
Ну и раз это номинация, давайте же выберем победителя через нечестное и предвзятое судейство. Оценивать буду по следующим критериям (они соотносятся с проблемами, которые описаны выше и добавим еще производительность):
- логика — возможность сломать URL и сложность обнаружения ошибки;
- сложность изменения — вероятность внесения ошибки при изменении функции;
- гарантии компилятора — возможность обнаружить ошибки на этапе компиляции;
- производительность.
Думаю, что победитель в номинации “худший способ сформировать URL строку в golang” нами обнаружен. Прошу вас, по возможности не используйте этот способ.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
А что вы думаете по этому поводу?
38.16%
всегда использую функции net/url
29
25%
можно аккуратно использовать fmt.Sprintf
19
10.53%
собираю URL конкатенацией используя QueryEscape
8
26.32%
нет разницы, главное, чтобы работало без ошибок
20
Проголосовали 76 пользователей.
Воздержались 28 пользователей.
Пакет url анализирует URL-адреса и реализует экранирование запросов.
Функция PathEscape
func PathEscape(s string) string
PathEscape экранирует строку, чтобы ее можно было безопасно разместить внутри сегмента пути URL, заменяя при необходимости специальные символы (включая /) последовательностями %XX.
Пример использования функции PathEscape
package main
import (
"fmt"
"net/url"
)
func main() {
space := url.PathEscape("one two")
fmt.Println(space)
percent := url.PathEscape("10%")
fmt.Println(percent)
symbols := url.PathEscape(" ?&=#+%!<>#"{}|\^[]`☺t:/@$'()*,;")
fmt.Println(symbols)
}
Вывод:
one%20two
10%25
%20%3F&=%23+%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09:%2F@$%27%28%29%2A%2C%3B
Пример в песочнице https://play.golang.org/p/LNmUJmU8uaq
Функция PathUnescape
func PathUnescape(s string) (string, error)
PathUnescape выполняет обратное преобразование PathEscape, преобразуя каждую 3-байтовую закодированную подстроку формы «%AB» в шестнадцатеричный байт 0xAB. Он возвращает ошибку, если за любым % не следуют две шестнадцатеричные цифры.
PathUnescape идентичен QueryUnescape, за исключением того, что он не отменяет экранирование ‘+’ на ‘ ‘ (пробел).
Пример использования функции PathUnescape
package main
import (
"fmt"
"net/url"
)
func main() {
space, err := url.PathUnescape("one%20two")
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(space)
percent, err := url.PathUnescape("10%25")
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(percent)
symbols, err := url.PathUnescape("%20%3F&=%23+%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09:%2F@$%27%28%29%2A%2C%3B")
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(symbols)
}
Вывод:
one two
10%
?&=#+%!<>#"{}|^[]`☺ :/@$'()*,;
Пример в песочнице https://play.golang.org/p/RevOg4UxSG7
Функция QueryEscape
func QueryEscape(s string) string
QueryEscape экранирует строку, чтобы ее можно было безопасно поместить в URL-запрос.
Пример использования функции QueryEscape
package main
import (
"fmt"
"net/url"
)
func main() {
space := url.QueryEscape("one two")
fmt.Println(space)
percent := url.QueryEscape("10%")
fmt.Println(percent)
symbols := url.QueryEscape(" ?&=#+%!<>#"{}|\^[]`☺t:/@$'()*,;")
fmt.Println(symbols)
}
Вывод:
one+two
10%25
+%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A%2F%40%24%27%28%29%2A%2C%3B
Пример в песочнице https://play.golang.org/p/hfKAuFsV00i
Функция QueryUnescape
func QueryUnescape(s string) (string, error)
QueryUnescape выполняет обратное преобразование QueryEscape, преобразуя каждую 3-байтовую закодированную подстроку формы «%AB» в шестнадцатеричный байт 0xAB. Он возвращает ошибку, если за любым % не следуют две шестнадцатеричные цифры.
Пример использования функции QueryUnescape
package main
import (
"fmt"
"net/url"
)
func main() {
space, err := url.QueryUnescape("one+two")
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(space)
percent, err := url.QueryUnescape("10%25")
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(percent)
symbols, err := url.QueryUnescape("+%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A%2F%40%24%27%28%29%2A%2C%3B")
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(symbols)
}
Вывод:
one two
10%
?&=#+%!<>#"{}|^[]`☺ :/@$'()*,;
Пример в песочнице https://play.golang.org/p/cIDrkclH5Qa
Тип URL
type URL struct {
Scheme string
Opaque string // закодированные непрозрачные данные
User *Userinfo // username и password информация
Host string // host или host:port
Path string // путь (в относительных путях может отсутствовать начальная косая черта)
RawPath string // закодированный путь (EscapedPath)
ForceQuery bool // добавить запрос ('?') даже если RawQuery пуст
RawQuery string // закодированные значения запроса, без '?'
Fragment string // фрагмент для ссылок, без '#'
RawFragment string // закодированный фрагмент (EscapedFragment)
}
URL представляет собой проанализированный URL-адрес (технически ссылка на URI).
Общая форма представленна как:
[scheme:][//[userinfo@]host][/]path[?query][#fragment]
URL-адреса, которые не начинаются с косой черты после схемы, интерпретируются как:
scheme:opaque[?query][#fragment]
Обратите внимание, что поле Path хранится в декодированной форме: /%47%6f%2f становится /Go/. Как следствие, невозможно определить, какие косые черты в пути были косыми чертами в необработанном URL, а какие были %2f. Это различие редко бывает важным, но когда это так, код должен использовать RawPath, необязательное поле, которое устанавливается только в том случае, если кодировка по умолчанию отличается от Path.
Метод URL String использует метод EscapedPath для получения пути.
Пример использования типа URL
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("http://bing.com/search?q=dotnet")
if err != nil {
log.Fatal(err)
}
u.Scheme = "https"
u.Host = "google.com"
q := u.Query()
q.Set("q", "golang")
u.RawQuery = q.Encode()
fmt.Println(u)
}
Вывод
https://google.com/search?q=golang
Пример использования типа URL
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
// Parse + String сохраняют первоначальное кодирование.
u, err := url.Parse("https://example.com/foo%2fbar")
if err != nil {
log.Fatal(err)
}
fmt.Println(u.Path)
fmt.Println(u.RawPath)
fmt.Println(u.String())
}
Вывод
/foo/bar
/foo%2fbar
https://example.com/foo%2fbar
Функция Parse
func Parse(rawURL string) (*URL, error)
Parse анализирует необработанный URL-адрес в структуру URL.
URL-адрес может быть относительным (путь без хоста) или абсолютным (начиная со схемы). Попытка проанализировать имя хоста и путь без схемы недопустима, но может не обязательно возвращать ошибку из-за неоднозначности синтаксического анализа.
Пример использования функции Parse
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("http://bing.com/search?q=dotnet")
if err != nil {
log.Fatal(err)
}
fmt.Println("Scheme: ", u.Scheme)
fmt.Println("Host: ", u.Host)
fmt.Println("Path: ", u.Path)
fmt.Println("RawQuery: ", u.RawQuery)
}
Вывод
Scheme: http
Host: bing.com
Path: /search
RawQuery: q=dotnet
Пример в песочнице https://play.golang.org/p/o5gLj5_fteS
Функция ParseRequestURI
func ParseRequestURI(rawURL string) (*URL, error)
ParseRequestURI анализирует необработанный URL-адрес в структуру URL. Предполагается, что URL-адрес был получен в HTTP-запросе, поэтому URL-адрес интерпретируется только как абсолютный URI или абсолютный путь. Предполагается, что строковый url не имеет суффикса #fragment. (Веб-браузеры удаляют #fragment перед отправкой URL-адреса на веб-сервер.)
Метод EscapedFragment
func (u *URL) EscapedFragment() string
EscapedFragment возвращает экранированную форму u.Fragment. В общем, существует несколько возможных экранированных форм любого фрагмента. EscapedFragment возвращает u.RawFragment, если это допустимое экранирование u.Fragment. В противном случае EscapedFragment игнорирует u.RawFragment и самостоятельно вычисляет экранированную форму. Метод String использует EscapedFragment для построения своего результата. В общем, код должен вызывать EscapedFragment вместо непосредственного чтения u.RawFragment.
Пример использования метода EscapedFragment
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("http://example.com/#x/y%2Fz")
if err != nil {
log.Fatal(err)
}
fmt.Println("Fragment:", u.Fragment)
fmt.Println("RawFragment:", u.RawFragment)
fmt.Println("EscapedFragment:", u.EscapedFragment())
}
Вывод
Fragment: x/y/z
RawFragment: x/y%2Fz
EscapedFragment: x/y%2Fz
Пример в песочнице https://play.golang.org/p/Q-I-8bfoXFO
Метод EscapedPath
func (u *URL) EscapedPath() string
EscapedPath возвращает экранированную форму u.Path. Как правило, у любого пути есть несколько возможных экранированных форм. EscapedPath возвращает u.RawPath, если это действительное экранирование u.Path. В противном случае EscapedPath игнорирует u.RawPath и вычисляет экранированную форму самостоятельно. Методы String и RequestURI используют EscapedPath для построения своих результатов. В общем, код должен вызывать EscapedPath вместо непосредственного чтения u.RawPath.
Пример использования метода EscapedPath
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("http://example.com/x/y%2Fz")
if err != nil {
log.Fatal(err)
}
fmt.Println("Path:", u.Path)
fmt.Println("RawPath:", u.RawPath)
fmt.Println("EscapedPath:", u.EscapedPath())
}
Вывод
Path: /x/y/z
RawPath: /x/y%2Fz
EscapedPath: /x/y%2Fz
Пример в песочнице https://play.golang.org/p/xvc45jZkqq6
Метод Hostname
func (u *URL) Hostname() string
Hostname возвращает u.Host, удаляя любой допустимый номер порта, если он присутствует.
Если результат заключен в квадратные скобки, как буквальные адреса IPv6, квадратные скобки удаляются из результата.
Пример использования метода Hostname
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("https://example.org:8000/path")
if err != nil {
log.Fatal(err)
}
fmt.Println(u.Hostname())
u, err = url.Parse("https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000")
if err != nil {
log.Fatal(err)
}
fmt.Println(u.Hostname())
}
Вывод
example.org
2001:0db8:85a3:0000:0000:8a2e:0370:7334
Пример в песочнице https://play.golang.org/p/0MV8vkqssmO
Метод IsAbs
func (u *URL) IsAbs() bool
IsAbs сообщает, является ли URL абсолютным. Абсолютное означает, что у него непустая схема.
Пример использования метода IsAbs
package main
import (
"fmt"
"net/url"
)
func main() {
u := url.URL{Host: "example.com", Path: "foo"}
fmt.Println(u.IsAbs())
u.Scheme = "http"
fmt.Println(u.IsAbs())
}
Вывод
false
true
Пример в песочнице https://play.golang.org/p/UfOBOdHopyF
Метод MarshalBinary
func (u *URL) MarshalBinary() (text []byte, err error)
Преобразует URL в срез байтов, выдает ошибку если она возникает при преобразовании.
Пример использования метода MarshalBinary
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, _ := url.Parse("https://example.org")
b, err := u.MarshalBinary()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%sn", b)
}
Вывод
https://example.org
Пример в песочнице https://play.golang.org/p/L2uSp9WIN1Y
Метод Parse
func (u *URL) Parse(ref string) (*URL, error)
Parse анализирует URL-адрес в контексте получателя. Предоставленный URL-адрес может быть относительным или абсолютным. Parse возвращает nil, ошибку при сбое синтаксического анализа, в противном случае его возвращаемое значение такое же, как ResolveReference.
Пример использования метода Parse
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("https://example.org")
if err != nil {
log.Fatal(err)
}
rel, err := u.Parse("/foo")
if err != nil {
log.Fatal(err)
}
fmt.Println(rel)
_, err = u.Parse(":foo")
if _, ok := err.(*url.Error); !ok {
log.Fatal(err)
}
}
Вывод
https://example.org/foo
Пример в песочнице https://play.golang.org/p/lyPqaigN1pw
Метод Port
func (u *URL) Port() string
Port возвращает часть порта u.Host без начального двоеточия.
Если u.Host не содержит допустимого числового порта, Port возвращает пустую строку.
Пример использования метода Port
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("https://example.org")
if err != nil {
log.Fatal(err)
}
fmt.Println(u.Port())
u, err = url.Parse("https://example.org:8080")
if err != nil {
log.Fatal(err)
}
fmt.Println(u.Port())
}
Вывод
8080
Пример в песочнице https://play.golang.org/p/xcP1_ozPxfG
Метод Query
func (u *URL) Query() Values
Query анализирует RawQuery и возвращает соответствующие значения. Он молча отбрасывает искаженные пары значений. Для проверки ошибок используйте ParseQuery.
Пример использования метода Query
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("https://example.org/?a=1&a=2&b=&=3&&&&")
if err != nil {
log.Fatal(err)
}
q := u.Query()
fmt.Println(q["a"])
fmt.Println(q.Get("b"))
fmt.Println(q.Get(""))
}
Вывод
[1 2]
3
Пример в песочнице https://play.golang.org/p/MJrTerqSaqd
Метод Redacted
func (u *URL) Redacted() string
Redacted аналогично String, но заменяет любой пароль на «xxxxx». Удаляется только пароль в u.URL.
Пример использования метода Redacted
package main
import (
"fmt"
"net/url"
)
func main() {
u := &url.URL{
Scheme: "https",
User: url.UserPassword("user", "password"),
Host: "example.com",
Path: "foo/bar",
}
fmt.Println(u.Redacted())
u.User = url.UserPassword("me", "newerPassword")
fmt.Println(u.Redacted())
}
Вывод
https://user:xxxxx@example.com/foo/bar
https://me:xxxxx@example.com/foo/bar
Пример в песочнице https://play.golang.org/p/FPsxk_4bbCV
Метод RequestURI
func (u *URL) RequestURI() string
RequestURI возвращает закодированный path?query или opaque?query строку, которая будет использоваться в HTTP-запросе для u.
Пример использования метода RequestURI
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("https://example.org/path?foo=bar")
if err != nil {
log.Fatal(err)
}
fmt.Println(u.RequestURI())
}
Вывод
/path?foo=bar
Пример в песочнице https://play.golang.org/p/QK-lScEgjou
Метод ResolveReference
func (u *URL) ResolveReference(ref *URL) *URL
ResolveReference разрешает ссылку URI на абсолютный URI из абсолютного базового URI u, согласно RFC 3986. Ссылка URI может быть относительной или абсолютной. ResolveReference всегда возвращает новый экземпляр URL, даже если возвращенный URL идентичен базовому или ref. Если ref является абсолютным URL, ResolveReference игнорирует base и возвращает копию ref.
Пример использования метода ResolveReference
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u, err := url.Parse("../../..//search?q=dotnet")
if err != nil {
log.Fatal(err)
}
base, err := url.Parse("http://example.com/directory/")
if err != nil {
log.Fatal(err)
}
fmt.Println(base.ResolveReference(u))
}
Вывод
http://example.com/search?q=dotnet
Пример в песочнице https://play.golang.org/p/WGNUEkswSmY
Метод String
func (u *URL) String() string
String повторно собирает URL в допустимую строку URL-адреса. Общий вид результата — один из:
scheme:opaque?query#fragment
scheme://userinfo@host/path?query#fragment
Если u.Opaque не пусто, String использует первую форму; в противном случае используется вторая форма. Любые символы, отличные от ASCII, в host экранируются. Чтобы получить путь (path), String использует u.EscapedPath().
Во второй форме действуют следующие правила:
- если u.Scheme пуст, scheme: не отображается.
- если u.User равен nil, userinfo@ опускается.
- если u.Host пуст, host/ не указывается.
- если u.Scheme и u.Host пусты, а u.User - nil,
вся часть scheme://userinfo@host/ опускается.
- если u.Host не пуст и u.Path начинается с /,
форма host/path не добавляет свой /.
- если u.RawQuery пуст, ?query опускается.
- если u.Fragment пуст, #fragment опускается.
Пример использования метода String
package main
import (
"fmt"
"net/url"
)
func main() {
u := &url.URL{
Scheme: "https",
User: url.UserPassword("me", "pass"),
Host: "example.com",
Path: "foo/bar",
RawQuery: "x=1&y=2",
Fragment: "anchor",
}
fmt.Println(u.String())
u.Opaque = "opaque"
fmt.Println(u.String())
}
Вывод
https://me:pass@example.com/foo/bar?x=1&y=2#anchor
https:opaque?x=1&y=2#anchor
Пример в песочнице https://play.golang.org/p/trgWI4TlgAP
Метод UnmarshalBinary
func (u *URL) UnmarshalBinary(text []byte) error
Преобразует срез байтов и наполняет поля структуры URL, на которой был вызван. Возвращает ошибку в случае ее возникновения при анализе среза байтов.
Пример использования метода UnmarshalBinary
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
u := &url.URL{}
err := u.UnmarshalBinary([]byte("https://example.org/foo"))
if err != nil {
log.Fatal(err)
}
fmt.Printf("%sn", u)
}
Вывод
https://example.org/foo
Пример в песочнице https://play.golang.org/p/SyeYQ-6_Vy4
Тип Values
type Values map[string][]string
Values сопоставляет строковый ключ со списком значений. Обычно он используется для параметров запроса и значений формы. В отличие от карты http.Header, ключи в карте Values чувствительны к регистру.
Пример использования типа Values
package main
import (
"fmt"
"net/url"
)
func main() {
v := url.Values{}
v.Set("name", "Ava")
v.Add("friend", "Jess")
v.Add("friend", "Sarah")
v.Add("friend", "Zoe")
fmt.Println(v.Encode())
fmt.Println(v.Get("name"))
fmt.Println(v.Get("friend"))
fmt.Println(v["friend"])
fmt.Println(v.Has("name"))
v.Del("name")
fmt.Println(v.Encode())
}
Вывод
friend=Jess&friend=Sarah&friend=Zoe&name=Ava
Ava
Jess
[Jess Sarah Zoe]
true
friend=Jess&friend=Sarah&friend=Zoe
Пример в песочнице https://play.golang.org/p/9Gvyq0Rnlx7
Функция ParseQuery
func ParseQuery(query string) (Values, error)
ParseQuery анализирует строку запроса в кодировке URL и возвращает карту, в которой перечислены значения, указанные для каждого ключа. ParseQuery всегда возвращает ненулевую карту, содержащую все найденные допустимые параметры запроса; err описывает первую обнаруженную ошибку декодирования, если таковая имеется.
Ожидается, что запрос будет списком настроек ключ = значение, разделенных амперсандами. Параметр без знака равенства интерпретируется как ключ, установленный на пустое значение. Параметры, содержащие точку с запятой без кодировки URL, считаются недействительными.
Пример использования функции ParseQuery
package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"strings"
)
func main() {
m, err := url.ParseQuery(`x=1&y=2&y=3`)
if err != nil {
log.Fatal(err)
}
fmt.Println(toJSON(m))
}
func toJSON(m interface{}) string {
js, err := json.Marshal(m)
if err != nil {
log.Fatal(err)
}
return strings.ReplaceAll(string(js), ",", ", ")
}
Вывод
{"x":["1"], "y":["2", "3"]}
Пример в песочнице https://play.golang.org/p/3ytJDMl5P5y
Методы типа Values
func (v Values) Add(key, value string)
Add добавляет значение к ключу. Он добавляется к любым существующим значениям, связанным с ключом.
func (v Values) Del(key string)
Del удаляет значения, связанные с ключом.
func (v Values) Encode() string
Encode кодирует значения в форму «закодированный URL» («bar=baz&foo=quux»), отсортированные по ключу.
func (v Values) Get(key string) string
Get получает первое значение, связанное с данным ключом. Если с ключом не связаны никакие значения, Get возвращает пустую строку. Чтобы получить доступ к нескольким значениям, используйте карту напрямую.
func (v Values) Has(key string) bool
Has проверяет, установлен ли данный ключ.
func (v Values) Set(key, value string)
Set устанавливает значение ключа. Он заменяет любые существующие значения.
Читайте также:
- Веб-приложение на Go: введение в пакет net/http, пример веб-сервера на Go
- Пакет net/http, краткий обзор
- Разработка RESTful API с помощью Go и Gin
- Функции пакета net/http, примеры
Канал в Телеграм
import "net/url"
- Overview
- Index
- Examples
Overview
Пакет url разбирает URL и реализует экранирование запросов.
Index
- func JoinPath (базовая строка, элемент … строка) (строка результата, ошибка ошибки)
- включить строку PathEscape(s string)
- func PathUnescape(s string)(строка,ошибка)
- строка функционала QueryEscape(s string)
- funceryUnescape(s string)(строка,ошибка)
- type Error
- функция (и *Error)Error()строка
- функция (e *Error)Temporary()bool
- func (e *Error) Timeout() bool
- ошибка Unwrap()func (e *Error)Unwrap()error
- type EscapeError
- строка Error()func (и EscapeError)Error()
- type InvalidHostError
- строка Error()func (и InvalidHostError)
- type URL
- func Parse(rawURL string) (*URL, error)
- func ParseRequestURI(rawURL string) (*URL, error)
- func (u *URL) EscapedFragment() string
- функция (u *URL)EscapedPath()строка
- func (u *URL) Hostname() string
- функционал (u *URL)IsAbs()bool
- func (u *URL) JoinPath(elem …string) *URL
- func (u *URL)MarshalBinary()(text []byte,error)
- func (u *URL)Parse(ref string)(*URL,ошибка)
- func (u *URL) Port() string
- func (u *URL) Query() Values
- func (u *URL) Redacted() string
- func (u *URL) RequestURI() string
- func (u *URL) ResolveReference(ref *URL) *URL
- func (u *URL) String() string
- func (u *URL)UnmarshalBinary(text []byte)ошибка
- type Userinfo
- включить опцию User(username string)*Userinfo
- включить UserPassword(имя пользователя,строка пароля)*Userinfo
- func (u *Userinfo) Password() (string, bool)
- func (u *Userinfo)String()строка
- func (u *Userinfo) Username() string
- type Values
- включить ParseQuery (строка запроса)(Значения,ошибка)
- func (v Values) Add(key, value string)
- func (v Values)Del(строка ключа)
- func (v Values) Encode() string
- func (v Values) Get(key string) string
- func (v Values) Has(key string) bool
- func (v Values) Set(key, value string)
Package files
url.go
func JoinPath1.19
func JoinPath(base string, elem ...string) (result string, err error)
JoinPath возвращает строку URL-адреса с предоставленными элементами пути, присоединенными к существующему пути базы, и полученный путь очищен от любых элементов ./ или ../.
func PathEscape1.8
func PathEscape(s string) string
PathEscape экранирует строку,чтобы ее можно было безопасно разместить внутри сегмента пути URL,заменяя специальные символы (включая /)на последовательности %XX по мере необходимости.
Example
Code:
path := url.PathEscape("my/cool+blog&about,stuff") fmt.Println(path)
Output:
my%2Fcool+blog&about%2Cstuff
func PathUnescape1.8
func PathUnescape(s string) (string, error)
PathUnescape выполняет обратное преобразование PathEscape,преобразуя каждую 3-байтовую закодированную подстроку формы «%AB» в шестнадцатеричный дешифрованный байт 0xAB.Возвращает ошибку,если за любым % не следуют две шестнадцатеричные цифры.
PathUnescape идентичен QueryUnescape за исключением того,что он не отбрасывает символ ‘+’ к » (пробел).
Example
Code:
escapedPath := "my%2Fcool+blog&about%2Cstuff" path, err := url.PathUnescape(escapedPath) if err != nil { log.Fatal(err) } fmt.Println(path)
Output:
my/cool+blog&about,stuff
func QueryEscape
func QueryEscape(s string) string
QueryEscape экранирует строку,чтобы ее можно было безопасно поместить внутри URL запроса.
Example
Code:
query := url.QueryEscape("my/cool+blog&about,stuff") fmt.Println(query)
Output:
my%2Fcool%2Bblog%26about%2Cstuff
func QueryUnescape
func QueryUnescape(s string) (string, error)
QueryUnescape выполняет обратное преобразование QueryEscape,преобразуя каждую 3-байтовую закодированную подстроку формы «%AB» в шестнадцатеричный дешифрованный байт 0xAB.Возвращает ошибку,если за любым % не следуют две шестнадцатеричные цифры.
Example
Code:
escapedQuery := "my%2Fcool%2Bblog%26about%2Cstuff" query, err := url.QueryUnescape(escapedQuery) if err != nil { log.Fatal(err) } fmt.Println(query)
Output:
my/cool+blog&about,stuff
type Error
Ошибка сообщает об ошибке,а также о вызвавшей ее операции и URL-адресе.
type Error struct { Op string URL string Err error }
func (*Error) Error
func (e *Error) Error() string
func (*Error) Temporary1.6
func (e *Error) Temporary() bool
func (*Ошибка)Таймаут1.6
func (e *Error) Timeout() bool
func (*Error) Unwrap1.13
func (e *Error) Unwrap() error
type EscapeError
type EscapeError string
func (EscapeError)Ошибка
func (e EscapeError) Error() string
type InvalidHostError1.6
type InvalidHostError string
func (InvalidHostError) Error1.6
func (e InvalidHostError) Error() string
type URL
URL представляет собой разобранный URL (технически-ссылка на URI).
Представлена общая форма:
[scheme:][//[userinfo@]host][/]path[?query][#fragment]
URL,которые не начинаются со слеша после схемы,интерпретируются как:
scheme:opaque[?query][
Обратите внимание,что поле Path хранится в декодированном виде:/%47%6f%2f становится /Go/.Следствием этого является то,что невозможно определить,какие слэши в Path были слэшами в исходном URL,а какие-%2f.Это различие редко важно,но когда оно есть,код должен использовать RawPath,необязательное поле,которое устанавливается только в том случае,если кодировка по умолчанию отличается от Path.
Метод URL String использует метод EscapedPath для получения пути.См.подробнее метод EscapedPath.
type URL struct { Scheme string Opaque string User *Userinfo Host string Path string RawPath string OmitHost bool ForceQuery bool RawQuery string Fragment string RawFragment string }
Example
Code:
u, err := url.Parse("http://bing.com/search?q=dotnet") if err != nil { log.Fatal(err) } u.Scheme = "https" u.Host = "google.com" q := u.Query() q.Set("q", "golang") u.RawQuery = q.Encode() fmt.Println(u)
Output:
https://google.com/search?q=golang
Example (Roundtrip)
Code:
u, err := url.Parse("https://example.com/foo%2fbar") if err != nil { log.Fatal(err) } fmt.Println(u.Path) fmt.Println(u.RawPath) fmt.Println(u.String())
Output:
/foo/bar /foo%2fbar https://example.com/foo%2fbar
func Parse
func Parse(rawURL string) (*URL, error)
Parse разбирает необработанный url в структуру URL.
url может быть относительным (путь без имени хоста)или абсолютным (начинающимся со схемы).Попытка разобрать имя хоста и путь без схемы является недействительной,но не обязательно вернет ошибку из-за неоднозначности разбора.
func ParseRequestURI
func ParseRequestURI(rawURL string) (*URL, error)
ParseRequestURI анализирует необработанный url в структуру URL.Предполагается,что url был получен в HTTP-запросе,поэтому url интерпретируется только как абсолютный URI или абсолютный путь.Предполагается,что строка url не содержит суффикса #fragment.(Веб-браузеры удаляют #fragment перед отправкой URL на веб-сервер).
func (*URL) EscapedFragment1.15
func (u *URL) EscapedFragment() string
EscapedFragment возвращает экранированную форму u.Fragment.В общем случае существует несколько возможных экранированных форм любого фрагмента.EscapedFragment возвращает u.RawFragment,если он является допустимой эскейп-формой u.Fragment.В противном случае EscapedFragment игнорирует u.RawFragment и вычисляет экранированную форму самостоятельно.Метод String использует EscapedFragment для построения своего результата.В общем случае код должен вызывать EscapedFragment вместо того,чтобы читать u.RawFragment напрямую.
Example
Code:
u, err := url.Parse("http://example.com/#x/y%2Fz") if err != nil { log.Fatal(err) } fmt.Println("Fragment:", u.Fragment) fmt.Println("RawFragment:", u.RawFragment) fmt.Println("EscapedFragment:", u.EscapedFragment())
Output:
Fragment: x/y/z RawFragment: x/y%2Fz EscapedFragment: x/y%2Fz
func (*URL) EscapedPath1.5
func (u *URL) EscapedPath() string
EscapedPath возвращает сбежавшую форму u.Path.В общем,существует несколько возможных экзекутивных форм любого пути.EscapedPath возвращает u.RawPath,когда он является действительным экранированием u.Path.В противном случае EscapedPath игнорирует u.RawPath и самостоятельно вычисляет экранированную форму.Методы String и RequestURI используют EscapedPath для построения своих результатов.В общем случае,код должен вызывать EscapedPath вместо того,чтобы читать u.RawPath напрямую.
Example
Code:
u, err := url.Parse("http://example.com/x/y%2Fz") if err != nil { log.Fatal(err) } fmt.Println("Path:", u.Path) fmt.Println("RawPath:", u.RawPath) fmt.Println("EscapedPath:", u.EscapedPath())
Output:
Path: /x/y/z RawPath: /x/y%2Fz EscapedPath: /x/y%2Fz
© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/net/url/
Go
1.19
-
Package smtp
-
Package textproto
-
func (*URL) Hostname 1.8
-
Package exec