Revamp the core API to reduce memory footprint and consumption

The API changes made so far turned out to increase the memory footprint
and consumption while our intention was actually decreasing them.

Memory consumption issue:

When there are many connections which does not exchange data frequently,
the old Netty 4 API spent a lot more memory than 3 because it always
allocates per-handler buffer for each connection unless otherwise
explicitly stated by a user.  In a usual real world load, a client
doesn't always send requests without pausing, so the idea of having a
buffer whose life cycle if bound to the life cycle of a connection
didn't work as expected.

Memory footprint issue:

The old Netty 4 API decreased overall memory footprint by a great deal
in many cases.  It was mainly because the old Netty 4 API did not
allocate a new buffer and event object for each read.  Instead, it
created a new buffer for each handler in a pipeline.  This works pretty
well as long as the number of handlers in a pipeline is only a few.
However, for a highly modular application with many handlers which
handles connections which lasts for relatively short period, it actually
makes the memory footprint issue much worse.

Changes:

All in all, this is about retaining all the good changes we made in 4 so
far such as better thread model and going back to the way how we dealt
with message events in 3.

To fix the memory consumption/footprint issue mentioned above, we made a
hard decision to break the backward compatibility again with the
following changes:

- Remove MessageBuf
- Merge Buf into ByteBuf
- Merge ChannelInboundByte/MessageHandler and ChannelStateHandler into ChannelInboundHandler
  - Similar changes were made to the adapter classes
- Merge ChannelOutboundByte/MessageHandler and ChannelOperationHandler into ChannelOutboundHandler
  - Similar changes were made to the adapter classes
- Introduce MessageList which is similar to `MessageEvent` in Netty 3
- Replace inboundBufferUpdated(ctx) with messageReceived(ctx, MessageList)
- Replace flush(ctx, promise) with write(ctx, MessageList, promise)
- Remove ByteToByteEncoder/Decoder/Codec
  - Replaced by MessageToByteEncoder<ByteBuf>, ByteToMessageDecoder<ByteBuf>, and ByteMessageCodec<ByteBuf>
- Merge EmbeddedByteChannel and EmbeddedMessageChannel into EmbeddedChannel
- Add SimpleChannelInboundHandler which is sometimes more useful than
  ChannelInboundHandlerAdapter
- Bring back Channel.isWritable() from Netty 3
- Add ChannelInboundHandler.channelWritabilityChanges() event
- Add RecvByteBufAllocator configuration property
  - Similar to ReceiveBufferSizePredictor in Netty 3
  - Some existing configuration properties such as
    DatagramChannelConfig.receivePacketSize is gone now.
- Remove suspend/resumeIntermediaryDeallocation() in ByteBuf

This change would have been impossible without @normanmaurer's help. He
fixed, ported, and improved many parts of the changes.
This commit is contained in:
Trustin Lee 2013-05-28 20:40:19 +09:00
parent fe711f65fb
commit 14158070bf
357 changed files with 6282 additions and 10019 deletions

View File

@ -20,7 +20,7 @@
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>4.0.0.Final-SNAPSHOT</version>
<version>4.0.0.CR4-SNAPSHOT</version>
</parent>
<artifactId>netty-all</artifactId>

View File

@ -20,7 +20,7 @@
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>4.0.0.Final-SNAPSHOT</version>
<version>4.0.0.CR4-SNAPSHOT</version>
</parent>
<artifactId>netty-buffer</artifactId>

View File

@ -50,11 +50,6 @@ public abstract class AbstractByteBuf implements ByteBuf {
this.maxCapacity = maxCapacity;
}
@Override
public BufType type() {
return BufType.BYTE;
}
@Override
public int maxCapacity() {
return maxCapacity;
@ -971,17 +966,17 @@ public abstract class AbstractByteBuf implements ByteBuf {
nioBuffer.flip();
}
return BufUtil.decodeString(nioBuffer, charset);
return ByteBufUtil.decodeString(nioBuffer, charset);
}
@Override
public int indexOf(int fromIndex, int toIndex, byte value) {
return BufUtil.indexOf(this, fromIndex, toIndex, value);
return ByteBufUtil.indexOf(this, fromIndex, toIndex, value);
}
@Override
public int indexOf(int fromIndex, int toIndex, ByteBufIndexFinder indexFinder) {
return BufUtil.indexOf(this, fromIndex, toIndex, indexFinder);
return ByteBufUtil.indexOf(this, fromIndex, toIndex, indexFinder);
}
@Override
@ -1027,7 +1022,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
@Override
public int hashCode() {
return BufUtil.hashCode(this);
return ByteBufUtil.hashCode(this);
}
@Override
@ -1036,14 +1031,14 @@ public abstract class AbstractByteBuf implements ByteBuf {
return true;
}
if (o instanceof ByteBuf) {
return BufUtil.equals(this, (ByteBuf) o);
return ByteBufUtil.equals(this, (ByteBuf) o);
}
return false;
}
@Override
public int compareTo(ByteBuf that) {
return BufUtil.compare(this, that);
return ByteBufUtil.compare(this, that);
}
@Override

View File

@ -52,14 +52,4 @@ public abstract class AbstractDerivedByteBuf extends AbstractByteBuf {
public final boolean release(int decrement) {
return unwrap().release(decrement);
}
@Override
public final ByteBuf suspendIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
@Override
public final ByteBuf resumeIntermediaryDeallocations() {
throw new UnsupportedOperationException("derived");
}
}

View File

@ -1,258 +0,0 @@
/*
* Copyright 2013 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.buffer;
import io.netty.util.internal.PlatformDependent;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/**
* Abstract base class for {@link MessageBuf} implementations.
* @param <T>
*/
public abstract class AbstractMessageBuf<T> extends AbstractQueue<T> implements MessageBuf<T> {
@SuppressWarnings("rawtypes")
private static final AtomicIntegerFieldUpdater<AbstractMessageBuf> refCntUpdater =
AtomicIntegerFieldUpdater.newUpdater(AbstractMessageBuf.class, "refCnt");
private static final long REFCNT_FIELD_OFFSET;
static {
long refCntFieldOffset = -1;
try {
if (PlatformDependent.hasUnsafe()) {
refCntFieldOffset = PlatformDependent.objectFieldOffset(
AbstractMessageBuf.class.getDeclaredField("refCnt"));
}
} catch (Throwable t) {
// Ignored
}
REFCNT_FIELD_OFFSET = refCntFieldOffset;
}
private final int maxCapacity;
@SuppressWarnings("FieldMayBeFinal")
private volatile int refCnt = 1;
protected AbstractMessageBuf(int maxCapacity) {
if (maxCapacity < 0) {
throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
}
this.maxCapacity = maxCapacity;
}
@Override
public final BufType type() {
return BufType.MESSAGE;
}
@Override
public final int refCnt() {
if (REFCNT_FIELD_OFFSET >= 0) {
// Try to do non-volatile read for performance.
return PlatformDependent.getInt(this, REFCNT_FIELD_OFFSET);
} else {
return refCnt;
}
}
@Override
public MessageBuf<T> retain() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalBufferAccessException("refCnt overflow");
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) {
break;
}
}
return this;
}
@Override
public MessageBuf<T> retain(int increment) {
if (increment <= 0) {
throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)");
}
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}
if (refCnt > Integer.MAX_VALUE - increment) {
throw new IllegalBufferAccessException("refCnt overflow");
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + increment)) {
break;
}
}
return this;
}
@Override
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) {
if (refCnt == 1) {
deallocate();
return true;
}
return false;
}
}
}
@Override
public final boolean release(int decrement) {
if (decrement <= 0) {
throw new IllegalArgumentException("decrement: " + decrement + " (expected: > 0)");
}
for (;;) {
int refCnt = this.refCnt;
if (refCnt < decrement) {
throw new IllegalBufferAccessException();
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) {
if (refCnt == decrement) {
deallocate();
return true;
}
return false;
}
}
}
protected abstract void deallocate();
@Override
public final int maxCapacity() {
return maxCapacity;
}
@Override
public final boolean isReadable() {
return !isEmpty();
}
@Override
public final boolean isReadable(int size) {
if (size < 0) {
throw new IllegalArgumentException("size: " + size + " (expected: >= 0)");
}
return size() >= size;
}
@Override
public final boolean isWritable() {
return size() < maxCapacity;
}
@Override
public final boolean isWritable(int size) {
if (size < 0) {
throw new IllegalArgumentException("size: " + size + " (expected: >= 0)");
}
return size() <= maxCapacity - size;
}
protected final void ensureAccessible() {
if (refCnt <= 0) {
throw new IllegalBufferAccessException();
}
}
@Override
public final boolean add(T t) {
return super.add(t);
}
@Override
public final T remove() {
return super.remove();
}
@Override
public final T element() {
return super.element();
}
@Override
public int drainTo(Collection<? super T> c) {
ensureAccessible();
int cnt = 0;
for (;;) {
T o = poll();
if (o == null) {
break;
}
c.add(o);
cnt ++;
}
return cnt;
}
@Override
public int drainTo(Collection<? super T> c, int maxElements) {
ensureAccessible();
int cnt = 0;
while (cnt < maxElements) {
T o = poll();
if (o == null) {
break;
}
c.add(o);
cnt ++;
}
return cnt;
}
@Override
public String toString() {
if (refCnt <= 0) {
return getClass().getSimpleName() + "(freed)";
}
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append("(size: ");
buf.append(size());
if (maxCapacity != Integer.MAX_VALUE) {
buf.append('/');
buf.append(maxCapacity);
}
buf.append(')');
return buf.toString();
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright 2012 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.buffer;
/**
* A buffer to operate on
*/
public interface Buf extends ReferenceCounted {
/**
* The BufType which will be handled by the Buf implementation
*/
BufType type();
/**
* Returns the maximum allowed capacity of this buffer.
*/
int maxCapacity();
/**
* Returns {@code true} if and only if this buffer contains at least one readable element.
*/
boolean isReadable();
/**
* Returns {@code true} if and only if this buffer contains equal to or more than the specified number of elements.
*/
boolean isReadable(int size);
/**
* Returns {@code true} if and only if this buffer has enough room to allow writing one element.
*/
boolean isWritable();
/**
* Returns {@code true} if and only if this buffer has enough room to allow writing the specified number of
* elements.
*/
boolean isWritable(int size);
@Override
Buf retain();
@Override
Buf retain(int increment);
}

View File

@ -227,7 +227,7 @@ import java.nio.charset.UnsupportedCharsetException;
* Please refer to {@link ByteBufInputStream} and
* {@link ByteBufOutputStream}.
*/
public interface ByteBuf extends Buf, Comparable<ByteBuf> {
public interface ByteBuf extends ReferenceCounted, Comparable<ByteBuf> {
/**
* Returns the number of bytes (octets) this buffer can contain.
@ -248,7 +248,6 @@ public interface ByteBuf extends Buf, Comparable<ByteBuf> {
* {@link #ensureWritable(int)}, those methods will raise an
* {@link IllegalArgumentException}.
*/
@Override
int maxCapacity();
/**
@ -391,9 +390,13 @@ public interface ByteBuf extends Buf, Comparable<ByteBuf> {
* if and only if {@code (this.writerIndex - this.readerIndex)} is greater
* than {@code 0}.
*/
@Override
boolean isReadable();
/**
* Returns {@code true} if and only if this buffer contains equal to or more than the specified number of elements.
*/
boolean isReadable(int size);
/**
* @deprecated Use {@link #isReadable()} or {@link #isReadable(int)} instead.
*/
@ -405,9 +408,14 @@ public interface ByteBuf extends Buf, Comparable<ByteBuf> {
* if and only if {@code (this.capacity - this.writerIndex)} is greater
* than {@code 0}.
*/
@Override
boolean isWritable();
/**
* Returns {@code true} if and only if this buffer has enough room to allow writing the specified number of
* elements.
*/
boolean isWritable(int size);
/**
* @deprecated Use {@link #isWritable()} or {@link #isWritable(int)} instead.
*/
@ -1869,23 +1877,6 @@ public interface ByteBuf extends Buf, Comparable<ByteBuf> {
*/
String toString(int index, int length, Charset charset);
/**
* Suspends the intermediary deallocation of the internal memory block of this buffer until asked via
* {@link #resumeIntermediaryDeallocations()}. An intermediary deallocation is usually made when the capacity of
* a buffer changes.
*
* @throws UnsupportedOperationException if this buffer is derived
*/
ByteBuf suspendIntermediaryDeallocations();
/**
* Resumes the intermediary deallocation of the internal memory block of this buffer, suspended by
* {@link #suspendIntermediaryDeallocations()}.
*
* @throws UnsupportedOperationException if this buffer is derived
*/
ByteBuf resumeIntermediaryDeallocations();
/**
* Returns a hash code which was calculated from the content of this
* buffer. If there's a byte array which is

View File

@ -25,13 +25,11 @@ import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Iterator;
/**
* A collection of utility methods that is related with handling {@link ByteBuf}, {@link MessageBuf}, and their
* elements.
* A collection of utility methods that is related with handling {@link ByteBuf}.
*/
public final class BufUtil {
public final class ByteBufUtil {
private static final char[] HEXDUMP_TABLE = new char[256 * 4];
@ -418,29 +416,5 @@ public final class BufUtil {
return dst.flip().toString();
}
/**
* Return the content of the given {@link MessageBuf} as string representation.
*/
public static String contentToString(MessageBuf<?> buf) {
if (buf.isEmpty()) {
return "[]";
}
Iterator<?> it = buf.iterator();
StringBuilder sb = new StringBuilder();
sb.append('[');
while (it.hasNext()) {
Object msg = it.next();
if (msg == buf) {
sb.append('(' + buf.getClass().getSimpleName() + ')');
} else {
sb.append(msg);
}
if (it.hasNext()) {
sb.append(", ");
}
}
return sb.append(']').toString();
}
private BufUtil() { }
private ByteBufUtil() { }
}

View File

@ -387,12 +387,6 @@ public interface CompositeByteBuf extends ByteBuf, Iterable<ByteBuf> {
@Override
CompositeByteBuf writeZero(int length);
@Override
CompositeByteBuf suspendIntermediaryDeallocations();
@Override
CompositeByteBuf resumeIntermediaryDeallocations();
@Override
CompositeByteBuf retain(int increment);

View File

@ -26,14 +26,12 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Queue;
/**
@ -50,7 +48,6 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp
private final int maxNumComponents;
private boolean freed;
private Queue<ByteBuf> suspendedDeallocations;
public DefaultCompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents) {
super(Integer.MAX_VALUE);
@ -1202,11 +1199,7 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp
void freeIfNecessary() {
// Unwrap so that we can free slices, too.
if (suspendedDeallocations == null) {
buf.release(); // We should not get a NPE here. If so, it must be a bug.
} else {
suspendedDeallocations.add(buf);
}
}
}
@ -1457,7 +1450,6 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp
}
freed = true;
resumeIntermediaryDeallocations();
for (Component c: components) {
c.freeIfNecessary();
}
@ -1465,30 +1457,6 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp
leak.close();
}
@Override
public CompositeByteBuf suspendIntermediaryDeallocations() {
ensureAccessible();
if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque<ByteBuf>(2);
}
return this;
}
@Override
public CompositeByteBuf resumeIntermediaryDeallocations() {
if (suspendedDeallocations == null) {
return this;
}
Queue<ByteBuf> suspendedDeallocations = this.suspendedDeallocations;
this.suspendedDeallocations = null;
for (ByteBuf buf: suspendedDeallocations) {
buf.release();
}
return this;
}
@Override
public ByteBuf unwrap() {
return null;

View File

@ -1,337 +0,0 @@
/*
* Copyright 2012 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.
*/
/*
* Written by Josh Bloch of Google Inc. and released to the public domain,
* as explained at http://creativecommons.org/publicdomain/zero/1.0/.
*/
package io.netty.buffer;
import java.lang.reflect.Array;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Default {@link MessageBuf} implementation.
*
* You should use {@link Unpooled#messageBuffer()} to create an instance
*
*/
public class DefaultMessageBuf<T> extends AbstractMessageBuf<T> {
private static final int MIN_INITIAL_CAPACITY = 8;
private static final Object[] PLACEHOLDER = new Object[2];
private T[] elements;
private int head;
private int tail;
protected DefaultMessageBuf() {
this(MIN_INITIAL_CAPACITY << 1);
}
protected DefaultMessageBuf(int initialCapacity) {
this(initialCapacity, Integer.MAX_VALUE);
}
protected DefaultMessageBuf(int initialCapacity, int maxCapacity) {
super(maxCapacity);
if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity: " + initialCapacity + " (expected: >= 0)");
}
if (maxCapacity < initialCapacity) {
throw new IllegalArgumentException(
"maxCapacity: " + maxCapacity + " (expected: >= initialCapacity(" + initialCapacity + ')');
}
// Find the best power of two to hold elements.
// Tests "<=" because arrays aren't kept full.
if (initialCapacity >= MIN_INITIAL_CAPACITY) {
initialCapacity |= initialCapacity >>> 1;
initialCapacity |= initialCapacity >>> 2;
initialCapacity |= initialCapacity >>> 4;
initialCapacity |= initialCapacity >>> 8;
initialCapacity |= initialCapacity >>> 16;
initialCapacity ++;
if (initialCapacity < 0) { // Too many elements, must back off
initialCapacity >>>= 1; // Good luck allocating 2 ^ 30 elements
}
} else {
initialCapacity = MIN_INITIAL_CAPACITY;
}
elements = cast(new Object[initialCapacity]);
}
@Override
protected void deallocate() {
head = 0;
tail = 0;
elements = cast(PLACEHOLDER);
}
@Override
public boolean offer(T e) {
if (e == null) {
throw new NullPointerException();
}
ensureAccessible();
if (!isWritable()) {
return false;
}
elements[tail] = e;
if ((tail = tail + 1 & elements.length - 1) == head) {
doubleCapacity();
}
return true;
}
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // number of elements to the right of p
int newCapacity = n << 1;
if (newCapacity < 0) {
throw new IllegalStateException("Sorry, deque too big");
}
Object[] a = new Object[newCapacity];
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = cast(a);
head = 0;
tail = n;
}
@Override
public T poll() {
ensureAccessible();
int h = head;
T result = elements[h]; // Element is null if deque empty
if (result == null) {
return null;
}
elements[h] = null; // Must null out slot
head = h + 1 & elements.length - 1;
return result;
}
@Override
public T peek() {
ensureAccessible();
return elements[head]; // elements[head] is null if deque empty
}
@Override
public boolean remove(Object o) {
if (o == null) {
return false;
}
ensureAccessible();
int mask = elements.length - 1;
int i = head;
T x;
while ((x = elements[i]) != null) {
if (o.equals(x)) {
delete(i);
return true;
}
i = i + 1 & mask;
}
return false;
}
private boolean delete(int i) {
assert elements[tail] == null;
assert head == tail ? elements[head] == null
: elements[head] != null && elements[tail - 1 & elements.length - 1] != null;
assert elements[head - 1 & elements.length - 1] == null;
final T[] elements = this.elements;
final int mask = elements.length - 1;
final int h = head;
final int t = tail;
final int front = i - h & mask;
final int back = t - i & mask;
// Invariant: head <= i < tail mod circularity
if (front >= (t - h & mask)) {
throw new ConcurrentModificationException();
}
// Optimize for least element motion
if (front < back) {
if (h <= i) {
System.arraycopy(elements, h, elements, h + 1, front);
} else { // Wrap around
System.arraycopy(elements, 0, elements, 1, i);
elements[0] = elements[mask];
System.arraycopy(elements, h, elements, h + 1, mask - h);
}
elements[h] = null;
head = h + 1 & mask;
return false;
} else {
if (i < t) { // Copy the null tail as well
System.arraycopy(elements, i + 1, elements, i, back);
tail = t - 1;
} else { // Wrap around
System.arraycopy(elements, i + 1, elements, i, mask - i);
elements[mask] = elements[0];
System.arraycopy(elements, 1, elements, 0, t);
tail = t - 1 & mask;
}
return true;
}
}
@Override
public int size() {
return tail - head & elements.length - 1;
}
@Override
public boolean isEmpty() {
return head == tail;
}
@Override
public Iterator<T> iterator() {
ensureAccessible();
return new Itr();
}
@Override
public boolean contains(Object o) {
if (o == null) {
return false;
}
ensureAccessible();
final int mask = elements.length - 1;
int i = head;
Object e;
while ((e = elements[i]) != null) {
if (o.equals(e)) {
return true;
}
i = i + 1 & mask;
}
return false;
}
@Override
public void clear() {
ensureAccessible();
int head = this.head;
int tail = this.tail;
if (head != tail) {
this.head = this.tail = 0;
final int mask = elements.length - 1;
int i = head;
do {
elements[i] = null;
i = i + 1 & mask;
} while (i != tail);
}
}
@Override
public Object[] toArray() {
ensureAccessible();
return copyElements(new Object[size()]);
}
@Override
public <T> T[] toArray(T[] a) {
ensureAccessible();
int size = size();
if (a.length < size) {
a = cast(Array.newInstance(a.getClass().getComponentType(), size));
}
copyElements(a);
if (a.length > size) {
a[size] = null;
}
return a;
}
private <U> U[] copyElements(U[] a) {
if (head < tail) {
System.arraycopy(elements, head, cast(a), 0, size());
} else if (head > tail) {
int headPortionLen = elements.length - head;
System.arraycopy(elements, head, cast(a), 0, headPortionLen);
System.arraycopy(elements, 0, cast(a), headPortionLen, tail);
}
return a;
}
@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
private static <T> T[] cast(Object a) {
return (T[]) a;
}
private class Itr implements Iterator<T> {
private int cursor = head;
private int fence = tail;
private int lastRet = -1;
@Override
public boolean hasNext() {
ensureAccessible();
return cursor != fence;
}
@Override
public T next() {
ensureAccessible();
if (cursor == fence) {
throw new NoSuchElementException();
}
T result = elements[cursor];
// This check doesn't catch all possible comodifications,
// but does catch the ones that corrupt traversal
if (tail != fence || result == null) {
throw new ConcurrentModificationException();
}
lastRet = cursor;
cursor = cursor + 1 & elements.length - 1;
return result;
}
@Override
public void remove() {
ensureAccessible();
if (lastRet < 0) {
throw new IllegalStateException();
}
if (delete(lastRet)) { // if left-shifted, undo increment in next()
cursor = cursor - 1 & elements.length - 1;
fence = tail;
}
lastRet = -1;
}
}
}

View File

@ -800,16 +800,6 @@ public final class EmptyByteBuf implements ByteBuf {
return toString(charset);
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
return this;
}
@Override
public int hashCode() {
return 0;
@ -830,11 +820,6 @@ public final class EmptyByteBuf implements ByteBuf {
return str;
}
@Override
public BufType type() {
return BufType.BYTE;
}
@Override
public boolean isReadable(int size) {
checkLength(size);

View File

@ -1,229 +0,0 @@
/*
* Copyright 2013 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.buffer;
import java.util.Collection;
import java.util.Iterator;
public abstract class FilteredMessageBuf implements MessageBuf<Object> {
protected final MessageBuf<Object> buf;
@SuppressWarnings("unchecked")
protected FilteredMessageBuf(MessageBuf<?> buf) {
if (buf == null) {
throw new NullPointerException("buf");
}
this.buf = (MessageBuf<Object>) buf;
}
protected abstract Object filter(Object msg);
@Override
public int drainTo(Collection<? super Object> c) {
return buf.drainTo(c);
}
@Override
public int drainTo(Collection<? super Object> c, int maxElements) {
return buf.drainTo(c, maxElements);
}
@Override
public BufType type() {
return buf.type();
}
@Override
public int maxCapacity() {
return buf.maxCapacity();
}
@Override
public boolean isReadable() {
return buf.isReadable();
}
@Override
public boolean isReadable(int size) {
return buf.isReadable(size);
}
@Override
public boolean isWritable() {
return buf.isWritable();
}
@Override
public boolean isWritable(int size) {
return buf.isWritable(size);
}
@Override
public boolean add(Object e) {
if (e == null) {
throw new NullPointerException("e");
}
e = filter(e);
ensureNonNull(e);
return buf.add(e);
}
@Override
public boolean offer(Object e) {
if (e == null) {
throw new NullPointerException("e");
}
e = filter(e);
ensureNonNull(e);
return buf.offer(e);
}
private void ensureNonNull(Object e) {
if (e == null) {
throw new IllegalStateException(getClass().getSimpleName() + ".filter() returned null");
}
}
@Override
public Object remove() {
return buf.remove();
}
@Override
public Object poll() {
return buf.poll();
}
@Override
public Object element() {
return buf.element();
}
@Override
public Object peek() {
return buf.peek();
}
@Override
public int size() {
return buf.size();
}
@Override
public boolean isEmpty() {
return buf.isEmpty();
}
@Override
public boolean contains(Object o) {
return buf.contains(o);
}
@Override
public Iterator<Object> iterator() {
return buf.iterator();
}
@Override
public Object[] toArray() {
return buf.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return buf.toArray(a);
}
@Override
public boolean remove(Object o) {
return buf.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return buf.containsAll(c);
}
@Override
public boolean addAll(Collection<?> c) {
int i = 0;
boolean added = false;
for (Object e: c) {
if (e == null) {
throw new NullPointerException("c[" + i + ']');
}
e = filter(e);
ensureNonNull(e);
added |= buf.add(e);
}
return added;
}
@Override
public boolean removeAll(Collection<?> c) {
return buf.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return buf.retainAll(c);
}
@Override
public void clear() {
buf.clear();
}
@Override
public int refCnt() {
return buf.refCnt();
}
@Override
public MessageBuf<Object> retain() {
buf.retain();
return this;
}
@Override
public MessageBuf<Object> retain(int increment) {
buf.retain(increment);
return this;
}
@Override
public boolean release() {
return buf.release();
}
@Override
public boolean release(int decrement) {
return buf.release(decrement);
}
@Override
public String toString() {
return getClass().getSimpleName() + '(' + buf + ')';
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright 2012 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.buffer;
import java.util.Collection;
import java.util.Queue;
/**
* Buf which operates on messages.
*
* @param <T> the type of the messages that are hold by this {@link MessageBuf}
*/
public interface MessageBuf<T> extends Buf, Queue<T> {
/**
* Drain the content of the {@link MessageBuf} to the given {@link Collection}.
*
* @param c the {@link Collection} to drain the content to
* @return number the number of objects which was transfered
*/
int drainTo(Collection<? super T> c);
/**
* Drain the content of the {@link MessageBuf} to the given {@link Collection}.
*
* @param c the {@link Collection} to drain the content to
* @param maxElements the max number of elements to drain
* @return number the number of objects which was transfered
*/
int drainTo(Collection<? super T> c, int maxElements);
@Override
MessageBuf<T> retain(int increment);
@Override
MessageBuf<T> retain();
}

View File

@ -20,8 +20,6 @@ import io.netty.util.ResourceLeak;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayDeque;
import java.util.Queue;
abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
@ -35,7 +33,6 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
private int maxLength;
private ByteBuffer tmpNioBuf;
private Queue<Allocation<T>> suspendedDeallocations;
protected PooledByteBuf(int maxCapacity) {
super(maxCapacity);
@ -108,13 +105,7 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
}
// Reallocation required.
if (suspendedDeallocations == null) {
chunk.arena.reallocate(this, newCapacity, true);
} else {
Allocation<T> old = new Allocation<T>(chunk, handle);
chunk.arena.reallocate(this, newCapacity, false);
suspendedDeallocations.add(old);
}
return this;
}
@ -143,38 +134,9 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
protected abstract ByteBuffer newInternalNioBuffer(T memory);
@Override
public final ByteBuf suspendIntermediaryDeallocations() {
ensureAccessible();
if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque<Allocation<T>>(2);
}
return this;
}
@Override
public final ByteBuf resumeIntermediaryDeallocations() {
if (suspendedDeallocations == null) {
return this;
}
Queue<Allocation<T>> suspendedDeallocations = this.suspendedDeallocations;
this.suspendedDeallocations = null;
if (suspendedDeallocations.isEmpty()) {
return this;
}
for (Allocation<T> a: suspendedDeallocations) {
a.chunk.arena.free(a.chunk, a.handle);
}
return this;
}
@Override
protected final void deallocate() {
if (handle >= 0) {
resumeIntermediaryDeallocations();
final long handle = this.handle;
this.handle = -1;
memory = null;
@ -186,14 +148,4 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
protected final int idx(int index) {
return offset + index;
}
private static final class Allocation<T> {
final PoolChunk<T> chunk;
final long handle;
Allocation(PoolChunk<T> chunk, long handle) {
this.chunk = chunk;
this.handle = handle;
}
}
}

View File

@ -1,132 +0,0 @@
/*
* Copyright 2012 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.buffer;
import java.util.Collection;
import java.util.Iterator;
import java.util.Queue;
final class QueueBackedMessageBuf<T> extends AbstractMessageBuf<T> {
private Queue<T> queue;
QueueBackedMessageBuf(Queue<T> queue) {
super(Integer.MAX_VALUE);
if (queue == null) {
throw new NullPointerException("queue");
}
this.queue = queue;
}
@Override
public boolean offer(T e) {
if (e == null) {
throw new NullPointerException("e");
}
ensureAccessible();
return isWritable() && queue.offer(e);
}
@Override
public T poll() {
ensureAccessible();
return queue.poll();
}
@Override
public T peek() {
ensureAccessible();
return queue.peek();
}
@Override
public int size() {
return queue.size();
}
@Override
public boolean isEmpty() {
return queue.isEmpty();
}
@Override
public boolean contains(Object o) {
ensureAccessible();
return queue.contains(o);
}
@Override
public Iterator<T> iterator() {
ensureAccessible();
return queue.iterator();
}
@Override
public Object[] toArray() {
ensureAccessible();
return queue.toArray();
}
@Override
public <E> E[] toArray(E[] a) {
ensureAccessible();
return queue.toArray(a);
}
@Override
public boolean remove(Object o) {
ensureAccessible();
return queue.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
ensureAccessible();
return queue.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends T> c) {
ensureAccessible();
return isWritable(c.size()) && queue.addAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
ensureAccessible();
return queue.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
ensureAccessible();
return queue.retainAll(c);
}
@Override
public void clear() {
ensureAccessible();
queue.clear();
}
@Override
protected void deallocate() {
for (T e: queue) {
BufUtil.release(e);
}
queue = null;
}
}

View File

@ -316,14 +316,4 @@ class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
public long memoryAddress() {
throw new UnsupportedOperationException();
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
return this;
}
}

View File

@ -67,11 +67,6 @@ public final class SwappedByteBuf implements ByteBuf {
return buf.alloc();
}
@Override
public BufType type() {
return BufType.MESSAGE;
}
@Override
public int capacity() {
return buf.capacity();
@ -245,7 +240,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public short getShort(int index) {
return BufUtil.swapShort(buf.getShort(index));
return ByteBufUtil.swapShort(buf.getShort(index));
}
@Override
@ -255,7 +250,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public int getMedium(int index) {
return BufUtil.swapMedium(buf.getMedium(index));
return ByteBufUtil.swapMedium(buf.getMedium(index));
}
@Override
@ -265,7 +260,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public int getInt(int index) {
return BufUtil.swapInt(buf.getInt(index));
return ByteBufUtil.swapInt(buf.getInt(index));
}
@Override
@ -275,7 +270,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public long getLong(int index) {
return BufUtil.swapLong(buf.getLong(index));
return ByteBufUtil.swapLong(buf.getLong(index));
}
@Override
@ -354,25 +349,25 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public ByteBuf setShort(int index, int value) {
buf.setShort(index, BufUtil.swapShort((short) value));
buf.setShort(index, ByteBufUtil.swapShort((short) value));
return this;
}
@Override
public ByteBuf setMedium(int index, int value) {
buf.setMedium(index, BufUtil.swapMedium(value));
buf.setMedium(index, ByteBufUtil.swapMedium(value));
return this;
}
@Override
public ByteBuf setInt(int index, int value) {
buf.setInt(index, BufUtil.swapInt(value));
buf.setInt(index, ByteBufUtil.swapInt(value));
return this;
}
@Override
public ByteBuf setLong(int index, long value) {
buf.setLong(index, BufUtil.swapLong(value));
buf.setLong(index, ByteBufUtil.swapLong(value));
return this;
}
@ -463,7 +458,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public short readShort() {
return BufUtil.swapShort(buf.readShort());
return ByteBufUtil.swapShort(buf.readShort());
}
@Override
@ -473,7 +468,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public int readMedium() {
return BufUtil.swapMedium(buf.readMedium());
return ByteBufUtil.swapMedium(buf.readMedium());
}
@Override
@ -483,7 +478,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public int readInt() {
return BufUtil.swapInt(buf.readInt());
return ByteBufUtil.swapInt(buf.readInt());
}
@Override
@ -493,7 +488,7 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public long readLong() {
return BufUtil.swapLong(buf.readLong());
return ByteBufUtil.swapLong(buf.readLong());
}
@Override
@ -588,25 +583,25 @@ public final class SwappedByteBuf implements ByteBuf {
@Override
public ByteBuf writeShort(int value) {
buf.writeShort(BufUtil.swapShort((short) value));
buf.writeShort(ByteBufUtil.swapShort((short) value));
return this;
}
@Override
public ByteBuf writeMedium(int value) {
buf.writeMedium(BufUtil.swapMedium(value));
buf.writeMedium(ByteBufUtil.swapMedium(value));
return this;
}
@Override
public ByteBuf writeInt(int value) {
buf.writeInt(BufUtil.swapInt(value));
buf.writeInt(ByteBufUtil.swapInt(value));
return this;
}
@Override
public ByteBuf writeLong(long value) {
buf.writeLong(BufUtil.swapLong(value));
buf.writeLong(ByteBufUtil.swapLong(value));
return this;
}
@ -813,18 +808,6 @@ public final class SwappedByteBuf implements ByteBuf {
return buf.toString(index, length, charset);
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
buf.suspendIntermediaryDeallocations();
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
buf.resumeIntermediaryDeallocations();
return this;
}
@Override
public int refCnt() {
return buf.refCnt();
@ -863,14 +846,14 @@ public final class SwappedByteBuf implements ByteBuf {
return true;
}
if (obj instanceof ByteBuf) {
return BufUtil.equals(this, (ByteBuf) obj);
return ByteBufUtil.equals(this, (ByteBuf) obj);
}
return false;
}
@Override
public int compareTo(ByteBuf buffer) {
return BufUtil.compare(this, buffer);
return ByteBufUtil.compare(this, buffer);
}
@Override

View File

@ -23,11 +23,10 @@ import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
/**
* Creates a new {@link ByteBuf} or a new {@link MessageBuf} by allocating new space or by wrapping
* Creates a new {@link ByteBuf} by allocating new space or by wrapping
* or copying existing byte arrays, byte buffers and a string.
*
* <h3>Use static import</h3>
@ -94,39 +93,6 @@ public final class Unpooled {
*/
public static final ByteBuf EMPTY_BUFFER = ALLOC.buffer(0, 0);
/**
* Creates a new {@link MessageBuf} with reasonably small initial capacity, which
* expands its capacity boundlessly on demand.
*/
public static <T> MessageBuf<T> messageBuffer() {
return new DefaultMessageBuf<T>();
}
/**
* Creates a new {@link MessageBuf} with the specified {@code initialCapacity}.
*/
public static <T> MessageBuf<T> messageBuffer(int initialCapacity) {
return new DefaultMessageBuf<T>(initialCapacity);
}
/**
* Creates a new {@link MessageBuf} with the specified {@code initialCapacity} and
* {@code maxCapacity}.
*/
public static <T> MessageBuf<T> messageBuffer(int initialCapacity, int maxCapacity) {
return new DefaultMessageBuf<T>(initialCapacity, maxCapacity);
}
/**
* Creates a new {@link MessageBuf} which wraps the given {@code queue}.
*/
public static <T> MessageBuf<T> wrappedBuffer(Queue<T> queue) {
if (queue instanceof MessageBuf) {
return (MessageBuf<T>) queue;
}
return new QueueBackedMessageBuf<T>(queue);
}
/**
* Creates a new big-endian Java heap buffer with reasonably small initial capacity, which
* expands its capacity boundlessly on demand.
@ -681,7 +647,7 @@ public final class Unpooled {
}
private static ByteBuf copiedBuffer(CharBuffer buffer, Charset charset) {
ByteBuffer dst = BufUtil.encodeString(buffer, charset);
ByteBuffer dst = ByteBufUtil.encodeString(buffer, charset);
ByteBuf result = wrappedBuffer(dst.array());
result.writerIndex(dst.remaining());
return result;

View File

@ -26,8 +26,6 @@ import java.nio.ByteOrder;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.util.ArrayDeque;
import java.util.Queue;
/**
* A NIO {@link ByteBuffer} based buffer. It is recommended to use {@link Unpooled#directBuffer(int)}
@ -43,7 +41,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
private ByteBuffer tmpNioBuf;
private int capacity;
private boolean doNotFree;
private Queue<ByteBuffer> suspendedDeallocations;
/**
* Creates a new direct buffer.
@ -111,11 +108,7 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
if (doNotFree) {
doNotFree = false;
} else {
if (suspendedDeallocations == null) {
PlatformDependent.freeDirectBuffer(oldBuffer);
} else {
suspendedDeallocations.add(oldBuffer);
}
}
}
@ -527,37 +520,12 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
this.buffer = null;
resumeIntermediaryDeallocations();
if (!doNotFree) {
PlatformDependent.freeDirectBuffer(buffer);
}
leak.close();
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
ensureAccessible();
if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque<ByteBuffer>(2);
}
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
if (suspendedDeallocations == null) {
return this;
}
Queue<ByteBuffer> suspendedDeallocations = this.suspendedDeallocations;
this.suspendedDeallocations = null;
for (ByteBuffer buf: suspendedDeallocations) {
PlatformDependent.freeDirectBuffer(buf);
}
return this;
}
@Override
public ByteBuf unwrap() {
return null;

View File

@ -417,16 +417,6 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
array = null;
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
return this;
}
@Override
public ByteBuf unwrap() {
return null;

View File

@ -26,8 +26,6 @@ import java.nio.ByteOrder;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.util.ArrayDeque;
import java.util.Queue;
/**
* A NIO {@link ByteBuffer} based buffer. It is recommended to use {@link Unpooled#directBuffer(int)}
@ -46,7 +44,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
private ByteBuffer tmpNioBuf;
private int capacity;
private boolean doNotFree;
private Queue<ByteBuffer> suspendedDeallocations;
/**
* Creates a new direct buffer.
@ -114,11 +111,7 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
if (doNotFree) {
doNotFree = false;
} else {
if (suspendedDeallocations == null) {
PlatformDependent.freeDirectBuffer(oldBuffer);
} else {
suspendedDeallocations.add(oldBuffer);
}
}
}
@ -459,37 +452,12 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
this.buffer = null;
resumeIntermediaryDeallocations();
if (!doNotFree) {
PlatformDependent.freeDirectBuffer(buffer);
}
leak.close();
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
ensureAccessible();
if (suspendedDeallocations == null) {
suspendedDeallocations = new ArrayDeque<ByteBuffer>(2);
}
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
if (suspendedDeallocations == null) {
return this;
}
Queue<ByteBuffer> suspendedDeallocations = this.suspendedDeallocations;
this.suspendedDeallocations = null;
for (ByteBuffer buf: suspendedDeallocations) {
PlatformDependent.freeDirectBuffer(buf);
}
return this;
}
@Override
public ByteBuf unwrap() {
return null;

View File

@ -796,18 +796,6 @@ final class UnreleasableByteBuf implements ByteBuf {
return buf.toString(index, length, charset);
}
@Override
public ByteBuf suspendIntermediaryDeallocations() {
buf.suspendIntermediaryDeallocations();
return this;
}
@Override
public ByteBuf resumeIntermediaryDeallocations() {
buf.resumeIntermediaryDeallocations();
return this;
}
@Override
public int hashCode() {
return buf.hashCode();
@ -838,11 +826,6 @@ final class UnreleasableByteBuf implements ByteBuf {
return this;
}
@Override
public BufType type() {
return buf.type();
}
@Override
public boolean isReadable(int size) {
return buf.isReadable(size);

View File

@ -142,20 +142,20 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
a.writerIndex(a.writerIndex() + 1);
b.writerIndex(b.writerIndex() + 1);
assertEquals(a.writerIndex(), b.writerIndex());
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// now discard
a.discardReadBytes();
b.discardReadBytes();
assertEquals(a.readerIndex(), b.readerIndex());
assertEquals(a.writerIndex(), b.writerIndex());
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
a.resetReaderIndex();
b.resetReaderIndex();
assertEquals(a.readerIndex(), b.readerIndex());
a.resetWriterIndex();
b.resetWriterIndex();
assertEquals(a.writerIndex(), b.writerIndex());
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
}
@Test
@ -231,7 +231,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
b = freeLater(wrappedBuffer(
wrappedBuffer(new byte[] { 1 }).order(order),
wrappedBuffer(new byte[] { 2 }).order(order)));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Same content, same firstIndex, short length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
@ -239,28 +239,28 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
wrappedBuffer(new byte[]{1}).order(order),
wrappedBuffer(new byte[]{2}).order(order),
wrappedBuffer(new byte[]{3}).order(order)));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Same content, different firstIndex, short length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
b = freeLater(wrappedBuffer(
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 1, 2).order(order),
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 3, 1).order(order)));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Different content, same firstIndex, short length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
b = freeLater(wrappedBuffer(
wrappedBuffer(new byte[] { 1, 2 }).order(order),
wrappedBuffer(new byte[] { 4 }).order(order)));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Different content, different firstIndex, short length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
b = freeLater(wrappedBuffer(
wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 1, 2).order(order),
wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 3, 1).order(order)));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Same content, same firstIndex, long length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order));
@ -268,28 +268,28 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
wrappedBuffer(new byte[] { 1, 2, 3 }).order(order),
wrappedBuffer(new byte[] { 4, 5, 6 }).order(order),
wrappedBuffer(new byte[] { 7, 8, 9, 10 }).order(order)));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Same content, different firstIndex, long length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order));
b = freeLater(wrappedBuffer(
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 5).order(order),
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5).order(order)));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Different content, same firstIndex, long length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order));
b = freeLater(wrappedBuffer(
wrappedBuffer(new byte[] { 1, 2, 3, 4, 6 }).order(order),
wrappedBuffer(new byte[] { 7, 8, 5, 9, 10 }).order(order)));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Different content, different firstIndex, long length.
a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order));
b = freeLater(wrappedBuffer(
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 5).order(order),
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5).order(order)));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
}
@Test
@ -345,7 +345,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
// to enable writeBytes
b.writerIndex(b.writerIndex() - 1);
b.writeBytes(wrappedBuffer(new byte[] { 2 }).order(order));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Same content, same firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
@ -354,7 +354,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
b.writerIndex(b.writerIndex() - 2);
b.writeBytes(wrappedBuffer(new byte[] { 2 }).order(order));
b.writeBytes(wrappedBuffer(new byte[] { 3 }).order(order));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Same content, different firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
@ -362,7 +362,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
// to enable writeBytes
b.writerIndex(b.writerIndex() - 1);
b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 3, 1).order(order));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Different content, same firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
@ -370,7 +370,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
// to enable writeBytes
b.writerIndex(b.writerIndex() - 1);
b.writeBytes(wrappedBuffer(new byte[] { 4 }).order(order));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Different content, different firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
@ -378,7 +378,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
// to enable writeBytes
b.writerIndex(b.writerIndex() - 1);
b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 3, 1).order(order));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Same content, same firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
@ -387,7 +387,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
b.writerIndex(b.writerIndex() - 7);
b.writeBytes(wrappedBuffer(new byte[] { 4, 5, 6 }).order(order));
b.writeBytes(wrappedBuffer(new byte[] { 7, 8, 9, 10 }).order(order));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Same content, different firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
@ -395,7 +395,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
// to enable writeBytes
b.writerIndex(b.writerIndex() - 5);
b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5).order(order));
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Different content, same firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
@ -403,7 +403,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
// to enable writeBytes
b.writerIndex(b.writerIndex() - 5);
b.writeBytes(wrappedBuffer(new byte[] { 7, 8, 5, 9, 10 }).order(order));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Different content, different firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
@ -411,7 +411,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
// to enable writeBytes
b.writerIndex(b.writerIndex() - 5);
b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5).order(order));
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
}
@Test

View File

@ -97,7 +97,7 @@ public class UnpooledTest {
for (Entry<byte[], Integer> e: map.entrySet()) {
assertEquals(
e.getValue().intValue(),
BufUtil.hashCode(wrappedBuffer(e.getKey())));
ByteBufUtil.hashCode(wrappedBuffer(e.getKey())));
}
}
@ -108,47 +108,47 @@ public class UnpooledTest {
// Different length.
a = wrappedBuffer(new byte[] { 1 });
b = wrappedBuffer(new byte[] { 1, 2 });
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Same content, same firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 });
b = wrappedBuffer(new byte[] { 1, 2, 3 });
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Same content, different firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 });
b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 1, 3);
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Different content, same firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 });
b = wrappedBuffer(new byte[] { 1, 2, 4 });
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Different content, different firstIndex, short length.
a = wrappedBuffer(new byte[] { 1, 2, 3 });
b = wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 1, 3);
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Same content, same firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
b = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Same content, different firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 10);
assertTrue(BufUtil.equals(a, b));
assertTrue(ByteBufUtil.equals(a, b));
// Different content, same firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
b = wrappedBuffer(new byte[] { 1, 2, 3, 4, 6, 7, 8, 5, 9, 10 });
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
// Different content, different firstIndex, long length.
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 10);
assertFalse(BufUtil.equals(a, b));
assertFalse(ByteBufUtil.equals(a, b));
}
@Test
@ -174,11 +174,11 @@ public class UnpooledTest {
for (int i = 0; i < expected.size(); i ++) {
for (int j = 0; j < expected.size(); j ++) {
if (i == j) {
assertEquals(0, BufUtil.compare(expected.get(i), expected.get(j)));
assertEquals(0, ByteBufUtil.compare(expected.get(i), expected.get(j)));
} else if (i < j) {
assertTrue(BufUtil.compare(expected.get(i), expected.get(j)) < 0);
assertTrue(ByteBufUtil.compare(expected.get(i), expected.get(j)) < 0);
} else {
assertTrue(BufUtil.compare(expected.get(i), expected.get(j)) > 0);
assertTrue(ByteBufUtil.compare(expected.get(i), expected.get(j)) > 0);
}
}
}
@ -217,12 +217,12 @@ public class UnpooledTest {
@Test
public void testCompare2() {
assertTrue(BufUtil.compare(
assertTrue(ByteBufUtil.compare(
wrappedBuffer(new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}),
wrappedBuffer(new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}))
> 0);
assertTrue(BufUtil.compare(
assertTrue(ByteBufUtil.compare(
wrappedBuffer(new byte[]{(byte) 0xFF}),
wrappedBuffer(new byte[]{(byte) 0x00}))
> 0);
@ -327,14 +327,14 @@ public class UnpooledTest {
@Test
public void testHexDump() {
assertEquals("", BufUtil.hexDump(EMPTY_BUFFER));
assertEquals("", ByteBufUtil.hexDump(EMPTY_BUFFER));
assertEquals("123456", BufUtil.hexDump(wrappedBuffer(
assertEquals("123456", ByteBufUtil.hexDump(wrappedBuffer(
new byte[]{
0x12, 0x34, 0x56
})));
assertEquals("1234567890abcdef", BufUtil.hexDump(wrappedBuffer(
assertEquals("1234567890abcdef", ByteBufUtil.hexDump(wrappedBuffer(
new byte[]{
0x12, 0x34, 0x56, 0x78,
(byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF
@ -343,8 +343,8 @@ public class UnpooledTest {
@Test
public void testSwapMedium() {
assertEquals(0x563412, BufUtil.swapMedium(0x123456));
assertEquals(0x80, BufUtil.swapMedium(0x800000));
assertEquals(0x563412, ByteBufUtil.swapMedium(0x123456));
assertEquals(0x80, ByteBufUtil.swapMedium(0x800000));
}
@Test

View File

@ -20,7 +20,7 @@
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>4.0.0.Final-SNAPSHOT</version>
<version>4.0.0.CR4-SNAPSHOT</version>
</parent>
<artifactId>netty-codec-http</artifactId>

View File

@ -16,13 +16,10 @@
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.FilteredMessageBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.CombinedChannelDuplexHandler;
import io.netty.channel.MessageList;
import io.netty.handler.codec.PrematureChannelClosureException;
import java.util.ArrayDeque;
@ -44,8 +41,7 @@ import java.util.concurrent.atomic.AtomicLong;
* @see HttpServerCodec
*/
public final class HttpClientCodec
extends CombinedChannelDuplexHandler
implements ChannelInboundByteHandler, ChannelOutboundMessageHandler<HttpObject> {
extends CombinedChannelDuplexHandler<HttpResponseDecoder, HttpRequestEncoder> {
/** A queue that is used for correlating a request and a response. */
private final Queue<HttpMethod> queue = new ArrayDeque<HttpMethod>();
@ -66,11 +62,11 @@ public final class HttpClientCodec
}
public void setSingleDecode(boolean singleDecode) {
decoder().setSingleDecode(singleDecode);
inboundHandler().setSingleDecode(singleDecode);
}
public boolean isSingleDecode() {
return decoder().isSingleDecode();
return inboundHandler().isSingleDecode();
}
/**
@ -86,29 +82,6 @@ public final class HttpClientCodec
this.failOnMissingResponse = failOnMissingResponse;
}
private Decoder decoder() {
return (Decoder) stateHandler();
}
private Encoder encoder() {
return (Encoder) operationHandler();
}
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return decoder().newInboundBuffer(ctx);
}
@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
decoder().discardInboundReadBytes(ctx);
}
@Override
public MessageBuf<HttpObject> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return encoder().newOutboundBuffer(ctx);
}
private final class Encoder extends HttpRequestEncoder {
@Override
@ -137,7 +110,7 @@ public final class HttpClientCodec
@Override
protected void decode(
ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf<Object> out) throws Exception {
ChannelHandlerContext ctx, ByteBuf buffer, MessageList<Object> out) throws Exception {
if (done) {
int readable = actualReadableBytes();
if (readable == 0) {
@ -147,16 +120,14 @@ public final class HttpClientCodec
}
out.add(buffer.readBytes(readable));
} else {
if (failOnMissingResponse) {
out = new FilteredMessageBuf(out) {
@Override
protected Object filter(Object msg) {
decrement(msg);
return msg;
}
};
}
int oldSize = out.size();
super.decode(ctx, buffer, out);
if (failOnMissingResponse) {
int size = out.size();
for (int i = oldSize; i < size; i++) {
decrement(out.get(i));
}
}
}
}

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.http;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.util.internal.StringUtil;
@ -119,7 +119,7 @@ public class HttpContentCompressor extends HttpContentEncoder {
return new Result(
targetContentEncoding,
new EmbeddedByteChannel(ZlibCodecFactory.newZlibEncoder(
new EmbeddedChannel(ZlibCodecFactory.newZlibEncoder(
wrapper, compressionLevel, windowBits, memLevel)));
}

View File

@ -15,21 +15,19 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.BufUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.MessageList;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.util.Collections;
/**
* Decodes the content of the received {@link HttpRequest} and {@link HttpContent}.
* The original content is replaced with the new content decoded by the
* {@link EmbeddedByteChannel}, which is created by {@link #newContentDecoder(String)}.
* {@link EmbeddedChannel}, which is created by {@link #newContentDecoder(String)}.
* Once decoding is finished, the value of the <tt>'Content-Encoding'</tt>
* header is set to the target content encoding, as returned by {@link #getTargetContentEncoding(String)}.
* Also, the <tt>'Content-Length'</tt> header is updated to the length of the
@ -47,20 +45,20 @@ import java.util.Collections;
*/
public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObject> {
private EmbeddedByteChannel decoder;
private EmbeddedChannel decoder;
private HttpMessage message;
private boolean decodeStarted;
private boolean continueResponse;
@Override
protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageList<Object> out) throws Exception {
if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().code() == 100) {
if (!(msg instanceof LastHttpContent)) {
continueResponse = true;
}
// 100-continue response must be passed through.
out.add(BufUtil.retain(msg));
out.add(ByteBufUtil.retain(msg));
return;
}
@ -69,7 +67,7 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
continueResponse = false;
}
// 100-continue response must be passed through.
out.add(BufUtil.retain(msg));
out.add(ByteBufUtil.retain(msg));
return;
}
@ -117,8 +115,7 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
HttpHeaders.Names.CONTENT_LENGTH,
Integer.toString(((ByteBufHolder) decoded[1]).content().readableBytes()));
}
Collections.addAll(out, decoded);
out.add(decoded);
return;
}
@ -131,7 +128,7 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
}
if (decoder != null) {
Collections.addAll(out, decodeContent(null, c));
out.add(decodeContent(null, c));
} else {
if (c instanceof LastHttpContent) {
decodeStarted = false;
@ -175,15 +172,15 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
}
/**
* Returns a new {@link EmbeddedByteChannel} that decodes the HTTP message
* Returns a new {@link EmbeddedChannel} that decodes the HTTP message
* content encoded in the specified <tt>contentEncoding</tt>.
*
* @param contentEncoding the value of the {@code "Content-Encoding"} header
* @return a new {@link EmbeddedByteChannel} if the specified encoding is supported.
* @return a new {@link EmbeddedChannel} if the specified encoding is supported.
* {@code null} otherwise (alternatively, you can throw an exception
* to block unknown encoding).
*/
protected abstract EmbeddedByteChannel newContentDecoder(String contentEncoding) throws Exception;
protected abstract EmbeddedChannel newContentDecoder(String contentEncoding) throws Exception;
/**
* Returns the expected content encoding of the decoded content.

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.http;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
@ -26,13 +26,13 @@ import io.netty.handler.codec.compression.ZlibWrapper;
*/
public class HttpContentDecompressor extends HttpContentDecoder {
@Override
protected EmbeddedByteChannel newContentDecoder(String contentEncoding) throws Exception {
protected EmbeddedChannel newContentDecoder(String contentEncoding) throws Exception {
if ("gzip".equalsIgnoreCase(contentEncoding) || "x-gzip".equalsIgnoreCase(contentEncoding)) {
return new EmbeddedByteChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
return new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
}
if ("deflate".equalsIgnoreCase(contentEncoding) || "x-deflate".equalsIgnoreCase(contentEncoding)) {
// To be strict, 'deflate' means ZLIB, but some servers were not implemented correctly.
return new EmbeddedByteChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
return new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
}
// 'identity' or unsupported

View File

@ -15,25 +15,24 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.BufUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.MessageList;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Queue;
/**
* Encodes the content of the outbound {@link HttpResponse} and {@link HttpContent}.
* The original content is replaced with the new content encoded by the
* {@link EmbeddedByteChannel}, which is created by {@link #beginEncode(HttpResponse, String)}.
* {@link EmbeddedChannel}, which is created by {@link #beginEncode(HttpResponse, String)}.
* Once encoding is finished, the value of the <tt>'Content-Encoding'</tt> header
* is set to the target content encoding, as returned by
* {@link #beginEncode(HttpResponse, String)}.
@ -62,7 +61,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
private final Queue<String> acceptEncodingQueue = new ArrayDeque<String>();
private String acceptEncoding;
private EmbeddedByteChannel encoder;
private EmbeddedChannel encoder;
private State state = State.AWAIT_HEADERS;
@Override
@ -71,18 +70,18 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
}
@Override
protected void decode(ChannelHandlerContext ctx, HttpRequest msg, MessageBuf<Object> out)
protected void decode(ChannelHandlerContext ctx, HttpRequest msg, MessageList<Object> out)
throws Exception {
String acceptedEncoding = msg.headers().get(HttpHeaders.Names.ACCEPT_ENCODING);
if (acceptedEncoding == null) {
acceptedEncoding = HttpHeaders.Values.IDENTITY;
}
acceptEncodingQueue.add(acceptedEncoding);
out.add(BufUtil.retain(msg));
out.add(ByteBufUtil.retain(msg));
}
@Override
protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf<Object> out) throws Exception {
protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageList<Object> out) throws Exception {
final boolean isFull = msg instanceof HttpResponse && msg instanceof LastHttpContent;
switch (state) {
case AWAIT_HEADERS: {
@ -93,7 +92,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
if (res.getStatus().code() == 100) {
if (isFull) {
out.add(BufUtil.retain(res));
out.add(ByteBufUtil.retain(res));
} else {
out.add(res);
// Pass through all following contents.
@ -114,7 +113,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
// Set the content length to 0.
res.headers().remove(Names.TRANSFER_ENCODING);
res.headers().set(Names.CONTENT_LENGTH, "0");
out.add(BufUtil.retain(res));
out.add(ByteBufUtil.retain(res));
break;
}
}
@ -128,7 +127,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
// As an unchunked response
res.headers().remove(Names.TRANSFER_ENCODING);
res.headers().set(Names.CONTENT_LENGTH, ((ByteBufHolder) res).content().readableBytes());
out.add(BufUtil.retain(res));
out.add(ByteBufUtil.retain(res));
} else {
// As a chunked response
res.headers().remove(Names.CONTENT_LENGTH);
@ -165,7 +164,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
case AWAIT_CONTENT: {
ensureContent(msg);
HttpContent[] encoded = encodeContent((HttpContent) msg);
Collections.addAll(out, encoded);
out.add(encoded);
if (encoded[encoded.length - 1] instanceof LastHttpContent) {
state = State.AWAIT_HEADERS;
}
@ -173,7 +172,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
}
case PASS_THROUGH: {
ensureContent(msg);
out.add(BufUtil.retain(msg));
out.add(ByteBufUtil.retain(msg));
// Passed through all following contents of the current response.
if (msg instanceof LastHttpContent) {
state = State.AWAIT_HEADERS;
@ -235,7 +234,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
* the value of the {@code "Accept-Encoding"} header
*
* @return the result of preparation, which is composed of the determined
* target content encoding and a new {@link EmbeddedByteChannel} that
* target content encoding and a new {@link EmbeddedChannel} that
* encodes the content into the target content encoding.
* {@code null} if {@code acceptEncoding} is unsupported or rejected
* and thus the content should be handled as-is (i.e. no encoding).
@ -276,7 +275,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
private void fetchEncoderOutput(ByteBuf out) {
for (;;) {
ByteBuf buf = encoder.readOutbound();
ByteBuf buf = (ByteBuf) encoder.readOutbound();
if (buf == null) {
break;
}
@ -286,9 +285,9 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
public static final class Result {
private final String targetContentEncoding;
private final EmbeddedByteChannel contentEncoder;
private final EmbeddedChannel contentEncoder;
public Result(String targetContentEncoding, EmbeddedByteChannel contentEncoder) {
public Result(String targetContentEncoding, EmbeddedChannel contentEncoder) {
if (targetContentEncoding == null) {
throw new NullPointerException("targetContentEncoding");
}
@ -304,7 +303,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
return targetContentEncoding;
}
public EmbeddedByteChannel contentEncoder() {
public EmbeddedChannel contentEncoder() {
return contentEncoder;
}
}

View File

@ -15,14 +15,14 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.BufUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.MessageList;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -108,7 +108,7 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
}
@Override
protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageList<Object> out) throws Exception {
FullHttpMessage currentMessage = this.currentMessage;
if (msg instanceof HttpMessage) {
@ -129,7 +129,7 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
if (!m.getDecoderResult().isSuccess()) {
removeTransferEncodingChunked(m);
this.currentMessage = null;
out.add(BufUtil.retain(m));
out.add(ByteBufUtil.retain(m));
return;
}
if (msg instanceof HttpRequest) {

View File

@ -16,10 +16,10 @@
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.MessageList;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -168,7 +168,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageList<Object> out) throws Exception {
switch (state()) {
case SKIP_CONTROL_CHARS: {
try {
@ -449,7 +449,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
private void reset() {
reset(null);
}
private void reset(MessageBuf<Object> out) {
private void reset(MessageList<Object> out) {
if (out != null) {
HttpMessage message = this.message;
ByteBuf content = this.content;
@ -500,7 +500,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
}
}
private void readFixedLengthContent(ByteBuf buffer, MessageBuf<Object> out) {
private void readFixedLengthContent(ByteBuf buffer, MessageList<Object> out) {
//we have a content-length so we just read the correct number of bytes
long length = HttpHeaders.getContentLength(message, -1);
assert length <= Integer.MAX_VALUE;

View File

@ -40,7 +40,7 @@ import static io.netty.handler.codec.http.HttpConstants.*;
*/
public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageToByteEncoder<HttpObject> {
private static final byte[] CRLF = { CR, LF };
private static final byte[] CRLF_END = { CR, LF, 0 };
private static final byte[] ZERO_CRLF = { '0', CR, LF };
private static final byte[] HEADER_SEPARATOR = { COLON , SP };
private static final int ST_INIT = 0;
private static final int ST_CONTENT_NON_CHUNK = 1;
@ -93,7 +93,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
}
if (chunk instanceof LastHttpContent) {
out.writeBytes(CRLF_END);
out.writeBytes(ZERO_CRLF);
encodeTrailingHeaders(out, (LastHttpContent) chunk);
out.writeBytes(CRLF);

View File

@ -15,11 +15,6 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.CombinedChannelDuplexHandler;
@ -30,8 +25,7 @@ import io.netty.channel.CombinedChannelDuplexHandler;
* @see HttpClientCodec
*/
public final class HttpServerCodec
extends CombinedChannelDuplexHandler
implements ChannelInboundByteHandler, ChannelOutboundMessageHandler<HttpObject> {
extends CombinedChannelDuplexHandler<HttpRequestDecoder, HttpResponseEncoder> {
/**
* Creates a new instance with the default decoder options
@ -48,27 +42,4 @@ public final class HttpServerCodec
public HttpServerCodec(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) {
super(new HttpRequestDecoder(maxInitialLineLength, maxHeaderSize, maxChunkSize), new HttpResponseEncoder());
}
private HttpRequestDecoder decoder() {
return (HttpRequestDecoder) stateHandler();
}
private HttpResponseEncoder encoder() {
return (HttpResponseEncoder) operationHandler();
}
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return decoder().newInboundBuffer(ctx);
}
@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
decoder().discardInboundReadBytes(ctx);
}
@Override
public MessageBuf<HttpObject> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return encoder().newOutboundBuffer(ctx);
}
}

View File

@ -15,7 +15,6 @@
*/
package io.netty.handler.codec.http.multipart;
import io.netty.buffer.BufUtil;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.http.HttpConstants;

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.MessageList;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultHttpContent;
@ -943,7 +943,7 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
* if the encoding is in error
*/
@Override
public boolean readChunk(MessageBuf<HttpContent> buffer) throws ErrorDataEncoderException {
public boolean readChunk(MessageList<HttpContent> buffer) throws ErrorDataEncoderException {
if (isLastChunkSent) {
return false;
} else {

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -50,7 +50,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder<Void> {
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
// Discard all data received if closing handshake was received before.
if (receivedClosingHandshake) {
in.skipBytes(actualReadableBytes());

View File

@ -54,9 +54,10 @@
package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -89,6 +90,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
private ByteBuf framePayload;
private int framePayloadBytesRead;
private ByteBuf maskingKey;
private ByteBuf payloadBuffer;
private final boolean allowExtensions;
private final boolean maskedPayload;
@ -118,7 +120,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
// Discard all data received if closing handshake was received before.
if (receivedClosingHandshake) {
@ -126,11 +128,13 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
return;
}
try {
switch (state()) {
case FRAME_START:
framePayloadBytesRead = 0;
framePayloadLength = -1;
framePayload = null;
payloadBuffer = null;
// FIN, RSV, OPCODE
byte b = in.readByte();
@ -171,7 +175,8 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
}
// check for reserved control frame opcodes
if (!(frameOpcode == OPCODE_CLOSE || frameOpcode == OPCODE_PING || frameOpcode == OPCODE_PONG)) {
if (!(frameOpcode == OPCODE_CLOSE || frameOpcode == OPCODE_PING
|| frameOpcode == OPCODE_PONG)) {
protocolViolation(ctx, "control frame using reserved opcode " + frameOpcode);
return;
}
@ -185,7 +190,8 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
}
} else { // data frame
// check for reserved data frame opcodes
if (!(frameOpcode == OPCODE_CONT || frameOpcode == OPCODE_TEXT || frameOpcode == OPCODE_BINARY)) {
if (!(frameOpcode == OPCODE_CONT || frameOpcode == OPCODE_TEXT
|| frameOpcode == OPCODE_BINARY)) {
protocolViolation(ctx, "data frame using reserved opcode " + frameOpcode);
return;
}
@ -198,7 +204,8 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
// check opcode vs message fragmentation state 2/2
if (fragmentedFramesCount != 0 && frameOpcode != OPCODE_CONT && frameOpcode != OPCODE_PING) {
protocolViolation(ctx, "received non-continuation data frame while inside fragmented message");
protocolViolation(ctx,
"received non-continuation data frame while inside fragmented message");
return;
}
}
@ -242,7 +249,6 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
// Sometimes, the payload may not be delivered in 1 nice packet
// We need to accumulate the data until we have it all
int rbytes = actualReadableBytes();
ByteBuf payloadBuffer = null;
long willHaveReadByteCount = framePayloadBytesRead + rbytes;
// logger.debug("Frame rbytes=" + rbytes + " willHaveReadByteCount="
@ -369,6 +375,21 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
default:
throw new Error("Shouldn't reach here.");
}
} catch (Exception e) {
if (payloadBuffer != null) {
if (payloadBuffer.refCnt() > 0) {
payloadBuffer.release();
}
payloadBuffer = null;
}
if (framePayload != null) {
if (framePayload.refCnt() > 0) {
framePayload.release();
}
framePayload = null;
}
throw e;
}
}
private void unmask(ByteBuf frame) {
@ -380,7 +401,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
private void protocolViolation(ChannelHandlerContext ctx, String reason) {
checkpoint(State.CORRUPT);
if (ctx.channel().isActive()) {
ctx.flush().addListener(ChannelFutureListener.CLOSE);
ctx.write(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
throw new CorruptedFrameException(reason);
}

View File

@ -19,8 +19,8 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.FullHttpRequest;
@ -230,11 +230,11 @@ public abstract class WebSocketClientHandshaker {
/**
* Returns the decoder to use after handshake is complete.
*/
protected abstract ChannelInboundByteHandler newWebsocketDecoder();
protected abstract ChannelInboundHandler newWebsocketDecoder();
/**
* Returns the encoder to use after the handshake is complete.
*/
protected abstract ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder();
protected abstract ChannelOutboundHandler newWebSocketEncoder();
}

View File

@ -17,8 +17,8 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -252,12 +252,12 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket00FrameDecoder(maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket00FrameEncoder();
}
}

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -191,12 +191,12 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket07FrameDecoder(false, allowExtensions, maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket07FrameEncoder(true);
}
}

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -191,12 +191,12 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket08FrameDecoder(false, allowExtensions, maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket08FrameEncoder(true);
}
}

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -191,12 +191,12 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket13FrameDecoder(false, allowExtensions, maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket13FrameEncoder(true);
}
}

View File

@ -16,8 +16,9 @@
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelStateHandler;
import io.netty.channel.MessageList;
import io.netty.handler.codec.http.HttpHeaders;
import java.net.URI;
@ -33,7 +34,7 @@ import java.net.URI;
* This implementation will establish the websocket connection once the connection to the remote server was complete.
*
* To know once a handshake was done you can intercept the
* {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type
* {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type
* {@link ClientHandshakeStateEvent#HANDSHAKE_ISSUED} or {@link ClientHandshakeStateEvent#HANDSHAKE_COMPLETE}.
*/
public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler {
@ -128,12 +129,12 @@ public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler {
}
@Override
public void messageReceived(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, MessageList<Object> out) throws Exception {
if (handleCloseFrames && frame instanceof CloseWebSocketFrame) {
ctx.close();
return;
}
super.messageReceived(ctx, frame);
super.decode(ctx, frame, out);
}
@Override

View File

@ -18,10 +18,11 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.MessageList;
import io.netty.handler.codec.http.FullHttpResponse;
class WebSocketClientProtocolHandshakeHandler extends ChannelInboundMessageHandlerAdapter<FullHttpResponse> {
class WebSocketClientProtocolHandshakeHandler extends ChannelInboundHandlerAdapter {
private final WebSocketClientHandshaker handshaker;
public WebSocketClientProtocolHandshakeHandler(WebSocketClientHandshaker handshaker) {
@ -45,9 +46,10 @@ class WebSocketClientProtocolHandshakeHandler extends ChannelInboundMessageHandl
}
@Override
public void messageReceived(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> messages) throws Exception {
if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ctx.channel(), msg);
handshaker.finishHandshake(ctx.channel(), (FullHttpResponse) messages.get(0));
messages.remove(0);
ctx.fireUserEventTriggered(
WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_COMPLETE);
ctx.pipeline().remove(this);

View File

@ -17,8 +17,8 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -47,7 +47,7 @@ public class WebSocketFrameAggregator extends MessageToMessageDecoder<WebSocketF
}
@Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, MessageList<Object> out) throws Exception {
if (currentFrame == null) {
tooLongFrameFound = false;
if (msg.isFinalFragment()) {

View File

@ -17,12 +17,12 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
abstract class WebSocketProtocolHandler extends ChannelInboundMessageHandlerAdapter<WebSocketFrame> {
import io.netty.channel.MessageList;
import io.netty.handler.codec.MessageToMessageDecoder;
abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocketFrame> {
@Override
public void messageReceived(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, MessageList<Object> out) throws Exception {
if (frame instanceof PingWebSocketFrame) {
frame.content().retain();
ctx.channel().write(new PongWebSocketFrame(frame.content()));
@ -33,8 +33,7 @@ abstract class WebSocketProtocolHandler extends ChannelInboundMessageHandlerAda
return;
}
frame.retain();
ctx.nextInboundMessageBuffer().add(frame);
out.add(frame.retain());
}
@Override

View File

@ -19,8 +19,8 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.FullHttpRequest;
@ -267,11 +267,11 @@ public abstract class WebSocketServerHandshaker {
/**
* Returns the decoder to use after handshake is complete.
*/
protected abstract ChannelInboundByteHandler newWebsocketDecoder();
protected abstract ChannelInboundHandler newWebsocketDecoder();
/**
* Returns the encoder to use after the handshake is complete.
*/
protected abstract ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder();
protected abstract ChannelOutboundHandler newWebSocketEncoder();
}

View File

@ -19,8 +19,8 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
@ -183,12 +183,12 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket00FrameDecoder(maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket00FrameEncoder();
}
}

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -132,12 +132,12 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket07FrameDecoder(true, allowExtensions, maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket07FrameEncoder(false);
}
}

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -131,12 +131,12 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket08FrameDecoder(true, allowExtensions, maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket08FrameEncoder(false);
}
}

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -130,12 +130,12 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
}
@Override
protected ChannelInboundByteHandler newWebsocketDecoder() {
protected ChannelInboundHandler newWebsocketDecoder() {
return new WebSocket13FrameDecoder(true, allowExtensions, maxFramePayloadLength());
}
@Override
protected ChannelOutboundMessageHandler<WebSocketFrame> newWebSocketEncoder() {
protected ChannelOutboundHandler newWebSocketEncoder() {
return new WebSocket13FrameEncoder(false);
}
}

View File

@ -19,9 +19,10 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelStateHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.MessageList;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -43,7 +44,7 @@ import static io.netty.handler.codec.http.HttpVersion.*;
* to the <tt>io.netty.example.http.websocketx.server.WebSocketServer</tt> example.
*
* To know once a handshake was done you can intercept the
* {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type
* {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type
* {@link ServerHandshakeStateEvent#HANDSHAKE_COMPLETE}.
*/
public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {
@ -90,14 +91,14 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {
}
@Override
public void messageReceived(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, MessageList<Object> out) throws Exception {
if (frame instanceof CloseWebSocketFrame) {
WebSocketServerHandshaker handshaker = getHandshaker(ctx);
frame.retain();
handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame);
return;
}
super.messageReceived(ctx, frame);
super.decode(ctx, frame, out);
}
@Override
@ -120,12 +121,19 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {
}
static ChannelHandler forbiddenHttpRequestResponder() {
return new ChannelInboundMessageHandlerAdapter<FullHttpRequest>() {
return new ChannelInboundHandlerAdapter() {
@Override
public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
public void messageReceived(final ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
for (int i = 0; i < msgs.size(); i++) {
Object msg = msgs.get(i);
if (msg instanceof FullHttpRequest) {
FullHttpResponse response =
new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN);
ctx.channel().write(response);
msgs.remove(i--);
}
}
ctx.fireMessageReceived(msgs);
}
};
}

View File

@ -18,8 +18,9 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.MessageList;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
@ -36,7 +37,7 @@ import static io.netty.handler.codec.http.HttpVersion.*;
* Handles the HTTP handshake (the HTTP Upgrade request) for {@link WebSocketServerProtocolHandler}.
*/
class WebSocketServerProtocolHandshakeHandler
extends ChannelInboundMessageHandlerAdapter<FullHttpRequest> {
extends ChannelInboundHandlerAdapter {
private final String websocketPath;
private final String subprotocols;
@ -50,7 +51,10 @@ class WebSocketServerProtocolHandshakeHandler
}
@Override
public void messageReceived(final ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
public void messageReceived(final ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
MessageList<FullHttpRequest> requests = msgs.cast();
for (int i = 0; i < requests.size(); i++) {
FullHttpRequest req = requests.get(i);
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
@ -79,6 +83,7 @@ class WebSocketServerProtocolHandshakeHandler
WebSocketServerProtocolHandler.forbiddenHttpRequestResponder());
}
}
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
ChannelFuture f = ctx.channel().write(res);

View File

@ -15,20 +15,12 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.CombinedChannelDuplexHandler;
/**
* A combination of {@link SpdyFrameDecoder} and {@link SpdyFrameEncoder}.
*/
public final class SpdyFrameCodec
extends CombinedChannelDuplexHandler
implements ChannelInboundByteHandler, ChannelOutboundMessageHandler<SpdyDataOrControlFrame> {
public final class SpdyFrameCodec extends CombinedChannelDuplexHandler<SpdyFrameDecoder, SpdyFrameEncoder> {
/**
* Creates a new instance with the specified {@code version} and
@ -51,27 +43,4 @@ public final class SpdyFrameCodec
new SpdyFrameDecoder(version, maxChunkSize, maxHeaderSize),
new SpdyFrameEncoder(version, compressionLevel, windowBits, memLevel));
}
private SpdyFrameDecoder decoder() {
return (SpdyFrameDecoder) stateHandler();
}
private SpdyFrameEncoder encoder() {
return (SpdyFrameEncoder) operationHandler();
}
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return decoder().newInboundBuffer(ctx);
}
@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
decoder().discardInboundReadBytes(ctx);
}
@Override
public MessageBuf<SpdyDataOrControlFrame> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return encoder().newOutboundBuffer(ctx);
}
}

View File

@ -16,9 +16,9 @@
package io.netty.handler.codec.spdy;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -94,7 +94,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
}
@Override
public void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
public void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
try {
decode(ctx, in, out);
} finally {
@ -103,7 +103,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageList<Object> out) throws Exception {
switch(state) {
case READ_COMMON_HEADER:
state = readCommonHeader(buffer);

View File

@ -15,20 +15,13 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.CombinedChannelDuplexHandler;
import io.netty.handler.codec.http.HttpObject;
/**
* A combination of {@link SpdyHttpDecoder} and {@link SpdyHttpEncoder}
*/
public final class SpdyHttpCodec
extends CombinedChannelDuplexHandler
implements ChannelInboundMessageHandler<SpdyDataOrControlFrame>, ChannelOutboundMessageHandler<HttpObject> {
extends CombinedChannelDuplexHandler<SpdyHttpDecoder, SpdyHttpEncoder> {
/**
* Creates a new instance with the specified decoder options.
@ -36,22 +29,4 @@ public final class SpdyHttpCodec
public SpdyHttpCodec(int version, int maxContentLength) {
super(new SpdyHttpDecoder(version, maxContentLength), new SpdyHttpEncoder(version));
}
private SpdyHttpDecoder decoder() {
return (SpdyHttpDecoder) stateHandler();
}
private SpdyHttpEncoder encoder() {
return (SpdyHttpEncoder) operationHandler();
}
@Override
public MessageBuf<SpdyDataOrControlFrame> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return decoder().newInboundBuffer(ctx);
}
@Override
public MessageBuf<HttpObject> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return encoder().newOutboundBuffer(ctx);
}
}

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.spdy;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
@ -91,7 +91,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyDataOrControlFr
}
@Override
protected void decode(ChannelHandlerContext ctx, SpdyDataOrControlFrame msg, MessageBuf<Object> out)
protected void decode(ChannelHandlerContext ctx, SpdyDataOrControlFrame msg, MessageList<Object> out)
throws Exception {
if (msg instanceof SpdySynStreamFrame) {

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.UnsupportedMessageTypeException;
import io.netty.handler.codec.http.FullHttpRequest;
@ -139,7 +139,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
}
@Override
protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf<Object> out) throws Exception {
protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageList<Object> out) throws Exception {
boolean valid = false;

View File

@ -15,9 +15,9 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.BufUtil;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.HttpMessage;
@ -40,17 +40,17 @@ public class SpdyHttpResponseStreamIdHandler extends
}
@Override
protected void encode(ChannelHandlerContext ctx, HttpMessage msg, MessageBuf<Object> out) throws Exception {
protected void encode(ChannelHandlerContext ctx, HttpMessage msg, MessageList<Object> out) throws Exception {
Integer id = ids.poll();
if (id != null && id.intValue() != NO_ID && !msg.headers().contains(SpdyHttpHeaders.Names.STREAM_ID)) {
SpdyHttpHeaders.setStreamId(msg, id);
}
out.add(BufUtil.retain(msg));
out.add(ByteBufUtil.retain(msg));
}
@Override
protected void decode(ChannelHandlerContext ctx, Object msg, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, Object msg, MessageList<Object> out) throws Exception {
if (msg instanceof HttpMessage) {
boolean contains = ((HttpMessage) msg).headers().contains(SpdyHttpHeaders.Names.STREAM_ID);
if (!contains) {
@ -62,6 +62,6 @@ public class SpdyHttpResponseStreamIdHandler extends
ids.remove(((SpdyRstStreamFrame) msg).getStreamId());
}
out.add(BufUtil.retain(msg));
out.add(ByteBufUtil.retain(msg));
}
}

View File

@ -15,14 +15,12 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelInboundByteHandlerAdapter;
import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.MessageList;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
@ -31,11 +29,11 @@ import io.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLEngine;
/**
* {@link ChannelInboundByteHandler} which is responsible to setup the {@link ChannelPipeline} either for
* {@link ChannelInboundHandler} which is responsible to setup the {@link ChannelPipeline} either for
* HTTP or SPDY. This offers an easy way for users to support both at the same time while not care to
* much about the low-level details.
*/
public abstract class SpdyOrHttpChooser extends ChannelInboundByteHandlerAdapter {
public abstract class SpdyOrHttpChooser extends ChannelInboundHandlerAdapter {
// TODO: Replace with generic NPN handler
@ -63,25 +61,13 @@ public abstract class SpdyOrHttpChooser extends ChannelInboundByteHandlerAdapter
protected abstract SelectedProtocol getProtocol(SSLEngine engine);
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return ChannelHandlerUtil.allocate(ctx);
}
@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
// No need to discard anything because this handler will be replaced with something else very quickly.
}
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> in) throws Exception {
if (initPipeline(ctx)) {
ctx.nextInboundByteBuffer().writeBytes(in);
// When we reached here we can remove this handler as its now clear what protocol we want to use
// from this point on.
ctx.pipeline().remove(this);
ctx.fireInboundBufferUpdated();
ctx.fireMessageReceived(in);
}
}
@ -140,21 +126,21 @@ public abstract class SpdyOrHttpChooser extends ChannelInboundByteHandlerAdapter
}
/**
* Create the {@link ChannelInboundMessageHandler} that is responsible for handling the http requests
* Create the {@link ChannelInboundHandler} that is responsible for handling the http requests
* when the {@link SelectedProtocol} was {@link SelectedProtocol#HTTP_1_0} or
* {@link SelectedProtocol#HTTP_1_1}
*/
protected abstract ChannelInboundMessageHandler<?> createHttpRequestHandlerForHttp();
protected abstract ChannelInboundHandler createHttpRequestHandlerForHttp();
/**
* Create the {@link ChannelInboundMessageHandler} that is responsible for handling the http responses
* Create the {@link ChannelInboundHandler} that is responsible for handling the http responses
* when the {@link SelectedProtocol} was {@link SelectedProtocol#SPDY_2} or
* {@link SelectedProtocol#SPDY_3}.
*
* Bye default this getMethod will just delecate to {@link #createHttpRequestHandlerForHttp()}, but
* sub-classes may override this to change the behaviour.
*/
protected ChannelInboundMessageHandler<?> createHttpRequestHandlerForSpdy() {
protected ChannelInboundHandler createHttpRequestHandlerForSpdy() {
return createHttpRequestHandlerForHttp();
}
}

View File

@ -15,15 +15,12 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MessageList;
import io.netty.util.internal.EmptyArrays;
import java.util.concurrent.atomic.AtomicInteger;
@ -32,8 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* Manages streams within a SPDY session.
*/
public class SpdySessionHandler
extends ChannelDuplexHandler
implements ChannelInboundMessageHandler<Object>, ChannelOutboundMessageHandler<Object> {
extends ChannelDuplexHandler {
private static final SpdyProtocolException PROTOCOL_EXCEPTION = new SpdyProtocolException();
private static final SpdyProtocolException STREAM_CLOSED = new SpdyProtocolException("Stream closed");
@ -85,21 +81,11 @@ public class SpdySessionHandler
}
@Override
public MessageBuf<Object> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.messageBuffer();
}
@Override
public MessageBuf<Object> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.messageBuffer();
}
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
MessageBuf<Object> in = ctx.inboundMessageBuffer();
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> in) throws Exception {
boolean handled = false;
for (;;) {
Object msg = in.poll();
MessageList<Object> out = MessageList.newInstance();
for (int i = 0 ; i < in.size(); i++) {
Object msg = in.get(i);
if (msg == null) {
break;
}
@ -108,18 +94,20 @@ public class SpdySessionHandler
// Let the next handlers handle the buffered messages before SYN_STREAM message updates the
// lastGoodStreamId.
if (handled) {
ctx.fireInboundBufferUpdated();
ctx.fireMessageReceived(out);
out = MessageList.newInstance();
}
}
handleInboundMessage(ctx, msg);
handleInboundMessage(ctx, msg, out);
handled = true;
}
ctx.fireInboundBufferUpdated();
in.recycle();
ctx.fireMessageReceived(out);
}
private void handleInboundMessage(ChannelHandlerContext ctx, Object msg) throws Exception {
private void handleInboundMessage(ChannelHandlerContext ctx, Object msg, MessageList<Object> out) throws Exception {
if (msg instanceof SpdyDataFrame) {
@ -152,22 +140,22 @@ public class SpdySessionHandler
// Check if we received a data frame for a Stream-ID which is not open
if (!spdySession.isActiveStream(streamID)) {
if (streamID <= lastGoodStreamId) {
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR);
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out);
} else if (!sentGoAwayFrame) {
issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM);
issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM, out);
}
return;
}
// Check if we received a data frame for a stream which is half-closed
if (spdySession.isRemoteSideClosed(streamID)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_ALREADY_CLOSED);
issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_ALREADY_CLOSED, out);
return;
}
// Check if we received a data frame before receiving a SYN_REPLY
if (!isRemoteInitiatedID(streamID) && !spdySession.hasReceivedReply(streamID)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR);
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out);
return;
}
@ -188,7 +176,7 @@ public class SpdySessionHandler
// This difference is stored for the session when writing the SETTINGS frame
// and is cleared once we send a WINDOW_UPDATE frame.
if (newWindowSize < spdySession.getReceiveWindowSizeLowerBound(streamID)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR);
issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR, out);
return;
}
@ -198,8 +186,7 @@ public class SpdySessionHandler
while (spdyDataFrame.content().readableBytes() > initialReceiveWindowSize) {
SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(streamID,
spdyDataFrame.content().readSlice(initialReceiveWindowSize).retain());
ctx.nextOutboundMessageBuffer().add(partialDataFrame);
ctx.flush();
ctx.write(partialDataFrame);
}
}
@ -241,7 +228,7 @@ public class SpdySessionHandler
if (spdySynStreamFrame.isInvalid() ||
!isRemoteInitiatedID(streamID) ||
spdySession.isActiveStream(streamID)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR);
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out);
return;
}
@ -256,7 +243,7 @@ public class SpdySessionHandler
boolean remoteSideClosed = spdySynStreamFrame.isLast();
boolean localSideClosed = spdySynStreamFrame.isUnidirectional();
if (!acceptStream(streamID, priority, remoteSideClosed, localSideClosed)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.REFUSED_STREAM);
issueStreamError(ctx, streamID, SpdyStreamStatus.REFUSED_STREAM, out);
return;
}
@ -276,13 +263,13 @@ public class SpdySessionHandler
if (spdySynReplyFrame.isInvalid() ||
isRemoteInitiatedID(streamID) ||
spdySession.isRemoteSideClosed(streamID)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM);
issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM, out);
return;
}
// Check if we have received multiple frames for the same Stream-ID
if (spdySession.hasReceivedReply(streamID)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_IN_USE);
issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_IN_USE, out);
return;
}
@ -368,12 +355,12 @@ public class SpdySessionHandler
// Check if we received a valid HEADERS frame
if (spdyHeadersFrame.isInvalid()) {
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR);
issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out);
return;
}
if (spdySession.isRemoteSideClosed(streamID)) {
issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM);
issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM, out);
return;
}
@ -406,15 +393,15 @@ public class SpdySessionHandler
// Check for numerical overflow
if (spdySession.getSendWindowSize(streamID) > Integer.MAX_VALUE - deltaWindowSize) {
issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR);
issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR, out);
return;
}
updateSendWindowSize(ctx, streamID, deltaWindowSize);
updateSendWindowSize(streamID, deltaWindowSize, out);
}
}
ctx.nextInboundMessageBuffer().add(msg);
out.add(msg);
}
@Override
@ -432,10 +419,10 @@ public class SpdySessionHandler
}
@Override
public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
MessageBuf<Object> in = ctx.outboundMessageBuffer();
for (;;) {
Object msg = in.poll();
public void write(ChannelHandlerContext ctx, MessageList<Object> msgs, ChannelPromise promise) throws Exception {
MessageList<Object> out = MessageList.newInstance();
for (int i = 0; i < msgs.size(); i++) {
Object msg = msgs.get(i);
if (msg == null) {
break;
}
@ -449,24 +436,26 @@ public class SpdySessionHandler
msg instanceof SpdyHeadersFrame ||
msg instanceof SpdyWindowUpdateFrame) {
try {
handleOutboundMessage(ctx, msg);
handleOutboundMessage(ctx, msg, out);
} catch (SpdyProtocolException e) {
if (e == PROTOCOL_EXCEPTION) {
// on the case of PROTOCOL_EXCEPTION faile the promise directly
// on the case of PROTOCOL_EXCEPTION, fail the promise directly
// See #1211
promise.setFailure(PROTOCOL_EXCEPTION);
return;
}
}
} else {
ctx.nextOutboundMessageBuffer().add(msg);
out.add(msg);
}
}
ctx.flush(promise);
}
private void handleOutboundMessage(ChannelHandlerContext ctx, Object msg) throws Exception {
msgs.recycle();
ctx.write(out, promise);
}
private void handleOutboundMessage(ChannelHandlerContext ctx, Object msg, MessageList<Object> out)
throws Exception {
if (msg instanceof SpdyDataFrame) {
SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg;
@ -656,7 +645,7 @@ public class SpdySessionHandler
throw PROTOCOL_EXCEPTION;
}
ctx.nextOutboundMessageBuffer().add(msg);
out.add(msg);
}
/*
@ -671,8 +660,7 @@ public class SpdySessionHandler
private void issueSessionError(
ChannelHandlerContext ctx, SpdySessionStatus status) {
sendGoAwayFrame(ctx, status);
ctx.flush().addListener(ChannelFutureListener.CLOSE);
sendGoAwayFrame(ctx, status).addListener(ChannelFutureListener.CLOSE);
}
/*
@ -687,7 +675,7 @@ public class SpdySessionHandler
* Note: this is only called by the worker thread
*/
private void issueStreamError(
ChannelHandlerContext ctx, int streamID, SpdyStreamStatus status) {
ChannelHandlerContext ctx, int streamID, SpdyStreamStatus status, MessageList<Object> in) {
boolean fireMessageReceived = !spdySession.isRemoteSideClosed(streamID);
removeStream(ctx, streamID);
@ -695,8 +683,11 @@ public class SpdySessionHandler
SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamID, status);
ctx.write(spdyRstStreamFrame);
if (fireMessageReceived) {
ctx.nextInboundMessageBuffer().add(spdyRstStreamFrame);
ctx.fireInboundBufferUpdated();
in.add(spdyRstStreamFrame);
ctx.fireMessageReceived(in);
while (!in.isEmpty()) {
in.remove(0);
}
}
}
@ -793,7 +784,7 @@ public class SpdySessionHandler
}
}
private void updateSendWindowSize(ChannelHandlerContext ctx, final int streamID, int deltaWindowSize) {
private void updateSendWindowSize(final int streamID, int deltaWindowSize, MessageList<Object> out) {
synchronized (flowControlLock) {
int newWindowSize = spdySession.updateSendWindowSize(streamID, deltaWindowSize);
@ -832,7 +823,7 @@ public class SpdySessionHandler
halfCloseStream(streamID, false);
}
ctx.nextOutboundMessageBuffer().add(spdyDataFrame);
out.add(spdyDataFrame);
} else {
// We can send a partial frame
spdySession.updateSendWindowSize(streamID, -1 * newWindowSize);
@ -858,7 +849,7 @@ public class SpdySessionHandler
// }
//});
ctx.nextOutboundMessageBuffer().add(partialDataFrame);
out.add(partialDataFrame);
newWindowSize = 0;
}
@ -873,8 +864,7 @@ public class SpdySessionHandler
return;
}
sendGoAwayFrame(ctx, SpdySessionStatus.OK);
ChannelFuture f = ctx.flush();
ChannelFuture f = sendGoAwayFrame(ctx, SpdySessionStatus.OK);
if (spdySession.noActiveStreams()) {
f.addListener(new ClosingChannelFutureListener(ctx, future));
} else {
@ -884,12 +874,14 @@ public class SpdySessionHandler
// FIXME: Close the connection forcibly after timeout.
}
private synchronized void sendGoAwayFrame(
private synchronized ChannelFuture sendGoAwayFrame(
ChannelHandlerContext ctx, SpdySessionStatus status) {
if (!sentGoAwayFrame) {
sentGoAwayFrame = true;
SpdyGoAwayFrame spdyGoAwayFrame = new DefaultSpdyGoAwayFrame(lastGoodStreamId, status);
ctx.nextOutboundMessageBuffer().add(spdyGoAwayFrame);
return ctx.write(spdyGoAwayFrame);
} else {
return ctx.newSucceededFuture();
}
}

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec.http;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.CodecException;
import io.netty.handler.codec.PrematureChannelClosureException;
import io.netty.util.CharsetUtil;
@ -37,7 +37,7 @@ public class HttpClientCodecTest {
@Test
public void testFailsNotOnRequestResponse() {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
EmbeddedChannel ch = new EmbeddedChannel(codec);
ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeInbound(Unpooled.copiedBuffer(RESPONSE, CharsetUtil.ISO_8859_1));
@ -47,7 +47,7 @@ public class HttpClientCodecTest {
@Test
public void testFailsNotOnRequestResponseChunked() {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
EmbeddedChannel ch = new EmbeddedChannel(codec);
ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeInbound(Unpooled.copiedBuffer(CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1));
@ -57,7 +57,7 @@ public class HttpClientCodecTest {
@Test
public void testFailsOnMissingResponse() {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
EmbeddedChannel ch = new EmbeddedChannel(codec);
assertTrue(ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
"http://localhost/")));
@ -74,7 +74,7 @@ public class HttpClientCodecTest {
@Test
public void testFailsOnIncompleteChunkedResponse() {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
EmbeddedChannel ch = new EmbeddedChannel(codec);
ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeInbound(Unpooled.copiedBuffer(INCOMPLETE_CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1));

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.http;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.codec.http.HttpHeaders.Names;
import org.junit.Test;
@ -63,7 +63,7 @@ public class HttpContentCompressorTest {
@Test
public void testEmptyContentCompression() throws Exception {
EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new HttpContentCompressor());
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
FullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
req.headers().set(Names.ACCEPT_ENCODING, "deflate");
ch.writeInbound(req);

View File

@ -19,9 +19,8 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.handler.codec.ByteToByteEncoder;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.util.CharsetUtil;
@ -35,9 +34,9 @@ public class HttpContentEncoderTest {
private static final class TestEncoder extends HttpContentEncoder {
@Override
protected Result beginEncode(HttpResponse headers, String acceptEncoding) {
return new Result("test", new EmbeddedByteChannel(new ByteToByteEncoder() {
return new Result("test", new EmbeddedChannel(new MessageToByteEncoder<ByteBuf>() {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) {
protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
out.writeBytes(String.valueOf(in.readableBytes()).getBytes(CharsetUtil.US_ASCII));
in.skipBytes(in.readableBytes());
}
@ -47,7 +46,7 @@ public class HttpContentEncoderTest {
@Test
public void testSplitContent() throws Exception {
EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder());
EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder());
ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"));
ch.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
@ -71,7 +70,7 @@ public class HttpContentEncoderTest {
@Test
public void testChunkedContent() throws Exception {
EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder());
EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder());
ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"));
HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
@ -98,7 +97,7 @@ public class HttpContentEncoderTest {
@Test
public void testFullContent() throws Exception {
EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder());
EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder());
ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"));
FullHttpResponse res = new DefaultFullHttpResponse(
@ -116,12 +115,12 @@ public class HttpContentEncoderTest {
}
/**
* If the length of the content is unknown, {@link HttpContentEncoder} should not skip encoding even if the
* actual length is turned out to be 0.
* If the length of the content is unknown, {@link HttpContentEncoder} should not skip encoding the content
* even if the actual length is turned out to be 0.
*/
@Test
public void testEmptySplitContent() throws Exception {
EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder());
EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder());
ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"));
ch.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
@ -129,7 +128,7 @@ public class HttpContentEncoderTest {
ch.writeOutbound(LastHttpContent.EMPTY_LAST_CONTENT);
HttpContent chunk = (HttpContent) ch.readOutbound();
assertThat(chunk.content().isReadable(), is(false));
assertThat(chunk.content().toString(CharsetUtil.US_ASCII), is("0"));
assertThat(chunk, is(instanceOf(LastHttpContent.class)));
assertThat(ch.readOutbound(), is(nullValue()));
}
@ -139,7 +138,7 @@ public class HttpContentEncoderTest {
*/
@Test
public void testEmptyFullContent() throws Exception {
EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder());
EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder());
ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"));
FullHttpResponse res = new DefaultFullHttpResponse(
@ -162,7 +161,7 @@ public class HttpContentEncoderTest {
assertThat(ch.readOutbound(), is(nullValue()));
}
private static void assertEncodedResponse(EmbeddedMessageChannel ch) {
private static void assertEncodedResponse(EmbeddedChannel ch) {
Object o = ch.readOutbound();
assertThat(o, is(instanceOf(HttpResponse.class)));

View File

@ -17,7 +17,7 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.DecoderResult;
import io.netty.util.CharsetUtil;
import org.junit.Test;
@ -32,7 +32,7 @@ public class HttpInvalidMessageTest {
@Test
public void testRequestWithBadInitialLine() throws Exception {
EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpRequestDecoder());
EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder());
ch.writeInbound(Unpooled.copiedBuffer("GET / HTTP/1.0 with extra\r\n", CharsetUtil.UTF_8));
HttpRequest req = (HttpRequest) ch.readInbound();
DecoderResult dr = req.getDecoderResult();
@ -43,7 +43,7 @@ public class HttpInvalidMessageTest {
@Test
public void testRequestWithBadHeader() throws Exception {
EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpRequestDecoder());
EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder());
ch.writeInbound(Unpooled.copiedBuffer("GET /maybe-something HTTP/1.0\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("Good_Name: Good Value\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("Bad=Name: Bad Value\r\n", CharsetUtil.UTF_8));
@ -59,7 +59,7 @@ public class HttpInvalidMessageTest {
@Test
public void testResponseWithBadInitialLine() throws Exception {
EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpResponseDecoder());
EmbeddedChannel ch = new EmbeddedChannel(new HttpResponseDecoder());
ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.0 BAD_CODE Bad Server\r\n", CharsetUtil.UTF_8));
HttpResponse res = (HttpResponse) ch.readInbound();
DecoderResult dr = res.getDecoderResult();
@ -70,7 +70,7 @@ public class HttpInvalidMessageTest {
@Test
public void testResponseWithBadHeader() throws Exception {
EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpResponseDecoder());
EmbeddedChannel ch = new EmbeddedChannel(new HttpResponseDecoder());
ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.0 200 Maybe OK\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("Good_Name: Good Value\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("Bad=Name: Bad Value\r\n", CharsetUtil.UTF_8));
@ -86,7 +86,7 @@ public class HttpInvalidMessageTest {
@Test
public void testBadChunk() throws Exception {
EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpRequestDecoder());
EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder());
ch.writeInbound(Unpooled.copiedBuffer("GET / HTTP/1.0\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("Transfer-Encoding: chunked\r\n\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("BAD_LENGTH\r\n", CharsetUtil.UTF_8));
@ -101,7 +101,7 @@ public class HttpInvalidMessageTest {
ensureInboundTrafficDiscarded(ch);
}
private void ensureInboundTrafficDiscarded(EmbeddedByteChannel ch) {
private void ensureInboundTrafficDiscarded(EmbeddedChannel ch) {
// Generate a lot of random traffic to ensure that it's discarded silently.
byte[] data = new byte[1048576];
rnd.nextBytes(data);
@ -109,9 +109,10 @@ public class HttpInvalidMessageTest {
ByteBuf buf = Unpooled.wrappedBuffer(data);
for (int i = 0; i < 4096; i ++) {
buf.setIndex(0, data.length);
ch.writeInbound(buf);
ch.writeInbound(buf.retain());
ch.checkException();
assertNull(ch.readInbound());
}
buf.release();
}
}

View File

@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.CharsetUtil;
import org.easymock.EasyMock;
@ -34,7 +34,7 @@ public class HttpObjectAggregatorTest {
@Test
public void testAggregate() {
HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024);
EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr);
EmbeddedChannel embedder = new EmbeddedChannel(aggr);
HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost");
@ -73,7 +73,7 @@ public class HttpObjectAggregatorTest {
@Test
public void testAggregateWithTrailer() {
HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024);
EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr);
EmbeddedChannel embedder = new EmbeddedChannel(aggr);
HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost");
HttpHeaders.setHeader(message, "X-Test", true);
@ -105,7 +105,7 @@ public class HttpObjectAggregatorTest {
@Test
public void testTooLongFrameException() {
HttpObjectAggregator aggr = new HttpObjectAggregator(4);
EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr);
EmbeddedChannel embedder = new EmbeddedChannel(aggr);
HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost");
HttpContent chunk1 = new DefaultHttpContent(Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII));
@ -159,7 +159,7 @@ public class HttpObjectAggregatorTest {
@Test
public void testAggregateTransferEncodingChunked() {
HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024);
EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr);
EmbeddedChannel embedder = new EmbeddedChannel(aggr);
HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost");

View File

@ -17,7 +17,7 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
@ -32,10 +32,11 @@ public class HttpServerCodecTest {
int maxChunkSize = 2000;
HttpServerCodec httpServerCodec = new HttpServerCodec(1000, 1000, maxChunkSize);
EmbeddedByteChannel decoderEmbedder = new EmbeddedByteChannel(httpServerCodec);
EmbeddedChannel decoderEmbedder = new EmbeddedChannel(httpServerCodec);
int totalContentLength = maxChunkSize * 5;
decoderEmbedder.writeInbound(Unpooled.copiedBuffer("PUT /test HTTP/1.1\r\n" +
decoderEmbedder.writeInbound(Unpooled.copiedBuffer(
"PUT /test HTTP/1.1\r\n" +
"Content-Length: " + totalContentLength + "\r\n" +
"\r\n", CharsetUtil.UTF_8));

View File

@ -17,7 +17,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.CharsetUtil;
import org.junit.Assert;
@ -32,7 +32,7 @@ public class WebSocketFrameAggregatorTest {
.writeBytes(content2.duplicate()).writeBytes(content3.duplicate());
@Test
public void testAggregationBinary() {
EmbeddedMessageChannel channel = new EmbeddedMessageChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE));
EmbeddedChannel channel = new EmbeddedChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE));
channel.writeInbound(new BinaryWebSocketFrame(true, 1, content1.copy()));
channel.writeInbound(new BinaryWebSocketFrame(false, 0, content1.copy()));
channel.writeInbound(new ContinuationWebSocketFrame(false, 0, content2.copy()));
@ -42,7 +42,7 @@ public class WebSocketFrameAggregatorTest {
Assert.assertTrue(channel.finish());
System.out.println(channel.lastInboundMessageBuffer().size());
System.out.println(channel.lastInboundBuffer().size());
BinaryWebSocketFrame frame = (BinaryWebSocketFrame) channel.readInbound();
Assert.assertTrue(frame.isFinalFragment());
Assert.assertEquals(1, frame.rsv());
@ -68,7 +68,7 @@ public class WebSocketFrameAggregatorTest {
@Test
public void testAggregationText() {
EmbeddedMessageChannel channel = new EmbeddedMessageChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE));
EmbeddedChannel channel = new EmbeddedChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE));
channel.writeInbound(new TextWebSocketFrame(true, 1, content1.copy()));
channel.writeInbound(new TextWebSocketFrame(false, 0, content1.copy()));
channel.writeInbound(new ContinuationWebSocketFrame(false, 0, content2.copy()));
@ -103,7 +103,7 @@ public class WebSocketFrameAggregatorTest {
@Test
public void textFrameTooBig() {
EmbeddedMessageChannel channel = new EmbeddedMessageChannel(new WebSocketFrameAggregator(8));
EmbeddedChannel channel = new EmbeddedChannel(new WebSocketFrameAggregator(8));
channel.writeInbound(new BinaryWebSocketFrame(true, 1, content1.copy()));
channel.writeInbound(new BinaryWebSocketFrame(false, 0, content1.copy()));
try {

View File

@ -17,7 +17,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
@ -39,7 +39,7 @@ public class WebSocketServerHandshaker00Test {
@Test
public void testPerformOpeningHandshake() {
EmbeddedByteChannel ch = new EmbeddedByteChannel(
EmbeddedChannel ch = new EmbeddedChannel(
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
FullHttpRequest req = new DefaultFullHttpRequest(
@ -56,9 +56,9 @@ public class WebSocketServerHandshaker00Test {
new WebSocketServerHandshaker00(
"ws://example.com/chat", "chat", Integer.MAX_VALUE).handshake(ch, req);
ByteBuf resBuf = ch.readOutbound();
ByteBuf resBuf = (ByteBuf) ch.readOutbound();
EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder());
EmbeddedChannel ch2 = new EmbeddedChannel(new HttpResponseDecoder());
ch2.writeInbound(resBuf);
HttpResponse res = (HttpResponse) ch2.readInbound();

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
@ -36,7 +36,7 @@ public class WebSocketServerHandshaker08Test {
@Test
public void testPerformOpeningHandshake() {
EmbeddedByteChannel ch = new EmbeddedByteChannel(
EmbeddedChannel ch = new EmbeddedChannel(
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
FullHttpRequest req = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat");
@ -51,9 +51,9 @@ public class WebSocketServerHandshaker08Test {
new WebSocketServerHandshaker08(
"ws://example.com/chat", "chat", false, Integer.MAX_VALUE).handshake(ch, req);
ByteBuf resBuf = ch.readOutbound();
ByteBuf resBuf = (ByteBuf) ch.readOutbound();
EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder());
EmbeddedChannel ch2 = new EmbeddedChannel(new HttpResponseDecoder());
ch2.writeInbound(resBuf);
HttpResponse res = (HttpResponse) ch2.readInbound();

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
@ -36,7 +36,7 @@ public class WebSocketServerHandshaker13Test {
@Test
public void testPerformOpeningHandshake() {
EmbeddedByteChannel ch = new EmbeddedByteChannel(
EmbeddedChannel ch = new EmbeddedChannel(
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
FullHttpRequest req = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat");
@ -51,9 +51,9 @@ public class WebSocketServerHandshaker13Test {
new WebSocketServerHandshaker13(
"ws://example.com/chat", "chat", false, Integer.MAX_VALUE).handshake(ch, req);
ByteBuf resBuf = ch.readOutbound();
ByteBuf resBuf = (ByteBuf) ch.readOutbound();
EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder());
EmbeddedChannel ch2 = new EmbeddedChannel(new HttpResponseDecoder());
ch2.writeInbound(resBuf);
HttpResponse res = (HttpResponse) ch2.readInbound();

View File

@ -15,25 +15,26 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelOperationHandlerAdapter;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.channel.MessageList;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayDeque;
import java.util.Queue;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
@ -41,29 +42,36 @@ import static org.junit.Assert.*;
public class WebSocketServerProtocolHandlerTest {
private final Queue<FullHttpResponse> responses = new ArrayDeque<FullHttpResponse>();
@Before
public void setUp() {
responses.clear();
}
@Test
public void testHttpUpgradeRequest() throws Exception {
EmbeddedMessageChannel ch = createChannel(new MockOutboundHandler());
EmbeddedChannel ch = createChannel(new MockOutboundHandler());
ChannelHandlerContext handshakerCtx = ch.pipeline().context(WebSocketServerProtocolHandshakeHandler.class);
writeUpgradeRequest(ch);
assertEquals(SWITCHING_PROTOCOLS, ((HttpResponse) ch.outboundMessageBuffer().poll()).getStatus());
assertEquals(SWITCHING_PROTOCOLS, responses.remove().getStatus());
assertNotNull(WebSocketServerProtocolHandler.getHandshaker(handshakerCtx));
}
@Test
public void testSubsequentHttpRequestsAfterUpgradeShouldReturn403() throws Exception {
EmbeddedMessageChannel ch = createChannel(new MockOutboundHandler());
EmbeddedChannel ch = createChannel();
writeUpgradeRequest(ch);
assertEquals(SWITCHING_PROTOCOLS, ((HttpResponse) ch.outboundMessageBuffer().poll()).getStatus());
assertEquals(SWITCHING_PROTOCOLS, responses.remove().getStatus());
ch.writeInbound(new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/test"));
assertEquals(FORBIDDEN, ((HttpResponse) ch.outboundMessageBuffer().poll()).getStatus());
assertEquals(FORBIDDEN, responses.remove().getStatus());
}
@Test
public void testHttpUpgradeRequestInvalidUpgradeHeader() {
EmbeddedMessageChannel ch = createChannel();
EmbeddedChannel ch = createChannel();
FullHttpRequest httpRequestWithEntity = new WebSocketRequestBuilder().httpVersion(HTTP_1_1)
.method(HttpMethod.GET)
.uri("/test")
@ -74,14 +82,14 @@ public class WebSocketServerProtocolHandlerTest {
ch.writeInbound(httpRequestWithEntity);
FullHttpResponse response = getHttpResponse(ch);
FullHttpResponse response = responses.remove();
assertEquals(BAD_REQUEST, response.getStatus());
assertEquals("not a WebSocket handshake request: missing upgrade", getResponseMessage(response));
}
@Test
public void testHttpUpgradeRequestMissingWSKeyHeader() {
EmbeddedMessageChannel ch = createChannel();
EmbeddedChannel ch = createChannel();
HttpRequest httpRequest = new WebSocketRequestBuilder().httpVersion(HTTP_1_1)
.method(HttpMethod.GET)
.uri("/test")
@ -93,7 +101,7 @@ public class WebSocketServerProtocolHandlerTest {
ch.writeInbound(httpRequest);
FullHttpResponse response = getHttpResponse(ch);
FullHttpResponse response = responses.remove();
assertEquals(BAD_REQUEST, response.getStatus());
assertEquals("not a WebSocket request: missing key", getResponseMessage(response));
}
@ -101,22 +109,26 @@ public class WebSocketServerProtocolHandlerTest {
@Test
public void testHandleTextFrame() {
CustomTextFrameHandler customTextFrameHandler = new CustomTextFrameHandler();
EmbeddedMessageChannel ch = createChannel(customTextFrameHandler);
EmbeddedChannel ch = createChannel(customTextFrameHandler);
writeUpgradeRequest(ch);
// Removing the HttpRequestDecoder as we are writing a TextWebSocketFrame so decoding is not neccessary.
if (ch.pipeline().context(HttpRequestDecoder.class) != null) {
// Removing the HttpRequestDecoder because we are writing a TextWebSocketFrame and thus
// decoding is not neccessary.
ch.pipeline().remove(HttpRequestDecoder.class);
}
ch.writeInbound(new TextWebSocketFrame("payload"));
assertEquals("processed: payload", customTextFrameHandler.getContent());
}
private static EmbeddedMessageChannel createChannel() {
private EmbeddedChannel createChannel() {
return createChannel(null);
}
private static EmbeddedMessageChannel createChannel(ChannelHandler handler) {
return new EmbeddedMessageChannel(
private EmbeddedChannel createChannel(ChannelHandler handler) {
return new EmbeddedChannel(
new WebSocketServerProtocolHandler("/test", null, false),
new HttpRequestDecoder(),
new HttpResponseEncoder(),
@ -124,7 +136,7 @@ public class WebSocketServerProtocolHandlerTest {
handler);
}
private static void writeUpgradeRequest(EmbeddedMessageChannel ch) {
private static void writeUpgradeRequest(EmbeddedChannel ch) {
ch.writeInbound(WebSocketRequestBuilder.sucessful());
}
@ -132,31 +144,25 @@ public class WebSocketServerProtocolHandlerTest {
return new String(response.content().array());
}
private static FullHttpResponse getHttpResponse(EmbeddedMessageChannel ch) {
MessageBuf<Object> outbound = ch.pipeline().context(MockOutboundHandler.class).outboundMessageBuffer();
return (FullHttpResponse) outbound.poll();
}
private static class MockOutboundHandler
extends ChannelOperationHandlerAdapter implements ChannelOutboundMessageHandler<Object> {
private class MockOutboundHandler extends ChannelOutboundHandlerAdapter {
@Override
public MessageBuf<Object> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return Unpooled.messageBuffer();
public void write(ChannelHandlerContext ctx, MessageList<Object> msgs, ChannelPromise promise)
throws Exception {
for (int i = 0; i < msgs.size(); i++) {
responses.add((FullHttpResponse) msgs.get(i));
}
@Override
public void flush(ChannelHandlerContext ctx, ChannelPromise future) throws Exception {
//NoOp
promise.setSuccess();
}
}
private static class CustomTextFrameHandler extends ChannelInboundMessageHandlerAdapter<TextWebSocketFrame> {
private static class CustomTextFrameHandler extends ChannelInboundHandlerAdapter {
private String content;
@Override
public void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
content = "processed: " + msg.text();
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
assertEquals(1, msgs.size());
content = "processed: " + ((TextWebSocketFrame) msgs.get(0)).text();
}
String getContent() {

View File

@ -16,8 +16,9 @@
package io.netty.handler.codec.spdy;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.MessageList;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.junit.Test;
@ -99,7 +100,7 @@ public class SpdySessionHandlerTest {
}
private static void testSpdySessionHandler(int version, boolean server) {
EmbeddedMessageChannel sessionHandler = new EmbeddedMessageChannel(
EmbeddedChannel sessionHandler = new EmbeddedChannel(
new SpdySessionHandler(version, server), new EchoHandler(closeSignal, server));
while (sessionHandler.readOutbound() != null) {
@ -278,7 +279,7 @@ public class SpdySessionHandlerTest {
// Echo Handler opens 4 half-closed streams on session connection
// and then sets the number of concurrent streams to 3
private static class EchoHandler extends ChannelInboundMessageHandlerAdapter<Object> {
private static class EchoHandler extends ChannelInboundHandlerAdapter {
private final int closeSignal;
private final boolean server;
@ -309,7 +310,9 @@ public class SpdySessionHandlerTest {
}
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> messages) throws Exception {
for (int i = 0; i < messages.size(); i++) {
Object msg = messages.get(i);
if (msg instanceof SpdyDataFrame ||
msg instanceof SpdyPingFrame ||
msg instanceof SpdyHeadersFrame) {
@ -343,3 +346,4 @@ public class SpdySessionHandlerTest {
}
}
}
}

View File

@ -20,7 +20,7 @@
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>4.0.0.Final-SNAPSHOT</version>
<version>4.0.0.CR4-SNAPSHOT</version>
</parent>
<artifactId>netty-codec-socks</artifactId>

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.socks;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.util.CharsetUtil;
@ -43,7 +43,7 @@ public class SocksAuthRequestDecoder extends ReplayingDecoder<SocksAuthRequestDe
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList<Object> out) throws Exception {
switch (state()) {
case CHECK_PROTOCOL_VERSION: {
version = SocksSubnegotiationVersion.fromByte(byteBuf.readByte());

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.socks;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ReplayingDecoder;
/**
@ -40,7 +40,7 @@ public class SocksAuthResponseDecoder extends ReplayingDecoder<SocksAuthResponse
}
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, MessageBuf<Object> out)
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, MessageList<Object> out)
throws Exception {
switch (state()) {
case CHECK_PROTOCOL_VERSION: {

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.socks;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.util.CharsetUtil;
@ -46,7 +46,7 @@ public class SocksCmdRequestDecoder extends ReplayingDecoder<SocksCmdRequestDeco
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList<Object> out) throws Exception {
switch (state()) {
case CHECK_PROTOCOL_VERSION: {
version = SocksProtocolVersion.fromByte(byteBuf.readByte());

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.socks;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.util.CharsetUtil;
@ -46,7 +46,7 @@ public class SocksCmdResponseDecoder extends ReplayingDecoder<SocksCmdResponseDe
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList<Object> out) throws Exception {
switch (state()) {
case CHECK_PROTOCOL_VERSION: {
version = SocksProtocolVersion.fromByte(byteBuf.readByte());

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.socks;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ReplayingDecoder;
import java.util.ArrayList;
@ -44,7 +44,7 @@ public class SocksInitRequestDecoder extends ReplayingDecoder<SocksInitRequestDe
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList<Object> out) throws Exception {
switch (state()) {
case CHECK_PROTOCOL_VERSION: {
version = SocksProtocolVersion.fromByte(byteBuf.readByte());

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec.socks;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.ReplayingDecoder;
/**
@ -41,7 +41,7 @@ public class SocksInitResponseDecoder extends ReplayingDecoder<SocksInitResponse
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList<Object> out) throws Exception {
switch (state()) {
case CHECK_PROTOCOL_VERSION: {
version = SocksProtocolVersion.fromByte(byteBuf.readByte());

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.socks;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.Test;
import static org.junit.Assert.*;
@ -28,7 +28,7 @@ public class SocksAuthRequestDecoderTest {
String password = "test";
SocksAuthRequest msg = new SocksAuthRequest(username, password);
SocksAuthRequestDecoder decoder = new SocksAuthRequestDecoder();
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
msg = (SocksAuthRequest) embedder.readInbound();
assertEquals(msg.username(), username);

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.socks;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.junit.Test;
@ -29,7 +29,7 @@ public class SocksAuthResponseDecoderTest {
logger.debug("Testing SocksAuthResponseDecoder with authStatus: " + authStatus);
SocksAuthResponse msg = new SocksAuthResponse(authStatus);
SocksAuthResponseDecoder decoder = new SocksAuthResponseDecoder();
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
msg = (SocksAuthResponse) embedder.readInbound();
assertSame(msg.authStatus(), authStatus);

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.socks;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.junit.Test;
@ -34,7 +34,7 @@ public class SocksCmdRequestDecoderTest {
" port: " + port);
SocksCmdRequest msg = new SocksCmdRequest(cmdType, addressType, host, port);
SocksCmdRequestDecoder decoder = new SocksCmdRequestDecoder();
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
if (msg.addressType() == SocksAddressType.UNKNOWN) {
assertTrue(embedder.readInbound() instanceof UnknownSocksRequest);

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.socks;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.junit.Test;
@ -25,12 +25,12 @@ import static org.junit.Assert.*;
public class SocksCmdResponseDecoderTest {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksCmdResponseDecoderTest.class);
private static void testSocksCmdResponseDecoderWithDifferentParams(SocksCmdStatus cmdStatus,
SocksAddressType addressType) {
private static void testSocksCmdResponseDecoderWithDifferentParams(
SocksCmdStatus cmdStatus, SocksAddressType addressType) {
logger.debug("Testing cmdStatus: " + cmdStatus + " addressType: " + addressType);
SocksResponse msg = new SocksCmdResponse(cmdStatus, addressType);
SocksCmdResponseDecoder decoder = new SocksCmdResponseDecoder();
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
if (addressType == SocksAddressType.UNKNOWN) {
assertTrue(embedder.readInbound() instanceof UnknownSocksResponse);

View File

@ -17,7 +17,7 @@ package io.netty.handler.codec.socks;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.channel.embedded.EmbeddedChannel;
final class SocksCommonTestUtils {
/**
@ -27,7 +27,7 @@ final class SocksCommonTestUtils {
//NOOP
}
public static void writeMessageIntoEmbedder(EmbeddedByteChannel embedder, SocksMessage msg) {
public static void writeMessageIntoEmbedder(EmbeddedChannel embedder, SocksMessage msg) {
ByteBuf buf = Unpooled.buffer();
msg.encodeAsByteBuf(buf);
embedder.writeInbound(buf);

View File

@ -20,7 +20,7 @@
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>4.0.0.Final-SNAPSHOT</version>
<version>4.0.0.CR4-SNAPSHOT</version>
</parent>
<artifactId>netty-codec</artifactId>

View File

@ -1,127 +0,0 @@
/*
* Copyright 2012 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;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundByteHandler;
import io.netty.channel.ChannelPromise;
/**
* A Codec for on-the-fly encoding/decoding of bytes.
*
* This can be thought of as a combination of {@link ByteToByteDecoder} and {@link ByteToByteEncoder}.
*
* Here is an example of a {@link ByteToByteCodec} which just square {@link Integer} read from a {@link ByteBuf}.
* <pre>
* public class SquareCodec extends {@link ByteToByteCodec} {
* {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value * value);
* }
*
* {@code @Overrride}
* public void encode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value / value);
* }
* }
* </pre>
*/
public abstract class ByteToByteCodec
extends ChannelDuplexHandler
implements ChannelInboundByteHandler, ChannelOutboundByteHandler {
private final ByteToByteEncoder encoder = new ByteToByteEncoder() {
@Override
protected void encode(
ChannelHandlerContext ctx,
ByteBuf in, ByteBuf out) throws Exception {
ByteToByteCodec.this.encode(ctx, in, out);
}
};
private final ByteToByteDecoder decoder = new ByteToByteDecoder() {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
ByteToByteCodec.this.decode(ctx, in, out);
}
@Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
ByteToByteCodec.this.decodeLast(ctx, in, out);
}
};
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return decoder.newInboundBuffer(ctx);
}
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
decoder.inboundBufferUpdated(ctx);
}
@Override
public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return encoder.newOutboundBuffer(ctx);
}
@Override
public void flush(
ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
encoder.flush(ctx, promise);
}
@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
decoder.discardInboundReadBytes(ctx);
}
@Override
public void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception {
encoder.discardOutboundReadBytes(ctx);
}
/**
* @see {@link ByteToByteEncoder#encode(ChannelHandlerContext, ByteBuf, ByteBuf)}
*/
protected abstract void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception;
/**
* @see {@link ByteToByteDecoder#decode(ChannelHandlerContext, ByteBuf, ByteBuf)}
*/
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception;
/**
* @see {@link ByteToByteDecoder#decodeLast(ChannelHandlerContext, ByteBuf, ByteBuf)}
*/
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
decode(ctx, in, out);
}
}

View File

@ -1,142 +0,0 @@
/*
* Copyright 2012 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;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandlerAdapter;
/**
* {@link ChannelInboundByteHandlerAdapter} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an
* other.
*
* This kind of decoder is often useful for doing on-the-fly processiing like i.e. compression.
*
* But you can also do other things with it. For example here is an implementation which reads {@link Integer}s from
* the input {@link ByteBuf} and square them before write them to the output {@link ByteBuf}.
*
* <pre>
* public class SquareDecoder extends {@link ByteToByteDecoder} {
* {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value * value);
* }
* }
* </pre>
*/
public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter {
private volatile boolean singleDecode;
/**
* If set then only one message is decoded on each {@link #inboundBufferUpdated(ChannelHandlerContext)} call.
* This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up.
*
* Default is {@code false} as this has performance impacts.
*/
public void setSingleDecode(boolean singleDecode) {
this.singleDecode = singleDecode;
}
/**
* If {@code true} then only one message is decoded on each
* {@link #inboundBufferUpdated(ChannelHandlerContext)} call.
*
* Default is {@code false} as this has performance impacts.
*/
public boolean isSingleDecode() {
return singleDecode;
}
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
callDecode(ctx, in, ctx.nextInboundByteBuffer());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ByteBuf in = ctx.inboundByteBuffer();
ByteBuf out = ctx.nextInboundByteBuffer();
if (!in.isReadable()) {
callDecode(ctx, in, out);
}
int oldOutSize = out.readableBytes();
try {
decodeLast(ctx, in, out);
} catch (CodecException e) {
throw e;
} catch (Throwable t) {
throw new DecoderException(t);
} finally {
if (out.readableBytes() > oldOutSize) {
ctx.fireInboundBufferUpdated();
}
ctx.fireChannelInactive();
}
}
/**
* Call the {@link #decode(ChannelHandlerContext, ByteBuf, ByteBuf)} method until it is done.
*/
private void callDecode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) {
int oldOutSize = out.readableBytes();
try {
while (in.isReadable()) {
int oldInSize = in.readableBytes();
decode(ctx, in, out);
if (oldInSize == in.readableBytes() || isSingleDecode()) {
break;
}
}
} catch (CodecException e) {
throw e;
} catch (Throwable t) {
throw new DecoderException(t);
} finally {
if (out.readableBytes() > oldOutSize) {
ctx.fireInboundBufferUpdated();
}
}
}
/**
* Decode the from one {@link ByteBuf} to an other. This method will be called till either the input
* {@link ByteBuf} has nothing to read anymore or till nothing was read from the input {@link ByteBuf}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data
* @param out the {@link ByteBuf} to which the decoded data will be written
* @throws Exception is thrown if an error accour
*/
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception;
/**
* Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the
* {@link #channelInactive(ChannelHandlerContext)} was triggered.
*
* By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, ByteBuf)} but sub-classes may
* override this for some special cleanup operation.
*/
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
decode(ctx, in, out);
}
}

View File

@ -1,150 +0,0 @@
/*
* Copyright 2012 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;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundByteHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.FileRegion;
import io.netty.channel.IncompleteFlushException;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
/**
* {@link ChannelOutboundByteHandlerAdapter} which encodes bytes in a stream-like fashion from one {@link ByteBuf} to an
* other.
*
* This kind of decoder is often useful for doing on-the-fly processing like i.e. compression.
*
* But you can also do other things with it. For example here is an implementation which reads {@link Integer}s from
* the input {@link ByteBuf} and square them before write them to the output {@link ByteBuf}.
*
* <pre>
* public class SquareEncoder extends {@link ByteToByteEncoder} {
* {@code @Override}
* public void encode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value * value);
* }
* }
* </pre>
*/
public abstract class ByteToByteEncoder extends ChannelOutboundByteHandlerAdapter {
@Override
protected void flush(ChannelHandlerContext ctx, ByteBuf in, ChannelPromise promise) throws Exception {
ByteBuf out = ctx.nextOutboundByteBuffer();
boolean encoded = false;
try {
while (in.isReadable()) {
int oldInSize = in.readableBytes();
encode(ctx, in, out);
encoded = true;
if (oldInSize == in.readableBytes()) {
break;
}
}
} catch (Throwable t) {
if (!(t instanceof CodecException)) {
t = new EncoderException(t);
}
if (encoded) {
t = new IncompleteFlushException("unable to encode all bytes", t);
}
in.discardSomeReadBytes();
promise.setFailure(t);
return;
}
ctx.flush(promise);
}
@Override
public void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception {
long written = 0;
try {
for (;;) {
long localWritten = region.transferTo(new BufferChannel(ctx.outboundByteBuffer()), written);
if (localWritten == -1) {
checkEOF(region, written);
flush(ctx, promise);
break;
}
written += localWritten;
if (written >= region.count()) {
flush(ctx, promise);
break;
}
}
} catch (IOException e) {
promise.setFailure(new EncoderException(e));
} finally {
region.release();
}
}
private static void checkEOF(FileRegion region, long writtenBytes) throws IOException {
if (writtenBytes < region.count()) {
throw new EOFException("Expected to be able to write "
+ region.count() + " bytes, but only wrote "
+ writtenBytes);
}
}
private static final class BufferChannel implements WritableByteChannel {
private final ByteBuf buffer;
BufferChannel(ByteBuf buffer) {
this.buffer = buffer;
}
@Override
public int write(ByteBuffer src) {
int bytes = src.remaining();
buffer.writeBytes(src);
return bytes;
}
@Override
public boolean isOpen() {
return buffer.refCnt() > 0;
}
@Override
public void close() {
// NOOP
}
}
/**
* Encodes the from one {@link ByteBuf} to an other. This method will be called till either the input
* {@link ByteBuf} has nothing to read anymore or till nothing was read from the input {@link ByteBuf}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data
* @param out the {@link ByteBuf} to which the decoded data will be written
* @throws Exception is thrown if an error accour
*/
protected abstract void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception;
}

View File

@ -16,16 +16,13 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MessageList;
import io.netty.util.internal.TypeParameterMatcher;
public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler
implements ChannelInboundByteHandler, ChannelOutboundMessageHandler<I> {
public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler {
private final TypeParameterMatcher outboundMsgMatcher;
private final MessageToByteEncoder<I> encoder = new MessageToByteEncoder<I>() {
@ -42,12 +39,12 @@ public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler
private final ByteToMessageDecoder decoder = new ByteToMessageDecoder() {
@Override
public void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
public void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
ByteToMessageCodec.this.decode(ctx, in, out);
}
@Override
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
ByteToMessageCodec.this.decodeLast(ctx, in, out);
}
};
@ -60,38 +57,23 @@ public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler
outboundMsgMatcher = TypeParameterMatcher.get(outboundMessageType);
}
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return decoder.newInboundBuffer(ctx);
}
@Override
public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
decoder.discardInboundReadBytes(ctx);
}
@Override
public MessageBuf<I> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return encoder.newOutboundBuffer(ctx);
}
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
decoder.inboundBufferUpdated(ctx);
}
@Override
public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
encoder.flush(ctx, promise);
}
public boolean acceptOutboundMessage(Object msg) throws Exception {
return outboundMsgMatcher.match(msg);
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
decoder.messageReceived(ctx, msgs);
}
@Override
public void write(ChannelHandlerContext ctx, MessageList<Object> msgs, ChannelPromise promise) throws Exception {
encoder.write(ctx, msgs, promise);
}
protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception;
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception;
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
decode(ctx, in, out);
}
}

View File

@ -16,14 +16,15 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelInboundByteHandlerAdapter;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.MessageList;
import io.netty.util.internal.StringUtil;
/**
* {@link ChannelInboundByteHandler} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an other
* Message type.
* {@link ChannelInboundHandlerAdapter} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an
* other Message type.
*
* For example here is an implementation which reads all readable bytes from
* the input {@link ByteBuf} and create a new {@link ByteBuf}.
@ -31,22 +32,24 @@ import io.netty.channel.ChannelInboundByteHandlerAdapter;
* <pre>
* public class SquareDecoder extends {@link ByteToMessageDecoder} {
* {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link MessageBuf} out)
* public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link MessageList} out)
* throws {@link Exception} {
* out.add(in.readBytes(in.readableBytes()));
* }
* }
* </pre>
*/
public abstract class ByteToMessageDecoder
extends ChannelInboundByteHandlerAdapter {
public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter {
protected ByteBuf cumulation;
private volatile boolean singleDecode;
private boolean decodeWasNull;
private MessageList<Object> out;
private boolean removed;
/**
* If set then only one message is decoded on each {@link #inboundBufferUpdated(ChannelHandlerContext)} call.
* This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up.
* If set then only one message is decoded on each {@link #messageReceived(ChannelHandlerContext, MessageList)}
* call. This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up.
*
* Default is {@code false} as this has performance impacts.
*/
@ -56,7 +59,7 @@ public abstract class ByteToMessageDecoder
/**
* If {@code true} then only one message is decoded on each
* {@link #inboundBufferUpdated(ChannelHandlerContext)} call.
* {@link #messageReceived(ChannelHandlerContext, MessageList)} call.
*
* Default is {@code false} as this has performance impacts.
*/
@ -64,9 +67,119 @@ public abstract class ByteToMessageDecoder
return singleDecode;
}
/**
* Returns the actual number of readable bytes in the internal cumulative
* buffer of this decoder. You usually do not need to rely on this value
* to write a decoder. Use it only when you must use it at your own risk.
* This method is a shortcut to {@link #internalBuffer() internalBuffer().readableBytes()}.
*/
protected int actualReadableBytes() {
return internalBuffer().readableBytes();
}
/**
* Returns the internal cumulative buffer of this decoder. You usually
* do not need to access the internal buffer directly to write a decoder.
* Use it only when you must use it at your own risk.
*/
protected ByteBuf internalBuffer() {
if (cumulation != null) {
return cumulation;
} else {
return Unpooled.EMPTY_BUFFER;
}
}
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
callDecode(ctx, in);
public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
removed = true;
ByteBuf buf = internalBuffer();
if (buf.isReadable()) {
if (out == null) {
ctx.fireMessageReceived(buf);
} else {
out.add(buf.copy());
}
buf.clear();
}
handlerRemoved0();
}
/**
* Gets called after the {@link ByteToMessageDecoder} was removed from the actual context and it doesn't handle
* events anymore.
*/
protected void handlerRemoved0() throws Exception { }
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
out = MessageList.newInstance();
try {
int size = msgs.size();
for (int i = 0; i < size; i ++) {
Object m = msgs.get(i);
// handler was removed in the loop
if (removed) {
out.add(m);
continue;
}
if (m instanceof ByteBuf) {
ByteBuf data = (ByteBuf) m;
if (cumulation == null) {
cumulation = data;
try {
callDecode(ctx, data, out);
} finally {
if (!data.isReadable()) {
cumulation = null;
data.release();
}
}
} else {
try {
if (cumulation.writerIndex() > cumulation.maxCapacity() - data.readableBytes()) {
ByteBuf oldCumulation = cumulation;
cumulation = ctx.alloc().buffer(oldCumulation.readableBytes() + data.readableBytes());
cumulation.writeBytes(oldCumulation);
oldCumulation.release();
}
cumulation.writeBytes(data);
callDecode(ctx, cumulation, out);
} finally {
if (!cumulation.isReadable()) {
cumulation.release();
cumulation = null;
} else {
cumulation.discardSomeReadBytes();
}
data.release();
}
}
} else {
out.add(m);
}
}
} catch (DecoderException e) {
throw e;
} catch (Throwable t) {
throw new DecoderException(t);
} finally {
// release the cumulation if the handler was removed while messages are processed
if (removed) {
if (cumulation != null) {
cumulation.release();
cumulation = null;
}
removed = false;
}
MessageList<Object> out = this.out;
this.out = null;
if (out.isEmpty()) {
decodeWasNull = true;
}
msgs.recycle();
ctx.fireMessageReceived(out);
}
}
@Override
@ -82,35 +195,36 @@ public abstract class ByteToMessageDecoder
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
OutputMessageBuf out = OutputMessageBuf.get();
MessageList<Object> out = MessageList.newInstance();
try {
ByteBuf in = ctx.inboundByteBuffer();
if (in.isReadable()) {
callDecode(ctx, in);
if (cumulation != null) {
callDecode(ctx, cumulation, out);
decodeLast(ctx, cumulation, out);
} else {
decodeLast(ctx, Unpooled.EMPTY_BUFFER, out);
}
decodeLast(ctx, in, out);
} catch (CodecException e) {
} catch (DecoderException e) {
throw e;
} catch (Throwable cause) {
throw new DecoderException(cause);
} catch (Exception e) {
throw new DecoderException(e);
} finally {
if (out.drainToNextInbound(ctx)) {
ctx.fireInboundBufferUpdated();
if (cumulation != null) {
cumulation.release();
cumulation = null;
}
ctx.fireMessageReceived(out);
ctx.fireChannelInactive();
}
}
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in) {
boolean wasNull = false;
OutputMessageBuf out = OutputMessageBuf.get();
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) {
try {
while (in.isReadable()) {
int outSize = out.size();
int oldInputLength = in.readableBytes();
decode(ctx, in, out);
if (outSize == out.size()) {
wasNull = true;
if (oldInputLength == in.readableBytes()) {
break;
} else {
@ -118,10 +232,10 @@ public abstract class ByteToMessageDecoder
}
}
wasNull = false;
if (oldInputLength == in.readableBytes()) {
throw new IllegalStateException(
"decode() did not read anything but decoded a message.");
throw new DecoderException(
StringUtil.simpleClassName(getClass()) +
".decode() did not read anything but decoded a message.");
}
if (isSingleDecode()) {
@ -132,15 +246,6 @@ public abstract class ByteToMessageDecoder
throw e;
} catch (Throwable cause) {
throw new DecoderException(cause);
} finally {
if (out.drainToNextInbound(ctx)) {
decodeWasNull = false;
ctx.fireInboundBufferUpdated();
} else {
if (wasNull) {
decodeWasNull = true;
}
}
}
}
@ -149,22 +254,22 @@ public abstract class ByteToMessageDecoder
* {@link ByteBuf} has nothing to read anymore, till nothing was read from the input {@link ByteBuf} or till
* this method returns {@code null}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data
* @param out the {@link MessageBuf} to which decoded messages should be added
* @param out the {@link MessageList} to which decoded messages should be added
* @throws Exception is thrown if an error accour
*/
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception;
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception;
/**
* Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the
* {@link #channelInactive(ChannelHandlerContext)} was triggered.
*
* By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, MessageBuf)} but sub-classes may
* By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, MessageList)} but sub-classes may
* override this for some special cleanup operation.
*/
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
decode(ctx, in, out);
}
}

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
/**
* A decoder that splits the received {@link ByteBuf}s by one or more
@ -211,7 +211,7 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);

View File

@ -16,9 +16,8 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.MessageList;
/**
* A decoder that splits the received {@link ByteBuf}s by the fixed number
@ -39,51 +38,30 @@ import io.netty.channel.ChannelHandlerUtil;
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
private final int frameLength;
private final boolean allocateFullBuffer;
/**
* Calls {@link #FixedLengthFrameDecoder(int, boolean)} with {@code false}
*/
public FixedLengthFrameDecoder(int frameLength) {
this(frameLength, false);
}
/**
* Creates a new instance.
*
* @param frameLength
* the length of the frame
* @param allocateFullBuffer
* {@code true} if the cumulative {@link ByteBuf} should use the
* {@link #frameLength} as its initial size
* @param frameLength the length of the frame
*/
public FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer) {
public FixedLengthFrameDecoder(int frameLength) {
if (frameLength <= 0) {
throw new IllegalArgumentException(
"frameLength must be a positive integer: " + frameLength);
}
this.frameLength = frameLength;
this.allocateFullBuffer = allocateFullBuffer;
}
@Override
public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
if (allocateFullBuffer) {
return ChannelHandlerUtil.allocate(ctx, frameLength);
} else {
return super.newInboundBuffer(ctx);
}
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);
}
}
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
protected Object decode(
@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < frameLength) {
return null;
} else {

View File

@ -16,9 +16,9 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
import io.netty.handler.codec.serialization.ObjectDecoder;
import java.nio.ByteOrder;
@ -348,7 +348,7 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.MessageList;
/**
* A decoder that splits the received {@link ByteBuf}s on line endings.
@ -69,7 +69,7 @@ public class LineBasedFrameDecoder extends ByteToMessageDecoder {
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);

View File

@ -16,13 +16,16 @@
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundMessageHandlerAdapter;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MessageList;
import io.netty.util.internal.TypeParameterMatcher;
/**
* {@link ChannelOutboundMessageHandlerAdapter} which encodes message in a stream-like fashion from one message to an
* {@link ChannelOutboundHandlerAdapter} which encodes message in a stream-like fashion from one message to an
* {@link ByteBuf}.
*
*
@ -38,27 +41,73 @@ import io.netty.channel.ChannelOutboundMessageHandlerAdapter;
* }
* </pre>
*/
public abstract class MessageToByteEncoder<I> extends ChannelOutboundMessageHandlerAdapter<I> {
public abstract class MessageToByteEncoder<I> extends ChannelOutboundHandlerAdapter {
protected MessageToByteEncoder() { }
private final TypeParameterMatcher matcher;
protected MessageToByteEncoder() {
matcher = TypeParameterMatcher.find(this, MessageToByteEncoder.class, "I");
}
protected MessageToByteEncoder(Class<? extends I> outboundMessageType) {
super(outboundMessageType);
matcher = TypeParameterMatcher.get(outboundMessageType);
}
public boolean acceptOutboundMessage(Object msg) throws Exception {
return matcher.match(msg);
}
@Override
public void flush(ChannelHandlerContext ctx, I msg) throws Exception {
public void write(ChannelHandlerContext ctx, MessageList<Object> msgs, ChannelPromise promise) throws Exception {
MessageList<Object> out = MessageList.newInstance();
boolean success = false;
try {
encode(ctx, msg, ctx.nextOutboundByteBuffer());
} catch (CodecException e) {
ByteBuf buf = null;
int size = msgs.size();
for (int i = 0; i < size; i ++) {
Object m = msgs.get(i);
if (acceptOutboundMessage(m)) {
@SuppressWarnings("unchecked")
I cast = (I) m;
if (buf == null) {
buf = ctx.alloc().buffer();
}
try {
encode(ctx, cast, buf);
} finally {
ByteBufUtil.release(cast);
}
} else {
if (buf != null && buf.isReadable()) {
out.add(buf);
buf = null;
}
out.add(m);
}
}
if (buf != null && buf.isReadable()) {
out.add(buf);
}
success = true;
} catch (EncoderException e) {
throw e;
} catch (Exception e) {
throw new CodecException(e);
} catch (Throwable e) {
throw new EncoderException(e);
} finally {
msgs.recycle();
if (success) {
ctx.write(out, promise);
} else {
out.releaseAllAndRecycle();
}
}
}
/**
* Encode a message into a {@link ByteBuf}. This method will be called till the {@link MessageBuf} has
* Encode a message into a {@link ByteBuf}. This method will be called till the {@link MessageList} has
* nothing left.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs to

View File

@ -15,12 +15,10 @@
*/
package io.netty.handler.codec;
import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MessageList;
import io.netty.util.internal.TypeParameterMatcher;
/**
@ -48,13 +46,10 @@ import io.netty.util.internal.TypeParameterMatcher;
* }
* </pre>
*/
public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN>
extends ChannelDuplexHandler
implements ChannelInboundMessageHandler<INBOUND_IN>,
ChannelOutboundMessageHandler<OUTBOUND_IN> {
public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN> extends ChannelDuplexHandler {
private final MessageToMessageEncoder<Object> encoder = new MessageToMessageEncoder<Object>() {
private final MessageToMessageEncoder<Object> encoder =
new MessageToMessageEncoder<Object>() {
@Override
public boolean acceptOutboundMessage(Object msg) throws Exception {
return MessageToMessageCodec.this.acceptOutboundMessage(msg);
@ -62,13 +57,12 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN>
@Override
@SuppressWarnings("unchecked")
protected void encode(ChannelHandlerContext ctx, Object msg, MessageBuf<Object> out) throws Exception {
protected void encode(ChannelHandlerContext ctx, Object msg, MessageList<Object> out) throws Exception {
MessageToMessageCodec.this.encode(ctx, (OUTBOUND_IN) msg, out);
}
};
private final MessageToMessageDecoder<Object> decoder =
new MessageToMessageDecoder<Object>() {
private final MessageToMessageDecoder<Object> decoder = new MessageToMessageDecoder<Object>() {
@Override
public boolean acceptInboundMessage(Object msg) throws Exception {
@ -77,7 +71,7 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN>
@Override
@SuppressWarnings("unchecked")
protected void decode(ChannelHandlerContext ctx, Object msg, MessageBuf<Object> out) throws Exception {
protected void decode(ChannelHandlerContext ctx, Object msg, MessageList<Object> out) throws Exception {
MessageToMessageCodec.this.decode(ctx, (INBOUND_IN) msg, out);
}
};
@ -97,26 +91,13 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN>
}
@Override
@SuppressWarnings("unchecked")
public MessageBuf<INBOUND_IN> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return (MessageBuf<INBOUND_IN>) decoder.newInboundBuffer(ctx);
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
decoder.messageReceived(ctx, msgs);
}
@Override
@SuppressWarnings("unchecked")
public MessageBuf<OUTBOUND_IN> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return (MessageBuf<OUTBOUND_IN>) encoder.newOutboundBuffer(ctx);
}
@Override
public void inboundBufferUpdated(
ChannelHandlerContext ctx) throws Exception {
decoder.inboundBufferUpdated(ctx);
}
@Override
public void flush(ChannelHandlerContext ctx, ChannelPromise future) throws Exception {
encoder.flush(ctx, future);
public void write(ChannelHandlerContext ctx, MessageList<Object> msgs, ChannelPromise promise) throws Exception {
encoder.write(ctx, msgs, promise);
}
/**
@ -137,6 +118,8 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN>
return outboundMsgMatcher.match(msg);
}
protected abstract void encode(ChannelHandlerContext ctx, OUTBOUND_IN msg, MessageBuf<Object> out) throws Exception;
protected abstract void decode(ChannelHandlerContext ctx, INBOUND_IN msg, MessageBuf<Object> out) throws Exception;
protected abstract void encode(ChannelHandlerContext ctx, OUTBOUND_IN msg, MessageList<Object> out)
throws Exception;
protected abstract void decode(ChannelHandlerContext ctx, INBOUND_IN msg, MessageList<Object> out)
throws Exception;
}

View File

@ -15,13 +15,14 @@
*/
package io.netty.handler.codec;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.MessageList;
import io.netty.util.internal.TypeParameterMatcher;
/**
* {@link ChannelInboundMessageHandler} which decodes from one message to an other message
* {@link ChannelInboundHandlerAdapter} which decodes from one message to an other message
*
* For example here is an implementation which decodes a {@link String} to an {@link Integer} which represent
* the length of the {@link String}.
@ -32,43 +33,66 @@ import io.netty.channel.ChannelInboundMessageHandlerAdapter;
*
* {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link String} message,
* {@link MessageBuf} out) throws {@link Exception} {
* {@link MessageList} out) throws {@link Exception} {
* out.add(message.length());
* }
* }
* </pre>
*
*/
public abstract class MessageToMessageDecoder<I> extends ChannelInboundMessageHandlerAdapter<I> {
public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAdapter {
protected MessageToMessageDecoder() { }
private final TypeParameterMatcher matcher;
protected MessageToMessageDecoder() {
matcher = TypeParameterMatcher.find(this, MessageToMessageDecoder.class, "I");
}
protected MessageToMessageDecoder(Class<? extends I> inboundMessageType) {
super(inboundMessageType);
matcher = TypeParameterMatcher.get(inboundMessageType);
}
public boolean acceptInboundMessage(Object msg) throws Exception {
return matcher.match(msg);
}
@Override
public final void messageReceived(ChannelHandlerContext ctx, I msg) throws Exception {
OutputMessageBuf out = OutputMessageBuf.get();
public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) throws Exception {
MessageList<Object> out = MessageList.newInstance();
try {
decode(ctx, msg, out);
} catch (CodecException e) {
throw e;
} catch (Throwable cause) {
throw new DecoderException(cause);
int size = msgs.size();
for (int i = 0; i < size; i ++) {
Object m = msgs.get(i);
if (acceptInboundMessage(m)) {
@SuppressWarnings("unchecked")
I cast = (I) m;
try {
decode(ctx, cast, out);
} finally {
out.drainToNextInbound(ctx);
ByteBufUtil.release(cast);
}
} else {
out.add(m);
}
}
} catch (DecoderException e) {
throw e;
} catch (Exception e) {
throw new DecoderException(e);
} finally {
msgs.recycle();
ctx.fireMessageReceived(out);
}
}
/**
* Decode from one message to an other. This method will be called till either the {@link MessageBuf} has
* Decode from one message to an other. This method will be called till either the {@link MessageList} has
* nothing left or till this method returns {@code null}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageDecoder} belongs to
* @param msg the message to decode to an other one
* @param out the {@link MessageBuf} to which decoded messages should be added
* @param out the {@link MessageList} to which decoded messages should be added
* @throws Exception is thrown if an error accour
*/
protected abstract void decode(ChannelHandlerContext ctx, I msg, MessageBuf<Object> out) throws Exception;
protected abstract void decode(ChannelHandlerContext ctx, I msg, MessageList<Object> out) throws Exception;
}

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