CorsHandler should release HttpRequest after processing preflight/error.

Motivation:
Currently, when the CorsHandler processes a preflight request, or
respondes with an 403 Forbidden using the short-curcuit option, the
HttpRequest is not released which leads to a buffer leak.

Modifications:
Releasing the HttpRequest when done processing a preflight request or
responding with an 403.

Result:
Using the CorsHandler will not cause buffer leaks.
This commit is contained in:
Daniel Bevenius 2014-10-21 09:47:42 +02:00 committed by Norman Maurer
parent 4e005b470f
commit a9dcdf8864
2 changed files with 30 additions and 2 deletions

View File

@ -29,6 +29,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
import static io.netty.handler.codec.http.HttpMethod.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.util.ReferenceCountUtil.release;
/**
* Handles <a href="http://www.w3.org/TR/cors/">Cross Origin Resource Sharing</a> (CORS) requests.
@ -72,6 +73,7 @@ public class CorsHandler extends ChannelDuplexHandler {
setMaxAge(response);
setPreflightHeaders(response);
}
release(request);
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
@ -199,6 +201,7 @@ public class CorsHandler extends ChannelDuplexHandler {
private static void forbidden(final ChannelHandlerContext ctx, final HttpRequest request) {
ctx.writeAndFlush(new DefaultFullHttpResponse(request.getProtocolVersion(), FORBIDDEN))
.addListener(ChannelFutureListener.CLOSE);
release(request);
}
}

View File

@ -237,6 +237,27 @@ public class CorsHandlerTest {
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is(nullValue()));
}
@Test
public void preflightRequestShouldReleaseRequest() {
final CorsConfig config = CorsConfig.withOrigin("http://localhost:8888")
.preflightResponseHeader("CustomHeader", Arrays.asList("value1", "value2"))
.build();
final EmbeddedChannel channel = new EmbeddedChannel(new CorsHandler(config));
final FullHttpRequest request = optionsRequest("http://localhost:8888", "content-type, xheader1");
channel.writeInbound(request);
assertThat(request.refCnt(), is(0));
}
@Test
public void forbiddenShouldReleaseRequest() {
final CorsConfig config = CorsConfig.withOrigin("https://localhost").shortCurcuit().build();
final EmbeddedChannel channel = new EmbeddedChannel(new CorsHandler(config), new EchoHandler());
final FullHttpRequest request = createHttpRequest(GET);
request.headers().set(ORIGIN, "http://localhost:8888");
channel.writeInbound(request);
assertThat(request.refCnt(), is(0));
}
private static HttpResponse simpleRequest(final CorsConfig config, final String origin) {
return simpleRequest(config, origin, null);
}
@ -267,12 +288,16 @@ public class CorsHandlerTest {
final String origin,
final String requestHeaders) {
final EmbeddedChannel channel = new EmbeddedChannel(new CorsHandler(config));
channel.writeInbound(optionsRequest(origin, requestHeaders));
return (HttpResponse) channel.readOutbound();
}
private static FullHttpRequest optionsRequest(final String origin, final String requestHeaders) {
final FullHttpRequest httpRequest = createHttpRequest(OPTIONS);
httpRequest.headers().set(ORIGIN, origin);
httpRequest.headers().set(ACCESS_CONTROL_REQUEST_METHOD, httpRequest.getMethod().toString());
httpRequest.headers().set(ACCESS_CONTROL_REQUEST_HEADERS, requestHeaders);
channel.writeInbound(httpRequest);
return (HttpResponse) channel.readOutbound();
return httpRequest;
}
private static FullHttpRequest createHttpRequest(HttpMethod method) {