spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

The "Host" header is not preserved with "preserveHostHeader()" when the route's target URI starts with "https"

Open meletis opened this issue 2 years ago • 0 comments

I configured the following route with Gateway MVC.fn:

    private RouterFunction<ServerResponse> createDefaultRoute(String routeId) {
        return route(routeId)
                .route(RequestPredicates.path("/**"), http("http://httpbin.org"))
                .before(preserveHostHeader())
                .filter(this.handlerFilterFunctionBuilder.buildRateLimitFilter(routeId))
                .filter(this.handlerFilterFunctionBuilder.buildSecureHeadersFilter(routeId))
                .build();
    }

When I test it with http://localhost:8080/headers, then I correctly get that the Host header has the value localhost:

{
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Accept-Language": "en-US,el;q=0.5", 
    "Cookie": "[STRIPPED-OUT]", 
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"127.0.0.1:52521\"", 
    "Host": "localhost", 
    "Http2-Settings": "AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA", 
    "Sec-Fetch-Dest": "document", 
    "Sec-Fetch-Mode": "navigate", 
    "Sec-Fetch-Site": "cross-site", 
    "Transfer-Encoding": "chunked", 
    "Upgrade": "h2c", 
    "Upgrade-Insecure-Requests": "1", 
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0", 
    "X-Amzn-Trace-Id": "Root=1-65a52ebf-4150fa8f2b4495e91ff06def", 
    "X-Forwarded-Host": "localhost:8080"
  }
}

Then I change the route configuration to target https instead of http:

    private RouterFunction<ServerResponse> createDefaultRoute(String routeId) {
        return route(routeId)
                .route(RequestPredicates.path("/**"), http("https://httpbin.org"))
                .before(preserveHostHeader())
                .filter(this.handlerFilterFunctionBuilder.buildRateLimitFilter(routeId))
                .filter(this.handlerFilterFunctionBuilder.buildSecureHeadersFilter(routeId))
                .build();
    }

When I tested again, the remote application is receiving a Host header with value httpbin.org:

{
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Accept-Language": "en-US,el;q=0.5", 
    "Cookie": "[STRIPPED-OUT]", 
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"127.0.0.1:52580\"", 
    "Host": "httpbin.org", 
    "Sec-Fetch-Dest": "document", 
    "Sec-Fetch-Mode": "navigate", 
    "Sec-Fetch-Site": "cross-site", 
    "Upgrade-Insecure-Requests": "1", 
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0", 
    "X-Amzn-Trace-Id": "Root=1-65a52fae-595a56ec0688739134637885", 
    "X-Forwarded-Host": "localhost:8080"
  }
}

However, I would expect the Host header on the application side to continue to be localhost, since the preserveHostHeader() filter is used.

I took a look in the code but couldn't find any flaws, so I feel like I'm missing something, although this does look like a bug to me.

meletis avatar Jan 15 '24 13:01 meletis