2 // ========================================================================
3 // Copyright (c) 1995-2016 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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.server;
21 import java.net.InetSocketAddress;
23 import org.eclipse.jetty.http.HttpFields;
24 import org.eclipse.jetty.http.HttpHeader;
25 import org.eclipse.jetty.http.HttpScheme;
26 import org.eclipse.jetty.server.HttpConfiguration.Customizer;
29 /* ------------------------------------------------------------ */
30 /** Customize Requests for Proxy Forwarding.
32 * This customizer looks at at HTTP request for headers that indicate
33 * it has been forwarded by one or more proxies. Specifically handled are:
35 * <li>X-Forwarded-Host</li>
36 * <li>X-Forwarded-Server</li>
37 * <li>X-Forwarded-For</li>
38 * <li>X-Forwarded-Proto</li>
40 * <p>If these headers are present, then the {@link Request} object is updated
41 * so that the proxy is not seen as the other end point of the connection on which
42 * the request came</p>
43 * <p>Headers can also be defined so that forwarded SSL Session IDs and Cipher
44 * suites may be customised</p>
45 * @see <a href="http://en.wikipedia.org/wiki/X-Forwarded-For">Wikipedia: X-Forwarded-For</a>
47 public class ForwardedRequestCustomizer implements Customizer
49 private String _hostHeader;
50 private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
51 private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
52 private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
53 private String _forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
54 private String _forwardedCipherSuiteHeader;
55 private String _forwardedSslSessionIdHeader;
58 /* ------------------------------------------------------------ */
59 public String getHostHeader()
64 /* ------------------------------------------------------------ */
66 * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
69 * The value of the host header to force.
71 public void setHostHeader(String hostHeader)
73 _hostHeader = hostHeader;
76 /* ------------------------------------------------------------ */
79 * @see #setForwarded(boolean)
81 public String getForwardedHostHeader()
83 return _forwardedHostHeader;
86 /* ------------------------------------------------------------ */
88 * @param forwardedHostHeader
89 * The header name for forwarded hosts (default x-forwarded-host)
91 public void setForwardedHostHeader(String forwardedHostHeader)
93 _forwardedHostHeader = forwardedHostHeader;
96 /* ------------------------------------------------------------ */
98 * @return the header name for forwarded server.
100 public String getForwardedServerHeader()
102 return _forwardedServerHeader;
105 /* ------------------------------------------------------------ */
107 * @param forwardedServerHeader
108 * The header name for forwarded server (default x-forwarded-server)
110 public void setForwardedServerHeader(String forwardedServerHeader)
112 _forwardedServerHeader = forwardedServerHeader;
115 /* ------------------------------------------------------------ */
117 * @return the forwarded for header
119 public String getForwardedForHeader()
121 return _forwardedForHeader;
124 /* ------------------------------------------------------------ */
126 * @param forwardedRemoteAddressHeader
127 * The header name for forwarded for (default x-forwarded-for)
129 public void setForwardedForHeader(String forwardedRemoteAddressHeader)
131 _forwardedForHeader = forwardedRemoteAddressHeader;
134 /* ------------------------------------------------------------ */
136 * Get the forwardedProtoHeader.
138 * @return the forwardedProtoHeader (default X-Forwarded-For)
140 public String getForwardedProtoHeader()
142 return _forwardedProtoHeader;
145 /* ------------------------------------------------------------ */
147 * Set the forwardedProtoHeader.
149 * @param forwardedProtoHeader
150 * the forwardedProtoHeader to set (default X-Forwarded-For)
152 public void setForwardedProtoHeader(String forwardedProtoHeader)
154 _forwardedProtoHeader = forwardedProtoHeader;
157 /* ------------------------------------------------------------ */
159 * @return The header name holding a forwarded cipher suite (default null)
161 public String getForwardedCipherSuiteHeader()
163 return _forwardedCipherSuiteHeader;
166 /* ------------------------------------------------------------ */
168 * @param forwardedCipherSuite
169 * The header name holding a forwarded cipher suite (default null)
171 public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
173 _forwardedCipherSuiteHeader = forwardedCipherSuite;
176 /* ------------------------------------------------------------ */
178 * @return The header name holding a forwarded SSL Session ID (default null)
180 public String getForwardedSslSessionIdHeader()
182 return _forwardedSslSessionIdHeader;
185 /* ------------------------------------------------------------ */
187 * @param forwardedSslSessionId
188 * The header name holding a forwarded SSL Session ID (default null)
190 public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
192 _forwardedSslSessionIdHeader = forwardedSslSessionId;
195 /* ------------------------------------------------------------ */
197 public void customize(Connector connector, HttpConfiguration config, Request request)
199 HttpFields httpFields = request.getHttpFields();
202 if (getForwardedCipherSuiteHeader()!=null)
204 String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
205 if (cipher_suite!=null)
206 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
208 if (getForwardedSslSessionIdHeader()!=null)
210 String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
211 if(ssl_session_id!=null)
213 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
214 request.setScheme(HttpScheme.HTTPS.asString());
218 // Retrieving headers from the request
219 String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader());
220 String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader());
221 String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader());
222 String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader());
224 if (_hostHeader != null)
226 // Update host header
227 httpFields.put(HttpHeader.HOST.toString(),_hostHeader);
228 request.setServerName(null);
229 request.setServerPort(-1);
230 request.getServerName();
232 else if (forwardedHost != null)
234 // Update host header
235 httpFields.put(HttpHeader.HOST.toString(),forwardedHost);
236 request.setServerName(null);
237 request.setServerPort(-1);
238 request.getServerName();
240 else if (forwardedServer != null)
242 // Use provided server name
243 request.setServerName(forwardedServer);
246 if (forwardedFor != null)
248 request.setRemoteAddr(InetSocketAddress.createUnresolved(forwardedFor,request.getRemotePort()));
251 if (forwardedProto != null)
253 request.setScheme(forwardedProto);
254 if (forwardedProto.equals(config.getSecureScheme()))
255 request.setSecure(true);
259 /* ------------------------------------------------------------ */
260 protected String getLeftMostFieldValue(HttpFields fields, String header)
265 String headerValue = fields.getStringField(header);
267 if (headerValue == null)
270 int commaIndex = headerValue.indexOf(',');
272 if (commaIndex == -1)
278 // The left-most value is the farthest downstream client
279 return headerValue.substring(0,commaIndex);
283 /* ------------------------------------------------------------ */
285 public String toString()
287 return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());