use of io.netty.channel.ChannelFutureListener in project netty by netty.
the class SslHandlerTest method compositeBufSizeEstimationGuaranteesSynchronousWrite.
private void compositeBufSizeEstimationGuaranteesSynchronousWrite(SslProvider serverProvider, SslProvider clientProvider) throws CertificateException, SSLException, ExecutionException, InterruptedException {
SelfSignedCertificate ssc = new SelfSignedCertificate();
final SslContext sslServerCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).sslProvider(serverProvider).build();
final SslContext sslClientCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).sslProvider(clientProvider).build();
EventLoopGroup group = new NioEventLoopGroup();
Channel sc = null;
Channel cc = null;
try {
final Promise<Void> donePromise = group.next().newPromise();
final int expectedBytes = 469 + 1024 + 1024;
sc = new ServerBootstrap().group(group).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(sslServerCtx.newHandler(ch.alloc()));
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof SslHandshakeCompletionEvent) {
SslHandshakeCompletionEvent sslEvt = (SslHandshakeCompletionEvent) evt;
if (sslEvt.isSuccess()) {
final ByteBuf input = ctx.alloc().buffer();
input.writeBytes(new byte[expectedBytes]);
CompositeByteBuf content = ctx.alloc().compositeBuffer();
content.addComponent(true, input.readRetainedSlice(469));
content.addComponent(true, input.readRetainedSlice(1024));
content.addComponent(true, input.readRetainedSlice(1024));
ctx.writeAndFlush(content).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
input.release();
}
});
} else {
donePromise.tryFailure(sslEvt.cause());
}
}
ctx.fireUserEventTriggered(evt);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
donePromise.tryFailure(cause);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
donePromise.tryFailure(new IllegalStateException("server closed"));
}
});
}
}).bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
cc = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(sslClientCtx.newHandler(ch.alloc()));
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
private int bytesSeen;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof ByteBuf) {
bytesSeen += ((ByteBuf) msg).readableBytes();
if (bytesSeen == expectedBytes) {
donePromise.trySuccess(null);
}
}
ReferenceCountUtil.release(msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
donePromise.tryFailure(cause);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
donePromise.tryFailure(new IllegalStateException("client closed"));
}
});
}
}).connect(sc.localAddress()).syncUninterruptibly().channel();
donePromise.get();
} finally {
if (cc != null) {
cc.close().syncUninterruptibly();
}
if (sc != null) {
sc.close().syncUninterruptibly();
}
group.shutdownGracefully();
ReferenceCountUtil.release(sslServerCtx);
ReferenceCountUtil.release(sslClientCtx);
ssc.delete();
}
}
use of io.netty.channel.ChannelFutureListener in project netty by netty.
the class ChunkedWriteHandlerTest method testListenerNotifiedWhenIsEnd.
// Test case which shows that there is not a bug like stated here:
// http://stackoverflow.com/a/10426305
@Test
public void testListenerNotifiedWhenIsEnd() {
ByteBuf buffer = Unpooled.copiedBuffer("Test", CharsetUtil.ISO_8859_1);
ChunkedInput<ByteBuf> input = new ChunkedInput<ByteBuf>() {
private boolean done;
private final ByteBuf buffer = Unpooled.copiedBuffer("Test", CharsetUtil.ISO_8859_1);
@Override
public boolean isEndOfInput() throws Exception {
return done;
}
@Override
public void close() throws Exception {
buffer.release();
}
@Deprecated
@Override
public ByteBuf readChunk(ChannelHandlerContext ctx) throws Exception {
return readChunk(ctx.alloc());
}
@Override
public ByteBuf readChunk(ByteBufAllocator allocator) throws Exception {
if (done) {
return null;
}
done = true;
return buffer.retainedDuplicate();
}
@Override
public long length() {
return -1;
}
@Override
public long progress() {
return 1;
}
};
final AtomicBoolean listenerNotified = new AtomicBoolean(false);
final ChannelFutureListener listener = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
listenerNotified.set(true);
}
};
EmbeddedChannel ch = new EmbeddedChannel(new ChunkedWriteHandler());
ch.writeAndFlush(input).addListener(listener).syncUninterruptibly();
ch.checkException();
ch.finish();
// the listener should have been notified
assertTrue(listenerNotified.get());
ByteBuf buffer2 = ch.readOutbound();
assertEquals(buffer, buffer2);
assertNull(ch.readOutbound());
buffer.release();
buffer2.release();
}
use of io.netty.channel.ChannelFutureListener in project netty by netty.
the class HttpObjectAggregator method handleOversizedMessage.
@Override
protected void handleOversizedMessage(final ChannelHandlerContext ctx, HttpMessage oversized) throws Exception {
if (oversized instanceof HttpRequest) {
// If keep-alive is off and 'Expect: 100-continue' is missing, no need to leave the connection open.
if (oversized instanceof FullHttpMessage || !HttpUtil.is100ContinueExpected(oversized) && !HttpUtil.isKeepAlive(oversized)) {
ChannelFuture future = ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate());
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
}
ctx.close();
}
});
} else {
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
ctx.close();
}
}
});
}
// If an oversized request was handled properly and the connection is still alive
// (i.e. rejected 100-continue). the decoder should prepare to handle a new message.
HttpObjectDecoder decoder = ctx.pipeline().get(HttpObjectDecoder.class);
if (decoder != null) {
decoder.reset();
}
} else if (oversized instanceof HttpResponse) {
ctx.close();
throw new TooLongFrameException("Response entity too large: " + oversized);
} else {
throw new IllegalStateException();
}
}
use of io.netty.channel.ChannelFutureListener in project netty by netty.
the class HttpServerUpgradeHandler method upgrade.
/**
* Attempts to upgrade to the protocol(s) identified by the {@link HttpHeaderNames#UPGRADE} header (if provided
* in the request).
*
* @param ctx the context for this handler.
* @param request the HTTP request.
* @return {@code true} if the upgrade occurred, otherwise {@code false}.
*/
private boolean upgrade(final ChannelHandlerContext ctx, final FullHttpRequest request) {
// Select the best protocol based on those requested in the UPGRADE header.
final List<CharSequence> requestedProtocols = splitHeader(request.headers().get(HttpHeaderNames.UPGRADE));
final int numRequestedProtocols = requestedProtocols.size();
UpgradeCodec upgradeCodec = null;
CharSequence upgradeProtocol = null;
for (int i = 0; i < numRequestedProtocols; i++) {
final CharSequence p = requestedProtocols.get(i);
final UpgradeCodec c = upgradeCodecFactory.newUpgradeCodec(p);
if (c != null) {
upgradeProtocol = p;
upgradeCodec = c;
break;
}
}
if (upgradeCodec == null) {
// None of the requested protocols are supported, don't upgrade.
return false;
}
// Make sure the CONNECTION header is present.
CharSequence connectionHeader = request.headers().get(HttpHeaderNames.CONNECTION);
if (connectionHeader == null) {
return false;
}
// Make sure the CONNECTION header contains UPGRADE as well as all protocol-specific headers.
Collection<CharSequence> requiredHeaders = upgradeCodec.requiredUpgradeHeaders();
List<CharSequence> values = splitHeader(connectionHeader);
if (!containsContentEqualsIgnoreCase(values, HttpHeaderNames.UPGRADE) || !containsAllContentEqualsIgnoreCase(values, requiredHeaders)) {
return false;
}
// Ensure that all required protocol-specific headers are found in the request.
for (CharSequence requiredHeader : requiredHeaders) {
if (!request.headers().contains(requiredHeader)) {
return false;
}
}
// Prepare and send the upgrade response. Wait for this write to complete before upgrading,
// since we need the old codec in-place to properly encode the response.
final FullHttpResponse upgradeResponse = createUpgradeResponse(upgradeProtocol);
if (!upgradeCodec.prepareUpgradeResponse(ctx, request, upgradeResponse.headers())) {
return false;
}
// Create the user event to be fired once the upgrade completes.
final UpgradeEvent event = new UpgradeEvent(upgradeProtocol, request);
final UpgradeCodec finalUpgradeCodec = upgradeCodec;
ctx.writeAndFlush(upgradeResponse).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
try {
if (future.isSuccess()) {
// Perform the upgrade to the new protocol.
sourceCodec.upgradeFrom(ctx);
finalUpgradeCodec.upgradeTo(ctx, request);
// Notify that the upgrade has occurred. Retain the event to offset
// the release() in the finally block.
ctx.fireUserEventTriggered(event.retain());
// Remove this handler from the pipeline.
ctx.pipeline().remove(HttpServerUpgradeHandler.this);
} else {
future.channel().close();
}
} finally {
// Release the event if the upgrade event wasn't fired.
event.release();
}
}
});
return true;
}
use of io.netty.channel.ChannelFutureListener in project netty by netty.
the class DefaultHttp2ConnectionEncoder method writeHeaders.
@Override
public ChannelFuture writeHeaders(final ChannelHandlerContext ctx, final int streamId, final Http2Headers headers, final int streamDependency, final short weight, final boolean exclusive, final int padding, final boolean endOfStream, ChannelPromise promise) {
try {
Http2Stream stream = connection.stream(streamId);
if (stream == null) {
stream = connection.local().createStream(streamId, endOfStream);
} else {
switch(stream.state()) {
case RESERVED_LOCAL:
stream.open(endOfStream);
break;
case OPEN:
case HALF_CLOSED_REMOTE:
// Allowed sending headers in these states.
break;
default:
throw new IllegalStateException(String.format("Stream %d in unexpected state: %s", stream.id(), stream.state()));
}
}
// Trailing headers must go through flow control if there are other frames queued in flow control
// for this stream.
Http2RemoteFlowController flowController = flowController();
if (!endOfStream || !flowController.hasFlowControlled(stream)) {
if (endOfStream) {
final Http2Stream finalStream = stream;
final ChannelFutureListener closeStreamLocalListener = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
lifecycleManager.closeStreamLocal(finalStream, future);
}
};
promise = promise.unvoid().addListener(closeStreamLocalListener);
}
ChannelFuture future = frameWriter.writeHeaders(ctx, streamId, headers, streamDependency, weight, exclusive, padding, endOfStream, promise);
// Writing headers may fail during the encode state if they violate HPACK limits.
Throwable failureCause = future.cause();
if (failureCause == null) {
// Synchronously set the headersSent flag to ensure that we do not subsequently write
// other headers containing pseudo-header fields.
stream.headersSent();
} else {
lifecycleManager.onError(ctx, failureCause);
}
return future;
} else {
// Pass headers to the flow-controller so it can maintain their sequence relative to DATA frames.
flowController.addFlowControlled(stream, new FlowControlledHeaders(stream, headers, streamDependency, weight, exclusive, padding, true, promise));
return promise;
}
} catch (Throwable t) {
lifecycleManager.onError(ctx, t);
promise.tryFailure(t);
return promise;
}
}
Aggregations