1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.spdy.parser;
20
21 import java.nio.ByteBuffer;
22
23 import org.eclipse.jetty.spdy.CompressionFactory;
24 import org.eclipse.jetty.spdy.api.ReplyInfo;
25 import org.eclipse.jetty.spdy.api.SPDY;
26 import org.eclipse.jetty.spdy.frames.ControlFrameType;
27 import org.eclipse.jetty.spdy.frames.SynReplyFrame;
28 import org.eclipse.jetty.util.Fields;
29
30 public class SynReplyBodyParser extends ControlFrameBodyParser
31 {
32 private final Fields headers = new Fields();
33 private final ControlFrameParser controlFrameParser;
34 private final HeadersBlockParser headersBlockParser;
35 private State state = State.STREAM_ID;
36 private int cursor;
37 private int streamId;
38
39 public SynReplyBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
40 {
41 this.controlFrameParser = controlFrameParser;
42 this.headersBlockParser = new SynReplyHeadersBlockParser(decompressor);
43 }
44
45 @Override
46 public boolean parse(ByteBuffer buffer)
47 {
48 while (buffer.hasRemaining())
49 {
50 switch (state)
51 {
52 case STREAM_ID:
53 {
54 if (buffer.remaining() >= 4)
55 {
56 streamId = buffer.getInt() & 0x7F_FF_FF_FF;
57 state = State.ADDITIONAL;
58 }
59 else
60 {
61 state = State.STREAM_ID_BYTES;
62 cursor = 4;
63 }
64 break;
65 }
66 case STREAM_ID_BYTES:
67 {
68 byte currByte = buffer.get();
69 --cursor;
70 streamId += (currByte & 0xFF) << 8 * cursor;
71 if (cursor == 0)
72 {
73 streamId &= 0x7F_FF_FF_FF;
74 state = State.ADDITIONAL;
75 }
76 break;
77 }
78 case ADDITIONAL:
79 {
80 switch (controlFrameParser.getVersion())
81 {
82 case SPDY.V2:
83 {
84 if (buffer.remaining() >= 2)
85 {
86 buffer.getShort();
87 state = State.HEADERS;
88 }
89 else
90 {
91 state = State.ADDITIONAL_BYTES;
92 cursor = 2;
93 }
94 break;
95 }
96 case SPDY.V3:
97 {
98 state = State.HEADERS;
99 break;
100 }
101 default:
102 {
103 throw new IllegalStateException();
104 }
105 }
106 break;
107 }
108 case ADDITIONAL_BYTES:
109 {
110 assert controlFrameParser.getVersion() == SPDY.V2;
111 buffer.get();
112 --cursor;
113 if (cursor == 0)
114 state = State.HEADERS;
115 break;
116 }
117 case HEADERS:
118 {
119 short version = controlFrameParser.getVersion();
120 int length = controlFrameParser.getLength() - getSynReplyDataLength(version);
121 if (headersBlockParser.parse(streamId, version, length, buffer))
122 {
123 byte flags = controlFrameParser.getFlags();
124 if (flags != 0 && flags != ReplyInfo.FLAG_CLOSE)
125 throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY);
126
127 SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Fields(headers, true));
128 controlFrameParser.onControlFrame(frame);
129
130 reset();
131 return true;
132 }
133 break;
134 }
135 default:
136 {
137 throw new IllegalStateException();
138 }
139 }
140 }
141 return false;
142 }
143
144 private int getSynReplyDataLength(short version)
145 {
146 switch (version)
147 {
148 case 2:
149 return 6;
150 case 3:
151 return 4;
152 default:
153 throw new IllegalStateException();
154 }
155 }
156
157 private void reset()
158 {
159 headers.clear();
160 state = State.STREAM_ID;
161 cursor = 0;
162 streamId = 0;
163 }
164
165 private enum State
166 {
167 STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS
168 }
169
170 private class SynReplyHeadersBlockParser extends HeadersBlockParser
171 {
172 public SynReplyHeadersBlockParser(CompressionFactory.Decompressor decompressor)
173 {
174 super(decompressor);
175 }
176
177 @Override
178 protected void onHeader(String name, String[] values)
179 {
180 for (String value : values)
181 headers.add(name, value);
182 }
183 }
184 }