pigfox
pigfox

Reputation: 1401

Cookie set and not detected

I am building a website that will use many routes and because of this I don't want individual handlers. My solution is to iterate over a list of endpoints. When I do this a cookie is set but not detected. The code below can be copy and pasted, just comments/uncomment the two route systems.

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
)

var tmpl *template.Template
const testCookieName = "testCookieName"
const testCookievalue = "testCookievalue"

func main(){
    port :=":8088"
    router := mux.NewRouter()
    router.Use(middlewareSetCookie)
    router.Use(middlewareCheckCookies)//no cookie sends page to /cookie for an error msg
    router.Use(middlewareNoWWW)
    router.Use(middlewareHeaders)

    //Using individual routes works as expected and a cookie is set and detected.
/*
    router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        err := tmpl.ExecuteTemplate(w, "index", "")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    })

    router.HandleFunc("/cookie", func(w http.ResponseWriter, r *http.Request) {
        err := tmpl.ExecuteTemplate(w, "cookie", "")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    })
*/


    //Given the number of routes I need I have to use a loop to iterate over all to keep the code base maintanable 
    //The cookie is set but not detected in the code below
/**/
    pages := make(map[string]string)
    pages["/"] = "index"
    pages["/cookie"] = "cookie"

    for k, v :=range pages{
            router.HandleFunc(k, func(w http.ResponseWriter, r *http.Request) {
            err := tmpl.ExecuteTemplate(w, v, "")
            if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
            }
        })
    }

    
    var err error
    tmpl, err = template.ParseGlob("views/*")
    if err != nil {
        panic(err.Error())
    }

    router.PathPrefix("/").HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        http.FileServer(http.Dir("./static/")).ServeHTTP(res, req)
    })

    fmt.Println("Server running on localhost" + port)

    err = http.ListenAndServe(port, handlers.CompressHandler(router))
    if err != nil {
        log.Fatal(err)
    }
}

func middlewareNoWWW(next http.Handler) http.Handler {
    fmt.Println("middlewareNoWWW")
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.Host[0:4] == "www." {
            target := "http://" + r.Host[4:]
            http.Redirect(w, r, target, 301)
        }
        next.ServeHTTP(w, r)
    })
}

func middlewareHeaders(next http.Handler) http.Handler {
    fmt.Println("middlewareHeaders")
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Cache-Control", "max-age=2592000") // 30 days
        w.Header().Set("Content-Encoding", "gzip")
        w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
        next.ServeHTTP(w, r)
    })
}

func middlewareSetCookie(next http.Handler) http.Handler {
    fmt.Println("middlewareSetCookie")
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        c, err := r.Cookie(testCookieName)
        if err != nil || c.Value != testCookievalue {
            cookie := http.Cookie{
                Name:     testCookieName,
                Value:    testCookievalue,
                Path:     "/",
                HttpOnly: true,
                MaxAge:   0,
                Domain:   "localhost"}

            http.SetCookie(w, &cookie)
        }
        next.ServeHTTP(w, r)
    })
}

func middlewareCheckCookies(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("middlewareCheckCookies")
        fmt.Println(r.URL.String())

        c, err := r.Cookie(testCookieName)
        if err != nil || c.Value != testCookievalue {
            redirectURL := "/cookie"
            if r.URL.String() != redirectURL {
                http.Redirect(w, r, redirectURL, http.StatusTemporaryRedirect)
                return
            }
        }
        next.ServeHTTP(w, r)
    })
}

./views/cookie.html

{{define "cookie"}}no cookie set<a href="/">index</a>{{end}}

./views/index.html

{{define "index"}}<a href="/">index</a>{{end}}

Any clue to solving this?

Upvotes: 1

Views: 187

Answers (1)

Andrey Dyatlov
Andrey Dyatlov

Reputation: 1668

The problem with your code is that it builds lousy closures for handler functions. It would help if you did not use uncontrollably changing (in this case by the loop) variables to build a closure. You can add the following line of code to fix the problem:

    for k, v := range pages {
        k, v := k, v // <-- this line

With that, each handler function will have its own set of external variables.

To be honest, I don't really understand what your initial problem is. What does it mean -- "a cookie is ... not detected"?

Upvotes: 2

Related Questions