Skip to content

Commit

Permalink
Update Netty 4.1.77 -> 4.1.78 (#2250)
Browse files Browse the repository at this point in the history
  • Loading branch information
idelpivnitskiy authored Jun 15, 2022
1 parent 0f1ac15 commit 26ed662
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 2 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ issueManagementUrl=https://github.com/apple/servicetalk/issues
ciManagementUrl=https://github.com/apple/servicetalk/actions

# dependency versions
nettyVersion=4.1.77.Final
nettyVersion=4.1.78.Final
nettyIoUringVersion=0.0.14.Final

jsr305Version=3.0.2
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2021 Apple Inc. and the ServiceTalk project authors
* Copyright © 2021-2022 Apple Inc. and the ServiceTalk project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,13 +21,45 @@
import io.netty.handler.codec.http2.Http2FrameCodecBuilder;
import io.netty.handler.codec.http2.Http2RemoteFlowController;
import io.netty.handler.codec.http2.UniformStreamByteDistributor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import javax.annotation.Nullable;

import static io.servicetalk.utils.internal.PlatformDependent.throwException;
import static java.lang.invoke.MethodType.methodType;

/**
* Optimized variant of {@link Http2FrameCodecBuilder} that allows us to use {@link UniformStreamByteDistributor}
* for {@link Http2RemoteFlowController}.
*/
final class OptimizedHttp2FrameCodecBuilder extends Http2FrameCodecBuilder {

private static final Logger LOGGER = LoggerFactory.getLogger(OptimizedHttp2FrameCodecBuilder.class);

@Nullable
private static final MethodHandle FLUSH_PREFACE;

static {
MethodHandle flushPreface;
try {
// Find a new method that exists only in Netty starting from 4.1.78.Final:
flushPreface = MethodHandles.publicLookup()
.findVirtual(Http2FrameCodecBuilder.class, "flushPreface",
methodType(Http2FrameCodecBuilder.class, boolean.class));
// Verify the method is working as expected:
disableFlushPreface(flushPreface, Http2FrameCodecBuilder.forClient());
} catch (Throwable cause) {
LOGGER.debug("Http2FrameCodecBuilder#flushPreface(boolean) is available only starting from " +
"Netty 4.1.78.Final. Detected Netty version: {}",
Http2FrameCodecBuilder.class.getPackage().getImplementationVersion(), cause);
flushPreface = null;
}
FLUSH_PREFACE = flushPreface;
}

private final boolean server;

/**
Expand All @@ -37,6 +69,7 @@ final class OptimizedHttp2FrameCodecBuilder extends Http2FrameCodecBuilder {
*/
OptimizedHttp2FrameCodecBuilder(final boolean server) {
this.server = server;
disableFlushPreface(FLUSH_PREFACE, this);
}

@Override
Expand All @@ -52,4 +85,29 @@ public Http2FrameCodec build() {
connection(connection);
return super.build();
}

/**
* We manage flushes at ST level and don't want netty to flush the preface & settings only. Instead, we write
* headers or entire message and flush them all together. Netty changed the default flush behavior starting from
* 4.1.78.Final. To avoid a strict dependency on Netty 4.1.78.Final in the classpath, we use {@link MethodHandle} to
* check if the new method is available or not.
*
* @param flushPrefaceMethod {@link MethodHandle} for {@link Http2FrameCodecBuilder#flushPreface(boolean)}
* @param builderInstance an instance of {@link Http2FrameCodecBuilder} where the flush behavior should be disabled
* @return {@link Http2FrameCodecBuilder} or {@code null} if {@code flushPrefaceMethod == null}
* @see <a href="https://github.com/netty/netty/pull/12349">Netty PR#12349</a>
*/
private static Http2FrameCodecBuilder disableFlushPreface(@Nullable final MethodHandle flushPrefaceMethod,
final Http2FrameCodecBuilder builderInstance) {
if (flushPrefaceMethod == null) {
return builderInstance;
}
try {
// invokeExact requires return type cast to match the type signature
return (Http2FrameCodecBuilder) flushPrefaceMethod.invokeExact(builderInstance, false);
} catch (Throwable t) {
throwException(t);
return builderInstance;
}
}
}

0 comments on commit 26ed662

Please sign in to comment.