1 /* 2 * Copyright 2023 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package io.netty.handler.codec.http; 17 18 import static io.netty.util.internal.ObjectUtil.checkNotNull; 19 import static io.netty.util.internal.ObjectUtil.checkPositive; 20 21 /** 22 * A configuration object for specifying the behaviour of {@link HttpObjectDecoder} and its subclasses. 23 * <p> 24 * The {@link HttpDecoderConfig} objects are mutable to reduce allocation, 25 * but also {@link Cloneable} in case a defensive copy is needed. 26 */ 27 public final class HttpDecoderConfig implements Cloneable { 28 private int maxChunkSize = HttpObjectDecoder.DEFAULT_MAX_CHUNK_SIZE; 29 private boolean chunkedSupported = HttpObjectDecoder.DEFAULT_CHUNKED_SUPPORTED; 30 private boolean allowPartialChunks = HttpObjectDecoder.DEFAULT_ALLOW_PARTIAL_CHUNKS; 31 private HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory(); 32 private HttpHeadersFactory trailersFactory = DefaultHttpHeadersFactory.trailersFactory(); 33 private boolean allowDuplicateContentLengths = HttpObjectDecoder.DEFAULT_ALLOW_DUPLICATE_CONTENT_LENGTHS; 34 private int maxInitialLineLength = HttpObjectDecoder.DEFAULT_MAX_INITIAL_LINE_LENGTH; 35 private int maxHeaderSize = HttpObjectDecoder.DEFAULT_MAX_HEADER_SIZE; 36 private int initialBufferSize = HttpObjectDecoder.DEFAULT_INITIAL_BUFFER_SIZE; 37 38 public int getInitialBufferSize() { 39 return initialBufferSize; 40 } 41 42 /** 43 * Set the initial size of the temporary buffer used when parsing the lines of the HTTP headers. 44 * 45 * @param initialBufferSize The buffer size in bytes. 46 * @return This decoder config. 47 */ 48 public HttpDecoderConfig setInitialBufferSize(int initialBufferSize) { 49 checkPositive(initialBufferSize, "initialBufferSize"); 50 this.initialBufferSize = initialBufferSize; 51 return this; 52 } 53 54 public int getMaxInitialLineLength() { 55 return maxInitialLineLength; 56 } 57 58 /** 59 * Set the maximum length of the first line of the HTTP header. 60 * This limits how much memory Netty will use when parsed the initial HTTP header line. 61 * You would typically set this to the same value as {@link #setMaxHeaderSize(int)}. 62 * 63 * @param maxInitialLineLength The maximum length, in bytes. 64 * @return This decoder config. 65 */ 66 public HttpDecoderConfig setMaxInitialLineLength(int maxInitialLineLength) { 67 checkPositive(maxInitialLineLength, "maxInitialLineLength"); 68 this.maxInitialLineLength = maxInitialLineLength; 69 return this; 70 } 71 72 public int getMaxHeaderSize() { 73 return maxHeaderSize; 74 } 75 76 /** 77 * Set the maximum line length of header lines. 78 * This limits how much memory Netty will use when parsing HTTP header key-value pairs. 79 * The limit applies to the sum of all the headers, so it applies equally to many short header-lines, 80 * or fewer but longer header lines. 81 * <p> 82 * You would typically set this to the same value as {@link #setMaxInitialLineLength(int)}. 83 * 84 * @param maxHeaderSize The maximum length, in bytes. 85 * @return This decoder config. 86 */ 87 public HttpDecoderConfig setMaxHeaderSize(int maxHeaderSize) { 88 checkPositive(maxHeaderSize, "maxHeaderSize"); 89 this.maxHeaderSize = maxHeaderSize; 90 return this; 91 } 92 93 public int getMaxChunkSize() { 94 return maxChunkSize; 95 } 96 97 /** 98 * Set the maximum chunk size. 99 * HTTP requests and responses can be quite large, in which case it's better to process the data as a stream of 100 * chunks. 101 * This sets the limit, in bytes, at which Netty will send a chunk down the pipeline. 102 * 103 * @param maxChunkSize The maximum chunk size, in bytes. 104 * @return This decoder config. 105 */ 106 public HttpDecoderConfig setMaxChunkSize(int maxChunkSize) { 107 checkPositive(maxChunkSize, "maxChunkSize"); 108 this.maxChunkSize = maxChunkSize; 109 return this; 110 } 111 112 public boolean isChunkedSupported() { 113 return chunkedSupported; 114 } 115 116 /** 117 * Set whether {@code Transfer-Encoding: Chunked} should be supported. 118 * 119 * @param chunkedSupported if {@code false}, then a {@code Transfer-Encoding: Chunked} header will produce an error, 120 * instead of a stream of chunks. 121 * @return This decoder config. 122 */ 123 public HttpDecoderConfig setChunkedSupported(boolean chunkedSupported) { 124 this.chunkedSupported = chunkedSupported; 125 return this; 126 } 127 128 public boolean isAllowPartialChunks() { 129 return allowPartialChunks; 130 } 131 132 /** 133 * Set whether chunks can be split into multiple messages, if their chunk size exceeds the size of the input buffer. 134 * 135 * @param allowPartialChunks set to {@code false} to only allow sending whole chunks down the pipeline. 136 * @return This decoder config. 137 */ 138 public HttpDecoderConfig setAllowPartialChunks(boolean allowPartialChunks) { 139 this.allowPartialChunks = allowPartialChunks; 140 return this; 141 } 142 143 public HttpHeadersFactory getHeadersFactory() { 144 return headersFactory; 145 } 146 147 /** 148 * Set the {@link HttpHeadersFactory} to use when creating new HTTP headers objects. 149 * The default headers factory is {@link DefaultHttpHeadersFactory#headersFactory()}. 150 * <p> 151 * For the purpose of {@link #clone()}, it is assumed that the factory is either immutable, or can otherwise be 152 * shared across different decoders and decoder configs. 153 * 154 * @param headersFactory The header factory to use. 155 * @return This decoder config. 156 */ 157 public HttpDecoderConfig setHeadersFactory(HttpHeadersFactory headersFactory) { 158 checkNotNull(headersFactory, "headersFactory"); 159 this.headersFactory = headersFactory; 160 return this; 161 } 162 163 public boolean isAllowDuplicateContentLengths() { 164 return allowDuplicateContentLengths; 165 } 166 167 /** 168 * Set whether more than one {@code Content-Length} header is allowed. 169 * You usually want to disallow this (which is the default) as multiple {@code Content-Length} headers can indicate 170 * a request- or response-splitting attack. 171 * 172 * @param allowDuplicateContentLengths set to {@code true} to allow multiple content length headers. 173 * @return This decoder config. 174 */ 175 public HttpDecoderConfig setAllowDuplicateContentLengths(boolean allowDuplicateContentLengths) { 176 this.allowDuplicateContentLengths = allowDuplicateContentLengths; 177 return this; 178 } 179 180 /** 181 * Set whether header validation should be enabled or not. 182 * This works by changing the configured {@linkplain #setHeadersFactory(HttpHeadersFactory) header factory} 183 * and {@linkplain #setTrailersFactory(HttpHeadersFactory) trailer factory}. 184 * <p> 185 * You usually want header validation enabled (which is the default) in order to prevent request-/response-splitting 186 * attacks. 187 * 188 * @param validateHeaders set to {@code false} to disable header validation. 189 * @return This decoder config. 190 */ 191 public HttpDecoderConfig setValidateHeaders(boolean validateHeaders) { 192 DefaultHttpHeadersFactory noValidation = DefaultHttpHeadersFactory.headersFactory().withValidation(false); 193 headersFactory = validateHeaders ? DefaultHttpHeadersFactory.headersFactory() : noValidation; 194 trailersFactory = validateHeaders ? DefaultHttpHeadersFactory.trailersFactory() : noValidation; 195 return this; 196 } 197 198 public HttpHeadersFactory getTrailersFactory() { 199 return trailersFactory; 200 } 201 202 /** 203 * Set the {@link HttpHeadersFactory} used to create HTTP trailers. 204 * This differs from {@link #setHeadersFactory(HttpHeadersFactory)} in that trailers have different validation 205 * requirements. 206 * The default trailer factory is {@link DefaultHttpHeadersFactory#headersFactory()}. 207 * <p> 208 * For the purpose of {@link #clone()}, it is assumed that the factory is either immutable, or can otherwise be 209 * shared across different decoders and decoder configs. 210 * 211 * @param trailersFactory The headers factory to use for creating trailers. 212 * @return This decoder config. 213 */ 214 public HttpDecoderConfig setTrailersFactory(HttpHeadersFactory trailersFactory) { 215 checkNotNull(trailersFactory, "trailersFactory"); 216 this.trailersFactory = trailersFactory; 217 return this; 218 } 219 220 @Override 221 public HttpDecoderConfig clone() { 222 try { 223 return (HttpDecoderConfig) super.clone(); 224 } catch (CloneNotSupportedException e) { 225 throw new AssertionError(); 226 } 227 } 228 }