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