type pattern … func (p *pattern) String() string { … } func (p *pattern) lastSegment() segment { … } type segment … // parsePattern parses a string into a Pattern. // The string's syntax is // // [METHOD] [HOST]/[PATH] // // where: // - METHOD is an HTTP method // - HOST is a hostname // - PATH consists of slash-separated segments, where each segment is either // a literal or a wildcard of the form "{name}", "{name...}", or "{$}". // // METHOD, HOST and PATH are all optional; that is, the string can be "/". // If METHOD is present, it must be followed by at least one space or tab. // Wildcard names must be valid Go identifiers. // The "{$}" and "{name...}" wildcard must occur at the end of PATH. // PATH may end with a '/'. // Wildcard names in a path must be distinct. func parsePattern(s string) (_ *pattern, err error) { … } func isValidWildcardName(s string) bool { … } func pathUnescape(path string) string { … } type relationship … const equivalent … const moreGeneral … const moreSpecific … const disjoint … const overlaps … // conflictsWith reports whether p1 conflicts with p2, that is, whether // there is a request that both match but where neither is higher precedence // than the other. // // Precedence is defined by two rules: // 1. Patterns with a host win over patterns without a host. // 2. Patterns whose method and path is more specific win. One pattern is more // specific than another if the second matches all the (method, path) pairs // of the first and more. // // If rule 1 doesn't apply, then two patterns conflict if their relationship // is either equivalence (they match the same set of requests) or overlap // (they both match some requests, but neither is more specific than the other). func (p1 *pattern) conflictsWith(p2 *pattern) bool { … } func (p1 *pattern) comparePathsAndMethods(p2 *pattern) relationship { … } // compareMethods determines the relationship between the method // part of patterns p1 and p2. // // A method can either be empty, "GET", or something else. // The empty string matches any method, so it is the most general. // "GET" matches both GET and HEAD. // Anything else matches only itself. func (p1 *pattern) compareMethods(p2 *pattern) relationship { … } // comparePaths determines the relationship between the path // part of two patterns. func (p1 *pattern) comparePaths(p2 *pattern) relationship { … } // compareSegments determines the relationship between two segments. func compareSegments(s1, s2 segment) relationship { … } // combineRelationships determines the overall relationship of two patterns // given the relationships of a partition of the patterns into two parts. // // For example, if p1 is more general than p2 in one way but equivalent // in the other, then it is more general overall. // // Or if p1 is more general in one way and more specific in the other, then // they overlap. func combineRelationships(r1, r2 relationship) relationship { … } // If p1 has relationship `r` to p2, then // p2 has inverseRelationship(r) to p1. func inverseRelationship(r relationship) relationship { … } // isLitOrSingle reports whether the segment is a non-dollar literal or a single wildcard. func isLitOrSingle(seg segment) bool { … } // describeConflict returns an explanation of why two patterns conflict. func describeConflict(p1, p2 *pattern) string { … } // writeMatchingPath writes to b a path that matches the segments. func writeMatchingPath(b *strings.Builder, segs []segment) { … } func writeSegment(b *strings.Builder, s segment) { … } // commonPath returns a path that both p1 and p2 match. // It assumes there is such a path. func commonPath(p1, p2 *pattern) string { … } // differencePath returns a path that p1 matches and p2 doesn't. // It assumes there is such a path. func differencePath(p1, p2 *pattern) string { … }