|
1 | 1 | /*
|
2 |
| - * Copyright 2016 LINE Corporation |
| 2 | + * Copyright 2024 LINE Corporation |
3 | 3 | *
|
4 | 4 | * LINE Corporation licenses this file to you under the Apache License,
|
5 | 5 | * version 2.0 (the "License"); you may not use this file except in compliance
|
@@ -208,8 +208,8 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
|
208 | 208 | // Validate the 'content-length' header.
|
209 | 209 | final String contentLengthStr = headers.get(HttpHeaderNames.CONTENT_LENGTH);
|
210 | 210 | final boolean contentEmpty;
|
| 211 | + long contentLength = 0; |
211 | 212 | if (contentLengthStr != null) {
|
212 |
| - long contentLength; |
213 | 213 | try {
|
214 | 214 | contentLength = Long.parseLong(contentLengthStr);
|
215 | 215 | } catch (NumberFormatException ignored) {
|
@@ -280,6 +280,10 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
|
280 | 280 | final boolean endOfStream = contentEmpty && !transferEncodingChunked;
|
281 | 281 | this.req = req = DecodedHttpRequest.of(endOfStream, eventLoop, id, 1, headers,
|
282 | 282 | keepAlive, inboundTrafficController, routingCtx);
|
| 283 | + final long maxRequestLength = req.maxRequestLength(); |
| 284 | + if (maxRequestLength > 0 && contentLength > maxRequestLength) { |
| 285 | + abortLargeRequest(ctx, req, id, endOfStream, keepAliveHandler, true); |
| 286 | + } |
283 | 287 | cfg.serverMetrics().increasePendingHttp1Requests();
|
284 | 288 | ctx.fireChannelRead(req);
|
285 | 289 | } else {
|
@@ -313,33 +317,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
|
313 | 317 | final long maxContentLength = decodedReq.maxRequestLength();
|
314 | 318 | final long transferredLength = decodedReq.transferredBytes();
|
315 | 319 | if (maxContentLength > 0 && transferredLength > maxContentLength) {
|
316 |
| - final ContentTooLargeException cause = |
317 |
| - ContentTooLargeException.builder() |
318 |
| - .maxContentLength(maxContentLength) |
319 |
| - .contentLength(req.headers()) |
320 |
| - .transferred(transferredLength) |
321 |
| - .build(); |
322 |
| - discarding = true; |
323 |
| - req = null; |
324 |
| - final boolean shouldReset; |
325 |
| - if (encoder instanceof ServerHttp1ObjectEncoder) { |
326 |
| - if (encoder.isResponseHeadersSent(id, 1)) { |
327 |
| - ctx.channel().close(); |
328 |
| - } else { |
329 |
| - keepAliveHandler.disconnectWhenFinished(); |
330 |
| - } |
331 |
| - shouldReset = false; |
332 |
| - } else { |
333 |
| - // Upgraded to HTTP/2. Reset only if the remote peer is still open. |
334 |
| - shouldReset = !endOfStream; |
335 |
| - } |
336 |
| - |
337 |
| - // Wrap the cause with the returned status to let LoggingService correctly log the |
338 |
| - // status. |
339 |
| - final HttpStatusException httpStatusException = |
340 |
| - HttpStatusException.of(HttpStatus.REQUEST_ENTITY_TOO_LARGE, cause); |
341 |
| - decodedReq.setShouldResetOnlyIfRemoteIsOpen(shouldReset); |
342 |
| - decodedReq.abortResponse(httpStatusException, true); |
| 320 | + abortLargeRequest(ctx, decodedReq, id, endOfStream, keepAliveHandler, false); |
343 | 321 | return;
|
344 | 322 | }
|
345 | 323 |
|
@@ -377,6 +355,39 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
|
377 | 355 | }
|
378 | 356 | }
|
379 | 357 |
|
| 358 | + private void abortLargeRequest(ChannelHandlerContext ctx, DecodedHttpRequest decodedReq, int id, |
| 359 | + boolean endOfStream, KeepAliveHandler keepAliveHandler, |
| 360 | + boolean isEarlyRejection) { |
| 361 | + final ContentTooLargeException cause = |
| 362 | + ContentTooLargeException.builder() |
| 363 | + .maxContentLength(decodedReq.maxRequestLength()) |
| 364 | + .transferred(decodedReq.transferredBytes()) |
| 365 | + .contentLength(decodedReq.headers()) |
| 366 | + .earlyRejection(isEarlyRejection) |
| 367 | + .build(); |
| 368 | + discarding = true; |
| 369 | + req = null; |
| 370 | + final boolean shouldReset; |
| 371 | + if (encoder instanceof ServerHttp1ObjectEncoder) { |
| 372 | + if (encoder.isResponseHeadersSent(id, 1)) { |
| 373 | + ctx.channel().close(); |
| 374 | + } else { |
| 375 | + keepAliveHandler.disconnectWhenFinished(); |
| 376 | + } |
| 377 | + shouldReset = false; |
| 378 | + } else { |
| 379 | + // Upgraded to HTTP/2. Reset only if the remote peer is still open. |
| 380 | + shouldReset = !endOfStream; |
| 381 | + } |
| 382 | + |
| 383 | + // Wrap the cause with the returned status to let LoggingService correctly log the |
| 384 | + // status. |
| 385 | + final HttpStatusException httpStatusException = |
| 386 | + HttpStatusException.of(HttpStatus.REQUEST_ENTITY_TOO_LARGE, cause); |
| 387 | + decodedReq.setShouldResetOnlyIfRemoteIsOpen(shouldReset); |
| 388 | + decodedReq.abortResponse(httpStatusException, true); |
| 389 | + } |
| 390 | + |
380 | 391 | private void removeFromPipelineIfUpgraded(ChannelHandlerContext ctx, boolean endOfStream) {
|
381 | 392 | if (endOfStream && encoder instanceof ServerHttp2ObjectEncoder) {
|
382 | 393 | // An HTTP/1 connection has been upgraded to HTTP/2.
|
|
0 commit comments