View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
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   * Decodes {@link ByteBuf}s into SPDY Frames.
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      // SPDY common header fields
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       * Creates a new instance with the specified {@code version}
87       * and the default {@code maxChunkSize (8192)}.
88       */
89      public SpdyFrameDecoder(SpdyVersion spdyVersion, SpdyFrameDecoderDelegate delegate) {
90          this(spdyVersion, delegate, 8192);
91      }
92  
93      /**
94       * Creates a new instance with the specified parameters.
95       */
96      public SpdyFrameDecoder(SpdyVersion spdyVersion, SpdyFrameDecoderDelegate delegate, int maxChunkSize) {
97          this(spdyVersion, delegate, maxChunkSize, DEFAULT_MAX_NUM_SETTINGS);
98      }
99  
100     /**
101      * Creates a new instance with the specified parameters.
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                         // Decode control frame common header
133                         version = getUnsignedShort(buffer, frameOffset) & 0x7FFF;
134                         frameType = getUnsignedShort(buffer, frameOffset + SPDY_HEADER_TYPE_OFFSET);
135                         streamId = 0; // Default to session Stream-ID
136                     } else {
137                         // Decode data frame common header
138                         version = spdyVersion; // Default to expected version
139                         frameType = SPDY_DATA_FRAME;
140                         streamId = getUnsignedInt(buffer, frameOffset);
141                     }
142 
143                     flags  = buffer.getByte(flagsOffset);
144                     length = getUnsignedMedium(buffer, lengthOffset);
145 
146                     // Check version first then validity
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                     // Generate data frames that do not exceed maxChunkSize
168                     int dataLength = Math.min(maxChunkSize, length);
169 
170                     // Wait until entire frame is readable
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                     // Validate frame length against number of entries. Each ID/Value entry is 8 bytes.
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      * Decode the unknown frame, returns true if parsed something, otherwise false.
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      * Check whether the unknown frame is valid, if not, the frame will be discarded,
471      * otherwise, the frame will be passed to {@link #decodeUnknownFrame(int, byte, int, ByteBuf)}.
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 }