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