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 }