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

org.jboss.netty.handler.codec.spdy.SpdyFrameCodec Maven / Gradle / Ivy

Go to download

The Netty project is an effort to provide an asynchronous event-driven network application framework and tools for rapid development of maintainable high performance and high scalability protocol servers and clients. In other words, Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.

There is a newer version: 4.0.0.Alpha8
Show newest version
/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project 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.jboss.netty.handler.codec.spdy;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelDownstreamHandler;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.frame.FrameDecoder;

/**
 * A {@link ChannelHandler} that encodes and decodes SPDY Frames.
 * @apiviz.has org.jboss.netty.handler.codec.spdy.SpdyFrameDecoder
 * @apiviz.has org.jboss.netty.handler.codec.spdy.SpdyFrameEncoder
 * @apiviz.has org.jboss.netty.handler.codec.spdy.SpdyHeaderBlockDecoder
 * @apiviz.has org.jboss.netty.handler.codec.spdy.SpdyHeaderBlockEncoder
 */
public class SpdyFrameCodec extends FrameDecoder
        implements SpdyFrameDecoderDelegate, ChannelDownstreamHandler {

    private static final SpdyProtocolException INVALID_FRAME =
        new SpdyProtocolException("Received invalid frame");

    private final SpdyFrameDecoder spdyFrameDecoder;
    private final SpdyFrameEncoder spdyFrameEncoder;
    private final SpdyHeaderBlockDecoder spdyHeaderBlockDecoder;
    private final SpdyHeaderBlockEncoder spdyHeaderBlockEncoder;

    private SpdyHeadersFrame spdyHeadersFrame;
    private SpdySettingsFrame spdySettingsFrame;

    private volatile ChannelHandlerContext ctx;

    /**
     * Creates a new instance with the specified {@code version} and
     * the default decoder and encoder options
     * ({@code maxChunkSize (8192)}, {@code maxHeaderSize (16384)},
     * {@code compressionLevel (6)}, {@code windowBits (15)},
     * and {@code memLevel (8)}).
     */
    public SpdyFrameCodec(SpdyVersion version) {
        this(version, 8192, 16384, 6, 15, 8);
    }

    /**
     * Creates a new instance with the specified decoder and encoder options.
     */
    public SpdyFrameCodec(
            SpdyVersion version, int maxChunkSize, int maxHeaderSize,
            int compressionLevel, int windowBits, int memLevel) {
        this(version, maxChunkSize,
            SpdyHeaderBlockDecoder.newInstance(version, maxHeaderSize),
            SpdyHeaderBlockEncoder.newInstance(version, compressionLevel, windowBits, memLevel));
    }

    protected SpdyFrameCodec(SpdyVersion version, int maxChunkSize,
            SpdyHeaderBlockDecoder spdyHeaderBlockDecoder, SpdyHeaderBlockEncoder spdyHeaderBlockEncoder) {
        spdyFrameDecoder = new SpdyFrameDecoder(version, this, maxChunkSize);
        spdyFrameEncoder = new SpdyFrameEncoder(version);
        this.spdyHeaderBlockDecoder = spdyHeaderBlockDecoder;
        this.spdyHeaderBlockEncoder = spdyHeaderBlockEncoder;
    }

    @Override
    public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
        super.beforeAdd(ctx);
        this.ctx = ctx;
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
        spdyFrameDecoder.decode(buffer);
        return null;
    }

    @Override
    protected void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
        try {
            super.cleanup(ctx, e);
        } finally {
            spdyHeaderBlockDecoder.end();
            synchronized (spdyHeaderBlockEncoder) {
                spdyHeaderBlockEncoder.end();
            }
        }
    }

    public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent evt) throws Exception {
        if (evt instanceof ChannelStateEvent) {
            ChannelStateEvent e = (ChannelStateEvent) evt;
            switch (e.getState()) {
            case OPEN:
            case CONNECTED:
            case BOUND:
                if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) {
                    synchronized (spdyHeaderBlockEncoder) {
                      spdyHeaderBlockEncoder.end();
                    }
                }
            }
        }

        if (!(evt instanceof MessageEvent)) {
          ctx.sendDownstream(evt);
          return;
        }

        final MessageEvent e = (MessageEvent) evt;
        Object msg = e.getMessage();

        if (msg instanceof SpdyDataFrame) {

            SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg;
            ChannelBuffer frame = spdyFrameEncoder.encodeDataFrame(
                spdyDataFrame.getStreamId(),
                spdyDataFrame.isLast(),
                spdyDataFrame.getData()
            );
            Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            return;
        }

        if (msg instanceof SpdySynStreamFrame) {

            synchronized (spdyHeaderBlockEncoder) {
                SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg;
                ChannelBuffer frame = spdyFrameEncoder.encodeSynStreamFrame(
                    spdySynStreamFrame.getStreamId(),
                    spdySynStreamFrame.getAssociatedToStreamId(),
                    spdySynStreamFrame.getPriority(),
                    spdySynStreamFrame.isLast(),
                    spdySynStreamFrame.isUnidirectional(),
                    spdyHeaderBlockEncoder.encode(spdySynStreamFrame)
                );
                // Writes of compressed data must occur in order
                Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            }
            return;
        }

        if (msg instanceof SpdySynReplyFrame) {

            synchronized (spdyHeaderBlockEncoder) {
                SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg;
                ChannelBuffer frame = spdyFrameEncoder.encodeSynReplyFrame(
                    spdySynReplyFrame.getStreamId(),
                    spdySynReplyFrame.isLast(),
                    spdyHeaderBlockEncoder.encode(spdySynReplyFrame)
                );
                // Writes of compressed data must occur in order
                Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            }
            return;
        }

        if (msg instanceof SpdyRstStreamFrame) {

            SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg;
            ChannelBuffer frame = spdyFrameEncoder.encodeRstStreamFrame(
                spdyRstStreamFrame.getStreamId(),
                spdyRstStreamFrame.getStatus().getCode()
            );
            Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            return;
        }

        if (msg instanceof SpdySettingsFrame) {

            SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg;
            ChannelBuffer frame = spdyFrameEncoder.encodeSettingsFrame(
                spdySettingsFrame
            );
            Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            return;
        }

        if (msg instanceof SpdyPingFrame) {

            SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg;
            ChannelBuffer frame = spdyFrameEncoder.encodePingFrame(
                spdyPingFrame.getId()
            );
            Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            return;
        }

        if (msg instanceof SpdyGoAwayFrame) {

            SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg;
            ChannelBuffer frame = spdyFrameEncoder.encodeGoAwayFrame(
                spdyGoAwayFrame.getLastGoodStreamId(),
                spdyGoAwayFrame.getStatus().getCode()
            );
            Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            return;
        }

        if (msg instanceof SpdyHeadersFrame) {

            synchronized (spdyHeaderBlockEncoder) {
                SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
                ChannelBuffer frame = spdyFrameEncoder.encodeHeadersFrame(
                    spdyHeadersFrame.getStreamId(),
                    spdyHeadersFrame.isLast(),
                    spdyHeaderBlockEncoder.encode(spdyHeadersFrame)
                );
                // Writes of compressed data must occur in order
                Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            }
            return;
        }

        if (msg instanceof SpdyWindowUpdateFrame) {

            SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg;
            ChannelBuffer frame = spdyFrameEncoder.encodeWindowUpdateFrame(
                spdyWindowUpdateFrame.getStreamId(),
                spdyWindowUpdateFrame.getDeltaWindowSize()
            );
            Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
            return;
        }

        // Unknown message type
        ctx.sendDownstream(evt);
    }

    public void readDataFrame(int streamId, boolean last, ChannelBuffer data) {
        SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId);
        spdyDataFrame.setLast(last);
        spdyDataFrame.setData(data);
        Channels.fireMessageReceived(ctx, spdyDataFrame);
    }

    public void readSynStreamFrame(
        int streamId, int associatedToStreamId, byte priority, boolean last, boolean unidirectional) {
        SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(streamId, associatedToStreamId, priority);
        spdySynStreamFrame.setLast(last);
        spdySynStreamFrame.setUnidirectional(unidirectional);
        spdyHeadersFrame = spdySynStreamFrame;
    }

    public void readSynReplyFrame(int streamId, boolean last) {
        SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
        spdySynReplyFrame.setLast(last);
        spdyHeadersFrame = spdySynReplyFrame;
    }

    public void readRstStreamFrame(int streamId, int statusCode) {
        SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, statusCode);
        Channels.fireMessageReceived(ctx, spdyRstStreamFrame);
    }

    public void readSettingsFrame(boolean clearPersisted) {
        spdySettingsFrame = new DefaultSpdySettingsFrame();
        spdySettingsFrame.setClearPreviouslyPersistedSettings(clearPersisted);
    }

    public void readSetting(int id, int value, boolean persistValue, boolean persisted) {
        spdySettingsFrame.setValue(id, value, persistValue, persisted);
    }

    public void readSettingsEnd() {
        Object frame = spdySettingsFrame;
        spdySettingsFrame = null;
        Channels.fireMessageReceived(ctx, frame);
    }

    public void readPingFrame(int id) {
        SpdyPingFrame spdyPingFrame = new DefaultSpdyPingFrame(id);
        Channels.fireMessageReceived(ctx, spdyPingFrame);
    }

    public void readGoAwayFrame(int lastGoodStreamId, int statusCode) {
        SpdyGoAwayFrame spdyGoAwayFrame = new DefaultSpdyGoAwayFrame(lastGoodStreamId, statusCode);
        Channels.fireMessageReceived(ctx, spdyGoAwayFrame);
    }

    public void readHeadersFrame(int streamId, boolean last) {
        spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamId);
        spdyHeadersFrame.setLast(last);
    }

    public void readWindowUpdateFrame(int streamId, int deltaWindowSize) {
        SpdyWindowUpdateFrame spdyWindowUpdateFrame = new DefaultSpdyWindowUpdateFrame(streamId, deltaWindowSize);
        Channels.fireMessageReceived(ctx, spdyWindowUpdateFrame);
    }

    public void readHeaderBlock(ChannelBuffer headerBlock) {
        try {
            spdyHeaderBlockDecoder.decode(headerBlock, spdyHeadersFrame);
        } catch (Exception e) {
            Channels.fireExceptionCaught(ctx, e);
        }
    }

    public void readHeaderBlockEnd() {
        Object frame = null;
        try {
            spdyHeaderBlockDecoder.endHeaderBlock(spdyHeadersFrame);
            frame = spdyHeadersFrame;
            spdyHeadersFrame = null;
        } catch (Exception e) {
            Channels.fireExceptionCaught(ctx, e);
        }
        if (frame != null) {
            Channels.fireMessageReceived(ctx, frame);
        }
    }

    public void readFrameError(String message) {
        Channels.fireExceptionCaught(ctx, INVALID_FRAME);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy