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 }