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 org.jboss.netty.buffer.ChannelBuffer;
19 import org.jboss.netty.channel.Channel;
20 import org.jboss.netty.channel.ChannelDownstreamHandler;
21 import org.jboss.netty.channel.ChannelEvent;
22 import org.jboss.netty.channel.ChannelHandler;
23 import org.jboss.netty.channel.ChannelHandlerContext;
24 import org.jboss.netty.channel.ChannelStateEvent;
25 import org.jboss.netty.channel.Channels;
26 import org.jboss.netty.channel.MessageEvent;
27 import org.jboss.netty.handler.codec.frame.FrameDecoder;
28
29
30
31
32
33
34
35
36 public class SpdyFrameCodec extends FrameDecoder
37 implements SpdyFrameDecoderDelegate, ChannelDownstreamHandler {
38
39 private static final SpdyProtocolException INVALID_FRAME =
40 new SpdyProtocolException("Received invalid frame");
41
42 private final SpdyFrameDecoder spdyFrameDecoder;
43 private final SpdyFrameEncoder spdyFrameEncoder;
44 private final SpdyHeaderBlockDecoder spdyHeaderBlockDecoder;
45 private final SpdyHeaderBlockEncoder spdyHeaderBlockEncoder;
46
47 private SpdyHeadersFrame spdyHeadersFrame;
48 private SpdySettingsFrame spdySettingsFrame;
49
50 private volatile ChannelHandlerContext ctx;
51
52
53
54
55
56
57
58
59 public SpdyFrameCodec(SpdyVersion version) {
60 this(version, 8192, 16384, 6, 15, 8);
61 }
62
63
64
65
66 public SpdyFrameCodec(
67 SpdyVersion version, int maxChunkSize, int maxHeaderSize,
68 int compressionLevel, int windowBits, int memLevel) {
69 this(version, maxChunkSize,
70 SpdyHeaderBlockDecoder.newInstance(version, maxHeaderSize),
71 SpdyHeaderBlockEncoder.newInstance(version, compressionLevel, windowBits, memLevel));
72 }
73
74 protected SpdyFrameCodec(SpdyVersion version, int maxChunkSize,
75 SpdyHeaderBlockDecoder spdyHeaderBlockDecoder, SpdyHeaderBlockEncoder spdyHeaderBlockEncoder) {
76 spdyFrameDecoder = new SpdyFrameDecoder(version, this, maxChunkSize);
77 spdyFrameEncoder = new SpdyFrameEncoder(version);
78 this.spdyHeaderBlockDecoder = spdyHeaderBlockDecoder;
79 this.spdyHeaderBlockEncoder = spdyHeaderBlockEncoder;
80 }
81
82 @Override
83 public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
84 super.beforeAdd(ctx);
85 this.ctx = ctx;
86 }
87
88 @Override
89 protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
90 spdyFrameDecoder.decode(buffer);
91 return null;
92 }
93
94 @Override
95 protected void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
96 try {
97 super.cleanup(ctx, e);
98 } finally {
99 spdyHeaderBlockDecoder.end();
100 synchronized (spdyHeaderBlockEncoder) {
101 spdyHeaderBlockEncoder.end();
102 }
103 }
104 }
105
106 public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent evt) throws Exception {
107 if (evt instanceof ChannelStateEvent) {
108 ChannelStateEvent e = (ChannelStateEvent) evt;
109 switch (e.getState()) {
110 case OPEN:
111 case CONNECTED:
112 case BOUND:
113 if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) {
114 synchronized (spdyHeaderBlockEncoder) {
115 spdyHeaderBlockEncoder.end();
116 }
117 }
118 }
119 }
120
121 if (!(evt instanceof MessageEvent)) {
122 ctx.sendDownstream(evt);
123 return;
124 }
125
126 final MessageEvent e = (MessageEvent) evt;
127 Object msg = e.getMessage();
128
129 if (msg instanceof SpdyDataFrame) {
130
131 SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg;
132 ChannelBuffer frame = spdyFrameEncoder.encodeDataFrame(
133 spdyDataFrame.getStreamId(),
134 spdyDataFrame.isLast(),
135 spdyDataFrame.getData()
136 );
137 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
138 return;
139 }
140
141 if (msg instanceof SpdySynStreamFrame) {
142
143 synchronized (spdyHeaderBlockEncoder) {
144 SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg;
145 ChannelBuffer frame = spdyFrameEncoder.encodeSynStreamFrame(
146 spdySynStreamFrame.getStreamId(),
147 spdySynStreamFrame.getAssociatedToStreamId(),
148 spdySynStreamFrame.getPriority(),
149 spdySynStreamFrame.isLast(),
150 spdySynStreamFrame.isUnidirectional(),
151 spdyHeaderBlockEncoder.encode(spdySynStreamFrame)
152 );
153
154 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
155 }
156 return;
157 }
158
159 if (msg instanceof SpdySynReplyFrame) {
160
161 synchronized (spdyHeaderBlockEncoder) {
162 SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg;
163 ChannelBuffer frame = spdyFrameEncoder.encodeSynReplyFrame(
164 spdySynReplyFrame.getStreamId(),
165 spdySynReplyFrame.isLast(),
166 spdyHeaderBlockEncoder.encode(spdySynReplyFrame)
167 );
168
169 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
170 }
171 return;
172 }
173
174 if (msg instanceof SpdyRstStreamFrame) {
175
176 SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg;
177 ChannelBuffer frame = spdyFrameEncoder.encodeRstStreamFrame(
178 spdyRstStreamFrame.getStreamId(),
179 spdyRstStreamFrame.getStatus().getCode()
180 );
181 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
182 return;
183 }
184
185 if (msg instanceof SpdySettingsFrame) {
186
187 SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg;
188 ChannelBuffer frame = spdyFrameEncoder.encodeSettingsFrame(
189 spdySettingsFrame
190 );
191 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
192 return;
193 }
194
195 if (msg instanceof SpdyPingFrame) {
196
197 SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg;
198 ChannelBuffer frame = spdyFrameEncoder.encodePingFrame(
199 spdyPingFrame.getId()
200 );
201 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
202 return;
203 }
204
205 if (msg instanceof SpdyGoAwayFrame) {
206
207 SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg;
208 ChannelBuffer frame = spdyFrameEncoder.encodeGoAwayFrame(
209 spdyGoAwayFrame.getLastGoodStreamId(),
210 spdyGoAwayFrame.getStatus().getCode()
211 );
212 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
213 return;
214 }
215
216 if (msg instanceof SpdyHeadersFrame) {
217
218 synchronized (spdyHeaderBlockEncoder) {
219 SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
220 ChannelBuffer frame = spdyFrameEncoder.encodeHeadersFrame(
221 spdyHeadersFrame.getStreamId(),
222 spdyHeadersFrame.isLast(),
223 spdyHeaderBlockEncoder.encode(spdyHeadersFrame)
224 );
225
226 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
227 }
228 return;
229 }
230
231 if (msg instanceof SpdyWindowUpdateFrame) {
232
233 SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg;
234 ChannelBuffer frame = spdyFrameEncoder.encodeWindowUpdateFrame(
235 spdyWindowUpdateFrame.getStreamId(),
236 spdyWindowUpdateFrame.getDeltaWindowSize()
237 );
238 Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress());
239 return;
240 }
241
242
243 ctx.sendDownstream(evt);
244 }
245
246 public void readDataFrame(int streamId, boolean last, ChannelBuffer data) {
247 SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId);
248 spdyDataFrame.setLast(last);
249 spdyDataFrame.setData(data);
250 Channels.fireMessageReceived(ctx, spdyDataFrame);
251 }
252
253 public void readSynStreamFrame(
254 int streamId, int associatedToStreamId, byte priority, boolean last, boolean unidirectional) {
255 SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(streamId, associatedToStreamId, priority);
256 spdySynStreamFrame.setLast(last);
257 spdySynStreamFrame.setUnidirectional(unidirectional);
258 spdyHeadersFrame = spdySynStreamFrame;
259 }
260
261 public void readSynReplyFrame(int streamId, boolean last) {
262 SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
263 spdySynReplyFrame.setLast(last);
264 spdyHeadersFrame = spdySynReplyFrame;
265 }
266
267 public void readRstStreamFrame(int streamId, int statusCode) {
268 SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, statusCode);
269 Channels.fireMessageReceived(ctx, spdyRstStreamFrame);
270 }
271
272 public void readSettingsFrame(boolean clearPersisted) {
273 spdySettingsFrame = new DefaultSpdySettingsFrame();
274 spdySettingsFrame.setClearPreviouslyPersistedSettings(clearPersisted);
275 }
276
277 public void readSetting(int id, int value, boolean persistValue, boolean persisted) {
278 spdySettingsFrame.setValue(id, value, persistValue, persisted);
279 }
280
281 public void readSettingsEnd() {
282 Object frame = spdySettingsFrame;
283 spdySettingsFrame = null;
284 Channels.fireMessageReceived(ctx, frame);
285 }
286
287 public void readPingFrame(int id) {
288 SpdyPingFrame spdyPingFrame = new DefaultSpdyPingFrame(id);
289 Channels.fireMessageReceived(ctx, spdyPingFrame);
290 }
291
292 public void readGoAwayFrame(int lastGoodStreamId, int statusCode) {
293 SpdyGoAwayFrame spdyGoAwayFrame = new DefaultSpdyGoAwayFrame(lastGoodStreamId, statusCode);
294 Channels.fireMessageReceived(ctx, spdyGoAwayFrame);
295 }
296
297 public void readHeadersFrame(int streamId, boolean last) {
298 spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamId);
299 spdyHeadersFrame.setLast(last);
300 }
301
302 public void readWindowUpdateFrame(int streamId, int deltaWindowSize) {
303 SpdyWindowUpdateFrame spdyWindowUpdateFrame = new DefaultSpdyWindowUpdateFrame(streamId, deltaWindowSize);
304 Channels.fireMessageReceived(ctx, spdyWindowUpdateFrame);
305 }
306
307 public void readHeaderBlock(ChannelBuffer headerBlock) {
308 try {
309 spdyHeaderBlockDecoder.decode(headerBlock, spdyHeadersFrame);
310 } catch (Exception e) {
311 Channels.fireExceptionCaught(ctx, e);
312 }
313 }
314
315 public void readHeaderBlockEnd() {
316 Object frame = null;
317 try {
318 spdyHeaderBlockDecoder.endHeaderBlock(spdyHeadersFrame);
319 frame = spdyHeadersFrame;
320 spdyHeadersFrame = null;
321 } catch (Exception e) {
322 Channels.fireExceptionCaught(ctx, e);
323 }
324 if (frame != null) {
325 Channels.fireMessageReceived(ctx, frame);
326 }
327 }
328
329 public void readFrameError(String message) {
330 Channels.fireExceptionCaught(ctx, INVALID_FRAME);
331 }
332 }