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.io.IOException;
22 import java.util.List;
23 import java.util.Set;
24 import java.util.concurrent.CopyOnWriteArrayList;
25
26 import org.eclipse.jetty.http.HttpMethod;
27 import org.eclipse.jetty.http.HttpScheme;
28 import org.eclipse.jetty.util.Jetty;
29 import org.eclipse.jetty.util.TreeTrie;
30 import org.eclipse.jetty.util.Trie;
31 import org.eclipse.jetty.util.annotation.ManagedAttribute;
32 import org.eclipse.jetty.util.annotation.ManagedObject;
33
34
35 /* ------------------------------------------------------------ */
36 /** HTTP Configuration.
37 * <p>This class is a holder of HTTP configuration for use by the
38 * {@link HttpChannel} class. Typically a HTTPConfiguration instance
39 * is instantiated and passed to a {@link ConnectionFactory} that can
40 * create HTTP channels (e.g. HTTP, AJP or FCGI).</p>
41 * <p>The configuration held by this class is not for the wire protocol,
42 * but for the interpretation and handling of HTTP requests that could
43 * be transported by a variety of protocols.
44 * </p>
45 */
46 @ManagedObject("HTTP Configuration")
47 public class HttpConfiguration
48 {
49 public static final String SERVER_VERSION = "Jetty(" + Jetty.VERSION + ")";
50
51 private final List<Customizer> _customizers=new CopyOnWriteArrayList<>();
52 private final Trie<Boolean> _formEncodedMethods = new TreeTrie<>();
53 private int _outputBufferSize=32*1024;
54 private int _outputAggregationSize=_outputBufferSize/4;
55 private int _requestHeaderSize=8*1024;
56 private int _responseHeaderSize=8*1024;
57 private int _headerCacheSize=512;
58 private int _securePort;
59 private long _blockingTimeout=-1;
60 private String _secureScheme = HttpScheme.HTTPS.asString();
61 private boolean _sendServerVersion = true;
62 private boolean _sendXPoweredBy = false;
63 private boolean _sendDateHeader = true;
64 private boolean _delayDispatchUntilContent = true;
65 private boolean _persistentConnectionsEnabled = true;
66 private int _maxErrorDispatches = 10;
67
68 /* ------------------------------------------------------------ */
69 /**
70 * <p>An interface that allows a request object to be customized
71 * for a particular HTTP connector configuration. Unlike Filters, customizer are
72 * applied before the request is submitted for processing and can be specific to the
73 * connector on which the request was received.
74 *
75 * <p>Typically Customizers perform tasks such as: <ul>
76 * <li>process header fields that may be injected by a proxy or load balancer.
77 * <li>setup attributes that may come from the connection/connector such as SSL Session IDs
78 * <li>Allow a request to be marked as secure or authenticated if those have been offloaded
79 * and communicated by header, cookie or other out-of-band mechanism
80 * <li>Set request attributes/fields that are determined by the connector on which the
81 * request was received
82 * </ul>
83 */
84 public interface Customizer
85 {
86 public void customize(Connector connector, HttpConfiguration channelConfig, Request request);
87 }
88
89 public interface ConnectionFactory
90 {
91 HttpConfiguration getHttpConfiguration();
92 }
93
94 public HttpConfiguration()
95 {
96 _formEncodedMethods.put(HttpMethod.POST.asString(),Boolean.TRUE);
97 _formEncodedMethods.put(HttpMethod.PUT.asString(),Boolean.TRUE);
98 }
99
100 /* ------------------------------------------------------------ */
101 /** Create a configuration from another.
102 * @param config The configuration to copy.
103 */
104 public HttpConfiguration(HttpConfiguration config)
105 {
106 _customizers.addAll(config._customizers);
107 for (String s:config._formEncodedMethods.keySet())
108 _formEncodedMethods.put(s,Boolean.TRUE);
109 _outputBufferSize=config._outputBufferSize;
110 _outputAggregationSize=config._outputAggregationSize;
111 _requestHeaderSize=config._requestHeaderSize;
112 _responseHeaderSize=config._responseHeaderSize;
113 _headerCacheSize=config._headerCacheSize;
114 _secureScheme=config._secureScheme;
115 _securePort=config._securePort;
116 _blockingTimeout=config._blockingTimeout;
117 _sendDateHeader=config._sendDateHeader;
118 _sendServerVersion=config._sendServerVersion;
119 _sendXPoweredBy=config._sendXPoweredBy;
120 _delayDispatchUntilContent=config._delayDispatchUntilContent;
121 _persistentConnectionsEnabled=config._persistentConnectionsEnabled;
122 _maxErrorDispatches=config._maxErrorDispatches;
123 }
124
125 /* ------------------------------------------------------------ */
126 /**
127 * <p>Add a {@link Customizer} that is invoked for every
128 * request received.</p>
129 * <p>Customiser are often used to interpret optional headers (eg {@link ForwardedRequestCustomizer}) or
130 * optional protocol semantics (eg {@link SecureRequestCustomizer}).
131 * @param customizer A request customizer
132 */
133 public void addCustomizer(Customizer customizer)
134 {
135 _customizers.add(customizer);
136 }
137
138 /* ------------------------------------------------------------ */
139 public List<Customizer> getCustomizers()
140 {
141 return _customizers;
142 }
143
144 /* ------------------------------------------------------------ */
145 public <T> T getCustomizer(Class<T> type)
146 {
147 for (Customizer c : _customizers)
148 if (type.isAssignableFrom(c.getClass()))
149 return (T)c;
150 return null;
151 }
152
153 /* ------------------------------------------------------------ */
154 @ManagedAttribute("The size in bytes of the output buffer used to aggregate HTTP output")
155 public int getOutputBufferSize()
156 {
157 return _outputBufferSize;
158 }
159
160 /* ------------------------------------------------------------ */
161 @ManagedAttribute("The maximum size in bytes for HTTP output to be aggregated")
162 public int getOutputAggregationSize()
163 {
164 return _outputAggregationSize;
165 }
166
167 /* ------------------------------------------------------------ */
168 @ManagedAttribute("The maximum allowed size in bytes for a HTTP request header")
169 public int getRequestHeaderSize()
170 {
171 return _requestHeaderSize;
172 }
173
174 /* ------------------------------------------------------------ */
175 @ManagedAttribute("The maximum allowed size in bytes for a HTTP response header")
176 public int getResponseHeaderSize()
177 {
178 return _responseHeaderSize;
179 }
180
181 /* ------------------------------------------------------------ */
182 @ManagedAttribute("The maximum allowed size in bytes for a HTTP header field cache")
183 public int getHeaderCacheSize()
184 {
185 return _headerCacheSize;
186 }
187
188 /* ------------------------------------------------------------ */
189 @ManagedAttribute("The port to which Integral or Confidential security constraints are redirected")
190 public int getSecurePort()
191 {
192 return _securePort;
193 }
194
195 /* ------------------------------------------------------------ */
196 @ManagedAttribute("The scheme with which Integral or Confidential security constraints are redirected")
197 public String getSecureScheme()
198 {
199 return _secureScheme;
200 }
201
202 /* ------------------------------------------------------------ */
203 @ManagedAttribute("True if HTTP/1 persistent connection are enabled")
204 public boolean isPersistentConnectionsEnabled()
205 {
206 return _persistentConnectionsEnabled;
207 }
208
209 /* ------------------------------------------------------------ */
210 /** Get the timeout applied to blocking operations.
211 * <p>This timeout is in addition to the {@link Connector#getIdleTimeout()}, and applies
212 * to the total operation (as opposed to the idle timeout that applies to the time no
213 * data is being sent).
214 * @return -1, for no blocking timeout (default), 0 for a blocking timeout equal to the
215 * idle timeout; >0 for a timeout in ms applied to the total blocking operation.
216 */
217 @ManagedAttribute("Timeout in MS for blocking operations.")
218 public long getBlockingTimeout()
219 {
220 return _blockingTimeout;
221 }
222
223 /**
224 * Set the timeout applied to blocking operations.
225 * <p>This timeout is in addition to the {@link Connector#getIdleTimeout()}, and applies
226 * to the total operation (as opposed to the idle timeout that applies to the time no
227 * data is being sent).
228 * @param blockingTimeout -1, for no blocking timeout (default), 0 for a blocking timeout equal to the
229 * idle timeout; >0 for a timeout in ms applied to the total blocking operation.
230 */
231 public void setBlockingTimeout(long blockingTimeout)
232 {
233 _blockingTimeout = blockingTimeout;
234 }
235
236 /* ------------------------------------------------------------ */
237 public void setPersistentConnectionsEnabled(boolean persistentConnectionsEnabled)
238 {
239 _persistentConnectionsEnabled = persistentConnectionsEnabled;
240 }
241
242 /* ------------------------------------------------------------ */
243 public void setSendServerVersion (boolean sendServerVersion)
244 {
245 _sendServerVersion = sendServerVersion;
246 }
247
248 /* ------------------------------------------------------------ */
249 @ManagedAttribute("if true, send the Server header in responses")
250 public boolean getSendServerVersion()
251 {
252 return _sendServerVersion;
253 }
254
255 /* ------------------------------------------------------------ */
256 public void writePoweredBy(Appendable out,String preamble,String postamble) throws IOException
257 {
258 if (getSendServerVersion())
259 {
260 if (preamble!=null)
261 out.append(preamble);
262 out.append(Jetty.POWERED_BY);
263 if (postamble!=null)
264 out.append(postamble);
265 }
266 }
267
268 /* ------------------------------------------------------------ */
269 public void setSendXPoweredBy (boolean sendXPoweredBy)
270 {
271 _sendXPoweredBy=sendXPoweredBy;
272 }
273
274 /* ------------------------------------------------------------ */
275 @ManagedAttribute("if true, send the X-Powered-By header in responses")
276 public boolean getSendXPoweredBy()
277 {
278 return _sendXPoweredBy;
279 }
280
281 /* ------------------------------------------------------------ */
282 public void setSendDateHeader(boolean sendDateHeader)
283 {
284 _sendDateHeader = sendDateHeader;
285 }
286
287 /* ------------------------------------------------------------ */
288 @ManagedAttribute("if true, include the date in HTTP headers")
289 public boolean getSendDateHeader()
290 {
291 return _sendDateHeader;
292 }
293
294 /* ------------------------------------------------------------ */
295 /**
296 * @param delay if true, delay the application dispatch until content is available (default false)
297 */
298 public void setDelayDispatchUntilContent(boolean delay)
299 {
300 _delayDispatchUntilContent = delay;
301 }
302
303 /* ------------------------------------------------------------ */
304 @ManagedAttribute("if true, delay the application dispatch until content is available")
305 public boolean isDelayDispatchUntilContent()
306 {
307 return _delayDispatchUntilContent;
308 }
309
310 /* ------------------------------------------------------------ */
311 /**
312 * <p>Set the {@link Customizer}s that are invoked for every
313 * request received.</p>
314 * <p>Customizers are often used to interpret optional headers (eg {@link ForwardedRequestCustomizer}) or
315 * optional protocol semantics (eg {@link SecureRequestCustomizer}).
316 * @param customizers the list of customizers
317 */
318 public void setCustomizers(List<Customizer> customizers)
319 {
320 _customizers.clear();
321 _customizers.addAll(customizers);
322 }
323
324 /* ------------------------------------------------------------ */
325 /**
326 * Set the size of the buffer into which response content is aggregated
327 * before being sent to the client. A larger buffer can improve performance by allowing
328 * a content producer to run without blocking, however larger buffers consume more memory and
329 * may induce some latency before a client starts processing the content.
330 * @param outputBufferSize buffer size in bytes.
331 */
332 public void setOutputBufferSize(int outputBufferSize)
333 {
334 _outputBufferSize = outputBufferSize;
335 setOutputAggregationSize(outputBufferSize / 4);
336 }
337
338 /* ------------------------------------------------------------ */
339 /**
340 * Set the max size of the response content write that is copied into the aggregate buffer.
341 * Writes that are smaller of this size are copied into the aggregate buffer, while
342 * writes that are larger of this size will cause the aggregate buffer to be flushed
343 * and the write to be executed without being copied.
344 * @param outputAggregationSize the max write size that is aggregated
345 */
346 public void setOutputAggregationSize(int outputAggregationSize)
347 {
348 _outputAggregationSize = outputAggregationSize;
349 }
350
351 /* ------------------------------------------------------------ */
352 /** Set the maximum size of a request header.
353 * <p>Larger headers will allow for more and/or larger cookies plus larger form content encoded
354 * in a URL. However, larger headers consume more memory and can make a server more vulnerable to denial of service
355 * attacks.</p>
356 * @param requestHeaderSize Max header size in bytes
357 */
358 public void setRequestHeaderSize(int requestHeaderSize)
359 {
360 _requestHeaderSize = requestHeaderSize;
361 }
362
363 /* ------------------------------------------------------------ */
364 /** Set the maximum size of a response header.
365 *
366 * <p>Larger headers will allow for more and/or larger cookies and longer HTTP headers (eg for redirection).
367 * However, larger headers will also consume more memory.</p>
368 * @param responseHeaderSize Response header size in bytes.
369 */
370 public void setResponseHeaderSize(int responseHeaderSize)
371 {
372 _responseHeaderSize = responseHeaderSize;
373 }
374
375 /* ------------------------------------------------------------ */
376 /** Set the header field cache size.
377 * @param headerCacheSize The size in bytes of the header field cache.
378 */
379 public void setHeaderCacheSize(int headerCacheSize)
380 {
381 _headerCacheSize = headerCacheSize;
382 }
383
384 /* ------------------------------------------------------------ */
385 /** Set the TCP/IP port used for CONFIDENTIAL and INTEGRAL redirections.
386 * @param securePort the secure port to redirect to.
387 */
388 public void setSecurePort(int securePort)
389 {
390 _securePort = securePort;
391 }
392
393 /* ------------------------------------------------------------ */
394 /** Set the URI scheme used for CONFIDENTIAL and INTEGRAL redirections.
395 * @param secureScheme A scheme string like "https"
396 */
397 public void setSecureScheme(String secureScheme)
398 {
399 _secureScheme = secureScheme;
400 }
401
402 /* ------------------------------------------------------------ */
403 @Override
404 public String toString()
405 {
406 return String.format("%s@%x{%d/%d,%d/%d,%s://:%d,%s}",
407 this.getClass().getSimpleName(),
408 hashCode(),
409 _outputBufferSize, _outputAggregationSize,
410 _requestHeaderSize,_responseHeaderSize,
411 _secureScheme,_securePort,
412 _customizers);
413 }
414
415 /* ------------------------------------------------------------ */
416 /** Set the form encoded methods.
417 * @param methods HTTP Methods of requests that can be decoded as
418 * x-www-form-urlencoded content to be made available via the
419 * {@link Request#getParameter(String)} and associated APIs
420 */
421 public void setFormEncodedMethods(String... methods)
422 {
423 _formEncodedMethods.clear();
424 for (String method:methods)
425 addFormEncodedMethod(method);
426 }
427
428 /* ------------------------------------------------------------ */
429 /**
430 * @return Set of HTTP Methods of requests that can be decoded as
431 * x-www-form-urlencoded content to be made available via the
432 * {@link Request#getParameter(String)} and associated APIs
433 */
434 public Set<String> getFormEncodedMethods()
435 {
436 return _formEncodedMethods.keySet();
437 }
438
439 /* ------------------------------------------------------------ */
440 /** Add a form encoded HTTP Method
441 * @param method HTTP Method of requests that can be decoded as
442 * x-www-form-urlencoded content to be made available via the
443 * {@link Request#getParameter(String)} and associated APIs
444 */
445 public void addFormEncodedMethod(String method)
446 {
447 _formEncodedMethods.put(method,Boolean.TRUE);
448 }
449
450 /* ------------------------------------------------------------ */
451 /**
452 * Test if the method type supports <code>x-www-form-urlencoded</code> content
453 *
454 * @param method the method type
455 * @return True of the requests of this method type can be
456 * decoded as <code>x-www-form-urlencoded</code> content to be made available via the
457 * {@link Request#getParameter(String)} and associated APIs
458 */
459 public boolean isFormEncodedMethod(String method)
460 {
461 return Boolean.TRUE.equals(_formEncodedMethods.get(method));
462 }
463
464 /* ------------------------------------------------------------ */
465 /**
466 * @return The maximum error dispatches for a request to prevent looping on an error
467 */
468 @ManagedAttribute("The maximum ERROR dispatches for a request for loop prevention (default 10)")
469 public int getMaxErrorDispatches()
470 {
471 return _maxErrorDispatches;
472 }
473
474 /* ------------------------------------------------------------ */
475 /**
476 * @param max The maximum error dispatches for a request to prevent looping on an error
477 */
478 public void setMaxErrorDispatches(int max)
479 {
480 _maxErrorDispatches=max;
481 }
482 }