Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-756

Redirect Location header ignores X-Forwarded-Host and X-Forwarded-Port but honours X-Forwarded-Proto

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 1.3.23.Final, 1.4.0.CR2
    • None
    • None

      The effect of a request's X-Forwarded-* headers appears to be inconsistent when sending a redirect. Here's a small server that should illustrate the problem:

      package com.example;
      
      import java.io.IOException;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      import io.undertow.Handlers;
      import io.undertow.Undertow;
      import io.undertow.servlet.Servlets;
      import io.undertow.servlet.api.DeploymentInfo;
      import io.undertow.servlet.api.DeploymentManager;
      
      public class RedirectServer {
      
      	public static void main(String[] args) throws ServletException {
      		DeploymentInfo servletBuilder = Servlets.deployment()
      				.setClassLoader(RedirectServer.class.getClassLoader())
      				.setContextPath("/myapp")
      				.setDeploymentName("test.war")
      				.addServlets(
      						Servlets.servlet("redirect", RedirectServlet.class).addMapping("/*"));
      
      		DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder);
      		manager.deploy();
      		Undertow server = Undertow.builder()
      				.addHttpListener(8080, "localhost")
      				.setHandler(Handlers.path(Handlers.proxyPeerAddress(manager.start())))
      				.build();
      		server.start();
      	}
      
      	@SuppressWarnings("serial")
      	static class RedirectServlet extends HttpServlet {
      
      		@Override
      		protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      			resp.sendRedirect("/redirected");
      		}
      
      	}
      
      }
      

      Making a request to /myapp/redirect with X-Forwarded-* headers results in a 302 response as expected but the Location header is not as expected:

      curl -v 127.0.0.1:8080/myapp/redirect -H 'X-Forwarded-Proto: https' -H 'X-Forwarded-Host: api.example.com' -H 'X-Forwarded-Port: 443'
      *   Trying 127.0.0.1...
      * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
      > GET /myapp/redirect HTTP/1.1
      > Host: 127.0.0.1:8080
      > User-Agent: curl/7.46.0
      > Accept: */*
      > X-Forwarded-Proto: https
      > X-Forwarded-Host: api.example.com
      > X-Forwarded-Port: 443
      >
      < HTTP/1.1 302 Found
      < Connection: keep-alive
      < Location: https://127.0.0.1:8080/redirected
      < Content-Length: 0
      < Date: Thu, 30 Jun 2016 10:04:42 GMT
      <
      * Connection #0 to host 127.0.0.1 left intact
      

      Given this request, I would expect the Location header to be https://api.example.com/redirected but it's https://127.0.0.1:8080. The scheme is as expected (X-Forwarded-Proto has been honoured) but the host and port are not (X-Forwarded-Host and X-Forwarded-Port have been ignored).

      FWIW, Jetty 9.3 produces a Location header based on all three X-Forwarded-* headers.

              sdouglas1@redhat.com Stuart Douglas (Inactive)
              ankinson Andy Wilkinson (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: