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