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

[BUG] handler and middleware running twice with middleware defined on pointer reciever #756

Closed
flipkickmedia opened this issue Apr 8, 2024 · 0 comments
Labels

Comments

@flipkickmedia
Copy link

flipkickmedia commented Apr 8, 2024

Is there an existing issue for this?

Current Behavior

Add middleware and a handler to a route as per the readme, call the route and the handler and middleware run twice, the output is a concat of the two handlers' output.

Expected Behavior

Middleware should run once, handler should run once

Steps To Reproduce

Create the simple example in the readme and then call a router, the middleware and handler will run twice.

Anything else?

This works as expected:

package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"log"
	"net/http"
)

func MiddlewareA(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		referer := r.Header.Get("Origin")
		w.Header().Set("Access-Control-Allow-Origin", referer)
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Origin, Cache-Control, Authorization, X-Requested-With")
		w.Header().Set("Access-Control-Allow-Method", "GET, POST,OPTIONS")
		next.ServeHTTP(w, r)
	})
}

func MiddlewareB(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		referer := r.Header.Get("Origin")
		w.Header().Set("Access-Control-Allow-Origin", referer)
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Origin, Cache-Control, Authorization, X-Requested-With")
		w.Header().Set("Access-Control-Allow-Method", "GET, POST,OPTIONS")
		next.ServeHTTP(w, r)
	})
}

func HandlerA(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "TestingA")
}

func HandlerB(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "TestingB")
}

func main() {
	router := mux.NewRouter()
	router.Use(MiddlewareA)
	router.Use(MiddlewareB)
	router.HandleFunc("/", HandlerA)
	router.HandleFunc("/test", HandlerB)
	log.Fatal(http.ListenAndServe(":9000", router))
}
tshaw@tshaw-ThinkPad-P14s-Gen-3:~$ curl http://localhost:9000
TestingA
tshaw@tshaw-ThinkPad-P14s-Gen-3:~$ curl http://localhost:9000/
TestingA
tshaw@tshaw-ThinkPad-P14s-Gen-3:~$ curl http://localhost:9000/test
TestingB
tshaw@tshaw-ThinkPad-P14s-Gen-3:~$ curl http://localhost:9000/test/
404 page not found
tshaw@tshaw-ThinkPad-P14s-Gen-3:~$ 

This causes the failure:

func (m *Cors) Middleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		referer := r.Header.Get("Origin")
		w.Header().Set("Access-Control-Allow-Origin", referer)
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Origin, Cache-Control, Authorization, X-Requested-With")
		w.Header().Set("Access-Control-Allow-Method", "GET, POST,OPTIONS")
		next.ServeHTTP(w, r)
	})
}

This problem is caused by passing a function which has a pointer reciever. The fix is to return an anonymous function:

// GetHandler
// Sets the content type to application/json
func (m *Cors) GetHandler() func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			referer := r.Header.Get("Origin")
			w.Header().Set("Access-Control-Allow-Origin", referer)
			w.Header().Set("Access-Control-Allow-Credentials", "true")
			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Origin, Cache-Control, Authorization, X-Requested-With")
			w.Header().Set("Access-Control-Allow-Method", "GET, POST,OPTIONS")
			next.ServeHTTP(w, r)
		})
	}
}

However, I want to access specific struct data in the handler context. Looking at the source code:

type MiddlewareFunc func(http.Handler) http.Handler

I'm implementing that interface so it should work. Looking at the readme https://github.com/gorilla/mux?tab=readme-ov-file#middleware what Im doing is documented but this causes a double response.

@flipkickmedia flipkickmedia changed the title [BUG] handler and middleware running twice due to trailing slash [BUG] handler and middleware running twice due to trailing slash and middleware defined on pointer reciever Apr 9, 2024
@flipkickmedia flipkickmedia changed the title [BUG] handler and middleware running twice due to trailing slash and middleware defined on pointer reciever [BUG] handler and middleware running twice with middleware defined on pointer reciever Apr 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant