org.wso2.carbon.http2.transport.util.Http2ClientHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.http2.transport.util.Http2ClientHandler.java

Source

/*
 *   Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *   WSO2 Inc. licenses this file to you 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 org.wso2.carbon.http2.transport.util;

import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http2.Http2Connection;
import io.netty.handler.codec.http2.Http2ConnectionEncoder;
import io.netty.handler.codec.http2.Http2DataFrame;
import io.netty.handler.codec.http2.Http2Error;
import io.netty.handler.codec.http2.Http2GoAwayFrame;
import io.netty.handler.codec.http2.Http2HeadersFrame;
import io.netty.handler.codec.http2.Http2ResetFrame;
import io.netty.handler.codec.http2.Http2Settings;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.inbound.InboundResponseSender;
import org.apache.synapse.transport.passthru.config.TargetConfiguration;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;

/**
 * Sending requests and receiving responses from a backend server
 */
public class Http2ClientHandler extends ChannelDuplexHandler {

    private static final Log log = LogFactory.getLog(Http2ClientHandler.class);

    private Http2RequestWriter writer;
    private Http2ResponseReceiver receiver;
    private Http2Connection connection;
    private Http2ConnectionEncoder encoder;
    private ChannelHandlerContext chContext;
    private Map<Integer, MessageContext> sentRequests;
    private LinkedList<MessageContext> pollReqeusts;

    public Http2ClientHandler(Http2Connection connection) {
        this.connection = connection;
        sentRequests = new TreeMap<>();
        writer = new Http2RequestWriter(connection);
        pollReqeusts = new LinkedList<>();
    }

    /**
     * Read respond frames from netty channel and pass to ResponseReceiver
     *
     * @param ctx
     * @param msg
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof Http2HeadersFrame) {
            Http2HeadersFrame frame = (Http2HeadersFrame) msg;
            if (!sentRequests.containsKey(frame.streamId())) {
                return;
            }
            receiver.onHeadersFrameRead(frame, sentRequests.get(frame.streamId()));
            if (frame.isEndStream()) {
                sentRequests.remove(frame.streamId());
            }
        } else if (msg instanceof Http2DataFrame) {
            Http2DataFrame frame = (Http2DataFrame) msg;
            if (!sentRequests.containsKey(frame.streamId())) {
                return;
            }
            receiver.onDataFrameRead(frame, sentRequests.get(frame.streamId()));
            if (frame.isEndStream()) {
                sentRequests.remove(frame.streamId());
            }
        } else if (msg instanceof Http2PushPromiseFrame) {
            Http2PushPromiseFrame frame = (Http2PushPromiseFrame) msg;
            if (!sentRequests.containsKey(frame.streamId())) {
                return;
            }
            MessageContext prevRequest = sentRequests.get(frame.streamId());

            //if the inbound is not accept push requests reject them
            if (!receiver.isServerPushAccepted()) {
                writer.writeRestSreamRequest(frame.getPushPromiseId(), Http2Error.REFUSED_STREAM);
                return;
            }

            sentRequests.put(frame.getPushPromiseId(), prevRequest);
            receiver.onPushPromiseFrameRead(frame, prevRequest);

        } else if (msg instanceof Http2Settings) {
            setChContext(ctx);
            receiver.onUnknownFrameRead(msg);

        } else if (msg instanceof Http2GoAwayFrame) {
            receiver.onUnknownFrameRead(msg);

        } else if (msg instanceof Http2ResetFrame) {
            if (sentRequests.containsKey(((Http2ResetFrame) msg).streamId())) {
                sentRequests.remove(((Http2ResetFrame) msg).streamId());
            }
            receiver.onUnknownFrameRead(msg);

        } else {
            receiver.onUnknownFrameRead(msg);

        }
    }

    /**
     * Take requests from TransportSender and pass them to RequestWriter
     *
     * @param request
     * @throws AxisFault
     */
    public synchronized void channelWrite(MessageContext request) throws AxisFault {
        if (chContext == null) {
            pollReqeusts.add(request);
            return;
        }
        if (receiver.getInboundChannel() == null)
            receiver.setInboundChannel((ChannelHandlerContext) request.getProperty(Http2Constants.STREAM_CHANNEL));

        String requestType = (String) request.getProperty(Http2Constants.HTTP2_REQUEST_TYPE);
        if (requestType == null || requestType.equals(Http2Constants.HTTP2_CLIENT_SENT_REQEUST)) {
            int streamId = writer.getNextStreamId();
            sentRequests.put(streamId, request);
            writer.writeSimpleReqeust(streamId, request);

        } else if (requestType.equals(Http2Constants.HTTP2_RESET_REQEUST)) {
            int id = (int) request.getProperty(Http2Constants.HTTP2_SERVER_STREAM_ID);
            Http2Error code = (Http2Error) request.getProperty(Http2Constants.HTTP2_ERROR_CODE);
            writer.writeRestSreamRequest(id, code);

        } else if (requestType.equals(Http2Constants.HTTP2_GO_AWAY_REQUEST)) { //Basically GoAway caused to dispose handler
            int id = (int) request.getProperty(Http2Constants.HTTP2_SERVER_STREAM_ID);
            Http2Error code = (Http2Error) request.getProperty(Http2Constants.HTTP2_ERROR_CODE);
            writer.writeGoAwayReqeust(id, code);
        }
    }

    public Http2RequestWriter getWriter() {
        return writer;
    }

    public void setWriter(Http2RequestWriter writer) {
        this.writer = writer;
    }

    public Http2ResponseReceiver getReceiver() {
        return receiver;
    }

    public void setReceiver(Http2ResponseReceiver receiver) {
        this.receiver = receiver;
    }

    public Http2Connection getConnection() {
        return connection;
    }

    public void setConnection(Http2Connection connection) {
        this.connection = connection;
    }

    public Http2ConnectionEncoder getEncoder() {
        return encoder;
    }

    public void setEncoder(Http2ConnectionEncoder encoder) {
        this.encoder = encoder;
        writer.setEncoder(encoder);

    }

    public ChannelHandlerContext getChContext() {
        return chContext;
    }

    public void setChContext(ChannelHandlerContext chContext) {
        this.chContext = chContext;
        writer.setChannelHandlerContext(chContext);

        if (!pollReqeusts.isEmpty()) {
            Iterator<MessageContext> requests = pollReqeusts.iterator();
            while (requests.hasNext()) {
                try {
                    channelWrite(requests.next());
                } catch (Exception e) {
                    log.error("Error while sending polled messages before channel establishment", e);
                }
            }
        }
    }

    /**
     * Create new instance of Http2ResponseReceiver
     *
     * @param tenantDomain
     * @param dispatchSequence
     * @param errorSequence
     * @param responseSender
     * @param targetConfiguration
     * @param serverPushAccept
     */
    public void setResponseReceiver(String tenantDomain, String dispatchSequence, String errorSequence,
            InboundResponseSender responseSender, TargetConfiguration targetConfiguration,
            boolean serverPushAccept) {
        receiver = new Http2ResponseReceiver(tenantDomain, responseSender, serverPushAccept, dispatchSequence,
                errorSequence, targetConfiguration);
    }
}