1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.spdy;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufAllocator;
20 import io.netty.util.internal.ObjectUtil;
21
22 import java.nio.ByteOrder;
23 import java.util.Set;
24
25 import static io.netty.handler.codec.spdy.SpdyCodecUtil.*;
26
27
28
29
30 public class SpdyFrameEncoder {
31
32 private final int version;
33
34
35
36
37 public SpdyFrameEncoder(SpdyVersion spdyVersion) {
38 version = ObjectUtil.checkNotNull(spdyVersion, "spdyVersion").getVersion();
39 }
40
41 private void writeControlFrameHeader(ByteBuf buffer, int type, byte flags, int length) {
42 buffer.writeShort(version | 0x8000);
43 buffer.writeShort(type);
44 buffer.writeByte(flags);
45 buffer.writeMedium(length);
46 }
47
48 public ByteBuf encodeDataFrame(ByteBufAllocator allocator, int streamId, boolean last, ByteBuf data) {
49 byte flags = last ? SPDY_DATA_FLAG_FIN : 0;
50 int length = data.readableBytes();
51 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
52 frame.writeInt(streamId & 0x7FFFFFFF);
53 frame.writeByte(flags);
54 frame.writeMedium(length);
55 frame.writeBytes(data, data.readerIndex(), length);
56 return frame;
57 }
58
59 public ByteBuf encodeSynStreamFrame(ByteBufAllocator allocator, int streamId, int associatedToStreamId,
60 byte priority, boolean last, boolean unidirectional, ByteBuf headerBlock) {
61 int headerBlockLength = headerBlock.readableBytes();
62 byte flags = last ? SPDY_FLAG_FIN : 0;
63 if (unidirectional) {
64 flags |= SPDY_FLAG_UNIDIRECTIONAL;
65 }
66 int length = 10 + headerBlockLength;
67 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
68 writeControlFrameHeader(frame, SPDY_SYN_STREAM_FRAME, flags, length);
69 frame.writeInt(streamId);
70 frame.writeInt(associatedToStreamId);
71 frame.writeShort((priority & 0xFF) << 13);
72 frame.writeBytes(headerBlock, headerBlock.readerIndex(), headerBlockLength);
73 return frame;
74 }
75
76 public ByteBuf encodeSynReplyFrame(ByteBufAllocator allocator, int streamId, boolean last, ByteBuf headerBlock) {
77 int headerBlockLength = headerBlock.readableBytes();
78 byte flags = last ? SPDY_FLAG_FIN : 0;
79 int length = 4 + headerBlockLength;
80 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
81 writeControlFrameHeader(frame, SPDY_SYN_REPLY_FRAME, flags, length);
82 frame.writeInt(streamId);
83 frame.writeBytes(headerBlock, headerBlock.readerIndex(), headerBlockLength);
84 return frame;
85 }
86
87 public ByteBuf encodeRstStreamFrame(ByteBufAllocator allocator, int streamId, int statusCode) {
88 byte flags = 0;
89 int length = 8;
90 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
91 writeControlFrameHeader(frame, SPDY_RST_STREAM_FRAME, flags, length);
92 frame.writeInt(streamId);
93 frame.writeInt(statusCode);
94 return frame;
95 }
96
97 public ByteBuf encodeSettingsFrame(ByteBufAllocator allocator, SpdySettingsFrame spdySettingsFrame) {
98 Set<Integer> ids = spdySettingsFrame.ids();
99 int numSettings = ids.size();
100
101 byte flags = spdySettingsFrame.clearPreviouslyPersistedSettings() ?
102 SPDY_SETTINGS_CLEAR : 0;
103 int length = 4 + 8 * numSettings;
104 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
105 writeControlFrameHeader(frame, SPDY_SETTINGS_FRAME, flags, length);
106 frame.writeInt(numSettings);
107 for (Integer id : ids) {
108 flags = 0;
109 if (spdySettingsFrame.isPersistValue(id)) {
110 flags |= SPDY_SETTINGS_PERSIST_VALUE;
111 }
112 if (spdySettingsFrame.isPersisted(id)) {
113 flags |= SPDY_SETTINGS_PERSISTED;
114 }
115 frame.writeByte(flags);
116 frame.writeMedium(id);
117 frame.writeInt(spdySettingsFrame.getValue(id));
118 }
119 return frame;
120 }
121
122 public ByteBuf encodePingFrame(ByteBufAllocator allocator, int id) {
123 byte flags = 0;
124 int length = 4;
125 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
126 writeControlFrameHeader(frame, SPDY_PING_FRAME, flags, length);
127 frame.writeInt(id);
128 return frame;
129 }
130
131 public ByteBuf encodeGoAwayFrame(ByteBufAllocator allocator, int lastGoodStreamId, int statusCode) {
132 byte flags = 0;
133 int length = 8;
134 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
135 writeControlFrameHeader(frame, SPDY_GOAWAY_FRAME, flags, length);
136 frame.writeInt(lastGoodStreamId);
137 frame.writeInt(statusCode);
138 return frame;
139 }
140
141 public ByteBuf encodeHeadersFrame(ByteBufAllocator allocator, int streamId, boolean last, ByteBuf headerBlock) {
142 int headerBlockLength = headerBlock.readableBytes();
143 byte flags = last ? SPDY_FLAG_FIN : 0;
144 int length = 4 + headerBlockLength;
145 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
146 writeControlFrameHeader(frame, SPDY_HEADERS_FRAME, flags, length);
147 frame.writeInt(streamId);
148 frame.writeBytes(headerBlock, headerBlock.readerIndex(), headerBlockLength);
149 return frame;
150 }
151
152 public ByteBuf encodeWindowUpdateFrame(ByteBufAllocator allocator, int streamId, int deltaWindowSize) {
153 byte flags = 0;
154 int length = 8;
155 ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
156 writeControlFrameHeader(frame, SPDY_WINDOW_UPDATE_FRAME, flags, length);
157 frame.writeInt(streamId);
158 frame.writeInt(deltaWindowSize);
159 return frame;
160 }
161 }