Skip to content

The router find function can't return matchAny raw router name #75

@xkeyideal

Description

@xkeyideal

When the METHOD is GET, route is /root/home/*filepath

The request of url '/root/home/log' should return /root/home/*filepath, but now just return /root/home

func (r *Router) find(req *http.Request) (prefix string, h http.HandlerFunc) {
	// get tree base node from the router
	cn := r.root

	h = notFoundHandler

	if !validMethod(req.Method) {
		// if the method is completely invalid
		h = methodNotAllowedHandler(cn.resource.allowedMethods)
		return
	}

	var (
		search          = req.URL.Path
		c               *node // Child node
		n               int   // Param counter
		collectedPnames = []string{}
	)

	// Search order static > param > match-any
	for {

		if search == "" {
			if cn.resource != nil {
				// Found route, check if method is applicable
				theHandler, allowedMethods := cn.resource.GetMethodHandler(req.Method)
				if theHandler == nil {
					if uint16(req.Method[0])<<8|uint16(req.Method[1]) == 0x4f50 {
						h = optionsHandler(r.globalCors, cn.resource.Cors, allowedMethods)
						return
					}
					if allowedMethods != "" {
						// route is valid, but method is not allowed, 405
						h = methodNotAllowedHandler(allowedMethods)
					}
					return
				}
				h = corsFlightWrapper(r.globalCors, cn.resource.Cors, allowedMethods, theHandler)
				for i, v := range collectedPnames {
					if len(cn.pnames[req.Method]) > i {
						AddParam(req, cn.pnames[req.Method][i], v)
					}
				}

				brokenPrefix := strings.Split(prefix, "/")
				prefix = ""
				k := 0
				for _, v := range brokenPrefix {
					if v != "" {
						prefix += "/"
						if v == ":" {
							if pnames, ok := cn.pnames[req.Method]; ok {
								prefix += v + pnames[k]
							}
							k++
						} else {
							prefix += v
						}
					}
				}
			}
			return
		}

		pl := 0 // Prefix length
		l := 0  // LCP length

		if cn.label != ':' {
			sl := len(search)
			pl = len(cn.prefix)
			prefix += cn.prefix

			// LCP
			max := pl
			if sl < max {
				max = sl
			}
			for ; l < max && search[l] == cn.prefix[l]; l++ {
			}
		}

		if l == pl {
			// Continue search
			search = search[l:]

			if search == "" && cn != nil && cn.parent != nil && cn.resource.allowedMethods == "" {
				parent := cn.parent
				search = cn.prefix
				for parent != nil {
					if sib := parent.findChildWithLabel('*'); sib != nil {
						search = parent.prefix + search
						cn = parent
						goto MatchAny
					}
					parent = parent.parent
				}
			}

		}

		if search == "" {
			// TODO: Needs improvement
			if cn.findChildWithType(mtype) == nil {
				continue
			}
			// Empty value
			goto MatchAny
		}

		// Static node
		c = cn.findChild(search, stype)
		if c != nil {
			cn = c
			continue
		}
		// Param node
	Param:

		c = cn.findChildWithType(ptype)
		if c != nil {
			cn = c

			i, l := 0, len(search)
			for ; i < l && search[i] != '/'; i++ {
			}

			collectedPnames = append(collectedPnames, search[0:i])
			prefix += ":"
			n++
			search = search[i:]

			if len(cn.children) == 0 && len(search) != 0 {
				return
			}

			continue
		}

		// Match-any node
	MatchAny:
		//		c = cn.getChild()
		c = cn.findChildWithType(mtype)
		if c != nil {
			cn = c
			collectedPnames = append(collectedPnames, search)
			search = "" // End search
			continue
		}
		// last ditch effort to match on wildcard (issue #8)
		var tmpsearch = search
		for {
			if cn != nil && cn.parent != nil && cn.prefix != ":" {
				tmpsearch = cn.prefix + tmpsearch
				cn = cn.parent
				if cn.prefix == "/" {
					var sib *node = cn.findChildWithLabel(':')
					if sib != nil {
						search = tmpsearch
						goto Param
					}
					if sib := cn.findChildWithLabel('*'); sib != nil {
						search = tmpsearch
						goto MatchAny
					}
				}
			} else {
				break
			}
		}

		// Not found
		return
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions