how to redirect http to https in Gorilla Mux?
Asked Answered
S

2

7

I am developing a golang application and I am using Gorilla Mux and i want to redirect HTTP requests to HTTPS

here is what i have so far

package main

import (
    "net/http"

    "github.com/gorilla/mux"
    "github.com/zolamk/deviant/handlers"
    "github.com/zolamk/deviant/lib"
)

func main() {

    router := mux.NewRouter()
    // this is where i am trying to redirect
    router.PathPrefix("/").Schemes("HTTP").HandlerFunc(func(res http.ResponseWriter, req *http.Request) {

        http.Redirect(res, req, fmt.Sprintf("https://%s", req.URL), http.StatusSeeOther)

    })

    router.Handle("/", handlers.ContextHandler(handlers.Index)).Methods("GET")

    router.Handle("/register/", handlers.ContextHandler(handlers.Register)).Methods("GET")

    router.Handle("/register/", handlers.ContextHandler(handlers.RegisterPost)).Methods("POST")

    router.Handle("/login/", handlers.ContextHandler(handlers.Login)).Methods("GET")

    router.Handle("/login/", handlers.ContextHandler(handlers.LoginPost)).Methods("POST")

    router.Handle("/logout/", handlers.ContextHandler(handlers.Logout)).Methods("GET")

    if lib.Settings.ServeStatic {

        router.PathPrefix("/public/").Handler(http.FileServer(http.Dir("./")))

    }

    router.NotFoundHandler = handlers.ContextHandler(handlers.NotFound)

    log.Printf("Deviant running @ http://%s\n", lib.Settings.Address)

    loggedRouter := handlers.LoggedRouter(os.Stdout, router)

    log.Fatal(http.ListenAndServe(lib.Settings.Address, loggedRouter))

}

so like i said before how do i redirect HTTP traffic to HTTPS without affecting my other routes? Thank You.

Skilken answered 12/1, 2017 at 15:29 Comment(0)
S
2

What I ended up doing was that, I wrote a middleware that redirects HTTP requests to HTTPS

func RedirectToHTTPSRouter(next http.Handler) http.Handler {
    return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        proto := req.Header.Get("x-forwarded-proto")
        if proto == "http" || proto == "HTTP" {
            http.Redirect(res, req, fmt.Sprintf("https://%s%s", req.Host, req.URL), http.StatusPermanentRedirect)
            return
        }

        next.ServeHTTP(res, req)

    })
}

func main() {

    router := mux.NewRouter()

    httpsRouter := RedirectToHTTPSRouter(router)

    log.Fatal(http.ListenAndServe(lib.Settings.Address, httpsRouter))

}
Skilken answered 14/1, 2017 at 7:18 Comment(3)
can someone explain why OP's self-submitted answer was downvoted?Sphygmoid
@Sphygmoid TheHippo's answer is what is necessary, because a http server can only listen on one port so you need one for the HTTP port and one for the HTTPS port. Basically, there are 3 possibilities here: 1. OP was using only a HTTPS listener, in which case the middleware never does anything because it never sees HTTP. 2. OP was using only a HTTP listener, in which case the redirect results in a connection refused. Or...Phillida
@Sphygmoid ...3. OP had 2 listeners as TheHippo demonstrates, and if they used the middleware on the HTTP listener this theoretically would have worked - however, since this listener is only HTTP, this code will always redirect and next will never be reached, so it's redundant to use a router with middleware here.Phillida
C
16

Start another HTTP handler on the other port in a separate go routine

go http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
}))
Cato answered 12/1, 2017 at 15:39 Comment(2)
In case nginx server is used as a reverse proxy, it's better to manager this in the nginx configuration.Ensheathe
This is exactly what I need for my google compute server.Nitrobacteria
S
2

What I ended up doing was that, I wrote a middleware that redirects HTTP requests to HTTPS

func RedirectToHTTPSRouter(next http.Handler) http.Handler {
    return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        proto := req.Header.Get("x-forwarded-proto")
        if proto == "http" || proto == "HTTP" {
            http.Redirect(res, req, fmt.Sprintf("https://%s%s", req.Host, req.URL), http.StatusPermanentRedirect)
            return
        }

        next.ServeHTTP(res, req)

    })
}

func main() {

    router := mux.NewRouter()

    httpsRouter := RedirectToHTTPSRouter(router)

    log.Fatal(http.ListenAndServe(lib.Settings.Address, httpsRouter))

}
Skilken answered 14/1, 2017 at 7:18 Comment(3)
can someone explain why OP's self-submitted answer was downvoted?Sphygmoid
@Sphygmoid TheHippo's answer is what is necessary, because a http server can only listen on one port so you need one for the HTTP port and one for the HTTPS port. Basically, there are 3 possibilities here: 1. OP was using only a HTTPS listener, in which case the middleware never does anything because it never sees HTTP. 2. OP was using only a HTTP listener, in which case the redirect results in a connection refused. Or...Phillida
@Sphygmoid ...3. OP had 2 listeners as TheHippo demonstrates, and if they used the middleware on the HTTP listener this theoretically would have worked - however, since this listener is only HTTP, this code will always redirect and next will never be reached, so it's redundant to use a router with middleware here.Phillida

© 2022 - 2024 — McMap. All rights reserved.