1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.eclipse.jetty.spdy.parser;
18
19 import java.nio.ByteBuffer;
20
21 import org.eclipse.jetty.spdy.api.DataInfo;
22 import org.eclipse.jetty.spdy.frames.DataFrame;
23
24 public abstract class DataFrameParser
25 {
26 private State state = State.STREAM_ID;
27 private int cursor;
28 private int streamId;
29 private byte flags;
30 private int length;
31
32
33
34
35
36
37
38 public boolean parse(ByteBuffer buffer)
39 {
40 while (buffer.hasRemaining())
41 {
42 switch (state)
43 {
44 case STREAM_ID:
45 {
46 if (buffer.remaining() >= 4)
47 {
48 streamId = buffer.getInt() & 0x7F_FF_FF_FF;
49 state = State.FLAGS;
50 }
51 else
52 {
53 state = State.STREAM_ID_BYTES;
54 cursor = 4;
55 }
56 break;
57 }
58 case STREAM_ID_BYTES:
59 {
60 byte currByte = buffer.get();
61 --cursor;
62 streamId += (currByte & 0xFF) << 8 * cursor;
63 if (cursor == 0)
64 state = State.FLAGS;
65 break;
66 }
67 case FLAGS:
68 {
69 flags = buffer.get();
70 cursor = 3;
71 state = State.LENGTH;
72 break;
73 }
74 case LENGTH:
75 {
76 byte currByte = buffer.get();
77 --cursor;
78 length += (currByte & 0xFF) << 8 * cursor;
79 if (cursor > 0)
80 break;
81 state = State.DATA;
82
83
84 if (length > 0)
85 break;
86 }
87 case DATA:
88 {
89
90
91
92
93
94
95 int size = Math.min(length, buffer.remaining());
96 int limit = buffer.limit();
97 buffer.limit(buffer.position() + size);
98 ByteBuffer bytes = buffer.slice();
99 buffer.limit(limit);
100 buffer.position(buffer.position() + size);
101 length -= size;
102 if (length == 0)
103 {
104 onDataFrame(bytes);
105 return true;
106 }
107 else
108 {
109
110
111 onDataFragment(bytes);
112 }
113 break;
114 }
115 default:
116 {
117 throw new IllegalStateException();
118 }
119 }
120 }
121 return false;
122 }
123
124 private void onDataFrame(ByteBuffer bytes)
125 {
126 DataFrame frame = new DataFrame(streamId, flags, bytes.remaining());
127 onDataFrame(frame, bytes);
128 reset();
129 }
130
131 private void onDataFragment(ByteBuffer bytes)
132 {
133 DataFrame frame = new DataFrame(streamId, (byte)(flags & ~DataInfo.FLAG_CLOSE), bytes.remaining());
134 onDataFrame(frame, bytes);
135
136 }
137
138 protected abstract void onDataFrame(DataFrame frame, ByteBuffer data);
139
140 private void reset()
141 {
142 state = State.STREAM_ID;
143 cursor = 0;
144 streamId = 0;
145 flags = 0;
146 length = 0;
147 }
148
149 private enum State
150 {
151 STREAM_ID, STREAM_ID_BYTES, FLAGS, LENGTH, DATA
152 }
153 }