Files
2026-10-26 14:15:10 +08:00

89 lines
2.1 KiB
Go

package util
import (
"net/url"
"regexp"
"strings"
)
// Match url with pattern by chrome extension match pattern style.
// Magnet URI patterns such as magnet:?* are also supported, with * as a wildcard.
// https://developer.chrome.com/docs/extensions/mv3/match_patterns/
func Match(pattern string, u string) bool {
url, err := url.Parse(u)
if err != nil {
return false
}
// Magnet URIs have no authority or path; match the raw scheme-specific
// part instead, preserving query punctuation and percent-encoding.
if strings.HasPrefix(pattern, "magnet:") && !strings.HasPrefix(pattern, "magnet://") {
if url.Scheme != "magnet" {
return false
}
_, target, _ := strings.Cut(u, ":")
expression := regexp.QuoteMeta(strings.TrimPrefix(pattern, "magnet:"))
expression = strings.ReplaceAll(expression, `\*`, ".*")
matched, _ := regexp.MatchString("^"+expression+"$", target)
return matched
}
scheme, host, path := parsePattern(pattern)
if scheme != "*" && scheme != url.Scheme {
return false
}
if !matchHost(host, url.Hostname()) {
return false
}
if !matchPath(path, url.Path) {
return false
}
return true
}
func parsePattern(pattern string) (scheme string, host string, path string) {
parts := strings.Split(pattern, "://")
if len(parts) == 2 {
scheme = parts[0]
pattern = parts[1]
} else {
scheme = ""
}
parts = strings.SplitN(pattern, "/", 2)
if len(parts) == 2 {
host = parts[0]
path = "/" + parts[1]
} else {
host = pattern
path = "/"
}
return
}
func matchHost(pattern string, host string) bool {
if pattern == "*" {
return true
}
if strings.HasPrefix(pattern, "*.") {
return strings.HasSuffix(host, pattern[1:])
}
return pattern == host
}
func matchPath(pattern string, path string) bool {
if pattern == "*" {
return true
}
if !strings.HasSuffix(pattern, "*") && !strings.HasSuffix(pattern, "/") {
pattern += "/"
}
if !strings.HasSuffix(path, "/") {
path += "/"
}
if strings.Contains(pattern, "*") {
pattern = strings.Replace(pattern, "*", ".*", -1)
matched, _ := regexp.MatchString("^"+pattern+"$", path)
return matched
}
return pattern == path
}