View Javadoc

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