Skip to content

Commit

Permalink
Provide opt-out mechansim for HTTP/2 content-length enforcement (#1353)
Browse files Browse the repository at this point in the history
Motivation:
We recently started strictly enforcing the content-length requirements
as specified by https://tools.ietf.org/html/rfc7540#section-8.1.2.6.
However not all h2/gRPC implementations have been updated and may
violate this clause which results in rejected requests/responses.

Modifications:
- Add a system property io.servicetalk.http2.allowInvalidContentLength
  which allows opting out of enforcement of the content-length
  enforcement requirements.

Result:
System property exists to opt-out of content-length enforcement
requirements. This option is temporary and will be removed in a future
release!
  • Loading branch information
Scottmitch authored and idelpivnitskiy committed Feb 5, 2021
1 parent 27b5ea5 commit 13d7f85
Showing 1 changed file with 23 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.handler.codec.http2.Http2ResetFrame;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;

Expand All @@ -42,9 +44,19 @@
import static io.servicetalk.http.netty.Http2Exception.newStreamResetException;
import static io.servicetalk.http.netty.HttpObjectEncoder.encodeAndRetain;
import static io.servicetalk.transport.netty.internal.ChannelCloseUtils.channelError;
import static java.lang.Boolean.getBoolean;
import static java.lang.Math.addExact;

abstract class AbstractH2DuplexHandler extends ChannelDuplexHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractH2DuplexHandler.class);
/**
* Temporary opt-out of
* <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">Malformed Requests and Responses</a> checks.
* This is only meant to ease interoperability until violating implementations are fixed.
* <b>Will be removed in future release!</b>
*/
private static final boolean ALLOW_INVALID_CONTENT_LENGTH =
getBoolean("io.servicetalk.http2.allowInvalidContentLength");
final BufferAllocator allocator;
final HttpHeadersFactory headersFactory;
final CloseHandler closeHandler;
Expand Down Expand Up @@ -141,7 +153,7 @@ final long contentLength(final Http2Headers headers) {

final void validateContentLengthMatch() {
if (contentLength >= 0 && seenContentLength != contentLength) {
throw newUnexpectedContentLength();
handleUnexpectedContentLength();
}
}

Expand All @@ -152,12 +164,18 @@ private void updateSeenContentLength(final int readableBytes) {
}
seenContentLength = addExact(seenContentLength, readableBytes);
if (seenContentLength > contentLength) {
throw newUnexpectedContentLength();
handleUnexpectedContentLength();
}
}

private IllegalArgumentException newUnexpectedContentLength() {
throw new IllegalArgumentException("Expected content-length " + contentLength +
" not equal to the actual length " + seenContentLength);
private void handleUnexpectedContentLength() {
final String msg = "Expected content-length " + contentLength + " not equal to the actual length " +
seenContentLength +
". Malformed request/response according to https://tools.ietf.org/html/rfc7540#section-8.1.2.6.";
if (ALLOW_INVALID_CONTENT_LENGTH) {
LOGGER.info(msg);
} else {
throw new IllegalArgumentException(msg);
}
}
}

0 comments on commit 13d7f85

Please sign in to comment.