1

I have a rate limiter for requests and using it as a middleware for every mux handler in my project.
The problem occurs when middleware is called 4 times when going to a page with path of /post. Every other page seems to work as expected - calls the middleware once.


Server handlers / configurations

mux := http.NewServeMux()

mux.Handle("/", ratelimit.Middleware(handler.Home(env)))

mux.Handle("/createpost", ratelimit.Middleware(post.Create(env)))
mux.Handle("/post", ratelimit.Middleware(post.View(env)))
mux.Handle("/addcomment", handler.AddComment(env))
...

// TLS Configurations (dont know if these should matter)
cfg := &tls.Config{

    // Causes servers to use Go's default ciphersuite preferences,
    // which are tuned to avoid attacks. Does nothing on clients.
    PreferServerCipherSuites: true,

    // Avoid server using unoptimized curves
    CurvePreferences: []tls.CurveID{
        tls.CurveP256,
        tls.X25519, // Go 1.8 only
    },
}

// Create a server with our configurations
s := &http.Server{
    Addr:      ":8000",
    Handler:   mux,
    TLSConfig: cfg,

    IdleTimeout:  time.Minute,      //  Close all keep-alive connections after IdleTimeout
    ReadTimeout:  5 * time.Second,  // Time for server to read HTTP request body/headers
    WriteTimeout: 10 * time.Second, // Time for server to write to response aka http.Handler lifecycle
}

if err := s.ListenAndServeTLS("./cert/CA/localhost/localhost.crt", "./cert/CA/localhost/localhost.decrypted.key"); err != nil {
    log.Fatalln(err)
}

Middleware(Rate limiting requests by Token Bucket algorithm)

func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
    ip, _, err := net.SplitHostPort(r.RemoteAddr)
    if err != nil {
        log.Println(err)
        return
    }

    if _, exists := IPTokenBuckets[ip]; !exists {
        IPTokenBuckets[ip] = &TokenBucket{
            maxTokens:     5,
            currentTokens: 5,
            lastRefill:    time.Now(),
            refillRate:    1, // how many per second
        }
    }

    tb := IPTokenBuckets[ip]
    // fmt.Println("Token bucket", tb)
    if tb.allowRequest() {

    } else {
        log.Println("Rate limit exceeded", ip)
        return
    }
    fmt.Println("Middleware")
    next.ServeHTTP(rw, r)

})

}

  • 1
    If `/post` is meant to be called with an HTTP POST request, it is likely that the additional calls to that middleware are OPTION calls coming from the browser. Check the HTTP method in the middleware. – Burak Serdar Jan 25 '22 at 18:49
  • @BurakSerdar /post is just meant to display a certain post from the database. I am pretty sure its GET request anyways I will check and let you know. Cheers. – Kristofer Kangro Jan 25 '22 at 19:49
  • If these are being called from a browser, then it is likely that you are handling OPTION requests with the middleware. – Burak Serdar Jan 25 '22 at 19:54
  • @BurakSerdar The request is GET. – Kristofer Kangro Jan 26 '22 at 07:12

1 Answers1

0

I had previously also tried to add middleware to every mux handler by wrapping the mux with my middleware in server configurations.

mux := http.NewServeMux()
s := &http.Server{
    Addr:      ":8000",
    Handler:   middleware(mux),
    TLSConfig: cfg,
}

This sent multiple unwanted middleware requests to fileserver.

fs := http.FileServer(http.Dir("./assets")) 
mux.Handle("/assets/", http.StripPrefix("/assets/", fs))

The problem went away when I added middleware to every handler except the fileserver.