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