]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / server / ForwardedRequestCustomizer.java
1 //
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.
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 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;
27
28
29 /* ------------------------------------------------------------ */
30 /** Customize Requests for Proxy Forwarding.
31  * <p>
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:
34  * <ul>
35  * <li>X-Forwarded-Host</li>
36  * <li>X-Forwarded-Server</li>
37  * <li>X-Forwarded-For</li>
38  * <li>X-Forwarded-Proto</li>
39  * </ul>
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>
46  */
47 public class ForwardedRequestCustomizer implements Customizer
48 {
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;
56     
57
58     /* ------------------------------------------------------------ */
59     public String getHostHeader()
60     {
61         return _hostHeader;
62     }
63
64     /* ------------------------------------------------------------ */
65     /**
66      * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
67      *
68      * @param hostHeader
69      *            The value of the host header to force.
70      */
71     public void setHostHeader(String hostHeader)
72     {
73         _hostHeader = hostHeader;
74     }
75
76     /* ------------------------------------------------------------ */
77     /*
78      *
79      * @see #setForwarded(boolean)
80      */
81     public String getForwardedHostHeader()
82     {
83         return _forwardedHostHeader;
84     }
85
86     /* ------------------------------------------------------------ */
87     /**
88      * @param forwardedHostHeader
89      *            The header name for forwarded hosts (default x-forwarded-host)
90      */
91     public void setForwardedHostHeader(String forwardedHostHeader)
92     {
93         _forwardedHostHeader = forwardedHostHeader;
94     }
95
96     /* ------------------------------------------------------------ */
97     /**
98      * @return the header name for forwarded server.
99      */
100     public String getForwardedServerHeader()
101     {
102         return _forwardedServerHeader;
103     }
104
105     /* ------------------------------------------------------------ */
106     /**
107      * @param forwardedServerHeader
108      *            The header name for forwarded server (default x-forwarded-server)
109      */
110     public void setForwardedServerHeader(String forwardedServerHeader)
111     {
112         _forwardedServerHeader = forwardedServerHeader;
113     }
114
115     /* ------------------------------------------------------------ */
116     /**
117      * @return the forwarded for header
118      */
119     public String getForwardedForHeader()
120     {
121         return _forwardedForHeader;
122     }
123
124     /* ------------------------------------------------------------ */
125     /**
126      * @param forwardedRemoteAddressHeader
127      *            The header name for forwarded for (default x-forwarded-for)
128      */
129     public void setForwardedForHeader(String forwardedRemoteAddressHeader)
130     {
131         _forwardedForHeader = forwardedRemoteAddressHeader;
132     }
133
134     /* ------------------------------------------------------------ */
135     /**
136      * Get the forwardedProtoHeader.
137      *
138      * @return the forwardedProtoHeader (default X-Forwarded-For)
139      */
140     public String getForwardedProtoHeader()
141     {
142         return _forwardedProtoHeader;
143     }
144
145     /* ------------------------------------------------------------ */
146     /**
147      * Set the forwardedProtoHeader.
148      *
149      * @param forwardedProtoHeader
150      *            the forwardedProtoHeader to set (default X-Forwarded-For)
151      */
152     public void setForwardedProtoHeader(String forwardedProtoHeader)
153     {
154         _forwardedProtoHeader = forwardedProtoHeader;
155     }
156
157     /* ------------------------------------------------------------ */
158     /**
159      * @return The header name holding a forwarded cipher suite (default null)
160      */
161     public String getForwardedCipherSuiteHeader()
162     {
163         return _forwardedCipherSuiteHeader;
164     }
165
166     /* ------------------------------------------------------------ */
167     /**
168      * @param forwardedCipherSuite
169      *            The header name holding a forwarded cipher suite (default null)
170      */
171     public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
172     {
173         _forwardedCipherSuiteHeader = forwardedCipherSuite;
174     }
175
176     /* ------------------------------------------------------------ */
177     /**
178      * @return The header name holding a forwarded SSL Session ID (default null)
179      */
180     public String getForwardedSslSessionIdHeader()
181     {
182         return _forwardedSslSessionIdHeader;
183     }
184
185     /* ------------------------------------------------------------ */
186     /**
187      * @param forwardedSslSessionId
188      *            The header name holding a forwarded SSL Session ID (default null)
189      */
190     public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
191     {
192         _forwardedSslSessionIdHeader = forwardedSslSessionId;
193     }
194
195     /* ------------------------------------------------------------ */
196     @Override
197     public void customize(Connector connector, HttpConfiguration config, Request request)
198     {
199         HttpFields httpFields = request.getHttpFields();
200
201         // Do SSL first
202         if (getForwardedCipherSuiteHeader()!=null)
203         {
204             String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
205             if (cipher_suite!=null)
206                 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
207         }
208         if (getForwardedSslSessionIdHeader()!=null)
209         {
210             String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
211             if(ssl_session_id!=null)
212             {
213                 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
214                 request.setScheme(HttpScheme.HTTPS.asString());
215             }
216         }
217
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());
223
224         if (_hostHeader != null)
225         {
226             // Update host header
227             httpFields.put(HttpHeader.HOST.toString(),_hostHeader);
228             request.setServerName(null);
229             request.setServerPort(-1);
230             request.getServerName();
231         }
232         else if (forwardedHost != null)
233         {
234             // Update host header
235             httpFields.put(HttpHeader.HOST.toString(),forwardedHost);
236             request.setServerName(null);
237             request.setServerPort(-1);
238             request.getServerName();
239         }
240         else if (forwardedServer != null)
241         {
242             // Use provided server name
243             request.setServerName(forwardedServer);
244         }
245
246         if (forwardedFor != null)
247         {
248             request.setRemoteAddr(InetSocketAddress.createUnresolved(forwardedFor,request.getRemotePort()));
249         }
250
251         if (forwardedProto != null)
252         {
253             request.setScheme(forwardedProto);
254             if (forwardedProto.equals(config.getSecureScheme()))
255                 request.setSecure(true);
256         }
257     }
258
259     /* ------------------------------------------------------------ */
260     protected String getLeftMostFieldValue(HttpFields fields, String header)
261     {
262         if (header == null)
263             return null;
264
265         String headerValue = fields.getStringField(header);
266
267         if (headerValue == null)
268             return null;
269
270         int commaIndex = headerValue.indexOf(',');
271
272         if (commaIndex == -1)
273         {
274             // Single value
275             return headerValue;
276         }
277
278         // The left-most value is the farthest downstream client
279         return headerValue.substring(0,commaIndex);
280     }
281
282
283     /* ------------------------------------------------------------ */
284     @Override
285     public String toString()
286     {
287         return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
288     }
289 }