better close/flush

This commit is contained in:
Jörg Prante 2023-03-30 17:44:14 +02:00
parent fc1beabb58
commit dfd3abd4a9
14 changed files with 113 additions and 152 deletions

View file

@ -34,18 +34,15 @@ public class Https1Handler extends ChannelDuplexHandler {
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpPipelinedRequest) { if (msg instanceof HttpPipelinedRequest httpPipelinedRequest) {
HttpPipelinedRequest httpPipelinedRequest = (HttpPipelinedRequest) msg;
try { try {
if (httpPipelinedRequest.getRequest() instanceof FullHttpRequest) { if (httpPipelinedRequest.getRequest() instanceof FullHttpRequest fullHttpRequest) {
FullHttpRequest fullHttpRequest = (FullHttpRequest) httpPipelinedRequest.getRequest();
requestReceived(ctx, fullHttpRequest, httpPipelinedRequest.getSequenceId()); requestReceived(ctx, fullHttpRequest, httpPipelinedRequest.getSequenceId());
} }
} finally { } finally {
httpPipelinedRequest.release(); httpPipelinedRequest.release();
} }
} else if (msg instanceof FullHttpRequest) { } else if (msg instanceof FullHttpRequest fullHttpRequest) {
FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
try { try {
requestReceived(ctx, fullHttpRequest, 0); requestReceived(ctx, fullHttpRequest, 0);
} finally { } finally {

View file

@ -36,8 +36,7 @@ public class Https2Handler extends ChannelDuplexHandler {
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) { if (msg instanceof FullHttpRequest fullHttpRequest) {
FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
HttpAddress httpAddress = ctx.channel().attr(NettyHttpsServerConfig.ATTRIBUTE_KEY_HTTP_ADDRESS).get(); HttpAddress httpAddress = ctx.channel().attr(NettyHttpsServerConfig.ATTRIBUTE_KEY_HTTP_ADDRESS).get();
try { try {
Integer streamId = fullHttpRequest.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()); Integer streamId = fullHttpRequest.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());

View file

@ -13,13 +13,9 @@ import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;
public class HttpRequestBuilder extends BaseHttpRequestBuilder { public class HttpRequestBuilder extends BaseHttpRequestBuilder {
private static final Logger logger = Logger.getLogger(HttpRequestBuilder.class.getName());
protected FullHttpRequest fullHttpRequest; protected FullHttpRequest fullHttpRequest;
protected ByteBuffer byteBuffer; protected ByteBuffer byteBuffer;
@ -117,7 +113,6 @@ public class HttpRequestBuilder extends BaseHttpRequestBuilder {
@Override @Override
public void release() { public void release() {
if (fullHttpRequest != null) { if (fullHttpRequest != null) {
logger.log(Level.FINER, "releasing retained netty request");
fullHttpRequest.release(); fullHttpRequest.release();
} }
} }

View file

@ -6,24 +6,16 @@ import java.io.IOException;
public class HttpResponse extends BaseHttpResponse { public class HttpResponse extends BaseHttpResponse {
private final HttpResponseBuilder builder;
protected HttpResponse(HttpResponseBuilder builder) { protected HttpResponse(HttpResponseBuilder builder) {
super(builder); super(builder);
this.builder = builder;
} }
public static HttpResponseBuilder builder() { public static HttpResponseBuilder builder() {
return new HttpResponseBuilder(); return new HttpResponseBuilder();
} }
@Override
public void close() throws IOException {
builder.release();
}
@Override @Override
public void flush() throws IOException { public void flush() throws IOException {
builder.flush(); // ignore
} }
} }

View file

@ -90,8 +90,8 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
} }
@Override @Override
public HttpResponseBuilder shouldFlush(boolean shouldFlush) { public HttpResponseBuilder withConnectionCloseHeader(boolean close) {
super.shouldFlush(shouldFlush); super.withConnectionCloseHeader(close);
return this; return this;
} }
@ -124,6 +124,24 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
return this; return this;
} }
@Override
public HttpResponse build() {
Objects.requireNonNull(ctx);
if (body != null) {
internalStringWrite(body);
} else if (charBuffer != null && charset != null) {
internalBufferWrite(charBuffer, charset);
} else if (dataBuffer != null) {
internalBufferWrite(dataBuffer);
} else if (fileChannel != null) {
internalFileWrite(fileChannel, bufferSize, true);
} else if (inputStream != null) {
internalStreamWrite(inputStream, bufferSize, true);
}
return new HttpResponse(this);
}
public void flush() { public void flush() {
internalBufferWrite(Unpooled.buffer(0)); internalBufferWrite(Unpooled.buffer(0));
} }
@ -131,47 +149,30 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
@Override @Override
public void release() { public void release() {
super.release(); super.release();
if (ctx != null && ctx.channel().isOpen()) {
logger.log(Level.FINER, "closing netty channel " + ctx.channel());
ctx.close();
}
} }
@Override private void internalStringWrite(String body) {
public HttpResponse build() { internalBufferWrite(dataBufferFactory.wrap(StandardCharsets.UTF_8.encode(body)));
Objects.requireNonNull(ctx);
if (body != null) {
internalWrite(body);
} else if (charBuffer != null && charset != null) {
internalWrite(charBuffer, charset);
} else if (dataBuffer != null) {
internalWrite(dataBuffer);
} else if (fileChannel != null) {
internalWrite(fileChannel, bufferSize, true);
} else if (inputStream != null) {
internalWrite(inputStream, bufferSize, true);
}
return new HttpResponse(this);
} }
private void internalWrite(String body) { private void internalBufferWrite(DataBuffer dataBuffer) {
internalWrite(dataBufferFactory.wrap(StandardCharsets.UTF_8.encode(body)));
}
private void internalWrite(DataBuffer dataBuffer) {
NettyDataBuffer nettyDataBuffer = (NettyDataBuffer) dataBuffer; NettyDataBuffer nettyDataBuffer = (NettyDataBuffer) dataBuffer;
internalBufferWrite(nettyDataBuffer.getNativeBuffer()); internalBufferWrite(nettyDataBuffer.getNativeBuffer());
} }
private void internalWrite(CharBuffer charBuffer, Charset charset) { private void internalBufferWrite(CharBuffer charBuffer, Charset charset) {
internalBufferWrite(ByteBufUtil.encodeString(ctx.alloc(), charBuffer, charset)); internalBufferWrite(ByteBufUtil.encodeString(ctx.alloc(), charBuffer, charset));
} }
private void internalBufferWrite(ByteBuf byteBuf) { private void internalBufferWrite(ByteBuf byteBuf) {
internalBufferWrite(byteBuf, byteBuf.readableBytes()); internalBufferWrite(byteBuf, byteBuf.readableBytes(), true);
} }
private void internalBufferWrite(ByteBuf byteBuf, int length) { private void internalBufferWrite(ByteBuf byteBuf, int length, boolean keepAlive) {
if (!ctx.channel().isWritable()) {
logger.log(Level.WARNING, "the channel " + ctx.channel() + " is not writable");
return;
}
super.buildHeaders(length); super.buildHeaders(length);
HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(status.code()); HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(status.code());
HttpHeaders headers = new DefaultHttpHeaders(); HttpHeaders headers = new DefaultHttpHeaders();
@ -186,25 +187,29 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
} }
HttpHeaders trailingHeaders = new DefaultHttpHeaders(); HttpHeaders trailingHeaders = new DefaultHttpHeaders();
super.trailingHeaders.entries().forEach(e -> trailingHeaders.add(e.getKey(), e.getValue())); super.trailingHeaders.entries().forEach(e -> trailingHeaders.add(e.getKey(), e.getValue()));
ctx.channel().eventLoop().execute(() -> {
FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.valueOf(version.text()), FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.valueOf(version.text()),
responseStatus, byteBuf.retain(), headers, trailingHeaders); responseStatus, byteBuf.retain(), headers, trailingHeaders);
if (!ctx.channel().isWritable()) { ChannelFuture channelFuture;
logger.log(Level.WARNING, "we have a problem, the channel " + ctx.channel() + " is not writable");
return;
}
if (sequenceId != null) { if (sequenceId != null) {
HttpPipelinedResponse httpPipelinedResponse = new HttpPipelinedResponse(fullHttpResponse, HttpPipelinedResponse httpPipelinedResponse = new HttpPipelinedResponse(fullHttpResponse,
ctx.channel().newPromise(), sequenceId); ctx.channel().newPromise(), sequenceId);
ctx.write(httpPipelinedResponse); channelFuture = ctx.write(httpPipelinedResponse);
} else { } else {
ctx.write(fullHttpResponse); channelFuture = ctx.write(fullHttpResponse);
}
if (!keepAlive || shouldClose()) {
logger.log(Level.FINER, "adding close listener to channel future " + channelFuture);
channelFuture.addListener(CLOSE);
} }
ctx.flush(); ctx.flush();
});
} }
private void internalWrite(FileChannel fileChannel, int bufferSize, boolean keepAlive) { private void internalFileWrite(FileChannel fileChannel, int bufferSize, boolean keepAlive) {
if (!ctx.channel().isWritable()) { if (!ctx.channel().isWritable()) {
logger.log(Level.WARNING, "channel not writeable: " + ctx.channel()); logger.log(Level.WARNING, "the channel is not writeable: " + ctx.channel());
return;
} }
HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(status.code()); HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(status.code());
DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, responseStatus); DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, responseStatus);
@ -216,21 +221,17 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} }
ChannelFuture channelFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); ChannelFuture channelFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if (headers.containsHeader(HttpHeaderNames.CONTENT_LENGTH)) { if (!keepAlive || shouldClose()) {
if (!keepAlive) {
logger.log(Level.FINER, "adding close listener to channel future " + channelFuture);
channelFuture.addListener(CLOSE);
}
} else {
logger.log(Level.FINER, "adding close listener to channel future " + channelFuture); logger.log(Level.FINER, "adding close listener to channel future " + channelFuture);
channelFuture.addListener(CLOSE); channelFuture.addListener(CLOSE);
} }
ctx.flush();
}); });
} }
private void internalWrite(InputStream inputStream, int bufferSize, boolean keepAlive) { private void internalStreamWrite(InputStream inputStream, int bufferSize, boolean keepAlive) {
if (!ctx.channel().isWritable()) { if (!ctx.channel().isWritable()) {
logger.log(Level.WARNING, "channel not writeable: " + ctx.channel()); logger.log(Level.WARNING, "the channel is not writeable: " + ctx.channel());
return; return;
} }
ByteBuf buffer; ByteBuf buffer;
@ -247,7 +248,7 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
return; return;
} }
if (count < bufferSize) { if (count < bufferSize) {
internalBufferWrite(buffer, count); internalBufferWrite(buffer, count, keepAlive);
} else { } else {
// chunked // chunked
super.buildHeaders(0); super.buildHeaders(0);
@ -259,6 +260,7 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
} }
HttpHeaders trailingHeaders = new DefaultHttpHeaders(); HttpHeaders trailingHeaders = new DefaultHttpHeaders();
super.trailingHeaders.entries().forEach(e -> trailingHeaders.add(e.getKey(), e.getValue())); super.trailingHeaders.entries().forEach(e -> trailingHeaders.add(e.getKey(), e.getValue()));
ctx.channel().eventLoop().execute(() -> {
DefaultHttpResponse defaultHttpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, responseStatus); DefaultHttpResponse defaultHttpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, responseStatus);
if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) { if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) {
headers.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); headers.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
@ -271,15 +273,12 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
ctx.write(defaultHttpResponse); ctx.write(defaultHttpResponse);
ctx.write(new ChunkedStream(inputStream, bufferSize)); ctx.write(new ChunkedStream(inputStream, bufferSize));
ChannelFuture channelFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); ChannelFuture channelFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if (headers.contains(HttpHeaderNames.CONTENT_LENGTH)) { if (!keepAlive || shouldClose) {
if (!keepAlive) {
logger.log(Level.FINER, "adding close listener to channel future " + channelFuture);
channelFuture.addListener(CLOSE);
}
} else {
logger.log(Level.FINER, "adding close listener to channel future " + channelFuture); logger.log(Level.FINER, "adding close listener to channel future " + channelFuture);
channelFuture.addListener(CLOSE); channelFuture.addListener(CLOSE);
} }
ctx.flush();
});
} }
} }
} }

