{"record":{"id":"5838a1cde5d0a2c0","repo":"geektutu/7days-golang","slug":"httppool-serving-unexpected-path-r-url-path","errorCode":null,"errorMessage":"HTTPPool serving unexpected path: \" + r.URL.Path","messagePattern":"HTTPPool serving unexpected path: \" \\+ r\\.URL\\.Path","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day3-http-server/geecache/http.go","lineNumber":35,"sourceCode":"}\n\n// NewHTTPPool initializes an HTTP pool of peers.\nfunc NewHTTPPool(self string) *HTTPPool {\n\treturn &HTTPPool{\n\t\tself:     self,\n\t\tbasePath: defaultBasePath,\n\t}\n}\n\n// Log info with server name\nfunc (p *HTTPPool) Log(format string, v ...interface{}) {\n\tlog.Printf(\"[Server %s] %s\", p.self, fmt.Sprintf(format, v...))\n}\n\n// ServeHTTP handle all http requests\nfunc (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tif !strings.HasPrefix(r.URL.Path, p.basePath) {\n\t\tpanic(\"HTTPPool serving unexpected path: \" + r.URL.Path)\n\t}\n\tp.Log(\"%s %s\", r.Method, r.URL.Path)\n\t// /<basepath>/<groupname>/<key> required\n\tparts := strings.SplitN(r.URL.Path[len(p.basePath):], \"/\", 2)\n\tif len(parts) != 2 {\n\t\thttp.Error(w, \"bad request\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tgroupName := parts[0]\n\tkey := parts[1]\n\n\tgroup := GetGroup(groupName)\n\tif group == nil {\n\t\thttp.Error(w, \"no such group: \"+groupName, http.StatusNotFound)\n\t\treturn\n\t}\n","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day3-http-server/geecache/http.go#L17-L53","documentation":"HTTPPool.ServeHTTP panics when the request path does not start with the pool's basePath (default \"/_geecache/\"). The handler is designed to serve only the internal peer-to-peer cache API at /<basePath>/<group>/<key>, so any foreign path is treated as a deployment/routing misconfiguration and panics immediately. Legitimate requests on the right prefix with a missing group/key get a 400 instead.","triggerScenarios":"Registering the HTTPPool on a mux that receives requests outside p.basePath — e.g. http.Handle(\"/\", pool), health checks hitting \"/\", a proxy stripping the /_geecache/ prefix before forwarding, or a client omitting the base path in its URL.","commonSituations":"Mounting the cache server behind a reverse proxy with a rewrite rule that drops the prefix; load balancer health probes on \"/\"; a client (NewHTTPPool on the fetch side) configured with a different basePath than the server.","solutions":["Serve the pool only at its basePath: http.Handle(\"/_geecache/\", pool)","Point health checks/probes at a separate handler or a path under /_geecache/","Fix proxy rewrite rules so the /_geecache/ prefix is preserved to ServeHTTP","Ensure client-side HTTPPool uses the same base path as the server"],"exampleFix":"// before\nhttp.Handle(\"/\", pool) // any path like / or /health panics\n// after\nhttp.Handle(\"/_geecache/\", pool)\nhttp.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) })","handlingStrategy":"validation","validationCode":"if !strings.HasPrefix(r.URL.Path, \"/_geecache/\") {\n    http.NotFound(w, r)\n    return\n}\npool.ServeHTTP(w, r)","typeGuard":null,"tryCatchPattern":"// Prefer not to route foreign paths to the pool. If you must wrap it:\nfunc safeServe(p *geecache.HTTPPool, w http.ResponseWriter, r *http.Request) {\n    defer func() {\n        if rec := recover(); rec != nil {\n            if s, ok := rec.(string); ok && strings.Contains(s, \"unexpected path\") {\n                http.NotFound(w, r)\n                return\n            }\n            panic(rec)\n        }\n    }()\n    p.ServeHTTP(w, r)\n}","preventionTips":["Register HTTPPool only at its exact basePath in the mux","Point load-balancer/health probes at dedicated endpoints","Keep reverse-proxy configs from stripping or rewriting the /_geecache/ prefix","Use the same base path on client and server pools"],"tags":["go","http","panic","routing"],"backgroundTag":"unexpected-http-path","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}