View Javadoc

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; &gt;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; &gt;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 }