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