PuerkitoBio/purell
GitHub: PuerkitoBio/purell
Purell 是一个基于 Go 的轻量级 URL 规范化库,通过灵活的标志位组合将 URL 转换为统一的纯净格式。
Stars: 485 | Forks: 61
# Purell
Purell 是一个小巧的 Go 库,用于规范化 URL。它返回一个纯净的 URL。Pure-ell(纯净)。就像净化器一样。是的,我知道……
基于 [维基百科文章][wiki] 和 [RFC 3986 文档][rfc]。
[](https://github.com/PuerkitoBio/purell/actions/workflows/ci.yml)
## 安装
`go get github.com/PuerkitoBio/purell`
## 更新日志
* **2026-05-17 (v1.2.2)** :修复了由于 CVE-2025-47912 引入的更严格的 IPv6 主机验证而导致的 Go 1.24.8+ 测试失败问题(感谢 @syedazeez337),并为 GitHub Actions 引入了 zizmor 检查。
* **2023-10-22 (v1.2.1)** :修复了主机名部分之间多余点的 `FlagRemoveUnnecessaryHostDots` 问题(感谢 @michael-peterson-cisco),并升级了依赖项。
* **2022-08-17 (v1.2.0)** :迁移至 Go modules,将 CI 移至 GitHub Actions,内联了来自 urlesc 的 URL 转义支持,并在 Go 1.19 上运行 CI。
* **v1.1.1** :修复了由于 Go1.12 更改导致的测试失败问题(感谢 @ianlancetaylor)。
* **2016-11-14 (v1.1.0)** :IDN:符合 RFC 5895:折叠字符宽度(感谢 @beeker1121)。
* **2016-07-27 (v1.0.0)** :将 IDN 规范化为 ASCII(感谢 @zenovich)。
* **2015-02-08** :添加了对相对路径问题的修复([PR #5][pr5]),并添加了对保留字符不必要编码的修复([参见 issue #7][iss7])。
* **v0.2.0** :添加了基准测试,尝试支持 IDN。
* **v0.1.0** :初始版本。
## 示例
摘自 `example_test.go`(请注意,在你的代码中,你需要导入 "github.com/PuerkitoBio/purell",并且在引用其方法和常量时需要加上 "purell." 前缀):
```
package purell
import (
"fmt"
"net/url"
)
func ExampleNormalizeURLString() {
if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
panic(err)
} else {
fmt.Print(normalized)
}
// Output: http://somewebsite.com:80/Amazing%3F/url/
}
func ExampleMustNormalizeURLString() {
normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
FlagsUnsafeGreedy)
fmt.Print(normalized)
// Output: http://somewebsite.com/Amazing%FA/url
}
func ExampleNormalizeURL() {
if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
panic(err)
} else {
normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
fmt.Print(normalized)
}
// Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
}
```
## API
正如上方示例所示,purell 提供了三个方法:`NormalizeURLString(string, NormalizationFlags) (string, error)`、`MustNormalizeURLString(string, NormalizationFlags) (string)` 和 `NormalizeURL(*url.URL, NormalizationFlags) (string)`。它们都会根据指定的标志位对提供的 URL 进行规范化。以下是可用的标志位:
```
const (
// Safe normalizations
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
FlagLowercaseHost // http://HOST -> http://host
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
FlagRemoveDefaultPort // http://host:80 -> http://host
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
// Usually safe normalizations
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)
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
// Unsafe normalizations
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
FlagRemoveFragment // http://host/path#fragment -> http://host/path
FlagForceHTTP // https://host -> http://host
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
FlagRemoveWWW // http://www.host/ -> http://host/
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
// Normalizations not in the wikipedia article, required to cover tests cases
// submitted by jehiah
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
// Convenience set of safe normalizations
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
// 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".
// Convenience set of usually safe normalizations (includes FlagsSafe)
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
// Convenience set of all available flags
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
)
```
为了方便起见,提供了 `FlagsSafe`、`FlagsUsuallySafe[Greedy|NonGreedy]`、`FlagsUnsafe[Greedy|NonGreedy]` 和 `FlagsAll[Greedy|NonGreedy]` 标志集,用于在 [维基百科的 URL 规范化页面][wiki] 上进行类似的分组规范化。如果需要,你可以从这些集合中添加(使用按位或 `|` 运算符)或移除(使用按位与非 `&^` 运算符)单个标志,以构建你自己的自定义集合。
[完整的 godoc 参考文档可在 gopkgdoc 上找到][godoc]。
需要注意的一些事项:
* `FlagDecodeUnnecessaryEscapes`、`FlagEncodeNecessaryEscapes`、`FlagUppercaseEscapes` 和 `FlagRemoveEmptyQuerySeparator` 总是会被隐式设置,因为在内部,URL 字符串会被解析为 URL 对象,该对象会自动解码不必要的转义,将必要的转义大写并编码,并移除空的查询分隔符(位于 URL 末尾不必要的 `?`)。因此,这个操作**必然**会执行。出于这个原因,`FlagRemoveEmptyQuerySeparator`(以及其他三个)已被包含在 `FlagsSafe` 便捷集合中,而不是维基百科所放置的 `FlagsUnsafe` 中。
* `FlagDecodeUnnecessaryEscapes` 会解码以下转义字符(*从 -> 至*):
- %24 -> $
- %26 -> &
- %2B-%3B -> +,-./0123456789:;
- %3D -> =
- %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
- %5F -> _
- %61-%7A -> abcdefghijklmnopqrstuvwxyz
- %7E -> ~
* 当使用 `NormalizeURL` 函数时(传入一个 URL 对象),该源 URL 对象会被修改(也就是说,调用之后,URL 对象将被修改以反映规范化后的结果)。
* *将 IP 替换为域名*的规范化(`http://208.77.188.166/ → http://www.example.com/`)在不发起网络请求的情况下,对于库来说显然是无法实现的。这在 purell 中未实现。
* *移除未使用的查询字符串参数*和*移除默认查询参数*也未实现,因为这是一种非常特定于具体场景的规范化,而且使用 URL 对象来执行此操作非常简单。
### 安全 与 通常安全 与 不安全 的对比
Purell 允许你控制在规范化 URL 时所承担的风险级别。你可以激进地进行规范化,也可以采取完全安全的策略,或者介于两者之间。
考虑以下 URL:
`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
使用 `FlagsSafe` 进行规范化会得到:
`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
使用 `FlagsUsuallySafeGreedy` 会得到:
`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
而使用 `FlagsUnsafeGreedy` 会得到:
`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
## 待办事项
* 添加一个类/默认实例以允许指定自定义的目录索引名称?目前,移除目录索引会移除 `(^|/)((?:default|index)\.\w{1,4})$`。
## 致谢 / 贡献
请参阅 。
## 许可证
采用 [BSD 3-Clause 许可证][bsd]。
标签:EVTX分析, Go, Ruby工具, Syscall, URL规范化, URL解析, Web开发, 开发工具库, 日志审计