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 }