Skip to content

Commit a887e92

Browse files
committed
Missing file headers
1 parent abafe2b commit a887e92

20 files changed

+417
-14
lines changed
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/*
2+
* Copyright 2012 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.codec.http;
17+
18+
import io.netty.buffer.ByteBuf;
19+
import io.netty.channel.ChannelHandlerContext;
20+
import io.netty.channel.embedded.EmbeddedChannel;
21+
import io.netty.handler.codec.CodecException;
22+
import io.netty.handler.codec.MessageToMessageDecoder;
23+
import io.netty.util.ReferenceCountUtil;
24+
25+
import java.util.List;
26+
27+
/**
28+
* Decodes the content of the received {@link HttpRequest} and {@link HttpContent}.
29+
* The original content is replaced with the new content decoded by the
30+
* {@link EmbeddedChannel}, which is created by {@link #newContentDecoder(String)}.
31+
* Once decoding is finished, the value of the <tt>'Content-Encoding'</tt>
32+
* header is set to the target content encoding, as returned by {@link #getTargetContentEncoding(String)}.
33+
* Also, the <tt>'Content-Length'</tt> header is updated to the length of the
34+
* decoded content. If the content encoding of the original is not supported
35+
* by the decoder, {@link #newContentDecoder(String)} should return {@code null}
36+
* so that no decoding occurs (i.e. pass-through).
37+
* <p>
38+
* Please note that this is an abstract class. You have to extend this class
39+
* and implement {@link #newContentDecoder(String)} properly to make this class
40+
* functional. For example, refer to the source code of {@link HttpContentDecompressor}.
41+
* <p>
42+
* This handler must be placed after {@link HttpObjectDecoder} in the pipeline
43+
* so that this handler can intercept HTTP requests after {@link HttpObjectDecoder}
44+
* converts {@link ByteBuf}s into HTTP requests.
45+
*/
46+
public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObject> {
47+
48+
protected ChannelHandlerContext ctx;
49+
private EmbeddedChannel decoder;
50+
private boolean continueResponse;
51+
52+
@Override
53+
protected void decode(ChannelHandlerContext ctx, HttpObject msg, List<Object> out) throws Exception {
54+
if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().code() == 100) {
55+
56+
if (!(msg instanceof LastHttpContent)) {
57+
continueResponse = true;
58+
}
59+
// 100-continue response must be passed through.
60+
out.add(ReferenceCountUtil.retain(msg));
61+
return;
62+
}
63+
64+
if (continueResponse) {
65+
if (msg instanceof LastHttpContent) {
66+
continueResponse = false;
67+
}
68+
// 100-continue response must be passed through.
69+
out.add(ReferenceCountUtil.retain(msg));
70+
return;
71+
}
72+
73+
if (msg instanceof HttpMessage) {
74+
cleanup();
75+
final HttpMessage message = (HttpMessage) msg;
76+
final HttpHeaders headers = message.headers();
77+
78+
// Determine the content encoding.
79+
String contentEncoding = headers.get(HttpHeaders.Names.CONTENT_ENCODING);
80+
if (contentEncoding != null) {
81+
contentEncoding = contentEncoding.trim();
82+
} else {
83+
contentEncoding = HttpHeaders.Values.IDENTITY;
84+
}
85+
decoder = newContentDecoder(contentEncoding);
86+
87+
if (decoder == null) {
88+
if (message instanceof HttpContent) {
89+
((HttpContent) message).retain();
90+
}
91+
out.add(message);
92+
return;
93+
}
94+
95+
// Remove content-length header:
96+
// the correct value can be set only after all chunks are processed/decoded.
97+
// If buffering is not an issue, add HttpObjectAggregator down the chain, it will set the header.
98+
// Otherwise, rely on LastHttpContent message.
99+
if (headers.contains(HttpHeaders.Names.CONTENT_LENGTH)) {
100+
headers.remove(HttpHeaders.Names.CONTENT_LENGTH);
101+
headers.set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
102+
}
103+
104+
// set new content encoding,
105+
CharSequence targetContentEncoding = getTargetContentEncoding(contentEncoding);
106+
if (HttpHeaders.Values.IDENTITY.equals(targetContentEncoding)) {
107+
// Do NOT set the 'Content-Encoding' header if the target encoding is 'identity'
108+
// as per: http://tools.ietf.org/html/rfc2616#section-14.11
109+
headers.remove(HttpHeaders.Names.CONTENT_ENCODING);
110+
} else {
111+
headers.set(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
112+
}
113+
114+
if (message instanceof HttpContent) {
115+
// If message is a full request or response object (headers + data), don't copy data part into out.
116+
// Output headers only; data part will be decoded below.
117+
// Note: "copy" object must not be an instance of LastHttpContent class,
118+
// as this would (erroneously) indicate the end of the HttpMessage to other handlers.
119+
HttpMessage copy;
120+
if (message instanceof HttpRequest) {
121+
HttpRequest r = (HttpRequest) message; // HttpRequest or FullHttpRequest
122+
copy = new DefaultHttpRequest(r.getProtocolVersion(), r.getMethod(), r.getUri());
123+
} else if (message instanceof HttpResponse) {
124+
HttpResponse r = (HttpResponse) message; // HttpResponse or FullHttpResponse
125+
copy = new DefaultHttpResponse(r.getProtocolVersion(), r.getStatus());
126+
} else {
127+
throw new CodecException("Object of class " + message.getClass().getName() +
128+
" is not a HttpRequest or HttpResponse");
129+
}
130+
copy.headers().set(message.headers());
131+
copy.setDecoderResult(message.getDecoderResult());
132+
out.add(copy);
133+
} else {
134+
out.add(message);
135+
}
136+
}
137+
138+
if (msg instanceof HttpContent) {
139+
final HttpContent c = (HttpContent) msg;
140+
if (decoder == null) {
141+
out.add(c.retain());
142+
} else {
143+
decodeContent(c, out);
144+
}
145+
}
146+
}
147+
148+
private void decodeContent(HttpContent c, List<Object> out) {
149+
ByteBuf content = c.content();
150+
151+
decode(content, out);
152+
153+
if (c instanceof LastHttpContent) {
154+
finishDecode(out);
155+
156+
LastHttpContent last = (LastHttpContent) c;
157+
// Generate an additional chunk if the decoder produced
158+
// the last product on closure,
159+
HttpHeaders headers = last.trailingHeaders();
160+
if (headers.isEmpty()) {
161+
out.add(LastHttpContent.EMPTY_LAST_CONTENT);
162+
} else {
163+
out.add(new ComposedLastHttpContent(headers));
164+
}
165+
}
166+
}
167+
168+
/**
169+
* Returns a new {@link EmbeddedChannel} that decodes the HTTP message
170+
* content encoded in the specified <tt>contentEncoding</tt>.
171+
*
172+
* @param contentEncoding the value of the {@code "Content-Encoding"} header
173+
* @return a new {@link EmbeddedChannel} if the specified encoding is supported.
174+
* {@code null} otherwise (alternatively, you can throw an exception
175+
* to block unknown encoding).
176+
*/
177+
protected abstract EmbeddedChannel newContentDecoder(String contentEncoding) throws Exception;
178+
179+
/**
180+
* Returns the expected content encoding of the decoded content.
181+
* This getMethod returns {@code "identity"} by default, which is the case for
182+
* most decoders.
183+
*
184+
* @param contentEncoding the value of the {@code "Content-Encoding"} header
185+
* @return the expected content encoding of the new content
186+
*/
187+
protected String getTargetContentEncoding(
188+
@SuppressWarnings("UnusedParameters") String contentEncoding) throws Exception {
189+
return HttpHeaders.Values.IDENTITY;
190+
}
191+
192+
@Override
193+
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
194+
cleanup();
195+
super.handlerRemoved(ctx);
196+
}
197+
198+
@Override
199+
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
200+
cleanup();
201+
super.channelInactive(ctx);
202+
}
203+
204+
@Override
205+
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
206+
this.ctx = ctx;
207+
super.handlerAdded(ctx);
208+
}
209+
210+
private void cleanup() {
211+
if (decoder != null) {
212+
// Clean-up the previous decoder if not cleaned up correctly.
213+
if (decoder.finish()) {
214+
for (;;) {
215+
ByteBuf buf = (ByteBuf) decoder.readInbound();
216+
if (buf == null) {
217+
break;
218+
}
219+
// Release the buffer
220+
buf.release();
221+
}
222+
}
223+
decoder = null;
224+
}
225+
}
226+
227+
private void decode(ByteBuf in, List<Object> out) {
228+
// call retain here as it will call release after its written to the channel
229+
decoder.writeInbound(in.retain());
230+
fetchDecoderOutput(out);
231+
}
232+
233+
private void finishDecode(List<Object> out) {
234+
if (decoder.finish()) {
235+
fetchDecoderOutput(out);
236+
}
237+
decoder = null;
238+
}
239+
240+
private void fetchDecoderOutput(List<Object> out) {
241+
for (;;) {
242+
ByteBuf buf = (ByteBuf) decoder.readInbound();
243+
if (buf == null) {
244+
break;
245+
}
246+
if (!buf.isReadable()) {
247+
buf.release();
248+
continue;
249+
}
250+
out.add(new DefaultHttpContent(buf));
251+
}
252+
}
253+
}

client/src/test/java/org/asynchttpclient/AsyncHttpClientDefaultsTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
114
package org.asynchttpclient;
215

316
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.ASYNC_CLIENT_CONFIG_ROOT;

client/src/test/java/org/asynchttpclient/PostRedirectGetTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1111
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1212
*/
13-
1413
package org.asynchttpclient;
1514

1615
import static org.asynchttpclient.Dsl.*;

client/src/test/java/org/asynchttpclient/RC10KTest.java renamed to client/src/test/java/org/asynchttpclient/RC1KTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@
4040
import org.testng.annotations.Test;
4141

4242
/**
43-
* Reverse C10K Problem test.
43+
* Reverse C1K Problem test.
4444
*
4545
* @author Hubert Iwaniuk
4646
*/
47-
public class RC10KTest extends AbstractBasicTest {
48-
private static final int C10K = 1000;
47+
public class RC1KTest extends AbstractBasicTest {
48+
private static final int C1K = 1000;
4949
private static final String ARG_HEADER = "Arg";
5050
private static final int SRV_COUNT = 10;
5151
protected Server[] servers = new Server[SRV_COUNT];
@@ -89,10 +89,10 @@ public void handle(String s, Request r, HttpServletRequest req, HttpServletRespo
8989

9090
@Test(timeOut = 10 * 60 * 1000, groups = "scalability")
9191
public void rc10kProblem() throws IOException, ExecutionException, TimeoutException, InterruptedException {
92-
try (AsyncHttpClient ahc = asyncHttpClient(config().setMaxConnectionsPerHost(C10K).setKeepAlive(true))) {
93-
List<Future<Integer>> resps = new ArrayList<>(C10K);
92+
try (AsyncHttpClient ahc = asyncHttpClient(config().setMaxConnectionsPerHost(C1K).setKeepAlive(true))) {
93+
List<Future<Integer>> resps = new ArrayList<>(C1K);
9494
int i = 0;
95-
while (i < C10K) {
95+
while (i < C1K) {
9696
resps.add(ahc.prepareGet(String.format("http://localhost:%d/%d", ports[i % SRV_COUNT], i)).execute(new MyAsyncHandler(i++)));
9797
}
9898
i = 0;

client/src/test/java/org/asynchttpclient/RedirectBodyTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
114
package org.asynchttpclient;
215

316
import static org.asynchttpclient.Dsl.*;

client/src/test/java/org/asynchttpclient/handler/resumable/MapResumableProcessor.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
114
package org.asynchttpclient.handler.resumable;
215

316
import org.asynchttpclient.handler.resumable.ResumableAsyncHandler.ResumableProcessor;

client/src/test/java/org/asynchttpclient/handler/resumable/PropertiesBasedResumableProcesserTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
package org.asynchttpclient.handler.resumable;
2-
31
/*
42
* Copyright (c) 2010 Sonatype, Inc. All rights reserved.
53
*
@@ -12,6 +10,7 @@
1210
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1311
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1412
*/
13+
package org.asynchttpclient.handler.resumable;
1514

1615
import static org.testng.Assert.assertEquals;
1716

client/src/test/java/org/asynchttpclient/handler/resumable/ResumableAsyncHandlerTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
package org.asynchttpclient.handler.resumable;
2-
31
/*
42
* Copyright (c) 2010 Sonatype, Inc. All rights reserved.
53
*
@@ -12,6 +10,7 @@
1210
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1311
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1412
*/
13+
package org.asynchttpclient.handler.resumable;
1514

1615
import static org.asynchttpclient.Dsl.get;
1716
import static org.mockito.Matchers.anyObject;

client/src/test/java/org/asynchttpclient/handler/resumable/ResumableRandomAccessFileListenerTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
114
package org.asynchttpclient.handler.resumable;
215

316
import static org.mockito.Mockito.*;

client/src/test/java/org/asynchttpclient/netty/EventPipelineTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1111
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1212
*/
13-
1413
package org.asynchttpclient.netty;
1514

1615
import static org.asynchttpclient.Dsl.*;

0 commit comments

Comments
 (0)