Gin: Redirect all HTTP to it's HTTPS equivalent

Created on 14 Jun 2016  路  5Comments  路  Source: gin-gonic/gin

I'm currently running my API fully in HTTPS. This is ok, but now I also want to add some front-end pages to my system. Most people land on that front-end by just typing www.mydomain.com (HTTP). How can I set Gin to behave so that all HTTP calls will be redirected to their HTTPS equivalent? So not only "/", but all other paths too.

Most helpful comment

Just to add the example here after has tested it with github.com/unrolled/secure.
Some note to highlight is, when client is first visiting the server, gin will throw
[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 301 with 200, due to http.Redirect is initiated by secure, but gin is not aware of it. Feel free to suggest if you have any way to improve this further.

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/unrolled/secure"
)

func main() {
    secureFunc := func() gin.HandlerFunc {
        return func(c *gin.Context) {
            secureMiddleware := secure.New(secure.Options{
                SSLRedirect: true,
                SSLHost:     "localhost:8888",
            })
            err := secureMiddleware.Process(c.Writer, c.Request)

            // If there was an error, do not continue.
            if err != nil {
                return
            }

            c.Next()
        }
    }()

    router := gin.Default()
    router.Use(secureFunc)

    router.GET("/", func(c *gin.Context) {
        c.String(200, "X-Frame-Options header is now `DENY`.")
    })

    // HTTP
    go router.Run(":8066")

    router.RunTLS(":8888", "server.pem", "server.key")
}

All 5 comments

@Allendar to start, you will need 2 sockets/ports in separate go routines to handle this behavior. I don't know any easy way, although possible, to listen 2 different protocols on the same port/socket, although it wouldn't follow convention.

After having two servers listening on 80 and 443 respectively, you will need to redirect every request.
There is two alternatives as far as I know:

  • 1st: only redirect HEAD and GET requests. You will need to create a handler for both verbs, with a wildcard parameter, then return a redirect with a 301/302
  • 2nd: redirect everything including POST. Same as above but, using 307. This code specifies that a manual retry must be done by the client so I can't know how your client will behave and if it follows RFC.

Bellow there is an small example:

package main

import "github.com/gin-gonic/gin"

func main() {
    httpsRouter := gin.Default()
    httpRouter := gin.Default()

    ...

    httpRouter.GET("/*path", func (c *gin.Context) {
        c.Redirect(302, "https://yourdomain/" + c.Param("variable"))
    })

    ...

    go httpsRouter.Run(":443", certFile, keyFile)

    httpRouter.Run(":80")

}

There is an another way to redirect; using a middleware which has SSLRedircet option.
For example, https://github.com/gin-gonic/contrib/tree/master/secure, https://github.com/unrolled/secure.

Thank you for your responses! https://github.com/unrolled/secure seems prefect for the job. Just need to figure out how to redirect without losing the request-type.

Just to add the example here after has tested it with github.com/unrolled/secure.
Some note to highlight is, when client is first visiting the server, gin will throw
[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 301 with 200, due to http.Redirect is initiated by secure, but gin is not aware of it. Feel free to suggest if you have any way to improve this further.

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/unrolled/secure"
)

func main() {
    secureFunc := func() gin.HandlerFunc {
        return func(c *gin.Context) {
            secureMiddleware := secure.New(secure.Options{
                SSLRedirect: true,
                SSLHost:     "localhost:8888",
            })
            err := secureMiddleware.Process(c.Writer, c.Request)

            // If there was an error, do not continue.
            if err != nil {
                return
            }

            c.Next()
        }
    }()

    router := gin.Default()
    router.Use(secureFunc)

    router.GET("/", func(c *gin.Context) {
        c.String(200, "X-Frame-Options header is now `DENY`.")
    })

    // HTTP
    go router.Run(":8066")

    router.RunTLS(":8888", "server.pem", "server.key")
}

@kenng maybe add a wrapper to unrolled/secure, so when it issues a redirect. I just openned a PR https://github.com/unrolled/secure/pull/9

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xpbliss picture xpbliss  路  3Comments

kekemuyu picture kekemuyu  路  3Comments

rawoke083 picture rawoke083  路  3Comments

CodingPapi picture CodingPapi  路  3Comments

oryband picture oryband  路  3Comments