Make retained derived buffers recyclable

Related: #4333 #4421 #5128

Motivation:

slice(), duplicate() and readSlice() currently create a non-recyclable
derived buffer instance. Under heavy load, an application that creates a
lot of derived buffers can put the garbage collector under pressure.

Modifications:

- Add the following methods which creates a non-recyclable derived buffer
  - retainedSlice()
  - retainedDuplicate()
  - readRetainedSlice()
- Add the new recyclable derived buffer implementations, which has its
  own reference count value
- Add ByteBufHolder.retainedDuplicate()
- Add ByteBufHolder.replace(ByteBuf) so that..
  - a user can replace the content of the holder in a consistent way
  - copy/duplicate/retainedDuplicate() can delegate the holder
    construction to replace(ByteBuf)
- Use retainedDuplicate() and retainedSlice() wherever possible
- Miscellaneous:
  - Rename DuplicateByteBufTest to DuplicatedByteBufTest (missing 'D')
  - Make ReplayingDecoderByteBuf.reject() return an exception instead of
    throwing it so that its callers don't need to add dummy return
    statement

Result:

Derived buffers are now recycled when created via retainedSlice() and
retainedDuplicate() and derived from a pooled buffer
This commit is contained in:
Trustin Lee 2016-04-14 17:31:48 +09:00 committed by Norman Maurer
parent 68cd670eb9
commit 3a9f472161
131 changed files with 2641 additions and 734 deletions

View File

@ -836,6 +836,13 @@ public abstract class AbstractByteBuf extends ByteBuf {
return slice; return slice;
} }
@Override
public ByteBuf readRetainedSlice(int length) {
ByteBuf slice = retainedSlice(readerIndex, length);
readerIndex += length;
return slice;
}
@Override @Override
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
checkReadableBytes(length); checkReadableBytes(length);
@ -1159,16 +1166,31 @@ public abstract class AbstractByteBuf extends ByteBuf {
return new DuplicatedAbstractByteBuf(this); return new DuplicatedAbstractByteBuf(this);
} }
@Override
public ByteBuf retainedDuplicate() {
return duplicate().retain();
}
@Override @Override
public ByteBuf slice() { public ByteBuf slice() {
return slice(readerIndex, readableBytes()); return slice(readerIndex, readableBytes());
} }
@Override
public ByteBuf retainedSlice() {
return slice().retain();
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return new SlicedAbstractByteBuf(this, index, length); return new SlicedAbstractByteBuf(this, index, length);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return slice(index, length).retain();
}
@Override @Override
public ByteBuffer nioBuffer() { public ByteBuffer nioBuffer() {
return nioBuffer(readerIndex, readableBytes()); return nioBuffer(readerIndex, readableBytes());

View File

@ -0,0 +1,134 @@
/*
* Copyright 2016 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.Recycler.Handle;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Abstract base class for derived {@link ByteBuf} implementations.
*/
abstract class AbstractPooledDerivedByteBuf<T> extends AbstractReferenceCountedByteBuf {
private final Handle<AbstractPooledDerivedByteBuf<T>> recyclerHandle;
private AbstractByteBuf buffer;
@SuppressWarnings("unchecked")
AbstractPooledDerivedByteBuf(Handle<? extends AbstractPooledDerivedByteBuf<T>> recyclerHandle) {
super(0);
this.recyclerHandle = (Handle<AbstractPooledDerivedByteBuf<T>>) recyclerHandle;
}
@Override
public final AbstractByteBuf unwrap() {
return buffer;
}
final <U extends AbstractPooledDerivedByteBuf<T>> U init(
AbstractByteBuf buffer, int readerIndex, int writerIndex, int maxCapacity) {
buffer.retain();
this.buffer = buffer;
boolean success = false;
try {
maxCapacity(maxCapacity);
setIndex(readerIndex, writerIndex);
setRefCnt(1);
@SuppressWarnings("unchecked")
final U castThis = (U) this;
success = true;
return castThis;
} finally {
if (!success) {
this.buffer = null;
buffer.release();
}
}
}
@Override
protected final void deallocate() {
recyclerHandle.recycle(this);
unwrap().release();
}
@Override
public final ByteBufAllocator alloc() {
return unwrap().alloc();
}
@Override
@Deprecated
public final ByteOrder order() {
return unwrap().order();
}
@Override
public boolean isReadOnly() {
return unwrap().isReadOnly();
}
@Override
public final boolean isDirect() {
return unwrap().isDirect();
}
@Override
public boolean hasArray() {
return unwrap().hasArray();
}
@Override
public byte[] array() {
return unwrap().array();
}
@Override
public boolean hasMemoryAddress() {
return unwrap().hasMemoryAddress();
}
@Override
public final int nioBufferCount() {
return unwrap().nioBufferCount();
}
@Override
public final ByteBuffer internalNioBuffer(int index, int length) {
return nioBuffer(index, length);
}
@Override
public final ByteBuf retainedDuplicate() {
return PooledDuplicatedByteBuf.newInstance(this, readerIndex(), writerIndex());
}
@Override
public final ByteBuf retainedSlice() {
final int index = readerIndex();
return retainedSlice(index, writerIndex() - index);
}
@Override
public final ByteBuf retainedSlice(int index, int length) {
return PooledSlicedByteBuf.newInstance(this, index, length, index);
}
}

View File

@ -76,24 +76,48 @@ final class AdvancedLeakAwareByteBuf extends WrappedByteBuf {
return new AdvancedLeakAwareByteBuf(super.slice(), leak); return new AdvancedLeakAwareByteBuf(super.slice(), leak);
} }
@Override
public ByteBuf retainedSlice() {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.retainedSlice(), leak);
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.slice(index, length), leak); return new AdvancedLeakAwareByteBuf(super.slice(index, length), leak);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.retainedSlice(index, length), leak);
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.duplicate(), leak); return new AdvancedLeakAwareByteBuf(super.duplicate(), leak);
} }
@Override
public ByteBuf retainedDuplicate() {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.retainedDuplicate(), leak);
}
@Override @Override
public ByteBuf readSlice(int length) { public ByteBuf readSlice(int length) {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.readSlice(length), leak); return new AdvancedLeakAwareByteBuf(super.readSlice(length), leak);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.readRetainedSlice(length), leak);
}
@Override @Override
public ByteBuf discardReadBytes() { public ByteBuf discardReadBytes() {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);

View File

@ -58,24 +58,48 @@ final class AdvancedLeakAwareCompositeByteBuf extends WrappedCompositeByteBuf {
return new AdvancedLeakAwareByteBuf(super.slice(), leak); return new AdvancedLeakAwareByteBuf(super.slice(), leak);
} }
@Override
public ByteBuf retainedSlice() {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.retainedSlice(), leak);
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.slice(index, length), leak); return new AdvancedLeakAwareByteBuf(super.slice(index, length), leak);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.retainedSlice(index, length), leak);
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.duplicate(), leak); return new AdvancedLeakAwareByteBuf(super.duplicate(), leak);
} }
@Override
public ByteBuf retainedDuplicate() {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.retainedDuplicate(), leak);
}
@Override @Override
public ByteBuf readSlice(int length) { public ByteBuf readSlice(int length) {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.readSlice(length), leak); return new AdvancedLeakAwareByteBuf(super.readSlice(length), leak);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
recordLeakNonRefCountingOperation(leak);
return new AdvancedLeakAwareByteBuf(super.readRetainedSlice(length), leak);
}
@Override @Override
public CompositeByteBuf discardReadBytes() { public CompositeByteBuf discardReadBytes() {
recordLeakNonRefCountingOperation(leak); recordLeakNonRefCountingOperation(leak);

View File

@ -194,17 +194,31 @@ import java.nio.charset.UnsupportedCharsetException;
* *
* <h3>Derived buffers</h3> * <h3>Derived buffers</h3>
* *
* You can create a view of an existing buffer by calling either * You can create a view of an existing buffer by calling one of the following methods:
* {@link #duplicate()}, {@link #slice()} or {@link #slice(int, int)}. * <ul>
* <li>{@link #duplicate()}</li>
* <li>{@link #slice()}</li>
* <li>{@link #slice(int, int)}</li>
* <li>{@link #readSlice(int)}</li>
* <li>{@link #retainedDuplicate()}</li>
* <li>{@link #retainedSlice()}</li>
* <li>{@link #retainedSlice(int, int)}</li>
* <li>{@link #readRetainedSlice(int)}</li>
* </ul>
* A derived buffer will have an independent {@link #readerIndex() readerIndex}, * A derived buffer will have an independent {@link #readerIndex() readerIndex},
* {@link #writerIndex() writerIndex} and marker indexes, while it shares * {@link #writerIndex() writerIndex} and marker indexes, while it shares
* other internal data representation, just like a NIO buffer does. * other internal data representation, just like a NIO buffer does.
* <p> * <p>
* In case a completely fresh copy of an existing buffer is required, please * In case a completely fresh copy of an existing buffer is required, please
* call {@link #copy()} method instead. * call {@link #copy()} method instead.
* <p> *
* Also be aware that obtaining derived buffers will NOT call {@link #retain()} and so the * <h4>Non-retained and retained derived buffers</h4>
* reference count will NOT be increased. *
* Note that the {@link #duplicate()}, {@link #slice()}, {@link #slice(int, int)} and {@link #readSlice(int)} does NOT
* call {@link #retain()} on the returned derived buffer, and thus its reference count will NOT be increased. If you
* need to create a derived buffer with increased reference count, consider using {@link #retainedDuplicate()},
* {@link #retainedSlice()}, {@link #retainedSlice(int, int)} and {@link #readRetainedSlice(int)} which may return
* a buffer implementation that produces less garbage.
* *
* <h3>Conversion to existing JDK types</h3> * <h3>Conversion to existing JDK types</h3>
* *
@ -1491,6 +1505,24 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
*/ */
public abstract ByteBuf readSlice(int length); public abstract ByteBuf readSlice(int length);
/**
* Returns a new retained slice of this buffer's sub-region starting at the current
* {@code readerIndex} and increases the {@code readerIndex} by the size
* of the new slice (= {@code length}).
* <p>
* Note that this method returns a {@linkplain #retain() retained} buffer unlike {@link #readSlice(int)}.
* This method behaves similarly to {@code readSlice(...).retain()} except that this method may return
* a buffer implementation that produces less garbage.
*
* @param length the size of the new slice
*
* @return the newly created slice
*
* @throws IndexOutOfBoundsException
* if {@code length} is greater than {@code this.readableBytes}
*/
public abstract ByteBuf readRetainedSlice(int length);
/** /**
* Transfers this buffer's data to the specified destination starting at * Transfers this buffer's data to the specified destination starting at
* the current {@code readerIndex} until the destination becomes * the current {@code readerIndex} until the destination becomes
@ -2060,6 +2092,20 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
*/ */
public abstract ByteBuf slice(); public abstract ByteBuf slice();
/**
* Returns a retained slice of this buffer's readable bytes. Modifying the content
* of the returned buffer or this buffer affects each other's content
* while they maintain separate indexes and marks. This method is
* identical to {@code buf.slice(buf.readerIndex(), buf.readableBytes())}.
* This method does not modify {@code readerIndex} or {@code writerIndex} of
* this buffer.
* <p>
* Note that this method returns a {@linkplain #retain() retained} buffer unlike {@link #slice()}.
* This method behaves similarly to {@code slice().retain()} except that this method may return
* a buffer implementation that produces less garbage.
*/
public abstract ByteBuf retainedSlice();
/** /**
* Returns a slice of this buffer's sub-region. Modifying the content of * Returns a slice of this buffer's sub-region. Modifying the content of
* the returned buffer or this buffer affects each other's content while * the returned buffer or this buffer affects each other's content while
@ -2072,6 +2118,19 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
*/ */
public abstract ByteBuf slice(int index, int length); public abstract ByteBuf slice(int index, int length);
/**
* Returns a retained slice of this buffer's sub-region. Modifying the content of
* the returned buffer or this buffer affects each other's content while
* they maintain separate indexes and marks.
* This method does not modify {@code readerIndex} or {@code writerIndex} of
* this buffer.
* <p>
* Note that this method returns a {@linkplain #retain() retained} buffer unlike {@link #slice(int, int)}.
* This method behaves similarly to {@code slice(...).retain()} except that this method may return
* a buffer implementation that produces less garbage.
*/
public abstract ByteBuf retainedSlice(int index, int length);
/** /**
* Returns a buffer which shares the whole region of this buffer. * Returns a buffer which shares the whole region of this buffer.
* Modifying the content of the returned buffer or this buffer affects * Modifying the content of the returned buffer or this buffer affects
@ -2085,6 +2144,20 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
*/ */
public abstract ByteBuf duplicate(); public abstract ByteBuf duplicate();
/**
* Returns a retained buffer which shares the whole region of this buffer.
* Modifying the content of the returned buffer or this buffer affects
* each other's content while they maintain separate indexes and marks.
* This method is identical to {@code buf.slice(0, buf.capacity())}.
* This method does not modify {@code readerIndex} or {@code writerIndex} of
* this buffer.
* <p>
* Note that this method returns a {@linkplain #retain() retained} buffer unlike {@link #slice(int, int)}.
* This method behaves similarly to {@code duplicate().retain()} except that this method may return
* a buffer implementation that produces less garbage.
*/
public abstract ByteBuf retainedDuplicate();
/** /**
* Returns the maximum number of NIO {@link ByteBuffer}s that consist this buffer. Note that {@link #nioBuffers()} * Returns the maximum number of NIO {@link ByteBuffer}s that consist this buffer. Note that {@link #nioBuffers()}
* or {@link #nioBuffers(int, int)} might return a less number of {@link ByteBuffer}s. * or {@link #nioBuffers(int, int)} might return a less number of {@link ByteBuffer}s.

View File

@ -28,15 +28,27 @@ public interface ByteBufHolder extends ReferenceCounted {
ByteBuf content(); ByteBuf content();
/** /**
* Create a deep copy of this {@link ByteBufHolder}. * Creates a deep copy of this {@link ByteBufHolder}.
*/ */
ByteBufHolder copy(); ByteBufHolder copy();
/** /**
* Duplicate the {@link ByteBufHolder}. Be aware that this will not automatically call {@link #retain()}. * Duplicates this {@link ByteBufHolder}. Be aware that this will not automatically call {@link #retain()}.
*/ */
ByteBufHolder duplicate(); ByteBufHolder duplicate();
/**
* Duplicates this {@link ByteBufHolder}. This method returns a retained duplicate unlike {@link #duplicate()}.
*
* @see ByteBuf#retainedDuplicate()
*/
ByteBufHolder retainedDuplicate();
/**
* Returns a new {@link ByteBufHolder} which contains the specified {@code content}.
*/
ByteBufHolder replace(ByteBuf content);
@Override @Override
ByteBufHolder retain(); ByteBufHolder retain();

View File

@ -41,14 +41,46 @@ public class DefaultByteBufHolder implements ByteBufHolder {
return data; return data;
} }
/**
* {@inheritDoc}
* <p>
* This method calls {@code replace(content().copy())} by default.
*/
@Override @Override
public ByteBufHolder copy() { public ByteBufHolder copy() {
return new DefaultByteBufHolder(data.copy()); return replace(data.copy());
} }
/**
* {@inheritDoc}
* <p>
* This method calls {@code replace(content().duplicate())} by default.
*/
@Override @Override
public ByteBufHolder duplicate() { public ByteBufHolder duplicate() {
return new DefaultByteBufHolder(data.duplicate()); return replace(data.duplicate());
}
/**
* {@inheritDoc}
* <p>
* This method calls {@code replace(content().retainedDuplicate())} by default.
*/
@Override
public ByteBufHolder retainedDuplicate() {
return replace(data.retainedDuplicate());
}
/**
* {@inheritDoc}
* <p>
* Override this method to return a new instance of this object whose content is set to the specified
* {@code content}. The default implementation of {@link #copy()}, {@link #duplicate()} and
* {@link #retainedDuplicate()} invokes this method to create a copy.
*/
@Override
public ByteBufHolder replace(ByteBuf content) {
return new DefaultByteBufHolder(content);
} }
@Override @Override

View File

@ -39,6 +39,10 @@ public class DuplicatedByteBuf extends AbstractDerivedByteBuf {
private final ByteBuf buffer; private final ByteBuf buffer;
public DuplicatedByteBuf(ByteBuf buffer) { public DuplicatedByteBuf(ByteBuf buffer) {
this(buffer, buffer.readerIndex(), buffer.writerIndex());
}
DuplicatedByteBuf(ByteBuf buffer, int readerIndex, int writerIndex) {
super(buffer.maxCapacity()); super(buffer.maxCapacity());
if (buffer instanceof DuplicatedByteBuf) { if (buffer instanceof DuplicatedByteBuf) {
@ -47,7 +51,7 @@ public class DuplicatedByteBuf extends AbstractDerivedByteBuf {
this.buffer = buffer; this.buffer = buffer;
} }
setIndex(buffer.readerIndex(), buffer.writerIndex()); setIndex(readerIndex, writerIndex);
markReaderIndex(); markReaderIndex();
markWriterIndex(); markWriterIndex();
} }

View File

@ -630,6 +630,11 @@ public final class EmptyByteBuf extends ByteBuf {
return checkLength(length); return checkLength(length);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
return checkLength(length);
}
@Override @Override
public ByteBuf readBytes(ByteBuf dst) { public ByteBuf readBytes(ByteBuf dst) {
return checkLength(dst.writableBytes()); return checkLength(dst.writableBytes());
@ -872,16 +877,31 @@ public final class EmptyByteBuf extends ByteBuf {
return this; return this;
} }
@Override
public ByteBuf retainedSlice() {
return this;
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return checkIndex(index, length); return checkIndex(index, length);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return checkIndex(index, length);
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
return this; return this;
} }
@Override
public ByteBuf retainedDuplicate() {
return this;
}
@Override @Override
public int nioBufferCount() { public int nioBufferCount() {
return 1; return 1;

View File

@ -136,6 +136,22 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
return null; return null;
} }
@Override
public final ByteBuf retainedDuplicate() {
return PooledDuplicatedByteBuf.newInstance(this, readerIndex(), writerIndex());
}
@Override
public final ByteBuf retainedSlice() {
final int index = readerIndex();
return retainedSlice(index, writerIndex() - index);
}
@Override
public final ByteBuf retainedSlice(int index, int length) {
return PooledSlicedByteBuf.newInstance(this, index, length, index);
}
protected final ByteBuffer internalNioBuffer() { protected final ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.tmpNioBuf; ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) { if (tmpNioBuf == null) {

View File

@ -0,0 +1,360 @@
/*
* Copyright 2016 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.ByteProcessor;
import io.netty.util.Recycler;
import io.netty.util.Recycler.Handle;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
final class PooledDuplicatedByteBuf extends AbstractPooledDerivedByteBuf<PooledDuplicatedByteBuf> {
private static final Recycler<PooledDuplicatedByteBuf> RECYCLER = new Recycler<PooledDuplicatedByteBuf>() {
@Override
protected PooledDuplicatedByteBuf newObject(Handle<PooledDuplicatedByteBuf> handle) {
return new PooledDuplicatedByteBuf(handle);
}
};
static PooledDuplicatedByteBuf newInstance(AbstractByteBuf buffer, int readerIndex, int writerIndex) {
final PooledDuplicatedByteBuf duplicate = RECYCLER.get();
duplicate.init(buffer, readerIndex, writerIndex, buffer.maxCapacity());
duplicate.markReaderIndex();
duplicate.markWriterIndex();
return duplicate;
}
private PooledDuplicatedByteBuf(Handle<PooledDuplicatedByteBuf> handle) {
super(handle);
}
@Override
public int capacity() {
return unwrap().capacity();
}
@Override
public ByteBuf capacity(int newCapacity) {
unwrap().capacity(newCapacity);
return this;
}
@Override
public int arrayOffset() {
return unwrap().arrayOffset();
}
@Override
public long memoryAddress() {
return unwrap().memoryAddress();
}
@Override
public ByteBuffer nioBuffer(int index, int length) {
return unwrap().nioBuffer(index, length);
}
@Override
public ByteBuffer[] nioBuffers(int index, int length) {
return unwrap().nioBuffers(index, length);
}
@Override
public ByteBuf copy(int index, int length) {
return unwrap().copy(index, length);
}
@Override
public byte getByte(int index) {
return unwrap().getByte(index);
}
@Override
protected byte _getByte(int index) {
return unwrap()._getByte(index);
}
@Override
public short getShort(int index) {
return unwrap().getShort(index);
}
@Override
protected short _getShort(int index) {
return unwrap()._getShort(index);
}
@Override
public short getShortLE(int index) {
return unwrap().getShortLE(index);
}
@Override
protected short _getShortLE(int index) {
return unwrap()._getShortLE(index);
}
@Override
public int getUnsignedMedium(int index) {
return unwrap().getUnsignedMedium(index);
}
@Override
protected int _getUnsignedMedium(int index) {
return unwrap()._getUnsignedMedium(index);
}
@Override
public int getUnsignedMediumLE(int index) {
return unwrap().getUnsignedMediumLE(index);
}
@Override
protected int _getUnsignedMediumLE(int index) {
return unwrap()._getUnsignedMediumLE(index);
}
@Override
public int getInt(int index) {
return unwrap().getInt(index);
}
@Override
protected int _getInt(int index) {
return unwrap()._getInt(index);
}
@Override
public int getIntLE(int index) {
return unwrap().getIntLE(index);
}
@Override
protected int _getIntLE(int index) {
return unwrap()._getIntLE(index);
}
@Override
public long getLong(int index) {
return unwrap().getLong(index);
}
@Override
protected long _getLong(int index) {
return unwrap()._getLong(index);
}
@Override
public long getLongLE(int index) {
return unwrap().getLongLE(index);
}
@Override
protected long _getLongLE(int index) {
return unwrap()._getLongLE(index);
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
unwrap().getBytes(index, dst, dstIndex, length);
return this;
}
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
unwrap().getBytes(index, dst, dstIndex, length);
return this;
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
unwrap().getBytes(index, dst);
return this;
}
@Override
public ByteBuf setByte(int index, int value) {
unwrap().setByte(index, value);
return this;
}
@Override
protected void _setByte(int index, int value) {
unwrap()._setByte(index, value);
}
@Override
public ByteBuf setShort(int index, int value) {
unwrap().setShort(index, value);
return this;
}
@Override
protected void _setShort(int index, int value) {
unwrap()._setShort(index, value);
}
@Override
public ByteBuf setShortLE(int index, int value) {
unwrap().setShortLE(index, value);
return this;
}
@Override
protected void _setShortLE(int index, int value) {
unwrap()._setShortLE(index, value);
}
@Override
public ByteBuf setMedium(int index, int value) {
unwrap().setMedium(index, value);
return this;
}
@Override
protected void _setMedium(int index, int value) {
unwrap()._setMedium(index, value);
}
@Override
public ByteBuf setMediumLE(int index, int value) {
unwrap().setMediumLE(index, value);
return this;
}
@Override
protected void _setMediumLE(int index, int value) {
unwrap()._setMediumLE(index, value);
}
@Override
public ByteBuf setInt(int index, int value) {
unwrap().setInt(index, value);
return this;
}
@Override
protected void _setInt(int index, int value) {
unwrap()._setInt(index, value);
}
@Override
public ByteBuf setIntLE(int index, int value) {
unwrap().setIntLE(index, value);
return this;
}
@Override
protected void _setIntLE(int index, int value) {
unwrap()._setIntLE(index, value);
}
@Override
public ByteBuf setLong(int index, long value) {
unwrap().setLong(index, value);
return this;
}
@Override
protected void _setLong(int index, long value) {
unwrap()._setLong(index, value);
}
@Override
public ByteBuf setLongLE(int index, long value) {
unwrap().setLongLE(index, value);
return this;
}
@Override
protected void _setLongLE(int index, long value) {
unwrap().setLongLE(index, value);
}
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
unwrap().setBytes(index, src, srcIndex, length);
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
unwrap().setBytes(index, src, srcIndex, length);
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
unwrap().setBytes(index, src);
return this;
}
@Override
public ByteBuf getBytes(int index, OutputStream out, int length)
throws IOException {
unwrap().getBytes(index, out, length);
return this;
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length)
throws IOException {
return unwrap().getBytes(index, out, length);
}
@Override
public int getBytes(int index, FileChannel out, long position, int length)
throws IOException {
return unwrap().getBytes(index, out, position, length);
}
@Override
public int setBytes(int index, InputStream in, int length)
throws IOException {
return unwrap().setBytes(index, in, length);
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length)
throws IOException {
return unwrap().setBytes(index, in, length);
}
@Override
public int setBytes(int index, FileChannel in, long position, int length)
throws IOException {
return unwrap().setBytes(index, in, position, length);
}
@Override
public int forEachByte(int index, int length, ByteProcessor processor) {
return unwrap().forEachByte(index, length, processor);
}
@Override
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
return unwrap().forEachByteDesc(index, length, processor);
}
}

View File

@ -0,0 +1,418 @@
/*
* Copyright 2016 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.ByteProcessor;
import io.netty.util.Recycler;
import io.netty.util.Recycler.Handle;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import static io.netty.util.internal.MathUtil.isOutOfBounds;
final class PooledSlicedByteBuf extends AbstractPooledDerivedByteBuf<PooledSlicedByteBuf> {
private static final Recycler<PooledSlicedByteBuf> RECYCLER = new Recycler<PooledSlicedByteBuf>() {
@Override
protected PooledSlicedByteBuf newObject(Handle<PooledSlicedByteBuf> handle) {
return new PooledSlicedByteBuf(handle);
}
};
static PooledSlicedByteBuf newInstance(AbstractByteBuf buffer, int index, int length, int adjustment) {
if (isOutOfBounds(index, length, buffer.capacity())) {
throw new IndexOutOfBoundsException(buffer + ".slice(" + index + ", " + length + ')');
}
final PooledSlicedByteBuf slice = RECYCLER.get();
slice.init(buffer, 0, length, length);
slice.discardMarks();
slice.adjustment = adjustment;
return slice;
}
private int adjustment;
private PooledSlicedByteBuf(Handle<PooledSlicedByteBuf> handle) {
super(handle);
}
@Override
public int capacity() {
return maxCapacity();
}
@Override
public ByteBuf capacity(int newCapacity) {
return reject();
}
@Override
public int arrayOffset() {
return idx(unwrap().arrayOffset());
}
@Override
public long memoryAddress() {
return unwrap().memoryAddress() + adjustment;
}
@Override
public ByteBuffer nioBuffer(int index, int length) {
checkIndex0(index, length);
return unwrap().nioBuffer(idx(index), length);
}
@Override
public ByteBuffer[] nioBuffers(int index, int length) {
checkIndex0(index, length);
return unwrap().nioBuffers(idx(index), length);
}
@Override
public ByteBuf copy(int index, int length) {
checkIndex0(index, length);
return unwrap().copy(idx(index), length);
}
@Override
public byte getByte(int index) {
checkIndex0(index, 1);
return unwrap().getByte(idx(index));
}
@Override
protected byte _getByte(int index) {
return unwrap()._getByte(idx(index));
}
@Override
public short getShort(int index) {
checkIndex0(index, 2);
return unwrap().getShort(idx(index));
}
@Override
protected short _getShort(int index) {
return unwrap()._getShort(idx(index));
}
@Override
public short getShortLE(int index) {
checkIndex0(index, 2);
return unwrap().getShortLE(idx(index));
}
@Override
protected short _getShortLE(int index) {
return unwrap()._getShortLE(idx(index));
}
@Override
public int getUnsignedMedium(int index) {
checkIndex0(index, 3);
return unwrap().getUnsignedMedium(idx(index));
}
@Override
protected int _getUnsignedMedium(int index) {
return unwrap()._getUnsignedMedium(idx(index));
}
@Override
public int getUnsignedMediumLE(int index) {
checkIndex0(index, 3);
return unwrap().getUnsignedMediumLE(idx(index));
}
@Override
protected int _getUnsignedMediumLE(int index) {
return unwrap()._getUnsignedMediumLE(idx(index));
}
@Override
public int getInt(int index) {
checkIndex0(index, 4);
return unwrap().getInt(idx(index));
}
@Override
protected int _getInt(int index) {
return unwrap()._getInt(idx(index));
}
@Override
public int getIntLE(int index) {
checkIndex0(index, 4);
return unwrap().getIntLE(idx(index));
}
@Override
protected int _getIntLE(int index) {
return unwrap()._getIntLE(idx(index));
}
@Override
public long getLong(int index) {
checkIndex0(index, 8);
return unwrap().getLong(idx(index));
}
@Override
protected long _getLong(int index) {
return unwrap()._getLong(idx(index));
}
@Override
public long getLongLE(int index) {
checkIndex0(index, 8);
return unwrap().getLongLE(idx(index));
}
@Override
protected long _getLongLE(int index) {
return unwrap()._getLongLE(idx(index));
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
checkIndex0(index, length);
unwrap().getBytes(idx(index), dst, dstIndex, length);
return this;
}
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
checkIndex0(index, length);
unwrap().getBytes(idx(index), dst, dstIndex, length);
return this;
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
checkIndex0(index, dst.remaining());
unwrap().getBytes(idx(index), dst);
return this;
}
@Override
public ByteBuf setByte(int index, int value) {
checkIndex0(index, 1);
unwrap().setByte(idx(index), value);
return this;
}
@Override
protected void _setByte(int index, int value) {
unwrap()._setByte(idx(index), value);
}
@Override
public ByteBuf setShort(int index, int value) {
checkIndex0(index, 2);
unwrap().setShort(idx(index), value);
return this;
}
@Override
protected void _setShort(int index, int value) {
unwrap()._setShort(idx(index), value);
}
@Override
public ByteBuf setShortLE(int index, int value) {
checkIndex0(index, 2);
unwrap().setShortLE(idx(index), value);
return this;
}
@Override
protected void _setShortLE(int index, int value) {
unwrap()._setShortLE(idx(index), value);
}
@Override
public ByteBuf setMedium(int index, int value) {
checkIndex0(index, 3);
unwrap().setMedium(idx(index), value);
return this;
}
@Override
protected void _setMedium(int index, int value) {
unwrap()._setMedium(idx(index), value);
}
@Override
public ByteBuf setMediumLE(int index, int value) {
checkIndex0(index, 3);
unwrap().setMediumLE(idx(index), value);
return this;
}
@Override
protected void _setMediumLE(int index, int value) {
unwrap()._setMediumLE(idx(index), value);
}
@Override
public ByteBuf setInt(int index, int value) {
checkIndex0(index, 4);
unwrap().setInt(idx(index), value);
return this;
}
@Override
protected void _setInt(int index, int value) {
unwrap()._setInt(idx(index), value);
}
@Override
public ByteBuf setIntLE(int index, int value) {
checkIndex0(index, 4);
unwrap().setIntLE(idx(index), value);
return this;
}
@Override
protected void _setIntLE(int index, int value) {
unwrap()._setIntLE(idx(index), value);
}
@Override
public ByteBuf setLong(int index, long value) {
checkIndex0(index, 8);
unwrap().setLong(idx(index), value);
return this;
}
@Override
protected void _setLong(int index, long value) {
unwrap()._setLong(idx(index), value);
}
@Override
public ByteBuf setLongLE(int index, long value) {
checkIndex0(index, 8);
unwrap().setLongLE(idx(index), value);
return this;
}
@Override
protected void _setLongLE(int index, long value) {
unwrap().setLongLE(idx(index), value);
}
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkIndex0(index, length);
unwrap().setBytes(idx(index), src, srcIndex, length);
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
checkIndex0(index, length);
unwrap().setBytes(idx(index), src, srcIndex, length);
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
checkIndex0(index, src.remaining());
unwrap().setBytes(idx(index), src);
return this;
}
@Override
public ByteBuf getBytes(int index, OutputStream out, int length)
throws IOException {
checkIndex0(index, length);
unwrap().getBytes(idx(index), out, length);
return this;
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length)
throws IOException {
checkIndex0(index, length);
return unwrap().getBytes(idx(index), out, length);
}
@Override
public int getBytes(int index, FileChannel out, long position, int length)
throws IOException {
checkIndex0(index, length);
return unwrap().getBytes(idx(index), out, position, length);
}
@Override
public int setBytes(int index, InputStream in, int length)
throws IOException {
checkIndex0(index, length);
return unwrap().setBytes(idx(index), in, length);
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length)
throws IOException {
checkIndex0(index, length);
return unwrap().setBytes(idx(index), in, length);
}
@Override
public int setBytes(int index, FileChannel in, long position, int length)
throws IOException {
checkIndex0(index, length);
return unwrap().setBytes(idx(index), in, position, length);
}
@Override
public int forEachByte(int index, int length, ByteProcessor processor) {
checkIndex0(index, length);
int ret = unwrap().forEachByte(idx(index), length, processor);
if (ret < adjustment) {
return -1;
}
return ret - adjustment;
}
@Override
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
checkIndex0(index, length);
int ret = unwrap().forEachByteDesc(idx(index), length, processor);
if (ret < adjustment) {
return -1;
}
return ret - adjustment;
}
private int idx(int index) {
return index + adjustment;
}
private static ByteBuf reject() {
throw new UnsupportedOperationException("sliced buffer");
}
}

View File

@ -72,18 +72,38 @@ final class SimpleLeakAwareByteBuf extends WrappedByteBuf {
return new SimpleLeakAwareByteBuf(super.slice(), leak); return new SimpleLeakAwareByteBuf(super.slice(), leak);
} }
@Override
public ByteBuf retainedSlice() {
return new SimpleLeakAwareByteBuf(super.retainedSlice(), leak);
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return new SimpleLeakAwareByteBuf(super.slice(index, length), leak); return new SimpleLeakAwareByteBuf(super.slice(index, length), leak);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return new SimpleLeakAwareByteBuf(super.retainedSlice(index, length), leak);
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
return new SimpleLeakAwareByteBuf(super.duplicate(), leak); return new SimpleLeakAwareByteBuf(super.duplicate(), leak);
} }
@Override
public ByteBuf retainedDuplicate() {
return new SimpleLeakAwareByteBuf(super.retainedDuplicate(), leak);
}
@Override @Override
public ByteBuf readSlice(int length) { public ByteBuf readSlice(int length) {
return new SimpleLeakAwareByteBuf(super.readSlice(length), leak); return new SimpleLeakAwareByteBuf(super.readSlice(length), leak);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
return new SimpleLeakAwareByteBuf(super.readRetainedSlice(length), leak);
}
} }

View File

@ -62,18 +62,38 @@ final class SimpleLeakAwareCompositeByteBuf extends WrappedCompositeByteBuf {
return new SimpleLeakAwareByteBuf(super.slice(), leak); return new SimpleLeakAwareByteBuf(super.slice(), leak);
} }
@Override
public ByteBuf retainedSlice() {
return new SimpleLeakAwareByteBuf(super.retainedSlice(), leak);
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return new SimpleLeakAwareByteBuf(super.slice(index, length), leak); return new SimpleLeakAwareByteBuf(super.slice(index, length), leak);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return new SimpleLeakAwareByteBuf(super.retainedSlice(index, length), leak);
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
return new SimpleLeakAwareByteBuf(super.duplicate(), leak); return new SimpleLeakAwareByteBuf(super.duplicate(), leak);
} }
@Override
public ByteBuf retainedDuplicate() {
return new SimpleLeakAwareByteBuf(super.retainedDuplicate(), leak);
}
@Override @Override
public ByteBuf readSlice(int length) { public ByteBuf readSlice(int length) {
return new SimpleLeakAwareByteBuf(super.readSlice(length), leak); return new SimpleLeakAwareByteBuf(super.readSlice(length), leak);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
return new SimpleLeakAwareByteBuf(super.readRetainedSlice(length), leak);
}
} }

View File

@ -64,6 +64,10 @@ public class SlicedByteBuf extends AbstractDerivedByteBuf {
writerIndex(length); writerIndex(length);
} }
final int adjustment() {
return adjustment;
}
@Override @Override
public ByteBuf unwrap() { public ByteBuf unwrap() {
return buffer; return buffer;

View File

@ -631,6 +631,11 @@ public class SwappedByteBuf extends ByteBuf {
return buf.readSlice(length).order(order); return buf.readSlice(length).order(order);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
return buf.readRetainedSlice(length).order(order);
}
@Override @Override
public ByteBuf readBytes(ByteBuf dst) { public ByteBuf readBytes(ByteBuf dst) {
buf.readBytes(dst); buf.readBytes(dst);
@ -889,16 +894,31 @@ public class SwappedByteBuf extends ByteBuf {
return buf.slice().order(order); return buf.slice().order(order);
} }
@Override
public ByteBuf retainedSlice() {
return buf.slice().order(order);
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return buf.slice(index, length).order(order); return buf.slice(index, length).order(order);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return buf.slice(index, length).order(order);
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
return buf.duplicate().order(order); return buf.duplicate().order(order);
} }
@Override
public ByteBuf retainedDuplicate() {
return buf.retainedDuplicate().order(order);
}
@Override @Override
public int nioBufferCount() { public int nioBufferCount() {
return buf.nioBufferCount(); return buf.nioBufferCount();

View File

@ -55,21 +55,41 @@ final class UnreleasableByteBuf extends WrappedByteBuf {
return new UnreleasableByteBuf(buf.readSlice(length)); return new UnreleasableByteBuf(buf.readSlice(length));
} }
@Override
public ByteBuf readRetainedSlice(int length) {
return new UnreleasableByteBuf(buf.readRetainedSlice(length));
}
@Override @Override
public ByteBuf slice() { public ByteBuf slice() {
return new UnreleasableByteBuf(buf.slice()); return new UnreleasableByteBuf(buf.slice());
} }
@Override
public ByteBuf retainedSlice() {
return new UnreleasableByteBuf(buf.retainedSlice());
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return new UnreleasableByteBuf(buf.slice(index, length)); return new UnreleasableByteBuf(buf.slice(index, length));
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return new UnreleasableByteBuf(buf.retainedSlice(index, length));
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
return new UnreleasableByteBuf(buf.duplicate()); return new UnreleasableByteBuf(buf.duplicate());
} }
@Override
public ByteBuf retainedDuplicate() {
return new UnreleasableByteBuf(buf.retainedDuplicate());
}
@Override @Override
public ByteBuf retain(int increment) { public ByteBuf retain(int increment) {
return this; return this;

View File

@ -621,6 +621,11 @@ class WrappedByteBuf extends ByteBuf {
return buf.readSlice(length); return buf.readSlice(length);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
return buf.readRetainedSlice(length);
}
@Override @Override
public ByteBuf readBytes(ByteBuf dst) { public ByteBuf readBytes(ByteBuf dst) {
buf.readBytes(dst); buf.readBytes(dst);
@ -879,16 +884,31 @@ class WrappedByteBuf extends ByteBuf {
return buf.slice(); return buf.slice();
} }
@Override
public ByteBuf retainedSlice() {
return buf.retainedSlice();
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return buf.slice(index, length); return buf.slice(index, length);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return buf.retainedSlice(index, length);
}
@Override @Override
public ByteBuf duplicate() { public ByteBuf duplicate() {
return buf.duplicate(); return buf.duplicate();
} }
@Override
public ByteBuf retainedDuplicate() {
return buf.retainedDuplicate();
}
@Override @Override
public int nioBufferCount() { public int nioBufferCount() {
return buf.nioBufferCount(); return buf.nioBufferCount();

View File

@ -332,11 +332,21 @@ class WrappedCompositeByteBuf extends CompositeByteBuf {
return wrapped.slice(); return wrapped.slice();
} }
@Override
public ByteBuf retainedSlice() {
return wrapped.retainedSlice();
}
@Override @Override
public ByteBuf slice(int index, int length) { public ByteBuf slice(int index, int length) {
return wrapped.slice(index, length); return wrapped.slice(index, length);
} }
@Override
public ByteBuf retainedSlice(int index, int length) {
return wrapped.retainedSlice(index, length);
}
@Override @Override
public ByteBuffer nioBuffer() { public ByteBuffer nioBuffer() {
return wrapped.nioBuffer(); return wrapped.nioBuffer();
@ -417,11 +427,21 @@ class WrappedCompositeByteBuf extends CompositeByteBuf {
return wrapped.duplicate(); return wrapped.duplicate();
} }
@Override
public ByteBuf retainedDuplicate() {
return wrapped.retainedDuplicate();
}
@Override @Override
public ByteBuf readSlice(int length) { public ByteBuf readSlice(int length) {
return wrapped.readSlice(length); return wrapped.readSlice(length);
} }
@Override
public ByteBuf readRetainedSlice(int length) {
return wrapped.readRetainedSlice(length);
}
@Override @Override
public int readBytes(GatheringByteChannel out, int length) throws IOException { public int readBytes(GatheringByteChannel out, int length) throws IOException {
return wrapped.readBytes(out, length); return wrapped.readBytes(out, length);

View File

@ -22,7 +22,7 @@ import static org.junit.Assert.assertEquals;
/** /**
* Tests duplicated channel buffers * Tests duplicated channel buffers
*/ */
public class DuplicateByteBufTest extends AbstractByteBufTest { public class DuplicatedByteBufTest extends AbstractByteBufTest {
@Override @Override
protected ByteBuf newBuffer(int length) { protected ByteBuf newBuffer(int length) {

View File

@ -0,0 +1,32 @@
/*
* Copyright 2016 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 static org.junit.Assert.assertEquals;
public class RetainedDuplicatedByteBufTest extends DuplicatedByteBufTest {
@Override
protected ByteBuf newBuffer(int length) {
ByteBuf wrapped = Unpooled.buffer(length);
ByteBuf buffer = wrapped.retainedDuplicate();
wrapped.release();
assertEquals(wrapped.writerIndex(), buffer.writerIndex());
assertEquals(wrapped.readerIndex(), buffer.readerIndex());
return buffer;
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2016 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.ThreadLocalRandom;
import static org.junit.Assert.assertEquals;
public class RetainedSlicedByteBufTest extends SlicedByteBufTest {
@Override
protected ByteBuf newBuffer(int length) {
ByteBuf wrapped = Unpooled.wrappedBuffer(new byte[length * 2]);
ByteBuf buffer = wrapped.retainedSlice(ThreadLocalRandom.current().nextInt(length - 1) + 1, length);
wrapped.release();
assertEquals(0, buffer.readerIndex());
assertEquals(length, buffer.writerIndex());
return buffer;
}
}

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.buffer; package io.netty.buffer;
import io.netty.util.internal.ThreadLocalRandom;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
@ -27,12 +28,11 @@ import static org.junit.Assert.*;
*/ */
public class SlicedByteBufTest extends AbstractByteBufTest { public class SlicedByteBufTest extends AbstractByteBufTest {
private final Random random = new Random();
@Override @Override
protected ByteBuf newBuffer(int length) { protected ByteBuf newBuffer(int length) {
ByteBuf buffer = Unpooled.wrappedBuffer( ByteBuf buffer = Unpooled.wrappedBuffer(
new byte[length * 2], random.nextInt(length - 1) + 1, length); new byte[length * 2], ThreadLocalRandom.current().nextInt(length - 1) + 1, length);
assertEquals(0, buffer.readerIndex());
assertEquals(length, buffer.writerIndex()); assertEquals(length, buffer.writerIndex());
return buffer; return buffer;
} }

View File

@ -69,12 +69,22 @@ public class DefaultDnsRawRecord extends AbstractDnsRecord implements DnsRawReco
@Override @Override
public DnsRawRecord copy() { public DnsRawRecord copy() {
return new DefaultDnsRawRecord(name(), type(), dnsClass(), timeToLive(), content().copy()); return replace(content().copy());
} }
@Override @Override
public DnsRawRecord duplicate() { public DnsRawRecord duplicate() {
return new DefaultDnsRawRecord(name(), type(), dnsClass(), timeToLive(), content().duplicate()); return replace(content().duplicate());
}
@Override
public DnsRawRecord retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public DnsRawRecord replace(ByteBuf content) {
return new DefaultDnsRawRecord(name(), type(), dnsClass(), timeToLive(), content);
} }
@Override @Override

View File

@ -95,7 +95,7 @@ public class DefaultDnsRecordDecoder implements DnsRecordDecoder {
return new DefaultDnsPtrRecord(name, dnsClass, timeToLive, decodeName(in)); return new DefaultDnsPtrRecord(name, dnsClass, timeToLive, decodeName(in));
} }
return new DefaultDnsRawRecord( return new DefaultDnsRawRecord(
name, type, dnsClass, timeToLive, in.duplicate().setIndex(offset, offset + length).retain()); name, type, dnsClass, timeToLive, in.retainedDuplicate().setIndex(offset, offset + length));
} }
/** /**

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.dns; package io.netty.handler.codec.dns;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder; import io.netty.buffer.ByteBufHolder;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
@ -29,6 +30,12 @@ public interface DnsRawRecord extends DnsRecord, ByteBufHolder {
@Override @Override
DnsRawRecord duplicate(); DnsRawRecord duplicate();
@Override
DnsRawRecord retainedDuplicate();
@Override
DnsRawRecord replace(ByteBuf content);
@Override @Override
DnsRawRecord retain(); DnsRawRecord retain();

View File

@ -27,6 +27,7 @@ final class ComposedLastHttpContent implements LastHttpContent {
ComposedLastHttpContent(HttpHeaders trailingHeaders) { ComposedLastHttpContent(HttpHeaders trailingHeaders) {
this.trailingHeaders = trailingHeaders; this.trailingHeaders = trailingHeaders;
} }
@Override @Override
public HttpHeaders trailingHeaders() { public HttpHeaders trailingHeaders() {
return trailingHeaders; return trailingHeaders;
@ -39,6 +40,23 @@ final class ComposedLastHttpContent implements LastHttpContent {
return content; return content;
} }
@Override
public LastHttpContent duplicate() {
return copy();
}
@Override
public LastHttpContent retainedDuplicate() {
return copy();
}
@Override
public LastHttpContent replace(ByteBuf content) {
final LastHttpContent dup = new DefaultLastHttpContent(content);
dup.trailingHeaders().setAll(trailingHeaders());
return dup;
}
@Override @Override
public LastHttpContent retain(int increment) { public LastHttpContent retain(int increment) {
return this; return this;
@ -59,11 +77,6 @@ final class ComposedLastHttpContent implements LastHttpContent {
return this; return this;
} }
@Override
public LastHttpContent duplicate() {
return copy();
}
@Override @Override
public ByteBuf content() { public ByteBuf content() {
return Unpooled.EMPTY_BUFFER; return Unpooled.EMPTY_BUFFER;

View File

@ -125,44 +125,24 @@ public class DefaultFullHttpRequest extends DefaultHttpRequest implements FullHt
return this; return this;
} }
/**
* Copy this object
*
* @param copyContent
* <ul>
* <li>{@code true} if this object's {@link #content()} should be used to copy.</li>
* <li>{@code false} if {@code newContent} should be used instead.</li>
* </ul>
* @param newContent
* <ul>
* <li>if {@code copyContent} is false then this will be used in the copy's content.</li>
* <li>if {@code null} then a default buffer of 0 size will be selected</li>
* </ul>
* @return A copy of this object
*/
private FullHttpRequest copy(boolean copyContent, ByteBuf newContent) {
return new DefaultFullHttpRequest(
protocolVersion(), method(), uri(),
copyContent ? content().copy() :
newContent == null ? Unpooled.buffer(0) : newContent,
headers(),
trailingHeaders());
}
@Override
public FullHttpRequest copy(ByteBuf newContent) {
return copy(false, newContent);
}
@Override @Override
public FullHttpRequest copy() { public FullHttpRequest copy() {
return copy(true, null); return replace(content().copy());
} }
@Override @Override
public FullHttpRequest duplicate() { public FullHttpRequest duplicate() {
return new DefaultFullHttpRequest( return replace(content().duplicate());
protocolVersion(), method(), uri(), content().duplicate(), headers(), trailingHeaders()); }
@Override
public FullHttpRequest retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public FullHttpRequest replace(ByteBuf content) {
return new DefaultFullHttpRequest(protocolVersion(), method(), uri(), content, headers(), trailingHeaders());
} }
@Override @Override

View File

@ -132,44 +132,24 @@ public class DefaultFullHttpResponse extends DefaultHttpResponse implements Full
return this; return this;
} }
/**
* Copy this object
*
* @param copyContent
* <ul>
* <li>{@code true} if this object's {@link #content()} should be used to copy.</li>
* <li>{@code false} if {@code newContent} should be used instead.</li>
* </ul>
* @param newContent
* <ul>
* <li>if {@code copyContent} is false then this will be used in the copy's content.</li>
* <li>if {@code null} then a default buffer of 0 size will be selected</li>
* </ul>
* @return A copy of this object
*/
private FullHttpResponse copy(boolean copyContent, ByteBuf newContent) {
return new DefaultFullHttpResponse(
protocolVersion(), status(),
copyContent ? content().copy() :
newContent == null ? Unpooled.buffer(0) : newContent,
headers(),
trailingHeaders());
}
@Override
public FullHttpResponse copy(ByteBuf newContent) {
return copy(false, newContent);
}
@Override @Override
public FullHttpResponse copy() { public FullHttpResponse copy() {
return copy(true, null); return replace(content().copy());
} }
@Override @Override
public FullHttpResponse duplicate() { public FullHttpResponse duplicate() {
return new DefaultFullHttpResponse(protocolVersion(), status(), return replace(content().duplicate());
content().duplicate(), headers(), trailingHeaders()); }
@Override
public FullHttpResponse retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public FullHttpResponse replace(ByteBuf content) {
return new DefaultFullHttpResponse(protocolVersion(), status(), content, headers(), trailingHeaders());
} }
@Override @Override

View File

@ -42,12 +42,22 @@ public class DefaultHttpContent extends DefaultHttpObject implements HttpContent
@Override @Override
public HttpContent copy() { public HttpContent copy() {
return new DefaultHttpContent(content.copy()); return replace(content.copy());
} }
@Override @Override
public HttpContent duplicate() { public HttpContent duplicate() {
return new DefaultHttpContent(content.duplicate()); return replace(content.duplicate());
}
@Override
public HttpContent retainedDuplicate() {
return replace(content.retainedDuplicate());
}
@Override
public HttpContent replace(ByteBuf content) {
return new DefaultHttpContent(content);
} }
@Override @Override

View File

@ -45,16 +45,24 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
@Override @Override
public LastHttpContent copy() { public LastHttpContent copy() {
DefaultLastHttpContent copy = new DefaultLastHttpContent(content().copy(), validateHeaders); return replace(content().copy());
copy.trailingHeaders().set(trailingHeaders());
return copy;
} }
@Override @Override
public LastHttpContent duplicate() { public LastHttpContent duplicate() {
DefaultLastHttpContent copy = new DefaultLastHttpContent(content().duplicate(), validateHeaders); return replace(content().duplicate());
copy.trailingHeaders().set(trailingHeaders()); }
return copy;
@Override
public LastHttpContent retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public LastHttpContent replace(ByteBuf content) {
final DefaultLastHttpContent dup = new DefaultLastHttpContent(content, validateHeaders);
dup.trailingHeaders().set(trailingHeaders());
return dup;
} }
@Override @Override

View File

@ -22,19 +22,18 @@ import io.netty.buffer.ByteBuf;
* message. So it represent a <i>complete</i> http message. * message. So it represent a <i>complete</i> http message.
*/ */
public interface FullHttpMessage extends HttpMessage, LastHttpContent { public interface FullHttpMessage extends HttpMessage, LastHttpContent {
/**
* Create a copy of this {@link FullHttpMessage} with alternative content.
*
* @param newContent The buffer to use instead of this {@link FullHttpMessage}'s content in the copy operation.
* <p>
* NOTE: retain will NOT be called on this buffer. {@code null} results in an empty default choice buffer.
* @return The result of the copy operation
*/
FullHttpMessage copy(ByteBuf newContent);
@Override @Override
FullHttpMessage copy(); FullHttpMessage copy();
@Override
FullHttpMessage duplicate();
@Override
FullHttpMessage retainedDuplicate();
@Override
FullHttpMessage replace(ByteBuf content);
@Override @Override
FullHttpMessage retain(int increment); FullHttpMessage retain(int increment);
@ -46,7 +45,4 @@ public interface FullHttpMessage extends HttpMessage, LastHttpContent {
@Override @Override
FullHttpMessage touch(Object hint); FullHttpMessage touch(Object hint);
@Override
FullHttpMessage duplicate();
} }

View File

@ -23,10 +23,16 @@ import io.netty.buffer.ByteBuf;
*/ */
public interface FullHttpRequest extends HttpRequest, FullHttpMessage { public interface FullHttpRequest extends HttpRequest, FullHttpMessage {
@Override @Override
FullHttpRequest copy(ByteBuf newContent); FullHttpRequest copy();
@Override @Override
FullHttpRequest copy(); FullHttpRequest duplicate();
@Override
FullHttpRequest retainedDuplicate();
@Override
FullHttpRequest replace(ByteBuf content);
@Override @Override
FullHttpRequest retain(int increment); FullHttpRequest retain(int increment);
@ -40,9 +46,6 @@ public interface FullHttpRequest extends HttpRequest, FullHttpMessage {
@Override @Override
FullHttpRequest touch(Object hint); FullHttpRequest touch(Object hint);
@Override
FullHttpRequest duplicate();
@Override @Override
FullHttpRequest setProtocolVersion(HttpVersion version); FullHttpRequest setProtocolVersion(HttpVersion version);

View File

@ -23,10 +23,16 @@ import io.netty.buffer.ByteBuf;
*/ */
public interface FullHttpResponse extends HttpResponse, FullHttpMessage { public interface FullHttpResponse extends HttpResponse, FullHttpMessage {
@Override @Override
FullHttpResponse copy(ByteBuf newContent); FullHttpResponse copy();
@Override @Override
FullHttpResponse copy(); FullHttpResponse duplicate();
@Override
FullHttpResponse retainedDuplicate();
@Override
FullHttpResponse replace(ByteBuf content);
@Override @Override
FullHttpResponse retain(int increment); FullHttpResponse retain(int increment);
@ -40,9 +46,6 @@ public interface FullHttpResponse extends HttpResponse, FullHttpMessage {
@Override @Override
FullHttpResponse touch(Object hint); FullHttpResponse touch(Object hint);
@Override
FullHttpResponse duplicate();
@Override @Override
FullHttpResponse setProtocolVersion(HttpVersion version); FullHttpResponse setProtocolVersion(HttpVersion version);

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.http; package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder; import io.netty.buffer.ByteBufHolder;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
@ -33,6 +34,12 @@ public interface HttpContent extends HttpObject, ByteBufHolder {
@Override @Override
HttpContent duplicate(); HttpContent duplicate();
@Override
HttpContent retainedDuplicate();
@Override
HttpContent replace(ByteBuf content);
@Override @Override
HttpContent retain(); HttpContent retain();

View File

@ -16,7 +16,6 @@
package io.netty.handler.codec.http; package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
@ -121,11 +120,11 @@ public class HttpObjectAggregator
protected Object newContinueResponse(HttpMessage start, int maxContentLength, ChannelPipeline pipeline) { protected Object newContinueResponse(HttpMessage start, int maxContentLength, ChannelPipeline pipeline) {
if (HttpUtil.is100ContinueExpected(start)) { if (HttpUtil.is100ContinueExpected(start)) {
if (getContentLength(start, -1L) <= maxContentLength) { if (getContentLength(start, -1L) <= maxContentLength) {
return CONTINUE.duplicate().retain(); return CONTINUE.retainedDuplicate();
} }
pipeline.fireUserEventTriggered(HttpExpectationFailedEvent.INSTANCE); pipeline.fireUserEventTriggered(HttpExpectationFailedEvent.INSTANCE);
return EXPECTATION_FAILED.duplicate().retain(); return EXPECTATION_FAILED.retainedDuplicate();
} }
return null; return null;
} }
@ -176,7 +175,7 @@ public class HttpObjectAggregator
// See rfc2616 14.13 Content-Length // See rfc2616 14.13 Content-Length
if (!HttpUtil.isContentLengthSet(aggregated)) { if (!HttpUtil.isContentLengthSet(aggregated)) {
aggregated.headers().set( aggregated.headers().set(
HttpHeaderNames.CONTENT_LENGTH, CONTENT_LENGTH,
String.valueOf(aggregated.content().readableBytes())); String.valueOf(aggregated.content().readableBytes()));
} }
} }
@ -185,7 +184,7 @@ public class HttpObjectAggregator
protected void handleOversizedMessage(final ChannelHandlerContext ctx, HttpMessage oversized) throws Exception { protected void handleOversizedMessage(final ChannelHandlerContext ctx, HttpMessage oversized) throws Exception {
if (oversized instanceof HttpRequest) { if (oversized instanceof HttpRequest) {
// send back a 413 and close the connection // send back a 413 and close the connection
ChannelFuture future = ctx.writeAndFlush(TOO_LARGE.duplicate().retain()).addListener( ChannelFuture future = ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener(
new ChannelFutureListener() { new ChannelFutureListener() {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) throws Exception {
@ -217,7 +216,7 @@ public class HttpObjectAggregator
} }
} }
private abstract static class AggregatedFullHttpMessage implements ByteBufHolder, FullHttpMessage { private abstract static class AggregatedFullHttpMessage implements FullHttpMessage {
protected final HttpMessage message; protected final HttpMessage message;
private final ByteBuf content; private final ByteBuf content;
private HttpHeaders trailingHeaders; private HttpHeaders trailingHeaders;
@ -327,6 +326,9 @@ public class HttpObjectAggregator
@Override @Override
public abstract FullHttpMessage duplicate(); public abstract FullHttpMessage duplicate();
@Override
public abstract FullHttpMessage retainedDuplicate();
} }
private static final class AggregatedFullHttpRequest extends AggregatedFullHttpMessage implements FullHttpRequest { private static final class AggregatedFullHttpRequest extends AggregatedFullHttpMessage implements FullHttpRequest {
@ -335,48 +337,27 @@ public class HttpObjectAggregator
super(request, content, trailingHeaders); super(request, content, trailingHeaders);
} }
/**
* Copy this object
*
* @param copyContent
* <ul>
* <li>{@code true} if this object's {@link #content()} should be used to copy.</li>
* <li>{@code false} if {@code newContent} should be used instead.</li>
* </ul>
* @param newContent
* <ul>
* <li>if {@code copyContent} is false then this will be used in the copy's content.</li>
* <li>if {@code null} then a default buffer of 0 size will be selected</li>
* </ul>
* @return A copy of this object
*/
private FullHttpRequest copy(boolean copyContent, ByteBuf newContent) {
DefaultFullHttpRequest copy = new DefaultFullHttpRequest(
protocolVersion(), method(), uri(),
copyContent ? content().copy() :
newContent == null ? Unpooled.buffer(0) : newContent);
copy.headers().set(headers());
copy.trailingHeaders().set(trailingHeaders());
return copy;
}
@Override
public FullHttpRequest copy(ByteBuf newContent) {
return copy(false, newContent);
}
@Override @Override
public FullHttpRequest copy() { public FullHttpRequest copy() {
return copy(true, null); return replace(content().copy());
} }
@Override @Override
public FullHttpRequest duplicate() { public FullHttpRequest duplicate() {
DefaultFullHttpRequest duplicate = new DefaultFullHttpRequest( return replace(content().duplicate());
getProtocolVersion(), getMethod(), getUri(), content().duplicate()); }
duplicate.headers().set(headers());
duplicate.trailingHeaders().set(trailingHeaders()); @Override
return duplicate; public FullHttpRequest retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public FullHttpRequest replace(ByteBuf content) {
DefaultFullHttpRequest dup = new DefaultFullHttpRequest(protocolVersion(), method(), uri(), content);
dup.headers().set(headers());
dup.trailingHeaders().set(trailingHeaders());
return dup;
} }
@Override @Override
@ -454,48 +435,27 @@ public class HttpObjectAggregator
super(message, content, trailingHeaders); super(message, content, trailingHeaders);
} }
/**
* Copy this object
*
* @param copyContent
* <ul>
* <li>{@code true} if this object's {@link #content()} should be used to copy.</li>
* <li>{@code false} if {@code newContent} should be used instead.</li>
* </ul>
* @param newContent
* <ul>
* <li>if {@code copyContent} is false then this will be used in the copy's content.</li>
* <li>if {@code null} then a default buffer of 0 size will be selected</li>
* </ul>
* @return A copy of this object
*/
private FullHttpResponse copy(boolean copyContent, ByteBuf newContent) {
DefaultFullHttpResponse copy = new DefaultFullHttpResponse(
protocolVersion(), status(),
copyContent ? content().copy() :
newContent == null ? Unpooled.buffer(0) : newContent);
copy.headers().set(headers());
copy.trailingHeaders().set(trailingHeaders());
return copy;
}
@Override
public FullHttpResponse copy(ByteBuf newContent) {
return copy(false, newContent);
}
@Override @Override
public FullHttpResponse copy() { public FullHttpResponse copy() {
return copy(true, null); return replace(content().copy());
} }
@Override @Override
public FullHttpResponse duplicate() { public FullHttpResponse duplicate() {
DefaultFullHttpResponse duplicate = new DefaultFullHttpResponse(getProtocolVersion(), getStatus(), return replace(content().duplicate());
content().duplicate()); }
duplicate.headers().set(headers());
duplicate.trailingHeaders().set(trailingHeaders()); @Override
return duplicate; public FullHttpResponse retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public FullHttpResponse replace(ByteBuf content) {
DefaultFullHttpResponse dup = new DefaultFullHttpResponse(getProtocolVersion(), getStatus(), content);
dup.headers().set(headers());
dup.trailingHeaders().set(trailingHeaders());
return dup;
} }
@Override @Override

View File

@ -279,7 +279,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
// Keep reading data as a chunk until the end of connection is reached. // Keep reading data as a chunk until the end of connection is reached.
int toRead = Math.min(buffer.readableBytes(), maxChunkSize); int toRead = Math.min(buffer.readableBytes(), maxChunkSize);
if (toRead > 0) { if (toRead > 0) {
ByteBuf content = buffer.readSlice(toRead).retain(); ByteBuf content = buffer.readRetainedSlice(toRead);
out.add(new DefaultHttpContent(content)); out.add(new DefaultHttpContent(content));
} }
return; return;
@ -301,7 +301,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
if (toRead > chunkSize) { if (toRead > chunkSize) {
toRead = (int) chunkSize; toRead = (int) chunkSize;
} }
ByteBuf content = buffer.readSlice(toRead).retain(); ByteBuf content = buffer.readRetainedSlice(toRead);
chunkSize -= toRead; chunkSize -= toRead;
if (chunkSize == 0) { if (chunkSize == 0) {
@ -341,7 +341,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
if (toRead == 0) { if (toRead == 0) {
return; return;
} }
HttpContent chunk = new DefaultHttpContent(buffer.readSlice(toRead).retain()); HttpContent chunk = new DefaultHttpContent(buffer.readRetainedSlice(toRead));
chunkSize -= toRead; chunkSize -= toRead;
out.add(chunk); out.add(chunk);

View File

@ -44,6 +44,16 @@ public interface LastHttpContent extends HttpContent {
return this; return this;
} }
@Override
public LastHttpContent replace(ByteBuf content) {
return new DefaultLastHttpContent(content);
}
@Override
public LastHttpContent retainedDuplicate() {
return this;
}
@Override @Override
public HttpHeaders trailingHeaders() { public HttpHeaders trailingHeaders() {
return EmptyHttpHeaders.INSTANCE; return EmptyHttpHeaders.INSTANCE;
@ -111,6 +121,15 @@ public interface LastHttpContent extends HttpContent {
@Override @Override
LastHttpContent copy(); LastHttpContent copy();
@Override
LastHttpContent duplicate();
@Override
LastHttpContent retainedDuplicate();
@Override
LastHttpContent replace(ByteBuf content);
@Override @Override
LastHttpContent retain(int increment); LastHttpContent retain(int increment);
@ -122,7 +141,4 @@ public interface LastHttpContent extends HttpContent {
@Override @Override
LastHttpContent touch(Object hint); LastHttpContent touch(Object hint);
@Override
LastHttpContent duplicate();
} }

View File

@ -28,7 +28,10 @@ import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import static io.netty.buffer.Unpooled.*; import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
import static io.netty.buffer.Unpooled.buffer;
import static io.netty.buffer.Unpooled.compositeBuffer;
import static io.netty.buffer.Unpooled.wrappedBuffer;
/** /**
* Abstract Memory HttpData implementation * Abstract Memory HttpData implementation
@ -209,7 +212,7 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
if (sizeLeft < length) { if (sizeLeft < length) {
sliceLength = sizeLeft; sliceLength = sizeLeft;
} }
ByteBuf chunk = byteBuf.slice(chunkPosition, sliceLength).retain(); ByteBuf chunk = byteBuf.retainedSlice(chunkPosition, sliceLength);
chunkPosition += sliceLength; chunkPosition += sliceLength;
return chunk; return chunk;
} }

View File

@ -15,6 +15,8 @@
*/ */
package io.netty.handler.codec.http.multipart; package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
import java.io.IOException; import java.io.IOException;
/** /**
@ -37,6 +39,12 @@ public interface Attribute extends HttpData {
@Override @Override
Attribute duplicate(); Attribute duplicate();
@Override
Attribute retainedDuplicate();
@Override
Attribute replace(ByteBuf content);
@Override @Override
Attribute retain(); Attribute retain();

View File

@ -22,7 +22,7 @@ import io.netty.handler.codec.http.HttpConstants;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import static io.netty.buffer.Unpooled.*; import static io.netty.buffer.Unpooled.wrappedBuffer;
/** /**
* Disk implementation of Attributes * Disk implementation of Attributes
@ -162,27 +162,43 @@ public class DiskAttribute extends AbstractDiskHttpData implements Attribute {
@Override @Override
public Attribute copy() { public Attribute copy() {
DiskAttribute attr = new DiskAttribute(getName()); final ByteBuf content = content();
attr.setCharset(getCharset()); return replace(content != null ? content.copy() : null);
ByteBuf content = content();
if (content != null) {
try {
attr.setContent(content.copy());
} catch (IOException e) {
throw new ChannelException(e);
}
}
return attr;
} }
@Override @Override
public Attribute duplicate() { public Attribute duplicate() {
DiskAttribute attr = new DiskAttribute(getName()); final ByteBuf content = content();
attr.setCharset(getCharset()); return replace(content != null ? content.duplicate() : null);
}
@Override
public Attribute retainedDuplicate() {
ByteBuf content = content(); ByteBuf content = content();
if (content != null) { if (content != null) {
content = content.retainedDuplicate();
boolean success = false;
try { try {
attr.setContent(content.duplicate()); Attribute duplicate = replace(content);
success = true;
return duplicate;
} finally {
if (!success) {
content.release();
}
}
} else {
return replace(null);
}
}
@Override
public Attribute replace(ByteBuf content) {
DiskAttribute attr = new DiskAttribute(getName());
attr.setCharset(getCharset());
if (content != null) {
try {
attr.setContent(content);
} catch (IOException e) { } catch (IOException e) {
throw new ChannelException(e); throw new ChannelException(e);
} }

View File

@ -173,27 +173,43 @@ public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload {
@Override @Override
public FileUpload copy() { public FileUpload copy() {
DiskFileUpload upload = new DiskFileUpload(getName(), final ByteBuf content = content();
getFilename(), getContentType(), getContentTransferEncoding(), getCharset(), size); return replace(content != null ? content.copy() : null);
ByteBuf buf = content();
if (buf != null) {
try {
upload.setContent(buf.copy());
} catch (IOException e) {
throw new ChannelException(e);
}
}
return upload;
} }
@Override @Override
public FileUpload duplicate() { public FileUpload duplicate() {
DiskFileUpload upload = new DiskFileUpload(getName(), final ByteBuf content = content();
getFilename(), getContentType(), getContentTransferEncoding(), getCharset(), size); return replace(content != null ? content.duplicate() : null);
ByteBuf buf = content(); }
if (buf != null) {
@Override
public FileUpload retainedDuplicate() {
ByteBuf content = content();
if (content != null) {
content = content.retainedDuplicate();
boolean success = false;
try { try {
upload.setContent(buf.duplicate()); FileUpload duplicate = replace(content);
success = true;
return duplicate;
} finally {
if (!success) {
content.release();
}
}
} else {
return replace(null);
}
}
@Override
public FileUpload replace(ByteBuf content) {
DiskFileUpload upload = new DiskFileUpload(
getName(), getFilename(), getContentType(), getContentTransferEncoding(), getCharset(), size);
if (content != null) {
try {
upload.setContent(content);
} catch (IOException e) { } catch (IOException e) {
throw new ChannelException(e); throw new ChannelException(e);
} }

View File

@ -15,6 +15,8 @@
*/ */
package io.netty.handler.codec.http.multipart; package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
/** /**
* FileUpload interface that could be in memory, on temporary file or any other implementations. * FileUpload interface that could be in memory, on temporary file or any other implementations.
* *
@ -62,6 +64,12 @@ public interface FileUpload extends HttpData {
@Override @Override
FileUpload duplicate(); FileUpload duplicate();
@Override
FileUpload retainedDuplicate();
@Override
FileUpload replace(ByteBuf content);
@Override @Override
FileUpload retain(); FileUpload retain();

View File

@ -219,6 +219,12 @@ public interface HttpData extends InterfaceHttpData, ByteBufHolder {
@Override @Override
HttpData duplicate(); HttpData duplicate();
@Override
HttpData retainedDuplicate();
@Override
HttpData replace(ByteBuf content);
@Override @Override
HttpData retain(); HttpData retain();

View File

@ -26,11 +26,11 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpConstants; import io.netty.handler.codec.http.HttpConstants;
import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.stream.ChunkedInput; import io.netty.handler.stream.ChunkedInput;
@ -48,7 +48,7 @@ import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static io.netty.buffer.Unpooled.*; import static io.netty.buffer.Unpooled.wrappedBuffer;
/** /**
* This encoder will help to encode Request for a FORM as POST. * This encoder will help to encode Request for a FORM as POST.
@ -836,7 +836,6 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
int length = currentBuffer.readableBytes(); int length = currentBuffer.readableBytes();
if (length > HttpPostBodyUtil.chunkSize) { if (length > HttpPostBodyUtil.chunkSize) {
ByteBuf slice = currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize); ByteBuf slice = currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize);
currentBuffer.retain();
currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize); currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize);
return slice; return slice;
} else { } else {
@ -1239,45 +1238,24 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
return this; return this;
} }
/**
* Copy this object
*
* @param copyContent
* <ul>
* <li>{@code true} if this object's {@link #content()} should be used to copy.</li>
* <li>{@code false} if {@code newContent} should be used instead.</li>
* </ul>
* @param newContent
* <ul>
* <li>if {@code copyContent} is false then this will be used in the copy's content.</li>
* <li>if {@code null} then a default buffer of 0 size will be selected</li>
* </ul>
* @return A copy of this object
*/
private FullHttpRequest copy(boolean copyContent, ByteBuf newContent) {
DefaultFullHttpRequest copy = new DefaultFullHttpRequest(
protocolVersion(), method(), uri(),
copyContent ? content().copy() :
newContent == null ? buffer(0) : newContent);
copy.headers().set(headers());
copy.trailingHeaders().set(trailingHeaders());
return copy;
}
@Override
public FullHttpRequest copy(ByteBuf newContent) {
return copy(false, newContent);
}
@Override @Override
public FullHttpRequest copy() { public FullHttpRequest copy() {
return copy(true, null); return replace(content().copy());
} }
@Override @Override
public FullHttpRequest duplicate() { public FullHttpRequest duplicate() {
DefaultFullHttpRequest duplicate = new DefaultFullHttpRequest( return replace(content().duplicate());
getProtocolVersion(), getMethod(), getUri(), content().duplicate()); }
@Override
public FullHttpRequest retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public FullHttpRequest replace(ByteBuf content) {
DefaultFullHttpRequest duplicate = new DefaultFullHttpRequest(protocolVersion(), method(), uri(), content);
duplicate.headers().set(headers()); duplicate.headers().set(headers());
duplicate.trailingHeaders().set(trailingHeaders()); duplicate.trailingHeaders().set(trailingHeaders());
return duplicate; return duplicate;

View File

@ -122,27 +122,43 @@ public class MemoryAttribute extends AbstractMemoryHttpData implements Attribute
@Override @Override
public Attribute copy() { public Attribute copy() {
MemoryAttribute attr = new MemoryAttribute(getName()); final ByteBuf content = content();
attr.setCharset(getCharset()); return replace(content != null ? content.copy() : null);
ByteBuf content = content();
if (content != null) {
try {
attr.setContent(content.copy());
} catch (IOException e) {
throw new ChannelException(e);
}
}
return attr;
} }
@Override @Override
public Attribute duplicate() { public Attribute duplicate() {
MemoryAttribute attr = new MemoryAttribute(getName()); final ByteBuf content = content();
attr.setCharset(getCharset()); return replace(content != null ? content.duplicate() : null);
}
@Override
public Attribute retainedDuplicate() {
ByteBuf content = content(); ByteBuf content = content();
if (content != null) { if (content != null) {
content = content.retainedDuplicate();
boolean success = false;
try { try {
attr.setContent(content.duplicate()); Attribute duplicate = replace(content);
success = true;
return duplicate;
} finally {
if (!success) {
content.release();
}
}
} else {
return replace(null);
}
}
@Override
public Attribute replace(ByteBuf content) {
MemoryAttribute attr = new MemoryAttribute(getName());
attr.setCharset(getCharset());
if (content != null) {
try {
attr.setContent(content);
} catch (IOException e) { } catch (IOException e) {
throw new ChannelException(e); throw new ChannelException(e);
} }

View File

@ -132,12 +132,43 @@ public class MemoryFileUpload extends AbstractMemoryHttpData implements FileUplo
@Override @Override
public FileUpload copy() { public FileUpload copy() {
MemoryFileUpload upload = new MemoryFileUpload(getName(), getFilename(), getContentType(), final ByteBuf content = content();
getContentTransferEncoding(), getCharset(), size); return replace(content != null ? content.copy() : content);
ByteBuf buf = content(); }
if (buf != null) {
@Override
public FileUpload duplicate() {
final ByteBuf content = content();
return replace(content != null ? content.duplicate() : content);
}
@Override
public FileUpload retainedDuplicate() {
ByteBuf content = content();
if (content != null) {
content = content.retainedDuplicate();
boolean success = false;
try { try {
upload.setContent(buf.copy()); FileUpload duplicate = replace(content);
success = true;
return duplicate;
} finally {
if (!success) {
content.release();
}
}
} else {
return replace(null);
}
}
@Override
public FileUpload replace(ByteBuf content) {
MemoryFileUpload upload = new MemoryFileUpload(
getName(), getFilename(), getContentType(), getContentTransferEncoding(), getCharset(), size);
if (content != null) {
try {
upload.setContent(content);
return upload; return upload;
} catch (IOException e) { } catch (IOException e) {
throw new ChannelException(e); throw new ChannelException(e);
@ -146,21 +177,6 @@ public class MemoryFileUpload extends AbstractMemoryHttpData implements FileUplo
return upload; return upload;
} }
@Override
public FileUpload duplicate() {
MemoryFileUpload upload = new MemoryFileUpload(getName(), getFilename(), getContentType(),
getContentTransferEncoding(), getCharset(), size);
ByteBuf buf = content();
if (buf != null) {
try {
upload.setContent(buf.duplicate());
return upload;
} catch (IOException e) {
throw new ChannelException(e);
}
}
return upload;
}
@Override @Override
public FileUpload retain() { public FileUpload retain() {
super.retain(); super.retain();

View File

@ -271,6 +271,16 @@ public class MixedAttribute implements Attribute {
return attribute.duplicate(); return attribute.duplicate();
} }
@Override
public Attribute retainedDuplicate() {
return attribute.retainedDuplicate();
}
@Override
public Attribute replace(ByteBuf content) {
return attribute.replace(content);
}
@Override @Override
public ByteBuf content() { public ByteBuf content() {
return attribute.content(); return attribute.content();

View File

@ -293,6 +293,16 @@ public class MixedFileUpload implements FileUpload {
return fileUpload.duplicate(); return fileUpload.duplicate();
} }
@Override
public FileUpload retainedDuplicate() {
return fileUpload.retainedDuplicate();
}
@Override
public FileUpload replace(ByteBuf content) {
return fileUpload.replace(content);
}
@Override @Override
public ByteBuf content() { public ByteBuf content() {
return fileUpload.content(); return fileUpload.content();

View File

@ -56,12 +56,22 @@ public class BinaryWebSocketFrame extends WebSocketFrame {
@Override @Override
public BinaryWebSocketFrame copy() { public BinaryWebSocketFrame copy() {
return new BinaryWebSocketFrame(isFinalFragment(), rsv(), content().copy()); return (BinaryWebSocketFrame) super.copy();
} }
@Override @Override
public BinaryWebSocketFrame duplicate() { public BinaryWebSocketFrame duplicate() {
return new BinaryWebSocketFrame(isFinalFragment(), rsv(), content().duplicate()); return (BinaryWebSocketFrame) super.duplicate();
}
@Override
public BinaryWebSocketFrame retainedDuplicate() {
return (BinaryWebSocketFrame) super.retainedDuplicate();
}
@Override
public BinaryWebSocketFrame replace(ByteBuf content) {
return new BinaryWebSocketFrame(isFinalFragment(), rsv(), content);
} }
@Override @Override

View File

@ -140,12 +140,22 @@ public class CloseWebSocketFrame extends WebSocketFrame {
@Override @Override
public CloseWebSocketFrame copy() { public CloseWebSocketFrame copy() {
return new CloseWebSocketFrame(isFinalFragment(), rsv(), content().copy()); return (CloseWebSocketFrame) super.copy();
} }
@Override @Override
public CloseWebSocketFrame duplicate() { public CloseWebSocketFrame duplicate() {
return new CloseWebSocketFrame(isFinalFragment(), rsv(), content().duplicate()); return (CloseWebSocketFrame) super.duplicate();
}
@Override
public CloseWebSocketFrame retainedDuplicate() {
return (CloseWebSocketFrame) super.retainedDuplicate();
}
@Override
public CloseWebSocketFrame replace(ByteBuf content) {
return new CloseWebSocketFrame(isFinalFragment(), rsv(), content);
} }
@Override @Override

View File

@ -93,12 +93,22 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
@Override @Override
public ContinuationWebSocketFrame copy() { public ContinuationWebSocketFrame copy() {
return new ContinuationWebSocketFrame(isFinalFragment(), rsv(), content().copy()); return (ContinuationWebSocketFrame) super.copy();
} }
@Override @Override
public ContinuationWebSocketFrame duplicate() { public ContinuationWebSocketFrame duplicate() {
return new ContinuationWebSocketFrame(isFinalFragment(), rsv(), content().duplicate()); return (ContinuationWebSocketFrame) super.duplicate();
}
@Override
public ContinuationWebSocketFrame retainedDuplicate() {
return (ContinuationWebSocketFrame) super.retainedDuplicate();
}
@Override
public ContinuationWebSocketFrame replace(ByteBuf content) {
return new ContinuationWebSocketFrame(isFinalFragment(), rsv(), content);
} }
@Override @Override

View File

@ -56,12 +56,22 @@ public class PingWebSocketFrame extends WebSocketFrame {
@Override @Override
public PingWebSocketFrame copy() { public PingWebSocketFrame copy() {
return new PingWebSocketFrame(isFinalFragment(), rsv(), content().copy()); return (PingWebSocketFrame) super.copy();
} }
@Override @Override
public PingWebSocketFrame duplicate() { public PingWebSocketFrame duplicate() {
return new PingWebSocketFrame(isFinalFragment(), rsv(), content().duplicate()); return (PingWebSocketFrame) super.duplicate();
}
@Override
public PingWebSocketFrame retainedDuplicate() {
return (PingWebSocketFrame) super.retainedDuplicate();
}
@Override
public PingWebSocketFrame replace(ByteBuf content) {
return new PingWebSocketFrame(isFinalFragment(), rsv(), content);
} }
@Override @Override

View File

@ -56,12 +56,22 @@ public class PongWebSocketFrame extends WebSocketFrame {
@Override @Override
public PongWebSocketFrame copy() { public PongWebSocketFrame copy() {
return new PongWebSocketFrame(isFinalFragment(), rsv(), content().copy()); return (PongWebSocketFrame) super.copy();
} }
@Override @Override
public PongWebSocketFrame duplicate() { public PongWebSocketFrame duplicate() {
return new PongWebSocketFrame(isFinalFragment(), rsv(), content().duplicate()); return (PongWebSocketFrame) super.duplicate();
}
@Override
public PongWebSocketFrame retainedDuplicate() {
return (PongWebSocketFrame) super.retainedDuplicate();
}
@Override
public PongWebSocketFrame replace(ByteBuf content) {
return new PongWebSocketFrame(isFinalFragment(), rsv(), content);
} }
@Override @Override

View File

@ -96,12 +96,22 @@ public class TextWebSocketFrame extends WebSocketFrame {
@Override @Override
public TextWebSocketFrame copy() { public TextWebSocketFrame copy() {
return new TextWebSocketFrame(isFinalFragment(), rsv(), content().copy()); return (TextWebSocketFrame) super.copy();
} }
@Override @Override
public TextWebSocketFrame duplicate() { public TextWebSocketFrame duplicate() {
return new TextWebSocketFrame(isFinalFragment(), rsv(), content().duplicate()); return (TextWebSocketFrame) super.duplicate();
}
@Override
public TextWebSocketFrame retainedDuplicate() {
return (TextWebSocketFrame) super.retainedDuplicate();
}
@Override
public TextWebSocketFrame replace(ByteBuf content) {
return new TextWebSocketFrame(isFinalFragment(), rsv(), content);
} }
@Override @Override

View File

@ -61,10 +61,22 @@ public abstract class WebSocketFrame extends DefaultByteBufHolder {
} }
@Override @Override
public abstract WebSocketFrame copy(); public WebSocketFrame copy() {
return (WebSocketFrame) super.copy();
}
@Override @Override
public abstract WebSocketFrame duplicate(); public WebSocketFrame duplicate() {
return (WebSocketFrame) super.duplicate();
}
@Override
public WebSocketFrame retainedDuplicate() {
return (WebSocketFrame) super.retainedDuplicate();
}
@Override
public abstract WebSocketFrame replace(ByteBuf content);
@Override @Override
public String toString() { public String toString() {

View File

@ -80,14 +80,22 @@ public class DefaultSpdyDataFrame extends DefaultSpdyStreamFrame implements Spdy
@Override @Override
public SpdyDataFrame copy() { public SpdyDataFrame copy() {
SpdyDataFrame frame = new DefaultSpdyDataFrame(streamId(), content().copy()); return replace(content().copy());
frame.setLast(isLast());
return frame;
} }
@Override @Override
public SpdyDataFrame duplicate() { public SpdyDataFrame duplicate() {
SpdyDataFrame frame = new DefaultSpdyDataFrame(streamId(), content().duplicate()); return replace(content().duplicate());
}
@Override
public SpdyDataFrame retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public SpdyDataFrame replace(ByteBuf content) {
SpdyDataFrame frame = new DefaultSpdyDataFrame(streamId(), content);
frame.setLast(isLast()); frame.setLast(isLast());
return frame; return frame;
} }

View File

@ -45,6 +45,12 @@ public interface SpdyDataFrame extends ByteBufHolder, SpdyStreamFrame {
@Override @Override
SpdyDataFrame duplicate(); SpdyDataFrame duplicate();
@Override
SpdyDataFrame retainedDuplicate();
@Override
SpdyDataFrame replace(ByteBuf content);
@Override @Override
SpdyDataFrame retain(); SpdyDataFrame retain();

View File

@ -24,7 +24,8 @@ import io.netty.util.internal.EmptyArrays;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static io.netty.handler.codec.spdy.SpdyCodecUtil.*; import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_SESSION_STREAM_ID;
import static io.netty.handler.codec.spdy.SpdyCodecUtil.isServerId;
/** /**
* Manages streams within a SPDY session. * Manages streams within a SPDY session.
@ -190,8 +191,8 @@ public class SpdySessionHandler extends ChannelDuplexHandler {
// Send data frames upstream in initialReceiveWindowSize chunks // Send data frames upstream in initialReceiveWindowSize chunks
if (newWindowSize < 0) { if (newWindowSize < 0) {
while (spdyDataFrame.content().readableBytes() > initialReceiveWindowSize) { while (spdyDataFrame.content().readableBytes() > initialReceiveWindowSize) {
SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(streamId, SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(
spdyDataFrame.content().readSlice(initialReceiveWindowSize).retain()); streamId, spdyDataFrame.content().readRetainedSlice(initialReceiveWindowSize));
ctx.writeAndFlush(partialDataFrame); ctx.writeAndFlush(partialDataFrame);
} }
} }
@ -497,8 +498,8 @@ public class SpdySessionHandler extends ChannelDuplexHandler {
spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * sendWindowSize); spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * sendWindowSize);
// Create a partial data frame whose length is the current window size // Create a partial data frame whose length is the current window size
SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(streamId, SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(
spdyDataFrame.content().readSlice(sendWindowSize).retain()); streamId, spdyDataFrame.content().readRetainedSlice(sendWindowSize));
// Enqueue the remaining data (will be the first frame queued) // Enqueue the remaining data (will be the first frame queued)
spdySession.putPendingWrite(streamId, new SpdySession.PendingWrite(spdyDataFrame, promise)); spdySession.putPendingWrite(streamId, new SpdySession.PendingWrite(spdyDataFrame, promise));
@ -778,8 +779,8 @@ public class SpdySessionHandler extends ChannelDuplexHandler {
spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * sendWindowSize); spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * sendWindowSize);
// Create a partial data frame whose length is the current window size // Create a partial data frame whose length is the current window size
SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(writeStreamId, SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(
spdyDataFrame.content().readSlice(sendWindowSize).retain()); writeStreamId, spdyDataFrame.content().readRetainedSlice(sendWindowSize));
// The transfer window size is pre-decremented when sending a data frame downstream. // The transfer window size is pre-decremented when sending a data frame downstream.
// Close the session on write failures that leave the transfer window in a corrupt state. // Close the session on write failures that leave the transfer window in a corrupt state.

View File

@ -74,22 +74,32 @@ public class AbstractMemoryHttpDataTest {
@Override @Override
public InterfaceHttpData.HttpDataType getHttpDataType() { public InterfaceHttpData.HttpDataType getHttpDataType() {
throw new UnsupportedOperationException("Should never be called."); throw reject();
} }
@Override @Override
public HttpData copy() { public HttpData copy() {
throw new UnsupportedOperationException("Should never be called."); throw reject();
} }
@Override @Override
public HttpData duplicate() { public HttpData duplicate() {
throw new UnsupportedOperationException("Should never be called."); throw reject();
}
@Override
public HttpData retainedDuplicate() {
throw reject();
}
@Override
public HttpData replace(ByteBuf content) {
return null;
} }
@Override @Override
public int compareTo(InterfaceHttpData o) { public int compareTo(InterfaceHttpData o) {
throw new UnsupportedOperationException("Should never be called."); throw reject();
} }
@Override @Override
@ -101,5 +111,9 @@ public class AbstractMemoryHttpDataTest {
public boolean equals(Object obj) { public boolean equals(Object obj) {
return super.equals(obj); return super.equals(obj);
} }
private static UnsupportedOperationException reject() {
throw new UnsupportedOperationException("Should never be called.");
}
} }
} }

View File

@ -460,7 +460,7 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
public void onPingRead(ChannelHandlerContext ctx, ByteBuf data) throws Http2Exception { public void onPingRead(ChannelHandlerContext ctx, ByteBuf data) throws Http2Exception {
// Send an ack back to the remote client. // Send an ack back to the remote client.
// Need to retain the buffer here since it will be released after the write completes. // Need to retain the buffer here since it will be released after the write completes.
encoder.writePing(ctx, true, data.slice().retain(), ctx.newPromise()); encoder.writePing(ctx, true, data.retainedSlice(), ctx.newPromise());
listener.onPingRead(ctx, data); listener.onPingRead(ctx, data);
} }

View File

@ -15,13 +15,13 @@
*/ */
package io.netty.handler.codec.http2; package io.netty.handler.codec.http2;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.util.IllegalReferenceCountException; import io.netty.util.IllegalReferenceCountException;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/** /**
* The default {@link Http2DataFrame} implementation. * The default {@link Http2DataFrame} implementation.
*/ */
@ -101,12 +101,22 @@ public final class DefaultHttp2DataFrame extends AbstractHttp2StreamFrame implem
@Override @Override
public DefaultHttp2DataFrame copy() { public DefaultHttp2DataFrame copy() {
return new DefaultHttp2DataFrame(content().copy(), endStream, padding); return replace(content().copy());
} }
@Override @Override
public DefaultHttp2DataFrame duplicate() { public DefaultHttp2DataFrame duplicate() {
return new DefaultHttp2DataFrame(content().duplicate(), endStream, padding); return replace(content().duplicate());
}
@Override
public DefaultHttp2DataFrame retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public DefaultHttp2DataFrame replace(ByteBuf content) {
return new DefaultHttp2DataFrame(content, endStream, padding);
} }
@Override @Override

View File

@ -15,6 +15,14 @@
package io.netty.handler.codec.http2; package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http2.Http2CodecUtil.SimpleChannelPromiseAggregator;
import io.netty.handler.codec.http2.Http2FrameWriter.Configuration;
import io.netty.util.internal.UnstableApi;
import static io.netty.buffer.Unpooled.directBuffer; import static io.netty.buffer.Unpooled.directBuffer;
import static io.netty.buffer.Unpooled.unreleasableBuffer; import static io.netty.buffer.Unpooled.unreleasableBuffer;
import static io.netty.handler.codec.http2.Http2CodecUtil.CONTINUATION_FRAME_HEADER_LENGTH; import static io.netty.handler.codec.http2.Http2CodecUtil.CONTINUATION_FRAME_HEADER_LENGTH;
@ -55,14 +63,6 @@ import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http2.Http2CodecUtil.SimpleChannelPromiseAggregator;
import io.netty.handler.codec.http2.Http2FrameWriter.Configuration;
import io.netty.util.internal.UnstableApi;
/** /**
* A {@link Http2FrameWriter} that supports all frame types defined by the HTTP/2 specification. * A {@link Http2FrameWriter} that supports all frame types defined by the HTTP/2 specification.
*/ */
@ -304,8 +304,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
// INT_FIELD_LENGTH is for the length of the promisedStreamId // INT_FIELD_LENGTH is for the length of the promisedStreamId
int nonFragmentLength = INT_FIELD_LENGTH + padding + flags.getPaddingPresenceFieldLength(); int nonFragmentLength = INT_FIELD_LENGTH + padding + flags.getPaddingPresenceFieldLength();
int maxFragmentLength = maxFrameSize - nonFragmentLength; int maxFragmentLength = maxFrameSize - nonFragmentLength;
ByteBuf fragment = ByteBuf fragment = headerBlock.readRetainedSlice(min(headerBlock.readableBytes(), maxFragmentLength));
headerBlock.readSlice(min(headerBlock.readableBytes(), maxFragmentLength));
flags.endOfHeaders(!headerBlock.isReadable()); flags.endOfHeaders(!headerBlock.isReadable());
@ -319,7 +318,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
ctx.write(buf, promiseAggregator.newPromise()); ctx.write(buf, promiseAggregator.newPromise());
// Write the first fragment. // Write the first fragment.
ctx.write(fragment.retain(), promiseAggregator.newPromise()); ctx.write(fragment, promiseAggregator.newPromise());
if (padding > 0) { // Write out the padding, if any. if (padding > 0) { // Write out the padding, if any.
ctx.write(ZERO_BUFFER.slice(0, padding), promiseAggregator.newPromise()); ctx.write(ZERO_BUFFER.slice(0, padding), promiseAggregator.newPromise());
@ -429,8 +428,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
// Read the first fragment (possibly everything). // Read the first fragment (possibly everything).
int nonFragmentBytes = padding + flags.getNumPriorityBytes() + flags.getPaddingPresenceFieldLength(); int nonFragmentBytes = padding + flags.getNumPriorityBytes() + flags.getPaddingPresenceFieldLength();
int maxFragmentLength = maxFrameSize - nonFragmentBytes; int maxFragmentLength = maxFrameSize - nonFragmentBytes;
ByteBuf fragment = ByteBuf fragment = headerBlock.readRetainedSlice(min(headerBlock.readableBytes(), maxFragmentLength));
headerBlock.readSlice(min(headerBlock.readableBytes(), maxFragmentLength));
// Set the end of headers flag for the first frame. // Set the end of headers flag for the first frame.
flags.endOfHeaders(!headerBlock.isReadable()); flags.endOfHeaders(!headerBlock.isReadable());
@ -450,7 +448,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
ctx.write(buf, promiseAggregator.newPromise()); ctx.write(buf, promiseAggregator.newPromise());
// Write the first fragment. // Write the first fragment.
ctx.write(fragment.retain(), promiseAggregator.newPromise()); ctx.write(fragment, promiseAggregator.newPromise());
if (padding > 0) { // Write out the padding, if any. if (padding > 0) { // Write out the padding, if any.
ctx.write(ZERO_BUFFER.slice(0, padding), promiseAggregator.newPromise()); ctx.write(ZERO_BUFFER.slice(0, padding), promiseAggregator.newPromise());
@ -493,7 +491,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
do { do {
fragmentReadableBytes = min(headerBlock.readableBytes(), maxFragmentLength); fragmentReadableBytes = min(headerBlock.readableBytes(), maxFragmentLength);
ByteBuf fragment = headerBlock.readSlice(fragmentReadableBytes).retain(); ByteBuf fragment = headerBlock.readRetainedSlice(fragmentReadableBytes);
payloadLength = fragmentReadableBytes + nonFragmentLength; payloadLength = fragmentReadableBytes + nonFragmentLength;
if (headerBlock.isReadable()) { if (headerBlock.isReadable()) {

View File

@ -78,7 +78,7 @@ public final class DefaultHttp2GoAwayFrame extends DefaultByteBufHolder implemen
} }
@Override @Override
public DefaultHttp2GoAwayFrame setExtraStreamIds(int extraStreamIds) { public Http2GoAwayFrame setExtraStreamIds(int extraStreamIds) {
if (extraStreamIds < 0) { if (extraStreamIds < 0) {
throw new IllegalArgumentException("extraStreamIds must be non-negative"); throw new IllegalArgumentException("extraStreamIds must be non-negative");
} }
@ -87,41 +87,45 @@ public final class DefaultHttp2GoAwayFrame extends DefaultByteBufHolder implemen
} }
@Override @Override
public DefaultHttp2GoAwayFrame copy() { public Http2GoAwayFrame copy() {
return new DefaultHttp2GoAwayFrame(errorCode, content().copy()).setExtraStreamIds(extraStreamIds); return (Http2GoAwayFrame) super.copy();
} }
@Override @Override
public DefaultHttp2GoAwayFrame duplicate() { public Http2GoAwayFrame duplicate() {
return new DefaultHttp2GoAwayFrame(errorCode, content().duplicate()).setExtraStreamIds(extraStreamIds); return (Http2GoAwayFrame) super.duplicate();
} }
@Override @Override
public DefaultHttp2GoAwayFrame retain() { public Http2GoAwayFrame retainedDuplicate() {
return (Http2GoAwayFrame) super.retainedDuplicate();
}
@Override
public Http2GoAwayFrame replace(ByteBuf content) {
return new DefaultHttp2GoAwayFrame(errorCode, content).setExtraStreamIds(extraStreamIds);
}
@Override
public Http2GoAwayFrame retain() {
super.retain(); super.retain();
return this; return this;
} }
@Override @Override
public DefaultHttp2GoAwayFrame retain(int increment) { public Http2GoAwayFrame retain(int increment) {
super.retain(increment); super.retain(increment);
return this; return this;
} }
@Override @Override
public String toString() { public Http2GoAwayFrame touch() {
return "DefaultHttp2GoAwayFrame(errorCode=" + errorCode + ", content=" + content()
+ ", extraStreamIds=" + extraStreamIds + ")";
}
@Override
public DefaultHttp2GoAwayFrame touch() {
super.touch(); super.touch();
return this; return this;
} }
@Override @Override
public DefaultHttp2GoAwayFrame touch(Object hint) { public Http2GoAwayFrame touch(Object hint) {
super.touch(hint); super.touch(hint);
return this; return this;
} }
@ -144,4 +148,10 @@ public final class DefaultHttp2GoAwayFrame extends DefaultByteBufHolder implemen
hash = hash * 31 + extraStreamIds; hash = hash * 31 + extraStreamIds;
return hash; return hash;
} }
@Override
public String toString() {
return "DefaultHttp2GoAwayFrame(errorCode=" + errorCode + ", content=" + content()
+ ", extraStreamIds=" + extraStreamIds + ")";
}
} }

View File

@ -119,7 +119,7 @@ public final class Http2CodecUtil {
*/ */
public static ByteBuf connectionPrefaceBuf() { public static ByteBuf connectionPrefaceBuf() {
// Return a duplicate so that modifications to the reader index will not affect the original buffer. // Return a duplicate so that modifications to the reader index will not affect the original buffer.
return CONNECTION_PREFACE.duplicate().retain(); return CONNECTION_PREFACE.retainedDuplicate();
} }
/** /**
@ -127,7 +127,7 @@ public final class Http2CodecUtil {
*/ */
public static ByteBuf emptyPingBuf() { public static ByteBuf emptyPingBuf() {
// Return a duplicate so that modifications to the reader index will not affect the original buffer. // Return a duplicate so that modifications to the reader index will not affect the original buffer.
return EMPTY_PING.duplicate().retain(); return EMPTY_PING.retainedDuplicate();
} }
/** /**

View File

@ -49,6 +49,12 @@ public interface Http2DataFrame extends Http2StreamFrame, ByteBufHolder {
@Override @Override
Http2DataFrame duplicate(); Http2DataFrame duplicate();
@Override
Http2DataFrame retainedDuplicate();
@Override
Http2DataFrame replace(ByteBuf content);
@Override @Override
Http2DataFrame retain(); Http2DataFrame retain();

View File

@ -58,6 +58,12 @@ public interface Http2GoAwayFrame extends Http2Frame, ByteBufHolder {
@Override @Override
Http2GoAwayFrame duplicate(); Http2GoAwayFrame duplicate();
@Override
Http2GoAwayFrame retainedDuplicate();
@Override
Http2GoAwayFrame replace(ByteBuf content);
@Override @Override
Http2GoAwayFrame retain(); Http2GoAwayFrame retain();

View File

@ -371,7 +371,7 @@ public final class Http2MultiplexCodec extends ChannelDuplexHandler {
StreamInfo streamInfo = (StreamInfo) stream.getProperty(streamInfoKey); StreamInfo streamInfo = (StreamInfo) stream.getProperty(streamInfoKey);
// TODO: Can we force a user interaction pattern that doesn't require us to duplicate()? // TODO: Can we force a user interaction pattern that doesn't require us to duplicate()?
// https://github.com/netty/netty/issues/4943 // https://github.com/netty/netty/issues/4943
streamInfo.childChannel.pipeline().fireUserEventTriggered(goAway.duplicate().retain()); streamInfo.childChannel.pipeline().fireUserEventTriggered(goAway.retainedDuplicate());
} }
return true; return true;
} }
@ -389,12 +389,12 @@ public final class Http2MultiplexCodec extends ChannelDuplexHandler {
}); });
} }
} }
ctx.fireUserEventTriggered(goAway.duplicate().retain()); ctx.fireUserEventTriggered(goAway.retainedDuplicate());
} }
} }
class InternalHttp2ConnectionHandler extends Http2ConnectionHandler { class InternalHttp2ConnectionHandler extends Http2ConnectionHandler {
public InternalHttp2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, InternalHttp2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
Http2Settings initialSettings) { Http2Settings initialSettings) {
super(decoder, encoder, initialSettings); super(decoder, encoder, initialSettings);
} }

View File

@ -16,6 +16,7 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpMessage; import io.netty.handler.codec.http.FullHttpMessage;
import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest;
@ -53,7 +54,7 @@ public class InboundHttp2ToHttpAdapter extends Http2EventAdapter {
@Override @Override
public FullHttpMessage copyIfNeeded(FullHttpMessage msg) { public FullHttpMessage copyIfNeeded(FullHttpMessage msg) {
if (msg instanceof FullHttpRequest) { if (msg instanceof FullHttpRequest) {
FullHttpRequest copy = ((FullHttpRequest) msg).copy(null); FullHttpRequest copy = ((FullHttpRequest) msg).replace(Unpooled.buffer(0));
copy.headers().remove(HttpHeaderNames.EXPECT); copy.headers().remove(HttpHeaderNames.EXPECT);
return copy; return copy;
} }

View File

@ -394,7 +394,7 @@ public class Http2ConnectionRoundtripTest {
public void run() throws Http2Exception { public void run() throws Http2Exception {
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
false, newPromise()); false, newPromise());
http2Client.encoder().writeData(ctx(), 3, data.duplicate().retain(), 0, false, newPromise()); http2Client.encoder().writeData(ctx(), 3, data.retainedDuplicate(), 0, false, newPromise());
// Write trailers. // Write trailers.
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
@ -479,9 +479,9 @@ public class Http2ConnectionRoundtripTest {
// Send a bunch of data on each stream. // Send a bunch of data on each stream.
http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16, http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16,
false, 0, false, newPromise()); false, 0, false, newPromise());
http2Client.encoder().writePing(ctx(), false, pingData.slice().retain(), http2Client.encoder().writePing(ctx(), false, pingData.retainedSlice(),
newPromise()); newPromise());
http2Client.encoder().writeData(ctx(), streamId, data.slice().retain(), 0, http2Client.encoder().writeData(ctx(), streamId, data.retainedSlice(), 0,
false, newPromise()); false, newPromise());
// Write trailers. // Write trailers.
http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16, http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16,

View File

@ -267,7 +267,7 @@ public class InboundHttp2ToHttpAdapterTest {
@Override @Override
public void run() { public void run() {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient()); clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 3, content.duplicate().retain(), 0, true, clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, true,
newPromiseClient()); newPromiseClient());
clientChannel.flush(); clientChannel.flush();
} }
@ -300,10 +300,11 @@ public class InboundHttp2ToHttpAdapterTest {
@Override @Override
public void run() { public void run() {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient()); clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 3, content.slice(0, midPoint).retain(), 0, false, clientHandler.encoder().writeData(
newPromiseClient()); ctxClient(), 3, content.retainedSlice(0, midPoint), 0, false, newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 3, clientHandler.encoder().writeData(
content.slice(midPoint, text.length() - midPoint).retain(), 0, true, newPromiseClient()); ctxClient(), 3, content.retainedSlice(midPoint, text.length() - midPoint),
0, true, newPromiseClient());
clientChannel.flush(); clientChannel.flush();
} }
}); });
@ -417,7 +418,7 @@ public class InboundHttp2ToHttpAdapterTest {
@Override @Override
public void run() { public void run() {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient()); clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 3, content.duplicate().retain(), 0, false, clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, false,
newPromiseClient()); newPromiseClient());
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers2, 0, true, newPromiseClient()); clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers2, 0, true, newPromiseClient());
clientChannel.flush(); clientChannel.flush();
@ -464,9 +465,9 @@ public class InboundHttp2ToHttpAdapterTest {
clientHandler.encoder().writeHeaders(ctxClient(), 5, http2Headers2, 0, false, newPromiseClient()); clientHandler.encoder().writeHeaders(ctxClient(), 5, http2Headers2, 0, false, newPromiseClient());
clientChannel.flush(); // Headers are queued in the flow controller and so flush them. clientChannel.flush(); // Headers are queued in the flow controller and so flush them.
clientHandler.encoder().writePriority(ctxClient(), 5, 3, (short) 123, true, newPromiseClient()); clientHandler.encoder().writePriority(ctxClient(), 5, 3, (short) 123, true, newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 3, content.duplicate().retain(), 0, true, clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, true,
newPromiseClient()); newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 5, content2.duplicate().retain(), 0, true, clientHandler.encoder().writeData(ctxClient(), 5, content2.retainedDuplicate(), 0, true,
newPromiseClient()); newPromiseClient());
clientChannel.flush(); clientChannel.flush();
} }
@ -518,9 +519,9 @@ public class InboundHttp2ToHttpAdapterTest {
public void run() { public void run() {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient()); clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
clientHandler.encoder().writeHeaders(ctxClient(), 5, http2Headers2, 0, false, newPromiseClient()); clientHandler.encoder().writeHeaders(ctxClient(), 5, http2Headers2, 0, false, newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 3, content.duplicate().retain(), 0, true, clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, true,
newPromiseClient()); newPromiseClient());
clientHandler.encoder().writeData(ctxClient(), 5, content2.duplicate().retain(), 0, true, clientHandler.encoder().writeData(ctxClient(), 5, content2.retainedDuplicate(), 0, true,
newPromiseClient()); newPromiseClient());
clientChannel.flush(); // headers and data are queued in the flow controller, so flush them. clientChannel.flush(); // headers and data are queued in the flow controller, so flush them.
clientHandler.encoder().writePriority(ctxClient(), 5, 3, (short) 222, false, newPromiseClient()); clientHandler.encoder().writePriority(ctxClient(), 5, 3, (short) 222, false, newPromiseClient());
@ -592,9 +593,9 @@ public class InboundHttp2ToHttpAdapterTest {
public void run() { public void run() {
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2Headers, 0, false, newPromiseServer()); serverHandler.encoder().writeHeaders(ctxServer(), 3, http2Headers, 0, false, newPromiseServer());
serverHandler.encoder().writePushPromise(ctxServer(), 3, 2, http2Headers2, 0, newPromiseServer()); serverHandler.encoder().writePushPromise(ctxServer(), 3, 2, http2Headers2, 0, newPromiseServer());
serverHandler.encoder().writeData(ctxServer(), 3, content.duplicate().retain(), 0, true, serverHandler.encoder().writeData(ctxServer(), 3, content.retainedDuplicate(), 0, true,
newPromiseServer()); newPromiseServer());
serverHandler.encoder().writeData(ctxServer(), 5, content2.duplicate().retain(), 0, true, serverHandler.encoder().writeData(ctxServer(), 5, content2.retainedDuplicate(), 0, true,
newPromiseServer()); newPromiseServer());
serverConnectedChannel.flush(); serverConnectedChannel.flush();
} }
@ -627,7 +628,7 @@ public class InboundHttp2ToHttpAdapterTest {
final FullHttpMessage response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE); final FullHttpMessage response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
final String text = "a big payload"; final String text = "a big payload";
final ByteBuf payload = Unpooled.copiedBuffer(text.getBytes()); final ByteBuf payload = Unpooled.copiedBuffer(text.getBytes());
final FullHttpMessage request2 = request.copy(payload); final FullHttpMessage request2 = request.replace(payload);
final FullHttpMessage response2 = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); final FullHttpMessage response2 = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
try { try {
@ -660,7 +661,7 @@ public class InboundHttp2ToHttpAdapterTest {
runInChannel(clientChannel, new Http2Runnable() { runInChannel(clientChannel, new Http2Runnable() {
@Override @Override
public void run() { public void run() {
clientHandler.encoder().writeData(ctxClient(), 3, payload.duplicate().retain(), 0, true, clientHandler.encoder().writeData(ctxClient(), 3, payload.retainedDuplicate(), 0, true,
newPromiseClient()); newPromiseClient());
clientChannel.flush(); clientChannel.flush();
} }

View File

@ -60,11 +60,21 @@ public class DefaultLastMemcacheContent extends DefaultMemcacheContent implement
@Override @Override
public LastMemcacheContent copy() { public LastMemcacheContent copy() {
return new DefaultLastMemcacheContent(content().copy()); return replace(content().copy());
} }
@Override @Override
public LastMemcacheContent duplicate() { public LastMemcacheContent duplicate() {
return new DefaultLastMemcacheContent(content().duplicate()); return replace(content().duplicate());
}
@Override
public LastMemcacheContent retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public LastMemcacheContent replace(ByteBuf content) {
return new DefaultLastMemcacheContent(content);
} }
} }

View File

@ -44,12 +44,22 @@ public class DefaultMemcacheContent extends AbstractMemcacheObject implements Me
@Override @Override
public MemcacheContent copy() { public MemcacheContent copy() {
return new DefaultMemcacheContent(content.copy()); return replace(content.copy());
} }
@Override @Override
public MemcacheContent duplicate() { public MemcacheContent duplicate() {
return new DefaultMemcacheContent(content.duplicate()); return replace(content.duplicate());
}
@Override
public MemcacheContent retainedDuplicate() {
return replace(content.retainedDuplicate());
}
@Override
public MemcacheContent replace(ByteBuf content) {
return new DefaultMemcacheContent(content);
} }
@Override @Override

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.memcache; package io.netty.handler.codec.memcache;
import io.netty.buffer.ByteBuf;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
/** /**
@ -27,6 +28,15 @@ public interface FullMemcacheMessage extends MemcacheMessage, LastMemcacheConten
@Override @Override
FullMemcacheMessage copy(); FullMemcacheMessage copy();
@Override
FullMemcacheMessage duplicate();
@Override
FullMemcacheMessage retainedDuplicate();
@Override
FullMemcacheMessage replace(ByteBuf content);
@Override @Override
FullMemcacheMessage retain(int increment); FullMemcacheMessage retain(int increment);
@ -38,7 +48,4 @@ public interface FullMemcacheMessage extends MemcacheMessage, LastMemcacheConten
@Override @Override
FullMemcacheMessage touch(Object hint); FullMemcacheMessage touch(Object hint);
@Override
FullMemcacheMessage duplicate();
} }

View File

@ -37,6 +37,21 @@ public interface LastMemcacheContent extends MemcacheContent {
return EMPTY_LAST_CONTENT; return EMPTY_LAST_CONTENT;
} }
@Override
public LastMemcacheContent duplicate() {
return this;
}
@Override
public LastMemcacheContent retainedDuplicate() {
return this;
}
@Override
public LastMemcacheContent replace(ByteBuf content) {
return new DefaultLastMemcacheContent(content);
}
@Override @Override
public LastMemcacheContent retain(int increment) { public LastMemcacheContent retain(int increment) {
return this; return this;
@ -57,11 +72,6 @@ public interface LastMemcacheContent extends MemcacheContent {
return this; return this;
} }
@Override
public LastMemcacheContent duplicate() {
return this;
}
@Override @Override
public ByteBuf content() { public ByteBuf content() {
return Unpooled.EMPTY_BUFFER; return Unpooled.EMPTY_BUFFER;
@ -96,6 +106,15 @@ public interface LastMemcacheContent extends MemcacheContent {
@Override @Override
LastMemcacheContent copy(); LastMemcacheContent copy();
@Override
LastMemcacheContent duplicate();
@Override
LastMemcacheContent retainedDuplicate();
@Override
LastMemcacheContent replace(ByteBuf content);
@Override @Override
LastMemcacheContent retain(int increment); LastMemcacheContent retain(int increment);
@ -107,7 +126,4 @@ public interface LastMemcacheContent extends MemcacheContent {
@Override @Override
LastMemcacheContent touch(Object hint); LastMemcacheContent touch(Object hint);
@Override
LastMemcacheContent duplicate();
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.memcache; package io.netty.handler.codec.memcache;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder; import io.netty.buffer.ByteBufHolder;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
@ -36,6 +37,12 @@ public interface MemcacheContent extends MemcacheObject, ByteBufHolder {
@Override @Override
MemcacheContent duplicate(); MemcacheContent duplicate();
@Override
MemcacheContent retainedDuplicate();
@Override
MemcacheContent replace(ByteBuf content);
@Override @Override
MemcacheContent retain(); MemcacheContent retain();

View File

@ -89,7 +89,7 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
return; return;
} }
currentMessage.setExtras(in.readSlice(extrasLength).retain()); currentMessage.setExtras(in.readRetainedSlice(extrasLength));
} }
state = State.READ_KEY; state = State.READ_KEY;
@ -105,7 +105,7 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
return; return;
} }
currentMessage.setKey(in.readSlice(keyLength).retain()); currentMessage.setKey(in.readRetainedSlice(keyLength));
} }
out.add(currentMessage.retain()); out.add(currentMessage.retain());
state = State.READ_CONTENT; state = State.READ_CONTENT;
@ -133,7 +133,7 @@ public abstract class AbstractBinaryMemcacheDecoder<M extends BinaryMemcacheMess
toRead = remainingLength; toRead = remainingLength;
} }
ByteBuf chunkBuffer = in.readSlice(toRead).retain(); ByteBuf chunkBuffer = in.readRetainedSlice(toRead);
MemcacheContent chunk; MemcacheContent chunk;
if ((alreadyReadChunkSize += toRead) >= valueLength) { if ((alreadyReadChunkSize += toRead) >= valueLength) {

View File

@ -117,4 +117,22 @@ public class DefaultFullBinaryMemcacheRequest extends DefaultBinaryMemcacheReque
} }
return new DefaultFullBinaryMemcacheRequest(key, extras, content().duplicate()); return new DefaultFullBinaryMemcacheRequest(key, extras, content().duplicate());
} }
@Override
public FullBinaryMemcacheRequest retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public FullBinaryMemcacheRequest replace(ByteBuf content) {
ByteBuf key = key();
if (key != null) {
key = key.retainedDuplicate();
}
ByteBuf extras = extras();
if (extras != null) {
extras = extras.retainedDuplicate();
}
return new DefaultFullBinaryMemcacheRequest(key, extras, content);
}
} }

View File

@ -117,4 +117,22 @@ public class DefaultFullBinaryMemcacheResponse extends DefaultBinaryMemcacheResp
} }
return new DefaultFullBinaryMemcacheResponse(key, extras, content().duplicate()); return new DefaultFullBinaryMemcacheResponse(key, extras, content().duplicate());
} }
@Override
public FullBinaryMemcacheResponse retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public FullBinaryMemcacheResponse replace(ByteBuf content) {
ByteBuf key = key();
if (key != null) {
key = key.retainedDuplicate();
}
ByteBuf extras = extras();
if (extras != null) {
extras = extras.retainedDuplicate();
}
return new DefaultFullBinaryMemcacheResponse(key, extras, content);
}
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.memcache.binary; package io.netty.handler.codec.memcache.binary;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.memcache.FullMemcacheMessage; import io.netty.handler.codec.memcache.FullMemcacheMessage;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
@ -27,6 +28,15 @@ public interface FullBinaryMemcacheRequest extends BinaryMemcacheRequest, FullMe
@Override @Override
FullBinaryMemcacheRequest copy(); FullBinaryMemcacheRequest copy();
@Override
FullBinaryMemcacheRequest duplicate();
@Override
FullBinaryMemcacheRequest retainedDuplicate();
@Override
FullBinaryMemcacheRequest replace(ByteBuf content);
@Override @Override
FullBinaryMemcacheRequest retain(int increment); FullBinaryMemcacheRequest retain(int increment);
@ -38,7 +48,4 @@ public interface FullBinaryMemcacheRequest extends BinaryMemcacheRequest, FullMe
@Override @Override
FullBinaryMemcacheRequest touch(Object hint); FullBinaryMemcacheRequest touch(Object hint);
@Override
FullBinaryMemcacheRequest duplicate();
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.memcache.binary; package io.netty.handler.codec.memcache.binary;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.memcache.FullMemcacheMessage; import io.netty.handler.codec.memcache.FullMemcacheMessage;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
@ -27,6 +28,15 @@ public interface FullBinaryMemcacheResponse extends BinaryMemcacheResponse, Full
@Override @Override
FullBinaryMemcacheResponse copy(); FullBinaryMemcacheResponse copy();
@Override
FullBinaryMemcacheResponse duplicate();
@Override
FullBinaryMemcacheResponse retainedDuplicate();
@Override
FullBinaryMemcacheResponse replace(ByteBuf content);
@Override @Override
FullBinaryMemcacheResponse retain(int increment); FullBinaryMemcacheResponse retain(int increment);
@ -38,7 +48,4 @@ public interface FullBinaryMemcacheResponse extends BinaryMemcacheResponse, Full
@Override @Override
FullBinaryMemcacheResponse touch(Object hint); FullBinaryMemcacheResponse touch(Object hint);
@Override
FullBinaryMemcacheResponse duplicate();
} }

View File

@ -26,7 +26,11 @@ import io.netty.util.CharsetUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static io.netty.handler.codec.mqtt.MqttCodecUtil.*; import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidClientId;
import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidMessageId;
import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidPublishTopicName;
import static io.netty.handler.codec.mqtt.MqttCodecUtil.resetUnusedFields;
import static io.netty.handler.codec.mqtt.MqttCodecUtil.validateFixedHeader;
/** /**
* Decodes Mqtt messages from bytes, following * Decodes Mqtt messages from bytes, following
@ -409,7 +413,7 @@ public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
} }
private static Result<ByteBuf> decodePublishPayload(ByteBuf buffer, int bytesRemainingInVariablePart) { private static Result<ByteBuf> decodePublishPayload(ByteBuf buffer, int bytesRemainingInVariablePart) {
ByteBuf b = buffer.readSlice(bytesRemainingInVariablePart).retain(); ByteBuf b = buffer.readRetainedSlice(bytesRemainingInVariablePart);
return new Result<ByteBuf>(b, bytesRemainingInVariablePart); return new Result<ByteBuf>(b, bytesRemainingInVariablePart);
} }

View File

@ -53,12 +53,22 @@ public class MqttPublishMessage extends MqttMessage implements ByteBufHolder {
@Override @Override
public MqttPublishMessage copy() { public MqttPublishMessage copy() {
return new MqttPublishMessage(fixedHeader(), variableHeader(), content().copy()); return replace(content().copy());
} }
@Override @Override
public MqttPublishMessage duplicate() { public MqttPublishMessage duplicate() {
return new MqttPublishMessage(fixedHeader(), variableHeader(), content().duplicate()); return replace(content().duplicate());
}
@Override
public MqttPublishMessage retainedDuplicate() {
return replace(content().retainedDuplicate());
}
@Override
public MqttPublishMessage replace(ByteBuf content) {
return new MqttPublishMessage(fixedHeader(), variableHeader(), content);
} }
@Override @Override

View File

@ -15,6 +15,7 @@
package io.netty.handler.codec.redis; package io.netty.handler.codec.redis;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder; import io.netty.buffer.ByteBufHolder;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
@ -28,4 +29,28 @@ import io.netty.util.internal.UnstableApi;
*/ */
@UnstableApi @UnstableApi
public interface BulkStringRedisContent extends RedisMessage, ByteBufHolder { public interface BulkStringRedisContent extends RedisMessage, ByteBufHolder {
@Override
BulkStringRedisContent copy();
@Override
BulkStringRedisContent duplicate();
@Override
BulkStringRedisContent retainedDuplicate();
@Override
BulkStringRedisContent replace(ByteBuf content);
@Override
BulkStringRedisContent retain();
@Override
BulkStringRedisContent retain(int increment);
@Override
BulkStringRedisContent touch();
@Override
BulkStringRedisContent touch(Object hint);
} }

View File

@ -35,6 +35,50 @@ public class DefaultBulkStringRedisContent extends DefaultByteBufHolder implemen
super(content); super(content);
} }
@Override
public BulkStringRedisContent copy() {
return (BulkStringRedisContent) super.copy();
}
@Override
public BulkStringRedisContent duplicate() {
return (BulkStringRedisContent) super.duplicate();
}
@Override
public BulkStringRedisContent retainedDuplicate() {
return (BulkStringRedisContent) super.retainedDuplicate();
}
@Override
public BulkStringRedisContent replace(ByteBuf content) {
return new DefaultBulkStringRedisContent(content);
}
@Override
public BulkStringRedisContent retain() {
super.retain();
return this;
}
@Override
public BulkStringRedisContent retain(int increment) {
super.retain(increment);
return this;
}
@Override
public BulkStringRedisContent touch() {
super.touch();
return this;
}
@Override
public BulkStringRedisContent touch(Object hint) {
super.touch(hint);
return this;
}
@Override @Override
public String toString() { public String toString() {
return new StringBuilder(StringUtil.simpleClassName(this)) return new StringBuilder(StringUtil.simpleClassName(this))

View File

@ -32,4 +32,48 @@ public final class DefaultLastBulkStringRedisContent extends DefaultBulkStringRe
public DefaultLastBulkStringRedisContent(ByteBuf content) { public DefaultLastBulkStringRedisContent(ByteBuf content) {
super(content); super(content);
} }
@Override
public LastBulkStringRedisContent copy() {
return (LastBulkStringRedisContent) super.copy();
}
@Override
public LastBulkStringRedisContent duplicate() {
return (LastBulkStringRedisContent) super.duplicate();
}
@Override
public LastBulkStringRedisContent retainedDuplicate() {
return (LastBulkStringRedisContent) super.retainedDuplicate();
}
@Override
public LastBulkStringRedisContent replace(ByteBuf content) {
return new DefaultLastBulkStringRedisContent(content);
}
@Override
public LastBulkStringRedisContent retain() {
super.retain();
return this;
}
@Override
public LastBulkStringRedisContent retain(int increment) {
super.retain(increment);
return this;
}
@Override
public LastBulkStringRedisContent touch() {
super.touch();
return this;
}
@Override
public LastBulkStringRedisContent touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -84,6 +84,11 @@ public class FullBulkStringRedisMessage extends DefaultByteBufHolder implements
return this; return this;
} }
@Override
public FullBulkStringRedisMessage retainedDuplicate() {
return this;
}
@Override @Override
public int refCnt() { public int refCnt() {
return 1; return 1;
@ -131,7 +136,7 @@ public class FullBulkStringRedisMessage extends DefaultByteBufHolder implements
@Override @Override
public FullBulkStringRedisMessage copy() { public FullBulkStringRedisMessage copy() {
return EMPTY_INSTANCE; return this;
} }
@Override @Override
@ -139,6 +144,11 @@ public class FullBulkStringRedisMessage extends DefaultByteBufHolder implements
return this; return this;
} }
@Override
public FullBulkStringRedisMessage retainedDuplicate() {
return this;
}
@Override @Override
public int refCnt() { public int refCnt() {
return 1; return 1;
@ -174,4 +184,48 @@ public class FullBulkStringRedisMessage extends DefaultByteBufHolder implements
return false; return false;
} }
}; };
@Override
public FullBulkStringRedisMessage copy() {
return (FullBulkStringRedisMessage) super.copy();
}
@Override
public FullBulkStringRedisMessage duplicate() {
return (FullBulkStringRedisMessage) super.duplicate();
}
@Override
public FullBulkStringRedisMessage retainedDuplicate() {
return (FullBulkStringRedisMessage) super.retainedDuplicate();
}
@Override
public FullBulkStringRedisMessage replace(ByteBuf content) {
return new FullBulkStringRedisMessage(content);
}
@Override
public FullBulkStringRedisMessage retain() {
super.retain();
return this;
}
@Override
public FullBulkStringRedisMessage retain(int increment) {
super.retain(increment);
return this;
}
@Override
public FullBulkStringRedisMessage touch() {
super.touch();
return this;
}
@Override
public FullBulkStringRedisMessage touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -16,7 +16,6 @@
package io.netty.handler.codec.redis; package io.netty.handler.codec.redis;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
@ -37,17 +36,32 @@ public interface LastBulkStringRedisContent extends BulkStringRedisContent {
} }
@Override @Override
public ByteBufHolder copy() { public LastBulkStringRedisContent copy() {
return this; return this;
} }
@Override @Override
public ByteBufHolder retain(int increment) { public LastBulkStringRedisContent duplicate() {
return this; return this;
} }
@Override @Override
public ByteBufHolder retain() { public LastBulkStringRedisContent retainedDuplicate() {
return this;
}
@Override
public LastBulkStringRedisContent replace(ByteBuf content) {
return new DefaultLastBulkStringRedisContent(content);
}
@Override
public LastBulkStringRedisContent retain(int increment) {
return this;
}
@Override
public LastBulkStringRedisContent retain() {
return this; return this;
} }
@ -57,12 +71,12 @@ public interface LastBulkStringRedisContent extends BulkStringRedisContent {
} }
@Override @Override
public ByteBufHolder touch() { public LastBulkStringRedisContent touch() {
return this; return this;
} }
@Override @Override
public ByteBufHolder touch(Object hint) { public LastBulkStringRedisContent touch(Object hint) {
return this; return this;
} }
@ -75,10 +89,29 @@ public interface LastBulkStringRedisContent extends BulkStringRedisContent {
public boolean release(int decrement) { public boolean release(int decrement) {
return false; return false;
} }
};
@Override @Override
public ByteBufHolder duplicate() { LastBulkStringRedisContent copy();
return this;
} @Override
}; LastBulkStringRedisContent duplicate();
@Override
LastBulkStringRedisContent retainedDuplicate();
@Override
LastBulkStringRedisContent replace(ByteBuf content);
@Override
LastBulkStringRedisContent retain();
@Override
LastBulkStringRedisContent retain(int increment);
@Override
LastBulkStringRedisContent touch();
@Override
LastBulkStringRedisContent touch(Object hint);
} }

View File

@ -33,34 +33,44 @@ public final class DefaultLastSmtpContent extends DefaultSmtpContent implements
@Override @Override
public LastSmtpContent copy() { public LastSmtpContent copy() {
return new DefaultLastSmtpContent(content().copy()); return (LastSmtpContent) super.copy();
} }
@Override @Override
public LastSmtpContent duplicate() { public LastSmtpContent duplicate() {
return new DefaultLastSmtpContent(content().duplicate()); return (LastSmtpContent) super.duplicate();
} }
@Override @Override
public LastSmtpContent retain() { public LastSmtpContent retainedDuplicate() {
return (LastSmtpContent) super.retainedDuplicate();
}
@Override
public LastSmtpContent replace(ByteBuf content) {
return new DefaultLastSmtpContent(content);
}
@Override
public DefaultLastSmtpContent retain() {
super.retain(); super.retain();
return this; return this;
} }
@Override @Override
public LastSmtpContent retain(int increment) { public DefaultLastSmtpContent retain(int increment) {
super.retain(increment); super.retain(increment);
return this; return this;
} }
@Override @Override
public LastSmtpContent touch() { public DefaultLastSmtpContent touch() {
super.touch(); super.touch();
return this; return this;
} }
@Override @Override
public LastSmtpContent touch(Object hint) { public DefaultLastSmtpContent touch(Object hint) {
super.touch(hint); super.touch(hint);
return this; return this;
} }

View File

@ -34,12 +34,22 @@ public class DefaultSmtpContent extends DefaultByteBufHolder implements SmtpCont
@Override @Override
public SmtpContent copy() { public SmtpContent copy() {
return new DefaultSmtpContent(content().copy()); return (SmtpContent) super.copy();
} }
@Override @Override
public SmtpContent duplicate() { public SmtpContent duplicate() {
return new DefaultSmtpContent(content().duplicate()); return (SmtpContent) super.duplicate();
}
@Override
public SmtpContent retainedDuplicate() {
return (SmtpContent) super.retainedDuplicate();
}
@Override
public SmtpContent replace(ByteBuf content) {
return new DefaultSmtpContent(content);
} }
@Override @Override

View File

@ -42,6 +42,16 @@ public interface LastSmtpContent extends SmtpContent {
return this; return this;
} }
@Override
public LastSmtpContent retainedDuplicate() {
return this;
}
@Override
public LastSmtpContent replace(ByteBuf content) {
return new DefaultLastSmtpContent(content);
}
@Override @Override
public LastSmtpContent retain() { public LastSmtpContent retain() {
return this; return this;
@ -89,6 +99,12 @@ public interface LastSmtpContent extends SmtpContent {
@Override @Override
LastSmtpContent duplicate(); LastSmtpContent duplicate();
@Override
LastSmtpContent retainedDuplicate();
@Override
LastSmtpContent replace(ByteBuf content);
@Override @Override
LastSmtpContent retain(); LastSmtpContent retain();

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.codec.smtp; package io.netty.handler.codec.smtp;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder; import io.netty.buffer.ByteBufHolder;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
@ -32,6 +33,12 @@ public interface SmtpContent extends ByteBufHolder {
@Override @Override
SmtpContent duplicate(); SmtpContent duplicate();
@Override
SmtpContent retainedDuplicate();
@Override
SmtpContent replace(ByteBuf content);
@Override @Override
SmtpContent retain(); SmtpContent retain();

View File

@ -76,7 +76,7 @@ public final class SmtpRequestEncoder extends MessageToMessageEncoder<Object> {
final ByteBuf content = ((SmtpContent) msg).content(); final ByteBuf content = ((SmtpContent) msg).content();
out.add(content.retain()); out.add(content.retain());
if (msg instanceof LastSmtpContent) { if (msg instanceof LastSmtpContent) {
out.add(DOT_CRLF_BUFFER.duplicate().retain()); out.add(DOT_CRLF_BUFFER.retainedDuplicate());
contentExpected = false; contentExpected = false;
} }
} }

View File

@ -64,7 +64,7 @@ public class Socks4ClientDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readSlice(readableBytes).retain()); out.add(in.readRetainedSlice(readableBytes));
} }
break; break;
} }

View File

@ -85,7 +85,7 @@ public class Socks4ServerDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readSlice(readableBytes).retain()); out.add(in.readRetainedSlice(readableBytes));
} }
break; break;
} }

View File

@ -78,7 +78,7 @@ public class Socks5CommandRequestDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readSlice(readableBytes).retain()); out.add(in.readRetainedSlice(readableBytes));
} }
break; break;
} }

View File

@ -77,7 +77,7 @@ public class Socks5CommandResponseDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readSlice(readableBytes).retain()); out.add(in.readRetainedSlice(readableBytes));
} }
break; break;
} }

View File

@ -71,7 +71,7 @@ public class Socks5InitialRequestDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readSlice(readableBytes).retain()); out.add(in.readRetainedSlice(readableBytes));
} }
break; break;
} }

View File

@ -62,7 +62,7 @@ public class Socks5InitialResponseDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readSlice(readableBytes).retain()); out.add(in.readRetainedSlice(readableBytes));
} }
break; break;
} }

View File

@ -69,7 +69,7 @@ public class Socks5PasswordAuthRequestDecoder extends ReplayingDecoder<State> {
case SUCCESS: { case SUCCESS: {
int readableBytes = actualReadableBytes(); int readableBytes = actualReadableBytes();
if (readableBytes > 0) { if (readableBytes > 0) {
out.add(in.readSlice(readableBytes).retain()); out.add(in.readRetainedSlice(readableBytes));
} }
break; break;
} }

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