I'm serving web content via a Go web server and using regular expressions to match handlers to request paths. I've noticed a really strange behaviour I've diluted to this test code below. Basically, any 8 letter/number combination is meant to be caught by a handler, while other specific request paths are meant to be caught by other handlers. This works great by in the case of the 8 letter/number path the match gets picked up by the first handler if the letter sequence ends in a lower case 'c'. Any other letter at the end works fine.
The code below can be pasted into a file and run. It will serve on localhost:8080. I've provided a few request links to demonstrate the problem.
package main
import (
"fmt"
"net/http"
"regexp"
)
// This is the handler when passing a string of 8 characters ([])
func runTest(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path[1:]
fmt.Fprintf(w, path)
}
func runTest2(w http.ResponseWriter, r *http.Request) {
path := "Reg ex for: .[(css|jpg|png|js|ttf|ico)]$"
fmt.Fprintf(w, path)
}
func runTest3(w http.ResponseWriter, r *http.Request) {
path := "Reg ex for: /all$"
fmt.Fprintf(w, path)
}
// Regular expression handler
type route struct {
pattern *regexp.Regexp
handler http.Handler
}
type RegexpHandler struct {
routes []*route
}
func (h *RegexpHandler) Handler(pattern *regexp.Regexp, handler http.Handler) {
h.routes = append(h.routes, &route{pattern, handler})
}
func (h *RegexpHandler) HandleFunc(pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request)) {
h.routes = append(h.routes, &route{pattern, http.HandlerFunc(handler)})
}
func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for _, route := range h.routes {
if route.pattern.MatchString(r.URL.Path) {
route.handler.ServeHTTP(w, r)
return
}
}
http.NotFound(w, r)
}
func main() {
handler := &RegexpHandler{}
handler.HandleFunc(regexp.MustCompile(`.[(css|jpg|png|js|ttf|ico)]$`), runTest2)
handler.HandleFunc(regexp.MustCompile("^/all$"), runTest3)
handler.HandleFunc(regexp.MustCompile("^/[A-Z0-9a-z]{8}$"), runTest)
http.ListenAndServe(":8080", handler)
}
This request gets picked up by the second handler (runTest3):
http://localhost:8080/all
This request gets picked up by the third handler (runTest) which prints out the path portion of the url:
http://localhost:8080/yr22FBMD.
This request however, gets picked up by the first handler (note its ending with a lower case c):
http://localhost:8080/yr22FBMc
Any ideas? This is extremely weird!