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