func (m MatchPath) Match(r *http.Request) bool {
	// PathUnescape returns an error if the escapes aren't
	// well-formed, meaning the count % matches the RFC.
	// Return early if the escape is improper.
	unescapedPath, err := url.PathUnescape(r.URL.Path)
	if err != nil {
		return false
	}

	lowerPath := strings.ToLower(unescapedPath)

	// Clean the path, merges doubled slashes, etc.
	// This ensures maliciously crafted requests can't bypass
	// the path matcher. See #4407
	lowerPath = path.Clean(lowerPath)

	// see #2917; Windows ignores trailing dots and spaces
	// when accessing files (sigh), potentially causing a
	// security risk (cry) if PHP files end up being served
	// as static files, exposing the source code, instead of
	// being matched by *.php to be treated as PHP scripts
	lowerPath = strings.TrimRight(lowerPath, ". ")

	// Cleaning may remove the trailing slash, but we want to keep it
	if lowerPath != "/" && strings.HasSuffix(r.URL.Path, "/") {
		lowerPath = lowerPath + "/"
	}

	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)

	for _, matchPath := range m {
		matchPath = repl.ReplaceAll(matchPath, "")

		// special case: whole path is wildcard; this is unnecessary
		// as it matches all requests, which is the same as no matcher
		if matchPath == "*" {
			return true
		}

		// special case: first and last characters are wildcard,
		// treat it as a fast substring match
		if len(matchPath) > 1 &&
			strings.HasPrefix(matchPath, "*") &&
			strings.HasSuffix(matchPath, "*") {
			if strings.Contains(lowerPath, matchPath[1:len(matchPath)-1]) {
				return true
			}
			continue
		}

		// special case: first character is a wildcard,
		// treat it as a fast suffix match
		if strings.HasPrefix(matchPath, "*") {
			if strings.HasSuffix(lowerPath, matchPath[1:]) {
				return true
			}
			continue
		}

		// special case: last character is a wildcard,
		// treat it as a fast prefix match
		if strings.HasSuffix(matchPath, "*") {
			if strings.HasPrefix(lowerPath, matchPath[:len(matchPath)-1]) {
				return true
			}
			continue
		}

		// for everything else, try globular matching, which also
		// is exact matching if there are no glob/wildcard chars;
		// can ignore error here because we can't handle it anyway
		matches, _ := filepath.Match(matchPath, lowerPath)
		if matches {
			return true
		}
	}
	return false
}
// Match returns true if r matches m.
Match returns true if r matches m.
// Match returns true if r matches m .
func (m MatchPath) Match(r *http.Request) bool {
	unescapedPath, err := url.PathUnescape(r.URL.Path)
	if err != nil {
		return false
	}
	lowerPath := strings.ToLower(unescapedPath)
	lowerPath = path.Clean(lowerPath)
	lowerPath = strings.TrimRight(lowerPath, ". ")
	if lowerPath != "/" && strings.HasSuffix(r.URL.Path, "/") {
		lowerPath = lowerPath + "/"
	}
	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
	for _, matchPath := range m {
		matchPath = repl.ReplaceAll(matchPath, "")
		if matchPath == "*" {
			return true
		}
		if len(matchPath) > 1 &&
			strings.HasPrefix(matchPath, "*") &&
			strings.HasSuffix(matchPath, "*") {
			if strings.Contains(lowerPath, matchPath[1:len(matchPath)-1]) {
				return true
			}
			continue
		}
		if strings.HasPrefix(matchPath, "*") {
			if strings.HasSuffix(lowerPath, matchPath[1:]) {
				return true
			}
			continue
		}
		if strings.HasSuffix(matchPath, "*") {
			if strings.HasPrefix(lowerPath, matchPath[:len(matchPath)-1]) {
				return true
			}
			continue
		}
		matches, _ := filepath.Match(matchPath, lowerPath)
		if matches {
			return true
		}
	}
	return false
}
func ( m MatchPath ) Match ( r * http . Request ) bool { unescapedPath , err := url . PathUnescape ( r . URL . Path ) if err != nil { return false } lowerPath := strings . ToLower ( unescapedPath ) lowerPath = path . Clean ( lowerPath ) lowerPath = strings . TrimRight ( lowerPath , " " ) if lowerPath != " " && strings . HasSuffix ( r . URL . Path , " " ) { lowerPath = lowerPath + " " } repl := r . Context ( ) . Value ( caddy . ReplacerCtxKey ) . ( * caddy . Replacer ) for _ , matchPath := range m { matchPath = repl . ReplaceAll ( matchPath , " " ) if matchPath == " " { return true } if len ( matchPath ) > 1 && strings . HasPrefix ( matchPath , " " ) && strings . HasSuffix ( matchPath , " " ) { if strings . Contains ( lowerPath , matchPath [ 1 : len ( matchPath ) - 1 ] ) { return true } continue } if strings . HasPrefix ( matchPath , " " ) { if strings . HasSuffix ( lowerPath , matchPath [ 1 : ] ) { return true } continue } if strings . HasSuffix ( matchPath , " " ) { if strings . HasPrefix ( lowerPath , matchPath [ : len ( matchPath ) - 1 ] ) { return true } continue } matches , _ := filepath . Match ( matchPath , lowerPath ) if matches { return true } } return false }
Match returns true if r matches m.
Match returns true if r matches m .
// PathUnescape returns an error if the escapes aren't // well-formed, meaning the count % matches the RFC. // Return early if the escape is improper. // Clean the path, merges doubled slashes, etc. // This ensures maliciously crafted requests can't bypass // the path matcher. See #4407 // see #2917; Windows ignores trailing dots and spaces // when accessing files (sigh), potentially causing a // security risk (cry) if PHP files end up being served // as static files, exposing the source code, instead of // being matched by *.php to be treated as PHP scripts // Cleaning may remove the trailing slash, but we want to keep it // special case: whole path is wildcard; this is unnecessary // as it matches all requests, which is the same as no matcher // special case: first and last characters are wildcard, // treat it as a fast substring match // special case: first character is a wildcard, // treat it as a fast suffix match // special case: last character is a wildcard, // treat it as a fast prefix match // for everything else, try globular matching, which also // is exact matching if there are no glob/wildcard chars; // can ignore error here because we can't handle it anyway