Search code examples
kotlingoogle-cloud-platformktorgoogle-cloud-load-balancer

ktor redirecting to 0.0.0.0 when doing an https redirect


I've added an http redirect to my Ktor application and it's redirecting to https://0.0.0.0 instead of to the actual domain's https

@ExperimentalTime
fun Application.module() {

    if (ENV.env != LOCAL) {
        install(ForwardedHeaderSupport)
        install(XForwardedHeaderSupport)
        install(HttpsRedirect)
    }

Intercepting the route and printing out the host

    routing {

            intercept(ApplicationCallPipeline.Features) {
            val host = this.context.request.host()

i seem to be getting 0:0:0:0:0:0:0:0 for the host

Do i need to add any special headers to Google Cloud's Load Balancer for this https redirect to work correctly? Seems like it's not picking up the correct host


Solution

  • So it seems either Google Cloud Load Balancer is sending the wrong headers or Ktor is reading the wrong headers or both.

    I've tried

        install(ForwardedHeaderSupport)
        install(XForwardedHeaderSupport)
        install(HttpsRedirect)
    

    or

        //install(ForwardedHeaderSupport)
        install(XForwardedHeaderSupport)
        install(HttpsRedirect)
    

    or

        install(ForwardedHeaderSupport)
        //install(XForwardedHeaderSupport)
        install(HttpsRedirect)
    

    or

        //install(ForwardedHeaderSupport)
        //install(XForwardedHeaderSupport)
        install(HttpsRedirect)
    

    All these combinations are working on another project, but that project is using an older version of Ktor (this being the one that was released with 1.4 rc) and that project is also using an older Google Cloud load balancer setup.

    So i've decided to roll my own. This line will log all the headers coming in with your request,

                    log.info(context.request.headers.toMap().toString())
    

    then just pick the relevant ones and build an https redirect:

    routing {
    
        intercept(ApplicationCallPipeline.Features) {
            if (ENV.env != LOCAL) {
    
                log.info(context.request.headers.toMap().toString())
    
                // workaround for call.request.host that contains the wrong host
                // and not redirecting properly to the correct https url
                val proto = call.request.header("X-Forwarded-Proto")
                val host = call.request.header("Host")
                val path = call.request.path()
    
                if (host == null || proto == null) {
                    log.error("Unknown host / port")
                } else if (proto == "http") {
                    val newUrl = "https://$host$path"
                    log.info("https redirecting to $newUrl")
    
                    // redirect browser
                    this.context.respondRedirect(url = newUrl, permanent = true)
                    this.finish()
                }
            }
        }