better close/flush
This commit is contained in:
parent
fc1beabb58
commit
dfd3abd4a9
14 changed files with 113 additions and 152 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue