All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.awssdk.http.nio.netty.internal.ChannelPipelineInitializer Maven / Gradle / Ivy

Go to download

A single bundled dependency that includes all service and dependent JARs with third-party libraries relocated to different namespaces.

There is a newer version: 2.5.20
Show newest version
/*
 * Copyright 2010-2018 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.http.nio.netty.internal;

import static software.amazon.awssdk.http.nio.netty.internal.ChannelAttributeKey.MAX_CONCURRENT_STREAMS;
import static software.amazon.awssdk.http.nio.netty.internal.ChannelAttributeKey.PROTOCOL_FUTURE;
import static software.amazon.awssdk.utils.StringUtils.lowerCase;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.pool.AbstractChannelPoolHandler;
import io.netty.channel.pool.ChannelPool;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http2.ForkedHttp2MultiplexCodecBuilder;
import io.netty.handler.codec.http2.Http2Settings;
import io.netty.handler.codec.http2.Http2SettingsFrame;
import io.netty.handler.ssl.SslContext;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.nio.netty.internal.http2.MultiplexedChannelRecord;
import software.amazon.awssdk.http.nio.netty.internal.http2.SdkHttp2FrameLogger;

/**
 * Configures the client pipeline to support HTTP/2 frames with multiplexed streams.
 */
@SdkInternalApi
public class ChannelPipelineInitializer extends AbstractChannelPoolHandler {
    private final Protocol protocol;
    private final SslContext sslCtx;
    private final long clientMaxStreams;
    private final AtomicReference channelPoolRef;

    public ChannelPipelineInitializer(Protocol protocol,
                                      SslContext sslCtx,
                                      long clientMaxStreams,
                                      AtomicReference channelPoolRef) {
        this.protocol = protocol;
        this.sslCtx = sslCtx;
        this.clientMaxStreams = clientMaxStreams;
        this.channelPoolRef = channelPoolRef;
    }

    @Override
    public void channelCreated(Channel ch) throws Exception {
        ch.attr(PROTOCOL_FUTURE).set(new CompletableFuture<>());
        ChannelPipeline pipeline = ch.pipeline();
        if (sslCtx != null) {
            pipeline.addLast(sslCtx.newHandler(ch.alloc()));
        }

        if (protocol == Protocol.HTTP2) {
            configureHttp2(ch, pipeline);
        } else {
            configureHttp11(ch, pipeline);
        }
    }

    private void configureHttp2(Channel ch, ChannelPipeline pipeline) {
        ForkedHttp2MultiplexCodecBuilder codecBuilder = ForkedHttp2MultiplexCodecBuilder
            .forClient(new NoOpChannelInitializer())
            .headerSensitivityDetector((name, value) -> lowerCase(name.toString()).equals("authorization"))
            .initialSettings(Http2Settings.defaultSettings().initialWindowSize(1_048_576));
        // If frame logging is enabled, add it
        SdkHttp2FrameLogger.frameLogger().ifPresent(codecBuilder::frameLogger);

        pipeline.addLast(codecBuilder.build());

        pipeline.addLast(new SimpleChannelInboundHandler() {
            @Override
            protected void channelRead0(ChannelHandlerContext ctx, Http2SettingsFrame msg) throws Exception {
                Long serverMaxStreams = Optional.ofNullable(msg.settings().maxConcurrentStreams()).orElse(Long.MAX_VALUE);
                ch.attr(MAX_CONCURRENT_STREAMS).set(Math.min(clientMaxStreams, serverMaxStreams));
                ch.attr(PROTOCOL_FUTURE).get().complete(Protocol.HTTP2);
            }

            @Override
            public void channelUnregistered(ChannelHandlerContext ctx) {
                if (!ch.attr(PROTOCOL_FUTURE).get().isDone()) {
                    channelError(new IOException("The channel was closed before the protocol could be determined."), ch);
                }
            }

            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                channelError(cause, ch);
            }
        });
    }

    private void channelError(Throwable cause, Channel ch) {
        ch.attr(PROTOCOL_FUTURE).get().completeExceptionally(cause);
        MultiplexedChannelRecord record = ch.attr(ChannelAttributeKey.CHANNEL_POOL_RECORD).get();
        // Deliver the exception to any child channels registered to this connection.
        if (record != null) {
            record.shutdownChildChannels(cause);
        }
        // Channel status may still be active at this point even if it's not so queue up the close so that status is
        // accurately updated
        ch.eventLoop().submit(() -> {
            try {
                if (ch.isActive()) {
                    ch.close();
                }
            } finally {
                channelPoolRef.get().release(ch);
            }
        });
    }

    private void configureHttp11(Channel ch, ChannelPipeline pipeline) {
        pipeline.addLast(new HttpClientCodec());
        ch.attr(PROTOCOL_FUTURE).get().complete(Protocol.HTTP1_1);
    }

    private static class NoOpChannelInitializer extends ChannelInitializer {
        @Override
        protected void initChannel(Channel ch) throws Exception {
        }
    }

}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy