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 static org.jboss.netty.channel.Channels.*;
19 import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
20
21 import java.util.List;
22 import java.util.Map.Entry;
23
24 import org.jboss.netty.buffer.ChannelBuffer;
25 import org.jboss.netty.buffer.ChannelBuffers;
26 import org.jboss.netty.channel.ChannelHandler;
27 import org.jboss.netty.channel.ChannelHandlerContext;
28 import org.jboss.netty.channel.ChannelPipeline;
29 import org.jboss.netty.channel.Channels;
30 import org.jboss.netty.channel.MessageEvent;
31 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
32 import org.jboss.netty.handler.codec.frame.TooLongFrameException;
33 import org.jboss.netty.util.CharsetUtil;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class HttpChunkAggregator extends SimpleChannelUpstreamHandler {
59
60 private static final ChannelBuffer CONTINUE = ChannelBuffers.copiedBuffer(
61 "HTTP/1.1 100 Continue\r\n\r\n", CharsetUtil.US_ASCII);
62
63 private final int maxContentLength;
64 private HttpMessage currentMessage;
65
66
67
68
69
70
71
72
73
74 public HttpChunkAggregator(int maxContentLength) {
75 if (maxContentLength <= 0) {
76 throw new IllegalArgumentException(
77 "maxContentLength must be a positive integer: " +
78 maxContentLength);
79 }
80 this.maxContentLength = maxContentLength;
81 }
82
83 @Override
84 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
85 throws Exception {
86
87 Object msg = e.getMessage();
88 HttpMessage currentMessage = this.currentMessage;
89
90 if (msg instanceof HttpMessage) {
91 HttpMessage m = (HttpMessage) msg;
92
93
94
95
96
97
98 if (is100ContinueExpected(m)) {
99 write(ctx, succeededFuture(ctx.getChannel()), CONTINUE.duplicate());
100 }
101
102 if (m.isChunked()) {
103
104
105 List<String> encodings = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
106 encodings.remove(HttpHeaders.Values.CHUNKED);
107 if (encodings.isEmpty()) {
108 m.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
109 }
110 m.setChunked(false);
111 m.setContent(ChannelBuffers.dynamicBuffer(e.getChannel().getConfig().getBufferFactory()));
112 this.currentMessage = m;
113 } else {
114
115 this.currentMessage = null;
116 ctx.sendUpstream(e);
117 }
118 } else if (msg instanceof HttpChunk) {
119
120 if (currentMessage == null) {
121 throw new IllegalStateException(
122 "received " + HttpChunk.class.getSimpleName() +
123 " without " + HttpMessage.class.getSimpleName());
124 }
125
126
127 HttpChunk chunk = (HttpChunk) msg;
128 ChannelBuffer content = currentMessage.getContent();
129
130 if (content.readableBytes() > maxContentLength - chunk.getContent().readableBytes()) {
131
132
133
134
135 throw new TooLongFrameException(
136 "HTTP content length exceeded " + maxContentLength +
137 " bytes.");
138 }
139
140 content.writeBytes(chunk.getContent());
141 if (chunk.isLast()) {
142 this.currentMessage = null;
143
144
145 if (chunk instanceof HttpChunkTrailer) {
146 HttpChunkTrailer trailer = (HttpChunkTrailer) chunk;
147 for (Entry<String, String> header: trailer.getHeaders()) {
148 currentMessage.setHeader(header.getKey(), header.getValue());
149 }
150 }
151
152
153 currentMessage.setHeader(
154 HttpHeaders.Names.CONTENT_LENGTH,
155 String.valueOf(content.readableBytes()));
156
157
158 Channels.fireMessageReceived(ctx, currentMessage, e.getRemoteAddress());
159 }
160 } else {
161
162 ctx.sendUpstream(e);
163 }
164 }
165 }