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 static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_DATA_FLAG_FIN;
19 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_DATA_FRAME;
20 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_FLAG_FIN;
21 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_FLAG_UNIDIRECTIONAL;
22 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_GOAWAY_FRAME;
23 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_HEADERS_FRAME;
24 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_HEADER_FLAGS_OFFSET;
25 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_HEADER_LENGTH_OFFSET;
26 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_HEADER_SIZE;
27 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_HEADER_TYPE_OFFSET;
28 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_PING_FRAME;
29 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_RST_STREAM_FRAME;
30 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_SETTINGS_CLEAR;
31 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_SETTINGS_FRAME;
32 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_SETTINGS_PERSISTED;
33 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_SETTINGS_PERSIST_VALUE;
34 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_SYN_REPLY_FRAME;
35 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_SYN_STREAM_FRAME;
36 import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_WINDOW_UPDATE_FRAME;
37 import static io.netty.handler.codec.spdy.SpdyCodecUtil.getSignedInt;
38 import static io.netty.handler.codec.spdy.SpdyCodecUtil.getUnsignedInt;
39 import static io.netty.handler.codec.spdy.SpdyCodecUtil.getUnsignedMedium;
40 import static io.netty.handler.codec.spdy.SpdyCodecUtil.getUnsignedShort;
41 import io.netty.buffer.ByteBuf;
42 import io.netty.buffer.Unpooled;
43
44
45
46
47 public class SpdyFrameDecoder {
48
49 private final int spdyVersion;
50 private final int maxChunkSize;
51
52 private final SpdyFrameDecoderDelegate delegate;
53
54 private State state;
55
56
57 private byte flags;
58 private int length;
59 private int streamId;
60
61 private int numSettings;
62
63 private enum State {
64 READ_COMMON_HEADER,
65 READ_DATA_FRAME,
66 READ_SYN_STREAM_FRAME,
67 READ_SYN_REPLY_FRAME,
68 READ_RST_STREAM_FRAME,
69 READ_SETTINGS_FRAME,
70 READ_SETTING,
71 READ_PING_FRAME,
72 READ_GOAWAY_FRAME,
73 READ_HEADERS_FRAME,
74 READ_WINDOW_UPDATE_FRAME,
75 READ_HEADER_BLOCK,
76 DISCARD_FRAME,
77 FRAME_ERROR
78 }
79
80
81
82
83
84 public SpdyFrameDecoder(SpdyVersion spdyVersion, SpdyFrameDecoderDelegate delegate) {
85 this(spdyVersion, delegate, 8192);
86 }
87
88
89
90
91 public SpdyFrameDecoder(SpdyVersion spdyVersion, SpdyFrameDecoderDelegate delegate, int maxChunkSize) {
92 if (spdyVersion == null) {
93 throw new NullPointerException("spdyVersion");
94 }
95 if (delegate == null) {
96 throw new NullPointerException("delegate");
97 }
98 if (maxChunkSize <= 0) {
99 throw new IllegalArgumentException(
100 "maxChunkSize must be a positive integer: " + maxChunkSize);
101 }
102 this.spdyVersion = spdyVersion.getVersion();
103 this.delegate = delegate;
104 this.maxChunkSize = maxChunkSize;
105 state = State.READ_COMMON_HEADER;
106 }
107
108 public void decode(ByteBuf buffer) {
109 boolean last;
110 int statusCode;
111
112 while (true) {
113 switch(state) {
114 case READ_COMMON_HEADER:
115 if (buffer.readableBytes() < SPDY_HEADER_SIZE) {
116 return;
117 }
118
119 int frameOffset = buffer.readerIndex();
120 int flagsOffset = frameOffset + SPDY_HEADER_FLAGS_OFFSET;
121 int lengthOffset = frameOffset + SPDY_HEADER_LENGTH_OFFSET;
122 buffer.skipBytes(SPDY_HEADER_SIZE);
123
124 boolean control = (buffer.getByte(frameOffset) & 0x80) != 0;
125
126 int version;
127 int type;
128 if (control) {
129
130 version = getUnsignedShort(buffer, frameOffset) & 0x7FFF;
131 type = getUnsignedShort(buffer, frameOffset + SPDY_HEADER_TYPE_OFFSET);
132 streamId = 0;
133 } else {
134
135 version = spdyVersion;
136 type = SPDY_DATA_FRAME;
137 streamId = getUnsignedInt(buffer, frameOffset);
138 }
139
140 flags = buffer.getByte(flagsOffset);
141 length = getUnsignedMedium(buffer, lengthOffset);
142
143
144 if (version != spdyVersion) {
145 state = State.FRAME_ERROR;
146 delegate.readFrameError("Invalid SPDY Version");
147 } else if (!isValidFrameHeader(streamId, type, flags, length)) {
148 state = State.FRAME_ERROR;
149 delegate.readFrameError("Invalid Frame Error");
150 } else {
151 state = getNextState(type, length);
152 }
153 break;
154
155 case READ_DATA_FRAME:
156 if (length == 0) {
157 state = State.READ_COMMON_HEADER;
158 delegate.readDataFrame(streamId, hasFlag(flags, SPDY_DATA_FLAG_FIN), Unpooled.buffer(0));
159 break;
160 }
161
162
163 int dataLength = Math.min(maxChunkSize, length);
164
165
166 if (buffer.readableBytes() < dataLength) {
167 return;
168 }
169
170 ByteBuf data = buffer.alloc().buffer(dataLength);
171 data.writeBytes(buffer, dataLength);
172 length -= dataLength;
173
174 if (length == 0) {
175 state = State.READ_COMMON_HEADER;
176 }
177
178 last = length == 0 && hasFlag(flags, SPDY_DATA_FLAG_FIN);
179
180 delegate.readDataFrame(streamId, last, data);
181 break;
182
183 case READ_SYN_STREAM_FRAME:
184 if (buffer.readableBytes() < 10) {
185 return;
186 }
187
188 int offset = buffer.readerIndex();
189 streamId = getUnsignedInt(buffer, offset);
190 int associatedToStreamId = getUnsignedInt(buffer, offset + 4);
191 byte priority = (byte) (buffer.getByte(offset + 8) >> 5 & 0x07);
192 last = hasFlag(flags, SPDY_FLAG_FIN);
193 boolean unidirectional = hasFlag(flags, SPDY_FLAG_UNIDIRECTIONAL);
194 buffer.skipBytes(10);
195 length -= 10;
196
197 if (streamId == 0) {
198 state = State.FRAME_ERROR;
199 delegate.readFrameError("Invalid SYN_STREAM Frame");
200 } else {
201 state = State.READ_HEADER_BLOCK;
202 delegate.readSynStreamFrame(streamId, associatedToStreamId, priority, last, unidirectional);
203 }
204 break;
205
206 case READ_SYN_REPLY_FRAME:
207 if (buffer.readableBytes() < 4) {
208 return;
209 }
210
211 streamId = getUnsignedInt(buffer, buffer.readerIndex());
212 last = hasFlag(flags, SPDY_FLAG_FIN);
213
214 buffer.skipBytes(4);
215 length -= 4;
216
217 if (streamId == 0) {
218 state = State.FRAME_ERROR;
219 delegate.readFrameError("Invalid SYN_REPLY Frame");
220 } else {
221 state = State.READ_HEADER_BLOCK;
222 delegate.readSynReplyFrame(streamId, last);
223 }
224 break;
225
226 case READ_RST_STREAM_FRAME:
227 if (buffer.readableBytes() < 8) {
228 return;
229 }
230
231 streamId = getUnsignedInt(buffer, buffer.readerIndex());
232 statusCode = getSignedInt(buffer, buffer.readerIndex() + 4);
233 buffer.skipBytes(8);
234
235 if (streamId == 0 || statusCode == 0) {
236 state = State.FRAME_ERROR;
237 delegate.readFrameError("Invalid RST_STREAM Frame");
238 } else {
239 state = State.READ_COMMON_HEADER;
240 delegate.readRstStreamFrame(streamId, statusCode);
241 }
242 break;
243
244 case READ_SETTINGS_FRAME:
245 if (buffer.readableBytes() < 4) {
246 return;
247 }
248
249 boolean clear = hasFlag(flags, SPDY_SETTINGS_CLEAR);
250
251 numSettings = getUnsignedInt(buffer, buffer.readerIndex());
252 buffer.skipBytes(4);
253 length -= 4;
254
255
256 if ((length & 0x07) != 0 || length >> 3 != numSettings) {
257 state = State.FRAME_ERROR;
258 delegate.readFrameError("Invalid SETTINGS Frame");
259 } else {
260 state = State.READ_SETTING;
261 delegate.readSettingsFrame(clear);
262 }
263 break;
264
265 case READ_SETTING:
266 if (numSettings == 0) {
267 state = State.READ_COMMON_HEADER;
268 delegate.readSettingsEnd();
269 break;
270 }
271
272 if (buffer.readableBytes() < 8) {
273 return;
274 }
275
276 byte settingsFlags = buffer.getByte(buffer.readerIndex());
277 int id = getUnsignedMedium(buffer, buffer.readerIndex() + 1);
278 int value = getSignedInt(buffer, buffer.readerIndex() + 4);
279 boolean persistValue = hasFlag(settingsFlags, SPDY_SETTINGS_PERSIST_VALUE);
280 boolean persisted = hasFlag(settingsFlags, SPDY_SETTINGS_PERSISTED);
281 buffer.skipBytes(8);
282
283 --numSettings;
284
285 delegate.readSetting(id, value, persistValue, persisted);
286 break;
287
288 case READ_PING_FRAME:
289 if (buffer.readableBytes() < 4) {
290 return;
291 }
292
293 int pingId = getSignedInt(buffer, buffer.readerIndex());
294 buffer.skipBytes(4);
295
296 state = State.READ_COMMON_HEADER;
297 delegate.readPingFrame(pingId);
298 break;
299
300 case READ_GOAWAY_FRAME:
301 if (buffer.readableBytes() < 8) {
302 return;
303 }
304
305 int lastGoodStreamId = getUnsignedInt(buffer, buffer.readerIndex());
306 statusCode = getSignedInt(buffer, buffer.readerIndex() + 4);
307 buffer.skipBytes(8);
308
309 state = State.READ_COMMON_HEADER;
310 delegate.readGoAwayFrame(lastGoodStreamId, statusCode);
311 break;
312
313 case READ_HEADERS_FRAME:
314 if (buffer.readableBytes() < 4) {
315 return;
316 }
317
318 streamId = getUnsignedInt(buffer, buffer.readerIndex());
319 last = hasFlag(flags, SPDY_FLAG_FIN);
320
321 buffer.skipBytes(4);
322 length -= 4;
323
324 if (streamId == 0) {
325 state = State.FRAME_ERROR;
326 delegate.readFrameError("Invalid HEADERS Frame");
327 } else {
328 state = State.READ_HEADER_BLOCK;
329 delegate.readHeadersFrame(streamId, last);
330 }
331 break;
332
333 case READ_WINDOW_UPDATE_FRAME:
334 if (buffer.readableBytes() < 8) {
335 return;
336 }
337
338 streamId = getUnsignedInt(buffer, buffer.readerIndex());
339 int deltaWindowSize = getUnsignedInt(buffer, buffer.readerIndex() + 4);
340 buffer.skipBytes(8);
341
342 if (deltaWindowSize == 0) {
343 state = State.FRAME_ERROR;
344 delegate.readFrameError("Invalid WINDOW_UPDATE Frame");
345 } else {
346 state = State.READ_COMMON_HEADER;
347 delegate.readWindowUpdateFrame(streamId, deltaWindowSize);
348 }
349 break;
350
351 case READ_HEADER_BLOCK:
352 if (length == 0) {
353 state = State.READ_COMMON_HEADER;
354 delegate.readHeaderBlockEnd();
355 break;
356 }
357
358 if (!buffer.isReadable()) {
359 return;
360 }
361
362 int compressedBytes = Math.min(buffer.readableBytes(), length);
363 ByteBuf headerBlock = buffer.alloc().buffer(compressedBytes);
364 headerBlock.writeBytes(buffer, compressedBytes);
365 length -= compressedBytes;
366
367 delegate.readHeaderBlock(headerBlock);
368 break;
369
370 case DISCARD_FRAME:
371 int numBytes = Math.min(buffer.readableBytes(), length);
372 buffer.skipBytes(numBytes);
373 length -= numBytes;
374 if (length == 0) {
375 state = State.READ_COMMON_HEADER;
376 break;
377 }
378 return;
379
380 case FRAME_ERROR:
381 buffer.skipBytes(buffer.readableBytes());
382 return;
383
384 default:
385 throw new Error("Shouldn't reach here.");
386 }
387 }
388 }
389
390 private static boolean hasFlag(byte flags, byte flag) {
391 return (flags & flag) != 0;
392 }
393
394 private static State getNextState(int type, int length) {
395 switch (type) {
396 case SPDY_DATA_FRAME:
397 return State.READ_DATA_FRAME;
398
399 case SPDY_SYN_STREAM_FRAME:
400 return State.READ_SYN_STREAM_FRAME;
401
402 case SPDY_SYN_REPLY_FRAME:
403 return State.READ_SYN_REPLY_FRAME;
404
405 case SPDY_RST_STREAM_FRAME:
406 return State.READ_RST_STREAM_FRAME;
407
408 case SPDY_SETTINGS_FRAME:
409 return State.READ_SETTINGS_FRAME;
410
411 case SPDY_PING_FRAME:
412 return State.READ_PING_FRAME;
413
414 case SPDY_GOAWAY_FRAME:
415 return State.READ_GOAWAY_FRAME;
416
417 case SPDY_HEADERS_FRAME:
418 return State.READ_HEADERS_FRAME;
419
420 case SPDY_WINDOW_UPDATE_FRAME:
421 return State.READ_WINDOW_UPDATE_FRAME;
422
423 default:
424 if (length != 0) {
425 return State.DISCARD_FRAME;
426 } else {
427 return State.READ_COMMON_HEADER;
428 }
429 }
430 }
431
432 private static boolean isValidFrameHeader(int streamId, int type, byte flags, int length) {
433 switch (type) {
434 case SPDY_DATA_FRAME:
435 return streamId != 0;
436
437 case SPDY_SYN_STREAM_FRAME:
438 return length >= 10;
439
440 case SPDY_SYN_REPLY_FRAME:
441 return length >= 4;
442
443 case SPDY_RST_STREAM_FRAME:
444 return flags == 0 && length == 8;
445
446 case SPDY_SETTINGS_FRAME:
447 return length >= 4;
448
449 case SPDY_PING_FRAME:
450 return length == 4;
451
452 case SPDY_GOAWAY_FRAME:
453 return length == 8;
454
455 case SPDY_HEADERS_FRAME:
456 return length >= 4;
457
458 case SPDY_WINDOW_UPDATE_FRAME:
459 return length == 8;
460
461 default:
462 return true;
463 }
464 }
465 }