1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http;
17
18 import org.jboss.netty.buffer.ChannelBuffer;
19 import org.jboss.netty.buffer.ChannelBuffers;
20 import org.jboss.netty.channel.ChannelHandlerContext;
21 import org.jboss.netty.channel.ChannelStateEvent;
22 import org.jboss.netty.channel.Channels;
23 import org.jboss.netty.channel.LifeCycleAwareChannelHandler;
24 import org.jboss.netty.channel.MessageEvent;
25 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
26 import org.jboss.netty.handler.codec.embedder.DecoderEmbedder;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public abstract class HttpContentDecoder extends SimpleChannelUpstreamHandler
48 implements LifeCycleAwareChannelHandler {
49
50 private DecoderEmbedder<ChannelBuffer> decoder;
51
52
53
54
55 protected HttpContentDecoder() {
56 }
57
58 @Override
59 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
60 Object msg = e.getMessage();
61 if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().getCode() == 100) {
62
63 ctx.sendUpstream(e);
64 } else if (msg instanceof HttpMessage) {
65 HttpMessage m = (HttpMessage) msg;
66
67
68 finishDecode();
69
70
71 String contentEncoding = m.getHeader(HttpHeaders.Names.CONTENT_ENCODING);
72 if (contentEncoding != null) {
73 contentEncoding = contentEncoding.trim();
74 } else {
75 contentEncoding = HttpHeaders.Values.IDENTITY;
76 }
77
78 boolean hasContent = m.isChunked() || m.getContent().readable();
79 if (hasContent && (decoder = newContentDecoder(contentEncoding)) != null) {
80
81
82 m.setHeader(
83 HttpHeaders.Names.CONTENT_ENCODING,
84 getTargetContentEncoding(contentEncoding));
85
86 if (!m.isChunked()) {
87 ChannelBuffer content = m.getContent();
88
89 content = ChannelBuffers.wrappedBuffer(
90 decode(content), finishDecode());
91
92
93 m.setContent(content);
94 if (m.containsHeader(HttpHeaders.Names.CONTENT_LENGTH)) {
95 m.setHeader(
96 HttpHeaders.Names.CONTENT_LENGTH,
97 Integer.toString(content.readableBytes()));
98 }
99 }
100 }
101
102
103 ctx.sendUpstream(e);
104 } else if (msg instanceof HttpChunk) {
105 HttpChunk c = (HttpChunk) msg;
106 ChannelBuffer content = c.getContent();
107
108
109 if (decoder != null) {
110 if (!c.isLast()) {
111 content = decode(content);
112 if (content.readable()) {
113 c.setContent(content);
114 ctx.sendUpstream(e);
115 }
116 } else {
117 ChannelBuffer lastProduct = finishDecode();
118
119
120
121 if (lastProduct.readable()) {
122 Channels.fireMessageReceived(
123 ctx, new DefaultHttpChunk(lastProduct), e.getRemoteAddress());
124 }
125
126
127 ctx.sendUpstream(e);
128 }
129 } else {
130 ctx.sendUpstream(e);
131 }
132 } else {
133 ctx.sendUpstream(e);
134 }
135 }
136
137 @Override
138 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
139
140 finishDecode();
141
142 super.channelClosed(ctx, e);
143 }
144
145
146
147
148
149
150
151
152
153
154 protected abstract DecoderEmbedder<ChannelBuffer> newContentDecoder(String contentEncoding) throws Exception;
155
156
157
158
159
160
161
162
163
164 protected String getTargetContentEncoding(String contentEncoding) throws Exception {
165 return HttpHeaders.Values.IDENTITY;
166 }
167
168 private ChannelBuffer decode(ChannelBuffer buf) {
169 decoder.offer(buf);
170 return ChannelBuffers.wrappedBuffer(decoder.pollAll(new ChannelBuffer[decoder.size()]));
171 }
172
173 private ChannelBuffer finishDecode() {
174 if (decoder == null) {
175 return ChannelBuffers.EMPTY_BUFFER;
176 }
177
178 ChannelBuffer result;
179 if (decoder.finish()) {
180 result = ChannelBuffers.wrappedBuffer(decoder.pollAll(new ChannelBuffer[decoder.size()]));
181 } else {
182 result = ChannelBuffers.EMPTY_BUFFER;
183 }
184 decoder = null;
185 return result;
186 }
187
188 public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
189
190 }
191
192 public void afterAdd(ChannelHandlerContext ctx) throws Exception {
193
194 }
195
196 public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
197
198 }
199
200 public void afterRemove(ChannelHandlerContext ctx) throws Exception {
201 finishDecode();
202 }
203 }