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

Undefined Route Request Leads to Infinite Loop in route matching #843

Open
soheilrt opened this issue Sep 1, 2023 · 6 comments
Open

Undefined Route Request Leads to Infinite Loop in route matching #843

soheilrt opened this issue Sep 1, 2023 · 6 comments

Comments

@soheilrt
Copy link

soheilrt commented Sep 1, 2023

I was implementing an HTTP server for my service and noticed that when I use 'chi' as shown below, the router does not respond to undefined routes. Additionally, I suspect the router gets stuck in an infinite loop, leading to a memory leak in the service.

package main

import (
	"fmt"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"net/http"
	_ "net/http/pprof"
)

func main() {
	r := chi.NewRouter().With(middleware.Logger)
	r.Mount("/", r.Group(func(r chi.Router) {
		r.Get("/ping", func(writer http.ResponseWriter, request *http.Request) {
			writer.WriteHeader(http.StatusOK)
			writer.Write([]byte("pong"))
		})
	}))

	fmt.Println("%v", http.ListenAndServe(":8080", r))
}

For the above-mentioned code, GET /ping request will be handled properly, but router never returns a response for an undefined request path.

@Kidsan
Copy link

Kidsan commented Sep 24, 2023

I was playing around with this bug a bit and found that if you mount the middleware with Use() instead of With() (because With() is for inline middleware, i.e. router.With(<handler-specific-mw>).Get(...) your example actually crashes with a fatal error for me.

package main

import (
	"fmt"
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

func main() {
	r := chi.NewRouter()
	r.Use(middleware.Logger)
	r.Mount("/", r.Group(func(r chi.Router) {
		r.Get("/ping", func(writer http.ResponseWriter, request *http.Request) {
			writer.WriteHeader(http.StatusOK)
			writer.Write([]byte("pong"))
		})
	}))

	fmt.Println("%v", http.ListenAndServe(":8080", r))
}
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0201e0408 stack=[0xc0201e0000, 0xc0401e0000]
fatal error: stack overflow

this seems to be due to some weirdness when doing r.Mount("/", r.Group(...)), seems like this is unnecessary anyway (?) but should not cause this behavior I think.

@Kidsan
Copy link

Kidsan commented Sep 25, 2023

This issue was actually raised previously: #663

@soheilrt
Copy link
Author

Hi @Kidsan,

Thanks for checking this out.

In general, I agree with you that with should be used for the route middleware definition only.

There is only one thing - I believe libraries should prevent misuse as much as possible and this case seems to be misuse, unless it's intended this way. If this is intended this way, then we have a bug here that needs to be addressed.

Also, regarding the usage of Use method and stack overflow error, it seems the error still exists, only in a different form!

Happy to hear your point of view on this!

@Kidsan
Copy link

Kidsan commented Sep 26, 2023

@soheilrt I don't disagree 😄 would like a maintainer to chime in though, based on the other issue I linked it looks like they aren't interested in presenting "obvious" misuse.

@soheilrt
Copy link
Author

Hey @pkieltyka , can we have your toughts on this as well?

@newacorn
Copy link

newacorn commented Dec 3, 2023

func (mx *Mux) Mount(pattern string, handler http.Handler) {
....
	subr, ok := handler.(*Mux)
	if ok {
		if subr.tree == mx.tree {
			panic("subRouter's tree equals its own.")
		}
	}

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

3 participants