Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
xkeyideal opened this issue Sep 5, 2017 · 1 comment
Open

Comments

@xkeyideal
Copy link

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
	}
}
@husobee
Copy link
Owner

husobee commented Sep 6, 2017

@xkeyideal: Will take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants