@Override protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { if (msg instanceof SpdyDataFrame) { SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; ByteBuf data = spdyDataFrame.data(); byte flags = spdyDataFrame.isLast() ? SPDY_DATA_FLAG_FIN : 0; out.ensureWritable(SPDY_HEADER_SIZE + data.readableBytes()); out.writeInt(spdyDataFrame.getStreamId() & 0x7FFFFFFF); out.writeByte(flags); out.writeMedium(data.readableBytes()); out.writeBytes(data, data.readerIndex(), data.readableBytes()); } else if (msg instanceof SpdySynStreamFrame) { SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; ByteBuf data = compressHeaderBlock(encodeHeaderBlock(version, spdySynStreamFrame)); byte flags = spdySynStreamFrame.isLast() ? SPDY_FLAG_FIN : 0; if (spdySynStreamFrame.isUnidirectional()) { flags |= SPDY_FLAG_UNIDIRECTIONAL; } int headerBlockLength = data.readableBytes(); int length; if (version < 3) { length = headerBlockLength == 0 ? 12 : 10 + headerBlockLength; } else { length = 10 + headerBlockLength; } out.ensureWritable(SPDY_HEADER_SIZE + length); out.writeShort(version | 0x8000); out.writeShort(SPDY_SYN_STREAM_FRAME); out.writeByte(flags); out.writeMedium(length); out.writeInt(spdySynStreamFrame.getStreamId()); out.writeInt(spdySynStreamFrame.getAssociatedToStreamId()); if (version < 3) { // Restrict priorities for SPDY/2 to between 0 and 3 byte priority = spdySynStreamFrame.getPriority(); if (priority > 3) { priority = 3; } out.writeShort((priority & 0xFF) << 14); } else { out.writeShort((spdySynStreamFrame.getPriority() & 0xFF) << 13); } if (version < 3 && data.readableBytes() == 0) { out.writeShort(0); } out.writeBytes(data, data.readerIndex(), headerBlockLength); } else if (msg instanceof SpdySynReplyFrame) { SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; ByteBuf data = compressHeaderBlock(encodeHeaderBlock(version, spdySynReplyFrame)); byte flags = spdySynReplyFrame.isLast() ? SPDY_FLAG_FIN : 0; int headerBlockLength = data.readableBytes(); int length; if (version < 3) { length = headerBlockLength == 0 ? 8 : 6 + headerBlockLength; } else { length = 4 + headerBlockLength; } out.ensureWritable(SPDY_HEADER_SIZE + length); out.writeShort(version | 0x8000); out.writeShort(SPDY_SYN_REPLY_FRAME); out.writeByte(flags); out.writeMedium(length); out.writeInt(spdySynReplyFrame.getStreamId()); if (version < 3) { if (headerBlockLength == 0) { out.writeInt(0); } else { out.writeShort(0); } } out.writeBytes(data, data.readerIndex(), headerBlockLength); } else if (msg instanceof SpdyRstStreamFrame) { SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; out.ensureWritable(SPDY_HEADER_SIZE + 8); out.writeShort(version | 0x8000); out.writeShort(SPDY_RST_STREAM_FRAME); out.writeInt(8); out.writeInt(spdyRstStreamFrame.getStreamId()); out.writeInt(spdyRstStreamFrame.getStatus().getCode()); } else if (msg instanceof SpdySettingsFrame) { SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; byte flags = spdySettingsFrame.clearPreviouslyPersistedSettings() ? SPDY_SETTINGS_CLEAR : 0; Set<Integer> IDs = spdySettingsFrame.getIds(); int numEntries = IDs.size(); int length = 4 + numEntries * 8; out.ensureWritable(SPDY_HEADER_SIZE + length); out.writeShort(version | 0x8000); out.writeShort(SPDY_SETTINGS_FRAME); out.writeByte(flags); out.writeMedium(length); out.writeInt(numEntries); for (Integer ID : IDs) { int id = ID.intValue(); byte ID_flags = 0; if (spdySettingsFrame.isPersistValue(id)) { ID_flags |= SPDY_SETTINGS_PERSIST_VALUE; } if (spdySettingsFrame.isPersisted(id)) { ID_flags |= SPDY_SETTINGS_PERSISTED; } if (version < 3) { // Chromium Issue 79156 // SPDY setting ids are not written in network byte order // Write id assuming the architecture is little endian out.writeByte(id & 0xFF); out.writeByte(id >> 8 & 0xFF); out.writeByte(id >> 16 & 0xFF); out.writeByte(ID_flags); } else { out.writeByte(ID_flags); out.writeMedium(id); } out.writeInt(spdySettingsFrame.getValue(id)); } } else if (msg instanceof SpdyNoOpFrame) { out.ensureWritable(SPDY_HEADER_SIZE); out.writeShort(version | 0x8000); out.writeShort(SPDY_NOOP_FRAME); out.writeInt(0); } else if (msg instanceof SpdyPingFrame) { SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; out.ensureWritable(SPDY_HEADER_SIZE + 4); out.writeShort(version | 0x8000); out.writeShort(SPDY_PING_FRAME); out.writeInt(4); out.writeInt(spdyPingFrame.getId()); } else if (msg instanceof SpdyGoAwayFrame) { SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg; int length = version < 3 ? 4 : 8; out.ensureWritable(SPDY_HEADER_SIZE + length); out.writeShort(version | 0x8000); out.writeShort(SPDY_GOAWAY_FRAME); out.writeInt(length); out.writeInt(spdyGoAwayFrame.getLastGoodStreamId()); if (version >= 3) { out.writeInt(spdyGoAwayFrame.getStatus().getCode()); } } else if (msg instanceof SpdyHeadersFrame) { SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; ByteBuf data = compressHeaderBlock(encodeHeaderBlock(version, spdyHeadersFrame)); byte flags = spdyHeadersFrame.isLast() ? SPDY_FLAG_FIN : 0; int headerBlockLength = data.readableBytes(); int length; if (version < 3) { length = headerBlockLength == 0 ? 4 : 6 + headerBlockLength; } else { length = 4 + headerBlockLength; } out.ensureWritable(SPDY_HEADER_SIZE + length); out.writeShort(version | 0x8000); out.writeShort(SPDY_HEADERS_FRAME); out.writeByte(flags); out.writeMedium(length); out.writeInt(spdyHeadersFrame.getStreamId()); if (version < 3 && headerBlockLength != 0) { out.writeShort(0); } out.writeBytes(data, data.readerIndex(), headerBlockLength); } else if (msg instanceof SpdyWindowUpdateFrame) { SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg; out.ensureWritable(SPDY_HEADER_SIZE + 8); out.writeShort(version | 0x8000); out.writeShort(SPDY_WINDOW_UPDATE_FRAME); out.writeInt(8); out.writeInt(spdyWindowUpdateFrame.getStreamId()); out.writeInt(spdyWindowUpdateFrame.getDeltaWindowSize()); } else { throw new UnsupportedMessageTypeException(msg); } }