View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server;
20  
21  import java.net.InetSocketAddress;
22  
23  import javax.servlet.ServletRequest;
24  
25  import org.eclipse.jetty.http.HttpFields;
26  import org.eclipse.jetty.http.HttpHeader;
27  import org.eclipse.jetty.http.HttpScheme;
28  import org.eclipse.jetty.server.HttpChannelConfig.Customizer;
29  
30  public class ForwardedRequestCustomizer implements Customizer
31  {
32      private String _hostHeader;
33      private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
34      private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
35      private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
36      private String _forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
37      private String _forwardedCipherSuiteHeader;
38      private String _forwardedSslSessionIdHeader;
39      
40  
41      /* ------------------------------------------------------------ */
42      public String getHostHeader()
43      {
44          return _hostHeader;
45      }
46  
47      /* ------------------------------------------------------------ */
48      /**
49       * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
50       * This value is only used if {@link #isForwarded()} is true.
51       *
52       * @param hostHeader
53       *            The value of the host header to force.
54       */
55      public void setHostHeader(String hostHeader)
56      {
57          _hostHeader = hostHeader;
58      }
59  
60      /* ------------------------------------------------------------ */
61      /*
62       *
63       * @see #setForwarded(boolean)
64       */
65      public String getForwardedHostHeader()
66      {
67          return _forwardedHostHeader;
68      }
69  
70      /* ------------------------------------------------------------ */
71      /**
72       * @param forwardedHostHeader
73       *            The header name for forwarded hosts (default x-forwarded-host)
74       * @see #setForwarded(boolean)
75       */
76      public void setForwardedHostHeader(String forwardedHostHeader)
77      {
78          _forwardedHostHeader = forwardedHostHeader;
79      }
80  
81      /* ------------------------------------------------------------ */
82      /**
83       * @return the header name for forwarded server.
84       * @see #setForwarded(boolean)
85       */
86      public String getForwardedServerHeader()
87      {
88          return _forwardedServerHeader;
89      }
90  
91      /* ------------------------------------------------------------ */
92      /**
93       * @param forwardedServerHeader
94       *            The header name for forwarded server (default x-forwarded-server)
95       * @see #setForwarded(boolean)
96       */
97      public void setForwardedServerHeader(String forwardedServerHeader)
98      {
99          _forwardedServerHeader = forwardedServerHeader;
100     }
101 
102     /* ------------------------------------------------------------ */
103     /**
104      * @return the forwarded for header
105      * @see #setForwarded(boolean)
106      */
107     public String getForwardedForHeader()
108     {
109         return _forwardedForHeader;
110     }
111 
112     /* ------------------------------------------------------------ */
113     /**
114      * @param forwardedRemoteAddressHeader
115      *            The header name for forwarded for (default x-forwarded-for)
116      * @see #setForwarded(boolean)
117      */
118     public void setForwardedForHeader(String forwardedRemoteAddressHeader)
119     {
120         _forwardedForHeader = forwardedRemoteAddressHeader;
121     }
122 
123     /* ------------------------------------------------------------ */
124     /**
125      * Get the forwardedProtoHeader.
126      *
127      * @return the forwardedProtoHeader (default X-Forwarded-For)
128      * @see #setForwarded(boolean)
129      */
130     public String getForwardedProtoHeader()
131     {
132         return _forwardedProtoHeader;
133     }
134 
135     /* ------------------------------------------------------------ */
136     /**
137      * Set the forwardedProtoHeader.
138      *
139      * @param forwardedProtoHeader
140      *            the forwardedProtoHeader to set (default X-Forwarded-For)
141      * @see #setForwarded(boolean)
142      */
143     public void setForwardedProtoHeader(String forwardedProtoHeader)
144     {
145         _forwardedProtoHeader = forwardedProtoHeader;
146     }
147 
148     /* ------------------------------------------------------------ */
149     /**
150      * @return The header name holding a forwarded cipher suite (default null)
151      */
152     public String getForwardedCipherSuiteHeader()
153     {
154         return _forwardedCipherSuiteHeader;
155     }
156 
157     /* ------------------------------------------------------------ */
158     /**
159      * @param forwardedCipherSuite
160      *            The header name holding a forwarded cipher suite (default null)
161      */
162     public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
163     {
164         _forwardedCipherSuiteHeader = forwardedCipherSuite;
165     }
166 
167     /* ------------------------------------------------------------ */
168     /**
169      * @return The header name holding a forwarded SSL Session ID (default null)
170      */
171     public String getForwardedSslSessionIdHeader()
172     {
173         return _forwardedSslSessionIdHeader;
174     }
175 
176     /* ------------------------------------------------------------ */
177     /**
178      * @param forwardedSslSessionId
179      *            The header name holding a forwarded SSL Session ID (default null)
180      */
181     public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
182     {
183         _forwardedSslSessionIdHeader = forwardedSslSessionId;
184     }
185 
186     /* ------------------------------------------------------------ */
187     @Override
188     public void customize(Connector connector, HttpChannelConfig config, Request request)
189     {
190         HttpFields httpFields = request.getHttpFields();
191 
192         // Do SSL first
193         if (getForwardedCipherSuiteHeader()!=null)
194         {
195             String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
196             if (cipher_suite!=null)
197                 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
198         }
199         if (getForwardedSslSessionIdHeader()!=null)
200         {
201             String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
202             if(ssl_session_id!=null)
203             {
204                 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
205                 request.setScheme(HttpScheme.HTTPS.asString());
206             }
207         }
208 
209         // Retrieving headers from the request
210         String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader());
211         String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader());
212         String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader());
213         String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader());
214 
215         if (_hostHeader != null)
216         {
217             // Update host header
218             httpFields.put(HttpHeader.HOST.toString(),_hostHeader);
219             request.setServerName(null);
220             request.setServerPort(-1);
221             request.getServerName();
222         }
223         else if (forwardedHost != null)
224         {
225             // Update host header
226             httpFields.put(HttpHeader.HOST.toString(),forwardedHost);
227             request.setServerName(null);
228             request.setServerPort(-1);
229             request.getServerName();
230         }
231         else if (forwardedServer != null)
232         {
233             // Use provided server name
234             request.setServerName(forwardedServer);
235         }
236 
237         if (forwardedFor != null)
238         {
239             request.setRemoteAddr(new InetSocketAddress(forwardedFor,request.getRemotePort()));
240         }
241 
242         if (forwardedProto != null)
243         {
244             request.setScheme(forwardedProto);
245             if (forwardedProto.equals(config.getSecureScheme()))
246                 request.setSecure(true);
247         }
248     }
249 
250     /* ------------------------------------------------------------ */
251     protected String getLeftMostFieldValue(HttpFields fields, String header)
252     {
253         if (header == null)
254             return null;
255 
256         String headerValue = fields.getStringField(header);
257 
258         if (headerValue == null)
259             return null;
260 
261         int commaIndex = headerValue.indexOf(',');
262 
263         if (commaIndex == -1)
264         {
265             // Single value
266             return headerValue;
267         }
268 
269         // The left-most value is the farthest downstream client
270         return headerValue.substring(0,commaIndex);
271     }
272 
273 
274     /* ------------------------------------------------------------ */
275     @Override
276     public String toString()
277     {
278         return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
279     }
280 }