Index: modules/jetty/src/test/java/org/mortbay/jetty/CheckReverseProxyHeadersTest.java
===================================================================
--- modules/jetty/src/test/java/org/mortbay/jetty/CheckReverseProxyHeadersTest.java	(révision 0)
+++ modules/jetty/src/test/java/org/mortbay/jetty/CheckReverseProxyHeadersTest.java	(révision 0)
@@ -0,0 +1,165 @@
+package org.mortbay.jetty;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.mortbay.jetty.handler.AbstractHandler;
+
+/**
+ * Test {@link AbstractConnector#checkReverseProxyHeaders(org.mortbay.io.EndPoint, Request)}.
+ */
+public class CheckReverseProxyHeadersTest extends TestCase
+{
+    Server server=new Server();
+    LocalConnector connector=new LocalConnector();
+
+    /**
+     * Constructor for CheckReverseProxyHeadersTest.
+     * @param name test case name.
+     */
+    public CheckReverseProxyHeadersTest(String name)
+    {
+        super(name);
+    }
+    
+    public void testCheckReverseProxyHeaders() throws Exception
+    {
+        // Classic ProxyPass from example.com:80 to localhost:8080
+        testRequest("Host: localhost:8080\n" +
+                    "X-Forwarded-For: 10.20.30.40\n" +
+                    "X-Forwarded-Host: example.com\n" +
+                    "X-Forwarded-Server: example.com", new RequestValidator()
+        {
+            public void validate(HttpServletRequest request)
+            {
+                assertEquals("example.com", request.getServerName());
+                assertEquals(80, request.getServerPort());
+                assertEquals("10.20.30.40", request.getRemoteAddr());
+                assertEquals("10.20.30.40", request.getRemoteHost());
+                assertEquals("example.com", request.getHeader("Host"));
+            }
+        });
+        
+        // ProxyPass from example.com:81 to localhost:8080
+        testRequest("Host: localhost:8080\n" +
+                    "X-Forwarded-For: 10.20.30.40\n" +
+                    "X-Forwarded-Host: example.com:81\n" +
+                    "X-Forwarded-Server: example.com", new RequestValidator()
+        {
+            public void validate(HttpServletRequest request)
+            {
+                assertEquals("example.com", request.getServerName());
+                assertEquals(81, request.getServerPort());
+                assertEquals("10.20.30.40", request.getRemoteAddr());
+                assertEquals("10.20.30.40", request.getRemoteHost());
+                assertEquals("example.com:81", request.getHeader("Host"));
+            }
+        });
+        
+        // Multiple ProxyPass from example.com:80 to rp.example.com:82 to localhost:8080
+        testRequest("Host: localhost:8080\n" +
+                    "X-Forwarded-For: 10.20.30.40, 10.0.0.1\n" +
+                    "X-Forwarded-Host: example.com, rp.example.com:82\n" +
+                    "X-Forwarded-Server: example.com, rp.example.com", new RequestValidator()
+        {
+            public void validate(HttpServletRequest request)
+            {
+                assertEquals("example.com", request.getServerName());
+                assertEquals(80, request.getServerPort());
+                assertEquals("10.20.30.40", request.getRemoteAddr());
+                assertEquals("10.20.30.40", request.getRemoteHost());
+                assertEquals("example.com", request.getHeader("Host"));
+            }
+        });
+    }
+
+    private void testRequest(String headers, RequestValidator requestValidator) throws Exception
+    {
+        Server server = new Server();
+        LocalConnector connector = new LocalConnector();
+        
+        // Activate reverse proxy headers checking
+        connector.setCheckReverseProxyHeaders(true);
+        
+        server.setConnectors(new Connector[] {connector});
+        ValidationHandler validationHandler = new ValidationHandler(requestValidator);
+        server.setHandler(validationHandler);
+        
+        try
+        {
+            server.start();
+            connector.getResponses("GET / HTTP/1.1\n" + headers + "\n\n");
+            
+            Error error = validationHandler.getError();
+            
+            if (error != null)
+            {
+                throw error;
+            }
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    /**
+     * Interface for validate a wrapped request.
+     */
+    private static interface RequestValidator
+    {
+        /**
+         * Validate the current request.
+         * @param request the request.
+         */
+        void validate(HttpServletRequest request);
+    }
+
+    /**
+     * Handler for validation.
+     */
+    private static class ValidationHandler extends AbstractHandler
+    {
+        private RequestValidator _requestValidator;
+        private Error _error;
+        
+        /**
+         * Create the validation handler with a request validator.
+         * @param requestValidator the request validator.
+         */
+        public ValidationHandler(RequestValidator requestValidator)
+        {
+            _requestValidator = requestValidator;
+        }
+        
+        /**
+         * Retrieve the validation error.
+         * @return the validation error or <code>null</code> if there was no error.
+         */
+        public Error getError()
+        {
+            return _error;
+        }
+        
+        public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException
+        {
+            try
+            {
+                _requestValidator.validate(request);
+            }
+            catch (Error e)
+            {
+                _error = e;
+            }
+            catch (Throwable e)
+            {
+                _error = new Error(e);
+            }
+        }
+    }
+}
Index: modules/jetty/src/main/java/org/mortbay/jetty/AbstractConnector.java
===================================================================
--- modules/jetty/src/main/java/org/mortbay/jetty/AbstractConnector.java	(révision 2758)
+++ modules/jetty/src/main/java/org/mortbay/jetty/AbstractConnector.java	(copie de travail)
@@ -16,7 +16,9 @@
 package org.mortbay.jetty;
 
 import java.io.IOException;
+import java.net.InetAddress;
 import java.net.Socket;
+import java.net.UnknownHostException;
 
 import org.mortbay.component.LifeCycle;
 import org.mortbay.io.EndPoint;
@@ -33,6 +35,7 @@
  * <li>Buffer management</li>
  * <li>Socket configuration</li>
  * <li>Base acceptor thread</li>
+ * <li>Optional reverse proxy headers checking</li>
  * </ul>
  * 
  * @author gregw
@@ -54,6 +57,10 @@
     private int _acceptors=1;
     private int _acceptorPriorityOffset=0;
     private boolean _useDNS;
+    private boolean _checkReverseProxyHeaders;
+    private String _forwardedHostHeader = "X-Forwarded-Host";             // default to mod_proxy_http header
+    private String _forwardedServerHeader = "X-Forwarded-Server";         // default to mod_proxy_http header
+    private String _forwardedRemoteAddressHeader = "X-Forwarded-For";     // default to mod_proxy_http header
     private boolean _reuseAddress=true;
     
     protected int _maxIdleTime=200000; 
@@ -360,10 +367,122 @@
     /* ------------------------------------------------------------ */
     public void customize(EndPoint endpoint, Request request)
         throws IOException
-    {      
+    {
+        if (getCheckReverseProxyHeaders())
+        {
+            checkReverseProxyHeaders(endpoint, request);
+        }
     }
-    
+
     /* ------------------------------------------------------------ */
+    protected void checkReverseProxyHeaders(EndPoint endpoint, Request request)
+        throws IOException
+    {
+        HttpFields httpFields = request.getConnection().getRequestFields();
+        
+        // Retrieving headers from the request
+        String hostHeader = getLeftMostValue(httpFields.getStringField(getForwardedHostHeader()));
+        String server = getLeftMostValue(httpFields.getStringField(getForwardedServerHeader()));
+        String remoteAddr = getLeftMostValue(httpFields.getStringField(getForwardedRemoteAddressHeader()));
+        
+        if (hostHeader != null)
+        {
+            // Update host header	
+            httpFields.put(HttpHeaders.HOST_BUFFER, hostHeader);
+            // Parse this header
+            int colonIndex = hostHeader.indexOf(":");
+            if (colonIndex == -1)
+            {
+                // Prefer host name dedicated header
+                if (server != null)
+                {
+                    request.setServerName(server);
+                }
+                else
+                {
+                    request.setServerName(hostHeader);
+                }
+                
+                // TODO handle https protocol
+                request.setServerPort(80);
+            }
+            else
+            {
+                // Prefer host name dedicated header
+                if (server != null)
+                {
+                    request.setServerName(server);
+                }
+                else
+                {
+                    request.setServerName(hostHeader.substring(0, colonIndex));
+                }
+                
+                String serverPort = hostHeader.substring(colonIndex + 1);
+                
+                try
+                {
+                    request.setServerPort(Integer.valueOf(serverPort).intValue());
+                }
+                catch (NumberFormatException e)
+                {
+                    throw new HttpException(HttpStatus.ORDINAL_400_Bad_Request, "Bad Request Invalid X-Forwarded-Host: '" + server + "'", e); 
+                }
+            }
+        }
+        else if (server != null)
+        {
+            // Use provided server name
+            request.setServerName(server);
+        }
+        
+        if (remoteAddr != null)
+        {
+            request.setRemoteAddr(remoteAddr);
+            InetAddress inetAddress = null;
+            
+            if (_useDNS)
+            {
+                try
+                {
+                    inetAddress = InetAddress.getByName(remoteAddr);
+                }
+                catch (UnknownHostException e)
+                {
+                    Log.ignore(e);
+                }
+            }
+            
+            if (inetAddress != null)
+            {
+                request.setRemoteHost(inetAddress.getHostName());
+            }
+            else
+            {
+                // Use remote address as the remote host
+                request.setRemoteHost(remoteAddr);
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    protected String getLeftMostValue(String headerValue) {
+        if (headerValue == null)
+            return null;
+        
+        int commaIndex = headerValue.indexOf(',');
+        
+        if (commaIndex == -1)
+        {
+            // Single value
+            return headerValue;
+        }
+
+        // The left-most value is the farthest downstream client
+        return headerValue.substring(0, commaIndex);
+    }
+
+    /* ------------------------------------------------------------ */
     public void persist(EndPoint endpoint)
         throws IOException
     {      
@@ -489,6 +608,56 @@
     }
     
     /* ------------------------------------------------------------ */
+    public boolean getCheckReverseProxyHeaders()
+    {
+        return _checkReverseProxyHeaders;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void setCheckReverseProxyHeaders(boolean check)
+    {
+        if (check)
+            Log.debug("Checking reverse proxy headers for "+this);
+        _checkReverseProxyHeaders=check;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String getForwardedHostHeader()
+    {
+        return _forwardedHostHeader;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void setForwardedHostHeader(String forwardedHostHeader)
+    {
+        _forwardedHostHeader=forwardedHostHeader;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String getForwardedServerHeader()
+    {
+        return _forwardedServerHeader;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void setForwardedServerHeader(String forwardedServerHeader)
+    {
+        _forwardedServerHeader=forwardedServerHeader;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String getForwardedRemoteAddressHeader()
+    {
+        return _forwardedRemoteAddressHeader;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void setForwardedRemoteAddressHeader(String forwardedRemoteAddressHeade)
+    {
+        _forwardedRemoteAddressHeader=forwardedRemoteAddressHeade;
+    }
+    
+    /* ------------------------------------------------------------ */
     public String toString()
     {
         String name = this.getClass().getName();
Index: modules/jetty/src/main/java/org/mortbay/jetty/Request.java
===================================================================
--- modules/jetty/src/main/java/org/mortbay/jetty/Request.java	(révision 2758)
+++ modules/jetty/src/main/java/org/mortbay/jetty/Request.java	(copie de travail)
@@ -114,6 +114,8 @@
     private String _characterEncoding;
     private String _queryEncoding;
     private String _serverName;
+    private String _remoteAddr;
+    private String _remoteHost;
     private String _method;
     private String _pathInfo;
     private int _port;
@@ -863,6 +865,8 @@
      */
     public String getRemoteAddr()
     {
+        if (_remoteAddr != null)
+            return _remoteAddr;	
         return _endp==null?null:_endp.getRemoteAddr();
     }
 
@@ -873,8 +877,14 @@
     public String getRemoteHost()
     {
         if (_dns)
+        {
+            if (_remoteHost != null)
+            {
+                return _remoteHost;
+            }
             return _endp==null?null:_endp.getRemoteHost();
-        return _endp==null?null:_endp.getRemoteAddr();
+        }
+        return getRemoteAddr();
     }
 
     /* ------------------------------------------------------------ */
@@ -1437,7 +1447,7 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param host The host to set.
+     * @param port The port to set.
      */
     public void setServerPort(int port)
     {
@@ -1446,6 +1456,24 @@
     
     /* ------------------------------------------------------------ */
     /**
+     * @param addr The address to set.
+     */
+    public void setRemoteAddr(String addr)
+    {
+        _remoteAddr = addr;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param host The host to set.
+     */
+    public void setRemoteHost(String host)
+    {
+        _remoteHost = host;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
      * @return Returns the uri.
      */
     public HttpURI getUri()

