SoFunction
Updated on 2025-03-05

Go Gin framework routing related bug analysis

introduction

Note: There are errors in the original text of this article, and the original text is not changed, but an errata was performed at the end. Please note that you will read the end of the article.

Gin related version v1.9.1

The bug will occur when you register two routes as follows.

r := ()
    ("/static/", func(c *) { (200, "static") })
    ("/static/*file", func(c *) { (200, "static file") })
    ()

The above code will report an error:

panic: runtime error: index out of range [0] with length 0

analyze

Although Gin itself will actively generate many panics when building a routing tree, the above panic is obviously an accident.

This bug is caused by the specificity of the catchAll wildcard.

catchAll wildcards are written*paramname, but when it builds the routing tree, it will match one forward/

Because catchAll wildcards usually exist to match paths, the classic application of catchAll wildcards in gin is to configure static file servers.

Refer to the gin projectdocument:

func (group *RouterGroup) StaticFS(relativePath string, fs ) IRoutes {
    if (relativePath, ":") || (relativePath, "*") {
        panic("URL parameters can not be used when serving a static folder")
    }
    handler := (relativePath, fs)
    urlPattern := (relativePath, "/*filepath")
    // Register GET and HEAD handlers
    (urlPattern, handler)
    (urlPattern, handler)
    return ()
}

Once you useStaticThe related functions configure the static file service and will eventually call the above method.

It uses the one you passed inrelativePathand/*filepathCombined into the final url:relativePath/*filepath

If the path you passed in is/static, the final url is/static/*filepath

This route will match all/static/The url at the beginning and assign all the following content tofilepath

Yes, it's all, including the ones behind/,for examplehtml/group1/, that is, it can be passedfilepathAccess to the subdirectory.

But there is actually a mistake in what is described above, you thinkfilepathThe saved content ishtml/group1/

Actually it is/html/group1/

catchAll wildcard will try to match one more forward/If you don't have this in your route/, an error will be reported.

The special feature of this feature leads to a bug in gin, which is when you have registered/static/After routing, register/static/*fileWhen we're in/static/Insert on node*filepathInstead/*filepath, This causes the program to match one forward after determining that this is a catchAll route./, at this timei--After that, it becomes a negative number, which leads toindex out of rangeError.

You may think that the error is correct, so you need to pay attention to distinguishing the panic caused by the error and the bug.

i--
if path[i] != '/' {
    panic("no / before catch-all in path '" + fullPath + "'")
}

What I said is the errorpanic("no / before catch-all in path '" + fullPath + "'")

The bug-generated panic is generated ini--Query after it becomes negativeif path[i] != '/'hour.

If it is simple to deal with, it should be correct hereijudging the value of , then actively panic to throw an error that can make people understand.

Of course, in order to solve this problem itself, the above code can be modified to:

r := ()
    ("/static", func(c *) { (200, "static") })
    ("/static/*file", func(c *) { (200, "static file") })
    ()

Do not add the end of the first route/, you can avoid this bug.

Errata

As mentioned earlierpanic: runtime error: index out of range [0] with length 0An error was reported, but it was obviously not an error with index negative, it was my previous predictioni--Wishful thinking when it is negative.

Actually this error occurred ini--The above lines:

if len() > 0 && [len()-1] == '/' {
    pathSeg := ([0].path, "/", 2)[0]
    panic("catch-all wildcard '" + path +
        "' in new path '" + fullPath +
        "' conflicts with existing path segment '" + pathSeg +
        "' in existing prefix '" +  + pathSeg +
        "'")
}
// currently fixed width 1 for '/'
i--
if path[i] != '/' {
    panic("no / before catch-all in path '" + fullPath + "'")
}

This line:pathSeg := ([0].path, "/", 2)[0]

HerechildrenThe length is actually 0, but here it is defaultchildrenThere is content.

See the content of the error reported by panic:catch-all wildcard "path" in new path "fullPath" conflicts with existing path segment "pathSeg" in existing prefix "" + "pathSeg"

The catchAll wildcard character conflicts with the current path, but here Gin defaults to this timeI still haven't figured out the logic of not being empty.

The above is the detailed content of the Go Gin framework routing-related bug analysis. For more information about Go Gin framework routing bugs, please follow my other related articles!