mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-15 12:58:45 +00:00
feat(lib): enable multiple consecutive slash support
Replaces #808 Closes #754 Some web applications require the ability to include multiple consecutive slashes in a URL. This could be for optional path variables or for wiki article titles that start with a leading slash. I wasn't aware that the RFC allowed this. Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
@@ -99,6 +99,7 @@ There are a bunch of other assorted features and fixes too:
|
|||||||
- Allow [Common Crawl](https://commoncrawl.org/) by default so scrapers have less incentive to scrape
|
- Allow [Common Crawl](https://commoncrawl.org/) by default so scrapers have less incentive to scrape
|
||||||
- The [bbolt storage backend](./admin/policies.mdx#bbolt) now runs its cleanup every hour instead of every five minutes.
|
- The [bbolt storage backend](./admin/policies.mdx#bbolt) now runs its cleanup every hour instead of every five minutes.
|
||||||
- Don't block Anubis starting up if [Thoth](./admin/thoth.mdx) health checks fail.
|
- Don't block Anubis starting up if [Thoth](./admin/thoth.mdx) health checks fail.
|
||||||
|
- Multiple consecutive slashes are supported in upstream application URLs ([#754](https://github.com/TecharoHQ/anubis/issues/754)).
|
||||||
|
|
||||||
### Potentially breaking changes
|
### Potentially breaking changes
|
||||||
|
|
||||||
|
|||||||
@@ -204,6 +204,63 @@ func TestCVE2025_24369(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDoubleSlashes(t *testing.T) {
|
||||||
|
pol := loadPolicies(t, "", 0)
|
||||||
|
|
||||||
|
path := ""
|
||||||
|
|
||||||
|
srv := spawnAnubis(t, Options{
|
||||||
|
Next: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
path = r.URL.Path
|
||||||
|
}),
|
||||||
|
Policy: pol,
|
||||||
|
})
|
||||||
|
|
||||||
|
ts := httptest.NewServer(internal.RemoteXRealIP(true, "tcp", srv))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
cli := httpClient(t)
|
||||||
|
chall := makeChallenge(t, ts, cli)
|
||||||
|
resp := handleChallengeZeroDifficulty(t, ts, cli, chall)
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusFound {
|
||||||
|
t.Fatal("can't solve challenge, see logs")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name, path string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "basic",
|
||||||
|
path: "/foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "leading slashes",
|
||||||
|
path: "//foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mid slashes",
|
||||||
|
path: "/foo//bar///baz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "trailing slashes",
|
||||||
|
path: "/foo/bar///",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if _, err := cli.Get(ts.URL + tt.path); err != nil {
|
||||||
|
t.Errorf("can't make request to %s: %v", tt.path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if path != tt.path {
|
||||||
|
t.Logf("want: %s", tt.path)
|
||||||
|
t.Logf("got: %s", path)
|
||||||
|
t.Error("invalid path sent to server")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCookieCustomExpiration(t *testing.T) {
|
func TestCookieCustomExpiration(t *testing.T) {
|
||||||
pol := loadPolicies(t, "", 0)
|
pol := loadPolicies(t, "", 0)
|
||||||
ckieExpiration := 10 * time.Minute
|
ckieExpiration := 10 * time.Minute
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ func New(opts Options) (*Server, error) {
|
|||||||
|
|
||||||
registerWithPrefix(anubis.APIPrefix+"pass-challenge", http.HandlerFunc(result.PassChallenge), "GET")
|
registerWithPrefix(anubis.APIPrefix+"pass-challenge", http.HandlerFunc(result.PassChallenge), "GET")
|
||||||
registerWithPrefix(anubis.APIPrefix+"check", http.HandlerFunc(result.maybeReverseProxyHttpStatusOnly), "")
|
registerWithPrefix(anubis.APIPrefix+"check", http.HandlerFunc(result.maybeReverseProxyHttpStatusOnly), "")
|
||||||
registerWithPrefix("/", http.HandlerFunc(result.maybeReverseProxyOrPage), "")
|
|
||||||
|
|
||||||
//goland:noinspection GoBoolExpressions
|
//goland:noinspection GoBoolExpressions
|
||||||
if anubis.Version == "devel" {
|
if anubis.Version == "devel" {
|
||||||
|
|||||||
@@ -200,7 +200,12 @@ func (s *Server) respondWithStatus(w http.ResponseWriter, r *http.Request, msg s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
s.mux.ServeHTTP(w, r)
|
switch strings.HasPrefix(r.URL.Path, anubis.StaticPath) {
|
||||||
|
case true:
|
||||||
|
s.mux.ServeHTTP(w, r)
|
||||||
|
case false:
|
||||||
|
s.maybeReverseProxyOrPage(w, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) stripBasePrefixFromRequest(r *http.Request) *http.Request {
|
func (s *Server) stripBasePrefixFromRequest(r *http.Request) *http.Request {
|
||||||
|
|||||||
Reference in New Issue
Block a user