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.headers().get(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 String targetContentEncoding = getTargetContentEncoding(contentEncoding);
83 if (HttpHeaders.Values.IDENTITY.equals(targetContentEncoding)) {
84
85
86 m.headers().remove(HttpHeaders.Names.CONTENT_ENCODING);
87 } else {
88 m.headers().set(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
89 }
90
91 if (!m.isChunked()) {
92 ChannelBuffer content = m.getContent();
93
94 content = ChannelBuffers.wrappedBuffer(
95 decode(content), finishDecode());
96
97
98 m.setContent(content);
99 if (m.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) {
100 m.headers().set(
101 HttpHeaders.Names.CONTENT_LENGTH,
102 Integer.toString(content.readableBytes()));
103 }
104 }
105 }
106
107
108 ctx.sendUpstream(e);
109 } else if (msg instanceof HttpChunk) {
110 HttpChunk c = (HttpChunk) msg;
111 ChannelBuffer content = c.getContent();
112
113
114 if (decoder != null) {
115 if (!c.isLast()) {
116 content = decode(content);
117 if (content.readable()) {
118 c.setContent(content);
119 ctx.sendUpstream(e);
120 }
121 } else {
122 ChannelBuffer lastProduct = finishDecode();
123
124
125
126 if (lastProduct.readable()) {
127 Channels.fireMessageReceived(
128 ctx, new DefaultHttpChunk(lastProduct), e.getRemoteAddress());
129 }
130
131
132 ctx.sendUpstream(e);
133 }
134 } else {
135 ctx.sendUpstream(e);
136 }
137 } else {
138 ctx.sendUpstream(e);
139 }
140 }
141
142 @Override
143 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
144
145 finishDecode();
146
147 super.channelClosed(ctx, e);
148 }
149
150
151
152
153
154
155
156
157
158
159 protected abstract DecoderEmbedder<ChannelBuffer> newContentDecoder(String contentEncoding) throws Exception;
160
161
162
163
164
165
166
167
168
169 protected String getTargetContentEncoding(String contentEncoding) throws Exception {
170 return HttpHeaders.Values.IDENTITY;
171 }
172
173 private ChannelBuffer decode(ChannelBuffer buf) {
174 decoder.offer(buf);
175 return ChannelBuffers.wrappedBuffer(decoder.pollAll(new ChannelBuffer[decoder.size()]));
176 }
177
178 private ChannelBuffer finishDecode() {
179 if (decoder == null) {
180 return ChannelBuffers.EMPTY_BUFFER;
181 }
182
183 ChannelBuffer result;
184 if (decoder.finish()) {
185 result = ChannelBuffers.wrappedBuffer(decoder.pollAll(new ChannelBuffer[decoder.size()]));
186 } else {
187 result = ChannelBuffers.EMPTY_BUFFER;
188 }
189 decoder = null;
190 return result;
191 }
192
193 public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
194
195 }
196
197 public void afterAdd(ChannelHandlerContext ctx) throws Exception {
198
199 }
200
201 public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
202
203 }
204
205 public void afterRemove(ChannelHandlerContext ctx) throws Exception {
206 finishDecode();
207 }
208 }