View file

@ -36,8 +36,7 @@ public class Http2Handler extends ChannelDuplexHandler {
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object object) throws IOException { public void channelRead(ChannelHandlerContext ctx, Object object) throws IOException {
if (object instanceof FullHttpRequest) { if (object instanceof FullHttpRequest fullHttpRequest) {
FullHttpRequest fullHttpRequest = (FullHttpRequest) object;
HttpAddress httpAddress = ctx.channel().attr(NettyHttpServerConfig.ATTRIBUTE_KEY_HTTP_ADDRESS).get(); HttpAddress httpAddress = ctx.channel().attr(NettyHttpServerConfig.ATTRIBUTE_KEY_HTTP_ADDRESS).get();
try { try {
Integer streamId = fullHttpRequest.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()); Integer streamId = fullHttpRequest.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());

View file

@ -22,11 +22,6 @@ public class HttpResponse extends BaseHttpResponse {
this.builder = builder; this.builder = builder;
} }
@Override
public void close() throws IOException {
builder.internalClose();
}
@Override @Override
public void flush() throws IOException { public void flush() throws IOException {
builder.internalFlush(); builder.internalFlush();

View file

@ -38,9 +38,6 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
public HttpResponse build() { public HttpResponse build() {
Objects.requireNonNull(outputStream); Objects.requireNonNull(outputStream);
try { try {
if (shouldFlush()) {
internalFlush();
}
if (body != null) { if (body != null) {
internalWrite(body); internalWrite(body);
} else if (charBuffer != null && charset != null) { } else if (charBuffer != null && charset != null) {
@ -52,14 +49,20 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
} else if (inputStream != null) { } else if (inputStream != null) {
internalWrite(inputStream, bufferSize); internalWrite(inputStream, bufferSize);
} }
if (shouldClose()) {
internalClose();
}
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e); logger.log(Level.SEVERE, e.getMessage(), e);
} return new HttpResponse(this); } return new HttpResponse(this);
} }
@Override
public void release() {
try {
internalClose();
} catch (IOException e) {
logger.log(Level.WARNING, e.getMessage(), e);
}
}
void internalFlush() throws IOException { void internalFlush() throws IOException {
outputStream.flush(); outputStream.flush();
} }
@ -114,8 +117,4 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
channel.write(fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, contentLength)); channel.write(fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, contentLength));
} }
} }
@Override
public void release() {
}
} }

View file

@ -13,11 +13,6 @@ public class HttpResponse extends BaseHttpResponse {
this.builder = builder; this.builder = builder;
} }
@Override
public void close() throws IOException {
builder.internalClose();
}
@Override @Override
public void flush() throws IOException { public void flush() throws IOException {
builder.internalFlush(); builder.internalFlush();

View file

@ -38,9 +38,6 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
public HttpResponse build() { public HttpResponse build() {
Objects.requireNonNull(outputStream); Objects.requireNonNull(outputStream);
try { try {
if (shouldFlush()) {
internalFlush();
}
if (body != null) { if (body != null) {
internalWrite(body); internalWrite(body);
} else if (charBuffer != null && charset != null) { } else if (charBuffer != null && charset != null) {
@ -52,16 +49,22 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
} else if (inputStream != null) { } else if (inputStream != null) {
internalWrite(inputStream, bufferSize); internalWrite(inputStream, bufferSize);
} }
if (shouldClose()) {
internalClose();
}
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e); logger.log(Level.SEVERE, e.getMessage(), e);
} }
return new HttpResponse(this); return new HttpResponse(this);
} }
void internalFlush() throws IOException { @Override
public void release() {
try {
internalClose();
} catch (IOException e) {
logger.log(Level.WARNING, e.getMessage(), e);
}
}
void internalFlush() {
write(dataBufferFactory.allocateBuffer()); write(dataBufferFactory.allocateBuffer());
} }
@ -118,8 +121,4 @@ public class HttpResponseBuilder extends BaseHttpResponseBuilder {
channel.write(fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, contentLength)); channel.write(fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, contentLength));
} }
} }
@Override
public void release() {
}
} }

View file

@ -57,9 +57,9 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
*/ */
protected HttpServerConfig httpServerConfig; protected HttpServerConfig httpServerConfig;
protected boolean shouldClose; protected boolean withConnectionCloseHeader;
protected boolean shouldFlush; protected boolean shouldClose;
protected Integer sequenceId; protected Integer sequenceId;
@ -103,7 +103,7 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
this.trailingHeaders = new HttpHeaders(); this.trailingHeaders = new HttpHeaders();
this.contentType = HttpHeaderValues.APPLICATION_OCTET_STREAM; this.contentType = HttpHeaderValues.APPLICATION_OCTET_STREAM;
this.dataBufferFactory = DefaultDataBufferFactory.getInstance(); this.dataBufferFactory = DefaultDataBufferFactory.getInstance();
this.shouldClose = false; // tell client we want to keep the connection alive this.withConnectionCloseHeader = false; // tell client we want to keep the connection alive
this.attributes = new BaseAttributes(); this.attributes = new BaseAttributes();
} }
@ -204,23 +204,22 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
return this; return this;
} }
@Override @Override
public BaseHttpResponseBuilder shouldFlush(boolean shouldFlush) { public BaseHttpResponseBuilder withConnectionCloseHeader(boolean withConnectionCloseHeader) {
if (done) { if (done) {
return this; return this;
} }
this.shouldFlush = shouldFlush; this.withConnectionCloseHeader = withConnectionCloseHeader;
return this; return this;
} }
@Override @Override
public boolean shouldFlush() { public boolean withConnectionCloseHeader() {
return shouldFlush; return withConnectionCloseHeader;
} }
@Override @Override
public BaseHttpResponseBuilder shouldClose(boolean shouldClose) { public HttpResponseBuilder shouldClose(boolean shouldClose) {
if (done) { if (done) {
return this; return this;
} }
@ -265,7 +264,7 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
if (body != null && this.body == null) { if (body != null && this.body == null) {
this.body = body; this.body = body;
} else { } else {
logger.log(Level.WARNING, "cannot write null string"); logger.log(Level.WARNING, "cannot write more than one body");
} }
return this; return this;
} }
@ -276,7 +275,7 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
this.charBuffer = charBuffer; this.charBuffer = charBuffer;
this.charset = charset; this.charset = charset;
} else { } else {
logger.log(Level.WARNING, "cannot write CharBuffer"); logger.log(Level.WARNING, "cannot write more than one CharBuffer");
} }
return this; return this;
} }
@ -286,7 +285,7 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
if (dataBuffer != null && this.dataBuffer == null) { if (dataBuffer != null && this.dataBuffer == null) {
this.dataBuffer = dataBuffer; this.dataBuffer = dataBuffer;
} else { } else {
logger.log(Level.WARNING, "cannot write DataBuffer"); logger.log(Level.WARNING, "cannot write more than one DataBuffer");
} }
return this; return this;
} }
@ -297,7 +296,7 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
this.inputStream = inputStream; this.inputStream = inputStream;
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
} else { } else {
logger.log(Level.WARNING, "cannot write InputStream"); logger.log(Level.WARNING, "cannot write more than one InputStream");
} }
return this; return this;
} }
@ -308,7 +307,7 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
this.fileChannel = fileChannel; this.fileChannel = fileChannel;
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
} else { } else {
logger.log(Level.WARNING, "cannot write FileChannel"); logger.log(Level.WARNING, "cannot write more than one FileChannel");
} }
return this; return this;
} }
@ -347,7 +346,6 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
@Override @Override
public void release() { public void release() {
if (dataBuffer != null) { if (dataBuffer != null) {
logger.log(Level.FINER, "databuffer release " + dataBuffer);
dataBuffer.release(); dataBuffer.release();
} }
} }
@ -372,7 +370,7 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder {
headers.add(HttpHeaderNames.CONTENT_LENGTH, Long.toString(contentLength)); headers.add(HttpHeaderNames.CONTENT_LENGTH, Long.toString(contentLength));
} }
} }
if (shouldClose) { if (withConnectionCloseHeader) {
headers.add(HttpHeaderNames.CONNECTION, "close"); headers.add(HttpHeaderNames.CONNECTION, "close");
} }
if (!headers.containsHeader(HttpHeaderNames.DATE)) { if (!headers.containsHeader(HttpHeaderNames.DATE)) {

View file

@ -1,9 +1,7 @@
package org.xbib.net.http.server; package org.xbib.net.http.server;
import java.io.IOException;
import org.xbib.net.Response; import org.xbib.net.Response;
public interface HttpResponse extends Response { public interface HttpResponse extends Response {
void close() throws IOException;
} }

View file

@ -38,9 +38,9 @@ public interface HttpResponseBuilder {
HttpResponseBuilder addCookie(Cookie cookie); HttpResponseBuilder addCookie(Cookie cookie);
HttpResponseBuilder shouldFlush(boolean sholdFlush); HttpResponseBuilder withConnectionCloseHeader(boolean withConnectionCloseHeader);
boolean shouldFlush(); boolean withConnectionCloseHeader();
HttpResponseBuilder shouldClose(boolean shouldClose); HttpResponseBuilder shouldClose(boolean shouldClose);

View file

@ -3,7 +3,6 @@ package org.xbib.net.http.server.render;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpResponse; import org.xbib.net.http.server.HttpResponse;
import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.HttpServerContext;
public class HttpResponseRenderer implements HttpHandler { public class HttpResponseRenderer implements HttpHandler {
@ -13,11 +12,8 @@ public class HttpResponseRenderer implements HttpHandler {
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpServerContext context) throws IOException {
HttpResponseBuilder httpResponseBuilder = context.response();
// here we do the heavy lifting of rendering all elements for the response // here we do the heavy lifting of rendering all elements for the response
HttpResponse httpResponse = httpResponseBuilder.build(); HttpResponse httpResponse = context.response().build();
if (httpResponseBuilder.shouldClose()) { httpResponse.flush();
httpResponse.close();
}
} }
} }