Commit f8918c0c authored by ale's avatar ale
Browse files

Merge branch 'renovate/github.com-puerkitobio-purell-0.x' into 'master'

Update module github.com/PuerkitoBio/purell to v0.1.0

See merge request !4
parents d82bb811 d22a0f91
Pipeline #17439 passed with stages
in 1 minute and 16 seconds
...@@ -4,7 +4,7 @@ go 1.15 ...@@ -4,7 +4,7 @@ go 1.15
require ( require (
github.com/PuerkitoBio/goquery v1.5.0 github.com/PuerkitoBio/goquery v1.5.0
github.com/PuerkitoBio/purell v0.0.0-20180310210909-975f53781597 github.com/PuerkitoBio/purell v0.1.0
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/google/go-cmp v0.3.1 github.com/google/go-cmp v0.3.1
github.com/google/uuid v1.1.1 // indirect github.com/google/uuid v1.1.1 // indirect
......
...@@ -2,6 +2,8 @@ github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP ...@@ -2,6 +2,8 @@ github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/purell v0.0.0-20180310210909-975f53781597 h1:1H3FyRw7YsqIty9WHPOVEGJaFJ1sfGVZ3PPDUw3ob2w= github.com/PuerkitoBio/purell v0.0.0-20180310210909-975f53781597 h1:1H3FyRw7YsqIty9WHPOVEGJaFJ1sfGVZ3PPDUw3ob2w=
github.com/PuerkitoBio/purell v0.0.0-20180310210909-975f53781597/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v0.0.0-20180310210909-975f53781597/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v0.1.0 h1:N8Bcc53nei5frgNYgAKo93qMUVdU5LUGHCBv8efdVcM=
github.com/PuerkitoBio/purell v0.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
......
*.sublime-* *.sublime-*
.DS_Store .DS_Store
*.swp
*.swo
tags
language: go language: go
go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- "1.10.x"
- tip
...@@ -4,20 +4,12 @@ Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. ...@@ -4,20 +4,12 @@ Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell.
Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc]. Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
[![build status](https://travis-ci.org/PuerkitoBio/purell.svg?branch=master)](http://travis-ci.org/PuerkitoBio/purell) [![build status](https://secure.travis-ci.org/PuerkitoBio/purell.png)](http://travis-ci.org/PuerkitoBio/purell)
## Install ## Install
`go get github.com/PuerkitoBio/purell` `go get github.com/PuerkitoBio/purell`
## Changelog
* **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121).
* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
* **v0.2.0** : Add benchmarks, Attempt IDN support.
* **v0.1.0** : Initial release.
## Examples ## Examples
From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."): From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
...@@ -66,54 +58,53 @@ As seen in the examples above, purell offers three methods, `NormalizeURLString( ...@@ -66,54 +58,53 @@ As seen in the examples above, purell offers three methods, `NormalizeURLString(
```go ```go
const ( const (
// Safe normalizations // Safe normalizations
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1 FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host
FlagLowercaseHost // http://HOST -> http://host FlagLowercaseHost // http://HOST -> http://host
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$ FlagRemoveDefaultPort // http://host:80 -> http://host
FlagRemoveDefaultPort // http://host:80 -> http://host FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
// Usually safe normalizations
// Usually safe normalizations FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags) FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
// Unsafe normalizations
// Unsafe normalizations FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/ FlagRemoveFragment // http://host/path#fragment -> http://host/path
FlagRemoveFragment // http://host/path#fragment -> http://host/path FlagForceHTTP // https://host -> http://host
FlagForceHTTP // https://host -> http://host FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b FlagRemoveWWW // http://www.host/ -> http://host/
FlagRemoveWWW // http://www.host/ -> http://host/ FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags) FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
// Normalizations not in the wikipedia article, required to cover tests cases
// Normalizations not in the wikipedia article, required to cover tests cases // submitted by jehiah
// submitted by jehiah FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147 FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147 FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147 FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
// Convenience set of safe normalizations
// Convenience set of safe normalizations FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags, // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
// Convenience set of usually safe normalizations (includes FlagsSafe)
// Convenience set of usually safe normalizations (includes FlagsSafe) FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe) FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
// Convenience set of all available flags
// Convenience set of all available flags FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
) )
``` ```
...@@ -123,7 +114,7 @@ The [full godoc reference is available on gopkgdoc][godoc]. ...@@ -123,7 +114,7 @@ The [full godoc reference is available on gopkgdoc][godoc].
Some things to note: Some things to note:
* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it. * `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it (strangely?).
* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*): * The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
- %24 -> $ - %24 -> $
...@@ -134,6 +125,7 @@ Some things to note: ...@@ -134,6 +125,7 @@ Some things to note:
- %5F -> _ - %5F -> _
- %61-%7A -> abcdefghijklmnopqrstuvwxyz - %61-%7A -> abcdefghijklmnopqrstuvwxyz
- %7E -> ~ - %7E -> ~
- When the test runs on Travis-ci, it fails because more escapes are decoded than on my machine, so it is either machine/OS-dependent or it is because they run a different Go version (**which they do, they run go1 while I run go1.0.2** so this is very likely the cause). To avoid a failing build banner on GitHub, I commented-out these specific tests (`TestDecodeUnnecessaryEscapesAll()`, `TestEncodeNecessaryEscapesAll()`, `TestGoVersion()`).
* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization). * When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
...@@ -164,16 +156,13 @@ And with `FlagsUnsafeGreedy`: ...@@ -164,16 +156,13 @@ And with `FlagsUnsafeGreedy`:
## TODOs ## TODOs
* Try to make jehiah's tests pass (more exactly, support IDNA domains/utf8/unicode encoding/escaping). For now theses tests are commented out.
* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`. * Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
## Thanks / Contributions ## Thanks / Contributions
@rogpeppe @rogpeppe
@jehiah @jehiah
@opennota
@pchristopher1275
@zenovich
@beeker1121
## License ## License
...@@ -182,6 +171,4 @@ The [BSD 3-Clause license][bsd]. ...@@ -182,6 +171,4 @@ The [BSD 3-Clause license][bsd].
[bsd]: http://opensource.org/licenses/BSD-3-Clause [bsd]: http://opensource.org/licenses/BSD-3-Clause
[wiki]: http://en.wikipedia.org/wiki/URL_normalization [wiki]: http://en.wikipedia.org/wiki/URL_normalization
[rfc]: http://tools.ietf.org/html/rfc3986#section-6 [rfc]: http://tools.ietf.org/html/rfc3986#section-6
[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell [godoc]: http://go.pkgdoc.org/github.com/puerkitobio/purell
[pr5]: https://github.com/PuerkitoBio/purell/pull/5
[iss7]: https://github.com/PuerkitoBio/purell/issues/7
...@@ -12,11 +12,6 @@ import ( ...@@ -12,11 +12,6 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"github.com/PuerkitoBio/urlesc"
"golang.org/x/net/idna"
"golang.org/x/text/unicode/norm"
"golang.org/x/text/width"
) )
// A set of normalization flags determines how a URL will // A set of normalization flags determines how a URL will
...@@ -25,7 +20,7 @@ type NormalizationFlags uint ...@@ -25,7 +20,7 @@ type NormalizationFlags uint
const ( const (
// Safe normalizations // Safe normalizations
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1 FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host
FlagLowercaseHost // http://HOST -> http://host FlagLowercaseHost // http://HOST -> http://host
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
...@@ -140,36 +135,23 @@ var flags = map[NormalizationFlags]func(*url.URL){ ...@@ -140,36 +135,23 @@ var flags = map[NormalizationFlags]func(*url.URL){
// MustNormalizeURLString returns the normalized string, and panics if an error occurs. // MustNormalizeURLString returns the normalized string, and panics if an error occurs.
// It takes an URL string as input, as well as the normalization flags. // It takes an URL string as input, as well as the normalization flags.
func MustNormalizeURLString(u string, f NormalizationFlags) string { func MustNormalizeURLString(u string, f NormalizationFlags) string {
result, e := NormalizeURLString(u, f) if parsed, e := url.Parse(u); e != nil {
if e != nil {
panic(e) panic(e)
} else {
return NormalizeURL(parsed, f)
} }
return result panic("Unreachable code.")
} }
// NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object. // NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object.
// It takes an URL string as input, as well as the normalization flags. // It takes an URL string as input, as well as the normalization flags.
func NormalizeURLString(u string, f NormalizationFlags) (string, error) { func NormalizeURLString(u string, f NormalizationFlags) (string, error) {
parsed, err := url.Parse(u) if parsed, e := url.Parse(u); e != nil {
if err != nil { return "", e
return "", err } else {
} return NormalizeURL(parsed, f), nil
if f&FlagLowercaseHost == FlagLowercaseHost {
parsed.Host = strings.ToLower(parsed.Host)
} }
panic("Unreachable code.")
// The idna package doesn't fully conform to RFC 5895
// (https://tools.ietf.org/html/rfc5895), so we do it here.
// Taken from Go 1.8 cycle source, courtesy of bradfitz.
// TODO: Remove when (if?) idna package conforms to RFC 5895.
parsed.Host = width.Fold.String(parsed.Host)
parsed.Host = norm.NFC.String(parsed.Host)
if parsed.Host, err = idna.ToASCII(parsed.Host); err != nil {
return "", err
}
return NormalizeURL(parsed, f), nil
} }
// NormalizeURL returns the normalized string. // NormalizeURL returns the normalized string.
...@@ -180,7 +162,7 @@ func NormalizeURL(u *url.URL, f NormalizationFlags) string { ...@@ -180,7 +162,7 @@ func NormalizeURL(u *url.URL, f NormalizationFlags) string {
flags[k](u) flags[k](u)
} }
} }
return urlesc.Escape(u) return u.String()
} }
func lowercaseScheme(u *url.URL) { func lowercaseScheme(u *url.URL) {
...@@ -208,26 +190,18 @@ func removeDefaultPort(u *url.URL) { ...@@ -208,26 +190,18 @@ func removeDefaultPort(u *url.URL) {
} }
func removeTrailingSlash(u *url.URL) { func removeTrailingSlash(u *url.URL) {
if l := len(u.Path); l > 0 { if l := len(u.Path); l > 0 && strings.HasSuffix(u.Path, "/") {
if strings.HasSuffix(u.Path, "/") { u.Path = u.Path[:l-1]
u.Path = u.Path[:l-1] } else if l = len(u.Host); l > 0 && strings.HasSuffix(u.Host, "/") {
} u.Host = u.Host[:l-1]
} else if l = len(u.Host); l > 0 {
if strings.HasSuffix(u.Host, "/") {
u.Host = u.Host[:l-1]
}
} }
} }
func addTrailingSlash(u *url.URL) { func addTrailingSlash(u *url.URL) {
if l := len(u.Path); l > 0 { if l := len(u.Path); l > 0 && !strings.HasSuffix(u.Path, "/") {
if !strings.HasSuffix(u.Path, "/") { u.Path += "/"
u.Path += "/" } else if l = len(u.Host); l > 0 && !strings.HasSuffix(u.Host, "/") {
} u.Host += "/"
} else if l = len(u.Host); l > 0 {
if !strings.HasSuffix(u.Host, "/") {
u.Host += "/"
}
} }
} }
...@@ -249,7 +223,7 @@ func removeDotSegments(u *url.URL) { ...@@ -249,7 +223,7 @@ func removeDotSegments(u *url.URL) {
} }
// Special case if host does not end with / and new path does not begin with / // Special case if host does not end with / and new path does not begin with /
u.Path = strings.Join(dotFree, "/") u.Path = strings.Join(dotFree, "/")
if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") { if !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") {
u.Path = "/" + u.Path u.Path = "/" + u.Path
} }
// Special case if the last segment was a dot, make sure the path ends with a slash // Special case if the last segment was a dot, make sure the path ends with a slash
...@@ -299,7 +273,7 @@ func sortQuery(u *url.URL) { ...@@ -299,7 +273,7 @@ func sortQuery(u *url.URL) {
if len(q) > 0 { if len(q) > 0 {
arKeys := make([]string, len(q)) arKeys := make([]string, len(q))
i := 0 i := 0
for k := range q { for k, _ := range q {
arKeys[i] = k arKeys[i] = k
i++ i++
} }
...@@ -311,7 +285,7 @@ func sortQuery(u *url.URL) { ...@@ -311,7 +285,7 @@ func sortQuery(u *url.URL) {
if buf.Len() > 0 { if buf.Len() > 0 {
buf.WriteRune('&') buf.WriteRune('&')
} }
buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v))) buf.WriteString(fmt.Sprintf("%s=%s", k, url.QueryEscape(v)))
} }
} }
......
language: go
go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- tip
install:
- go build .
script:
- go test -v
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
urlesc [![Build Status](https://travis-ci.org/PuerkitoBio/urlesc.svg?branch=master)](https://travis-ci.org/PuerkitoBio/urlesc) [![GoDoc](http://godoc.org/github.com/PuerkitoBio/urlesc?status.svg)](http://godoc.org/github.com/PuerkitoBio/urlesc)
======
Package urlesc implements query escaping as per RFC 3986.
It contains some parts of the net/url package, modified so as to allow
some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)).
## Install
go get github.com/PuerkitoBio/urlesc
## License
Go license (BSD-3-Clause)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package urlesc implements query escaping as per RFC 3986.
// It contains some parts of the net/url package, modified so as to allow
// some reserved characters incorrectly escaped by net/url.
// See https://github.com/golang/go/issues/5684
package urlesc
import (
"bytes"
"net/url"
"strings"
)
type encoding int
const (
encodePath encoding = 1 + iota
encodeUserPassword
encodeQueryComponent
encodeFragment
)
// Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 3986.
func shouldEscape(c byte, mode encoding) bool {
// §2.3 Unreserved characters (alphanum)
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
return false
}
switch c {
case '-', '.', '_', '~': // §2.3 Unreserved characters (mark)
return false
// §2.2 Reserved characters (reserved)
case ':', '/', '?', '#', '[', ']', '@', // gen-delims
'!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims
// Different sections of the URL allow a few of
// the reserved characters to appear unescaped.
switch mode {
case encodePath: // §3.3
// The RFC allows sub-delims and : @.
// '/', '[' and ']' can be used to assign meaning to individual path
// segments. This package only manipulates the path as a whole,
// so we allow those as well. That leaves only ? and # to escape.
return c == '?' || c == '#'
case encodeUserPassword: // §3.2.1
// The RFC allows : and sub-delims in
// userinfo. The parsing of userinfo treats ':' as special so we must escape
// all the gen-delims.
return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
case encodeQueryComponent: // §3.4
// The RFC allows / and ?.
return c != '/' && c != '?'
case encodeFragment: // §4.1
// The RFC text is silent but the grammar allows
// everything, so escape nothing but #
return c == '#'
}
}
// Everything else must be escaped.
return true
}
// QueryEscape escapes the string so it can be safely placed
// inside a URL query.
func QueryEscape(s string) string {
return escape(s, encodeQueryComponent)
}
func escape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
c := s[i]
if shouldEscape(c, mode) {
if c == ' ' && mode == encodeQueryComponent {
spaceCount++
} else {
hexCount++
}
}
}
if spaceCount == 0 && hexCount == 0 {
return s
}
t := make([]byte, len(s)+2*hexCount)
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
case c == ' ' && mode == encodeQueryComponent:
t[j] = '+'
j++
case shouldEscape(c, mode):
t[j] = '%'
t[j+1] = "0123456789ABCDEF"[c>>4]
t[j+2] = "0123456789ABCDEF"[c&15]
j += 3
default:
t[j] = s[i]
j++
}
}
return string(t)