/*
 * Copyright 2018 Netflix, Inc.
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License 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 com.netflix.zuul.netty.server.http2;

import com.netflix.netty.common.channel.config.ChannelConfig;
import com.netflix.netty.common.channel.config.CommonChannelConfigKeys;
import com.netflix.netty.common.http2.DynamicHttp2FrameLogger;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http2.Http2Connection;
import io.netty.handler.codec.http2.Http2FrameCodec;
import io.netty.handler.codec.http2.Http2MultiplexCodec;
import io.netty.handler.codec.http2.Http2MultiplexCodecBuilder;
import io.netty.handler.codec.http2.Http2Settings;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.ssl.ApplicationProtocolNames;
import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
import io.netty.util.AttributeKey;

import java.util.function.Consumer;

import static com.netflix.zuul.netty.server.BaseZuulChannelInitializer.HTTP_CODEC_HANDLER_NAME;

/**
 * Http2 Or Http Handler
 *
 * Author: Arthur Gonigberg
 * Date: December 15, 2017
 */
public class Http2OrHttpHandler extends ApplicationProtocolNegotiationHandler {
    public static final AttributeKey<String> PROTOCOL_NAME = AttributeKey.valueOf("protocol_name");
    public static final AttributeKey<Http2Connection> H2_CONN_KEY = AttributeKey.newInstance("h2_connection");

    private static final DynamicHttp2FrameLogger FRAME_LOGGER = new DynamicHttp2FrameLogger(LogLevel.DEBUG, Http2FrameCodec.class);

    private final ChannelHandler http2StreamHandler;
    private final int maxConcurrentStreams;
    private final int initialWindowSize;
    private final long maxHeaderTableSize;
    private final long maxHeaderListSize;
    private final Consumer<ChannelPipeline> addHttpHandlerFn;


    public Http2OrHttpHandler(ChannelHandler http2StreamHandler, ChannelConfig channelConfig,
                              Consumer<ChannelPipeline> addHttpHandlerFn) {
        super(ApplicationProtocolNames.HTTP_1_1);
        this.http2StreamHandler = http2StreamHandler;
        this.maxConcurrentStreams = channelConfig.get(CommonChannelConfigKeys.maxConcurrentStreams);
        this.initialWindowSize = channelConfig.get(CommonChannelConfigKeys.initialWindowSize);
        this.maxHeaderTableSize = channelConfig.get(CommonChannelConfigKeys.maxHttp2HeaderTableSize);
        this.maxHeaderListSize = channelConfig.get(CommonChannelConfigKeys.maxHttp2HeaderListSize);
        this.addHttpHandlerFn = addHttpHandlerFn;
    }

    @Override
    protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
        if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
            ctx.channel().attr(PROTOCOL_NAME).set("HTTP/2");
            configureHttp2(ctx.pipeline());
            return;
        }
        if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) {
            ctx.channel().attr(PROTOCOL_NAME).set("HTTP/1.1");
            configureHttp1(ctx.pipeline());
            return;
        }

        throw new IllegalStateException("unknown protocol: " + protocol);
    }

    private void configureHttp2(ChannelPipeline pipeline) {

        // setup the initial stream settings for the server to use.
        Http2Settings settings = new Http2Settings()
                .maxConcurrentStreams(maxConcurrentStreams)
                .initialWindowSize(initialWindowSize)
                .headerTableSize(maxHeaderTableSize)
                .maxHeaderListSize(maxHeaderListSize);

        Http2MultiplexCodec multiplexCodec = Http2MultiplexCodecBuilder
                .forServer(http2StreamHandler)
                .frameLogger(FRAME_LOGGER)
                .initialSettings(settings)
                .validateHeaders(true)
                .build();
        pipeline.replace("codec_placeholder", HTTP_CODEC_HANDLER_NAME, multiplexCodec);

        // Need to pass the connection to our handler later, so store it on channel now.
        Http2Connection connection = multiplexCodec.connection();
        pipeline.channel().attr(H2_CONN_KEY).set(connection);
    }

    private void configureHttp1(ChannelPipeline pipeline) {
        addHttpHandlerFn.accept(pipeline);
    }
}

@@ -1048,26 +1048,26 @@
 p2.Http2
-Connection
+FrameCodec
 ;%0Aimport
@@ -1115,65 +1115,15 @@
 odec
-;%0Aimport io.netty.handler.codec.http2.Http2MultiplexCodec
+Builder
 ;%0Aim
@@ -1170,26 +1170,21 @@
 ultiplex
-CodecBuild
+Handl
 er;%0Aimpo
@@ -1837,119 +1837,8 @@
 e%22);
-%0A    public static final AttributeKey%3CHttp2Connection%3E H2_CONN_KEY = AttributeKey.newInstance(%22h2_connection%22);
 %0A%0A  
@@ -4004,32 +4004,24 @@
 ttp2
-MultiplexCodec multiplex
+FrameCodec frame
 Code
@@ -4029,25 +4029,21 @@
  = Http2
-Multiplex
+Frame
 CodecBui
@@ -4050,54 +4050,19 @@
 lder
-%0A                .forServer(http2StreamHandler
+.forServer(
 )%0A  
@@ -4206,32 +4206,33 @@
   .build();%0A
+%0A
         
 pipeline.rep
@@ -4223,303 +4223,315 @@
     
-pipeline.replace(%22codec_placeholder%22, HTTP_CODEC_HANDLER_NAME, multiplexCodec);%0A%0A        // Need to pass the connection to our handler later, so store it on channel now.%0A        Http2Connection connection = multiplexCodec.connection();%0A        pipeline.channel().attr(H2_CONN_KEY).set(connection
+Http2MultiplexHandler multiplexHandler = new Http2MultiplexHandler(http2StreamHandler);%0A%0A        // The frame codec MUST be in the pipeline.%0A        pipeline.addBefore(%22codec_placeholder%22, /* name= */ null, frameCodec);%0A        pipeline.replace(%22codec_placeholder%22, HTTP_CODEC_HANDLER_NAME, multiplexHandler
 );%0A 

use non deprecated Http2 Multiplex handlers