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