-
Notifications
You must be signed in to change notification settings - Fork 869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Skip ALPN if request is HTTP endpoint #5854
base: master
Are you sure you want to change the base?
Changes from 3 commits
4b838ea
e799151
ed58871
75577b4
1264d9a
b4cc3a2
00ecf34
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -99,7 +99,9 @@ public void channelCreated(Channel ch) { | |||
ch.attr(CHANNEL_DIAGNOSTICS).set(new ChannelDiagnostics(ch)); | ||||
ch.attr(PROTOCOL_FUTURE).set(new CompletableFuture<>()); | ||||
ChannelPipeline pipeline = ch.pipeline(); | ||||
if (sslCtx != null) { | ||||
|
||||
boolean sslCtxPresent = sslCtx != null; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whats the reason for this change ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are saving the boolean as variable since we pass to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have test cases for this change ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is existing behavior, to use prior knowledge. Covered by test here, to make sure we don't throw Line 49 in ed58871
|
||||
if (sslCtxPresent) { | ||||
|
||||
SslHandler sslHandler = newSslHandler(sslCtx, ch.alloc(), poolKey.getHost(), poolKey.getPort(), | ||||
configuration.tlsHandshakeTimeout()); | ||||
|
@@ -114,11 +116,16 @@ public void channelCreated(Channel ch) { | |||
} | ||||
} | ||||
|
||||
configureProtocolHandlers(ch, pipeline, protocol); | ||||
configureProtocolHandlers(ch, pipeline, protocol, sslCtxPresent); | ||||
configurePostProtocolHandlers(pipeline, protocol); | ||||
} | ||||
|
||||
private void configureProtocolHandlers(Channel ch, ChannelPipeline pipeline, Protocol protocol) { | ||||
private void configureProtocolHandlers(Channel ch, ChannelPipeline pipeline, Protocol protocol, boolean sslContextPresent) { | ||||
if (!sslContextPresent) { | ||||
configureAssumeProtocol(ch, pipeline, protocol); | ||||
return; | ||||
} | ||||
|
||||
switch (protocolNegotiation) { | ||||
case ASSUME_PROTOCOL: | ||||
configureAssumeProtocol(ch, pipeline, protocol); | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"version":"2.0", | ||
"metadata":{ | ||
"apiVersion":"2016-03-11", | ||
"endpointPrefix":"h2-service", | ||
"jsonVersion":"1.1", | ||
"protocol":"rest-json", | ||
"protocolSettings":{"h2":"eventstream"}, | ||
"serviceAbbreviation":"H2 Service", | ||
"serviceFullName":"H2 Test Service", | ||
"serviceId":"H2 Service", | ||
"signatureVersion":"v4", | ||
"targetPrefix":"ProtocolTestsService", | ||
"uid":"restjson-2016-03-11" | ||
}, | ||
"operations":{ | ||
"OneOperation":{ | ||
"name":"OneOperation", | ||
"http":{ | ||
"method":"POST", | ||
"requestUri":"/2016-03-11/oneoperation" | ||
}, | ||
"input":{"shape":"OneShape"} | ||
} | ||
}, | ||
"shapes": { | ||
"OneShape": { | ||
"type": "structure", | ||
"members": { | ||
"StringMember": { | ||
"shape": "String" | ||
} | ||
} | ||
}, | ||
"String":{"type":"string"} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"). | ||
* You may not use this file except in compliance with the License. | ||
* A copy of the License is located at | ||
* | ||
* http://aws.amazon.com/apache2.0 | ||
* | ||
* or in the "license" file accompanying this file. This file is distributed | ||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either | ||
* express or implied. See the License for the specific language governing | ||
* permissions and limitations under the License. | ||
*/ | ||
|
||
package software.amazon.awssdk.services.h2; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
import java.lang.invoke.MethodHandle; | ||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.MethodType; | ||
import java.net.ConnectException; | ||
import java.net.URI; | ||
import java.security.AccessController; | ||
import java.security.PrivilegedExceptionAction; | ||
import java.util.concurrent.CompletionException; | ||
import javax.net.ssl.SSLContext; | ||
import javax.net.ssl.SSLEngine; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.condition.EnabledIf; | ||
import software.amazon.awssdk.core.exception.SdkClientException; | ||
import software.amazon.awssdk.http.Protocol; | ||
import software.amazon.awssdk.http.ProtocolNegotiation; | ||
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient; | ||
|
||
public class AlpnHttpTest { | ||
|
||
@Test | ||
@EnabledIf("alpnSupported") | ||
public void clientWithDefaultSettingAlpn_httpRequest_doesNotThrowUnsupportedOperationException() { | ||
H2AsyncClient client = clientBuilderWithHttpEndpoint().build(); | ||
|
||
CompletionException e = assertThrows(CompletionException.class, () -> makeRequest(client)); | ||
assertThat(e).hasCauseInstanceOf(SdkClientException.class); | ||
assertThat(e.getCause()).hasCauseInstanceOf(ConnectException.class); | ||
assertThat(e.getMessage()).contains("Connection refused"); | ||
assertThat(e.getMessage()).doesNotContain("ALPN can only be used with HTTPS, not HTTP"); | ||
} | ||
|
||
@Test | ||
@EnabledIf("alpnSupported") | ||
public void clientWithUserConfiguredAlpn_httpRequest_throwsUnsupportedOperationException() { | ||
H2AsyncClient client = clientBuilderWithHttpEndpoint().httpClient(NettyNioAsyncHttpClient.builder() | ||
.protocolNegotiation(ProtocolNegotiation.ALPN) | ||
.protocol(Protocol.HTTP2) | ||
.build()) | ||
.build(); | ||
|
||
CompletionException e = assertThrows(CompletionException.class, () -> makeRequest(client)); | ||
assertThat(e).hasCauseInstanceOf(SdkClientException.class); | ||
assertThat(e.getCause()).hasCauseInstanceOf(UnsupportedOperationException.class); | ||
assertThat(e.getMessage()).contains("ALPN can only be used with HTTPS, not HTTP"); | ||
} | ||
|
||
private H2AsyncClientBuilder clientBuilderWithHttpEndpoint() { | ||
return H2AsyncClient.builder() | ||
.endpointOverride(URI.create("http://localhost:8080")); | ||
} | ||
|
||
private void makeRequest(H2AsyncClient client) { | ||
client.oneOperation(c -> c.stringMember("payload")).join(); | ||
} | ||
|
||
private static boolean alpnSupported() { | ||
try { | ||
SSLContext context = SSLContext.getInstance("TLS"); | ||
context.init(null, null, null); | ||
SSLEngine engine = context.createSSLEngine(); | ||
MethodHandles.Lookup lookup = MethodHandles.lookup(); | ||
|
||
MethodHandle getApplicationProtocol = AccessController.doPrivileged( | ||
(PrivilegedExceptionAction<MethodHandle>) () -> | ||
lookup.findVirtual(SSLEngine.class, "getApplicationProtocol", MethodType.methodType(String.class))); | ||
|
||
getApplicationProtocol.invoke(engine); | ||
return true; | ||
} catch (Throwable t) { | ||
return false; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This log will be logged for every request. What is the significance of this log, as in if the default ALPN is not supported for the service, won't we immediately get server-side exceptions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
discussed offline, will remove logging. We fallback to prior knowledge in
ChannelPipelineInitializer
. This scenario of ALPN default setting with HTTP endpoint should only be present in mock tests