continue netty 4 — we MUST write LastHttpContent or use FullHttpResponse

This commit is contained in:
Vladimir Krivosheev
2013-08-20 18:02:37 +02:00
parent 2f1696561e
commit fc0c11a7b2
4 changed files with 48 additions and 55 deletions
@@ -24,9 +24,9 @@ import io.netty.handler.codec.http.QueryStringDecoder;
abstract class DelegatingHttpRequestHandlerBase extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext context, FullHttpRequest message) throws Exception {
//if (BuiltInServer.LOG.isDebugEnabled()) {
//BuiltInServer.LOG.debug(request.toString());
//}
if (BuiltInServer.LOG.isDebugEnabled()) {
BuiltInServer.LOG.debug("IN HTTP:\n" + message);
}
if (!process(context, message, new QueryStringDecoder(message.getUri()))) {
Responses.sendStatus(HttpResponseStatus.NOT_FOUND, context.channel(), message);
@@ -32,6 +32,7 @@ import java.io.RandomAccessFile;
import java.text.ParseException;
import java.util.Date;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static org.jetbrains.io.Responses.*;
public class FileResponses {
@@ -46,7 +47,7 @@ public class FileResponses {
if (!StringUtil.isEmpty(ifModifiedSince)) {
try {
if (Responses.DATE_FORMAT.get().parse(ifModifiedSince).getTime() >= lastModified) {
sendStatus(HttpResponseStatus.NOT_MODIFIED, channel, request);
send(response(HttpResponseStatus.NOT_MODIFIED), channel, request);
return true;
}
}
@@ -67,7 +68,8 @@ public class FileResponses {
RandomAccessFile raf = new RandomAccessFile(file, "r");
try {
long fileLength = raf.length();
HttpResponse response = create(getContentType(file.getPath()));
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.headers().add(CONTENT_TYPE, getContentType(file.getPath()));
addCommonHeaders(response);
response.headers().set(HttpHeaders.Names.CACHE_CONTROL, "private, must-revalidate");
response.headers().set(HttpHeaders.Names.LAST_MODIFIED, Responses.DATE_FORMAT.get().format(new Date(file.lastModified())));
@@ -76,22 +78,22 @@ public class FileResponses {
HttpHeaders.setContentLength(response, fileLength);
}
ChannelFuture future = channel.write(response);
channel.write(response);
if (request.getMethod() != HttpMethod.HEAD) {
if (channel.pipeline().get(SslHandler.class) == null) {
// No encryption - use zero-copy
future = channel.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength));
channel.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength));
}
else {
// Cannot use zero-copy with HTTPS
future = channel.write(new ChunkedFile(raf, 0, fileLength, 8192));
channel.write(new ChunkedFile(raf, 0, fileLength, 8192));
}
}
ChannelFuture future = channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if (!keepAlive) {
future.addListener(ChannelFutureListener.CLOSE);
}
channel.flush();
fileWillBeClosed = true;
}
@@ -17,12 +17,11 @@ package org.jetbrains.io;
import com.intellij.openapi.util.AtomicNotNullLazyValue;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.*;
import io.netty.handler.codec.compression.JZlibEncoder;
import io.netty.handler.codec.compression.JdkZlibDecoder;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.jetbrains.annotations.NotNull;
@@ -105,6 +104,17 @@ final class PortUnificationServerHandler extends Decoder<ByteBuf> {
else {
NettyUtil.initHttpHandlers(pipeline);
pipeline.addLast(delegatingHttpRequestHandler);
if (BuiltInServer.LOG.isDebugEnabled()) {
pipeline.addLast(new ChannelOutboundHandlerAdapter() {
@Override
public void write(ChannelHandlerContext context, Object message, ChannelPromise promise) throws Exception {
if (message instanceof HttpMessage) {
BuiltInServer.LOG.debug("OUT HTTP:\n" + message);
}
super.write(context, message, promise);
}
});
}
}
}
// must be after new channels handlers addition (netty bug?)
@@ -52,6 +52,19 @@ public final class Responses {
private static String SERVER_HEADER_VALUE;
public static FullHttpResponse response(HttpResponseStatus status) {
return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.EMPTY_BUFFER);
}
public static HttpResponse create(@Nullable String contentType, @Nullable ByteBuf content) {
HttpResponse response =
new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content == null ? Unpooled.EMPTY_BUFFER : content);
if (contentType != null) {
response.headers().add(CONTENT_TYPE, contentType);
}
return response;
}
public static void addAllowAnyOrigin(HttpResponse response) {
response.headers().add(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
}
@@ -88,18 +101,10 @@ public final class Responses {
}
}
public static void send(String contentType, CharSequence content, Channel channel, HttpRequest request) {
send(create(contentType, Unpooled.copiedBuffer(content, CharsetUtil.UTF_8)), channel, request);
}
public static void send(HttpResponse response, Channel channel, @Nullable HttpRequest request) {
if (response.getStatus() != HttpResponseStatus.NOT_MODIFIED) {
if (response instanceof FullHttpResponse) {
HttpHeaders.setContentLength(response, ((FullHttpResponse)response).content().readableBytes());
}
else if (!HttpHeaders.isContentLengthSet(response)) {
HttpHeaders.setContentLength(response, 0);
}
if (response.getStatus() != HttpResponseStatus.NOT_MODIFIED && !HttpHeaders.isContentLengthSet(response)) {
HttpHeaders.setContentLength(response,
response instanceof FullHttpResponse ? ((FullHttpResponse)response).content().readableBytes() : 0);
}
addCommonHeaders(response);
@@ -120,34 +125,12 @@ public final class Responses {
addAllowAnyOrigin(response);
}
public static HttpResponse create(String contentType) {
return create(contentType, null);
}
public static HttpResponse create(@Nullable String contentType, @Nullable ByteBuf content) {
HttpResponse response = content == null
? new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
: new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
if (contentType != null) {
response.headers().add(CONTENT_TYPE, contentType);
}
return response;
}
public static void send(CharSequence content, Channel channel, @Nullable HttpRequest request) {
send(content, CharsetUtil.US_ASCII, channel, request);
}
public static void send(CharSequence content, Charset charset, Channel channel, @Nullable HttpRequest request) {
send(create(null, Unpooled.copiedBuffer(content, charset)), channel, request);
}
public static void send(HttpResponse response, Channel channel) {
send(response, channel, true);
}
public static void send(HttpResponseStatus status, ChannelHandlerContext context) {
send(new DefaultHttpResponse(HttpVersion.HTTP_1_1, status), context.channel());
send(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(content, charset)), channel, request);
}
private static void send(HttpResponse response, Channel channel, boolean close) {
@@ -155,7 +138,11 @@ public final class Responses {
return;
}
ChannelFuture future = channel.writeAndFlush(response);
ChannelFuture future = channel.write(response);
if (!(response instanceof FullHttpResponse)) {
channel.write(LastHttpContent.EMPTY_LAST_CONTENT);
}
channel.flush();
if (close) {
future.addListener(ChannelFutureListener.CLOSE);
}
@@ -173,14 +160,9 @@ public final class Responses {
send(createStatusResponse(responseStatus, request, description), channel, request);
}
public static void sendStatus(HttpResponse response, HttpRequest request, Channel channel) {
response.headers().add(CONTENT_TYPE, "text/html");
send(response, channel, request);
}
private static HttpResponse createStatusResponse(HttpResponseStatus responseStatus, @Nullable HttpRequest request, @Nullable String description) {
if (request != null && request.getMethod() == HttpMethod.HEAD) {
return new DefaultHttpResponse(HttpVersion.HTTP_1_1, responseStatus);
return response(responseStatus);
}
StringBuilder builder = new StringBuilder();
@@ -197,8 +179,7 @@ public final class Responses {
}
public static void sendOptionsResponse(String allowHeaders, HttpRequest request, ChannelHandlerContext context) {
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
addAllowAnyOrigin(response);
HttpResponse response = response(HttpResponseStatus.OK);
response.headers().set(ACCESS_CONTROL_ALLOW_METHODS, allowHeaders);
response.headers().set(ALLOW, allowHeaders);
send(response, context.channel(), request);