Remove the intermediate List from ByteToMessageDecoder (and sub-class… (#8626)

Motivation:

ByteToMessageDecoder requires using an intermediate List to put results into. This intermediate list adds overhead (memory/CPU) which grows as the number of objects increases. This overhead can be avoided by directly propagating events through the ChannelPipeline via ctx.fireChannelRead(...). This also makes the semantics more clear and allows us to keep track if we need to call ctx.read() in all cases.

Modifications:

- Remove List from the method signature of ByteToMessageDecoder.decode(...) and decodeLast(...)
- Adjust all sub-classes
- Adjust unit tests
- Fix javadocs.

Result:

Adjust ByteToMessageDecoder as noted in https://github.com/netty/netty/issues/8525.
This commit is contained in:
Norman Maurer 2019-12-16 21:00:32 +01:00 committed by GitHub
parent 33d576dbed
commit 0e4c073bcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 1483 additions and 926 deletions

View File

@ -23,7 +23,6 @@ import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import java.util.List;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -51,11 +50,10 @@ public class DatagramDnsQueryDecoder extends MessageToMessageDecoder<DatagramPac
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, DatagramPacket packet, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
final ByteBuf buf = packet.content(); final ByteBuf buf = packet.content();
final DnsQuery query = newQuery(packet, buf); DnsQuery query = newQuery(packet, buf);
boolean success = false;
try { try {
final int questionCount = buf.readUnsignedShort(); final int questionCount = buf.readUnsignedShort();
final int answerCount = buf.readUnsignedShort(); final int answerCount = buf.readUnsignedShort();
@ -67,10 +65,11 @@ public class DatagramDnsQueryDecoder extends MessageToMessageDecoder<DatagramPac
decodeRecords(query, DnsSection.AUTHORITY, buf, authorityRecordCount); decodeRecords(query, DnsSection.AUTHORITY, buf, authorityRecordCount);
decodeRecords(query, DnsSection.ADDITIONAL, buf, additionalRecordCount); decodeRecords(query, DnsSection.ADDITIONAL, buf, additionalRecordCount);
out.add(query); DnsQuery q = query;
success = true; query = null;
ctx.fireChannelRead(q);
} finally { } finally {
if (!success) { if (query != null) {
query.release(); query.release();
} }
} }

View File

@ -22,7 +22,6 @@ import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.List;
/** /**
* Decodes a {@link DatagramPacket} into a {@link DatagramDnsResponse}. * Decodes a {@link DatagramPacket} into a {@link DatagramDnsResponse}.
@ -54,8 +53,9 @@ public class DatagramDnsResponseDecoder extends MessageToMessageDecoder<Datagram
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, DatagramPacket packet, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
out.add(decodeResponse(ctx, packet)); DnsResponse response = decodeResponse(ctx, packet);
ctx.fireChannelRead(response);
} }
protected DnsResponse decodeResponse(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { protected DnsResponse decodeResponse(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {

View File

@ -52,8 +52,8 @@ public final class TcpDnsResponseDecoder extends LengthFieldBasedFrameDecoder {
} }
@Override @Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { protected Object decode0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, in); ByteBuf frame = (ByteBuf) super.decode0(ctx, in);
if (frame == null) { if (frame == null) {
return null; return null;
} }

View File

@ -21,8 +21,6 @@ import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.ProtocolDetectionResult; import io.netty.handler.codec.ProtocolDetectionResult;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import java.util.List;
/** /**
* Decodes an HAProxy proxy protocol header * Decodes an HAProxy proxy protocol header
* *
@ -256,7 +254,7 @@ public class HAProxyMessageDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected final void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
// determine the specification version // determine the specification version
if (version == -1) { if (version == -1) {
if ((version = findVersion(in)) == -1) { if ((version = findVersion(in)) == -1) {
@ -276,9 +274,9 @@ public class HAProxyMessageDecoder extends ByteToMessageDecoder {
finished = true; finished = true;
try { try {
if (version == 1) { if (version == 1) {
out.add(HAProxyMessage.decodeHeader(decoded.toString(CharsetUtil.US_ASCII))); ctx.fireChannelRead(HAProxyMessage.decodeHeader(decoded.toString(CharsetUtil.US_ASCII)));
} else { } else {
out.add(HAProxyMessage.decodeHeader(decoded)); ctx.fireChannelRead(HAProxyMessage.decodeHeader(decoded));
} }
} catch (HAProxyProtocolException e) { } catch (HAProxyProtocolException e) {
fail(ctx, null, e); fail(ctx, null, e);

View File

@ -0,0 +1,268 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelProgressivePromise;
import io.netty.channel.ChannelPromise;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.ObjectUtil;
import java.net.SocketAddress;
abstract class DelegatingChannelHandlerContext implements ChannelHandlerContext {
private final ChannelHandlerContext ctx;
DelegatingChannelHandlerContext(ChannelHandlerContext ctx) {
this.ctx = ObjectUtil.checkNotNull(ctx, "ctx");
}
@Override
public Channel channel() {
return ctx.channel();
}
@Override
public EventExecutor executor() {
return ctx.executor();
}
@Override
public String name() {
return ctx.name();
}
@Override
public ChannelHandler handler() {
return ctx.handler();
}
@Override
public boolean isRemoved() {
return ctx.isRemoved();
}
@Override
public ChannelHandlerContext fireChannelRegistered() {
ctx.fireChannelRegistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelUnregistered() {
ctx.fireChannelUnregistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelActive() {
ctx.fireChannelActive();
return this;
}
@Override
public ChannelHandlerContext fireChannelInactive() {
ctx.fireChannelInactive();
return this;
}
@Override
public ChannelHandlerContext fireExceptionCaught(Throwable cause) {
ctx.fireExceptionCaught(cause);
return this;
}
@Override
public ChannelHandlerContext fireUserEventTriggered(Object evt) {
ctx.fireUserEventTriggered(evt);
return this;
}
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
ctx.fireChannelRead(msg);
return this;
}
@Override
public ChannelHandlerContext fireChannelReadComplete() {
ctx.fireChannelReadComplete();
return this;
}
@Override
public ChannelHandlerContext fireChannelWritabilityChanged() {
ctx.fireChannelWritabilityChanged();
return this;
}
@Override
public ChannelHandlerContext read() {
ctx.read();
return this;
}
@Override
public ChannelHandlerContext flush() {
ctx.flush();
return this;
}
@Override
public ChannelPipeline pipeline() {
return ctx.pipeline();
}
@Override
public ByteBufAllocator alloc() {
return ctx.alloc();
}
@Deprecated
public <T> Attribute<T> attr(AttributeKey<T> key) {
return ctx.attr(key);
}
@Deprecated
public <T> boolean hasAttr(AttributeKey<T> key) {
return ctx.hasAttr(key);
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
return ctx.bind(localAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
return ctx.connect(remoteAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return ctx.connect(remoteAddress, localAddress);
}
@Override
public ChannelFuture disconnect() {
return ctx.disconnect();
}
@Override
public ChannelFuture close() {
return ctx.close();
}
@Override
public ChannelFuture deregister() {
return ctx.deregister();
}
@Override
public ChannelFuture register() {
return ctx.register();
}
@Override
public ChannelFuture register(ChannelPromise promise) {
return ctx.register(promise);
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return ctx.bind(localAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return ctx.connect(remoteAddress, promise);
}
@Override
public ChannelFuture connect(
SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
return ctx.connect(remoteAddress, localAddress, promise);
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
return ctx.disconnect(promise);
}
@Override
public ChannelFuture close(ChannelPromise promise) {
return ctx.close(promise);
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
return ctx.deregister(promise);
}
@Override
public ChannelFuture write(Object msg) {
return ctx.write(msg);
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
return ctx.write(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
return ctx.writeAndFlush(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
return ctx.writeAndFlush(msg);
}
@Override
public ChannelPromise newPromise() {
return ctx.newPromise();
}
@Override
public ChannelProgressivePromise newProgressivePromise() {
return ctx.newProgressivePromise();
}
@Override
public ChannelFuture newSucceededFuture() {
return ctx.newSucceededFuture();
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
return ctx.newFailedFuture(cause);
}
@Override
public ChannelPromise voidPromise() {
return ctx.voidPromise();
}
}

View File

@ -177,6 +177,9 @@ public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResp
} }
private final class Decoder extends HttpResponseDecoder { private final class Decoder extends HttpResponseDecoder {
private ChannelHandlerContext context;
Decoder(int maxInitialLineLength, int maxHeaderSize, boolean validateHeaders) { Decoder(int maxInitialLineLength, int maxHeaderSize, boolean validateHeaders) {
super(maxInitialLineLength, maxHeaderSize, validateHeaders); super(maxInitialLineLength, maxHeaderSize, validateHeaders);
} }
@ -187,8 +190,24 @@ public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResp
} }
@Override @Override
protected void decode( protected void handlerAdded0(ChannelHandlerContext ctx) {
ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { if (failOnMissingResponse) {
context = new DelegatingChannelHandlerContext(ctx) {
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
decrement(msg);
super.fireChannelRead(msg);
return this;
}
};
} else {
context = ctx;
}
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
if (done) { if (done) {
int readable = actualReadableBytes(); int readable = actualReadableBytes();
if (readable == 0) { if (readable == 0) {
@ -196,16 +215,9 @@ public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResp
// https://github.com/netty/netty/issues/1159 // https://github.com/netty/netty/issues/1159
return; return;
} }
out.add(buffer.readBytes(readable)); ctx.fireChannelRead(buffer.readBytes(readable));
} else { } else {
int oldSize = out.size(); super.decode(context, buffer);
super.decode(ctx, buffer, out);
if (failOnMissingResponse) {
int size = out.size();
for (int i = oldSize; i < size; i++) {
decrement(out.get(i));
}
}
} }
} }

View File

@ -21,7 +21,6 @@ import io.netty.util.AsciiString;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import static io.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS; import static io.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS;
@ -188,7 +187,7 @@ public class HttpClientUpgradeHandler extends HttpObjectAggregator {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, HttpObject msg, List<Object> out) protected void decode(final ChannelHandlerContext ctx, HttpObject msg)
throws Exception { throws Exception {
FullHttpResponse response = null; FullHttpResponse response = null;
try { try {
@ -212,21 +211,30 @@ public class HttpClientUpgradeHandler extends HttpObjectAggregator {
if (msg instanceof FullHttpResponse) { if (msg instanceof FullHttpResponse) {
response = (FullHttpResponse) msg; response = (FullHttpResponse) msg;
// Need to retain since the base class will release after returning from this method. // Need to retain since the base class will release after returning from this method.
response.retain(); tryUpgrade(ctx, response.retain());
out.add(response);
} else { } else {
// Call the base class to handle the aggregation of the full request. // Call the base class to handle the aggregation of the full request.
super.decode(ctx, msg, out); super.decode(new DelegatingChannelHandlerContext(ctx) {
if (out.isEmpty()) { @Override
// The full request hasn't been created yet, still awaiting more data. public ChannelHandlerContext fireChannelRead(Object msg) {
return; FullHttpResponse response = (FullHttpResponse) msg;
tryUpgrade(ctx, response);
return this;
}
}, msg);
} }
assert out.size() == 1; } catch (Throwable t) {
response = (FullHttpResponse) out.get(0); release(response);
ctx.fireExceptionCaught(t);
removeThisHandler(ctx);
}
} }
private void tryUpgrade(ChannelHandlerContext ctx, FullHttpResponse response) {
try {
CharSequence upgradeHeader = response.headers().get(HttpHeaderNames.UPGRADE); CharSequence upgradeHeader = response.headers().get(HttpHeaderNames.UPGRADE);
if (upgradeHeader != null && !AsciiString.contentEqualsIgnoreCase(upgradeCodec.protocol(), upgradeHeader)) { if (upgradeHeader != null && !AsciiString.contentEqualsIgnoreCase(upgradeCodec.protocol(), upgradeHeader)) {
throw new IllegalStateException( throw new IllegalStateException(
@ -247,7 +255,6 @@ public class HttpClientUpgradeHandler extends HttpObjectAggregator {
// We switched protocols, so we're done with the upgrade response. // We switched protocols, so we're done with the upgrade response.
// Release it and clear it from the output. // Release it and clear it from the output.
response.release(); response.release();
out.clear();
removeThisHandler(ctx); removeThisHandler(ctx);
} catch (Throwable t) { } catch (Throwable t) {
release(response); release(response);

View File

@ -23,8 +23,6 @@ import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import java.util.List;
/** /**
* Decodes the content of the received {@link HttpRequest} and {@link HttpContent}. * Decodes the content of the received {@link HttpRequest} and {@link HttpContent}.
* The original content is replaced with the new content decoded by the * The original content is replaced with the new content decoded by the
@ -54,15 +52,14 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
private boolean needRead = true; private boolean needRead = true;
@Override @Override
protected void decode(ChannelHandlerContext ctx, HttpObject msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
try {
if (msg instanceof HttpResponse && ((HttpResponse) msg).status().code() == 100) { if (msg instanceof HttpResponse && ((HttpResponse) msg).status().code() == 100) {
if (!(msg instanceof LastHttpContent)) { if (!(msg instanceof LastHttpContent)) {
continueResponse = true; continueResponse = true;
} }
// 100-continue response must be passed through. // 100-continue response must be passed through.
out.add(ReferenceCountUtil.retain(msg)); fireChannelRead(ctx, ReferenceCountUtil.retain(msg));
return; return;
} }
@ -71,7 +68,7 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
continueResponse = false; continueResponse = false;
} }
// 100-continue response must be passed through. // 100-continue response must be passed through.
out.add(ReferenceCountUtil.retain(msg)); fireChannelRead(ctx, ReferenceCountUtil.retain(msg));
return; return;
} }
@ -79,7 +76,6 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
cleanup(); cleanup();
final HttpMessage message = (HttpMessage) msg; final HttpMessage message = (HttpMessage) msg;
final HttpHeaders headers = message.headers(); final HttpHeaders headers = message.headers();
// Determine the content encoding. // Determine the content encoding.
String contentEncoding = headers.get(HttpHeaderNames.CONTENT_ENCODING); String contentEncoding = headers.get(HttpHeaderNames.CONTENT_ENCODING);
if (contentEncoding != null) { if (contentEncoding != null) {
@ -93,7 +89,7 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
if (message instanceof HttpContent) { if (message instanceof HttpContent) {
((HttpContent) message).retain(); ((HttpContent) message).retain();
} }
out.add(message); fireChannelRead(ctx, message);
return; return;
} }
@ -136,41 +132,38 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
} }
copy.headers().set(message.headers()); copy.headers().set(message.headers());
copy.setDecoderResult(message.decoderResult()); copy.setDecoderResult(message.decoderResult());
out.add(copy); fireChannelRead(ctx, copy);
} else { } else {
out.add(message); fireChannelRead(ctx, message);
} }
} }
if (msg instanceof HttpContent) { if (msg instanceof HttpContent) {
final HttpContent c = (HttpContent) msg; final HttpContent c = (HttpContent) msg;
if (decoder == null) { if (decoder == null) {
out.add(c.retain()); fireChannelRead(ctx, c.retain());
} else { } else {
decodeContent(c, out); decodeContent(ctx, c);
} }
} }
} finally {
needRead = out.isEmpty();
}
} }
private void decodeContent(HttpContent c, List<Object> out) { private void decodeContent(ChannelHandlerContext ctx, HttpContent c) {
ByteBuf content = c.content(); ByteBuf content = c.content();
decode(content, out); decode(ctx, content);
if (c instanceof LastHttpContent) { if (c instanceof LastHttpContent) {
finishDecode(out); finishDecode(ctx);
LastHttpContent last = (LastHttpContent) c; LastHttpContent last = (LastHttpContent) c;
// Generate an additional chunk if the decoder produced // Generate an additional chunk if the decoder produced
// the last product on closure, // the last product on closure,
HttpHeaders headers = last.trailingHeaders(); HttpHeaders headers = last.trailingHeaders();
if (headers.isEmpty()) { if (headers.isEmpty()) {
out.add(LastHttpContent.EMPTY_LAST_CONTENT); fireChannelRead(ctx, LastHttpContent.EMPTY_LAST_CONTENT);
} else { } else {
out.add(new ComposedLastHttpContent(headers, DecoderResult.SUCCESS)); fireChannelRead(ctx, new ComposedLastHttpContent(headers, DecoderResult.SUCCESS));
} }
} }
} }
@ -249,20 +242,20 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
} }
} }
private void decode(ByteBuf in, List<Object> out) { private void decode(ChannelHandlerContext ctx, ByteBuf in) {
// call retain here as it will call release after its written to the channel // call retain here as it will call release after its written to the channel
decoder.writeInbound(in.retain()); decoder.writeInbound(in.retain());
fetchDecoderOutput(out); fetchDecoderOutput(ctx);
} }
private void finishDecode(List<Object> out) { private void finishDecode(ChannelHandlerContext ctx) {
if (decoder.finish()) { if (decoder.finish()) {
fetchDecoderOutput(out); fetchDecoderOutput(ctx);
} }
decoder = null; decoder = null;
} }
private void fetchDecoderOutput(List<Object> out) { private void fetchDecoderOutput(ChannelHandlerContext ctx) {
for (;;) { for (;;) {
ByteBuf buf = decoder.readInbound(); ByteBuf buf = decoder.readInbound();
if (buf == null) { if (buf == null) {
@ -272,7 +265,12 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
buf.release(); buf.release();
continue; continue;
} }
out.add(new DefaultHttpContent(buf)); ctx.fireChannelRead(new DefaultHttpContent(buf));
} }
} }
private void fireChannelRead(ChannelHandlerContext ctx, Object msg) {
needRead = false;
ctx.fireChannelRead(msg);
}
} }

View File

@ -76,7 +76,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, HttpRequest msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
CharSequence acceptEncoding; CharSequence acceptEncoding;
List<String> acceptEncodingHeaders = msg.headers().getAll(ACCEPT_ENCODING); List<String> acceptEncodingHeaders = msg.headers().getAll(ACCEPT_ENCODING);
switch (acceptEncodingHeaders.size()) { switch (acceptEncodingHeaders.size()) {
@ -100,7 +100,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
} }
acceptEncodingQueue.add(acceptEncoding); acceptEncodingQueue.add(acceptEncoding);
out.add(ReferenceCountUtil.retain(msg)); ctx.fireChannelRead(ReferenceCountUtil.retain(msg));
} }
@Override @Override

View File

@ -179,7 +179,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
if (resetRequested) { if (resetRequested) {
resetNow(); resetNow();
} }
@ -207,7 +207,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
currentState = State.READ_HEADER; currentState = State.READ_HEADER;
// fall-through // fall-through
} catch (Exception e) { } catch (Exception e) {
out.add(invalidMessage(buffer, e)); ctx.fireChannelRead(invalidMessage(buffer, e));
return; return;
} }
case READ_HEADER: try { case READ_HEADER: try {
@ -220,8 +220,8 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
case SKIP_CONTROL_CHARS: case SKIP_CONTROL_CHARS:
// fast-path // fast-path
// No content is expected. // No content is expected.
out.add(message); ctx.fireChannelRead(message);
out.add(LastHttpContent.EMPTY_LAST_CONTENT); ctx.fireChannelRead(LastHttpContent.EMPTY_LAST_CONTENT);
resetNow(); resetNow();
return; return;
case READ_CHUNK_SIZE: case READ_CHUNK_SIZE:
@ -229,7 +229,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
throw new IllegalArgumentException("Chunked messages not supported"); throw new IllegalArgumentException("Chunked messages not supported");
} }
// Chunked encoding - generate HttpMessage first. HttpChunks will follow. // Chunked encoding - generate HttpMessage first. HttpChunks will follow.
out.add(message); ctx.fireChannelRead(message);
return; return;
default: default:
/** /**
@ -240,8 +240,8 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
*/ */
long contentLength = contentLength(); long contentLength = contentLength();
if (contentLength == 0 || contentLength == -1 && isDecodingRequest()) { if (contentLength == 0 || contentLength == -1 && isDecodingRequest()) {
out.add(message); ctx.fireChannelRead(message);
out.add(LastHttpContent.EMPTY_LAST_CONTENT); ctx.fireChannelRead(LastHttpContent.EMPTY_LAST_CONTENT);
resetNow(); resetNow();
return; return;
} }
@ -249,7 +249,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
assert nextState == State.READ_FIXED_LENGTH_CONTENT || assert nextState == State.READ_FIXED_LENGTH_CONTENT ||
nextState == State.READ_VARIABLE_LENGTH_CONTENT; nextState == State.READ_VARIABLE_LENGTH_CONTENT;
out.add(message); ctx.fireChannelRead(message);
if (nextState == State.READ_FIXED_LENGTH_CONTENT) { if (nextState == State.READ_FIXED_LENGTH_CONTENT) {
// chunkSize will be decreased as the READ_FIXED_LENGTH_CONTENT state reads data chunk by chunk. // chunkSize will be decreased as the READ_FIXED_LENGTH_CONTENT state reads data chunk by chunk.
@ -260,7 +260,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
return; return;
} }
} catch (Exception e) { } catch (Exception e) {
out.add(invalidMessage(buffer, e)); ctx.fireChannelRead(invalidMessage(buffer, e));
return; return;
} }
case READ_VARIABLE_LENGTH_CONTENT: { case READ_VARIABLE_LENGTH_CONTENT: {
@ -268,7 +268,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
int toRead = buffer.readableBytes(); int toRead = buffer.readableBytes();
if (toRead > 0) { if (toRead > 0) {
ByteBuf content = buffer.readRetainedSlice(toRead); ByteBuf content = buffer.readRetainedSlice(toRead);
out.add(new DefaultHttpContent(content)); ctx.fireChannelRead(new DefaultHttpContent(content));
} }
return; return;
} }
@ -294,10 +294,10 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
if (chunkSize == 0) { if (chunkSize == 0) {
// Read all content. // Read all content.
out.add(new DefaultLastHttpContent(content, validateHeaders)); ctx.fireChannelRead(new DefaultLastHttpContent(content, validateHeaders));
resetNow(); resetNow();
} else { } else {
out.add(new DefaultHttpContent(content)); ctx.fireChannelRead(new DefaultHttpContent(content));
} }
return; return;
} }
@ -319,7 +319,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
currentState = State.READ_CHUNKED_CONTENT; currentState = State.READ_CHUNKED_CONTENT;
// fall-through // fall-through
} catch (Exception e) { } catch (Exception e) {
out.add(invalidChunk(buffer, e)); ctx.fireChannelRead(invalidChunk(buffer, e));
return; return;
} }
case READ_CHUNKED_CONTENT: { case READ_CHUNKED_CONTENT: {
@ -332,7 +332,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
HttpContent chunk = new DefaultHttpContent(buffer.readRetainedSlice(toRead)); HttpContent chunk = new DefaultHttpContent(buffer.readRetainedSlice(toRead));
chunkSize -= toRead; chunkSize -= toRead;
out.add(chunk); ctx.fireChannelRead(chunk);
if (chunkSize != 0) { if (chunkSize != 0) {
return; return;
@ -358,11 +358,11 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
if (trailer == null) { if (trailer == null) {
return; return;
} }
out.add(trailer); ctx.fireChannelRead(trailer);
resetNow(); resetNow();
return; return;
} catch (Exception e) { } catch (Exception e) {
out.add(invalidChunk(buffer, e)); ctx.fireChannelRead(invalidChunk(buffer, e));
return; return;
} }
case BAD_MESSAGE: { case BAD_MESSAGE: {
@ -377,7 +377,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
// other handler will replace this codec with the upgraded protocol codec to // other handler will replace this codec with the upgraded protocol codec to
// take the traffic over at some point then. // take the traffic over at some point then.
// See https://github.com/netty/netty/issues/2173 // See https://github.com/netty/netty/issues/2173
out.add(buffer.readBytes(readableBytes)); ctx.fireChannelRead(buffer.readBytes(readableBytes));
} }
break; break;
} }
@ -385,8 +385,8 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
super.decodeLast(ctx, in, out); super.decodeLast(ctx, in);
if (resetRequested) { if (resetRequested) {
// If a reset was requested by decodeLast() we need to do it now otherwise we may produce a // If a reset was requested by decodeLast() we need to do it now otherwise we may produce a
@ -398,7 +398,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
boolean chunked = HttpUtil.isTransferEncodingChunked(message); boolean chunked = HttpUtil.isTransferEncodingChunked(message);
if (currentState == State.READ_VARIABLE_LENGTH_CONTENT && !in.isReadable() && !chunked) { if (currentState == State.READ_VARIABLE_LENGTH_CONTENT && !in.isReadable() && !chunked) {
// End of connection. // End of connection.
out.add(LastHttpContent.EMPTY_LAST_CONTENT); ctx.fireChannelRead(LastHttpContent.EMPTY_LAST_CONTENT);
resetNow(); resetNow();
return; return;
} }
@ -406,7 +406,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
if (currentState == State.READ_HEADER) { if (currentState == State.READ_HEADER) {
// If we are still in the state of reading headers we need to create a new invalid message that // If we are still in the state of reading headers we need to create a new invalid message that
// signals that the connection was closed before we received the headers. // signals that the connection was closed before we received the headers.
out.add(invalidMessage(Unpooled.EMPTY_BUFFER, ctx.fireChannelRead(invalidMessage(Unpooled.EMPTY_BUFFER,
new PrematureChannelClosureException("Connection closed before received headers"))); new PrematureChannelClosureException("Connection closed before received headers")));
resetNow(); resetNow();
return; return;
@ -425,7 +425,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
} }
if (!prematureClosure) { if (!prematureClosure) {
out.add(LastHttpContent.EMPTY_LAST_CONTENT); ctx.fireChannelRead(LastHttpContent.EMPTY_LAST_CONTENT);
} }
resetNow(); resetNow();
} }

View File

@ -20,7 +20,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.CombinedChannelDuplexHandler; import io.netty.channel.CombinedChannelDuplexHandler;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.List;
import java.util.Queue; import java.util.Queue;
/** /**
@ -81,6 +80,9 @@ public final class HttpServerCodec extends CombinedChannelDuplexHandler<HttpRequ
} }
private final class HttpServerRequestDecoder extends HttpRequestDecoder { private final class HttpServerRequestDecoder extends HttpRequestDecoder {
private ChannelHandlerContext context;
HttpServerRequestDecoder(int maxInitialLineLength, int maxHeaderSize) { HttpServerRequestDecoder(int maxInitialLineLength, int maxHeaderSize) {
super(maxInitialLineLength, maxHeaderSize); super(maxInitialLineLength, maxHeaderSize);
} }
@ -96,16 +98,23 @@ public final class HttpServerCodec extends CombinedChannelDuplexHandler<HttpRequ
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { protected void decode(final ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
int oldSize = out.size(); super.decode(context, buffer);
super.decode(ctx, buffer, out);
int size = out.size();
for (int i = oldSize; i < size; i++) {
Object obj = out.get(i);
if (obj instanceof HttpRequest) {
queue.add(((HttpRequest) obj).method());
} }
@Override
protected void handlerAdded0(final ChannelHandlerContext ctx) {
context = new DelegatingChannelHandlerContext(ctx) {
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
if (msg instanceof HttpRequest) {
queue.add(((HttpRequest) msg).method());
} }
super.fireChannelRead(msg);
return this;
}
};
} }
} }

View File

@ -206,45 +206,42 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, HttpObject msg, List<Object> out) protected void decode(final ChannelHandlerContext ctx, HttpObject msg)
throws Exception { throws Exception {
// Determine if we're already handling an upgrade request or just starting a new one. // Determine if we're already handling an upgrade request or just starting a new one.
handlingUpgrade |= isUpgradeRequest(msg); handlingUpgrade |= isUpgradeRequest(msg);
if (!handlingUpgrade) { if (!handlingUpgrade) {
// Not handling an upgrade request, just pass it to the next handler. // Not handling an upgrade request, just pass it to the next handler.
ReferenceCountUtil.retain(msg); ReferenceCountUtil.retain(msg);
out.add(msg); ctx.fireChannelRead(msg);
return; return;
} }
FullHttpRequest fullRequest; FullHttpRequest fullRequest;
if (msg instanceof FullHttpRequest) { if (msg instanceof FullHttpRequest) {
fullRequest = (FullHttpRequest) msg; fullRequest = (FullHttpRequest) msg;
ReferenceCountUtil.retain(msg); tryUpgrade(ctx, fullRequest.retain());
out.add(msg);
} else { } else {
// Call the base class to handle the aggregation of the full request. // Call the base class to handle the aggregation of the full request.
super.decode(ctx, msg, out); super.decode(new DelegatingChannelHandlerContext(ctx) {
if (out.isEmpty()) { @Override
// The full request hasn't been created yet, still awaiting more data. public ChannelHandlerContext fireChannelRead(Object msg) {
return;
}
// Finished aggregating the full request, get it from the output list. // Finished aggregating the full request, get it from the output list.
assert out.size() == 1;
handlingUpgrade = false; handlingUpgrade = false;
fullRequest = (FullHttpRequest) out.get(0); tryUpgrade(ctx, (FullHttpRequest) msg);
return this;
}
}, msg);
}
} }
if (upgrade(ctx, fullRequest)) { private void tryUpgrade(ChannelHandlerContext ctx, FullHttpRequest request) {
// The upgrade was successful, remove the message from the output list if (!upgrade(ctx, request)) {
// so that it's not propagated to the next handler. This request will
// be propagated as a user event instead.
out.clear();
}
// The upgrade did not succeed, just allow the full request to propagate to the // The upgrade did not succeed, just allow the full request to propagate to the
// next handler. // next handler.
ctx.fireChannelRead(request);
}
} }
/** /**

View File

@ -20,7 +20,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.TooLongFrameException;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import static io.netty.buffer.ByteBufUtil.readBytes; import static io.netty.buffer.ByteBufUtil.readBytes;
@ -65,7 +64,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder<Void> implements W
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
// Discard all data received if closing handshake was received before. // Discard all data received if closing handshake was received before.
if (receivedClosingHandshake) { if (receivedClosingHandshake) {
in.skipBytes(actualReadableBytes()); in.skipBytes(actualReadableBytes());
@ -84,7 +83,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder<Void> implements W
} }
if (frame != null) { if (frame != null) {
out.add(frame); ctx.fireChannelRead(frame);
} }
} }

View File

@ -63,7 +63,6 @@ import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import static io.netty.buffer.ByteBufUtil.readBytes; import static io.netty.buffer.ByteBufUtil.readBytes;
@ -158,7 +157,7 @@ public class WebSocket08FrameDecoder extends ByteToMessageDecoder
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
// Discard all data received if closing handshake was received before. // Discard all data received if closing handshake was received before.
if (receivedClosingHandshake) { if (receivedClosingHandshake) {
in.skipBytes(actualReadableBytes()); in.skipBytes(actualReadableBytes());
@ -325,20 +324,23 @@ public class WebSocket08FrameDecoder extends ByteToMessageDecoder
// Processing ping/pong/close frames because they cannot be // Processing ping/pong/close frames because they cannot be
// fragmented // fragmented
if (frameOpcode == OPCODE_PING) { if (frameOpcode == OPCODE_PING) {
out.add(new PingWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer)); WebSocketFrame frame = new PingWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer);
payloadBuffer = null; payloadBuffer = null;
ctx.fireChannelRead(frame);
return; return;
} }
if (frameOpcode == OPCODE_PONG) { if (frameOpcode == OPCODE_PONG) {
out.add(new PongWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer)); WebSocketFrame frame = new PongWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer);
payloadBuffer = null; payloadBuffer = null;
ctx.fireChannelRead(frame);
return; return;
} }
if (frameOpcode == OPCODE_CLOSE) { if (frameOpcode == OPCODE_CLOSE) {
receivedClosingHandshake = true; receivedClosingHandshake = true;
checkCloseFrameBody(ctx, payloadBuffer); checkCloseFrameBody(ctx, payloadBuffer);
out.add(new CloseWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer)); WebSocketFrame frame = new CloseWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer);
payloadBuffer = null; payloadBuffer = null;
ctx.fireChannelRead(frame);
return; return;
} }
@ -357,17 +359,19 @@ public class WebSocket08FrameDecoder extends ByteToMessageDecoder
// Return the frame // Return the frame
if (frameOpcode == OPCODE_TEXT) { if (frameOpcode == OPCODE_TEXT) {
out.add(new TextWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer)); WebSocketFrame frame = new TextWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer);
payloadBuffer = null; payloadBuffer = null;
ctx.fireChannelRead(frame);
return; return;
} else if (frameOpcode == OPCODE_BINARY) { } else if (frameOpcode == OPCODE_BINARY) {
out.add(new BinaryWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer)); WebSocketFrame frame = new BinaryWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer);
payloadBuffer = null; payloadBuffer = null;
ctx.fireChannelRead(frame);
return; return;
} else if (frameOpcode == OPCODE_CONT) { } else if (frameOpcode == OPCODE_CONT) {
out.add(new ContinuationWebSocketFrame(frameFinalFlag, frameRsv, WebSocketFrame frame = new ContinuationWebSocketFrame(frameFinalFlag, frameRsv, payloadBuffer);
payloadBuffer));
payloadBuffer = null; payloadBuffer = null;
ctx.fireChannelRead(frame);
return; return;
} else { } else {
throw new UnsupportedOperationException("Cannot decode web socket frame with opcode: " throw new UnsupportedOperationException("Cannot decode web socket frame with opcode: "

View File

@ -21,7 +21,6 @@ import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpHeaders;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import static io.netty.handler.codec.http.websocketx.WebSocketClientProtocolConfig.DEFAULT; import static io.netty.handler.codec.http.websocketx.WebSocketClientProtocolConfig.DEFAULT;
@ -357,12 +356,12 @@ public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
if (clientConfig.handleCloseFrames() && frame instanceof CloseWebSocketFrame) { if (clientConfig.handleCloseFrames() && frame instanceof CloseWebSocketFrame) {
ctx.close(); ctx.close();
return; return;
} }
super.decode(ctx, frame, out); super.decode(ctx, frame);
} }
@Override @Override

View File

@ -44,7 +44,7 @@ abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocke
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
if (frame instanceof PingWebSocketFrame) { if (frame instanceof PingWebSocketFrame) {
frame.content().retain(); frame.content().retain();
ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content())); ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content()));
@ -56,7 +56,7 @@ abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocke
return; return;
} }
out.add(frame.retain()); ctx.fireChannelRead(frame.retain());
} }
private static void readIfNeeded(ChannelHandlerContext ctx) { private static void readIfNeeded(ChannelHandlerContext ctx) {

View File

@ -29,7 +29,6 @@ import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import static io.netty.handler.codec.http.HttpVersion.*; import static io.netty.handler.codec.http.HttpVersion.*;
@ -235,7 +234,7 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
if (serverConfig.handleCloseFrames() && frame instanceof CloseWebSocketFrame) { if (serverConfig.handleCloseFrames() && frame instanceof CloseWebSocketFrame) {
WebSocketServerHandshaker handshaker = getHandshaker(ctx.channel()); WebSocketServerHandshaker handshaker = getHandshaker(ctx.channel());
if (handshaker != null) { if (handshaker != null) {
@ -246,7 +245,7 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {
} }
return; return;
} }
super.decode(ctx, frame, out); super.decode(ctx, frame);
} }
@Override @Override

View File

@ -30,7 +30,6 @@ import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionDecoder; import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionDecoder;
import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilter; import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilter;
import java.util.List;
import java.util.Objects; import java.util.Objects;
/** /**
@ -75,7 +74,7 @@ abstract class DeflateDecoder extends WebSocketExtensionDecoder {
protected abstract int newRsv(WebSocketFrame msg); protected abstract int newRsv(WebSocketFrame msg);
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
final ByteBuf decompressedContent = decompressContent(ctx, msg); final ByteBuf decompressedContent = decompressContent(ctx, msg);
final WebSocketFrame outMsg; final WebSocketFrame outMsg;
@ -89,7 +88,7 @@ abstract class DeflateDecoder extends WebSocketExtensionDecoder {
throw new CodecException("unexpected frame type: " + msg.getClass().getName()); throw new CodecException("unexpected frame type: " + msg.getClass().getName());
} }
out.add(outMsg); ctx.fireChannelRead(outMsg);
} }
@Override @Override

View File

@ -23,8 +23,6 @@ import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtension; import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtension;
import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilter; import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilter;
import java.util.List;
/** /**
* Per-message implementation of deflate decompressor. * Per-message implementation of deflate decompressor.
*/ */
@ -82,11 +80,11 @@ class PerMessageDeflateDecoder extends DeflateDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
List<Object> out) throws Exception { boolean isFinal = msg.isFinalFragment();
super.decode(ctx, msg, out); super.decode(ctx, msg);
if (msg.isFinalFragment()) { if (isFinal) {
compressing = false; compressing = false;
} else if (msg instanceof TextWebSocketFrame || msg instanceof BinaryWebSocketFrame) { } else if (msg instanceof TextWebSocketFrame || msg instanceof BinaryWebSocketFrame) {
compressing = true; compressing = true;

View File

@ -32,6 +32,7 @@ public class WebSocket08FrameDecoderTest {
public void channelInactive() throws Exception { public void channelInactive() throws Exception {
final WebSocket08FrameDecoder decoder = new WebSocket08FrameDecoder(true, true, 65535, false); final WebSocket08FrameDecoder decoder = new WebSocket08FrameDecoder(true, true, 65535, false);
final ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); final ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
decoder.handlerAdded(ctx);
decoder.channelInactive(ctx); decoder.channelInactive(ctx);
verify(ctx).fireChannelInactive(); verify(ctx).fireChannelInactive();
} }

View File

@ -33,7 +33,6 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionException;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -58,12 +57,12 @@ public class WebSocketHandshakeHandOverTest {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
if (frame instanceof CloseWebSocketFrame) { if (frame instanceof CloseWebSocketFrame) {
serverReceivedCloseHandshake = true; serverReceivedCloseHandshake = true;
return; return;
} }
super.decode(ctx, frame, out); super.decode(ctx, frame);
} }
} }

View File

@ -97,8 +97,7 @@ public final class WebSocketExtensionTestUtil {
static class DummyDecoder extends WebSocketExtensionDecoder { static class DummyDecoder extends WebSocketExtensionDecoder {
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
List<Object> out) throws Exception {
// unused // unused
} }
} }
@ -113,8 +112,7 @@ public final class WebSocketExtensionTestUtil {
static class Dummy2Decoder extends WebSocketExtensionDecoder { static class Dummy2Decoder extends WebSocketExtensionDecoder {
@Override @Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
List<Object> out) throws Exception {
// unused // unused
} }
} }

View File

@ -25,8 +25,6 @@ import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpServerUpgradeHandler; import io.netty.handler.codec.http.HttpServerUpgradeHandler;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import java.util.List;
import static io.netty.buffer.Unpooled.unreleasableBuffer; import static io.netty.buffer.Unpooled.unreleasableBuffer;
import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf; import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf;
@ -77,7 +75,7 @@ public final class CleartextHttp2ServerUpgradeHandler extends ChannelHandlerAdap
*/ */
private final class PriorKnowledgeHandler extends ByteToMessageDecoder { private final class PriorKnowledgeHandler extends ByteToMessageDecoder {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
int prefaceLength = CONNECTION_PREFACE.readableBytes(); int prefaceLength = CONNECTION_PREFACE.readableBytes();
int bytesRead = Math.min(in.readableBytes(), prefaceLength); int bytesRead = Math.min(in.readableBytes(), prefaceLength);

View File

@ -59,8 +59,8 @@ public class DecoratingHttp2ConnectionDecoder implements Http2ConnectionDecoder
} }
@Override @Override
public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Http2Exception { public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in) throws Http2Exception {
delegate.decodeFrame(ctx, in, out); delegate.decodeFrame(ctx, in);
} }
@Override @Override

View File

@ -22,8 +22,6 @@ import io.netty.util.internal.UnstableApi;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.util.List;
import static io.netty.handler.codec.http.HttpStatusClass.INFORMATIONAL; import static io.netty.handler.codec.http.HttpStatusClass.INFORMATIONAL;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT; import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT;
import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR; import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
@ -185,7 +183,7 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
} }
@Override @Override
public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Http2Exception { public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in) throws Http2Exception {
frameReader.readFrame(ctx, in, internalFrameListener); frameReader.readFrame(ctx, in, internalFrameListener);
} }

View File

@ -60,7 +60,7 @@ public interface Http2ConnectionDecoder extends Closeable {
/** /**
* Called by the {@link Http2ConnectionHandler} to decode the next frame from the input buffer. * Called by the {@link Http2ConnectionHandler} to decode the next frame from the input buffer.
*/ */
void decodeFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Http2Exception; void decodeFrame(ChannelHandlerContext ctx, ByteBuf in) throws Http2Exception;
/** /**
* Gets the local settings for this endpoint of the HTTP/2 connection. * Gets the local settings for this endpoint of the HTTP/2 connection.

View File

@ -32,7 +32,6 @@ import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static io.netty.buffer.ByteBufUtil.hexDump; import static io.netty.buffer.ByteBufUtil.hexDump;
@ -193,7 +192,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
} }
private abstract class BaseDecoder { private abstract class BaseDecoder {
public abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception; public abstract void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception;
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { } public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { }
public void channelActive(ChannelHandlerContext ctx) throws Exception { } public void channelActive(ChannelHandlerContext ctx) throws Exception { }
@ -232,12 +231,12 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
} }
@Override @Override
public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { public void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
if (ctx.channel().isActive() && readClientPrefaceString(in) && verifyFirstFrameIsSettings(in)) { if (ctx.channel().isActive() && readClientPrefaceString(in) && verifyFirstFrameIsSettings(in)) {
// After the preface is read, it is time to hand over control to the post initialized decoder. // After the preface is read, it is time to hand over control to the post initialized decoder.
byteDecoder = new FrameDecoder(); byteDecoder = new FrameDecoder();
byteDecoder.decode(ctx, in, out); byteDecoder.decode(ctx, in);
} }
} catch (Throwable e) { } catch (Throwable e) {
onError(ctx, false, e); onError(ctx, false, e);
@ -371,9 +370,9 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
private final class FrameDecoder extends BaseDecoder { private final class FrameDecoder extends BaseDecoder {
@Override @Override
public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { public void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
decoder.decodeFrame(ctx, in, out); decoder.decodeFrame(ctx, in);
} catch (Throwable e) { } catch (Throwable e) {
onError(ctx, false, e); onError(ctx, false, e);
} }
@ -381,7 +380,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
} }
@Override @Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception { public void handlerAdded0(ChannelHandlerContext ctx) throws Exception {
// Initialize the encoder, decoder, flow controllers, and internal state. // Initialize the encoder, decoder, flow controllers, and internal state.
encoder.lifecycleManager(this); encoder.lifecycleManager(this);
decoder.lifecycleManager(this); decoder.lifecycleManager(this);
@ -432,8 +431,8 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
byteDecoder.decode(ctx, in, out); byteDecoder.decode(ctx, in);
} }
@Override @Override

View File

@ -209,10 +209,9 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
} }
@Override @Override
public final void handlerAdded(ChannelHandlerContext ctx) throws Exception { public void handlerAdded0(ChannelHandlerContext ctx) throws Exception {
super.handlerAdded0(ctx);
this.ctx = ctx; this.ctx = ctx;
super.handlerAdded(ctx);
handlerAdded0(ctx);
// Must be after Http2ConnectionHandler does its initialization in handlerAdded above. // Must be after Http2ConnectionHandler does its initialization in handlerAdded above.
// The server will not send a connection preface so we are good to send a window update. // The server will not send a connection preface so we are good to send a window update.
Http2Connection connection = connection(); Http2Connection connection = connection();
@ -237,10 +236,6 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
} }
} }
void handlerAdded0(@SuppressWarnings("unsed") ChannelHandlerContext ctx) throws Exception {
// sub-class can override this for extra steps that needs to be done when the handler is added.
}
/** /**
* Handles the cleartext HTTP upgrade event. If an upgrade occurred, sends a simple response via * Handles the cleartext HTTP upgrade event. If an upgrade occurred, sends a simple response via
* HTTP/2 on stream 1 (the stream specifically reserved for cleartext HTTP upgrade). * HTTP/2 on stream 1 (the stream specifically reserved for cleartext HTTP upgrade).

View File

@ -124,6 +124,7 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
throw new IllegalStateException("EventExecutor must be EventLoop of Channel"); throw new IllegalStateException("EventExecutor must be EventLoop of Channel");
} }
this.ctx = ctx; this.ctx = ctx;
super.handlerAdded0(ctx);
} }
@Override @Override

View File

@ -82,7 +82,7 @@ public class Http2StreamFrameToHttpObjectCodec extends MessageToMessageCodec<Htt
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, Http2StreamFrame frame, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, Http2StreamFrame frame) throws Exception {
if (frame instanceof Http2HeadersFrame) { if (frame instanceof Http2HeadersFrame) {
Http2HeadersFrame headersFrame = (Http2HeadersFrame) frame; Http2HeadersFrame headersFrame = (Http2HeadersFrame) frame;
Http2Headers headers = headersFrame.headers(); Http2Headers headers = headersFrame.headers();
@ -95,7 +95,7 @@ public class Http2StreamFrameToHttpObjectCodec extends MessageToMessageCodec<Htt
// but we need to decode it as a FullHttpResponse to play nice with HttpObjectAggregator. // but we need to decode it as a FullHttpResponse to play nice with HttpObjectAggregator.
if (null != status && HttpResponseStatus.CONTINUE.codeAsText().contentEquals(status)) { if (null != status && HttpResponseStatus.CONTINUE.codeAsText().contentEquals(status)) {
final FullHttpMessage fullMsg = newFullMessage(id, headers, ctx.alloc()); final FullHttpMessage fullMsg = newFullMessage(id, headers, ctx.alloc());
out.add(fullMsg); ctx.fireChannelRead(fullMsg);
return; return;
} }
@ -104,24 +104,24 @@ public class Http2StreamFrameToHttpObjectCodec extends MessageToMessageCodec<Htt
LastHttpContent last = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER, validateHeaders); LastHttpContent last = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER, validateHeaders);
HttpConversionUtil.addHttp2ToHttpHeaders(id, headers, last.trailingHeaders(), HttpConversionUtil.addHttp2ToHttpHeaders(id, headers, last.trailingHeaders(),
HttpVersion.HTTP_1_1, true, true); HttpVersion.HTTP_1_1, true, true);
out.add(last); ctx.fireChannelRead(last);
} else { } else {
FullHttpMessage full = newFullMessage(id, headers, ctx.alloc()); FullHttpMessage full = newFullMessage(id, headers, ctx.alloc());
out.add(full); ctx.fireChannelRead(full);
} }
} else { } else {
HttpMessage req = newMessage(id, headers); HttpMessage req = newMessage(id, headers);
if (!HttpUtil.isContentLengthSet(req)) { if (!HttpUtil.isContentLengthSet(req)) {
req.headers().add(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); req.headers().add(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
} }
out.add(req); ctx.fireChannelRead(req);
} }
} else if (frame instanceof Http2DataFrame) { } else if (frame instanceof Http2DataFrame) {
Http2DataFrame dataFrame = (Http2DataFrame) frame; Http2DataFrame dataFrame = (Http2DataFrame) frame;
if (dataFrame.isEndStream()) { if (dataFrame.isEndStream()) {
out.add(new DefaultLastHttpContent(dataFrame.content().retain(), validateHeaders)); ctx.fireChannelRead(new DefaultLastHttpContent(dataFrame.content().retain(), validateHeaders));
} else { } else {
out.add(new DefaultHttpContent(dataFrame.content().retain())); ctx.fireChannelRead(new DefaultHttpContent(dataFrame.content().retain()));
} }
} }
} }

View File

@ -821,7 +821,7 @@ public class DefaultHttp2ConnectionDecoderTest {
private Http2FrameListener decode() throws Exception { private Http2FrameListener decode() throws Exception {
ArgumentCaptor<Http2FrameListener> internalListener = ArgumentCaptor.forClass(Http2FrameListener.class); ArgumentCaptor<Http2FrameListener> internalListener = ArgumentCaptor.forClass(Http2FrameListener.class);
doNothing().when(reader).readFrame(eq(ctx), any(ByteBuf.class), internalListener.capture()); doNothing().when(reader).readFrame(eq(ctx), any(ByteBuf.class), internalListener.capture());
decoder.decodeFrame(ctx, EMPTY_BUFFER, Collections.emptyList()); decoder.decodeFrame(ctx, EMPTY_BUFFER);
return internalListener.getValue(); return internalListener.getValue();
} }

View File

@ -39,9 +39,7 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
@ -49,7 +47,6 @@ import org.mockito.stubbing.Answer;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static io.netty.buffer.Unpooled.copiedBuffer; import static io.netty.buffer.Unpooled.copiedBuffer;
import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf; import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf;
@ -192,7 +189,8 @@ public class Http2ConnectionHandlerTest {
when(connection.stream(STREAM_ID)).thenReturn(stream); when(connection.stream(STREAM_ID)).thenReturn(stream);
when(connection.goAwaySent(anyInt(), anyLong(), any(ByteBuf.class))).thenReturn(true); when(connection.goAwaySent(anyInt(), anyLong(), any(ByteBuf.class))).thenReturn(true);
when(stream.open(anyBoolean())).thenReturn(stream); when(stream.open(anyBoolean())).thenReturn(stream);
when(encoder.writeSettings(eq(ctx), any(Http2Settings.class), eq(promise))).thenReturn(future); when(encoder.writeSettings(any(ChannelHandlerContext.class),
any(Http2Settings.class), eq(promise))).thenReturn(future);
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT); when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
when(ctx.channel()).thenReturn(channel); when(ctx.channel()).thenReturn(channel);
when(ctx.newSucceededFuture()).thenReturn(future); when(ctx.newSucceededFuture()).thenReturn(future);
@ -293,7 +291,7 @@ public class Http2ConnectionHandlerTest {
handler = newHandler(); handler = newHandler();
handler.channelRead(ctx, copiedBuffer("BAD_PREFACE", UTF_8)); handler.channelRead(ctx, copiedBuffer("BAD_PREFACE", UTF_8));
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class); ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
verify(frameWriter).writeGoAway(eq(ctx), eq(0), eq(PROTOCOL_ERROR.code()), verify(frameWriter).writeGoAway(any(ChannelHandlerContext.class), eq(0), eq(PROTOCOL_ERROR.code()),
captor.capture(), eq(promise)); captor.capture(), eq(promise));
assertEquals(0, captor.getValue().refCnt()); assertEquals(0, captor.getValue().refCnt());
} }
@ -304,7 +302,7 @@ public class Http2ConnectionHandlerTest {
handler = newHandler(); handler = newHandler();
handler.channelRead(ctx, copiedBuffer("GET /path HTTP/1.1", US_ASCII)); handler.channelRead(ctx, copiedBuffer("GET /path HTTP/1.1", US_ASCII));
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class); ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
verify(frameWriter).writeGoAway(eq(ctx), eq(0), eq(PROTOCOL_ERROR.code()), verify(frameWriter).writeGoAway(any(ChannelHandlerContext.class), eq(0), eq(PROTOCOL_ERROR.code()),
captor.capture(), eq(promise)); captor.capture(), eq(promise));
assertEquals(0, captor.getValue().refCnt()); assertEquals(0, captor.getValue().refCnt());
assertTrue(goAwayDebugCap.contains("/path")); assertTrue(goAwayDebugCap.contains("/path"));
@ -320,8 +318,8 @@ public class Http2ConnectionHandlerTest {
ByteBuf buf = Unpooled.buffer().writeBytes(connectionPrefaceBuf()).writeZero(10); ByteBuf buf = Unpooled.buffer().writeBytes(connectionPrefaceBuf()).writeZero(10);
handler.channelRead(ctx, buf); handler.channelRead(ctx, buf);
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class); ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
verify(frameWriter, atLeastOnce()).writeGoAway(eq(ctx), eq(0), eq(PROTOCOL_ERROR.code()), verify(frameWriter, atLeastOnce()).writeGoAway(any(ChannelHandlerContext.class),
captor.capture(), eq(promise)); eq(0), eq(PROTOCOL_ERROR.code()), captor.capture(), eq(promise));
assertEquals(0, captor.getValue().refCnt()); assertEquals(0, captor.getValue().refCnt());
} }
@ -332,7 +330,7 @@ public class Http2ConnectionHandlerTest {
ByteBuf prefacePlusSome = addSettingsHeader(Unpooled.buffer().writeBytes(connectionPrefaceBuf())); ByteBuf prefacePlusSome = addSettingsHeader(Unpooled.buffer().writeBytes(connectionPrefaceBuf()));
handler.channelRead(ctx, prefacePlusSome); handler.channelRead(ctx, prefacePlusSome);
verify(decoder, atLeastOnce()).decodeFrame(any(ChannelHandlerContext.class), verify(decoder, atLeastOnce()).decodeFrame(any(ChannelHandlerContext.class),
any(ByteBuf.class), ArgumentMatchers.any()); any(ByteBuf.class));
} }
@Test @Test
@ -344,7 +342,7 @@ public class Http2ConnectionHandlerTest {
ByteBuf preface = connectionPrefaceBuf(); ByteBuf preface = connectionPrefaceBuf();
handler.channelRead(ctx, preface); handler.channelRead(ctx, preface);
verify(decoder, never()).decodeFrame(any(ChannelHandlerContext.class), verify(decoder, never()).decodeFrame(any(ChannelHandlerContext.class),
any(ByteBuf.class), ArgumentMatchers.any()); any(ByteBuf.class));
// Now remove and add the handler...this is setting up the test condition. // Now remove and add the handler...this is setting up the test condition.
handler.handlerRemoved(ctx); handler.handlerRemoved(ctx);
@ -353,7 +351,7 @@ public class Http2ConnectionHandlerTest {
// Now verify we can continue as normal, reading connection preface plus more. // Now verify we can continue as normal, reading connection preface plus more.
ByteBuf prefacePlusSome = addSettingsHeader(Unpooled.buffer().writeBytes(connectionPrefaceBuf())); ByteBuf prefacePlusSome = addSettingsHeader(Unpooled.buffer().writeBytes(connectionPrefaceBuf()));
handler.channelRead(ctx, prefacePlusSome); handler.channelRead(ctx, prefacePlusSome);
verify(decoder, atLeastOnce()).decodeFrame(eq(ctx), any(ByteBuf.class), ArgumentMatchers.any()); verify(decoder, atLeastOnce()).decodeFrame(any(ChannelHandlerContext.class), any(ByteBuf.class));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -70,10 +70,8 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyShort;
import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same; import static org.mockito.Mockito.same;
@ -141,13 +139,13 @@ public class Http2FrameCodecTest {
channel.pipeline().fireChannelActive(); channel.pipeline().fireChannelActive();
// Handshake // Handshake
verify(frameWriter).writeSettings(eqFrameCodecCtx(), anyHttp2Settings(), anyChannelPromise()); verify(frameWriter).writeSettings(any(ChannelHandlerContext.class), anyHttp2Settings(), anyChannelPromise());
verifyNoMoreInteractions(frameWriter); verifyNoMoreInteractions(frameWriter);
channel.writeInbound(Http2CodecUtil.connectionPrefaceBuf()); channel.writeInbound(Http2CodecUtil.connectionPrefaceBuf());
frameInboundWriter.writeInboundSettings(initialRemoteSettings); frameInboundWriter.writeInboundSettings(initialRemoteSettings);
verify(frameWriter).writeSettingsAck(eqFrameCodecCtx(), anyChannelPromise()); verify(frameWriter).writeSettingsAck(any(ChannelHandlerContext.class), anyChannelPromise());
frameInboundWriter.writeInboundSettingsAck(); frameInboundWriter.writeInboundSettingsAck();
@ -177,10 +175,10 @@ public class Http2FrameCodecTest {
channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2)); channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2));
verify(frameWriter).writeHeaders( verify(frameWriter).writeHeaders(
eqFrameCodecCtx(), eq(1), eq(response), any(ChannelHandlerContext.class), eq(1), eq(response),
eq(27), eq(true), anyChannelPromise()); eq(27), eq(true), anyChannelPromise());
verify(frameWriter, never()).writeRstStream( verify(frameWriter, never()).writeRstStream(
eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise()); any(ChannelHandlerContext.class), anyInt(), anyLong(), anyChannelPromise());
assertEquals(State.CLOSED, stream.state()); assertEquals(State.CLOSED, stream.state());
event = inboundHandler.readInboundMessageOrUserEvent(); event = inboundHandler.readInboundMessageOrUserEvent();
@ -206,10 +204,10 @@ public class Http2FrameCodecTest {
channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2)); channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2));
verify(frameWriter).writeHeaders( verify(frameWriter).writeHeaders(
eqFrameCodecCtx(), eq(1), eq(response), any(ChannelHandlerContext.class), eq(1), eq(response),
eq(27), eq(true), anyChannelPromise()); eq(27), eq(true), anyChannelPromise());
verify(frameWriter, never()).writeRstStream( verify(frameWriter, never()).writeRstStream(
eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise()); any(ChannelHandlerContext.class), anyInt(), anyLong(), anyChannelPromise());
assertEquals(State.CLOSED, stream.state()); assertEquals(State.CLOSED, stream.state());
assertTrue(channel.isActive()); assertTrue(channel.isActive());
@ -264,13 +262,13 @@ public class Http2FrameCodecTest {
assertNull(inboundHandler.readInbound()); assertNull(inboundHandler.readInbound());
channel.writeOutbound(new DefaultHttp2HeadersFrame(response, false).stream(stream2)); inboundHandler.writeOutbound(new DefaultHttp2HeadersFrame(response, false).stream(stream2));
verify(frameWriter).writeHeaders(eqFrameCodecCtx(), eq(1), eq(response), verify(frameWriter).writeHeaders(any(ChannelHandlerContext.class), eq(1), eq(response), eq(0),
eq(0), eq(false), anyChannelPromise()); eq(false), anyChannelPromise());
channel.writeOutbound(new DefaultHttp2DataFrame(bb("world"), true, 27).stream(stream2)); channel.writeOutbound(new DefaultHttp2DataFrame(bb("world"), true, 27).stream(stream2));
ArgumentCaptor<ByteBuf> outboundData = ArgumentCaptor.forClass(ByteBuf.class); ArgumentCaptor<ByteBuf> outboundData = ArgumentCaptor.forClass(ByteBuf.class);
verify(frameWriter).writeData(eqFrameCodecCtx(), eq(1), outboundData.capture(), eq(27), verify(frameWriter).writeData(any(ChannelHandlerContext.class), eq(1), outboundData.capture(), eq(27),
eq(true), anyChannelPromise()); eq(true), anyChannelPromise());
ByteBuf bb = bb("world"); ByteBuf bb = bb("world");
@ -279,7 +277,8 @@ public class Http2FrameCodecTest {
bb.release(); bb.release();
outboundData.getValue().release(); outboundData.getValue().release();
verify(frameWriter, never()).writeRstStream(eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise()); verify(frameWriter, never()).writeRstStream(any(ChannelHandlerContext.class),
anyInt(), anyLong(), anyChannelPromise());
assertTrue(channel.isActive()); assertTrue(channel.isActive());
} }
@ -300,7 +299,7 @@ public class Http2FrameCodecTest {
assertEquals(3, stream2.id()); assertEquals(3, stream2.id());
channel.writeOutbound(new DefaultHttp2ResetFrame(314 /* non-standard error */).stream(stream2)); channel.writeOutbound(new DefaultHttp2ResetFrame(314 /* non-standard error */).stream(stream2));
verify(frameWriter).writeRstStream(eqFrameCodecCtx(), eq(3), eq(314L), anyChannelPromise()); verify(frameWriter).writeRstStream(any(ChannelHandlerContext.class), eq(3), eq(314L), anyChannelPromise());
assertEquals(State.CLOSED, stream.state()); assertEquals(State.CLOSED, stream.state());
assertTrue(channel.isActive()); assertTrue(channel.isActive());
} }
@ -341,7 +340,7 @@ public class Http2FrameCodecTest {
goAwayFrame.setExtraStreamIds(2); goAwayFrame.setExtraStreamIds(2);
channel.writeOutbound(goAwayFrame); channel.writeOutbound(goAwayFrame);
verify(frameWriter).writeGoAway(eqFrameCodecCtx(), eq(7), verify(frameWriter).writeGoAway(any(ChannelHandlerContext.class), eq(7),
eq(NO_ERROR.code()), eq(expected), anyChannelPromise()); eq(NO_ERROR.code()), eq(expected), anyChannelPromise());
assertEquals(State.OPEN, stream.state()); assertEquals(State.OPEN, stream.state());
assertTrue(channel.isActive()); assertTrue(channel.isActive());
@ -405,7 +404,7 @@ public class Http2FrameCodecTest {
channel.writeOutbound(goAwayFrame); channel.writeOutbound(goAwayFrame);
// When the last stream id computation overflows, the last stream id should just be set to 2^31 - 1. // When the last stream id computation overflows, the last stream id should just be set to 2^31 - 1.
verify(frameWriter).writeGoAway(eqFrameCodecCtx(), eq(Integer.MAX_VALUE), verify(frameWriter).writeGoAway(any(ChannelHandlerContext.class), eq(Integer.MAX_VALUE),
eq(NO_ERROR.code()), eq(debugData), anyChannelPromise()); eq(NO_ERROR.code()), eq(debugData), anyChannelPromise());
debugData.release(); debugData.release();
assertEquals(State.OPEN, stream.state()); assertEquals(State.OPEN, stream.state());
@ -581,7 +580,7 @@ public class Http2FrameCodecTest {
unknownFrame.stream(stream); unknownFrame.stream(stream);
channel.write(unknownFrame); channel.write(unknownFrame);
verify(frameWriter).writeFrame(eqFrameCodecCtx(), eq(unknownFrame.frameType()), verify(frameWriter).writeFrame(any(ChannelHandlerContext.class), eq(unknownFrame.frameType()),
eq(unknownFrame.stream().id()), eq(unknownFrame.flags()), eq(buffer), any(ChannelPromise.class)); eq(unknownFrame.stream().id()), eq(unknownFrame.flags()), eq(buffer), any(ChannelPromise.class));
} }
@ -590,7 +589,7 @@ public class Http2FrameCodecTest {
Http2Settings settings = new Http2Settings(); Http2Settings settings = new Http2Settings();
channel.write(new DefaultHttp2SettingsFrame(settings)); channel.write(new DefaultHttp2SettingsFrame(settings));
verify(frameWriter).writeSettings(eqFrameCodecCtx(), same(settings), any(ChannelPromise.class)); verify(frameWriter).writeSettings(any(ChannelHandlerContext.class), same(settings), any(ChannelPromise.class));
} }
@Test(timeout = 5000) @Test(timeout = 5000)
@ -751,7 +750,8 @@ public class Http2FrameCodecTest {
public void sendPing() { public void sendPing() {
channel.writeAndFlush(new DefaultHttp2PingFrame(12345)); channel.writeAndFlush(new DefaultHttp2PingFrame(12345));
verify(frameWriter).writePing(eqFrameCodecCtx(), eq(false), eq(12345L), anyChannelPromise()); verify(frameWriter).writePing(any(ChannelHandlerContext.class), eq(false),
eq(12345L), anyChannelPromise());
} }
@Test @Test
@ -769,7 +769,7 @@ public class Http2FrameCodecTest {
Http2Settings settings = new Http2Settings().maxConcurrentStreams(1); Http2Settings settings = new Http2Settings().maxConcurrentStreams(1);
channel.writeAndFlush(new DefaultHttp2SettingsFrame(settings)); channel.writeAndFlush(new DefaultHttp2SettingsFrame(settings));
verify(frameWriter).writeSettings(eqFrameCodecCtx(), eq(settings), anyChannelPromise()); verify(frameWriter).writeSettings(any(ChannelHandlerContext.class), eq(settings), anyChannelPromise());
} }
@Test @Test
@ -825,21 +825,21 @@ public class Http2FrameCodecTest {
Http2PingFrame frame = inboundHandler.readInbound(); Http2PingFrame frame = inboundHandler.readInbound();
assertFalse(frame.ack()); assertFalse(frame.ack());
assertEquals(8, frame.content()); assertEquals(8, frame.content());
verify(frameWriter).writePing(eqFrameCodecCtx(), eq(true), eq(8L), anyChannelPromise()); verify(frameWriter).writePing(any(ChannelHandlerContext.class), eq(true), eq(8L), anyChannelPromise());
} }
@Test @Test
public void autoAckPingFalse() throws Exception { public void autoAckPingFalse() throws Exception {
setUp(Http2FrameCodecBuilder.forServer().autoAckPingFrame(false), new Http2Settings()); setUp(Http2FrameCodecBuilder.forServer().autoAckPingFrame(false), new Http2Settings());
frameInboundWriter.writeInboundPing(false, 8); frameInboundWriter.writeInboundPing(false, 8);
verify(frameWriter, never()).writePing(eqFrameCodecCtx(), eq(true), eq(8L), anyChannelPromise()); verify(frameWriter, never()).writePing(any(ChannelHandlerContext.class), eq(true), eq(8L), anyChannelPromise());
Http2PingFrame frame = inboundHandler.readInbound(); Http2PingFrame frame = inboundHandler.readInbound();
assertFalse(frame.ack()); assertFalse(frame.ack());
assertEquals(8, frame.content()); assertEquals(8, frame.content());
// Now ack the frame manually. // Now ack the frame manually.
channel.writeAndFlush(new DefaultHttp2PingFrame(8, true)); channel.writeAndFlush(new DefaultHttp2PingFrame(8, true));
verify(frameWriter).writePing(eqFrameCodecCtx(), eq(true), eq(8L), anyChannelPromise()); verify(frameWriter).writePing(any(ChannelHandlerContext.class), eq(true), eq(8L), anyChannelPromise());
} }
@Test @Test
@ -911,8 +911,4 @@ public class Http2FrameCodecTest {
"HTTP/2", request); "HTTP/2", request);
channel.pipeline().fireUserEventTriggered(upgradeEvent); channel.pipeline().fireUserEventTriggered(upgradeEvent);
} }
private ChannelHandlerContext eqFrameCodecCtx() {
return eq(frameCodec.ctx);
}
} }

View File

@ -64,7 +64,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyShort;
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@ -108,7 +107,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
Http2Settings settings = new Http2Settings().initialWindowSize(initialRemoteStreamWindow); Http2Settings settings = new Http2Settings().initialWindowSize(initialRemoteStreamWindow);
frameInboundWriter.writeInboundSettings(settings); frameInboundWriter.writeInboundSettings(settings);
verify(frameWriter).writeSettingsAck(eqCodecCtx(), anyChannelPromise()); verify(frameWriter).writeSettingsAck(any(ChannelHandlerContext.class), anyChannelPromise());
frameInboundWriter.writeInboundSettingsAck(); frameInboundWriter.writeInboundSettingsAck();
@ -118,14 +117,10 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
assertNotNull(settingsAckFrame); assertNotNull(settingsAckFrame);
// Handshake // Handshake
verify(frameWriter).writeSettings(eqCodecCtx(), verify(frameWriter).writeSettings(any(ChannelHandlerContext.class),
anyHttp2Settings(), anyChannelPromise()); anyHttp2Settings(), anyChannelPromise());
} }
private ChannelHandlerContext eqCodecCtx() {
return eq(codec.ctx);
}
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
if (childChannelInitializer.handler instanceof LastInboundHandler) { if (childChannelInitializer.handler instanceof LastInboundHandler) {
@ -152,8 +147,8 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
}); });
assertTrue(childChannel.isActive()); assertTrue(childChannel.isActive());
verify(frameWriter).writeFrame(eq(codec.ctx), eq((byte) 99), eqStreamId(childChannel), any(Http2Flags.class), verify(frameWriter).writeFrame(any(ChannelHandlerContext.class), eq((byte) 99), eqStreamId(childChannel),
any(ByteBuf.class), any(ChannelPromise.class)); any(Http2Flags.class), any(ByteBuf.class), any(ChannelPromise.class));
} }
private Http2StreamChannel newInboundStream(int streamId, boolean endStream, final ChannelHandler childHandler) { private Http2StreamChannel newInboundStream(int streamId, boolean endStream, final ChannelHandler childHandler) {
@ -418,13 +413,13 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
assertTrue(childChannel.isActive()); assertTrue(childChannel.isActive());
childChannel.close(); childChannel.close();
verify(frameWriter).writeRstStream(eqCodecCtx(), verify(frameWriter).writeRstStream(any(ChannelHandlerContext.class),
eqStreamId(childChannel), eq(Http2Error.CANCEL.code()), anyChannelPromise()); eqStreamId(childChannel), eq(Http2Error.CANCEL.code()), anyChannelPromise());
} }
@Test @Test
public void outboundStreamShouldNotWriteResetFrameOnClose_IfStreamDidntExist() { public void outboundStreamShouldNotWriteResetFrameOnClose_IfStreamDidntExist() {
when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
any(Http2Headers.class), anyInt(), anyBoolean(), any(Http2Headers.class), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() { any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
@ -453,8 +448,8 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
childChannel.close(); childChannel.close();
// The channel was never active so we should not generate a RST frame. // The channel was never active so we should not generate a RST frame.
verify(frameWriter, never()).writeRstStream(eqCodecCtx(), eqStreamId(childChannel), anyLong(), verify(frameWriter, never()).writeRstStream(any(ChannelHandlerContext.class),
anyChannelPromise()); eqStreamId(childChannel), anyLong(), anyChannelPromise());
assertTrue(parentChannel.outboundMessages().isEmpty()); assertTrue(parentChannel.outboundMessages().isEmpty());
} }
@ -469,7 +464,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
assertFalse(inboundHandler.isChannelActive()); assertFalse(inboundHandler.isChannelActive());
// A RST_STREAM frame should NOT be emitted, as we received a RST_STREAM. // A RST_STREAM frame should NOT be emitted, as we received a RST_STREAM.
verify(frameWriter, Mockito.never()).writeRstStream(eqCodecCtx(), eqStreamId(channel), verify(frameWriter, Mockito.never()).writeRstStream(any(ChannelHandlerContext.class), eqStreamId(channel),
anyLong(), anyChannelPromise()); anyLong(), anyChannelPromise());
} }
@ -493,7 +488,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
assertTrue(childChannel.isActive()); assertTrue(childChannel.isActive());
Http2Headers headers = new DefaultHttp2Headers(); Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
eq(headers), anyInt(), anyBoolean(), eq(headers), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer(invocationOnMock -> { any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure( return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(
@ -537,7 +532,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
childChannel.close(); childChannel.close();
// An active outbound stream should emit a RST_STREAM frame. // An active outbound stream should emit a RST_STREAM frame.
verify(frameWriter).writeRstStream(eqCodecCtx(), eqStreamId(childChannel), verify(frameWriter).writeRstStream(any(ChannelHandlerContext.class), eqStreamId(childChannel),
anyLong(), anyChannelPromise()); anyLong(), anyChannelPromise());
assertFalse(childChannel.isOpen()); assertFalse(childChannel.isOpen());
@ -555,7 +550,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
assertTrue(childChannel.isActive()); assertTrue(childChannel.isActive());
Http2Headers headers = new DefaultHttp2Headers(); Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> { eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure( return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(
new Http2NoMoreStreamIdsException()); new Http2NoMoreStreamIdsException());
@ -637,7 +632,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
final AtomicBoolean channelActive = new AtomicBoolean(true); final AtomicBoolean channelActive = new AtomicBoolean(true);
Http2Headers headers = new DefaultHttp2Headers(); Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
eq(headers), anyInt(), anyBoolean(), eq(headers), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer(invocationOnMock -> { any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
ChannelPromise promise = invocationOnMock.getArgument(5); ChannelPromise promise = invocationOnMock.getArgument(5);

View File

@ -35,7 +35,6 @@ import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -204,7 +203,7 @@ public final class Http2TestUtil {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
reader.readFrame(ctx, in, new Http2FrameListener() { reader.readFrame(ctx, in, new Http2FrameListener() {
@Override @Override
public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding, public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,

View File

@ -165,8 +165,8 @@ public class StreamBufferingEncoderTest {
writeVerifyWriteHeaders(times(2), 3); writeVerifyWriteHeaders(times(2), 3);
// Contiguous data writes are coalesced // Contiguous data writes are coalesced
ArgumentCaptor<ByteBuf> bufCaptor = ArgumentCaptor.forClass(ByteBuf.class); ArgumentCaptor<ByteBuf> bufCaptor = ArgumentCaptor.forClass(ByteBuf.class);
verify(writer, times(1)) verify(writer, times(1)).writeData(any(ChannelHandlerContext.class), eq(3),
.writeData(eq(ctx), eq(3), bufCaptor.capture(), eq(0), eq(false), any(ChannelPromise.class)); bufCaptor.capture(), eq(0), eq(false), any(ChannelPromise.class));
assertEquals(expectedBytes, bufCaptor.getValue().readableBytes()); assertEquals(expectedBytes, bufCaptor.getValue().readableBytes());
} }

View File

@ -28,8 +28,6 @@ import io.netty.handler.codec.memcache.LastMemcacheContent;
import io.netty.handler.codec.memcache.MemcacheContent; import io.netty.handler.codec.memcache.MemcacheContent;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import java.util.List;
/** /**
* Decoder for both {@link BinaryMemcacheRequest} and {@link BinaryMemcacheResponse}. * Decoder for both {@link BinaryMemcacheRequest} and {@link BinaryMemcacheResponse}.
* <p/> * <p/>
@ -67,7 +65,7 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
switch (state) { switch (state) {
case READ_HEADER: try { case READ_HEADER: try {
if (in.readableBytes() < 24) { if (in.readableBytes() < 24) {
@ -79,7 +77,7 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
state = State.READ_EXTRAS; state = State.READ_EXTRAS;
} catch (Exception e) { } catch (Exception e) {
resetDecoder(); resetDecoder();
out.add(invalidMessage(e)); ctx.fireChannelRead(invalidMessage(e));
return; return;
} }
case READ_EXTRAS: try { case READ_EXTRAS: try {
@ -95,7 +93,7 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
state = State.READ_KEY; state = State.READ_KEY;
} catch (Exception e) { } catch (Exception e) {
resetDecoder(); resetDecoder();
out.add(invalidMessage(e)); ctx.fireChannelRead(invalidMessage(e));
return; return;
} }
case READ_KEY: try { case READ_KEY: try {
@ -107,11 +105,11 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
currentMessage.setKey(in.readRetainedSlice(keyLength)); currentMessage.setKey(in.readRetainedSlice(keyLength));
} }
out.add(currentMessage.retain()); ctx.fireChannelRead(currentMessage.retain());
state = State.READ_CONTENT; state = State.READ_CONTENT;
} catch (Exception e) { } catch (Exception e) {
resetDecoder(); resetDecoder();
out.add(invalidMessage(e)); ctx.fireChannelRead(invalidMessage(e));
return; return;
} }
case READ_CONTENT: try { case READ_CONTENT: try {
@ -142,12 +140,12 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
chunk = new DefaultMemcacheContent(chunkBuffer); chunk = new DefaultMemcacheContent(chunkBuffer);
} }
out.add(chunk); ctx.fireChannelRead(chunk);
if (alreadyReadChunkSize < valueLength) { if (alreadyReadChunkSize < valueLength) {
return; return;
} }
} else { } else {
out.add(LastMemcacheContent.EMPTY_LAST_CONTENT); ctx.fireChannelRead(LastMemcacheContent.EMPTY_LAST_CONTENT);
} }
resetDecoder(); resetDecoder();
@ -155,7 +153,7 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
return; return;
} catch (Exception e) { } catch (Exception e) {
resetDecoder(); resetDecoder();
out.add(invalidChunk(e)); ctx.fireChannelRead(invalidChunk(e));
return; return;
} }
case BAD_MESSAGE: case BAD_MESSAGE:

View File

@ -16,12 +16,23 @@
package io.netty.handler.codec.memcache.binary; package io.netty.handler.codec.memcache.binary;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelProgressivePromise;
import io.netty.channel.ChannelPromise;
import io.netty.channel.CombinedChannelDuplexHandler; import io.netty.channel.CombinedChannelDuplexHandler;
import io.netty.handler.codec.PrematureChannelClosureException; import io.netty.handler.codec.PrematureChannelClosureException;
import io.netty.handler.codec.memcache.LastMemcacheContent; import io.netty.handler.codec.memcache.LastMemcacheContent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import java.net.SocketAddress;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@ -84,24 +95,212 @@ public final class BinaryMemcacheClientCodec extends
private final class Decoder extends BinaryMemcacheResponseDecoder { private final class Decoder extends BinaryMemcacheResponseDecoder {
private ChannelHandlerContext context;
Decoder(int chunkSize) { Decoder(int chunkSize) {
super(chunkSize); super(chunkSize);
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void handlerAdded0(final ChannelHandlerContext ctx) {
int oldSize = out.size(); context = new ChannelHandlerContext() {
super.decode(ctx, in, out); @Override
public Channel channel() {
return ctx.channel();
}
if (failOnMissingResponse) { public EventExecutor executor() {
final int size = out.size(); return ctx.executor();
for (int i = oldSize; i < size; i ++) { }
Object msg = out.get(i);
if (msg instanceof LastMemcacheContent) { public String name() {
return ctx.name();
}
public ChannelHandler handler() {
return ctx.handler();
}
public boolean isRemoved() {
return ctx.isRemoved();
}
public ChannelHandlerContext fireChannelRegistered() {
ctx.fireChannelRegistered();
return this;
}
public ChannelHandlerContext fireChannelUnregistered() {
ctx.fireChannelUnregistered();
return this;
}
public ChannelHandlerContext fireChannelActive() {
ctx.fireChannelActive();
return this;
}
public ChannelHandlerContext fireChannelInactive() {
ctx.fireChannelInactive();
return this;
}
public ChannelHandlerContext fireExceptionCaught(Throwable cause) {
ctx.fireExceptionCaught(cause);
return this;
}
public ChannelHandlerContext fireUserEventTriggered(Object evt) {
ctx.fireUserEventTriggered(evt);
return this;
}
public ChannelHandlerContext fireChannelRead(Object msg) {
if (failOnMissingResponse && msg instanceof LastMemcacheContent) {
requestResponseCounter.decrementAndGet(); requestResponseCounter.decrementAndGet();
} }
ctx.fireChannelRead(msg);
return this;
} }
public ChannelHandlerContext fireChannelReadComplete() {
ctx.fireChannelReadComplete();
return this;
} }
public ChannelHandlerContext fireChannelWritabilityChanged() {
ctx.fireChannelWritabilityChanged();
return this;
}
public ChannelHandlerContext read() {
ctx.read();
return this;
}
public ChannelHandlerContext flush() {
ctx.flush();
return this;
}
public ChannelPipeline pipeline() {
return ctx.pipeline();
}
public ByteBufAllocator alloc() {
return ctx.alloc();
}
@Deprecated
public <T> Attribute<T> attr(AttributeKey<T> key) {
return ctx.attr(key);
}
@Deprecated
public <T> boolean hasAttr(AttributeKey<T> key) {
return ctx.hasAttr(key);
}
public ChannelFuture bind(SocketAddress localAddress) {
return ctx.bind(localAddress);
}
public ChannelFuture connect(SocketAddress remoteAddress) {
return ctx.connect(remoteAddress);
}
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return ctx.connect(remoteAddress, localAddress);
}
public ChannelFuture disconnect() {
return ctx.disconnect();
}
public ChannelFuture close() {
return ctx.close();
}
public ChannelFuture deregister() {
return ctx.deregister();
}
@Override
public ChannelFuture register() {
return ctx.register();
}
@Override
public ChannelFuture register(ChannelPromise promise) {
return ctx.register(promise);
}
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return ctx.bind(localAddress, promise);
}
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return ctx.connect(remoteAddress, promise);
}
public ChannelFuture connect(
SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
return ctx.connect(remoteAddress, localAddress, promise);
}
public ChannelFuture disconnect(ChannelPromise promise) {
return ctx.disconnect(promise);
}
public ChannelFuture close(ChannelPromise promise) {
return ctx.close(promise);
}
public ChannelFuture deregister(ChannelPromise promise) {
return ctx.deregister(promise);
}
public ChannelFuture write(Object msg) {
return ctx.write(msg);
}
public ChannelFuture write(Object msg, ChannelPromise promise) {
return ctx.write(msg, promise);
}
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
return ctx.writeAndFlush(msg, promise);
}
public ChannelFuture writeAndFlush(Object msg) {
return ctx.writeAndFlush(msg);
}
public ChannelPromise newPromise() {
return ctx.newPromise();
}
public ChannelProgressivePromise newProgressivePromise() {
return ctx.newProgressivePromise();
}
public ChannelFuture newSucceededFuture() {
return ctx.newSucceededFuture();
}
public ChannelFuture newFailedFuture(Throwable cause) {
return ctx.newFailedFuture(cause);
}
public ChannelPromise voidPromise() {
return ctx.voidPromise();
}
};
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
super.decode(context, in);
} }
@Override @Override

View File

@ -69,7 +69,7 @@ public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
switch (state()) { switch (state()) {
case READ_FIXED_HEADER: try { case READ_FIXED_HEADER: try {
mqttFixedHeader = decodeFixedHeader(buffer); mqttFixedHeader = decodeFixedHeader(buffer);
@ -77,7 +77,7 @@ public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
checkpoint(DecoderState.READ_VARIABLE_HEADER); checkpoint(DecoderState.READ_VARIABLE_HEADER);
// fall through // fall through
} catch (Exception cause) { } catch (Exception cause) {
out.add(invalidMessage(cause)); ctx.fireChannelRead(invalidMessage(cause));
return; return;
} }
@ -91,7 +91,7 @@ public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
checkpoint(DecoderState.READ_PAYLOAD); checkpoint(DecoderState.READ_PAYLOAD);
// fall through // fall through
} catch (Exception cause) { } catch (Exception cause) {
out.add(invalidMessage(cause)); ctx.fireChannelRead(invalidMessage(cause));
return; return;
} }
@ -113,10 +113,10 @@ public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
mqttFixedHeader, variableHeader, decodedPayload.value); mqttFixedHeader, variableHeader, decodedPayload.value);
mqttFixedHeader = null; mqttFixedHeader = null;
variableHeader = null; variableHeader = null;
out.add(message); ctx.fireChannelRead(message);
break; break;
} catch (Exception cause) { } catch (Exception cause) {
out.add(invalidMessage(cause)); ctx.fireChannelRead(invalidMessage(cause));
return; return;
} }

View File

@ -25,6 +25,7 @@ import io.netty.handler.codec.DecoderException;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
@ -74,12 +75,11 @@ public class MqttCodecTest {
final MqttConnectMessage message = createConnectMessage(MqttVersion.MQTT_3_1); final MqttConnectMessage message = createConnectMessage(MqttVersion.MQTT_3_1);
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttConnectMessage> captor = ArgumentCaptor.forClass(MqttConnectMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttConnectMessage decodedMessage = captor.getValue();
final MqttConnectMessage decodedMessage = (MqttConnectMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateConnectVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validateConnectVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
@ -91,12 +91,11 @@ public class MqttCodecTest {
final MqttConnectMessage message = createConnectMessage(MqttVersion.MQTT_3_1_1); final MqttConnectMessage message = createConnectMessage(MqttVersion.MQTT_3_1_1);
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttConnectMessage> captor = ArgumentCaptor.forClass(MqttConnectMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttConnectMessage decodedMessage = captor.getValue();
final MqttConnectMessage decodedMessage = (MqttConnectMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateConnectVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validateConnectVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
@ -110,12 +109,12 @@ public class MqttCodecTest {
try { try {
// Set the reserved flag in the CONNECT Packet to 1 // Set the reserved flag in the CONNECT Packet to 1
byteBuf.setByte(9, byteBuf.getByte(9) | 0x1); byteBuf.setByte(9, byteBuf.getByte(9) | 0x1);
final List<Object> out = new LinkedList<>();
mqttDecoder.decode(ctx, byteBuf, out);
assertEquals("Expected one object but got " + out.size(), 1, out.size()); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
final MqttMessage decodedMessage = (MqttMessage) out.get(0); final MqttMessage decodedMessage = captor.getValue();
assertTrue(decodedMessage.decoderResult().isFailure()); assertTrue(decodedMessage.decoderResult().isFailure());
Throwable cause = decodedMessage.decoderResult().cause(); Throwable cause = decodedMessage.decoderResult().cause();
assertTrue(cause instanceof DecoderException); assertTrue(cause instanceof DecoderException);
@ -141,12 +140,11 @@ public class MqttCodecTest {
final MqttConnAckMessage message = createConnAckMessage(); final MqttConnAckMessage message = createConnAckMessage();
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttConnAckMessage> captor = ArgumentCaptor.forClass(MqttConnAckMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttConnAckMessage decodedMessage = captor.getValue();
final MqttConnAckMessage decodedMessage = (MqttConnAckMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateConnAckVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validateConnAckVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
} }
@ -156,12 +154,11 @@ public class MqttCodecTest {
final MqttPublishMessage message = createPublishMessage(); final MqttPublishMessage message = createPublishMessage();
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttPublishMessage> captor = ArgumentCaptor.forClass(MqttPublishMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttPublishMessage decodedMessage = captor.getValue();
final MqttPublishMessage decodedMessage = (MqttPublishMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validatePublishVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validatePublishVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
validatePublishPayload(message.payload(), decodedMessage.payload()); validatePublishPayload(message.payload(), decodedMessage.payload());
@ -192,12 +189,11 @@ public class MqttCodecTest {
final MqttSubscribeMessage message = createSubscribeMessage(); final MqttSubscribeMessage message = createSubscribeMessage();
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttSubscribeMessage> captor = ArgumentCaptor.forClass(MqttSubscribeMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttSubscribeMessage decodedMessage = captor.getValue();
final MqttSubscribeMessage decodedMessage = (MqttSubscribeMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
validateSubscribePayload(message.payload(), decodedMessage.payload()); validateSubscribePayload(message.payload(), decodedMessage.payload());
@ -208,12 +204,11 @@ public class MqttCodecTest {
final MqttSubAckMessage message = createSubAckMessage(); final MqttSubAckMessage message = createSubAckMessage();
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttSubAckMessage> captor = ArgumentCaptor.forClass(MqttSubAckMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttSubAckMessage decodedMessage = captor.getValue();
final MqttSubAckMessage decodedMessage = (MqttSubAckMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
validateSubAckPayload(message.payload(), decodedMessage.payload()); validateSubAckPayload(message.payload(), decodedMessage.payload());
@ -230,12 +225,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttSubAckMessage> captor = ArgumentCaptor.forClass(MqttSubAckMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); MqttSubAckMessage decodedMessage = captor.getValue();
MqttSubAckMessage decodedMessage = (MqttSubAckMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
validateSubAckPayload(message.payload(), decodedMessage.payload()); validateSubAckPayload(message.payload(), decodedMessage.payload());
@ -248,12 +242,11 @@ public class MqttCodecTest {
final MqttUnsubscribeMessage message = createUnsubscribeMessage(); final MqttUnsubscribeMessage message = createUnsubscribeMessage();
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttUnsubscribeMessage> captor = ArgumentCaptor.forClass(MqttUnsubscribeMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttUnsubscribeMessage decodedMessage = captor.getValue();
final MqttUnsubscribeMessage decodedMessage = (MqttUnsubscribeMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader()); validateMessageIdVariableHeader(message.variableHeader(), decodedMessage.variableHeader());
validateUnsubscribePayload(message.payload(), decodedMessage.payload()); validateUnsubscribePayload(message.payload(), decodedMessage.payload());
@ -287,12 +280,12 @@ public class MqttCodecTest {
try { try {
// setting an invalid message type (15, reserved and forbidden by MQTT 3.1.1 spec) // setting an invalid message type (15, reserved and forbidden by MQTT 3.1.1 spec)
byteBuf.setByte(0, 0xF0); byteBuf.setByte(0, 0xF0);
final List<Object> out = new LinkedList<>();
mqttDecoder.decode(ctx, byteBuf, out);
assertEquals("Expected one object but got " + out.size(), 1, out.size()); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
final MqttMessage decodedMessage = (MqttMessage) out.get(0); final MqttMessage decodedMessage = captor.getValue();
assertTrue(decodedMessage.decoderResult().isFailure()); assertTrue(decodedMessage.decoderResult().isFailure());
Throwable cause = decodedMessage.decoderResult().cause(); Throwable cause = decodedMessage.decoderResult().cause();
assertTrue(cause instanceof IllegalArgumentException); assertTrue(cause instanceof IllegalArgumentException);
@ -308,12 +301,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
try { try {
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoderLimitedMessageSize.decode(ctx, byteBuf, out); mqttDecoderLimitedMessageSize.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateConnectVariableHeader(message.variableHeader(), validateConnectVariableHeader(message.variableHeader(),
@ -330,12 +322,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
try { try {
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoderLimitedMessageSize.decode(ctx, byteBuf, out); mqttDecoderLimitedMessageSize.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateConnectVariableHeader(message.variableHeader(), validateConnectVariableHeader(message.variableHeader(),
@ -352,12 +343,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
try { try {
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoderLimitedMessageSize.decode(ctx, byteBuf, out); mqttDecoderLimitedMessageSize.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateDecoderExceptionTooLargeMessage(decodedMessage); validateDecoderExceptionTooLargeMessage(decodedMessage);
} finally { } finally {
@ -371,12 +361,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
try { try {
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoderLimitedMessageSize.decode(ctx, byteBuf, out); mqttDecoderLimitedMessageSize.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validatePublishVariableHeader(message.variableHeader(), validatePublishVariableHeader(message.variableHeader(),
@ -393,12 +382,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
try { try {
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoderLimitedMessageSize.decode(ctx, byteBuf, out); mqttDecoderLimitedMessageSize.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader(message.variableHeader(), validateMessageIdVariableHeader(message.variableHeader(),
(MqttMessageIdVariableHeader) decodedMessage.variableHeader()); (MqttMessageIdVariableHeader) decodedMessage.variableHeader());
@ -414,12 +402,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
try { try {
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoderLimitedMessageSize.decode(ctx, byteBuf, out); mqttDecoderLimitedMessageSize.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader(message.variableHeader(), validateMessageIdVariableHeader(message.variableHeader(),
(MqttMessageIdVariableHeader) decodedMessage.variableHeader()); (MqttMessageIdVariableHeader) decodedMessage.variableHeader());
@ -435,12 +422,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
try { try {
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoderLimitedMessageSize.decode(ctx, byteBuf, out); mqttDecoderLimitedMessageSize.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader(message.variableHeader(), validateMessageIdVariableHeader(message.variableHeader(),
(MqttMessageIdVariableHeader) decodedMessage.variableHeader()); (MqttMessageIdVariableHeader) decodedMessage.variableHeader());
@ -453,12 +439,11 @@ public class MqttCodecTest {
private void testMessageWithOnlyFixedHeader(MqttMessage message) throws Exception { private void testMessageWithOnlyFixedHeader(MqttMessage message) throws Exception {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
} }
@ -468,12 +453,11 @@ public class MqttCodecTest {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message); ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
final List<Object> out = new LinkedList<>(); ArgumentCaptor<MqttMessage> captor = ArgumentCaptor.forClass(MqttMessage.class);
mqttDecoder.decode(ctx, byteBuf, out); mqttDecoder.decode(ctx, byteBuf);
verify(ctx).fireChannelRead(captor.capture());
assertEquals("Expected one object but got " + out.size(), 1, out.size()); final MqttMessage decodedMessage = captor.getValue();
final MqttMessage decodedMessage = (MqttMessage) out.get(0);
validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader()); validateFixedHeaders(message.fixedHeader(), decodedMessage.fixedHeader());
validateMessageIdVariableHeader( validateMessageIdVariableHeader(
(MqttMessageIdVariableHeader) message.variableHeader(), (MqttMessageIdVariableHeader) message.variableHeader(),

View File

@ -36,7 +36,7 @@ public final class RedisArrayAggregator extends MessageToMessageDecoder<RedisMes
private final Deque<AggregateState> depths = new ArrayDeque<>(4); private final Deque<AggregateState> depths = new ArrayDeque<>(4);
@Override @Override
protected void decode(ChannelHandlerContext ctx, RedisMessage msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, RedisMessage msg) throws Exception {
if (msg instanceof ArrayHeaderRedisMessage) { if (msg instanceof ArrayHeaderRedisMessage) {
msg = decodeRedisArrayHeader((ArrayHeaderRedisMessage) msg); msg = decodeRedisArrayHeader((ArrayHeaderRedisMessage) msg);
if (msg == null) { if (msg == null) {
@ -60,7 +60,7 @@ public final class RedisArrayAggregator extends MessageToMessageDecoder<RedisMes
} }
} }
out.add(msg); ctx.fireChannelRead(msg);
} }
private RedisMessage decodeRedisArrayHeader(ArrayHeaderRedisMessage header) { private RedisMessage decodeRedisArrayHeader(ArrayHeaderRedisMessage header) {

View File

@ -22,8 +22,6 @@ import io.netty.util.ByteProcessor;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import java.util.List;
/** /**
* Decodes the Redis protocol into {@link RedisMessage} objects following * Decodes the Redis protocol into {@link RedisMessage} objects following
* <a href="http://redis.io/topics/protocol">RESP (REdis Serialization Protocol)</a>. * <a href="http://redis.io/topics/protocol">RESP (REdis Serialization Protocol)</a>.
@ -95,7 +93,7 @@ public final class RedisDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
for (;;) { for (;;) {
switch (state) { switch (state) {
@ -105,22 +103,22 @@ public final class RedisDecoder extends ByteToMessageDecoder {
} }
break; break;
case DECODE_INLINE: case DECODE_INLINE:
if (!decodeInline(in, out)) { if (!decodeInline(ctx, in)) {
return; return;
} }
break; break;
case DECODE_LENGTH: case DECODE_LENGTH:
if (!decodeLength(in, out)) { if (!decodeLength(ctx, in)) {
return; return;
} }
break; break;
case DECODE_BULK_STRING_EOL: case DECODE_BULK_STRING_EOL:
if (!decodeBulkStringEndOfLine(in, out)) { if (!decodeBulkStringEndOfLine(ctx, in)) {
return; return;
} }
break; break;
case DECODE_BULK_STRING_CONTENT: case DECODE_BULK_STRING_CONTENT:
if (!decodeBulkStringContent(in, out)) { if (!decodeBulkStringContent(ctx, in)) {
return; return;
} }
break; break;
@ -152,7 +150,7 @@ public final class RedisDecoder extends ByteToMessageDecoder {
return true; return true;
} }
private boolean decodeInline(ByteBuf in, List<Object> out) throws Exception { private boolean decodeInline(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf lineBytes = readLine(in); ByteBuf lineBytes = readLine(in);
if (lineBytes == null) { if (lineBytes == null) {
if (in.readableBytes() > maxInlineMessageLength) { if (in.readableBytes() > maxInlineMessageLength) {
@ -161,12 +159,12 @@ public final class RedisDecoder extends ByteToMessageDecoder {
} }
return false; return false;
} }
out.add(newInlineRedisMessage(type, lineBytes)); ctx.fireChannelRead(newInlineRedisMessage(type, lineBytes));
resetDecoder(); resetDecoder();
return true; return true;
} }
private boolean decodeLength(ByteBuf in, List<Object> out) throws Exception { private boolean decodeLength(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf lineByteBuf = readLine(in); ByteBuf lineByteBuf = readLine(in);
if (lineByteBuf == null) { if (lineByteBuf == null) {
return false; return false;
@ -177,7 +175,7 @@ public final class RedisDecoder extends ByteToMessageDecoder {
} }
switch (type) { switch (type) {
case ARRAY_HEADER: case ARRAY_HEADER:
out.add(new ArrayHeaderRedisMessage(length)); ctx.fireChannelRead(new ArrayHeaderRedisMessage(length));
resetDecoder(); resetDecoder();
return true; return true;
case BULK_STRING: case BULK_STRING:
@ -186,41 +184,41 @@ public final class RedisDecoder extends ByteToMessageDecoder {
RedisConstants.REDIS_MESSAGE_MAX_LENGTH + ")"); RedisConstants.REDIS_MESSAGE_MAX_LENGTH + ")");
} }
remainingBulkLength = (int) length; // range(int) is already checked. remainingBulkLength = (int) length; // range(int) is already checked.
return decodeBulkString(in, out); return decodeBulkString(ctx, in);
default: default:
throw new RedisCodecException("bad type: " + type); throw new RedisCodecException("bad type: " + type);
} }
} }
private boolean decodeBulkString(ByteBuf in, List<Object> out) throws Exception { private boolean decodeBulkString(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
switch (remainingBulkLength) { switch (remainingBulkLength) {
case RedisConstants.NULL_VALUE: // $-1\r\n case RedisConstants.NULL_VALUE: // $-1\r\n
out.add(FullBulkStringRedisMessage.NULL_INSTANCE); ctx.fireChannelRead(FullBulkStringRedisMessage.NULL_INSTANCE);
resetDecoder(); resetDecoder();
return true; return true;
case 0: case 0:
state = State.DECODE_BULK_STRING_EOL; state = State.DECODE_BULK_STRING_EOL;
return decodeBulkStringEndOfLine(in, out); return decodeBulkStringEndOfLine(ctx, in);
default: // expectedBulkLength is always positive. default: // expectedBulkLength is always positive.
out.add(new BulkStringHeaderRedisMessage(remainingBulkLength)); ctx.fireChannelRead(new BulkStringHeaderRedisMessage(remainingBulkLength));
state = State.DECODE_BULK_STRING_CONTENT; state = State.DECODE_BULK_STRING_CONTENT;
return decodeBulkStringContent(in, out); return decodeBulkStringContent(ctx, in);
} }
} }
// $0\r\n <here> \r\n // $0\r\n <here> \r\n
private boolean decodeBulkStringEndOfLine(ByteBuf in, List<Object> out) throws Exception { private boolean decodeBulkStringEndOfLine(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < RedisConstants.EOL_LENGTH) { if (in.readableBytes() < RedisConstants.EOL_LENGTH) {
return false; return false;
} }
readEndOfLine(in); readEndOfLine(in);
out.add(FullBulkStringRedisMessage.EMPTY_INSTANCE); ctx.fireChannelRead(FullBulkStringRedisMessage.EMPTY_INSTANCE);
resetDecoder(); resetDecoder();
return true; return true;
} }
// ${expectedBulkLength}\r\n <here> {data...}\r\n // ${expectedBulkLength}\r\n <here> {data...}\r\n
private boolean decodeBulkStringContent(ByteBuf in, List<Object> out) throws Exception { private boolean decodeBulkStringContent(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
final int readableBytes = in.readableBytes(); final int readableBytes = in.readableBytes();
if (readableBytes == 0 || remainingBulkLength == 0 && readableBytes < RedisConstants.EOL_LENGTH) { if (readableBytes == 0 || remainingBulkLength == 0 && readableBytes < RedisConstants.EOL_LENGTH) {
return false; return false;
@ -231,7 +229,7 @@ public final class RedisDecoder extends ByteToMessageDecoder {
ByteBuf content = in.readSlice(remainingBulkLength); ByteBuf content = in.readSlice(remainingBulkLength);
readEndOfLine(in); readEndOfLine(in);
// Only call retain after readEndOfLine(...) as the method may throw an exception. // Only call retain after readEndOfLine(...) as the method may throw an exception.
out.add(new DefaultLastBulkStringRedisContent(content.retain())); ctx.fireChannelRead(new DefaultLastBulkStringRedisContent(content.retain()));
resetDecoder(); resetDecoder();
return true; return true;
} }
@ -239,7 +237,7 @@ public final class RedisDecoder extends ByteToMessageDecoder {
// chunked write. // chunked write.
int toRead = Math.min(remainingBulkLength, readableBytes); int toRead = Math.min(remainingBulkLength, readableBytes);
remainingBulkLength -= toRead; remainingBulkLength -= toRead;
out.add(new DefaultBulkStringRedisContent(in.readSlice(toRead).retain())); ctx.fireChannelRead(new DefaultBulkStringRedisContent(in.readSlice(toRead).retain()));
return true; return true;
} }

View File

@ -42,8 +42,8 @@ public final class SmtpResponseDecoder extends LineBasedFrameDecoder {
} }
@Override @Override
protected SmtpResponse decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { protected SmtpResponse decode0(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, buffer); ByteBuf frame = (ByteBuf) super.decode0(ctx, buffer);
if (frame == null) { if (frame == null) {
// No full line received yet. // No full line received yet.
return null; return null;

View File

@ -20,8 +20,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socks.SocksAuthRequestDecoder.State; import io.netty.handler.codec.socks.SocksAuthRequestDecoder.State;
import java.util.List;
/** /**
* Decodes {@link ByteBuf}s into {@link SocksAuthRequest}. * Decodes {@link ByteBuf}s into {@link SocksAuthRequest}.
* Before returning SocksRequest decoder removes itself from pipeline. * Before returning SocksRequest decoder removes itself from pipeline.
@ -35,11 +33,11 @@ public class SocksAuthRequestDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
switch (state()) { switch (state()) {
case CHECK_PROTOCOL_VERSION: { case CHECK_PROTOCOL_VERSION: {
if (byteBuf.readByte() != SocksSubnegotiationVersion.AUTH_PASSWORD.byteValue()) { if (byteBuf.readByte() != SocksSubnegotiationVersion.AUTH_PASSWORD.byteValue()) {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST);
break; break;
} }
checkpoint(State.READ_USERNAME); checkpoint(State.READ_USERNAME);
@ -52,7 +50,7 @@ public class SocksAuthRequestDecoder extends ReplayingDecoder<State> {
case READ_PASSWORD: { case READ_PASSWORD: {
int fieldLength = byteBuf.readByte(); int fieldLength = byteBuf.readByte();
String password = SocksCommonUtils.readUsAscii(byteBuf, fieldLength); String password = SocksCommonUtils.readUsAscii(byteBuf, fieldLength);
out.add(new SocksAuthRequest(username, password)); ctx.fireChannelRead(new SocksAuthRequest(username, password));
break; break;
} }
default: { default: {

View File

@ -20,8 +20,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socks.SocksAuthResponseDecoder.State; import io.netty.handler.codec.socks.SocksAuthResponseDecoder.State;
import java.util.List;
/** /**
* Decodes {@link ByteBuf}s into {@link SocksAuthResponse}. * Decodes {@link ByteBuf}s into {@link SocksAuthResponse}.
* Before returning SocksResponse decoder removes itself from pipeline. * Before returning SocksResponse decoder removes itself from pipeline.
@ -33,26 +31,26 @@ public class SocksAuthResponseDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out) protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf)
throws Exception { throws Exception {
switch (state()) { switch (state()) {
case CHECK_PROTOCOL_VERSION: { case CHECK_PROTOCOL_VERSION: {
if (byteBuf.readByte() != SocksSubnegotiationVersion.AUTH_PASSWORD.byteValue()) { if (byteBuf.readByte() != SocksSubnegotiationVersion.AUTH_PASSWORD.byteValue()) {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE);
break; break;
} }
checkpoint(State.READ_AUTH_RESPONSE); checkpoint(State.READ_AUTH_RESPONSE);
} }
case READ_AUTH_RESPONSE: { case READ_AUTH_RESPONSE: {
SocksAuthStatus authStatus = SocksAuthStatus.valueOf(byteBuf.readByte()); SocksAuthStatus authStatus = SocksAuthStatus.valueOf(byteBuf.readByte());
out.add(new SocksAuthResponse(authStatus)); ctx.fireChannelRead(new SocksAuthResponse(authStatus));
break; break;
} }
default: { default: {
throw new Error(); throw new Error();
} }
} }
channelHandlerContext.pipeline().remove(this); ctx.pipeline().remove(this);
} }
enum State { enum State {

View File

@ -21,8 +21,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socks.SocksCmdRequestDecoder.State; import io.netty.handler.codec.socks.SocksCmdRequestDecoder.State;
import io.netty.util.NetUtil; import io.netty.util.NetUtil;
import java.util.List;
/** /**
* Decodes {@link ByteBuf}s into {@link SocksCmdRequest}. * Decodes {@link ByteBuf}s into {@link SocksCmdRequest}.
* Before returning SocksRequest decoder removes itself from pipeline. * Before returning SocksRequest decoder removes itself from pipeline.
@ -37,11 +35,11 @@ public class SocksCmdRequestDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
switch (state()) { switch (state()) {
case CHECK_PROTOCOL_VERSION: { case CHECK_PROTOCOL_VERSION: {
if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) { if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST);
break; break;
} }
checkpoint(State.READ_CMD_HEADER); checkpoint(State.READ_CMD_HEADER);
@ -57,14 +55,14 @@ public class SocksCmdRequestDecoder extends ReplayingDecoder<State> {
case IPv4: { case IPv4: {
String host = NetUtil.intToIpAddress(byteBuf.readInt()); String host = NetUtil.intToIpAddress(byteBuf.readInt());
int port = byteBuf.readUnsignedShort(); int port = byteBuf.readUnsignedShort();
out.add(new SocksCmdRequest(cmdType, addressType, host, port)); ctx.fireChannelRead(new SocksCmdRequest(cmdType, addressType, host, port));
break; break;
} }
case DOMAIN: { case DOMAIN: {
int fieldLength = byteBuf.readByte(); int fieldLength = byteBuf.readByte();
String host = SocksCommonUtils.readUsAscii(byteBuf, fieldLength); String host = SocksCommonUtils.readUsAscii(byteBuf, fieldLength);
int port = byteBuf.readUnsignedShort(); int port = byteBuf.readUnsignedShort();
out.add(new SocksCmdRequest(cmdType, addressType, host, port)); ctx.fireChannelRead(new SocksCmdRequest(cmdType, addressType, host, port));
break; break;
} }
case IPv6: { case IPv6: {
@ -72,11 +70,11 @@ public class SocksCmdRequestDecoder extends ReplayingDecoder<State> {
byteBuf.readBytes(bytes); byteBuf.readBytes(bytes);
String host = SocksCommonUtils.ipv6toStr(bytes); String host = SocksCommonUtils.ipv6toStr(bytes);
int port = byteBuf.readUnsignedShort(); int port = byteBuf.readUnsignedShort();
out.add(new SocksCmdRequest(cmdType, addressType, host, port)); ctx.fireChannelRead(new SocksCmdRequest(cmdType, addressType, host, port));
break; break;
} }
case UNKNOWN: { case UNKNOWN: {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST);
break; break;
} }
default: { default: {

View File

@ -21,8 +21,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socks.SocksCmdResponseDecoder.State; import io.netty.handler.codec.socks.SocksCmdResponseDecoder.State;
import io.netty.util.NetUtil; import io.netty.util.NetUtil;
import java.util.List;
/** /**
* Decodes {@link ByteBuf}s into {@link SocksCmdResponse}. * Decodes {@link ByteBuf}s into {@link SocksCmdResponse}.
* Before returning SocksResponse decoder removes itself from pipeline. * Before returning SocksResponse decoder removes itself from pipeline.
@ -37,11 +35,11 @@ public class SocksCmdResponseDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
switch (state()) { switch (state()) {
case CHECK_PROTOCOL_VERSION: { case CHECK_PROTOCOL_VERSION: {
if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) { if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE);
break; break;
} }
checkpoint(State.READ_CMD_HEADER); checkpoint(State.READ_CMD_HEADER);
@ -57,14 +55,14 @@ public class SocksCmdResponseDecoder extends ReplayingDecoder<State> {
case IPv4: { case IPv4: {
String host = NetUtil.intToIpAddress(byteBuf.readInt()); String host = NetUtil.intToIpAddress(byteBuf.readInt());
int port = byteBuf.readUnsignedShort(); int port = byteBuf.readUnsignedShort();
out.add(new SocksCmdResponse(cmdStatus, addressType, host, port)); ctx.fireChannelRead(new SocksCmdResponse(cmdStatus, addressType, host, port));
break; break;
} }
case DOMAIN: { case DOMAIN: {
int fieldLength = byteBuf.readByte(); int fieldLength = byteBuf.readByte();
String host = SocksCommonUtils.readUsAscii(byteBuf, fieldLength); String host = SocksCommonUtils.readUsAscii(byteBuf, fieldLength);
int port = byteBuf.readUnsignedShort(); int port = byteBuf.readUnsignedShort();
out.add(new SocksCmdResponse(cmdStatus, addressType, host, port)); ctx.fireChannelRead(new SocksCmdResponse(cmdStatus, addressType, host, port));
break; break;
} }
case IPv6: { case IPv6: {
@ -72,11 +70,11 @@ public class SocksCmdResponseDecoder extends ReplayingDecoder<State> {
byteBuf.readBytes(bytes); byteBuf.readBytes(bytes);
String host = SocksCommonUtils.ipv6toStr(bytes); String host = SocksCommonUtils.ipv6toStr(bytes);
int port = byteBuf.readUnsignedShort(); int port = byteBuf.readUnsignedShort();
out.add(new SocksCmdResponse(cmdStatus, addressType, host, port)); ctx.fireChannelRead(new SocksCmdResponse(cmdStatus, addressType, host, port));
break; break;
} }
case UNKNOWN: { case UNKNOWN: {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE);
break; break;
} }
default: { default: {

View File

@ -35,11 +35,11 @@ public class SocksInitRequestDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
switch (state()) { switch (state()) {
case CHECK_PROTOCOL_VERSION: { case CHECK_PROTOCOL_VERSION: {
if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) { if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST);
break; break;
} }
checkpoint(State.READ_AUTH_SCHEMES); checkpoint(State.READ_AUTH_SCHEMES);
@ -55,7 +55,7 @@ public class SocksInitRequestDecoder extends ReplayingDecoder<State> {
} else { } else {
authSchemes = Collections.emptyList(); authSchemes = Collections.emptyList();
} }
out.add(new SocksInitRequest(authSchemes)); ctx.fireChannelRead(new SocksInitRequest(authSchemes));
break; break;
} }
default: { default: {

View File

@ -20,8 +20,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socks.SocksInitResponseDecoder.State; import io.netty.handler.codec.socks.SocksInitResponseDecoder.State;
import java.util.List;
/** /**
* Decodes {@link ByteBuf}s into {@link SocksInitResponse}. * Decodes {@link ByteBuf}s into {@link SocksInitResponse}.
* Before returning SocksResponse decoder removes itself from pipeline. * Before returning SocksResponse decoder removes itself from pipeline.
@ -33,18 +31,18 @@ public class SocksInitResponseDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
switch (state()) { switch (state()) {
case CHECK_PROTOCOL_VERSION: { case CHECK_PROTOCOL_VERSION: {
if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) { if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) {
out.add(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE); ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE);
break; break;
} }
checkpoint(State.READ_PREFERRED_AUTH_TYPE); checkpoint(State.READ_PREFERRED_AUTH_TYPE);
} }
case READ_PREFERRED_AUTH_TYPE: { case READ_PREFERRED_AUTH_TYPE: {
SocksAuthScheme authScheme = SocksAuthScheme.valueOf(byteBuf.readByte()); SocksAuthScheme authScheme = SocksAuthScheme.valueOf(byteBuf.readByte());
out.add(new SocksInitResponse(authScheme)); ctx.fireChannelRead(new SocksInitResponse(authScheme));
break; break;
} }
default: { default: {

View File

@ -30,8 +30,6 @@ import io.netty.handler.codec.socksx.v5.Socks5ServerEncoder;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.util.List;
/** /**
* Detects the version of the current SOCKS connection and initializes the pipeline with * Detects the version of the current SOCKS connection and initializes the pipeline with
* {@link Socks4ServerDecoder} or {@link Socks5InitialRequestDecoder}. * {@link Socks4ServerDecoder} or {@link Socks5InitialRequestDecoder}.
@ -61,7 +59,7 @@ public class SocksPortUnificationServerHandler extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
final int readerIndex = in.readerIndex(); final int readerIndex = in.readerIndex();
if (in.writerIndex() == readerIndex) { if (in.writerIndex() == readerIndex) {
return; return;

View File

@ -23,8 +23,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socksx.v4.Socks4ClientDecoder.State; import io.netty.handler.codec.socksx.v4.Socks4ClientDecoder.State;
import io.netty.util.NetUtil; import io.netty.util.NetUtil;
import java.util.List;
/** /**
* Decodes a single {@link Socks4CommandResponse} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks4CommandResponse} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -45,7 +43,7 @@ public class Socks4ClientDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case START: { case START: {
@ -58,13 +56,13 @@ public class Socks4ClientDecoder extends ReplayingDecoder<State> {
final int dstPort = in.readUnsignedShort(); final int dstPort = in.readUnsignedShort();
final String dstAddr = NetUtil.intToIpAddress(in.readInt()); final String dstAddr = NetUtil.intToIpAddress(in.readInt());
out.add(new DefaultSocks4CommandResponse(status, dstAddr, dstPort)); ctx.fireChannelRead(new DefaultSocks4CommandResponse(status, dstAddr, dstPort));
checkpoint(State.SUCCESS); checkpoint(State.SUCCESS);
} }
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -74,18 +72,18 @@ public class Socks4ClientDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
Socks4CommandResponse m = new DefaultSocks4CommandResponse(Socks4CommandStatus.REJECTED_OR_FAILED); Socks4CommandResponse m = new DefaultSocks4CommandResponse(Socks4CommandStatus.REJECTED_OR_FAILED);
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
checkpoint(State.FAILURE); checkpoint(State.FAILURE);
} }

View File

@ -25,8 +25,6 @@ import io.netty.handler.codec.socksx.v4.Socks4ServerDecoder.State;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import io.netty.util.NetUtil; import io.netty.util.NetUtil;
import java.util.List;
/** /**
* Decodes a single {@link Socks4CommandRequest} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks4CommandRequest} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -56,7 +54,7 @@ public class Socks4ServerDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case START: { case START: {
@ -79,13 +77,13 @@ public class Socks4ServerDecoder extends ReplayingDecoder<State> {
if (!"0.0.0.0".equals(dstAddr) && dstAddr.startsWith("0.0.0.")) { if (!"0.0.0.0".equals(dstAddr) && dstAddr.startsWith("0.0.0.")) {
dstAddr = readString("dstAddr", in); dstAddr = readString("dstAddr", in);
} }
out.add(new DefaultSocks4CommandRequest(type, dstAddr, dstPort, userId)); ctx.fireChannelRead(new DefaultSocks4CommandRequest(type, dstAddr, dstPort, userId));
checkpoint(State.SUCCESS); checkpoint(State.SUCCESS);
} }
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -95,11 +93,11 @@ public class Socks4ServerDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
@ -111,7 +109,7 @@ public class Socks4ServerDecoder extends ReplayingDecoder<State> {
userId != null? userId : ""); userId != null? userId : "");
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
checkpoint(State.FAILURE); checkpoint(State.FAILURE);
} }

View File

@ -26,8 +26,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socksx.SocksVersion; import io.netty.handler.codec.socksx.SocksVersion;
import io.netty.handler.codec.socksx.v5.Socks5CommandRequestDecoder.State; import io.netty.handler.codec.socksx.v5.Socks5CommandRequestDecoder.State;
import java.util.List;
/** /**
* Decodes a single {@link Socks5CommandRequest} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks5CommandRequest} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -56,7 +54,7 @@ public class Socks5CommandRequestDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case INIT: { case INIT: {
@ -72,13 +70,13 @@ public class Socks5CommandRequestDecoder extends ReplayingDecoder<State> {
final String dstAddr = addressDecoder.decodeAddress(dstAddrType, in); final String dstAddr = addressDecoder.decodeAddress(dstAddrType, in);
final int dstPort = in.readUnsignedShort(); final int dstPort = in.readUnsignedShort();
out.add(new DefaultSocks5CommandRequest(type, dstAddrType, dstAddr, dstPort)); ctx.fireChannelRead(new DefaultSocks5CommandRequest(type, dstAddrType, dstAddr, dstPort));
checkpoint(State.SUCCESS); checkpoint(State.SUCCESS);
} }
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -88,11 +86,11 @@ public class Socks5CommandRequestDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
@ -102,6 +100,6 @@ public class Socks5CommandRequestDecoder extends ReplayingDecoder<State> {
Socks5Message m = new DefaultSocks5CommandRequest( Socks5Message m = new DefaultSocks5CommandRequest(
Socks5CommandType.CONNECT, Socks5AddressType.IPv4, "0.0.0.0", 1); Socks5CommandType.CONNECT, Socks5AddressType.IPv4, "0.0.0.0", 1);
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
} }
} }

View File

@ -26,8 +26,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socksx.SocksVersion; import io.netty.handler.codec.socksx.SocksVersion;
import io.netty.handler.codec.socksx.v5.Socks5CommandResponseDecoder.State; import io.netty.handler.codec.socksx.v5.Socks5CommandResponseDecoder.State;
import java.util.List;
/** /**
* Decodes a single {@link Socks5CommandResponse} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks5CommandResponse} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -56,7 +54,7 @@ public class Socks5CommandResponseDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case INIT: { case INIT: {
@ -71,13 +69,13 @@ public class Socks5CommandResponseDecoder extends ReplayingDecoder<State> {
final String addr = addressDecoder.decodeAddress(addrType, in); final String addr = addressDecoder.decodeAddress(addrType, in);
final int port = in.readUnsignedShort(); final int port = in.readUnsignedShort();
out.add(new DefaultSocks5CommandResponse(status, addrType, addr, port)); ctx.fireChannelRead(new DefaultSocks5CommandResponse(status, addrType, addr, port));
checkpoint(State.SUCCESS); checkpoint(State.SUCCESS);
} }
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -87,11 +85,11 @@ public class Socks5CommandResponseDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
@ -101,6 +99,6 @@ public class Socks5CommandResponseDecoder extends ReplayingDecoder<State> {
Socks5Message m = new DefaultSocks5CommandResponse( Socks5Message m = new DefaultSocks5CommandResponse(
Socks5CommandStatus.FAILURE, Socks5AddressType.IPv4, null, 0); Socks5CommandStatus.FAILURE, Socks5AddressType.IPv4, null, 0);
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
} }
} }

View File

@ -24,8 +24,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socksx.SocksVersion; import io.netty.handler.codec.socksx.SocksVersion;
import io.netty.handler.codec.socksx.v5.Socks5InitialRequestDecoder.State; import io.netty.handler.codec.socksx.v5.Socks5InitialRequestDecoder.State;
import java.util.List;
/** /**
* Decodes a single {@link Socks5InitialRequest} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks5InitialRequest} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -45,7 +43,7 @@ public class Socks5InitialRequestDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case INIT: { case INIT: {
@ -62,13 +60,13 @@ public class Socks5InitialRequestDecoder extends ReplayingDecoder<State> {
authMethods[i] = Socks5AuthMethod.valueOf(in.readByte()); authMethods[i] = Socks5AuthMethod.valueOf(in.readByte());
} }
out.add(new DefaultSocks5InitialRequest(authMethods)); ctx.fireChannelRead(new DefaultSocks5InitialRequest(authMethods));
checkpoint(State.SUCCESS); checkpoint(State.SUCCESS);
} }
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -78,11 +76,11 @@ public class Socks5InitialRequestDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
@ -91,6 +89,6 @@ public class Socks5InitialRequestDecoder extends ReplayingDecoder<State> {
Socks5Message m = new DefaultSocks5InitialRequest(Socks5AuthMethod.NO_AUTH); Socks5Message m = new DefaultSocks5InitialRequest(Socks5AuthMethod.NO_AUTH);
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
} }
} }

View File

@ -24,8 +24,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socksx.SocksVersion; import io.netty.handler.codec.socksx.SocksVersion;
import io.netty.handler.codec.socksx.v5.Socks5InitialResponseDecoder.State; import io.netty.handler.codec.socksx.v5.Socks5InitialResponseDecoder.State;
import java.util.List;
/** /**
* Decodes a single {@link Socks5InitialResponse} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks5InitialResponse} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -45,7 +43,7 @@ public class Socks5InitialResponseDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case INIT: { case INIT: {
@ -56,13 +54,13 @@ public class Socks5InitialResponseDecoder extends ReplayingDecoder<State> {
} }
final Socks5AuthMethod authMethod = Socks5AuthMethod.valueOf(in.readByte()); final Socks5AuthMethod authMethod = Socks5AuthMethod.valueOf(in.readByte());
out.add(new DefaultSocks5InitialResponse(authMethod)); ctx.fireChannelRead(new DefaultSocks5InitialResponse(authMethod));
checkpoint(State.SUCCESS); checkpoint(State.SUCCESS);
} }
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -72,11 +70,11 @@ public class Socks5InitialResponseDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
@ -85,6 +83,6 @@ public class Socks5InitialResponseDecoder extends ReplayingDecoder<State> {
Socks5Message m = new DefaultSocks5InitialResponse(Socks5AuthMethod.UNACCEPTED); Socks5Message m = new DefaultSocks5InitialResponse(Socks5AuthMethod.UNACCEPTED);
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
} }
} }

View File

@ -24,8 +24,6 @@ import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socksx.v5.Socks5PasswordAuthRequestDecoder.State; import io.netty.handler.codec.socksx.v5.Socks5PasswordAuthRequestDecoder.State;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import java.util.List;
/** /**
* Decodes a single {@link Socks5PasswordAuthRequest} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks5PasswordAuthRequest} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -45,7 +43,7 @@ public class Socks5PasswordAuthRequestDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case INIT: { case INIT: {
@ -60,7 +58,7 @@ public class Socks5PasswordAuthRequestDecoder extends ReplayingDecoder<State> {
final int totalLength = usernameLength + passwordLength + 3; final int totalLength = usernameLength + passwordLength + 3;
in.skipBytes(totalLength); in.skipBytes(totalLength);
out.add(new DefaultSocks5PasswordAuthRequest( ctx.fireChannelRead(new DefaultSocks5PasswordAuthRequest(
in.toString(startOffset + 2, usernameLength, CharsetUtil.US_ASCII), in.toString(startOffset + 2, usernameLength, CharsetUtil.US_ASCII),
in.toString(startOffset + 3 + usernameLength, passwordLength, CharsetUtil.US_ASCII))); in.toString(startOffset + 3 + usernameLength, passwordLength, CharsetUtil.US_ASCII)));
@ -69,7 +67,7 @@ public class Socks5PasswordAuthRequestDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -79,11 +77,11 @@ public class Socks5PasswordAuthRequestDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
@ -92,6 +90,6 @@ public class Socks5PasswordAuthRequestDecoder extends ReplayingDecoder<State> {
Socks5Message m = new DefaultSocks5PasswordAuthRequest("", ""); Socks5Message m = new DefaultSocks5PasswordAuthRequest("", "");
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
} }
} }

View File

@ -23,8 +23,6 @@ import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.socksx.v5.Socks5PasswordAuthResponseDecoder.State; import io.netty.handler.codec.socksx.v5.Socks5PasswordAuthResponseDecoder.State;
import java.util.List;
/** /**
* Decodes a single {@link Socks5PasswordAuthResponse} from the inbound {@link ByteBuf}s. * Decodes a single {@link Socks5PasswordAuthResponse} from the inbound {@link ByteBuf}s.
* On successful decode, this decoder will forward the received data to the next handler, so that * On successful decode, this decoder will forward the received data to the next handler, so that
@ -44,7 +42,7 @@ public class Socks5PasswordAuthResponseDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (state()) { switch (state()) {
case INIT: { case INIT: {
@ -53,13 +51,14 @@ public class Socks5PasswordAuthResponseDecoder extends ReplayingDecoder<State> {
throw new DecoderException("unsupported subnegotiation version: " + version + " (expected: 1)"); throw new DecoderException("unsupported subnegotiation version: " + version + " (expected: 1)");
} }
out.add(new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.valueOf(in.readByte()))); ctx.fireChannelRead(
new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.valueOf(in.readByte())));
checkpoint(State.SUCCESS); checkpoint(State.SUCCESS);
} }
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readRetainedSlice(readableBytes)); ctx.fireChannelRead(in.readRetainedSlice(readableBytes));
} }
break; break;
} }
@ -69,11 +68,11 @@ public class Socks5PasswordAuthResponseDecoder extends ReplayingDecoder<State> {
} }
} }
} catch (Exception e) { } catch (Exception e) {
fail(out, e); fail(ctx, e);
} }
} }
private void fail(List<Object> out, Exception cause) { private void fail(ChannelHandlerContext ctx, Exception cause) {
if (!(cause instanceof DecoderException)) { if (!(cause instanceof DecoderException)) {
cause = new DecoderException(cause); cause = new DecoderException(cause);
} }
@ -82,6 +81,6 @@ public class Socks5PasswordAuthResponseDecoder extends ReplayingDecoder<State> {
Socks5Message m = new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.FAILURE); Socks5Message m = new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.FAILURE);
m.setDecoderResult(DecoderResult.failure(cause)); m.setDecoderResult(DecoderResult.failure(cause));
out.add(m); ctx.fireChannelRead(m);
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.stomp; package io.netty.handler.codec.stomp;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
@ -28,7 +29,6 @@ import io.netty.util.internal.AppendableCharSequence;
import io.netty.util.internal.ObjectUtil; import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import static io.netty.buffer.ByteBufUtil.*; import static io.netty.buffer.ByteBufUtil.*;
@ -94,7 +94,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
switch (state()) { switch (state()) {
case SKIP_CONTROL_CHARACTERS: case SKIP_CONTROL_CHARACTERS:
skipControlCharacters(in); skipControlCharacters(in);
@ -107,13 +107,13 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
command = readCommand(in); command = readCommand(in);
frame = new DefaultStompHeadersSubframe(command); frame = new DefaultStompHeadersSubframe(command);
checkpoint(readHeaders(in, frame.headers())); checkpoint(readHeaders(in, frame.headers()));
out.add(frame); ctx.fireChannelRead(frame);
} catch (Exception e) { } catch (Exception e) {
if (frame == null) { if (frame == null) {
frame = new DefaultStompHeadersSubframe(command); frame = new DefaultStompHeadersSubframe(command);
} }
frame.setDecoderResult(DecoderResult.failure(e)); frame.setDecoderResult(DecoderResult.failure(e));
out.add(frame); ctx.fireChannelRead(frame);
checkpoint(State.BAD_FRAME); checkpoint(State.BAD_FRAME);
return; return;
} }
@ -142,7 +142,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
lastContent = new DefaultLastStompContentSubframe(chunkBuffer); lastContent = new DefaultLastStompContentSubframe(chunkBuffer);
checkpoint(State.FINALIZE_FRAME_READ); checkpoint(State.FINALIZE_FRAME_READ);
} else { } else {
out.add(new DefaultStompContentSubframe(chunkBuffer)); ctx.fireChannelRead(new DefaultStompContentSubframe(chunkBuffer));
return; return;
} }
} else { } else {
@ -161,7 +161,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
lastContent = new DefaultLastStompContentSubframe(chunkBuffer); lastContent = new DefaultLastStompContentSubframe(chunkBuffer);
checkpoint(State.FINALIZE_FRAME_READ); checkpoint(State.FINALIZE_FRAME_READ);
} else { } else {
out.add(new DefaultStompContentSubframe(chunkBuffer)); ctx.fireChannelRead(new DefaultStompContentSubframe(chunkBuffer));
return; return;
} }
} }
@ -172,13 +172,13 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
if (lastContent == null) { if (lastContent == null) {
lastContent = LastStompContentSubframe.EMPTY_LAST_CONTENT; lastContent = LastStompContentSubframe.EMPTY_LAST_CONTENT;
} }
out.add(lastContent); ctx.fireChannelRead(lastContent);
resetDecoder(); resetDecoder();
} }
} catch (Exception e) { } catch (Exception e) {
StompContentSubframe errorContent = new DefaultLastStompContentSubframe(Unpooled.EMPTY_BUFFER); StompContentSubframe errorContent = new DefaultLastStompContentSubframe(Unpooled.EMPTY_BUFFER);
errorContent.setDecoderResult(DecoderResult.failure(e)); errorContent.setDecoderResult(DecoderResult.failure(e));
out.add(errorContent); ctx.fireChannelRead(errorContent);
checkpoint(State.BAD_FRAME); checkpoint(State.BAD_FRAME);
} }
} }

View File

@ -25,7 +25,6 @@ import io.netty.handler.codec.ByteToMessageDecoder;
import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import java.util.List;
/** /**
* Async XML decoder based on <a href="https://github.com/FasterXML/aalto-xml">Aalto XML parser</a>. * Async XML decoder based on <a href="https://github.com/FasterXML/aalto-xml">Aalto XML parser</a>.
@ -42,7 +41,7 @@ public class XmlDecoder extends ByteToMessageDecoder {
private final AsyncByteArrayFeeder streamFeeder = streamReader.getInputFeeder(); private final AsyncByteArrayFeeder streamFeeder = streamReader.getInputFeeder();
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
byte[] buffer = new byte[in.readableBytes()]; byte[] buffer = new byte[in.readableBytes()];
in.readBytes(buffer); in.readBytes(buffer);
try { try {
@ -56,11 +55,11 @@ public class XmlDecoder extends ByteToMessageDecoder {
int type = streamReader.next(); int type = streamReader.next();
switch (type) { switch (type) {
case XMLStreamConstants.START_DOCUMENT: case XMLStreamConstants.START_DOCUMENT:
out.add(new XmlDocumentStart(streamReader.getEncoding(), streamReader.getVersion(), ctx.fireChannelRead(new XmlDocumentStart(streamReader.getEncoding(), streamReader.getVersion(),
streamReader.isStandalone(), streamReader.getCharacterEncodingScheme())); streamReader.isStandalone(), streamReader.getCharacterEncodingScheme()));
break; break;
case XMLStreamConstants.END_DOCUMENT: case XMLStreamConstants.END_DOCUMENT:
out.add(XML_DOCUMENT_END); ctx.fireChannelRead(XML_DOCUMENT_END);
break; break;
case XMLStreamConstants.START_ELEMENT: case XMLStreamConstants.START_ELEMENT:
XmlElementStart elementStart = new XmlElementStart(streamReader.getLocalName(), XmlElementStart elementStart = new XmlElementStart(streamReader.getLocalName(),
@ -76,7 +75,7 @@ public class XmlDecoder extends ByteToMessageDecoder {
streamReader.getNamespaceURI(x)); streamReader.getNamespaceURI(x));
elementStart.namespaces().add(namespace); elementStart.namespaces().add(namespace);
} }
out.add(elementStart); ctx.fireChannelRead(elementStart);
break; break;
case XMLStreamConstants.END_ELEMENT: case XMLStreamConstants.END_ELEMENT:
XmlElementEnd elementEnd = new XmlElementEnd(streamReader.getLocalName(), XmlElementEnd elementEnd = new XmlElementEnd(streamReader.getLocalName(),
@ -86,28 +85,29 @@ public class XmlDecoder extends ByteToMessageDecoder {
streamReader.getNamespaceURI(x)); streamReader.getNamespaceURI(x));
elementEnd.namespaces().add(namespace); elementEnd.namespaces().add(namespace);
} }
out.add(elementEnd); ctx.fireChannelRead(elementEnd);
break; break;
case XMLStreamConstants.PROCESSING_INSTRUCTION: case XMLStreamConstants.PROCESSING_INSTRUCTION:
out.add(new XmlProcessingInstruction(streamReader.getPIData(), streamReader.getPITarget())); ctx.fireChannelRead(
new XmlProcessingInstruction(streamReader.getPIData(), streamReader.getPITarget()));
break; break;
case XMLStreamConstants.CHARACTERS: case XMLStreamConstants.CHARACTERS:
out.add(new XmlCharacters(streamReader.getText())); ctx.fireChannelRead(new XmlCharacters(streamReader.getText()));
break; break;
case XMLStreamConstants.COMMENT: case XMLStreamConstants.COMMENT:
out.add(new XmlComment(streamReader.getText())); ctx.fireChannelRead(new XmlComment(streamReader.getText()));
break; break;
case XMLStreamConstants.SPACE: case XMLStreamConstants.SPACE:
out.add(new XmlSpace(streamReader.getText())); ctx.fireChannelRead(new XmlSpace(streamReader.getText()));
break; break;
case XMLStreamConstants.ENTITY_REFERENCE: case XMLStreamConstants.ENTITY_REFERENCE:
out.add(new XmlEntityReference(streamReader.getLocalName(), streamReader.getText())); ctx.fireChannelRead(new XmlEntityReference(streamReader.getLocalName(), streamReader.getText()));
break; break;
case XMLStreamConstants.DTD: case XMLStreamConstants.DTD:
out.add(new XmlDTD(streamReader.getText())); ctx.fireChannelRead(new XmlDTD(streamReader.getText()));
break; break;
case XMLStreamConstants.CDATA: case XMLStreamConstants.CDATA:
out.add(new XmlCdata(streamReader.getText())); ctx.fireChannelRead(new XmlCdata(streamReader.getText()));
break; break;
} }
} }

View File

@ -21,8 +21,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.util.internal.TypeParameterMatcher; import io.netty.util.internal.TypeParameterMatcher;
import java.util.List;
/** /**
* A Codec for on-the-fly encoding/decoding of bytes to messages and vise-versa. * A Codec for on-the-fly encoding/decoding of bytes to messages and vise-versa.
* *
@ -38,13 +36,13 @@ public abstract class ByteToMessageCodec<I> extends ChannelHandlerAdapter {
private final ByteToMessageDecoder decoder = new ByteToMessageDecoder() { private final ByteToMessageDecoder decoder = new ByteToMessageDecoder() {
@Override @Override
public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { public void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteToMessageCodec.this.decode(ctx, in, out); ByteToMessageCodec.this.decode(ctx, in);
} }
@Override @Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteToMessageCodec.this.decodeLast(ctx, in, out); ByteToMessageCodec.this.decodeLast(ctx, in);
} }
}; };
@ -142,18 +140,18 @@ public abstract class ByteToMessageCodec<I> extends ChannelHandlerAdapter {
protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception; protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;
/** /**
* @see ByteToMessageDecoder#decode(ChannelHandlerContext, ByteBuf, List) * @see ByteToMessageDecoder#decode(ChannelHandlerContext, ByteBuf)
*/ */
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception; protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception;
/** /**
* @see ByteToMessageDecoder#decodeLast(ChannelHandlerContext, ByteBuf, List) * @see ByteToMessageDecoder#decodeLast(ChannelHandlerContext, ByteBuf)
*/ */
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.isReadable()) { if (in.isReadable()) {
// Only call decode() if there is something left in the buffer to decode. // Only call decode() if there is something left in the buffer to decode.
// See https://github.com/netty/netty/issues/4386 // See https://github.com/netty/netty/issues/4386
decode(ctx, in, out); decode(ctx, in);
} }
} }

View File

@ -26,10 +26,18 @@ import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelProgressivePromise;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.ChannelInputShutdownEvent; import io.netty.channel.socket.ChannelInputShutdownEvent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import java.util.List; import java.net.SocketAddress;
import static java.lang.Integer.MAX_VALUE; import static java.lang.Integer.MAX_VALUE;
@ -38,14 +46,15 @@ import static java.lang.Integer.MAX_VALUE;
* other Message type. * other Message type.
* *
* For example here is an implementation which reads all readable bytes from * For example here is an implementation which reads all readable bytes from
* the input {@link ByteBuf} and create a new {@link ByteBuf}. * the input {@link ByteBuf}, creates a new {@link ByteBuf} and forward it to the next {@link ChannelHandler}
* in the {@link ChannelPipeline}.
* *
* <pre> * <pre>
* public class SquareDecoder extends {@link ByteToMessageDecoder} { * public class SquareDecoder extends {@link ByteToMessageDecoder} {
* {@code @Override} * {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, List&lt;Object&gt; out) * public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in)
* throws {@link Exception} { * throws {@link Exception} {
* out.add(in.readBytes(in.readableBytes())); * ctx.fireChannelRead(in.readBytes(in.readableBytes()));
* } * }
* } * }
* </pre> * </pre>
@ -71,8 +80,9 @@ import static java.lang.Integer.MAX_VALUE;
* annotated with {@link @Sharable}. * annotated with {@link @Sharable}.
* <p> * <p>
* Some methods such as {@link ByteBuf#readBytes(int)} will cause a memory leak if the returned buffer * Some methods such as {@link ByteBuf#readBytes(int)} will cause a memory leak if the returned buffer
* is not released or added to the <tt>out</tt> {@link List}. Use derived buffers like {@link ByteBuf#readSlice(int)} * is not released or fired through the {@link ChannelPipeline} via
* to avoid leaking memory. * {@link ChannelHandlerContext#fireChannelRead(Object)}. Use derived buffers like {@link ByteBuf#readSlice(int)} to
* avoid leaking memory.
*/ */
public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter { public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
@ -161,6 +171,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
private byte decodeState = STATE_INIT; private byte decodeState = STATE_INIT;
private int discardAfterReads = 16; private int discardAfterReads = 16;
private int numReads; private int numReads;
private ByteToMessageDecoderContext context;
protected ByteToMessageDecoder() { protected ByteToMessageDecoder() {
ensureNotSharable(); ensureNotSharable();
@ -226,6 +237,15 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
} }
} }
@Override
public final void handlerAdded(ChannelHandlerContext ctx) throws Exception {
this.context = new ByteToMessageDecoderContext(ctx);
handlerAdded0(this.context);
}
protected void handlerAdded0(ChannelHandlerContext ctx) throws Exception {
}
@Override @Override
public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception { public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
if (decodeState == STATE_CALLING_CHILD_DECODE) { if (decodeState == STATE_CALLING_CHILD_DECODE) {
@ -245,7 +265,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
buf.release(); buf.release();
} }
} }
handlerRemoved0(ctx); handlerRemoved0(this.context);
} }
/** /**
@ -257,7 +277,6 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof ByteBuf) { if (msg instanceof ByteBuf) {
CodecOutputList out = CodecOutputList.newInstance();
try { try {
ByteBuf data = (ByteBuf) msg; ByteBuf data = (ByteBuf) msg;
first = cumulation == null; first = cumulation == null;
@ -266,7 +285,9 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
} else { } else {
cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data); cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
} }
callDecode(ctx, cumulation, out); assert context.ctx == ctx || ctx == context;
callDecode(context, cumulation);
} catch (DecoderException e) { } catch (DecoderException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -283,38 +304,14 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
discardSomeReadBytes(); discardSomeReadBytes();
} }
int size = out.size(); firedChannelRead |= context.fireChannelReadCallCount() > 0;
firedChannelRead |= out.insertSinceRecycled(); context.reset();
fireChannelRead(ctx, out, size);
out.recycle();
} }
} else { } else {
ctx.fireChannelRead(msg); ctx.fireChannelRead(msg);
} }
} }
/**
* Get {@code numElements} out of the {@link List} and forward these through the pipeline.
*/
static void fireChannelRead(ChannelHandlerContext ctx, List<Object> msgs, int numElements) {
if (msgs instanceof CodecOutputList) {
fireChannelRead(ctx, (CodecOutputList) msgs, numElements);
} else {
for (int i = 0; i < numElements; i++) {
ctx.fireChannelRead(msgs.get(i));
}
}
}
/**
* Get {@code numElements} out of the {@link CodecOutputList} and forward these through the pipeline.
*/
static void fireChannelRead(ChannelHandlerContext ctx, CodecOutputList msgs, int numElements) {
for (int i = 0; i < numElements; i ++) {
ctx.fireChannelRead(msgs.getUnsafe(i));
}
}
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
numReads = 0; numReads = 0;
@ -341,7 +338,8 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) throws Exception {
channelInputClosed(ctx, true); assert context.ctx == ctx || ctx == context;
channelInputClosed(context, true);
} }
@Override @Override
@ -350,38 +348,32 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
// The decodeLast method is invoked when a channelInactive event is encountered. // The decodeLast method is invoked when a channelInactive event is encountered.
// This method is responsible for ending requests in some situations and must be called // This method is responsible for ending requests in some situations and must be called
// when the input has been shutdown. // when the input has been shutdown.
channelInputClosed(ctx, false); assert context.ctx == ctx || ctx == context;
channelInputClosed(context, false);
} }
ctx.fireUserEventTriggered(evt); ctx.fireUserEventTriggered(evt);
} }
private void channelInputClosed(ChannelHandlerContext ctx, boolean callChannelInactive) { private void channelInputClosed(ByteToMessageDecoderContext ctx, boolean callChannelInactive) {
CodecOutputList out = CodecOutputList.newInstance();
try { try {
channelInputClosed(ctx, out); channelInputClosed(ctx);
} catch (DecoderException e) { } catch (DecoderException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
throw new DecoderException(e); throw new DecoderException(e);
} finally { } finally {
try {
if (cumulation != null) { if (cumulation != null) {
cumulation.release(); cumulation.release();
cumulation = null; cumulation = null;
} }
int size = out.size(); if (ctx.fireChannelReadCallCount() > 0) {
fireChannelRead(ctx, out, size); ctx.reset();
if (size > 0) {
// Something was read, call fireChannelReadComplete() // Something was read, call fireChannelReadComplete()
ctx.fireChannelReadComplete(); ctx.fireChannelReadComplete();
} }
if (callChannelInactive) { if (callChannelInactive) {
ctx.fireChannelInactive(); ctx.fireChannelInactive();
} }
} finally {
// Recycle in all cases
out.recycle();
}
} }
} }
@ -389,45 +381,29 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
* Called when the input of the channel was closed which may be because it changed to inactive or because of * Called when the input of the channel was closed which may be because it changed to inactive or because of
* {@link ChannelInputShutdownEvent}. * {@link ChannelInputShutdownEvent}.
*/ */
void channelInputClosed(ChannelHandlerContext ctx, List<Object> out) throws Exception { void channelInputClosed(ByteToMessageDecoderContext ctx) throws Exception {
if (cumulation != null) { if (cumulation != null) {
callDecode(ctx, cumulation, out); callDecode(ctx, cumulation);
decodeLast(ctx, cumulation, out); decodeLast(ctx, cumulation);
} else { } else {
decodeLast(ctx, Unpooled.EMPTY_BUFFER, out); decodeLast(ctx, Unpooled.EMPTY_BUFFER);
} }
} }
/** /**
* Called once data should be decoded from the given {@link ByteBuf}. This method will call * Called once data should be decoded from the given {@link ByteBuf}. This method will call
* {@link #decode(ChannelHandlerContext, ByteBuf, List)} as long as decoding should take place. * {@link #decode(ChannelHandlerContext, ByteBuf)} as long as decoding should take place.
* *
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data * @param in the {@link ByteBuf} from which to read data
* @param out the {@link List} to which decoded messages should be added
*/ */
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { void callDecode(ByteToMessageDecoderContext ctx, ByteBuf in) {
try { try {
while (in.isReadable()) { while (in.isReadable() && !ctx.isRemoved()) {
int outSize = out.size();
if (outSize > 0) {
fireChannelRead(ctx, out, outSize);
out.clear();
// Check if this handler was removed before continuing with decoding.
// If it was removed, it is not safe to continue to operate on the buffer.
//
// See:
// - https://github.com/netty/netty/issues/4635
if (ctx.isRemoved()) {
break;
}
outSize = 0;
}
int oldInputLength = in.readableBytes(); int oldInputLength = in.readableBytes();
decodeRemovalReentryProtection(ctx, in, out); int numReadCalled = ctx.fireChannelReadCallCount();
decodeRemovalReentryProtection(ctx, in);
// Check if this handler was removed before continuing the loop. // Check if this handler was removed before continuing the loop.
// If it was removed, it is not safe to continue to operate on the buffer. // If it was removed, it is not safe to continue to operate on the buffer.
@ -437,7 +413,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
break; break;
} }
if (outSize == out.size()) { if (numReadCalled == ctx.fireChannelReadCallCount()) {
if (oldInputLength == in.readableBytes()) { if (oldInputLength == in.readableBytes()) {
break; break;
} else { } else {
@ -469,10 +445,9 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
* *
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data * @param in the {@link ByteBuf} from which to read data
* @param out the {@link List} to which decoded messages should be added
* @throws Exception is thrown if an error occurs * @throws Exception is thrown if an error occurs
*/ */
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception; protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception;
/** /**
* Decode the from one {@link ByteBuf} to an other. This method will be called till either the input * Decode the from one {@link ByteBuf} to an other. This method will be called till either the input
@ -481,20 +456,17 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
* *
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data * @param in the {@link ByteBuf} from which to read data
* @param out the {@link List} to which decoded messages should be added
* @throws Exception is thrown if an error occurs * @throws Exception is thrown if an error occurs
*/ */
final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in)
throws Exception { throws Exception {
decodeState = STATE_CALLING_CHILD_DECODE; decodeState = STATE_CALLING_CHILD_DECODE;
try { try {
decode(ctx, in, out); decode(ctx, in);
} finally { } finally {
boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING; boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING;
decodeState = STATE_INIT; decodeState = STATE_INIT;
if (removePending) { if (removePending) {
fireChannelRead(ctx, out, out.size());
out.clear();
handlerRemoved(ctx); handlerRemoved(ctx);
} }
} }
@ -504,14 +476,14 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
* Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the * Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the
* {@link #channelInactive(ChannelHandlerContext)} was triggered. * {@link #channelInactive(ChannelHandlerContext)} was triggered.
* *
* By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, List)} but sub-classes may * By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf)} but sub-classes may
* override this for some special cleanup operation. * override this for some special cleanup operation.
*/ */
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.isReadable()) { if (in.isReadable()) {
// Only call decode() if there is something left in the buffer to decode. // Only call decode() if there is something left in the buffer to decode.
// See https://github.com/netty/netty/issues/4386 // See https://github.com/netty/netty/issues/4386
decodeRemovalReentryProtection(ctx, in, out); decodeRemovalReentryProtection(ctx, in);
} }
} }
@ -540,4 +512,251 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
*/ */
ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in); ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in);
} }
// Package private so we can also make use of it in ReplayingDecoder.
static final class ByteToMessageDecoderContext implements ChannelHandlerContext {
private final ChannelHandlerContext ctx;
private int fireChannelReadCalled;
private ByteToMessageDecoderContext(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
void reset() {
fireChannelReadCalled = 0;
}
int fireChannelReadCallCount() {
return fireChannelReadCalled;
}
@Override
public Channel channel() {
return ctx.channel();
}
@Override
public EventExecutor executor() {
return ctx.executor();
}
@Override
public String name() {
return ctx.name();
}
@Override
public ChannelHandler handler() {
return ctx.handler();
}
@Override
public boolean isRemoved() {
return ctx.isRemoved();
}
@Override
public ChannelHandlerContext fireChannelRegistered() {
ctx.fireChannelRegistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelUnregistered() {
ctx.fireChannelUnregistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelActive() {
ctx.fireChannelActive();
return this;
}
@Override
public ChannelHandlerContext fireChannelInactive() {
ctx.fireChannelInactive();
return this;
}
@Override
public ChannelHandlerContext fireExceptionCaught(Throwable cause) {
ctx.fireExceptionCaught(cause);
return this;
}
@Override
public ChannelHandlerContext fireUserEventTriggered(Object evt) {
ctx.fireUserEventTriggered(evt);
return this;
}
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
fireChannelReadCalled ++;
ctx.fireChannelRead(msg);
return this;
}
@Override
public ChannelHandlerContext fireChannelReadComplete() {
ctx.fireChannelReadComplete();
return this;
}
@Override
public ChannelHandlerContext fireChannelWritabilityChanged() {
ctx.fireChannelWritabilityChanged();
return this;
}
@Override
public ChannelHandlerContext read() {
ctx.read();
return this;
}
@Override
public ChannelHandlerContext flush() {
ctx.flush();
return this;
}
@Override
public ChannelPipeline pipeline() {
return ctx.pipeline();
}
@Override
public ByteBufAllocator alloc() {
return ctx.alloc();
}
@Override
@Deprecated
public <T> Attribute<T> attr(AttributeKey<T> key) {
return ctx.attr(key);
}
@Override
@Deprecated
public <T> boolean hasAttr(AttributeKey<T> key) {
return ctx.hasAttr(key);
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
return ctx.bind(localAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
return ctx.connect(remoteAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return ctx.connect(remoteAddress, localAddress);
}
@Override
public ChannelFuture disconnect() {
return ctx.disconnect();
}
@Override
public ChannelFuture close() {
return ctx.close();
}
@Override
public ChannelFuture deregister() {
return ctx.deregister();
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return ctx.bind(localAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return ctx.connect(remoteAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
return ctx.connect(remoteAddress, localAddress, promise);
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
return ctx.disconnect(promise);
}
@Override
public ChannelFuture close(ChannelPromise promise) {
return ctx.close(promise);
}
@Override
public ChannelFuture register() {
return ctx.register();
}
@Override
public ChannelFuture register(ChannelPromise promise) {
return ctx.register(promise);
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
return ctx.deregister(promise);
}
@Override
public ChannelFuture write(Object msg) {
return ctx.write(msg);
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
return ctx.write(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
return ctx.writeAndFlush(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
return ctx.writeAndFlush(msg);
}
@Override
public ChannelPromise newPromise() {
return ctx.newPromise();
}
@Override
public ChannelProgressivePromise newProgressivePromise() {
return ctx.newProgressivePromise();
}
@Override
public ChannelFuture newSucceededFuture() {
return ctx.newSucceededFuture();
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
return ctx.newFailedFuture(cause);
}
@Override
public ChannelPromise voidPromise() {
return ctx.voidPromise();
}
}
} }

View File

@ -56,8 +56,8 @@ public class DatagramPacketDecoder extends MessageToMessageDecoder<DatagramPacke
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
decoder.decode(ctx, msg.content(), out); decoder.decode(ctx, msg.content());
} }
@Override @Override

View File

@ -21,8 +21,6 @@ import static java.util.Objects.requireNonNull;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.List;
/** /**
* A decoder that splits the received {@link ByteBuf}s by one or more * A decoder that splits the received {@link ByteBuf}s by one or more
* delimiters. It is particularly useful for decoding the frames which ends * delimiters. It is particularly useful for decoding the frames which ends
@ -213,10 +211,10 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected final void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
Object decoded = decode(ctx, in); Object decoded = decode0(ctx, in);
if (decoded != null) { if (decoded != null) {
out.add(decoded); ctx.fireChannelRead(decoded);
} }
} }
@ -228,9 +226,9 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
* @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could * @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could
* be created. * be created.
*/ */
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { protected Object decode0(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
if (lineBasedDecoder != null) { if (lineBasedDecoder != null) {
return lineBasedDecoder.decode(ctx, buffer); return lineBasedDecoder.decode0(ctx, buffer);
} }
// Try all delimiters and choose the delimiter which yields the shortest frame. // Try all delimiters and choose the delimiter which yields the shortest frame.
int minFrameLength = Integer.MAX_VALUE; int minFrameLength = Integer.MAX_VALUE;

View File

@ -20,8 +20,6 @@ import static io.netty.util.internal.ObjectUtil.checkPositive;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.List;
/** /**
* A decoder that splits the received {@link ByteBuf}s by the fixed number * A decoder that splits the received {@link ByteBuf}s by the fixed number
* of bytes. For example, if you received the following four fragmented packets: * of bytes. For example, if you received the following four fragmented packets:
@ -53,10 +51,10 @@ public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected final void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
Object decoded = decode(ctx, in); Object decoded = decode0(ctx, in);
if (decoded != null) { if (decoded != null) {
out.add(decoded); ctx.fireChannelRead(decoded);
} }
} }
@ -68,7 +66,7 @@ public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
* @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could * @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could
* be created. * be created.
*/ */
protected Object decode( protected Object decode0(
@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception { @SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < frameLength) { if (in.readableBytes() < frameLength) {
return null; return null;

View File

@ -20,7 +20,6 @@ import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.List;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
@ -329,10 +328,10 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected final void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
Object decoded = decode(ctx, in); Object decoded = decode0(ctx, in);
if (decoded != null) { if (decoded != null) {
out.add(decoded); ctx.fireChannelRead(decoded);
} }
} }
@ -394,7 +393,7 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
* @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could * @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could
* be created. * be created.
*/ */
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { protected Object decode0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (discardingTooLongFrame) { if (discardingTooLongFrame) {
discardingTooLongFrame(in); discardingTooLongFrame(in);
} }

View File

@ -19,8 +19,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ByteProcessor; import io.netty.util.ByteProcessor;
import java.util.List;
/** /**
* A decoder that splits the received {@link ByteBuf}s on line endings. * A decoder that splits the received {@link ByteBuf}s on line endings.
* <p> * <p>
@ -80,10 +78,10 @@ public class LineBasedFrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected final void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
Object decoded = decode(ctx, in); Object decoded = decode0(ctx, in);
if (decoded != null) { if (decoded != null) {
out.add(decoded); ctx.fireChannelRead(decoded);
} }
} }
@ -95,7 +93,7 @@ public class LineBasedFrameDecoder extends ByteToMessageDecoder {
* @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could * @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could
* be created. * be created.
*/ */
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { protected Object decode0(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
final int eol = findEndOfLine(buffer); final int eol = findEndOfLine(buffer);
if (!discarding) { if (!discarding) {
if (eol >= 0) { if (eol >= 0) {

View File

@ -25,8 +25,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import java.util.List;
import static io.netty.buffer.Unpooled.EMPTY_BUFFER; import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero; import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
@ -205,9 +203,8 @@ public abstract class MessageAggregator<I, S, C extends ByteBufHolder, O extends
} }
@Override @Override
protected void decode(final ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception { protected void decode(final ChannelHandlerContext ctx, I msg) throws Exception {
assert aggregating; assert aggregating;
if (isStartMessage(msg)) { if (isStartMessage(msg)) {
handlingOversizedMessage = false; handlingOversizedMessage = false;
if (currentMessage != null) { if (currentMessage != null) {
@ -259,8 +256,8 @@ public abstract class MessageAggregator<I, S, C extends ByteBufHolder, O extends
} else { } else {
aggregated = beginAggregation(m, EMPTY_BUFFER); aggregated = beginAggregation(m, EMPTY_BUFFER);
} }
finishAggregation0(aggregated); finishAggregation(aggregated);
out.add(aggregated); ctx.fireChannelRead(aggregated);
return; return;
} }
@ -317,8 +314,9 @@ public abstract class MessageAggregator<I, S, C extends ByteBufHolder, O extends
finishAggregation0(currentMessage); finishAggregation0(currentMessage);
// All done // All done
out.add(currentMessage); O message = currentMessage;
currentMessage = null; currentMessage = null;
ctx.fireChannelRead(message);
} }
} else { } else {
throw new MessageAggregationException(); throw new MessageAggregationException();

View File

@ -77,8 +77,8 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN> extends Cha
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void decode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, Object msg) throws Exception {
MessageToMessageCodec.this.decode(ctx, (INBOUND_IN) msg, out); MessageToMessageCodec.this.decode(ctx, (INBOUND_IN) msg);
} }
}; };
@ -141,8 +141,8 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN> extends Cha
throws Exception; throws Exception;
/** /**
* @see MessageToMessageDecoder#decode(ChannelHandlerContext, Object, List) * @see MessageToMessageDecoder#decode(ChannelHandlerContext, Object)
*/ */
protected abstract void decode(ChannelHandlerContext ctx, INBOUND_IN msg, List<Object> out) protected abstract void decode(ChannelHandlerContext ctx, INBOUND_IN msg)
throws Exception; throws Exception;
} }

View File

@ -79,29 +79,22 @@ public abstract class MessageToMessageDecoder<I> extends ChannelHandlerAdapter i
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
CodecOutputList out = CodecOutputList.newInstance();
try { try {
if (acceptInboundMessage(msg)) { if (acceptInboundMessage(msg)) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
I cast = (I) msg; I cast = (I) msg;
try { try {
decode(ctx, cast, out); decode(ctx, cast);
} finally { } finally {
ReferenceCountUtil.release(cast); ReferenceCountUtil.release(cast);
} }
} else { } else {
out.add(msg); ctx.fireChannelRead(msg);
} }
} catch (DecoderException e) { } catch (DecoderException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
throw new DecoderException(e); throw new DecoderException(e);
} finally {
int size = out.size();
for (int i = 0; i < size; i ++) {
ctx.fireChannelRead(out.getUnsafe(i));
}
out.recycle();
} }
} }
@ -111,8 +104,7 @@ public abstract class MessageToMessageDecoder<I> extends ChannelHandlerAdapter i
* *
* @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageDecoder} belongs to * @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageDecoder} belongs to
* @param msg the message to decode to an other one * @param msg the message to decode to an other one
* @param out the {@link List} to which decoded messages should be added
* @throws Exception is thrown if an error occurs * @throws Exception is thrown if an error occurs
*/ */
protected abstract void decode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception; protected abstract void decode(ChannelHandlerContext ctx, I msg) throws Exception;
} }

View File

@ -23,8 +23,6 @@ import io.netty.channel.ChannelPipeline;
import io.netty.util.Signal; import io.netty.util.Signal;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import java.util.List;
/** /**
* A specialized variation of {@link ByteToMessageDecoder} which enables implementation * A specialized variation of {@link ByteToMessageDecoder} which enables implementation
* of a non-blocking decoder in the blocking I/O paradigm. * of a non-blocking decoder in the blocking I/O paradigm.
@ -39,8 +37,7 @@ import java.util.List;
* public class IntegerHeaderFrameDecoder extends {@link ByteToMessageDecoder} { * public class IntegerHeaderFrameDecoder extends {@link ByteToMessageDecoder} {
* *
* {@code @Override} * {@code @Override}
* protected void decode({@link ChannelHandlerContext} ctx, * protected void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} buf) throws Exception {
* {@link ByteBuf} buf, List&lt;Object&gt; out) throws Exception {
* *
* if (buf.readableBytes() &lt; 4) { * if (buf.readableBytes() &lt; 4) {
* return; * return;
@ -54,7 +51,7 @@ import java.util.List;
* return; * return;
* } * }
* *
* out.add(buf.readBytes(length)); * ctx.fireChannelRead(buf.readBytes(length));
* } * }
* } * }
* </pre> * </pre>
@ -108,7 +105,7 @@ import java.util.List;
* private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;(); * private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;();
* *
* {@code @Override} * {@code @Override}
* public void decode(.., {@link ByteBuf} buf, List&lt;Object&gt; out) throws Exception { * public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} buf) throws Exception {
* *
* // A message contains 2 integers. * // A message contains 2 integers.
* values.offer(buf.readInt()); * values.offer(buf.readInt());
@ -117,7 +114,7 @@ import java.util.List;
* // This assertion will fail intermittently since values.offer() * // This assertion will fail intermittently since values.offer()
* // can be called more than two times! * // can be called more than two times!
* assert values.size() == 2; * assert values.size() == 2;
* out.add(values.poll() + values.poll()); * ctx.fireChannelRead(values.poll() + values.poll());
* } * }
* }</pre> * }</pre>
* The correct implementation looks like the following, and you can also * The correct implementation looks like the following, and you can also
@ -128,7 +125,7 @@ import java.util.List;
* private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;(); * private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;();
* *
* {@code @Override} * {@code @Override}
* public void decode(.., {@link ByteBuf} buf, List&lt;Object&gt; out) throws Exception { * public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} buf) throws Exception {
* *
* // Revert the state of the variable that might have been changed * // Revert the state of the variable that might have been changed
* // since the last partial decode. * // since the last partial decode.
@ -140,7 +137,7 @@ import java.util.List;
* *
* // Now we know this assertion will never fail. * // Now we know this assertion will never fail.
* assert values.size() == 2; * assert values.size() == 2;
* out.add(values.poll() + values.poll()); * ctx.fireChannelRead(values.poll() + values.poll());
* } * }
* }</pre> * }</pre>
* </li> * </li>
@ -180,8 +177,7 @@ import java.util.List;
* } * }
* *
* {@code @Override} * {@code @Override}
* protected void decode({@link ChannelHandlerContext} ctx, * protected void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} buf) throws Exception {
* {@link ByteBuf} buf, List&lt;Object&gt; out) throws Exception {
* switch (state()) { * switch (state()) {
* case READ_LENGTH: * case READ_LENGTH:
* length = buf.readInt(); * length = buf.readInt();
@ -189,7 +185,7 @@ import java.util.List;
* case READ_CONTENT: * case READ_CONTENT:
* ByteBuf frame = buf.readBytes(length); * ByteBuf frame = buf.readBytes(length);
* <strong>checkpoint(MyDecoderState.READ_LENGTH);</strong> * <strong>checkpoint(MyDecoderState.READ_LENGTH);</strong>
* out.add(frame); * ctx.fireChannelRead(frame);
* break; * break;
* default: * default:
* throw new Error("Shouldn't reach here."); * throw new Error("Shouldn't reach here.");
@ -209,8 +205,7 @@ import java.util.List;
* private int length; * private int length;
* *
* {@code @Override} * {@code @Override}
* protected void decode({@link ChannelHandlerContext} ctx, * protected void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} buf) throws Exception {
* {@link ByteBuf} buf, List&lt;Object&gt; out) throws Exception {
* if (!readLength) { * if (!readLength) {
* length = buf.readInt(); * length = buf.readInt();
* <strong>readLength = true;</strong> * <strong>readLength = true;</strong>
@ -221,7 +216,7 @@ import java.util.List;
* ByteBuf frame = buf.readBytes(length); * ByteBuf frame = buf.readBytes(length);
* <strong>readLength = false;</strong> * <strong>readLength = false;</strong>
* <strong>checkpoint();</strong> * <strong>checkpoint();</strong>
* out.add(frame); * ctx.fireChannelRead(frame);
* } * }
* } * }
* } * }
@ -240,8 +235,7 @@ import java.util.List;
* public class FirstDecoder extends {@link ReplayingDecoder}&lt;{@link Void}&gt; { * public class FirstDecoder extends {@link ReplayingDecoder}&lt;{@link Void}&gt; {
* *
* {@code @Override} * {@code @Override}
* protected void decode({@link ChannelHandlerContext} ctx, * protected void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} buf) {
* {@link ByteBuf} buf, List&lt;Object&gt; out) {
* ... * ...
* // Decode the first message * // Decode the first message
* Object firstMessage = ...; * Object firstMessage = ...;
@ -251,11 +245,11 @@ import java.util.List;
* *
* if (buf.isReadable()) { * if (buf.isReadable()) {
* // Hand off the remaining data to the second decoder * // Hand off the remaining data to the second decoder
* out.add(firstMessage); * ctx.fireChannelRead(firstMessage);
* out.add(buf.readBytes(<b>super.actualReadableBytes()</b>)); * ctx.fireChannelRead(buf.readBytes(<b>super.actualReadableBytes()</b>));
* } else { * } else {
* // Nothing to hand off * // Nothing to hand off
* out.add(firstMessage); * ctx.fireChannelRead(firstMessage);
* } * }
* // Remove the first decoder (me) * // Remove the first decoder (me)
* ctx.pipeline().remove(this); * ctx.pipeline().remove(this);
@ -322,15 +316,15 @@ public abstract class ReplayingDecoder<S> extends ByteToMessageDecoder {
} }
@Override @Override
final void channelInputClosed(ChannelHandlerContext ctx, List<Object> out) throws Exception { final void channelInputClosed(ByteToMessageDecoderContext ctx) throws Exception {
try { try {
replayable.terminate(); replayable.terminate();
if (cumulation != null) { if (cumulation != null) {
callDecode(ctx, internalBuffer(), out); callDecode(ctx, internalBuffer());
} else { } else {
replayable.setCumulation(Unpooled.EMPTY_BUFFER); replayable.setCumulation(Unpooled.EMPTY_BUFFER);
} }
decodeLast(ctx, replayable, out); decodeLast(ctx, replayable);
} catch (Signal replay) { } catch (Signal replay) {
// Ignore // Ignore
replay.expect(REPLAY); replay.expect(REPLAY);
@ -338,32 +332,17 @@ public abstract class ReplayingDecoder<S> extends ByteToMessageDecoder {
} }
@Override @Override
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void callDecode(ByteToMessageDecoderContext ctx, ByteBuf in) {
replayable.setCumulation(in); replayable.setCumulation(in);
try { try {
while (in.isReadable()) { while (in.isReadable()) {
int oldReaderIndex = checkpoint = in.readerIndex(); int oldReaderIndex = checkpoint = in.readerIndex();
int outSize = out.size();
if (outSize > 0) {
fireChannelRead(ctx, out, outSize);
out.clear();
// Check if this handler was removed before continuing with decoding.
// If it was removed, it is not safe to continue to operate on the buffer.
//
// See:
// - https://github.com/netty/netty/issues/4635
if (ctx.isRemoved()) {
break;
}
outSize = 0;
}
S oldState = state; S oldState = state;
int oldInputLength = in.readableBytes(); int oldInputLength = in.readableBytes();
try { try {
decodeRemovalReentryProtection(ctx, replayable, out); int oldNumRead = ctx.fireChannelReadCallCount();
decodeRemovalReentryProtection(ctx, replayable);
// Check if this handler was removed before continuing the loop. // Check if this handler was removed before continuing the loop.
// If it was removed, it is not safe to continue to operate on the buffer. // If it was removed, it is not safe to continue to operate on the buffer.
@ -373,7 +352,7 @@ public abstract class ReplayingDecoder<S> extends ByteToMessageDecoder {
break; break;
} }
if (outSize == out.size()) { if (oldNumRead == ctx.fireChannelReadCallCount()) {
if (oldInputLength == in.readableBytes() && oldState == state) { if (oldInputLength == in.readableBytes() && oldState == state) {
throw new DecoderException( throw new DecoderException(
StringUtil.simpleClassName(getClass()) + ".decode() must consume the inbound " + StringUtil.simpleClassName(getClass()) + ".decode() must consume the inbound " +

View File

@ -60,7 +60,7 @@ public class Base64Decoder extends MessageToMessageDecoder<ByteBuf> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
out.add(Base64.decode(msg, msg.readerIndex(), msg.readableBytes(), dialect)); ctx.fireChannelRead(Base64.decode(msg, msg.readerIndex(), msg.readableBytes(), dialect));
} }
} }

View File

@ -51,8 +51,8 @@ import java.util.List;
*/ */
public class ByteArrayDecoder extends MessageToMessageDecoder<ByteBuf> { public class ByteArrayDecoder extends MessageToMessageDecoder<ByteBuf> {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
// copy the ByteBuf content to a byte array // copy the ByteBuf content to a byte array
out.add(ByteBufUtil.getBytes(msg)); ctx.fireChannelRead(ByteBufUtil.getBytes(msg));
} }
} }

View File

@ -19,8 +19,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
import static io.netty.handler.codec.compression.Bzip2Constants.*; import static io.netty.handler.codec.compression.Bzip2Constants.*;
/** /**
@ -77,7 +75,7 @@ public class Bzip2Decoder extends ByteToMessageDecoder {
private int streamCRC; private int streamCRC;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (!in.isReadable()) { if (!in.isReadable()) {
return; return;
} }
@ -302,7 +300,7 @@ public class Bzip2Decoder extends ByteToMessageDecoder {
int currentBlockCRC = blockDecompressor.checkCRC(); int currentBlockCRC = blockDecompressor.checkCRC();
streamCRC = (streamCRC << 1 | streamCRC >>> 31) ^ currentBlockCRC; streamCRC = (streamCRC << 1 | streamCRC >>> 31) ^ currentBlockCRC;
out.add(uncompressed); ctx.fireChannelRead(uncompressed);
success = true; success = true;
} finally { } finally {
if (!success) { if (!success) {

View File

@ -20,7 +20,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.internal.EmptyArrays; import io.netty.util.internal.EmptyArrays;
import java.util.List;
import java.util.zip.Adler32; import java.util.zip.Adler32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
@ -108,7 +107,7 @@ public class FastLzFrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (currentState) { switch (currentState) {
case INIT_BLOCK: case INIT_BLOCK:
@ -199,7 +198,7 @@ public class FastLzFrameDecoder extends ByteToMessageDecoder {
if (uncompressed != null) { if (uncompressed != null) {
uncompressed.writerIndex(uncompressed.writerIndex() + originalLength); uncompressed.writerIndex(uncompressed.writerIndex() + originalLength);
out.add(uncompressed); ctx.fireChannelRead(uncompressed);
} }
in.skipBytes(chunkLength); in.skipBytes(chunkLength);

View File

@ -22,8 +22,6 @@ import com.jcraft.jzlib.JZlib;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.List;
public class JZlibDecoder extends ZlibDecoder { public class JZlibDecoder extends ZlibDecoder {
private final Inflater z = new Inflater(); private final Inflater z = new Inflater();
@ -81,7 +79,7 @@ public class JZlibDecoder extends ZlibDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (finished) { if (finished) {
// Skip data received after finished. // Skip data received after finished.
in.skipBytes(in.readableBytes()); in.skipBytes(in.readableBytes());
@ -154,7 +152,7 @@ public class JZlibDecoder extends ZlibDecoder {
} finally { } finally {
in.skipBytes(z.next_in_index - oldNextInIndex); in.skipBytes(z.next_in_index - oldNextInIndex);
if (decompressed.isReadable()) { if (decompressed.isReadable()) {
out.add(decompressed); ctx.fireChannelRead(decompressed);
} else { } else {
decompressed.release(); decompressed.release();
} }

View File

@ -20,7 +20,6 @@ import static java.util.Objects.requireNonNull;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.List;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.DataFormatException; import java.util.zip.DataFormatException;
import java.util.zip.Deflater; import java.util.zip.Deflater;
@ -128,7 +127,7 @@ public class JdkZlibDecoder extends ZlibDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (finished) { if (finished) {
// Skip data received after finished. // Skip data received after finished.
in.skipBytes(in.readableBytes()); in.skipBytes(in.readableBytes());
@ -231,7 +230,7 @@ public class JdkZlibDecoder extends ZlibDecoder {
} finally { } finally {
if (decompressed.isReadable()) { if (decompressed.isReadable()) {
out.add(decompressed); ctx.fireChannelRead(decompressed);
} else { } else {
decompressed.release(); decompressed.release();
} }

View File

@ -22,7 +22,6 @@ import net.jpountz.lz4.LZ4Exception;
import net.jpountz.lz4.LZ4Factory; import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor; import net.jpountz.lz4.LZ4FastDecompressor;
import java.util.List;
import java.util.zip.Checksum; import java.util.zip.Checksum;
import static io.netty.handler.codec.compression.Lz4Constants.*; import static io.netty.handler.codec.compression.Lz4Constants.*;
@ -143,7 +142,7 @@ public class Lz4FrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (currentState) { switch (currentState) {
case INIT_BLOCK: case INIT_BLOCK:
@ -238,7 +237,7 @@ public class Lz4FrameDecoder extends ByteToMessageDecoder {
if (checksum != null) { if (checksum != null) {
CompressionUtil.checkChecksum(checksum, uncompressed, currentChecksum); CompressionUtil.checkChecksum(checksum, uncompressed, currentChecksum);
} }
out.add(uncompressed); ctx.fireChannelRead(uncompressed);
uncompressed = null; uncompressed = null;
currentState = State.INIT_BLOCK; currentState = State.INIT_BLOCK;
} catch (LZ4Exception e) { } catch (LZ4Exception e) {

View File

@ -22,8 +22,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
import static com.ning.compress.lzf.LZFChunk.BLOCK_TYPE_COMPRESSED; import static com.ning.compress.lzf.LZFChunk.BLOCK_TYPE_COMPRESSED;
import static com.ning.compress.lzf.LZFChunk.BLOCK_TYPE_NON_COMPRESSED; import static com.ning.compress.lzf.LZFChunk.BLOCK_TYPE_NON_COMPRESSED;
import static com.ning.compress.lzf.LZFChunk.BYTE_V; import static com.ning.compress.lzf.LZFChunk.BYTE_V;
@ -108,7 +106,7 @@ public class LzfDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
try { try {
switch (currentState) { switch (currentState) {
case INIT_BLOCK: case INIT_BLOCK:
@ -178,7 +176,7 @@ public class LzfDecoder extends ByteToMessageDecoder {
try { try {
decoder.decodeChunk(inputArray, inPos, outputArray, outPos, outPos + originalLength); decoder.decodeChunk(inputArray, inPos, outputArray, outPos, outPos + originalLength);
uncompressed.writerIndex(uncompressed.writerIndex() + originalLength); uncompressed.writerIndex(uncompressed.writerIndex() + originalLength);
out.add(uncompressed); ctx.fireChannelRead(uncompressed);
in.skipBytes(chunkLength); in.skipBytes(chunkLength);
success = true; success = true;
} finally { } finally {
@ -191,7 +189,7 @@ public class LzfDecoder extends ByteToMessageDecoder {
recycler.releaseInputBuffer(inputArray); recycler.releaseInputBuffer(inputArray);
} }
} else if (chunkLength > 0) { } else if (chunkLength > 0) {
out.add(in.readRetainedSlice(chunkLength)); ctx.fireChannelRead(in.readRetainedSlice(chunkLength));
} }
currentState = State.INIT_BLOCK; currentState = State.INIT_BLOCK;

View File

@ -19,8 +19,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
import static io.netty.handler.codec.compression.Snappy.validateChecksum; import static io.netty.handler.codec.compression.Snappy.validateChecksum;
/** /**
@ -76,7 +74,7 @@ public class SnappyFrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (corrupted) { if (corrupted) {
in.skipBytes(in.readableBytes()); in.skipBytes(in.readableBytes());
return; return;
@ -155,7 +153,7 @@ public class SnappyFrameDecoder extends ByteToMessageDecoder {
} else { } else {
in.skipBytes(4); in.skipBytes(4);
} }
out.add(in.readRetainedSlice(chunkLength - 4)); ctx.fireChannelRead(in.readRetainedSlice(chunkLength - 4));
break; break;
case COMPRESSED_DATA: case COMPRESSED_DATA:
if (!started) { if (!started) {
@ -182,7 +180,7 @@ public class SnappyFrameDecoder extends ByteToMessageDecoder {
} else { } else {
snappy.decode(in.readSlice(chunkLength - 4), uncompressed); snappy.decode(in.readSlice(chunkLength - 4), uncompressed);
} }
out.add(uncompressed); ctx.fireChannelRead(uncompressed);
uncompressed = null; uncompressed = null;
} finally { } finally {
if (uncompressed != null) { if (uncompressed != null) {

View File

@ -25,8 +25,6 @@ import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.TooLongFrameException;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import java.util.List;
/** /**
* Splits a byte stream of JSON objects and arrays into individual objects/arrays and passes them up the * Splits a byte stream of JSON objects and arrays into individual objects/arrays and passes them up the
* {@link ChannelPipeline}. * {@link ChannelPipeline}.
@ -89,7 +87,7 @@ public class JsonObjectDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (state == ST_CORRUPTED) { if (state == ST_CORRUPTED) {
in.skipBytes(in.readableBytes()); in.skipBytes(in.readableBytes());
return; return;
@ -121,7 +119,7 @@ public class JsonObjectDecoder extends ByteToMessageDecoder {
if (openBraces == 0) { if (openBraces == 0) {
ByteBuf json = extractObject(ctx, in, in.readerIndex(), idx + 1 - in.readerIndex()); ByteBuf json = extractObject(ctx, in, in.readerIndex(), idx + 1 - in.readerIndex());
if (json != null) { if (json != null) {
out.add(json); ctx.fireChannelRead(json);
} }
// The JSON object/array was extracted => discard the bytes from // The JSON object/array was extracted => discard the bytes from
@ -149,7 +147,7 @@ public class JsonObjectDecoder extends ByteToMessageDecoder {
ByteBuf json = extractObject(ctx, in, in.readerIndex(), idxNoSpaces + 1 - in.readerIndex()); ByteBuf json = extractObject(ctx, in, in.readerIndex(), idxNoSpaces + 1 - in.readerIndex());
if (json != null) { if (json != null) {
out.add(json); ctx.fireChannelRead(json);
} }
in.readerIndex(idx + 1); in.readerIndex(idx + 1);

View File

@ -24,7 +24,6 @@ import org.jboss.marshalling.ByteInput;
import org.jboss.marshalling.Unmarshaller; import org.jboss.marshalling.Unmarshaller;
import java.io.ObjectStreamConstants; import java.io.ObjectStreamConstants;
import java.util.List;
/** /**
* {@link ReplayingDecoder} which use an {@link Unmarshaller} to read the Object out of the {@link ByteBuf}. * {@link ReplayingDecoder} which use an {@link Unmarshaller} to read the Object out of the {@link ByteBuf}.
@ -55,7 +54,7 @@ public class CompatibleMarshallingDecoder extends ReplayingDecoder<Void> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
if (discardingTooLongFrame) { if (discardingTooLongFrame) {
buffer.skipBytes(actualReadableBytes()); buffer.skipBytes(actualReadableBytes());
checkpoint(); checkpoint();
@ -72,7 +71,7 @@ public class CompatibleMarshallingDecoder extends ReplayingDecoder<Void> {
unmarshaller.start(input); unmarshaller.start(input);
Object obj = unmarshaller.readObject(); Object obj = unmarshaller.readObject();
unmarshaller.finish(); unmarshaller.finish();
out.add(obj); ctx.fireChannelRead(obj);
} catch (LimitingByteInput.TooBigObjectException ignored) { } catch (LimitingByteInput.TooBigObjectException ignored) {
discardingTooLongFrame = true; discardingTooLongFrame = true;
throw new TooLongFrameException(); throw new TooLongFrameException();
@ -80,7 +79,7 @@ public class CompatibleMarshallingDecoder extends ReplayingDecoder<Void> {
} }
@Override @Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
switch (buffer.readableBytes()) { switch (buffer.readableBytes()) {
case 0: case 0:
return; return;
@ -92,7 +91,7 @@ public class CompatibleMarshallingDecoder extends ReplayingDecoder<Void> {
} }
} }
decode(ctx, buffer, out); decode(ctx, buffer);
} }
@Override @Override

View File

@ -59,8 +59,8 @@ public class MarshallingDecoder extends LengthFieldBasedFrameDecoder {
} }
@Override @Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { protected Object decode0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, in); ByteBuf frame = (ByteBuf) super.decode0(ctx, in);
if (frame == null) { if (frame == null) {
return null; return null;
} }

View File

@ -31,8 +31,6 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageDecoder;
import java.util.List;
/** /**
* Decodes a received {@link ByteBuf} into a * Decodes a received {@link ByteBuf} into a
* <a href="https://github.com/google/protobuf">Google Protocol Buffers</a> * <a href="https://github.com/google/protobuf">Google Protocol Buffers</a>
@ -103,7 +101,7 @@ public class ProtobufDecoder extends MessageToMessageDecoder<ByteBuf> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
final byte[] array; final byte[] array;
final int offset; final int offset;
final int length = msg.readableBytes(); final int length = msg.readableBytes();
@ -117,16 +115,16 @@ public class ProtobufDecoder extends MessageToMessageDecoder<ByteBuf> {
if (extensionRegistry == null) { if (extensionRegistry == null) {
if (HAS_PARSER) { if (HAS_PARSER) {
out.add(prototype.getParserForType().parseFrom(array, offset, length)); ctx.fireChannelRead(prototype.getParserForType().parseFrom(array, offset, length));
} else { } else {
out.add(prototype.newBuilderForType().mergeFrom(array, offset, length).build()); ctx.fireChannelRead(prototype.newBuilderForType().mergeFrom(array, offset, length).build());
} }
} else { } else {
if (HAS_PARSER) { if (HAS_PARSER) {
out.add(prototype.getParserForType().parseFrom( ctx.fireChannelRead(prototype.getParserForType().parseFrom(
array, offset, length, extensionRegistry)); array, offset, length, extensionRegistry));
} else { } else {
out.add(prototype.newBuilderForType().mergeFrom( ctx.fireChannelRead(prototype.newBuilderForType().mergeFrom(
array, offset, length, extensionRegistry).build()); array, offset, length, extensionRegistry).build());
} }
} }

View File

@ -71,8 +71,7 @@ public class ProtobufDecoderNano extends MessageToMessageDecoder<ByteBuf> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) protected void decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
throws Exception {
final byte[] array; final byte[] array;
final int offset; final int offset;
final int length = msg.readableBytes(); final int length = msg.readableBytes();
@ -84,6 +83,6 @@ public class ProtobufDecoderNano extends MessageToMessageDecoder<ByteBuf> {
offset = 0; offset = 0;
} }
MessageNano prototype = clazz.getConstructor().newInstance(); MessageNano prototype = clazz.getConstructor().newInstance();
out.add(MessageNano.mergeFrom(prototype, array, offset, length)); ctx.fireChannelRead(MessageNano.mergeFrom(prototype, array, offset, length));
} }
} }

View File

@ -22,8 +22,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException; import io.netty.handler.codec.CorruptedFrameException;
import java.util.List;
/** /**
* A decoder that splits the received {@link ByteBuf}s dynamically by the * A decoder that splits the received {@link ByteBuf}s dynamically by the
* value of the Google Protocol Buffers * value of the Google Protocol Buffers
@ -46,7 +44,7 @@ public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder {
// (just like LengthFieldBasedFrameDecoder) // (just like LengthFieldBasedFrameDecoder)
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) protected void decode(ChannelHandlerContext ctx, ByteBuf in)
throws Exception { throws Exception {
int readerIndex = in.readerIndex(); int readerIndex = in.readerIndex();
int preIndex = in.readerIndex(); int preIndex = in.readerIndex();
@ -61,7 +59,7 @@ public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder {
if (in.readableBytes() < length) { if (in.readableBytes() < length) {
in.readerIndex(readerIndex); in.readerIndex(readerIndex);
} else { } else {
out.add(in.readRetainedSlice(length)); ctx.fireChannelRead(in.readRetainedSlice(length));
} }
} }

View File

@ -65,8 +65,8 @@ public class ObjectDecoder extends LengthFieldBasedFrameDecoder {
} }
@Override @Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { protected Object decode0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, in); ByteBuf frame = (ByteBuf) super.decode0(ctx, in);
if (frame == null) { if (frame == null) {
return null; return null;
} }

View File

@ -27,7 +27,6 @@ import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageDecoder;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.List;
/** /**
* Decodes a received {@link ByteBuf} into a {@link String}. Please * Decodes a received {@link ByteBuf} into a {@link String}. Please
@ -75,7 +74,7 @@ public class StringDecoder extends MessageToMessageDecoder<ByteBuf> {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
out.add(msg.toString(charset)); ctx.fireChannelRead(msg.toString(charset));
} }
} }

View File

@ -21,8 +21,6 @@ import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException; import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.TooLongFrameException;
import java.util.List;
/** /**
* A frame decoder for single separate XML based message streams. * A frame decoder for single separate XML based message streams.
* <p/> * <p/>
@ -85,7 +83,7 @@ public class XmlFrameDecoder extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
boolean openingBracketFound = false; boolean openingBracketFound = false;
boolean atLeastOneXmlElementFound = false; boolean atLeastOneXmlElementFound = false;
boolean inCDATASection = false; boolean inCDATASection = false;
@ -189,7 +187,7 @@ public class XmlFrameDecoder extends ByteToMessageDecoder {
final ByteBuf frame = final ByteBuf frame =
extractFrame(in, readerIndex + leadingWhiteSpaceCount, xmlElementLength - leadingWhiteSpaceCount); extractFrame(in, readerIndex + leadingWhiteSpaceCount, xmlElementLength - leadingWhiteSpaceCount);
in.skipBytes(xmlElementLength); in.skipBytes(xmlElementLength);
out.add(frame); ctx.fireChannelRead(frame);
} }
} }

View File

@ -22,8 +22,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.Test; import org.junit.Test;
import java.util.List;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class ByteToMessageCodecTest { public class ByteToMessageCodecTest {
@ -47,9 +45,9 @@ public class ByteToMessageCodecTest {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() >= 4) { if (in.readableBytes() >= 4) {
out.add(in.readInt()); ctx.fireChannelRead(in.readInt());
} }
} }
}; };
@ -81,7 +79,7 @@ public class ByteToMessageCodecTest {
protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception { } protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception { }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { } protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { }
} }
@ChannelHandler.Sharable @ChannelHandler.Sharable
@ -94,6 +92,6 @@ public class ByteToMessageCodecTest {
protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception { } protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception { }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { } protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { }
} }
} }

View File

@ -26,9 +26,9 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.util.List;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -49,7 +49,7 @@ public class ByteToMessageDecoderTest {
private boolean removed; private boolean removed;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
assertFalse(removed); assertFalse(removed);
in.readByte(); in.readByte();
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
@ -72,7 +72,7 @@ public class ByteToMessageDecoderTest {
private boolean removed; private boolean removed;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
assertFalse(removed); assertFalse(removed);
in.readByte(); in.readByte();
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
@ -125,7 +125,7 @@ public class ByteToMessageDecoderTest {
private EmbeddedChannel newInternalBufferTestChannel() { private EmbeddedChannel newInternalBufferTestChannel() {
return new EmbeddedChannel(new ByteToMessageDecoder() { return new EmbeddedChannel(new ByteToMessageDecoder() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
ByteBuf byteBuf = internalBuffer(); ByteBuf byteBuf = internalBuffer();
assertEquals(1, byteBuf.refCnt()); assertEquals(1, byteBuf.refCnt());
in.readByte(); in.readByte();
@ -144,7 +144,7 @@ public class ByteToMessageDecoderTest {
public void handlerRemovedWillNotReleaseBufferIfDecodeInProgress() { public void handlerRemovedWillNotReleaseBufferIfDecodeInProgress() {
EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
assertTrue(in.refCnt() != 0); assertTrue(in.refCnt() != 0);
} }
@ -172,16 +172,16 @@ public class ByteToMessageDecoderTest {
final ByteBuf buf = Unpooled.buffer().writeBytes(new byte[] {'a', 'b'}); final ByteBuf buf = Unpooled.buffer().writeBytes(new byte[] {'a', 'b'});
EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
int readable = in.readableBytes(); int readable = in.readableBytes();
assertTrue(readable > 0); assertTrue(readable > 0);
in.skipBytes(readable); in.skipBytes(readable);
} }
@Override @Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in) {
assertFalse(in.isReadable()); assertFalse(in.isReadable());
out.add("data"); ctx.fireChannelRead("data");
} }
}, new ChannelHandler() { }, new ChannelHandler() {
@Override @Override
@ -215,9 +215,9 @@ public class ByteToMessageDecoderTest {
final Object upgradeMessage = new Object(); final Object upgradeMessage = new Object();
final ByteToMessageDecoder decoder = new ByteToMessageDecoder() { final ByteToMessageDecoder decoder = new ByteToMessageDecoder() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
assertEquals('a', in.readByte()); assertEquals('a', in.readByte());
out.add(upgradeMessage); ctx.fireChannelRead(upgradeMessage);
} }
}; };
@ -245,10 +245,10 @@ public class ByteToMessageDecoderTest {
public void testDecodeLastEmptyBuffer() { public void testDecodeLastEmptyBuffer() {
EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
int readable = in.readableBytes(); int readable = in.readableBytes();
assertTrue(readable > 0); assertTrue(readable > 0);
out.add(in.readBytes(readable)); ctx.fireChannelRead(in.readBytes(readable));
} }
}); });
byte[] bytes = new byte[1024]; byte[] bytes = new byte[1024];
@ -267,20 +267,20 @@ public class ByteToMessageDecoderTest {
private boolean decodeLast; private boolean decodeLast;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
int readable = in.readableBytes(); int readable = in.readableBytes();
assertTrue(readable > 0); assertTrue(readable > 0);
if (!decodeLast && readable == 1) { if (!decodeLast && readable == 1) {
return; return;
} }
out.add(in.readBytes(decodeLast ? readable : readable - 1)); ctx.fireChannelRead(in.readBytes(decodeLast ? readable : readable - 1));
} }
@Override @Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
assertFalse(decodeLast); assertFalse(decodeLast);
decodeLast = true; decodeLast = true;
super.decodeLast(ctx, in, out); super.decodeLast(ctx, in);
} }
}); });
byte[] bytes = new byte[1024]; byte[] bytes = new byte[1024];
@ -307,8 +307,7 @@ public class ByteToMessageDecoderTest {
public void testReadOnlyBuffer() { public void testReadOnlyBuffer() {
EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) { }
}
}); });
assertFalse(channel.writeInbound(Unpooled.buffer(8).writeByte(1).asReadOnly())); assertFalse(channel.writeInbound(Unpooled.buffer(8).writeByte(1).asReadOnly()));
assertFalse(channel.writeInbound(Unpooled.wrappedBuffer(new byte[] { (byte) 2 }))); assertFalse(channel.writeInbound(Unpooled.wrappedBuffer(new byte[] { (byte) 2 })));
@ -486,8 +485,8 @@ public class ByteToMessageDecoderTest {
//read 4 byte then remove this decoder //read 4 byte then remove this decoder
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
out.add(in.readByte()); ctx.fireChannelRead(in.readByte());
if (++count >= 4) { if (++count >= 4) {
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
} }

View File

@ -84,7 +84,7 @@ public class DatagramPacketDecoderTest {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
// NOOP // NOOP
} }

View File

@ -23,7 +23,6 @@ import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.channel.socket.ChannelInputShutdownEvent; import io.netty.channel.socket.ChannelInputShutdownEvent;
import org.junit.Test; import org.junit.Test;
import java.util.List;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -67,10 +66,10 @@ public class ReplayingDecoderTest {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
ByteBuf msg = in.readBytes(in.bytesBefore((byte) '\n')); ByteBuf msg = in.readBytes(in.bytesBefore((byte) '\n'));
out.add(msg);
in.skipBytes(1); in.skipBytes(1);
ctx.fireChannelRead(msg);
} }
} }
@ -141,7 +140,7 @@ public class ReplayingDecoderTest {
private boolean removed; private boolean removed;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
assertFalse(removed); assertFalse(removed);
in.readByte(); in.readByte();
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
@ -163,7 +162,7 @@ public class ReplayingDecoderTest {
private boolean removed; private boolean removed;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
assertFalse(removed); assertFalse(removed);
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
@ -189,7 +188,7 @@ public class ReplayingDecoderTest {
private boolean removed; private boolean removed;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
assertFalse(removed); assertFalse(removed);
in.readByte(); in.readByte();
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
@ -214,17 +213,17 @@ public class ReplayingDecoderTest {
EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder<Integer>() { EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder<Integer>() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
int readable = in.readableBytes(); int readable = in.readableBytes();
assertTrue(readable > 0); assertTrue(readable > 0);
in.skipBytes(readable); in.skipBytes(readable);
out.add("data"); ctx.fireChannelRead("data");
} }
@Override @Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
assertFalse(in.isReadable()); assertFalse(in.isReadable());
out.add("data"); ctx.fireChannelRead("data");
} }
}, new ChannelHandler() { }, new ChannelHandler() {
@Override @Override
@ -261,7 +260,7 @@ public class ReplayingDecoderTest {
private boolean decoded; private boolean decoded;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (!(in instanceof ReplayingDecoderByteBuf)) { if (!(in instanceof ReplayingDecoderByteBuf)) {
error.set(new AssertionError("in must be of type " + ReplayingDecoderByteBuf.class error.set(new AssertionError("in must be of type " + ReplayingDecoderByteBuf.class
+ " but was " + in.getClass())); + " but was " + in.getClass()));
@ -292,7 +291,7 @@ public class ReplayingDecoderTest {
public void handlerRemovedWillNotReleaseBufferIfDecodeInProgress() { public void handlerRemovedWillNotReleaseBufferIfDecodeInProgress() {
EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder<Integer>() { EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder<Integer>() {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ctx.pipeline().remove(this); ctx.pipeline().remove(this);
assertTrue(in.refCnt() != 0); assertTrue(in.refCnt() != 0);
} }

View File

@ -21,7 +21,6 @@ import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException; import io.netty.handler.codec.CorruptedFrameException;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List;
/** /**
* Decodes the binary representation of a {@link BigInteger} prepended * Decodes the binary representation of a {@link BigInteger} prepended
@ -32,7 +31,7 @@ import java.util.List;
public class BigIntegerDecoder extends ByteToMessageDecoder { public class BigIntegerDecoder extends ByteToMessageDecoder {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
// Wait until the length prefix is available. // Wait until the length prefix is available.
if (in.readableBytes() < 5) { if (in.readableBytes() < 5) {
return; return;
@ -58,6 +57,6 @@ public class BigIntegerDecoder extends ByteToMessageDecoder {
byte[] decoded = new byte[dataLength]; byte[] decoded = new byte[dataLength];
in.readBytes(decoded); in.readBytes(decoded);
out.add(new BigInteger(decoded)); ctx.fireChannelRead(new BigInteger(decoded));
} }
} }

View File

@ -31,8 +31,6 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler; import io.netty.handler.ssl.SslHandler;
import java.util.List;
/** /**
* Manipulates the current pipeline dynamically to switch protocols or enable * Manipulates the current pipeline dynamically to switch protocols or enable
* SSL or GZIP. * SSL or GZIP.
@ -54,7 +52,7 @@ public class PortUnificationServerHandler extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
// Will use the first five bytes to detect a protocol. // Will use the first five bytes to detect a protocol.
if (in.readableBytes() < 5) { if (in.readableBytes() < 5) {
return; return;

View File

@ -28,7 +28,6 @@ import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
@ -49,7 +48,7 @@ public abstract class AbstractSniHandler<T> extends ByteToMessageDecoder {
private ByteBuf handshakeBuffer; private ByteBuf handshakeBuffer;
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (!suppressRead && !handshakeFailed) { if (!suppressRead && !handshakeFailed) {
try { try {
int readerIndex = in.readerIndex(); int readerIndex = in.readerIndex();

View File

@ -26,7 +26,6 @@ import io.netty.util.ReferenceCountUtil;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLParameters;
import java.util.List;
/** /**
* {@link OptionalSslHandler} is a utility decoder to support both SSL and non-SSL handlers * {@link OptionalSslHandler} is a utility decoder to support both SSL and non-SSL handlers
@ -41,7 +40,7 @@ public class OptionalSslHandler extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext context, ByteBuf in, List<Object> out) throws Exception { protected void decode(ChannelHandlerContext context, ByteBuf in) throws Exception {
if (in.readableBytes() < SslUtils.SSL_RECORD_HEADER_LENGTH) { if (in.readableBytes() < SslUtils.SSL_RECORD_HEADER_LENGTH) {
return; return;
} }

View File

@ -55,7 +55,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel; import java.nio.channels.DatagramChannel;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
@ -1260,7 +1259,7 @@ public class SslHandler extends ByteToMessageDecoder {
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws SSLException { protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws SSLException {
if (processTask) { if (processTask) {
return; return;
} }
@ -1868,7 +1867,7 @@ public class SslHandler extends ByteToMessageDecoder {
} }
@Override @Override
public void handlerAdded(final ChannelHandlerContext ctx) throws Exception { public void handlerAdded0(final ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx; this.ctx = ctx;
pendingUnencryptedWrites = new SslHandlerCoalescingBufferQueue(ctx.channel(), 16); pendingUnencryptedWrites = new SslHandlerCoalescingBufferQueue(ctx.channel(), 16);

View File

@ -41,7 +41,6 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Exchanger; import java.util.concurrent.Exchanger;
@ -484,11 +483,11 @@ public class FlowControlHandlerTest {
*/ */
private static final class OneByteToThreeStringsDecoder extends ByteToMessageDecoder { private static final class OneByteToThreeStringsDecoder extends ByteToMessageDecoder {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { protected void decode(ChannelHandlerContext ctx, ByteBuf in) {
for (int i = 0; i < in.readableBytes(); i++) { for (int i = 0; i < in.readableBytes(); i++) {
out.add("1"); ctx.fireChannelRead("1");
out.add("2"); ctx.fireChannelRead("2");
out.add("3"); ctx.fireChannelRead("3");
} }
in.readerIndex(in.readableBytes()); in.readerIndex(in.readableBytes());
} }

View File

@ -54,7 +54,7 @@ public class OptionalSslHandlerTest {
OptionalSslHandler handler = new OptionalSslHandler(sslContext); OptionalSslHandler handler = new OptionalSslHandler(sslContext);
final ByteBuf payload = Unpooled.copiedBuffer("plaintext".getBytes()); final ByteBuf payload = Unpooled.copiedBuffer("plaintext".getBytes());
try { try {
handler.decode(context, payload, null); handler.decode(context, payload);
verify(pipeline).remove(handler); verify(pipeline).remove(handler);
} finally { } finally {
payload.release(); payload.release();
@ -77,7 +77,7 @@ public class OptionalSslHandlerTest {
}; };
final ByteBuf payload = Unpooled.copiedBuffer("plaintext".getBytes()); final ByteBuf payload = Unpooled.copiedBuffer("plaintext".getBytes());
try { try {
handler.decode(context, payload, null); handler.decode(context, payload);
verify(pipeline).replace(handler, HANDLER_NAME, nonSslHandler); verify(pipeline).replace(handler, HANDLER_NAME, nonSslHandler);
} finally { } finally {
payload.release(); payload.release();
@ -100,7 +100,7 @@ public class OptionalSslHandlerTest {
}; };
final ByteBuf payload = Unpooled.wrappedBuffer(new byte[] { 22, 3, 1, 0, 5 }); final ByteBuf payload = Unpooled.wrappedBuffer(new byte[] { 22, 3, 1, 0, 5 });
try { try {
handler.decode(context, payload, null); handler.decode(context, payload);
verify(pipeline).replace(handler, SSL_HANDLER_NAME, sslHandler); verify(pipeline).replace(handler, SSL_HANDLER_NAME, sslHandler);
} finally { } finally {
payload.release(); payload.release();
@ -112,7 +112,7 @@ public class OptionalSslHandlerTest {
OptionalSslHandler handler = new OptionalSslHandler(sslContext); OptionalSslHandler handler = new OptionalSslHandler(sslContext);
final ByteBuf payload = Unpooled.wrappedBuffer(new byte[] { 22, 3 }); final ByteBuf payload = Unpooled.wrappedBuffer(new byte[] { 22, 3 });
try { try {
handler.decode(context, payload, null); handler.decode(context, payload);
verifyZeroInteractions(pipeline); verifyZeroInteractions(pipeline);
} finally { } finally {
payload.release(); payload.release();

Some files were not shown because too many files have changed in this diff Show More