migrate java8: use lambda and method reference (#8781)
Motivation: We can use lambdas now as we use Java8. Modification: use lambda function for all package, #8751 only migrate transport package. Result: Code cleanup.
This commit is contained in:
parent
185efa5b7c
commit
6222101924
|
@ -28,109 +28,59 @@ public interface ByteBufProcessor extends ByteProcessor {
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_NUL}.
|
* @deprecated Use {@link ByteProcessor#FIND_NUL}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_NUL = new ByteBufProcessor() {
|
ByteBufProcessor FIND_NUL = value -> value != 0;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value != 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_NON_NUL}.
|
* @deprecated Use {@link ByteProcessor#FIND_NON_NUL}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_NON_NUL = new ByteBufProcessor() {
|
ByteBufProcessor FIND_NON_NUL = value -> value == 0;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value == 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_CR}.
|
* @deprecated Use {@link ByteProcessor#FIND_CR}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_CR = new ByteBufProcessor() {
|
ByteBufProcessor FIND_CR = value -> value != '\r';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value != '\r';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_NON_CR}.
|
* @deprecated Use {@link ByteProcessor#FIND_NON_CR}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_NON_CR = new ByteBufProcessor() {
|
ByteBufProcessor FIND_NON_CR = value -> value == '\r';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value == '\r';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_LF}.
|
* @deprecated Use {@link ByteProcessor#FIND_LF}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_LF = new ByteBufProcessor() {
|
ByteBufProcessor FIND_LF = value -> value != '\n';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value != '\n';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_NON_LF}.
|
* @deprecated Use {@link ByteProcessor#FIND_NON_LF}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_NON_LF = new ByteBufProcessor() {
|
ByteBufProcessor FIND_NON_LF = value -> value == '\n';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value == '\n';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_CRLF}.
|
* @deprecated Use {@link ByteProcessor#FIND_CRLF}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_CRLF = new ByteBufProcessor() {
|
ByteBufProcessor FIND_CRLF = value -> value != '\r' && value != '\n';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value != '\r' && value != '\n';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_NON_CRLF}.
|
* @deprecated Use {@link ByteProcessor#FIND_NON_CRLF}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_NON_CRLF = new ByteBufProcessor() {
|
ByteBufProcessor FIND_NON_CRLF = value -> value == '\r' || value == '\n';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value == '\r' || value == '\n';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_LINEAR_WHITESPACE}.
|
* @deprecated Use {@link ByteProcessor#FIND_LINEAR_WHITESPACE}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_LINEAR_WHITESPACE = new ByteBufProcessor() {
|
ByteBufProcessor FIND_LINEAR_WHITESPACE = value -> value != ' ' && value != '\t';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value != ' ' && value != '\t';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link ByteProcessor#FIND_NON_LINEAR_WHITESPACE}.
|
* @deprecated Use {@link ByteProcessor#FIND_NON_LINEAR_WHITESPACE}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ByteBufProcessor FIND_NON_LINEAR_WHITESPACE = new ByteBufProcessor() {
|
ByteBufProcessor FIND_NON_LINEAR_WHITESPACE = value -> value == ' ' || value == '\t';
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return value == ' ' || value == '\t';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1254,12 +1254,7 @@ public final class ByteBufUtil {
|
||||||
/**
|
/**
|
||||||
* Aborts on a byte which is not a valid ASCII character.
|
* Aborts on a byte which is not a valid ASCII character.
|
||||||
*/
|
*/
|
||||||
private static final ByteProcessor FIND_NON_ASCII = new ByteProcessor() {
|
private static final ByteProcessor FIND_NON_ASCII = value -> value >= 0;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) {
|
|
||||||
return value >= 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
|
* Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
|
||||||
|
|
|
@ -2089,16 +2089,13 @@ public abstract class AbstractByteBufTest {
|
||||||
final AtomicReference<Throwable> errorRef = new AtomicReference<>();
|
final AtomicReference<Throwable> errorRef = new AtomicReference<>();
|
||||||
List<Thread> threads = new ArrayList<>();
|
List<Thread> threads = new ArrayList<>();
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
Thread thread = new Thread(new Runnable() {
|
Thread thread = new Thread(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
while (errorRef.get() == null && counter.decrementAndGet() > 0) {
|
||||||
try {
|
assertEquals("Hello, World!", buffer.toString(CharsetUtil.ISO_8859_1));
|
||||||
while (errorRef.get() == null && counter.decrementAndGet() > 0) {
|
|
||||||
assertEquals("Hello, World!", buffer.toString(CharsetUtil.ISO_8859_1));
|
|
||||||
}
|
|
||||||
} catch (Throwable cause) {
|
|
||||||
errorRef.compareAndSet(null, cause);
|
|
||||||
}
|
}
|
||||||
|
} catch (Throwable cause) {
|
||||||
|
errorRef.compareAndSet(null, cause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
threads.add(thread);
|
threads.add(thread);
|
||||||
|
@ -2358,34 +2355,31 @@ public abstract class AbstractByteBufTest {
|
||||||
final CountDownLatch latch = new CountDownLatch(60000);
|
final CountDownLatch latch = new CountDownLatch(60000);
|
||||||
final CyclicBarrier barrier = new CyclicBarrier(11);
|
final CyclicBarrier barrier = new CyclicBarrier(11);
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
new Thread(new Runnable() {
|
new Thread(() -> {
|
||||||
@Override
|
while (latch.getCount() > 0) {
|
||||||
public void run() {
|
ByteBuf buf;
|
||||||
while (latch.getCount() > 0) {
|
if (slice) {
|
||||||
ByteBuf buf;
|
buf = buffer.slice();
|
||||||
if (slice) {
|
} else {
|
||||||
buf = buffer.slice();
|
buf = buffer.duplicate();
|
||||||
} else {
|
}
|
||||||
buf = buffer.duplicate();
|
TestGatheringByteChannel channel = new TestGatheringByteChannel();
|
||||||
}
|
|
||||||
TestGatheringByteChannel channel = new TestGatheringByteChannel();
|
|
||||||
|
|
||||||
while (buf.isReadable()) {
|
while (buf.isReadable()) {
|
||||||
try {
|
try {
|
||||||
buf.readBytes(channel, buf.readableBytes());
|
buf.readBytes(channel, buf.readableBytes());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Never happens
|
// Never happens
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assertArrayEquals(bytes, channel.writtenBytes());
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
barrier.await();
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
|
assertArrayEquals(bytes, channel.writtenBytes());
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
barrier.await();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
@ -2413,34 +2407,31 @@ public abstract class AbstractByteBufTest {
|
||||||
final CountDownLatch latch = new CountDownLatch(60000);
|
final CountDownLatch latch = new CountDownLatch(60000);
|
||||||
final CyclicBarrier barrier = new CyclicBarrier(11);
|
final CyclicBarrier barrier = new CyclicBarrier(11);
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
new Thread(new Runnable() {
|
new Thread(() -> {
|
||||||
@Override
|
while (latch.getCount() > 0) {
|
||||||
public void run() {
|
ByteBuf buf;
|
||||||
while (latch.getCount() > 0) {
|
if (slice) {
|
||||||
ByteBuf buf;
|
buf = buffer.slice();
|
||||||
if (slice) {
|
} else {
|
||||||
buf = buffer.slice();
|
buf = buffer.duplicate();
|
||||||
} else {
|
}
|
||||||
buf = buffer.duplicate();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
}
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
while (buf.isReadable()) {
|
while (buf.isReadable()) {
|
||||||
try {
|
try {
|
||||||
buf.readBytes(out, buf.readableBytes());
|
buf.readBytes(out, buf.readableBytes());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Never happens
|
// Never happens
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assertArrayEquals(bytes, out.toByteArray());
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
barrier.await();
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
|
assertArrayEquals(bytes, out.toByteArray());
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
barrier.await();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
@ -2469,33 +2460,30 @@ public abstract class AbstractByteBufTest {
|
||||||
final CountDownLatch latch = new CountDownLatch(60000);
|
final CountDownLatch latch = new CountDownLatch(60000);
|
||||||
final CyclicBarrier barrier = new CyclicBarrier(11);
|
final CyclicBarrier barrier = new CyclicBarrier(11);
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
new Thread(new Runnable() {
|
new Thread(() -> {
|
||||||
@Override
|
while (cause.get() == null && latch.getCount() > 0) {
|
||||||
public void run() {
|
ByteBuf buf;
|
||||||
while (cause.get() == null && latch.getCount() > 0) {
|
if (slice) {
|
||||||
ByteBuf buf;
|
buf = buffer.slice();
|
||||||
if (slice) {
|
} else {
|
||||||
buf = buffer.slice();
|
buf = buffer.duplicate();
|
||||||
} else {
|
|
||||||
buf = buffer.duplicate();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] array = new byte[8];
|
|
||||||
buf.readBytes(array);
|
|
||||||
|
|
||||||
assertArrayEquals(bytes, array);
|
|
||||||
|
|
||||||
Arrays.fill(array, (byte) 0);
|
|
||||||
buf.getBytes(0, array);
|
|
||||||
assertArrayEquals(bytes, array);
|
|
||||||
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
barrier.await();
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] array = new byte[8];
|
||||||
|
buf.readBytes(array);
|
||||||
|
|
||||||
|
assertArrayEquals(bytes, array);
|
||||||
|
|
||||||
|
Arrays.fill(array, (byte) 0);
|
||||||
|
buf.getBytes(0, array);
|
||||||
|
assertArrayEquals(bytes, array);
|
||||||
|
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
barrier.await();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
@ -4643,30 +4631,24 @@ public abstract class AbstractByteBufTest {
|
||||||
final ByteBuf buffer = newBuffer(4);
|
final ByteBuf buffer = newBuffer(4);
|
||||||
assertEquals(1, buffer.refCnt());
|
assertEquals(1, buffer.refCnt());
|
||||||
final AtomicInteger cnt = new AtomicInteger(Integer.MAX_VALUE);
|
final AtomicInteger cnt = new AtomicInteger(Integer.MAX_VALUE);
|
||||||
Thread t1 = new Thread(new Runnable() {
|
Thread t1 = new Thread(() -> {
|
||||||
@Override
|
boolean released;
|
||||||
public void run() {
|
if (parameter) {
|
||||||
boolean released;
|
released = buffer.release(buffer.refCnt());
|
||||||
if (parameter) {
|
} else {
|
||||||
released = buffer.release(buffer.refCnt());
|
released = buffer.release();
|
||||||
} else {
|
}
|
||||||
released = buffer.release();
|
assertTrue(released);
|
||||||
}
|
Thread t2 = new Thread(() -> {
|
||||||
assertTrue(released);
|
cnt.set(buffer.refCnt());
|
||||||
Thread t2 = new Thread(new Runnable() {
|
latch.countDown();
|
||||||
@Override
|
});
|
||||||
public void run() {
|
t2.start();
|
||||||
cnt.set(buffer.refCnt());
|
try {
|
||||||
latch.countDown();
|
// Keep Thread alive a bit so the ThreadLocal caches are not freed
|
||||||
}
|
innerLatch.await();
|
||||||
});
|
} catch (InterruptedException ignore) {
|
||||||
t2.start();
|
// ignore
|
||||||
try {
|
|
||||||
// Keep Thread alive a bit so the ThreadLocal caches are not freed
|
|
||||||
innerLatch.await();
|
|
||||||
} catch (InterruptedException ignore) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
t1.start();
|
t1.start();
|
||||||
|
|
|
@ -680,16 +680,13 @@ public class ByteBufUtilTest {
|
||||||
final AtomicReference<Throwable> errorRef = new AtomicReference<>();
|
final AtomicReference<Throwable> errorRef = new AtomicReference<>();
|
||||||
List<Thread> threads = new ArrayList<>();
|
List<Thread> threads = new ArrayList<>();
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
Thread thread = new Thread(new Runnable() {
|
Thread thread = new Thread(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
while (errorRef.get() == null && counter.decrementAndGet() > 0) {
|
||||||
try {
|
assertTrue(ByteBufUtil.isText(buffer, CharsetUtil.ISO_8859_1));
|
||||||
while (errorRef.get() == null && counter.decrementAndGet() > 0) {
|
|
||||||
assertTrue(ByteBufUtil.isText(buffer, CharsetUtil.ISO_8859_1));
|
|
||||||
}
|
|
||||||
} catch (Throwable cause) {
|
|
||||||
errorRef.compareAndSet(null, cause);
|
|
||||||
}
|
}
|
||||||
|
} catch (Throwable cause) {
|
||||||
|
errorRef.compareAndSet(null, cause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
threads.add(thread);
|
threads.add(thread);
|
||||||
|
|
|
@ -257,23 +257,20 @@ public class PooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest<Poo
|
||||||
|
|
||||||
final AtomicBoolean threadCachesCreated = new AtomicBoolean(true);
|
final AtomicBoolean threadCachesCreated = new AtomicBoolean(true);
|
||||||
|
|
||||||
final Runnable task = new Runnable() {
|
final Runnable task = () -> {
|
||||||
@Override
|
ByteBuf buf = allocator.newHeapBuffer(1024, 1024);
|
||||||
public void run() {
|
for (int i = 0; i < buf.capacity(); i++) {
|
||||||
ByteBuf buf = allocator.newHeapBuffer(1024, 1024);
|
buf.writeByte(0);
|
||||||
for (int i = 0; i < buf.capacity(); i++) {
|
|
||||||
buf.writeByte(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that thread caches are actually created,
|
|
||||||
// so that down below we are not testing for zero
|
|
||||||
// thread caches without any of them ever having been initialized.
|
|
||||||
if (allocator.metric().numThreadLocalCaches() == 0) {
|
|
||||||
threadCachesCreated.set(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure that thread caches are actually created,
|
||||||
|
// so that down below we are not testing for zero
|
||||||
|
// thread caches without any of them ever having been initialized.
|
||||||
|
if (allocator.metric().numThreadLocalCaches() == 0) {
|
||||||
|
threadCachesCreated.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.release();
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < numArenas; i++) {
|
for (int i = 0; i < numArenas; i++) {
|
||||||
|
@ -368,39 +365,32 @@ public class PooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest<Poo
|
||||||
throws InterruptedException {
|
throws InterruptedException {
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final CountDownLatch cacheLatch = new CountDownLatch(1);
|
final CountDownLatch cacheLatch = new CountDownLatch(1);
|
||||||
final Thread t = new FastThreadLocalThread(new Runnable() {
|
final Thread t = new FastThreadLocalThread(() -> {
|
||||||
|
ByteBuf buf = allocator.newHeapBuffer(1024, 1024);
|
||||||
|
|
||||||
@Override
|
// Countdown the latch after we allocated a buffer. At this point the cache must exists.
|
||||||
public void run() {
|
cacheLatch.countDown();
|
||||||
ByteBuf buf = allocator.newHeapBuffer(1024, 1024);
|
|
||||||
|
|
||||||
// Countdown the latch after we allocated a buffer. At this point the cache must exists.
|
buf.writeZero(buf.capacity());
|
||||||
cacheLatch.countDown();
|
|
||||||
|
|
||||||
buf.writeZero(buf.capacity());
|
try {
|
||||||
|
latch.await();
|
||||||
try {
|
} catch (InterruptedException e) {
|
||||||
latch.await();
|
throw new IllegalStateException(e);
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.release();
|
|
||||||
|
|
||||||
FastThreadLocal.removeAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf.release();
|
||||||
|
|
||||||
|
FastThreadLocal.removeAll();
|
||||||
});
|
});
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
// Wait until we allocated a buffer and so be sure the thread was started and the cache exists.
|
// Wait until we allocated a buffer and so be sure the thread was started and the cache exists.
|
||||||
cacheLatch.await();
|
cacheLatch.await();
|
||||||
|
|
||||||
return new ThreadCache() {
|
return () -> {
|
||||||
@Override
|
latch.countDown();
|
||||||
public void destroy() throws InterruptedException {
|
t.join();
|
||||||
latch.countDown();
|
|
||||||
t.join();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,24 +57,14 @@ public class CombinedHttpHeaders extends DefaultHttpHeaders {
|
||||||
|
|
||||||
private CsvValueEscaper<Object> objectEscaper() {
|
private CsvValueEscaper<Object> objectEscaper() {
|
||||||
if (objectEscaper == null) {
|
if (objectEscaper == null) {
|
||||||
objectEscaper = new CsvValueEscaper<Object>() {
|
objectEscaper = value -> StringUtil.escapeCsv(valueConverter().convertObject(value), true);
|
||||||
@Override
|
|
||||||
public CharSequence escape(Object value) {
|
|
||||||
return StringUtil.escapeCsv(valueConverter().convertObject(value), true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return objectEscaper;
|
return objectEscaper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CsvValueEscaper<CharSequence> charSequenceEscaper() {
|
private CsvValueEscaper<CharSequence> charSequenceEscaper() {
|
||||||
if (charSequenceEscaper == null) {
|
if (charSequenceEscaper == null) {
|
||||||
charSequenceEscaper = new CsvValueEscaper<CharSequence>() {
|
charSequenceEscaper = value -> StringUtil.escapeCsv(value, true);
|
||||||
@Override
|
|
||||||
public CharSequence escape(CharSequence value) {
|
|
||||||
return StringUtil.escapeCsv(value, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return charSequenceEscaper;
|
return charSequenceEscaper;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,30 +44,24 @@ import static io.netty.util.AsciiString.CASE_SENSITIVE_HASHER;
|
||||||
*/
|
*/
|
||||||
public class DefaultHttpHeaders extends HttpHeaders {
|
public class DefaultHttpHeaders extends HttpHeaders {
|
||||||
private static final int HIGHEST_INVALID_VALUE_CHAR_MASK = ~15;
|
private static final int HIGHEST_INVALID_VALUE_CHAR_MASK = ~15;
|
||||||
private static final ByteProcessor HEADER_NAME_VALIDATOR = new ByteProcessor() {
|
private static final ByteProcessor HEADER_NAME_VALIDATOR = value -> {
|
||||||
@Override
|
validateHeaderNameElement(value);
|
||||||
public boolean process(byte value) throws Exception {
|
return true;
|
||||||
validateHeaderNameElement(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
static final NameValidator<CharSequence> HttpNameValidator = new NameValidator<CharSequence>() {
|
static final NameValidator<CharSequence> HttpNameValidator = name -> {
|
||||||
@Override
|
if (name == null || name.length() == 0) {
|
||||||
public void validateName(CharSequence name) {
|
throw new IllegalArgumentException("empty headers are not allowed [" + name + "]");
|
||||||
if (name == null || name.length() == 0) {
|
}
|
||||||
throw new IllegalArgumentException("empty headers are not allowed [" + name + "]");
|
if (name instanceof AsciiString) {
|
||||||
|
try {
|
||||||
|
((AsciiString) name).forEachByte(HEADER_NAME_VALIDATOR);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
}
|
}
|
||||||
if (name instanceof AsciiString) {
|
} else {
|
||||||
try {
|
// Go through each character in the name
|
||||||
((AsciiString) name).forEachByte(HEADER_NAME_VALIDATOR);
|
for (int index = 0; index < name.length(); ++index) {
|
||||||
} catch (Exception e) {
|
validateHeaderNameElement(name.charAt(index));
|
||||||
PlatformDependent.throwException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Go through each character in the name
|
|
||||||
for (int index = 0; index < name.length(); ++index) {
|
|
||||||
validateHeaderNameElement(name.charAt(index));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -115,15 +115,12 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class TrailingHttpHeaders extends DefaultHttpHeaders {
|
private static final class TrailingHttpHeaders extends DefaultHttpHeaders {
|
||||||
private static final NameValidator<CharSequence> TrailerNameValidator = new NameValidator<CharSequence>() {
|
private static final NameValidator<CharSequence> TrailerNameValidator = name -> {
|
||||||
@Override
|
DefaultHttpHeaders.HttpNameValidator.validateName(name);
|
||||||
public void validateName(CharSequence name) {
|
if (HttpHeaderNames.CONTENT_LENGTH.contentEqualsIgnoreCase(name)
|
||||||
DefaultHttpHeaders.HttpNameValidator.validateName(name);
|
|| HttpHeaderNames.TRANSFER_ENCODING.contentEqualsIgnoreCase(name)
|
||||||
if (HttpHeaderNames.CONTENT_LENGTH.contentEqualsIgnoreCase(name)
|
|| HttpHeaderNames.TRAILER.contentEqualsIgnoreCase(name)) {
|
||||||
|| HttpHeaderNames.TRANSFER_ENCODING.contentEqualsIgnoreCase(name)
|
throw new IllegalArgumentException("prohibited trailing header: " + name);
|
||||||
|| HttpHeaderNames.TRAILER.contentEqualsIgnoreCase(name)) {
|
|
||||||
throw new IllegalArgumentException("prohibited trailing header: " + name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -251,23 +251,17 @@ public class HttpObjectAggregator
|
||||||
if (oversized instanceof FullHttpMessage ||
|
if (oversized instanceof FullHttpMessage ||
|
||||||
!HttpUtil.is100ContinueExpected(oversized) && !HttpUtil.isKeepAlive(oversized)) {
|
!HttpUtil.is100ContinueExpected(oversized) && !HttpUtil.isKeepAlive(oversized)) {
|
||||||
ChannelFuture future = ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate());
|
ChannelFuture future = ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate());
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future1 -> {
|
||||||
@Override
|
if (!future1.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
logger.debug("Failed to send a 413 Request Entity Too Large.", future1.cause());
|
||||||
if (!future.isSuccess()) {
|
|
||||||
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
|
|
||||||
}
|
|
||||||
ctx.close();
|
|
||||||
}
|
}
|
||||||
|
ctx.close();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener(new ChannelFutureListener() {
|
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
|
||||||
if (!future.isSuccess()) {
|
ctx.close();
|
||||||
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,26 +91,23 @@ public final class ClientCookieEncoder extends CookieEncoder {
|
||||||
* Sort cookies into decreasing order of path length, breaking ties by sorting into increasing chronological
|
* Sort cookies into decreasing order of path length, breaking ties by sorting into increasing chronological
|
||||||
* order of creation time, as recommended by RFC 6265.
|
* order of creation time, as recommended by RFC 6265.
|
||||||
*/
|
*/
|
||||||
private static final Comparator<Cookie> COOKIE_COMPARATOR = new Comparator<Cookie>() {
|
private static final Comparator<Cookie> COOKIE_COMPARATOR = (c1, c2) -> {
|
||||||
@Override
|
String path1 = c1.path();
|
||||||
public int compare(Cookie c1, Cookie c2) {
|
String path2 = c2.path();
|
||||||
String path1 = c1.path();
|
// Cookies with unspecified path default to the path of the request. We don't
|
||||||
String path2 = c2.path();
|
// know the request path here, but we assume that the length of an unspecified
|
||||||
// Cookies with unspecified path default to the path of the request. We don't
|
// path is longer than any specified path (i.e. pathless cookies come first),
|
||||||
// know the request path here, but we assume that the length of an unspecified
|
// because setting cookies with a path longer than the request path is of
|
||||||
// path is longer than any specified path (i.e. pathless cookies come first),
|
// limited use.
|
||||||
// because setting cookies with a path longer than the request path is of
|
int len1 = path1 == null ? Integer.MAX_VALUE : path1.length();
|
||||||
// limited use.
|
int len2 = path2 == null ? Integer.MAX_VALUE : path2.length();
|
||||||
int len1 = path1 == null ? Integer.MAX_VALUE : path1.length();
|
int diff = len2 - len1;
|
||||||
int len2 = path2 == null ? Integer.MAX_VALUE : path2.length();
|
if (diff != 0) {
|
||||||
int diff = len2 - len1;
|
return diff;
|
||||||
if (diff != 0) {
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
// Rely on Java's sort stability to retain creation order in cases where
|
|
||||||
// cookies have same path length.
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
// Rely on Java's sort stability to retain creation order in cases where
|
||||||
|
// cookies have same path length.
|
||||||
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -174,26 +174,23 @@ public abstract class WebSocketClientHandshaker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.writeAndFlush(request).addListener(new ChannelFutureListener() {
|
channel.writeAndFlush(request).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) {
|
ChannelPipeline p = future.channel().pipeline();
|
||||||
if (future.isSuccess()) {
|
ChannelHandlerContext ctx = p.context(HttpRequestEncoder.class);
|
||||||
ChannelPipeline p = future.channel().pipeline();
|
if (ctx == null) {
|
||||||
ChannelHandlerContext ctx = p.context(HttpRequestEncoder.class);
|
ctx = p.context(HttpClientCodec.class);
|
||||||
if (ctx == null) {
|
|
||||||
ctx = p.context(HttpClientCodec.class);
|
|
||||||
}
|
|
||||||
if (ctx == null) {
|
|
||||||
promise.setFailure(new IllegalStateException("ChannelPipeline does not contain " +
|
|
||||||
"a HttpRequestEncoder or HttpClientCodec"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p.addAfter(ctx.name(), "ws-encoder", newWebSocketEncoder());
|
|
||||||
|
|
||||||
promise.setSuccess();
|
|
||||||
} else {
|
|
||||||
promise.setFailure(future.cause());
|
|
||||||
}
|
}
|
||||||
|
if (ctx == null) {
|
||||||
|
promise.setFailure(new IllegalStateException("ChannelPipeline does not contain " +
|
||||||
|
"a HttpRequestEncoder or HttpClientCodec"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p.addAfter(ctx.name(), "ws-encoder", newWebSocketEncoder());
|
||||||
|
|
||||||
|
promise.setSuccess();
|
||||||
|
} else {
|
||||||
|
promise.setFailure(future.cause());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
|
@ -274,12 +271,7 @@ public abstract class WebSocketClientHandshaker {
|
||||||
// Delay the removal of the decoder so the user can setup the pipeline if needed to handle
|
// Delay the removal of the decoder so the user can setup the pipeline if needed to handle
|
||||||
// WebSocketFrame messages.
|
// WebSocketFrame messages.
|
||||||
// See https://github.com/netty/netty/issues/4533
|
// See https://github.com/netty/netty/issues/4533
|
||||||
channel.eventLoop().execute(new Runnable() {
|
channel.eventLoop().execute(() -> p.remove(codec));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
p.remove(codec);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
if (p.get(HttpRequestEncoder.class) != null) {
|
if (p.get(HttpRequestEncoder.class) != null) {
|
||||||
// Remove the encoder part of the codec as the user may start writing frames after this method returns.
|
// Remove the encoder part of the codec as the user may start writing frames after this method returns.
|
||||||
|
@ -291,12 +283,7 @@ public abstract class WebSocketClientHandshaker {
|
||||||
// Delay the removal of the decoder so the user can setup the pipeline if needed to handle
|
// Delay the removal of the decoder so the user can setup the pipeline if needed to handle
|
||||||
// WebSocketFrame messages.
|
// WebSocketFrame messages.
|
||||||
// See https://github.com/netty/netty/issues/4533
|
// See https://github.com/netty/netty/issues/4533
|
||||||
channel.eventLoop().execute(new Runnable() {
|
channel.eventLoop().execute(() -> p.remove(context.handler()));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
p.remove(context.handler());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,15 +31,12 @@ class WebSocketClientProtocolHandshakeHandler extends ChannelInboundHandlerAdapt
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
||||||
super.channelActive(ctx);
|
super.channelActive(ctx);
|
||||||
handshaker.handshake(ctx.channel()).addListener(new ChannelFutureListener() {
|
handshaker.handshake(ctx.channel()).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
ctx.fireExceptionCaught(future.cause());
|
||||||
if (!future.isSuccess()) {
|
} else {
|
||||||
ctx.fireExceptionCaught(future.cause());
|
ctx.fireUserEventTriggered(
|
||||||
} else {
|
WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_ISSUED);
|
||||||
ctx.fireUserEventTriggered(
|
|
||||||
WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_ISSUED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,16 +191,13 @@ public abstract class WebSocketServerHandshaker {
|
||||||
encoderName = p.context(HttpResponseEncoder.class).name();
|
encoderName = p.context(HttpResponseEncoder.class).name();
|
||||||
p.addBefore(encoderName, "wsencoder", newWebSocketEncoder());
|
p.addBefore(encoderName, "wsencoder", newWebSocketEncoder());
|
||||||
}
|
}
|
||||||
channel.writeAndFlush(response).addListener(new ChannelFutureListener() {
|
channel.writeAndFlush(response).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
ChannelPipeline p1 = future.channel().pipeline();
|
||||||
if (future.isSuccess()) {
|
p1.remove(encoderName);
|
||||||
ChannelPipeline p = future.channel().pipeline();
|
promise.setSuccess();
|
||||||
p.remove(encoderName);
|
} else {
|
||||||
promise.setSuccess();
|
promise.setFailure(future.cause());
|
||||||
} else {
|
|
||||||
promise.setFailure(future.cause());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
|
|
|
@ -81,19 +81,16 @@ class WebSocketServerProtocolHandshakeHandler extends ChannelInboundHandlerAdapt
|
||||||
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
|
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
|
||||||
} else {
|
} else {
|
||||||
final ChannelFuture handshakeFuture = handshaker.handshake(ctx.channel(), req);
|
final ChannelFuture handshakeFuture = handshaker.handshake(ctx.channel(), req);
|
||||||
handshakeFuture.addListener(new ChannelFutureListener() {
|
handshakeFuture.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
ctx.fireExceptionCaught(future.cause());
|
||||||
if (!future.isSuccess()) {
|
} else {
|
||||||
ctx.fireExceptionCaught(future.cause());
|
// Kept for compatibility
|
||||||
} else {
|
ctx.fireUserEventTriggered(
|
||||||
// Kept for compatibility
|
WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE);
|
||||||
ctx.fireUserEventTriggered(
|
ctx.fireUserEventTriggered(
|
||||||
WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE);
|
new WebSocketServerProtocolHandler.HandshakeComplete(
|
||||||
ctx.fireUserEventTriggered(
|
req.uri(), req.headers(), handshaker.selectedSubprotocol()));
|
||||||
new WebSocketServerProtocolHandler.HandshakeComplete(
|
|
||||||
req.uri(), req.headers(), handshaker.selectedSubprotocol()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
WebSocketServerProtocolHandler.setHandshaker(ctx.channel(), handshaker);
|
WebSocketServerProtocolHandler.setHandshaker(ctx.channel(), handshaker);
|
||||||
|
|
|
@ -115,20 +115,17 @@ public class WebSocketServerExtensionHandler extends ChannelDuplexHandler {
|
||||||
extensionData.name(), extensionData.parameters());
|
extensionData.name(), extensionData.parameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.addListener(new ChannelFutureListener() {
|
promise.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
for (WebSocketServerExtension extension : validExtensions) {
|
||||||
if (future.isSuccess()) {
|
WebSocketExtensionDecoder decoder = extension.newExtensionDecoder();
|
||||||
for (WebSocketServerExtension extension : validExtensions) {
|
WebSocketExtensionEncoder encoder = extension.newExtensionEncoder();
|
||||||
WebSocketExtensionDecoder decoder = extension.newExtensionDecoder();
|
ctx.pipeline().addAfter(ctx.name(), decoder.getClass().getName(), decoder);
|
||||||
WebSocketExtensionEncoder encoder = extension.newExtensionEncoder();
|
ctx.pipeline().addAfter(ctx.name(), encoder.getClass().getName(), encoder);
|
||||||
ctx.pipeline().addAfter(ctx.name(), decoder.getClass().getName(), decoder);
|
|
||||||
ctx.pipeline().addAfter(ctx.name(), encoder.getClass().getName(), encoder);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.pipeline().remove(ctx.name());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.pipeline().remove(ctx.name());
|
||||||
});
|
});
|
||||||
|
|
||||||
if (headerValue != null) {
|
if (headerValue != null) {
|
||||||
|
|
|
@ -27,12 +27,7 @@ import static io.netty.util.AsciiString.CASE_INSENSITIVE_HASHER;
|
||||||
import static io.netty.util.AsciiString.CASE_SENSITIVE_HASHER;
|
import static io.netty.util.AsciiString.CASE_SENSITIVE_HASHER;
|
||||||
|
|
||||||
public class DefaultSpdyHeaders extends DefaultHeaders<CharSequence, CharSequence, SpdyHeaders> implements SpdyHeaders {
|
public class DefaultSpdyHeaders extends DefaultHeaders<CharSequence, CharSequence, SpdyHeaders> implements SpdyHeaders {
|
||||||
private static final NameValidator<CharSequence> SpdyNameValidator = new NameValidator<CharSequence>() {
|
private static final NameValidator<CharSequence> SpdyNameValidator = SpdyCodecUtil::validateHeaderName;
|
||||||
@Override
|
|
||||||
public void validateName(CharSequence name) {
|
|
||||||
SpdyCodecUtil.validateHeaderName(name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public DefaultSpdyHeaders() {
|
public DefaultSpdyHeaders() {
|
||||||
this(true);
|
this(true);
|
||||||
|
|
|
@ -109,12 +109,9 @@ public class SpdyFrameCodec extends ByteToMessageDecoder
|
||||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||||
super.handlerAdded(ctx);
|
super.handlerAdded(ctx);
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
ctx.channel().closeFuture().addListener(new ChannelFutureListener() {
|
ctx.channel().closeFuture().addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
spdyHeaderBlockDecoder.end();
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
spdyHeaderBlockEncoder.end();
|
||||||
spdyHeaderBlockDecoder.end();
|
|
||||||
spdyHeaderBlockEncoder.end();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -504,12 +504,9 @@ public class SpdySessionHandler extends ChannelDuplexHandler {
|
||||||
// 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.
|
||||||
final ChannelHandlerContext context = ctx;
|
final ChannelHandlerContext context = ctx;
|
||||||
ctx.write(partialDataFrame).addListener(new ChannelFutureListener() {
|
ctx.write(partialDataFrame).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
issueSessionError(context, SpdySessionStatus.INTERNAL_ERROR);
|
||||||
if (!future.isSuccess()) {
|
|
||||||
issueSessionError(context, SpdySessionStatus.INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -521,12 +518,9 @@ public class SpdySessionHandler extends ChannelDuplexHandler {
|
||||||
// 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.
|
||||||
final ChannelHandlerContext context = ctx;
|
final ChannelHandlerContext context = ctx;
|
||||||
promise.addListener(new ChannelFutureListener() {
|
promise.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
issueSessionError(context, SpdySessionStatus.INTERNAL_ERROR);
|
||||||
if (!future.isSuccess()) {
|
|
||||||
issueSessionError(context, SpdySessionStatus.INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -781,12 +775,9 @@ public class SpdySessionHandler extends ChannelDuplexHandler {
|
||||||
|
|
||||||
// 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.
|
||||||
ctx.writeAndFlush(partialDataFrame).addListener(new ChannelFutureListener() {
|
ctx.writeAndFlush(partialDataFrame).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
issueSessionError(ctx, SpdySessionStatus.INTERNAL_ERROR);
|
||||||
if (!future.isSuccess()) {
|
|
||||||
issueSessionError(ctx, SpdySessionStatus.INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -802,12 +793,9 @@ public class SpdySessionHandler extends ChannelDuplexHandler {
|
||||||
|
|
||||||
// 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.
|
||||||
ctx.writeAndFlush(spdyDataFrame, pendingWrite.promise).addListener(new ChannelFutureListener() {
|
ctx.writeAndFlush(spdyDataFrame, pendingWrite.promise).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
issueSessionError(ctx, SpdySessionStatus.INTERNAL_ERROR);
|
||||||
if (!future.isSuccess()) {
|
|
||||||
issueSessionError(ctx, SpdySessionStatus.INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,22 +147,16 @@ public class HttpClientCodecTest {
|
||||||
sChannel.writeAndFlush(Unpooled.wrappedBuffer(("HTTP/1.0 200 OK\r\n" +
|
sChannel.writeAndFlush(Unpooled.wrappedBuffer(("HTTP/1.0 200 OK\r\n" +
|
||||||
"Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n" +
|
"Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n" +
|
||||||
"Content-Type: text/html\r\n\r\n").getBytes(CharsetUtil.ISO_8859_1)))
|
"Content-Type: text/html\r\n\r\n").getBytes(CharsetUtil.ISO_8859_1)))
|
||||||
.addListener(new ChannelFutureListener() {
|
.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
assertTrue(future.isSuccess());
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
sChannel.writeAndFlush(Unpooled.wrappedBuffer(
|
||||||
assertTrue(future.isSuccess());
|
"<html><body>hello half closed!</body></html>\r\n"
|
||||||
sChannel.writeAndFlush(Unpooled.wrappedBuffer(
|
.getBytes(CharsetUtil.ISO_8859_1)))
|
||||||
"<html><body>hello half closed!</body></html>\r\n"
|
.addListener((ChannelFutureListener) future1 -> {
|
||||||
.getBytes(CharsetUtil.ISO_8859_1)))
|
assertTrue(future1.isSuccess());
|
||||||
.addListener(new ChannelFutureListener() {
|
sChannel.shutdownOutput();
|
||||||
@Override
|
});
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
assertTrue(future.isSuccess());
|
|
||||||
sChannel.shutdownOutput();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
serverChannelLatch.countDown();
|
serverChannelLatch.countDown();
|
||||||
|
|
|
@ -64,12 +64,7 @@ public class HttpServerUpgradeHandlerTest {
|
||||||
@Test
|
@Test
|
||||||
public void upgradesPipelineInSameMethodInvocation() {
|
public void upgradesPipelineInSameMethodInvocation() {
|
||||||
final HttpServerCodec httpServerCodec = new HttpServerCodec();
|
final HttpServerCodec httpServerCodec = new HttpServerCodec();
|
||||||
final UpgradeCodecFactory factory = new UpgradeCodecFactory() {
|
final UpgradeCodecFactory factory = protocol -> new TestUpgradeCodec();
|
||||||
@Override
|
|
||||||
public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
|
|
||||||
return new TestUpgradeCodec();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChannelHandler testInStackFrame = new ChannelDuplexHandler() {
|
ChannelHandler testInStackFrame = new ChannelDuplexHandler() {
|
||||||
// marker boolean to signal that we're in the `channelRead` method
|
// marker boolean to signal that we're in the `channelRead` method
|
||||||
|
@ -102,18 +97,8 @@ public class HttpServerUpgradeHandlerTest {
|
||||||
// make sure the pipeline was reformed irrespective of the flush completing.
|
// make sure the pipeline was reformed irrespective of the flush completing.
|
||||||
assertTrue(inReadCall);
|
assertTrue(inReadCall);
|
||||||
writeUpgradeMessage = true;
|
writeUpgradeMessage = true;
|
||||||
ctx.channel().eventLoop().execute(new Runnable() {
|
ctx.channel().eventLoop().execute(() -> ctx.write(msg, promise));
|
||||||
@Override
|
promise.addListener((ChannelFutureListener) future -> writeFlushed = true);
|
||||||
public void run() {
|
|
||||||
ctx.write(msg, promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
promise.addListener(new ChannelFutureListener() {
|
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) {
|
|
||||||
writeFlushed = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -186,12 +186,7 @@ public class CorsHandlerTest {
|
||||||
@Test
|
@Test
|
||||||
public void preflightRequestWithValueGenerator() {
|
public void preflightRequestWithValueGenerator() {
|
||||||
final CorsConfig config = forOrigin("http://localhost:8888")
|
final CorsConfig config = forOrigin("http://localhost:8888")
|
||||||
.preflightResponseHeader("GenHeader", new Callable<String>() {
|
.preflightResponseHeader("GenHeader", () -> "generatedValue").build();
|
||||||
@Override
|
|
||||||
public String call() throws Exception {
|
|
||||||
return "generatedValue";
|
|
||||||
}
|
|
||||||
}).build();
|
|
||||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||||
assertThat(response.headers().get(of("GenHeader")), equalTo("generatedValue"));
|
assertThat(response.headers().get(of("GenHeader")), equalTo("generatedValue"));
|
||||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||||
|
|
|
@ -277,14 +277,11 @@ public class DefaultHttp2Connection implements Http2Connection {
|
||||||
|
|
||||||
private void closeStreamsGreaterThanLastKnownStreamId(final int lastKnownStream,
|
private void closeStreamsGreaterThanLastKnownStreamId(final int lastKnownStream,
|
||||||
final DefaultEndpoint<?> endpoint) throws Http2Exception {
|
final DefaultEndpoint<?> endpoint) throws Http2Exception {
|
||||||
forEachActiveStream(new Http2StreamVisitor() {
|
forEachActiveStream(stream -> {
|
||||||
@Override
|
if (stream.id() > lastKnownStream && endpoint.isValidStreamId(stream.id())) {
|
||||||
public boolean visit(Http2Stream stream) {
|
stream.close();
|
||||||
if (stream.id() > lastKnownStream && endpoint.isValidStreamId(stream.id())) {
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,12 +939,7 @@ public class DefaultHttp2Connection implements Http2Connection {
|
||||||
if (allowModifications()) {
|
if (allowModifications()) {
|
||||||
addToActiveStreams(stream);
|
addToActiveStreams(stream);
|
||||||
} else {
|
} else {
|
||||||
pendingEvents.add(new Event() {
|
pendingEvents.add(() -> addToActiveStreams(stream));
|
||||||
@Override
|
|
||||||
public void process() {
|
|
||||||
addToActiveStreams(stream);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,12 +947,7 @@ public class DefaultHttp2Connection implements Http2Connection {
|
||||||
if (allowModifications() || itr != null) {
|
if (allowModifications() || itr != null) {
|
||||||
removeFromActiveStreams(stream, itr);
|
removeFromActiveStreams(stream, itr);
|
||||||
} else {
|
} else {
|
||||||
pendingEvents.add(new Event() {
|
pendingEvents.add(() -> removeFromActiveStreams(stream, itr));
|
||||||
@Override
|
|
||||||
public void process() {
|
|
||||||
removeFromActiveStreams(stream, itr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -463,13 +463,10 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyLifecycleManagerOnError(ChannelFuture future, final ChannelHandlerContext ctx) {
|
private void notifyLifecycleManagerOnError(ChannelFuture future, final ChannelHandlerContext ctx) {
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future1 -> {
|
||||||
@Override
|
Throwable cause = future1.cause();
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
if (cause != null) {
|
||||||
Throwable cause = future.cause();
|
lifecycleManager.onError(ctx, true, cause);
|
||||||
if (cause != null) {
|
|
||||||
lifecycleManager.onError(ctx, true, cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,43 +31,35 @@ import static io.netty.util.AsciiString.isUpperCase;
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class DefaultHttp2Headers
|
public class DefaultHttp2Headers
|
||||||
extends DefaultHeaders<CharSequence, CharSequence, Http2Headers> implements Http2Headers {
|
extends DefaultHeaders<CharSequence, CharSequence, Http2Headers> implements Http2Headers {
|
||||||
private static final ByteProcessor HTTP2_NAME_VALIDATOR_PROCESSOR = new ByteProcessor() {
|
private static final ByteProcessor HTTP2_NAME_VALIDATOR_PROCESSOR = value -> !isUpperCase(value);
|
||||||
@Override
|
static final NameValidator<CharSequence> HTTP2_NAME_VALIDATOR = name -> {
|
||||||
public boolean process(byte value) {
|
if (name == null || name.length() == 0) {
|
||||||
return !isUpperCase(value);
|
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
||||||
|
"empty headers are not allowed [%s]", name));
|
||||||
}
|
}
|
||||||
};
|
if (name instanceof AsciiString) {
|
||||||
static final NameValidator<CharSequence> HTTP2_NAME_VALIDATOR = new NameValidator<CharSequence>() {
|
final int index;
|
||||||
@Override
|
try {
|
||||||
public void validateName(CharSequence name) {
|
index = ((AsciiString) name).forEachByte(HTTP2_NAME_VALIDATOR_PROCESSOR);
|
||||||
if (name == null || name.length() == 0) {
|
} catch (Http2Exception e) {
|
||||||
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
PlatformDependent.throwException(e);
|
||||||
"empty headers are not allowed [%s]", name));
|
return;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR, t,
|
||||||
|
"unexpected error. invalid header name [%s]", name));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (name instanceof AsciiString) {
|
|
||||||
final int index;
|
|
||||||
try {
|
|
||||||
index = ((AsciiString) name).forEachByte(HTTP2_NAME_VALIDATOR_PROCESSOR);
|
|
||||||
} catch (Http2Exception e) {
|
|
||||||
PlatformDependent.throwException(e);
|
|
||||||
return;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR, t,
|
|
||||||
"unexpected error. invalid header name [%s]", name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
|
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
||||||
|
"invalid header name [%s]", name));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < name.length(); ++i) {
|
||||||
|
if (isUpperCase(name.charAt(i))) {
|
||||||
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
||||||
"invalid header name [%s]", name));
|
"invalid header name [%s]", name));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (int i = 0; i < name.length(); ++i) {
|
|
||||||
if (isUpperCase(name.charAt(i))) {
|
|
||||||
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
|
||||||
"invalid header name [%s]", name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -641,12 +641,9 @@ public class DefaultHttp2RemoteFlowController implements Http2RemoteFlowControll
|
||||||
|
|
||||||
final int delta = newWindowSize - initialWindowSize;
|
final int delta = newWindowSize - initialWindowSize;
|
||||||
initialWindowSize = newWindowSize;
|
initialWindowSize = newWindowSize;
|
||||||
connection.forEachActiveStream(new Http2StreamVisitor() {
|
connection.forEachActiveStream(stream -> {
|
||||||
@Override
|
state(stream).incrementStreamWindow(delta);
|
||||||
public boolean visit(Http2Stream stream) throws Http2Exception {
|
return true;
|
||||||
state(stream).incrementStreamWindow(delta);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (delta > 0 && isChannelWritable()) {
|
if (delta > 0 && isChannelWritable()) {
|
||||||
|
|
|
@ -606,12 +606,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
checkCloseConnection(future);
|
checkCloseConnection(future);
|
||||||
} else {
|
} else {
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) this::checkCloseConnection);
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
checkCloseConnection(future);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,12 +745,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
closeConnectionOnError(ctx, future);
|
closeConnectionOnError(ctx, future);
|
||||||
} else {
|
} else {
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future1 -> closeConnectionOnError(ctx, future1));
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
closeConnectionOnError(ctx, future);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
@ -795,12 +785,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
processRstStreamWriteResult(ctx, stream, future);
|
processRstStreamWriteResult(ctx, stream, future);
|
||||||
} else {
|
} else {
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future1 -> processRstStreamWriteResult(ctx, stream, future1));
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
processRstStreamWriteResult(ctx, stream, future);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
|
@ -831,12 +816,8 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
|
processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
|
||||||
} else {
|
} else {
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future1 ->
|
||||||
@Override
|
processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future1));
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
|
@ -938,11 +919,8 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
||||||
long timeout, TimeUnit unit) {
|
long timeout, TimeUnit unit) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.promise = promise;
|
this.promise = promise;
|
||||||
timeoutTask = ctx.executor().schedule(new Runnable() {
|
timeoutTask = ctx.executor().schedule(() -> {
|
||||||
@Override
|
ctx.close(promise);
|
||||||
public void run() {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
}, timeout, unit);
|
}, timeout, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,15 +183,12 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
|
||||||
final void forEachActiveStream(final Http2FrameStreamVisitor streamVisitor) throws Http2Exception {
|
final void forEachActiveStream(final Http2FrameStreamVisitor streamVisitor) throws Http2Exception {
|
||||||
assert ctx.executor().inEventLoop();
|
assert ctx.executor().inEventLoop();
|
||||||
|
|
||||||
connection().forEachActiveStream(new Http2StreamVisitor() {
|
connection().forEachActiveStream(stream -> {
|
||||||
@Override
|
try {
|
||||||
public boolean visit(Http2Stream stream) {
|
return streamVisitor.visit((Http2FrameStream) stream.getProperty(streamKey));
|
||||||
try {
|
} catch (Throwable cause) {
|
||||||
return streamVisitor.visit((Http2FrameStream) stream.getProperty(streamKey));
|
onError(ctx, false, cause);
|
||||||
} catch (Throwable cause) {
|
return false;
|
||||||
onError(ctx, false, cause);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -381,13 +378,10 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
|
||||||
} else {
|
} else {
|
||||||
numBufferedStreams++;
|
numBufferedStreams++;
|
||||||
|
|
||||||
writePromise.addListener(new ChannelFutureListener() {
|
writePromise.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
numBufferedStreams--;
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
numBufferedStreams--;
|
|
||||||
|
|
||||||
notifyHeaderWritePromise(future, promise);
|
notifyHeaderWritePromise(future, promise);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,20 +90,10 @@ public interface Http2HeadersEncoder {
|
||||||
/**
|
/**
|
||||||
* Always return {@code false} for {@link SensitivityDetector#isSensitive(CharSequence, CharSequence)}.
|
* Always return {@code false} for {@link SensitivityDetector#isSensitive(CharSequence, CharSequence)}.
|
||||||
*/
|
*/
|
||||||
SensitivityDetector NEVER_SENSITIVE = new SensitivityDetector() {
|
SensitivityDetector NEVER_SENSITIVE = (name, value) -> false;
|
||||||
@Override
|
|
||||||
public boolean isSensitive(CharSequence name, CharSequence value) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Always return {@code true} for {@link SensitivityDetector#isSensitive(CharSequence, CharSequence)}.
|
* Always return {@code true} for {@link SensitivityDetector#isSensitive(CharSequence, CharSequence)}.
|
||||||
*/
|
*/
|
||||||
SensitivityDetector ALWAYS_SENSITIVE = new SensitivityDetector() {
|
SensitivityDetector ALWAYS_SENSITIVE = (name, value) -> true;
|
||||||
@Override
|
|
||||||
public boolean isSensitive(CharSequence name, CharSequence value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,12 +108,7 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
||||||
|
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultHttp2StreamChannel.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultHttp2StreamChannel.class);
|
||||||
|
|
||||||
private static final ChannelFutureListener CHILD_CHANNEL_REGISTRATION_LISTENER = new ChannelFutureListener() {
|
private static final ChannelFutureListener CHILD_CHANNEL_REGISTRATION_LISTENER = Http2MultiplexCodec::registerDone;
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) {
|
|
||||||
registerDone(future);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
|
private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
|
||||||
private static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
|
private static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
|
||||||
|
@ -131,15 +126,10 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
||||||
|
|
||||||
static final FlowControlledFrameSizeEstimator INSTANCE = new FlowControlledFrameSizeEstimator();
|
static final FlowControlledFrameSizeEstimator INSTANCE = new FlowControlledFrameSizeEstimator();
|
||||||
|
|
||||||
static final MessageSizeEstimator.Handle HANDLE_INSTANCE = new MessageSizeEstimator.Handle() {
|
static final MessageSizeEstimator.Handle HANDLE_INSTANCE = msg -> msg instanceof Http2DataFrame ?
|
||||||
@Override
|
// Guard against overflow.
|
||||||
public int size(Object msg) {
|
(int) min(Integer.MAX_VALUE, ((Http2DataFrame) msg).initialFlowControlledBytes() +
|
||||||
return msg instanceof Http2DataFrame ?
|
(long) MIN_HTTP2_FRAME_SIZE) : MIN_HTTP2_FRAME_SIZE;
|
||||||
// Guard against overflow.
|
|
||||||
(int) min(Integer.MAX_VALUE, ((Http2DataFrame) msg).initialFlowControlledBytes() +
|
|
||||||
(long) MIN_HTTP2_FRAME_SIZE) : MIN_HTTP2_FRAME_SIZE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Handle newHandle() {
|
public Handle newHandle() {
|
||||||
|
@ -361,16 +351,13 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
||||||
|
|
||||||
private void onHttp2GoAwayFrame(ChannelHandlerContext ctx, final Http2GoAwayFrame goAwayFrame) {
|
private void onHttp2GoAwayFrame(ChannelHandlerContext ctx, final Http2GoAwayFrame goAwayFrame) {
|
||||||
try {
|
try {
|
||||||
forEachActiveStream(new Http2FrameStreamVisitor() {
|
forEachActiveStream(stream -> {
|
||||||
@Override
|
final int streamId = stream.id();
|
||||||
public boolean visit(Http2FrameStream stream) {
|
final DefaultHttp2StreamChannel childChannel = ((Http2MultiplexCodecStream) stream).channel;
|
||||||
final int streamId = stream.id();
|
if (streamId > goAwayFrame.lastStreamId() && connection().local().isValidStreamId(streamId)) {
|
||||||
final DefaultHttp2StreamChannel childChannel = ((Http2MultiplexCodecStream) stream).channel;
|
childChannel.pipeline().fireUserEventTriggered(goAwayFrame.retainedDuplicate());
|
||||||
if (streamId > goAwayFrame.lastStreamId() && connection().local().isValidStreamId(streamId)) {
|
|
||||||
childChannel.pipeline().fireUserEventTriggered(goAwayFrame.retainedDuplicate());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
} catch (Http2Exception e) {
|
} catch (Http2Exception e) {
|
||||||
ctx.fireExceptionCaught(e);
|
ctx.fireExceptionCaught(e);
|
||||||
|
@ -890,12 +877,7 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
||||||
promise.setSuccess();
|
promise.setSuccess();
|
||||||
} else if (!(promise instanceof VoidChannelPromise)) { // Only needed if no VoidChannelPromise.
|
} else if (!(promise instanceof VoidChannelPromise)) { // Only needed if no VoidChannelPromise.
|
||||||
// This means close() was called before so we just register a listener and return
|
// This means close() was called before so we just register a listener and return
|
||||||
closePromise.addListener(new ChannelFutureListener() {
|
closePromise.addListener((ChannelFutureListener) future -> promise.setSuccess());
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) {
|
|
||||||
promise.setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -959,20 +941,17 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
||||||
//
|
//
|
||||||
// See:
|
// See:
|
||||||
// https://github.com/netty/netty/issues/4435
|
// https://github.com/netty/netty/issues/4435
|
||||||
invokeLater(new Runnable() {
|
invokeLater(() -> {
|
||||||
@Override
|
if (fireChannelInactive) {
|
||||||
public void run() {
|
pipeline.fireChannelInactive();
|
||||||
if (fireChannelInactive) {
|
|
||||||
pipeline.fireChannelInactive();
|
|
||||||
}
|
|
||||||
// The user can fire `deregister` events multiple times but we only want to fire the pipeline
|
|
||||||
// event if the channel was actually registered.
|
|
||||||
if (registered) {
|
|
||||||
registered = false;
|
|
||||||
pipeline.fireChannelUnregistered();
|
|
||||||
}
|
|
||||||
safeSetSuccess(promise);
|
|
||||||
}
|
}
|
||||||
|
// The user can fire `deregister` events multiple times but we only want to fire the pipeline
|
||||||
|
// event if the channel was actually registered.
|
||||||
|
if (registered) {
|
||||||
|
registered = false;
|
||||||
|
pipeline.fireChannelUnregistered();
|
||||||
|
}
|
||||||
|
safeSetSuccess(promise);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,12 +1106,8 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
firstWriteComplete(future, promise);
|
firstWriteComplete(future, promise);
|
||||||
} else {
|
} else {
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future12 ->
|
||||||
@Override
|
firstWriteComplete(future12, promise));
|
||||||
public void operationComplete(ChannelFuture future) {
|
|
||||||
firstWriteComplete(future, promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1149,12 +1124,7 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
writeComplete(future, promise);
|
writeComplete(future, promise);
|
||||||
} else {
|
} else {
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future1 -> writeComplete(future1, promise));
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) {
|
|
||||||
writeComplete(future, promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
promise.tryFailure(t);
|
promise.tryFailure(t);
|
||||||
|
|
|
@ -118,12 +118,7 @@ public final class Http2StreamChannelBootstrap {
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
open0(ctx, promise);
|
open0(ctx, promise);
|
||||||
} else {
|
} else {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> open0(ctx, promise));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
open0(ctx, promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return promise;
|
return promise;
|
||||||
|
@ -141,22 +136,19 @@ public final class Http2StreamChannelBootstrap {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelFuture future = streamChannel.register();
|
ChannelFuture future = streamChannel.register();
|
||||||
future.addListener(new ChannelFutureListener() {
|
future.addListener((ChannelFutureListener) future1 -> {
|
||||||
@Override
|
if (future1.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
promise.setSuccess(streamChannel);
|
||||||
if (future.isSuccess()) {
|
} else if (future1.isCancelled()) {
|
||||||
promise.setSuccess(streamChannel);
|
promise.cancel(false);
|
||||||
} else if (future.isCancelled()) {
|
} else {
|
||||||
promise.cancel(false);
|
if (streamChannel.isRegistered()) {
|
||||||
|
streamChannel.close();
|
||||||
} else {
|
} else {
|
||||||
if (streamChannel.isRegistered()) {
|
streamChannel.unsafe().closeForcibly();
|
||||||
streamChannel.close();
|
|
||||||
} else {
|
|
||||||
streamChannel.unsafe().closeForcibly();
|
|
||||||
}
|
|
||||||
|
|
||||||
promise.setFailure(future.cause());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
promise.setFailure(future1.cause());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,21 +35,18 @@ abstract class AbstractWeightedFairQueueByteDistributorDependencyTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Answer<Void> writeAnswer(final boolean closeIfNoFrame) {
|
Answer<Void> writeAnswer(final boolean closeIfNoFrame) {
|
||||||
return new Answer<Void>() {
|
return in -> {
|
||||||
@Override
|
Http2Stream stream = in.getArgument(0);
|
||||||
public Void answer(InvocationOnMock in) throws Throwable {
|
int numBytes = in.getArgument(1);
|
||||||
Http2Stream stream = in.getArgument(0);
|
TestStreamByteDistributorStreamState state = stateMap.get(stream.id());
|
||||||
int numBytes = in.getArgument(1);
|
state.pendingBytes -= numBytes;
|
||||||
TestStreamByteDistributorStreamState state = stateMap.get(stream.id());
|
state.hasFrame = state.pendingBytes > 0;
|
||||||
state.pendingBytes -= numBytes;
|
state.isWriteAllowed = state.hasFrame;
|
||||||
state.hasFrame = state.pendingBytes > 0;
|
if (closeIfNoFrame && !state.hasFrame) {
|
||||||
state.isWriteAllowed = state.hasFrame;
|
stream.close();
|
||||||
if (closeIfNoFrame && !state.hasFrame) {
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
distributor.updateStreamableBytes(state);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
distributor.updateStreamableBytes(state);
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,12 +63,7 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
|
||||||
http2ConnectionHandler = new Http2ConnectionHandlerBuilder()
|
http2ConnectionHandler = new Http2ConnectionHandlerBuilder()
|
||||||
.frameListener(frameListener).build();
|
.frameListener(frameListener).build();
|
||||||
|
|
||||||
UpgradeCodecFactory upgradeCodecFactory = new UpgradeCodecFactory() {
|
UpgradeCodecFactory upgradeCodecFactory = protocol -> new Http2ServerUpgradeCodec(http2ConnectionHandler);
|
||||||
@Override
|
|
||||||
public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
|
|
||||||
return new Http2ServerUpgradeCodec(http2ConnectionHandler);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
userEvents = new ArrayList<>();
|
userEvents = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -205,12 +200,7 @@ public class CleartextHttp2ServerUpgradeHandlerTest {
|
||||||
protected void initChannel(Channel ch) throws Exception {
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
}
|
}
|
||||||
}).build();
|
}).build();
|
||||||
UpgradeCodecFactory upgradeCodecFactory = new UpgradeCodecFactory() {
|
UpgradeCodecFactory upgradeCodecFactory = protocol -> new Http2ServerUpgradeCodec(http2Codec);
|
||||||
@Override
|
|
||||||
public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
|
|
||||||
return new Http2ServerUpgradeCodec(http2Codec);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
http2ConnectionHandler = http2Codec;
|
http2ConnectionHandler = http2Codec;
|
||||||
|
|
||||||
userEvents = new ArrayList<>();
|
userEvents = new ArrayList<>();
|
||||||
|
|
|
@ -92,24 +92,18 @@ public class DataCompressionHttp2Test {
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws InterruptedException, Http2Exception {
|
public void setup() throws InterruptedException, Http2Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(invocation -> {
|
||||||
@Override
|
if (invocation.getArgument(4)) {
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
serverConnection.stream((Integer) invocation.getArgument(1)).close();
|
||||||
if (invocation.getArgument(4)) {
|
|
||||||
serverConnection.stream((Integer) invocation.getArgument(1)).close();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
|
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
|
||||||
anyInt(), anyBoolean());
|
anyInt(), anyBoolean());
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(invocation -> {
|
||||||
@Override
|
if (invocation.getArgument(7)) {
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
serverConnection.stream((Integer) invocation.getArgument(1)).close();
|
||||||
if (invocation.getArgument(7)) {
|
|
||||||
serverConnection.stream((Integer) invocation.getArgument(1)).close();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
|
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
|
||||||
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
|
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
@ -148,12 +142,9 @@ public class DataCompressionHttp2Test {
|
||||||
final Http2Headers headers = new DefaultHttp2Headers().method(GET).path(PATH)
|
final Http2Headers headers = new DefaultHttp2Headers().method(GET).path(PATH)
|
||||||
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, true, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientHandler.flush(ctxClient());
|
||||||
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, true, newPromiseClient());
|
|
||||||
clientHandler.flush(ctxClient());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitServer();
|
awaitServer();
|
||||||
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(3), eq(headers), eq(0),
|
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(3), eq(headers), eq(0),
|
||||||
|
@ -169,13 +160,10 @@ public class DataCompressionHttp2Test {
|
||||||
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
||||||
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientEncoder.writeData(ctxClient(), 3, data.retain(), 0, true, newPromiseClient());
|
||||||
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
clientHandler.flush(ctxClient());
|
||||||
clientEncoder.writeData(ctxClient(), 3, data.retain(), 0, true, newPromiseClient());
|
|
||||||
clientHandler.flush(ctxClient());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitServer();
|
awaitServer();
|
||||||
assertEquals(text, serverOut.toString(CharsetUtil.UTF_8.name()));
|
assertEquals(text, serverOut.toString(CharsetUtil.UTF_8.name()));
|
||||||
|
@ -193,13 +181,10 @@ public class DataCompressionHttp2Test {
|
||||||
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
||||||
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientEncoder.writeData(ctxClient(), 3, data.retain(), 0, true, newPromiseClient());
|
||||||
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
clientHandler.flush(ctxClient());
|
||||||
clientEncoder.writeData(ctxClient(), 3, data.retain(), 0, true, newPromiseClient());
|
|
||||||
clientHandler.flush(ctxClient());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitServer();
|
awaitServer();
|
||||||
assertEquals(text, serverOut.toString(CharsetUtil.UTF_8.name()));
|
assertEquals(text, serverOut.toString(CharsetUtil.UTF_8.name()));
|
||||||
|
@ -219,14 +204,11 @@ public class DataCompressionHttp2Test {
|
||||||
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
||||||
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.GZIP);
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientEncoder.writeData(ctxClient(), 3, data1.retain(), 0, false, newPromiseClient());
|
||||||
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
clientEncoder.writeData(ctxClient(), 3, data2.retain(), 0, true, newPromiseClient());
|
||||||
clientEncoder.writeData(ctxClient(), 3, data1.retain(), 0, false, newPromiseClient());
|
clientHandler.flush(ctxClient());
|
||||||
clientEncoder.writeData(ctxClient(), 3, data2.retain(), 0, true, newPromiseClient());
|
|
||||||
clientHandler.flush(ctxClient());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitServer();
|
awaitServer();
|
||||||
assertEquals(text1 + text2, serverOut.toString(CharsetUtil.UTF_8.name()));
|
assertEquals(text1 + text2, serverOut.toString(CharsetUtil.UTF_8.name()));
|
||||||
|
@ -247,13 +229,10 @@ public class DataCompressionHttp2Test {
|
||||||
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
final Http2Headers headers = new DefaultHttp2Headers().method(POST).path(PATH)
|
||||||
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.DEFLATE);
|
.set(HttpHeaderNames.CONTENT_ENCODING, HttpHeaderValues.DEFLATE);
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientEncoder.writeData(ctxClient(), 3, data.retain(), 0, true, newPromiseClient());
|
||||||
clientEncoder.writeHeaders(ctxClient(), 3, headers, 0, false, newPromiseClient());
|
clientHandler.flush(ctxClient());
|
||||||
clientEncoder.writeData(ctxClient(), 3, data.retain(), 0, true, newPromiseClient());
|
|
||||||
clientHandler.flush(ctxClient());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitServer();
|
awaitServer();
|
||||||
assertEquals(data.readerIndex(0).toString(CharsetUtil.UTF_8),
|
assertEquals(data.readerIndex(0).toString(CharsetUtil.UTF_8),
|
||||||
|
@ -281,20 +260,17 @@ public class DataCompressionHttp2Test {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer(in -> {
|
||||||
@Override
|
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
||||||
public Integer answer(InvocationOnMock in) throws Throwable {
|
int padding = (Integer) in.getArguments()[3];
|
||||||
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
int processedBytes = buf.readableBytes() + padding;
|
||||||
int padding = (Integer) in.getArguments()[3];
|
|
||||||
int processedBytes = buf.readableBytes() + padding;
|
|
||||||
|
|
||||||
buf.readBytes(serverOut, buf.readableBytes());
|
buf.readBytes(serverOut, buf.readableBytes());
|
||||||
|
|
||||||
if (in.getArgument(4)) {
|
if (in.getArgument(4)) {
|
||||||
serverConnection.stream((Integer) in.getArgument(1)).close();
|
serverConnection.stream((Integer) in.getArgument(1)).close();
|
||||||
}
|
|
||||||
return processedBytes;
|
|
||||||
}
|
}
|
||||||
|
return processedBytes;
|
||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||||
|
|
||||||
|
|
|
@ -130,52 +130,38 @@ public class DefaultHttp2ConnectionDecoderTest {
|
||||||
when(stream.state()).thenReturn(OPEN);
|
when(stream.state()).thenReturn(OPEN);
|
||||||
when(stream.open(anyBoolean())).thenReturn(stream);
|
when(stream.open(anyBoolean())).thenReturn(stream);
|
||||||
when(pushStream.id()).thenReturn(PUSH_STREAM_ID);
|
when(pushStream.id()).thenReturn(PUSH_STREAM_ID);
|
||||||
doAnswer(new Answer<Boolean>() {
|
doAnswer((Answer<Boolean>) in ->
|
||||||
@Override
|
(headersReceivedState.get() & STATE_RECV_HEADERS) != 0).when(stream).isHeadersReceived();
|
||||||
public Boolean answer(InvocationOnMock in) throws Throwable {
|
doAnswer((Answer<Boolean>) in ->
|
||||||
return (headersReceivedState.get() & STATE_RECV_HEADERS) != 0;
|
(headersReceivedState.get() & STATE_RECV_TRAILERS) != 0).when(stream).isTrailersReceived();
|
||||||
}
|
doAnswer((Answer<Http2Stream>) in -> {
|
||||||
}).when(stream).isHeadersReceived();
|
boolean isInformational = in.getArgument(0);
|
||||||
doAnswer(new Answer<Boolean>() {
|
if (isInformational) {
|
||||||
@Override
|
|
||||||
public Boolean answer(InvocationOnMock in) throws Throwable {
|
|
||||||
return (headersReceivedState.get() & STATE_RECV_TRAILERS) != 0;
|
|
||||||
}
|
|
||||||
}).when(stream).isTrailersReceived();
|
|
||||||
doAnswer(new Answer<Http2Stream>() {
|
|
||||||
@Override
|
|
||||||
public Http2Stream answer(InvocationOnMock in) throws Throwable {
|
|
||||||
boolean isInformational = in.getArgument(0);
|
|
||||||
if (isInformational) {
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
int current = headersReceivedState.get();
|
|
||||||
int next = current;
|
|
||||||
if ((current & STATE_RECV_HEADERS) != 0) {
|
|
||||||
if ((current & STATE_RECV_TRAILERS) != 0) {
|
|
||||||
throw new IllegalStateException("already sent headers!");
|
|
||||||
}
|
|
||||||
next |= STATE_RECV_TRAILERS;
|
|
||||||
} else {
|
|
||||||
next |= STATE_RECV_HEADERS;
|
|
||||||
}
|
|
||||||
if (headersReceivedState.compareAndSet(current, next)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
}).when(stream).headersReceived(anyBoolean());
|
for (;;) {
|
||||||
doAnswer(new Answer<Http2Stream>() {
|
int current = headersReceivedState.get();
|
||||||
@Override
|
int next = current;
|
||||||
public Http2Stream answer(InvocationOnMock in) throws Throwable {
|
if ((current & STATE_RECV_HEADERS) != 0) {
|
||||||
Http2StreamVisitor visitor = in.getArgument(0);
|
if ((current & STATE_RECV_TRAILERS) != 0) {
|
||||||
if (!visitor.visit(stream)) {
|
throw new IllegalStateException("already sent headers!");
|
||||||
return stream;
|
}
|
||||||
|
next |= STATE_RECV_TRAILERS;
|
||||||
|
} else {
|
||||||
|
next |= STATE_RECV_HEADERS;
|
||||||
|
}
|
||||||
|
if (headersReceivedState.compareAndSet(current, next)) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return stream;
|
||||||
|
}).when(stream).headersReceived(anyBoolean());
|
||||||
|
doAnswer((Answer<Http2Stream>) in -> {
|
||||||
|
Http2StreamVisitor visitor = in.getArgument(0);
|
||||||
|
if (!visitor.visit(stream)) {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}).when(connection).forEachActiveStream(any(Http2StreamVisitor.class));
|
}).when(connection).forEachActiveStream(any(Http2StreamVisitor.class));
|
||||||
when(connection.stream(STREAM_ID)).thenReturn(stream);
|
when(connection.stream(STREAM_ID)).thenReturn(stream);
|
||||||
when(connection.streamMayHaveExisted(STREAM_ID)).thenReturn(true);
|
when(connection.streamMayHaveExisted(STREAM_ID)).thenReturn(true);
|
||||||
|
@ -391,30 +377,19 @@ public class DefaultHttp2ConnectionDecoderTest {
|
||||||
final ByteBuf data = dummyData();
|
final ByteBuf data = dummyData();
|
||||||
final int padding = 10;
|
final int padding = 10;
|
||||||
final AtomicInteger unprocessed = new AtomicInteger(data.readableBytes() + padding);
|
final AtomicInteger unprocessed = new AtomicInteger(data.readableBytes() + padding);
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) in -> unprocessed.get()).when(localFlow).unconsumedBytes(eq(stream));
|
||||||
@Override
|
doAnswer((Answer<Void>) in -> {
|
||||||
public Integer answer(InvocationOnMock in) throws Throwable {
|
int delta = (Integer) in.getArguments()[1];
|
||||||
return unprocessed.get();
|
int newValue = unprocessed.addAndGet(-delta);
|
||||||
}
|
if (newValue < 0) {
|
||||||
}).when(localFlow).unconsumedBytes(eq(stream));
|
throw new RuntimeException("Returned too many bytes");
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock in) throws Throwable {
|
|
||||||
int delta = (Integer) in.getArguments()[1];
|
|
||||||
int newValue = unprocessed.addAndGet(-delta);
|
|
||||||
if (newValue < 0) {
|
|
||||||
throw new RuntimeException("Returned too many bytes");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}).when(localFlow).consumeBytes(eq(stream), anyInt());
|
}).when(localFlow).consumeBytes(eq(stream), anyInt());
|
||||||
// When the listener callback is called, process a few bytes and then throw.
|
// When the listener callback is called, process a few bytes and then throw.
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) in -> {
|
||||||
@Override
|
localFlow.consumeBytes(stream, 4);
|
||||||
public Integer answer(InvocationOnMock in) throws Throwable {
|
throw new RuntimeException("Fake Exception");
|
||||||
localFlow.consumeBytes(stream, 4);
|
|
||||||
throw new RuntimeException("Fake Exception");
|
|
||||||
}
|
|
||||||
}).when(listener).onDataRead(eq(ctx), eq(STREAM_ID), any(ByteBuf.class), eq(10), eq(true));
|
}).when(listener).onDataRead(eq(ctx), eq(STREAM_ID), any(ByteBuf.class), eq(10), eq(true));
|
||||||
try {
|
try {
|
||||||
decode().onDataRead(ctx, STREAM_ID, data, padding, true);
|
decode().onDataRead(ctx, STREAM_ID, data, padding, true);
|
||||||
|
@ -759,12 +734,8 @@ public class DefaultHttp2ConnectionDecoderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mockFlowControl(final int processedBytes) throws Http2Exception {
|
private void mockFlowControl(final int processedBytes) throws Http2Exception {
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) invocation ->
|
||||||
@Override
|
processedBytes).when(listener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||||
public Integer answer(InvocationOnMock invocation) throws Throwable {
|
|
||||||
return processedBytes;
|
|
||||||
}
|
|
||||||
}).when(listener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
|
||||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,82 +127,55 @@ public class DefaultHttp2ConnectionEncoderTest {
|
||||||
when(channel.unsafe()).thenReturn(unsafe);
|
when(channel.unsafe()).thenReturn(unsafe);
|
||||||
ChannelConfig config = new DefaultChannelConfig(channel);
|
ChannelConfig config = new DefaultChannelConfig(channel);
|
||||||
when(channel.config()).thenReturn(config);
|
when(channel.config()).thenReturn(config);
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
doAnswer(in -> newPromise()
|
||||||
@Override
|
.setFailure((Throwable) in.getArgument(0))).when(channel).newFailedFuture(any(Throwable.class));
|
||||||
public ChannelFuture answer(InvocationOnMock in) {
|
|
||||||
return newPromise().setFailure((Throwable) in.getArgument(0));
|
|
||||||
}
|
|
||||||
}).when(channel).newFailedFuture(any(Throwable.class));
|
|
||||||
|
|
||||||
when(writer.configuration()).thenReturn(writerConfig);
|
when(writer.configuration()).thenReturn(writerConfig);
|
||||||
when(writerConfig.frameSizePolicy()).thenReturn(frameSizePolicy);
|
when(writerConfig.frameSizePolicy()).thenReturn(frameSizePolicy);
|
||||||
when(frameSizePolicy.maxFrameSize()).thenReturn(64);
|
when(frameSizePolicy.maxFrameSize()).thenReturn(64);
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
doAnswer((Answer<ChannelFuture>) in -> ((ChannelPromise) in.getArguments()[2])
|
||||||
@Override
|
.setSuccess()).when(writer).writeSettings(eq(ctx), any(Http2Settings.class), any(ChannelPromise.class));
|
||||||
public ChannelFuture answer(InvocationOnMock in) throws Throwable {
|
doAnswer((Answer<ChannelFuture>) in -> {
|
||||||
return ((ChannelPromise) in.getArguments()[2]).setSuccess();
|
((ByteBuf) in.getArguments()[3]).release();
|
||||||
}
|
return ((ChannelPromise) in.getArguments()[4]).setSuccess();
|
||||||
}).when(writer).writeSettings(eq(ctx), any(Http2Settings.class), any(ChannelPromise.class));
|
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
|
||||||
@Override
|
|
||||||
public ChannelFuture answer(InvocationOnMock in) throws Throwable {
|
|
||||||
((ByteBuf) in.getArguments()[3]).release();
|
|
||||||
return ((ChannelPromise) in.getArguments()[4]).setSuccess();
|
|
||||||
}
|
|
||||||
}).when(writer).writeGoAway(eq(ctx), anyInt(), anyInt(), any(ByteBuf.class), any(ChannelPromise.class));
|
}).when(writer).writeGoAway(eq(ctx), anyInt(), anyInt(), any(ByteBuf.class), any(ChannelPromise.class));
|
||||||
writtenData = new ArrayList<>();
|
writtenData = new ArrayList<>();
|
||||||
writtenPadding = new ArrayList<>();
|
writtenPadding = new ArrayList<>();
|
||||||
when(writer.writeData(eq(ctx), anyInt(), any(ByteBuf.class), anyInt(), anyBoolean(),
|
when(writer.writeData(eq(ctx), anyInt(), any(ByteBuf.class), anyInt(), anyBoolean(),
|
||||||
any(ChannelPromise.class))).then(new Answer<ChannelFuture>() {
|
any(ChannelPromise.class))).then((Answer<ChannelFuture>) in -> {
|
||||||
@Override
|
// Make sure we only receive stream closure on the last frame and that void promises
|
||||||
public ChannelFuture answer(InvocationOnMock in) throws Throwable {
|
// are used for all writes except the last one.
|
||||||
// Make sure we only receive stream closure on the last frame and that void promises
|
ChannelPromise promise = (ChannelPromise) in.getArguments()[5];
|
||||||
// are used for all writes except the last one.
|
if (streamClosed) {
|
||||||
ChannelPromise promise = (ChannelPromise) in.getArguments()[5];
|
fail("Stream already closed");
|
||||||
if (streamClosed) {
|
} else {
|
||||||
fail("Stream already closed");
|
streamClosed = (Boolean) in.getArguments()[4];
|
||||||
} else {
|
|
||||||
streamClosed = (Boolean) in.getArguments()[4];
|
|
||||||
}
|
|
||||||
writtenPadding.add((Integer) in.getArguments()[3]);
|
|
||||||
ByteBuf data = (ByteBuf) in.getArguments()[2];
|
|
||||||
writtenData.add(data.toString(UTF_8));
|
|
||||||
// Release the buffer just as DefaultHttp2FrameWriter does
|
|
||||||
data.release();
|
|
||||||
// Let the promise succeed to trigger listeners.
|
|
||||||
return promise.setSuccess();
|
|
||||||
}
|
}
|
||||||
|
writtenPadding.add((Integer) in.getArguments()[3]);
|
||||||
|
ByteBuf data = (ByteBuf) in.getArguments()[2];
|
||||||
|
writtenData.add(data.toString(UTF_8));
|
||||||
|
// Release the buffer just as DefaultHttp2FrameWriter does
|
||||||
|
data.release();
|
||||||
|
// Let the promise succeed to trigger listeners.
|
||||||
|
return promise.setSuccess();
|
||||||
});
|
});
|
||||||
when(writer.writeHeaders(eq(ctx), anyInt(), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(),
|
when(writer.writeHeaders(eq(ctx), anyInt(), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(),
|
||||||
anyInt(), anyBoolean(), any(ChannelPromise.class)))
|
anyInt(), anyBoolean(), any(ChannelPromise.class)))
|
||||||
.then(new Answer<ChannelFuture>() {
|
.then((Answer<ChannelFuture>) invocationOnMock -> {
|
||||||
@Override
|
ChannelPromise promise = (ChannelPromise) invocationOnMock.getArguments()[8];
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) throws Throwable {
|
if (streamClosed) {
|
||||||
ChannelPromise promise = (ChannelPromise) invocationOnMock.getArguments()[8];
|
fail("Stream already closed");
|
||||||
if (streamClosed) {
|
} else {
|
||||||
fail("Stream already closed");
|
streamClosed = (Boolean) invocationOnMock.getArguments()[5];
|
||||||
} else {
|
|
||||||
streamClosed = (Boolean) invocationOnMock.getArguments()[5];
|
|
||||||
}
|
|
||||||
return promise.setSuccess();
|
|
||||||
}
|
}
|
||||||
|
return promise.setSuccess();
|
||||||
});
|
});
|
||||||
payloadCaptor = ArgumentCaptor.forClass(Http2RemoteFlowController.FlowControlled.class);
|
payloadCaptor = ArgumentCaptor.forClass(Http2RemoteFlowController.FlowControlled.class);
|
||||||
doNothing().when(remoteFlow).addFlowControlled(any(Http2Stream.class), payloadCaptor.capture());
|
doNothing().when(remoteFlow).addFlowControlled(any(Http2Stream.class), payloadCaptor.capture());
|
||||||
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
||||||
when(ctx.channel()).thenReturn(channel);
|
when(ctx.channel()).thenReturn(channel);
|
||||||
doAnswer(new Answer<ChannelPromise>() {
|
doAnswer((Answer<ChannelPromise>) in -> newPromise()).when(ctx).newPromise();
|
||||||
@Override
|
doAnswer((Answer<ChannelFuture>) in -> newSucceededFuture()).when(ctx).newSucceededFuture();
|
||||||
public ChannelPromise answer(InvocationOnMock in) throws Throwable {
|
|
||||||
return newPromise();
|
|
||||||
}
|
|
||||||
}).when(ctx).newPromise();
|
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
|
||||||
@Override
|
|
||||||
public ChannelFuture answer(InvocationOnMock in) throws Throwable {
|
|
||||||
return newSucceededFuture();
|
|
||||||
}
|
|
||||||
}).when(ctx).newSucceededFuture();
|
|
||||||
when(ctx.flush()).thenThrow(new AssertionFailedError("forbidden"));
|
when(ctx.flush()).thenThrow(new AssertionFailedError("forbidden"));
|
||||||
when(channel.alloc()).thenReturn(PooledByteBufAllocator.DEFAULT);
|
when(channel.alloc()).thenReturn(PooledByteBufAllocator.DEFAULT);
|
||||||
|
|
||||||
|
@ -337,13 +310,10 @@ public class DefaultHttp2ConnectionEncoderTest {
|
||||||
final Throwable cause = new RuntimeException("fake exception");
|
final Throwable cause = new RuntimeException("fake exception");
|
||||||
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(),
|
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(),
|
||||||
anyInt(), anyBoolean(), any(ChannelPromise.class)))
|
anyInt(), anyBoolean(), any(ChannelPromise.class)))
|
||||||
.then(new Answer<ChannelFuture>() {
|
.then((Answer<ChannelFuture>) invocationOnMock -> {
|
||||||
@Override
|
ChannelPromise promise = invocationOnMock.getArgument(8);
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) throws Throwable {
|
assertFalse(promise.isVoid());
|
||||||
ChannelPromise promise = invocationOnMock.getArgument(8);
|
return promise.setFailure(cause);
|
||||||
assertFalse(promise.isVoid());
|
|
||||||
return promise.setFailure(cause);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
createStream(STREAM_ID, false);
|
createStream(STREAM_ID, false);
|
||||||
// END_STREAM flag, so that a listener is added to the future.
|
// END_STREAM flag, so that a listener is added to the future.
|
||||||
|
@ -754,12 +724,9 @@ public class DefaultHttp2ConnectionEncoderTest {
|
||||||
// Fake an encoding error, like HPACK's HeaderListSizeException
|
// Fake an encoding error, like HPACK's HeaderListSizeException
|
||||||
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0),
|
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0),
|
||||||
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise)))
|
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise)))
|
||||||
.thenAnswer(new Answer<ChannelFuture>() {
|
.thenAnswer((Answer<ChannelFuture>) invocation -> {
|
||||||
@Override
|
promise.setFailure(ex);
|
||||||
public ChannelFuture answer(InvocationOnMock invocation) {
|
return promise;
|
||||||
promise.setFailure(ex);
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
writeAllFlowControlledFrames();
|
writeAllFlowControlledFrames();
|
||||||
|
@ -781,12 +748,9 @@ public class DefaultHttp2ConnectionEncoderTest {
|
||||||
// Fake an encoding error, like HPACK's HeaderListSizeException
|
// Fake an encoding error, like HPACK's HeaderListSizeException
|
||||||
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0),
|
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0),
|
||||||
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise)))
|
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise)))
|
||||||
.thenAnswer(new Answer<ChannelFuture>() {
|
.thenAnswer((Answer<ChannelFuture>) invocation -> {
|
||||||
@Override
|
promise.setFailure(ex);
|
||||||
public ChannelFuture answer(InvocationOnMock invocation) {
|
return promise;
|
||||||
promise.setFailure(ex);
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
writeAllFlowControlledFrames();
|
writeAllFlowControlledFrames();
|
||||||
|
@ -873,14 +837,11 @@ public class DefaultHttp2ConnectionEncoderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAllFlowControlledFrames() {
|
private void writeAllFlowControlledFrames() {
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
FlowControlled flowControlled = (FlowControlled) invocationOnMock.getArguments()[1];
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
flowControlled.write(ctx, Integer.MAX_VALUE);
|
||||||
FlowControlled flowControlled = (FlowControlled) invocationOnMock.getArguments()[1];
|
flowControlled.writeComplete();
|
||||||
flowControlled.write(ctx, Integer.MAX_VALUE);
|
return null;
|
||||||
flowControlled.writeComplete();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(remoteFlow).addFlowControlled(any(Http2Stream.class), payloadCaptor.capture());
|
}).when(remoteFlow).addFlowControlled(any(Http2Stream.class), payloadCaptor.capture());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,19 +88,13 @@ public class DefaultHttp2ConnectionTest {
|
||||||
server = new DefaultHttp2Connection(true);
|
server = new DefaultHttp2Connection(true);
|
||||||
client = new DefaultHttp2Connection(false);
|
client = new DefaultHttp2Connection(false);
|
||||||
client.addListener(clientListener);
|
client.addListener(clientListener);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocation -> {
|
||||||
@Override
|
assertNotNull(client.stream(((Http2Stream) invocation.getArgument(0)).id()));
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
return null;
|
||||||
assertNotNull(client.stream(((Http2Stream) invocation.getArgument(0)).id()));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener).onStreamClosed(any(Http2Stream.class));
|
}).when(clientListener).onStreamClosed(any(Http2Stream.class));
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocation -> {
|
||||||
@Override
|
assertNull(client.stream(((Http2Stream) invocation.getArgument(0)).id()));
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
return null;
|
||||||
assertNull(client.stream(((Http2Stream) invocation.getArgument(0)).id()));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener).onStreamRemoved(any(Http2Stream.class));
|
}).when(clientListener).onStreamRemoved(any(Http2Stream.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,13 +135,10 @@ public class DefaultHttp2ConnectionTest {
|
||||||
public void removeIndividualStreamsWhileCloseDoesNotNPE() throws InterruptedException, Http2Exception {
|
public void removeIndividualStreamsWhileCloseDoesNotNPE() throws InterruptedException, Http2Exception {
|
||||||
final Http2Stream streamA = client.local().createStream(3, false);
|
final Http2Stream streamA = client.local().createStream(3, false);
|
||||||
final Http2Stream streamB = client.remote().createStream(2, false);
|
final Http2Stream streamB = client.remote().createStream(2, false);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocation -> {
|
||||||
@Override
|
streamA.close();
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
streamB.close();
|
||||||
streamA.close();
|
return null;
|
||||||
streamB.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener2).onStreamClosed(any(Http2Stream.class));
|
}).when(clientListener2).onStreamClosed(any(Http2Stream.class));
|
||||||
try {
|
try {
|
||||||
client.addListener(clientListener2);
|
client.addListener(clientListener2);
|
||||||
|
@ -167,18 +158,12 @@ public class DefaultHttp2ConnectionTest {
|
||||||
}
|
}
|
||||||
final Promise<Void> promise = group.next().newPromise();
|
final Promise<Void> promise = group.next().newPromise();
|
||||||
final CountDownLatch latch = new CountDownLatch(client.numActiveStreams());
|
final CountDownLatch latch = new CountDownLatch(client.numActiveStreams());
|
||||||
client.forEachActiveStream(new Http2StreamVisitor() {
|
client.forEachActiveStream(stream -> {
|
||||||
@Override
|
client.close(promise).addListener((FutureListener<Void>) future -> {
|
||||||
public boolean visit(Http2Stream stream) {
|
assertTrue(promise.isDone());
|
||||||
client.close(promise).addListener(new FutureListener<Void>() {
|
latch.countDown();
|
||||||
@Override
|
});
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
return true;
|
||||||
assertTrue(promise.isDone());
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
@ -195,23 +180,17 @@ public class DefaultHttp2ConnectionTest {
|
||||||
final Promise<Void> promise = group.next().newPromise();
|
final Promise<Void> promise = group.next().newPromise();
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
try {
|
try {
|
||||||
client.forEachActiveStream(new Http2StreamVisitor() {
|
client.forEachActiveStream(stream -> {
|
||||||
@Override
|
// This close call is basically a noop, because the following statement will throw an exception.
|
||||||
public boolean visit(Http2Stream stream) throws Http2Exception {
|
client.close(promise);
|
||||||
// This close call is basically a noop, because the following statement will throw an exception.
|
// Do an invalid operation while iterating.
|
||||||
client.close(promise);
|
remote.createStream(3, false);
|
||||||
// Do an invalid operation while iterating.
|
return true;
|
||||||
remote.createStream(3, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (Http2Exception ignored) {
|
} catch (Http2Exception ignored) {
|
||||||
client.close(promise).addListener(new FutureListener<Void>() {
|
client.close(promise).addListener((FutureListener<Void>) future -> {
|
||||||
@Override
|
assertTrue(promise.isDone());
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
latch.countDown();
|
||||||
assertTrue(promise.isDone());
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||||
|
@ -590,12 +569,9 @@ public class DefaultHttp2ConnectionTest {
|
||||||
private void testRemoveAllStreams() throws InterruptedException {
|
private void testRemoveAllStreams() throws InterruptedException {
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final Promise<Void> promise = group.next().newPromise();
|
final Promise<Void> promise = group.next().newPromise();
|
||||||
client.close(promise).addListener(new FutureListener<Void>() {
|
client.close(promise).addListener((FutureListener<Void>) future -> {
|
||||||
@Override
|
assertTrue(promise.isDone());
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
latch.countDown();
|
||||||
assertTrue(promise.isDone());
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,16 +76,13 @@ public class DefaultHttp2FrameWriterTest {
|
||||||
|
|
||||||
http2HeadersEncoder = new DefaultHttp2HeadersEncoder();
|
http2HeadersEncoder = new DefaultHttp2HeadersEncoder();
|
||||||
|
|
||||||
Answer<Object> answer = new Answer<Object>() {
|
Answer<Object> answer = var1 -> {
|
||||||
@Override
|
Object msg = var1.getArgument(0);
|
||||||
public Object answer(InvocationOnMock var1) throws Throwable {
|
if (msg instanceof ByteBuf) {
|
||||||
Object msg = var1.getArgument(0);
|
outbound.writeBytes((ByteBuf) msg);
|
||||||
if (msg instanceof ByteBuf) {
|
|
||||||
outbound.writeBytes((ByteBuf) msg);
|
|
||||||
}
|
|
||||||
ReferenceCountUtil.release(msg);
|
|
||||||
return future;
|
|
||||||
}
|
}
|
||||||
|
ReferenceCountUtil.release(msg);
|
||||||
|
return future;
|
||||||
};
|
};
|
||||||
when(ctx.write(any())).then(answer);
|
when(ctx.write(any())).then(answer);
|
||||||
when(ctx.write(any(), any(ChannelPromise.class))).then(answer);
|
when(ctx.write(any(), any(ChannelPromise.class))).then(answer);
|
||||||
|
|
|
@ -691,12 +691,9 @@ public abstract class DefaultHttp2RemoteFlowControllerTest {
|
||||||
public void flowControlledWriteThrowsAnException() throws Exception {
|
public void flowControlledWriteThrowsAnException() throws Exception {
|
||||||
final Http2RemoteFlowController.FlowControlled flowControlled = mockedFlowControlledThatThrowsOnWrite();
|
final Http2RemoteFlowController.FlowControlled flowControlled = mockedFlowControlledThatThrowsOnWrite();
|
||||||
final Http2Stream stream = stream(STREAM_A);
|
final Http2Stream stream = stream(STREAM_A);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
stream.closeLocalSide();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) {
|
return null;
|
||||||
stream.closeLocalSide();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(flowControlled).error(any(ChannelHandlerContext.class), any(Throwable.class));
|
}).when(flowControlled).error(any(ChannelHandlerContext.class), any(Throwable.class));
|
||||||
|
|
||||||
int windowBefore = window(STREAM_A);
|
int windowBefore = window(STREAM_A);
|
||||||
|
@ -724,11 +721,8 @@ public abstract class DefaultHttp2RemoteFlowControllerTest {
|
||||||
final Http2RemoteFlowController.FlowControlled flowControlled = mockedFlowControlledThatThrowsOnWrite();
|
final Http2RemoteFlowController.FlowControlled flowControlled = mockedFlowControlledThatThrowsOnWrite();
|
||||||
final Http2Stream stream = stream(STREAM_A);
|
final Http2Stream stream = stream(STREAM_A);
|
||||||
final RuntimeException fakeException = new RuntimeException("error failed");
|
final RuntimeException fakeException = new RuntimeException("error failed");
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
throw fakeException;
|
||||||
public Void answer(InvocationOnMock invocationOnMock) {
|
|
||||||
throw fakeException;
|
|
||||||
}
|
|
||||||
}).when(flowControlled).error(any(ChannelHandlerContext.class), any(Throwable.class));
|
}).when(flowControlled).error(any(ChannelHandlerContext.class), any(Throwable.class));
|
||||||
|
|
||||||
int windowBefore = window(STREAM_A);
|
int windowBefore = window(STREAM_A);
|
||||||
|
@ -757,26 +751,15 @@ public abstract class DefaultHttp2RemoteFlowControllerTest {
|
||||||
mock(Http2RemoteFlowController.FlowControlled.class);
|
mock(Http2RemoteFlowController.FlowControlled.class);
|
||||||
Http2Stream streamA = stream(STREAM_A);
|
Http2Stream streamA = stream(STREAM_A);
|
||||||
final AtomicInteger size = new AtomicInteger(150);
|
final AtomicInteger size = new AtomicInteger(150);
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) invocationOnMock -> size.get()).when(flowControlled).size();
|
||||||
@Override
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
|
size.addAndGet(-50);
|
||||||
return size.get();
|
return null;
|
||||||
}
|
|
||||||
}).when(flowControlled).size();
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
|
||||||
size.addAndGet(-50);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(flowControlled).write(any(ChannelHandlerContext.class), anyInt());
|
}).when(flowControlled).write(any(ChannelHandlerContext.class), anyInt());
|
||||||
|
|
||||||
final Http2Stream stream = stream(STREAM_A);
|
final Http2Stream stream = stream(STREAM_A);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
throw new RuntimeException("writeComplete failed");
|
||||||
public Void answer(InvocationOnMock invocationOnMock) {
|
|
||||||
throw new RuntimeException("writeComplete failed");
|
|
||||||
}
|
|
||||||
}).when(flowControlled).writeComplete();
|
}).when(flowControlled).writeComplete();
|
||||||
|
|
||||||
int windowBefore = window(STREAM_A);
|
int windowBefore = window(STREAM_A);
|
||||||
|
@ -807,12 +790,9 @@ public abstract class DefaultHttp2RemoteFlowControllerTest {
|
||||||
when(flowControlled.size()).thenReturn(100);
|
when(flowControlled.size()).thenReturn(100);
|
||||||
doThrow(new RuntimeException("write failed"))
|
doThrow(new RuntimeException("write failed"))
|
||||||
.when(flowControlled).write(any(ChannelHandlerContext.class), anyInt());
|
.when(flowControlled).write(any(ChannelHandlerContext.class), anyInt());
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
stream.close();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) {
|
return null;
|
||||||
stream.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(flowControlled).error(any(ChannelHandlerContext.class), any(Throwable.class));
|
}).when(flowControlled).error(any(ChannelHandlerContext.class), any(Throwable.class));
|
||||||
|
|
||||||
controller.addFlowControlled(stream, flowControlled);
|
controller.addFlowControlled(stream, flowControlled);
|
||||||
|
@ -960,13 +940,10 @@ public abstract class DefaultHttp2RemoteFlowControllerTest {
|
||||||
final Http2RemoteFlowController.FlowControlled flowControlled =
|
final Http2RemoteFlowController.FlowControlled flowControlled =
|
||||||
mock(Http2RemoteFlowController.FlowControlled.class);
|
mock(Http2RemoteFlowController.FlowControlled.class);
|
||||||
when(flowControlled.size()).thenReturn(100);
|
when(flowControlled.size()).thenReturn(100);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) in -> {
|
||||||
@Override
|
// Write most of the bytes and then fail
|
||||||
public Void answer(InvocationOnMock in) throws Throwable {
|
when(flowControlled.size()).thenReturn(10);
|
||||||
// Write most of the bytes and then fail
|
throw new RuntimeException("Write failed");
|
||||||
when(flowControlled.size()).thenReturn(10);
|
|
||||||
throw new RuntimeException("Write failed");
|
|
||||||
}
|
|
||||||
}).when(flowControlled).write(any(ChannelHandlerContext.class), anyInt());
|
}).when(flowControlled).write(any(ChannelHandlerContext.class), anyInt());
|
||||||
return flowControlled;
|
return flowControlled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,28 +51,20 @@ public final class HashCollisionTest {
|
||||||
// More "english words" can be found here:
|
// More "english words" can be found here:
|
||||||
// https://gist.github.com/Scottmitch/de2f03912778016ecee3c140478f07e0#file-englishwords-txt
|
// https://gist.github.com/Scottmitch/de2f03912778016ecee3c140478f07e0#file-englishwords-txt
|
||||||
|
|
||||||
Map<Integer, List<CharSequence>> dups = calculateDuplicates(strings, new Function<CharSequence, Integer>() {
|
Map<Integer, List<CharSequence>> dups = calculateDuplicates(strings, string -> {
|
||||||
@Override
|
int h = 0;
|
||||||
public Integer apply(CharSequence string) {
|
for (int i = 0; i < string.length(); ++i) {
|
||||||
int h = 0;
|
// masking with 0x1F reduces the number of overall bits that impact the hash code but makes the hash
|
||||||
for (int i = 0; i < string.length(); ++i) {
|
// code the same regardless of character case (upper case or lower case hash is the same).
|
||||||
// masking with 0x1F reduces the number of overall bits that impact the hash code but makes the hash
|
h = h * 31 + (string.charAt(i) & 0x1F);
|
||||||
// code the same regardless of character case (upper case or lower case hash is the same).
|
|
||||||
h = h * 31 + (string.charAt(i) & 0x1F);
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
}
|
||||||
|
return h;
|
||||||
});
|
});
|
||||||
PrintStream writer = System.out;
|
PrintStream writer = System.out;
|
||||||
writer.println("==Old Duplicates==");
|
writer.println("==Old Duplicates==");
|
||||||
printResults(writer, dups);
|
printResults(writer, dups);
|
||||||
|
|
||||||
dups = calculateDuplicates(strings, new Function<CharSequence, Integer>() {
|
dups = calculateDuplicates(strings, PlatformDependent::hashCodeAscii);
|
||||||
@Override
|
|
||||||
public Integer apply(CharSequence string) {
|
|
||||||
return PlatformDependent.hashCodeAscii(string);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
writer.println();
|
writer.println();
|
||||||
writer.println("==New Duplicates==");
|
writer.println("==New Duplicates==");
|
||||||
printResults(writer, dups);
|
printResults(writer, dups);
|
||||||
|
|
|
@ -180,12 +180,7 @@ final class HpackTestCase {
|
||||||
private static byte[] encode(HpackEncoder hpackEncoder, List<HpackHeaderField> headers, int maxHeaderTableSize,
|
private static byte[] encode(HpackEncoder hpackEncoder, List<HpackHeaderField> headers, int maxHeaderTableSize,
|
||||||
final boolean sensitive) throws Http2Exception {
|
final boolean sensitive) throws Http2Exception {
|
||||||
Http2Headers http2Headers = toHttp2Headers(headers);
|
Http2Headers http2Headers = toHttp2Headers(headers);
|
||||||
Http2HeadersEncoder.SensitivityDetector sensitivityDetector = new Http2HeadersEncoder.SensitivityDetector() {
|
Http2HeadersEncoder.SensitivityDetector sensitivityDetector = (name, value) -> sensitive;
|
||||||
@Override
|
|
||||||
public boolean isSensitive(CharSequence name, CharSequence value) {
|
|
||||||
return sensitive;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ByteBuf buffer = Unpooled.buffer();
|
ByteBuf buffer = Unpooled.buffer();
|
||||||
try {
|
try {
|
||||||
if (maxHeaderTableSize != -1) {
|
if (maxHeaderTableSize != -1) {
|
||||||
|
|
|
@ -154,25 +154,19 @@ public class Http2ConnectionHandlerTest {
|
||||||
when(encoder.frameWriter()).thenReturn(frameWriter);
|
when(encoder.frameWriter()).thenReturn(frameWriter);
|
||||||
when(encoder.flowController()).thenReturn(remoteFlow);
|
when(encoder.flowController()).thenReturn(remoteFlow);
|
||||||
when(decoder.flowController()).thenReturn(localFlow);
|
when(decoder.flowController()).thenReturn(localFlow);
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
doAnswer((Answer<ChannelFuture>) invocation -> {
|
||||||
@Override
|
ByteBuf buf = invocation.getArgument(3);
|
||||||
public ChannelFuture answer(InvocationOnMock invocation) throws Throwable {
|
goAwayDebugCap = buf.toString(UTF_8);
|
||||||
ByteBuf buf = invocation.getArgument(3);
|
buf.release();
|
||||||
goAwayDebugCap = buf.toString(UTF_8);
|
return future;
|
||||||
buf.release();
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
}).when(frameWriter).writeGoAway(
|
}).when(frameWriter).writeGoAway(
|
||||||
any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class), any(ChannelPromise.class));
|
any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class), any(ChannelPromise.class));
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
doAnswer((Answer<ChannelFuture>) invocation -> {
|
||||||
@Override
|
Object o = invocation.getArguments()[0];
|
||||||
public ChannelFuture answer(InvocationOnMock invocation) throws Throwable {
|
if (o instanceof ChannelFutureListener) {
|
||||||
Object o = invocation.getArguments()[0];
|
((ChannelFutureListener) o).operationComplete(future);
|
||||||
if (o instanceof ChannelFutureListener) {
|
|
||||||
((ChannelFutureListener) o).operationComplete(future);
|
|
||||||
}
|
|
||||||
return future;
|
|
||||||
}
|
}
|
||||||
|
return future;
|
||||||
}).when(future).addListener(any(GenericFutureListener.class));
|
}).when(future).addListener(any(GenericFutureListener.class));
|
||||||
when(future.cause()).thenReturn(fakeException);
|
when(future.cause()).thenReturn(fakeException);
|
||||||
when(future.channel()).thenReturn(channel);
|
when(future.channel()).thenReturn(channel);
|
||||||
|
@ -182,15 +176,12 @@ public class Http2ConnectionHandlerTest {
|
||||||
when(remote.flowController()).thenReturn(remoteFlowController);
|
when(remote.flowController()).thenReturn(remoteFlowController);
|
||||||
when(connection.local()).thenReturn(local);
|
when(connection.local()).thenReturn(local);
|
||||||
when(local.flowController()).thenReturn(localFlowController);
|
when(local.flowController()).thenReturn(localFlowController);
|
||||||
doAnswer(new Answer<Http2Stream>() {
|
doAnswer((Answer<Http2Stream>) in -> {
|
||||||
@Override
|
Http2StreamVisitor visitor = in.getArgument(0);
|
||||||
public Http2Stream answer(InvocationOnMock in) throws Throwable {
|
if (!visitor.visit(stream)) {
|
||||||
Http2StreamVisitor visitor = in.getArgument(0);
|
return stream;
|
||||||
if (!visitor.visit(stream)) {
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}).when(connection).forEachActiveStream(any(Http2StreamVisitor.class));
|
}).when(connection).forEachActiveStream(any(Http2StreamVisitor.class));
|
||||||
when(connection.stream(NON_EXISTANT_STREAM_ID)).thenReturn(null);
|
when(connection.stream(NON_EXISTANT_STREAM_ID)).thenReturn(null);
|
||||||
when(connection.numActiveStreams()).thenReturn(1);
|
when(connection.numActiveStreams()).thenReturn(1);
|
||||||
|
@ -205,13 +196,10 @@ public class Http2ConnectionHandlerTest {
|
||||||
when(ctx.voidPromise()).thenReturn(voidPromise);
|
when(ctx.voidPromise()).thenReturn(voidPromise);
|
||||||
when(ctx.write(any())).thenReturn(future);
|
when(ctx.write(any())).thenReturn(future);
|
||||||
when(ctx.executor()).thenReturn(executor);
|
when(ctx.executor()).thenReturn(executor);
|
||||||
doAnswer(new Answer() {
|
doAnswer(in -> {
|
||||||
@Override
|
Object msg = in.getArgument(0);
|
||||||
public Object answer(InvocationOnMock in) throws Throwable {
|
ReferenceCountUtil.release(msg);
|
||||||
Object msg = in.getArgument(0);
|
return null;
|
||||||
ReferenceCountUtil.release(msg);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(ctx).fireChannelRead(any());
|
}).when(ctx).fireChannelRead(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,15 +249,12 @@ public class Http2ConnectionHandlerTest {
|
||||||
Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE;
|
Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE;
|
||||||
|
|
||||||
final AtomicBoolean verified = new AtomicBoolean(false);
|
final AtomicBoolean verified = new AtomicBoolean(false);
|
||||||
final Answer verifier = new Answer() {
|
final Answer verifier = in -> {
|
||||||
@Override
|
assertTrue(in.getArgument(0).equals(evt)); // sanity check...
|
||||||
public Object answer(final InvocationOnMock in) throws Throwable {
|
verify(ctx).write(eq(connectionPrefaceBuf()));
|
||||||
assertTrue(in.getArgument(0).equals(evt)); // sanity check...
|
verify(encoder).writeSettings(eq(ctx), any(Http2Settings.class), any(ChannelPromise.class));
|
||||||
verify(ctx).write(eq(connectionPrefaceBuf()));
|
verified.set(true);
|
||||||
verify(encoder).writeSettings(eq(ctx), any(Http2Settings.class), any(ChannelPromise.class));
|
return null;
|
||||||
verified.set(true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
doAnswer(verifier).when(ctx).fireUserEventTriggered(evt);
|
doAnswer(verifier).when(ctx).fireUserEventTriggered(evt);
|
||||||
|
@ -562,23 +547,16 @@ public class Http2ConnectionHandlerTest {
|
||||||
handler = newHandler();
|
handler = newHandler();
|
||||||
when(future.isDone()).thenReturn(true);
|
when(future.isDone()).thenReturn(true);
|
||||||
when(future.isSuccess()).thenReturn(true);
|
when(future.isSuccess()).thenReturn(true);
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
doAnswer((Answer<ChannelFuture>) invocation -> {
|
||||||
@Override
|
Object[] args = invocation.getArguments();
|
||||||
public ChannelFuture answer(InvocationOnMock invocation) throws Throwable {
|
GenericFutureListener<ChannelFuture> listener = (GenericFutureListener<ChannelFuture>) args[0];
|
||||||
Object[] args = invocation.getArguments();
|
// Simulate that all streams have become inactive by the time the future completes.
|
||||||
GenericFutureListener<ChannelFuture> listener = (GenericFutureListener<ChannelFuture>) args[0];
|
doAnswer((Answer<Http2Stream>) in -> null).when(connection).forEachActiveStream(
|
||||||
// Simulate that all streams have become inactive by the time the future completes.
|
any(Http2StreamVisitor.class));
|
||||||
doAnswer(new Answer<Http2Stream>() {
|
when(connection.numActiveStreams()).thenReturn(0);
|
||||||
@Override
|
// Simulate the future being completed.
|
||||||
public Http2Stream answer(InvocationOnMock in) throws Throwable {
|
listener.operationComplete(future);
|
||||||
return null;
|
return future;
|
||||||
}
|
|
||||||
}).when(connection).forEachActiveStream(any(Http2StreamVisitor.class));
|
|
||||||
when(connection.numActiveStreams()).thenReturn(0);
|
|
||||||
// Simulate the future being completed.
|
|
||||||
listener.operationComplete(future);
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
}).when(future).addListener(any(GenericFutureListener.class));
|
}).when(future).addListener(any(GenericFutureListener.class));
|
||||||
handler.close(ctx, promise);
|
handler.close(ctx, promise);
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
|
@ -597,12 +575,9 @@ public class Http2ConnectionHandlerTest {
|
||||||
long errorCode = Http2Error.INTERNAL_ERROR.code();
|
long errorCode = Http2Error.INTERNAL_ERROR.code();
|
||||||
when(future.isDone()).thenReturn(true);
|
when(future.isDone()).thenReturn(true);
|
||||||
when(future.isSuccess()).thenReturn(true);
|
when(future.isSuccess()).thenReturn(true);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocation -> {
|
||||||
@Override
|
((GenericFutureListener) invocation.getArgument(0)).operationComplete(future);
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
return null;
|
||||||
((GenericFutureListener) invocation.getArgument(0)).operationComplete(future);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(future).addListener(any(GenericFutureListener.class));
|
}).when(future).addListener(any(GenericFutureListener.class));
|
||||||
handler = newHandler();
|
handler = newHandler();
|
||||||
handler.goAway(ctx, STREAM_ID, errorCode, data, promise);
|
handler.goAway(ctx, STREAM_ID, errorCode, data, promise);
|
||||||
|
@ -645,11 +620,8 @@ public class Http2ConnectionHandlerTest {
|
||||||
|
|
||||||
when(connection.goAwaySent()).thenReturn(true);
|
when(connection.goAwaySent()).thenReturn(true);
|
||||||
when(remote.lastStreamKnownByPeer()).thenReturn(STREAM_ID);
|
when(remote.lastStreamKnownByPeer()).thenReturn(STREAM_ID);
|
||||||
doAnswer(new Answer<Boolean>() {
|
doAnswer((Answer<Boolean>) invocationOnMock -> {
|
||||||
@Override
|
throw new IllegalStateException();
|
||||||
public Boolean answer(InvocationOnMock invocationOnMock) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
}).when(connection).goAwaySent(anyInt(), anyLong(), any(ByteBuf.class));
|
}).when(connection).goAwaySent(anyInt(), anyLong(), any(ByteBuf.class));
|
||||||
handler.goAway(ctx, STREAM_ID + 2, errorCode, data, promise);
|
handler.goAway(ctx, STREAM_ID + 2, errorCode, data, promise);
|
||||||
assertTrue(promise.isDone());
|
assertTrue(promise.isDone());
|
||||||
|
@ -665,18 +637,15 @@ public class Http2ConnectionHandlerTest {
|
||||||
long errorCode = Http2Error.INTERNAL_ERROR.code();
|
long errorCode = Http2Error.INTERNAL_ERROR.code();
|
||||||
handler = newHandler();
|
handler = newHandler();
|
||||||
final Throwable cause = new RuntimeException("fake exception");
|
final Throwable cause = new RuntimeException("fake exception");
|
||||||
doAnswer(new Answer<ChannelFuture>() {
|
doAnswer((Answer<ChannelFuture>) invocation -> {
|
||||||
@Override
|
ChannelPromise promise = invocation.getArgument(4);
|
||||||
public ChannelFuture answer(InvocationOnMock invocation) throws Throwable {
|
assertFalse(promise.isVoid());
|
||||||
ChannelPromise promise = invocation.getArgument(4);
|
// This is what DefaultHttp2FrameWriter does... I hate mocking :-(.
|
||||||
assertFalse(promise.isVoid());
|
SimpleChannelPromiseAggregator aggregatedPromise =
|
||||||
// This is what DefaultHttp2FrameWriter does... I hate mocking :-(.
|
new SimpleChannelPromiseAggregator(promise, channel, ImmediateEventExecutor.INSTANCE);
|
||||||
SimpleChannelPromiseAggregator aggregatedPromise =
|
aggregatedPromise.newPromise();
|
||||||
new SimpleChannelPromiseAggregator(promise, channel, ImmediateEventExecutor.INSTANCE);
|
aggregatedPromise.doneAllocatingPromises();
|
||||||
aggregatedPromise.newPromise();
|
return aggregatedPromise.setFailure(cause);
|
||||||
aggregatedPromise.doneAllocatingPromises();
|
|
||||||
return aggregatedPromise.setFailure(cause);
|
|
||||||
}
|
|
||||||
}).when(frameWriter).writeGoAway(
|
}).when(frameWriter).writeGoAway(
|
||||||
any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class), any(ChannelPromise.class));
|
any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class), any(ChannelPromise.class));
|
||||||
handler.goAway(ctx, STREAM_ID, errorCode, data, newVoidPromise(channel));
|
handler.goAway(ctx, STREAM_ID, errorCode, data, newVoidPromise(channel));
|
||||||
|
@ -742,13 +711,10 @@ public class Http2ConnectionHandlerTest {
|
||||||
final Throwable cause = new RuntimeException("fake exception");
|
final Throwable cause = new RuntimeException("fake exception");
|
||||||
when(stream.id()).thenReturn(STREAM_ID);
|
when(stream.id()).thenReturn(STREAM_ID);
|
||||||
when(frameWriter.writeRstStream(eq(ctx), eq(streamId), anyLong(), any(ChannelPromise.class)))
|
when(frameWriter.writeRstStream(eq(ctx), eq(streamId), anyLong(), any(ChannelPromise.class)))
|
||||||
.then(new Answer<ChannelFuture>() {
|
.then((Answer<ChannelFuture>) invocationOnMock -> {
|
||||||
@Override
|
ChannelPromise promise = invocationOnMock.getArgument(3);
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) throws Throwable {
|
assertFalse(promise.isVoid());
|
||||||
ChannelPromise promise = invocationOnMock.getArgument(3);
|
return promise.setFailure(cause);
|
||||||
assertFalse(promise.isVoid());
|
|
||||||
return promise.setFailure(cause);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
handler.resetStream(ctx, streamId, STREAM_CLOSED.code(), newVoidPromise(channel));
|
handler.resetStream(ctx, streamId, STREAM_CLOSED.code(), newVoidPromise(channel));
|
||||||
verify(frameWriter).writeRstStream(eq(ctx), eq(streamId), anyLong(), any(ChannelPromise.class));
|
verify(frameWriter).writeRstStream(eq(ctx), eq(streamId), anyLong(), any(ChannelPromise.class));
|
||||||
|
|
|
@ -148,50 +148,38 @@ public class Http2ConnectionRoundtripTest {
|
||||||
public void inflightFrameAfterStreamResetShouldNotMakeConnectionUnusable() throws Exception {
|
public void inflightFrameAfterStreamResetShouldNotMakeConnectionUnusable() throws Exception {
|
||||||
bootstrapEnv(1, 1, 2, 1);
|
bootstrapEnv(1, 1, 2, 1);
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(invocationOnMock -> {
|
||||||
@Override
|
ChannelHandlerContext ctx = invocationOnMock.getArgument(0);
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
http2Server.encoder().writeHeaders(ctx,
|
||||||
ChannelHandlerContext ctx = invocationOnMock.getArgument(0);
|
(Integer) invocationOnMock.getArgument(1),
|
||||||
http2Server.encoder().writeHeaders(ctx,
|
(Http2Headers) invocationOnMock.getArgument(2),
|
||||||
(Integer) invocationOnMock.getArgument(1),
|
0,
|
||||||
(Http2Headers) invocationOnMock.getArgument(2),
|
false,
|
||||||
0,
|
ctx.newPromise());
|
||||||
false,
|
http2Server.flush(ctx);
|
||||||
ctx.newPromise());
|
return null;
|
||||||
http2Server.flush(ctx);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
|
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
|
||||||
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
|
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
latch.countDown();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
return null;
|
||||||
latch.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5), any(Http2Headers.class),
|
}).when(clientListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5), any(Http2Headers.class),
|
||||||
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
|
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
|
||||||
|
|
||||||
// Create a single stream by sending a HEADERS frame to the server.
|
// Create a single stream by sending a HEADERS frame to the server.
|
||||||
final short weight = 16;
|
final short weight = 16;
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, weight, false, 0, false, newPromise());
|
||||||
public void run() throws Http2Exception {
|
http2Client.flush(ctx());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, weight, false, 0, false, newPromise());
|
http2Client.encoder().writeRstStream(ctx(), 3, Http2Error.INTERNAL_ERROR.code(), newPromise());
|
||||||
http2Client.flush(ctx());
|
http2Client.flush(ctx());
|
||||||
http2Client.encoder().writeRstStream(ctx(), 3, Http2Error.INTERNAL_ERROR.code(), newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, weight, false, 0, false, newPromise());
|
||||||
public void run() throws Http2Exception {
|
http2Client.flush(ctx());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, weight, false, 0, false, newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(latch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(latch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -204,13 +192,10 @@ public class Http2ConnectionRoundtripTest {
|
||||||
// Create a single stream by sending a HEADERS frame to the server.
|
// Create a single stream by sending a HEADERS frame to the server.
|
||||||
final short weight = 16;
|
final short weight = 16;
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, weight, false, 0, true,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, weight, false, 0, true,
|
http2Client.flush(ctx());
|
||||||
newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -245,68 +230,45 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
serverSettingsAckLatch1.countDown();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
serverSettingsAckLatch2.countDown();
|
||||||
serverSettingsAckLatch1.countDown();
|
return null;
|
||||||
serverSettingsAckLatch2.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(serverListener).onSettingsAckRead(any(ChannelHandlerContext.class));
|
}).when(serverListener).onSettingsAckRead(any(ChannelHandlerContext.class));
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
clientSettingsLatch1.countDown();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
return null;
|
||||||
clientSettingsLatch1.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener).onSettingsRead(any(ChannelHandlerContext.class), any(Http2Settings.class));
|
}).when(clientListener).onSettingsRead(any(ChannelHandlerContext.class), any(Http2Settings.class));
|
||||||
|
|
||||||
// Manually add a listener for when we receive the expected headers on the server.
|
// Manually add a listener for when we receive the expected headers on the server.
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
serverRevHeadersLatch.countDown();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
return null;
|
||||||
serverRevHeadersLatch.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5), eq(headers),
|
}).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5), eq(headers),
|
||||||
anyInt(), anyShort(), anyBoolean(), eq(0), eq(true));
|
anyInt(), anyShort(), anyBoolean(), eq(0), eq(true));
|
||||||
|
|
||||||
// Set the maxHeaderListSize to 100 so we may be able to write some headers, but not all. We want to verify
|
// Set the maxHeaderListSize to 100 so we may be able to write some headers, but not all. We want to verify
|
||||||
// that we don't corrupt state if some can be written but not all.
|
// that we don't corrupt state if some can be written but not all.
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
http2Server.encoder().writeSettings(serverCtx(),
|
||||||
public void run() throws Http2Exception {
|
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
||||||
http2Server.encoder().writeSettings(serverCtx(),
|
.maxHeaderListSize(100),
|
||||||
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
serverNewPromise());
|
||||||
.maxHeaderListSize(100),
|
http2Server.flush(serverCtx());
|
||||||
serverNewPromise());
|
|
||||||
http2Server.flush(serverCtx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, false, newPromise())
|
||||||
public void run() throws Http2Exception {
|
.addListener((ChannelFutureListener) future -> clientHeadersWriteException.set(future.cause()));
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, false, newPromise())
|
// It is expected that this write should fail locally and the remote peer will never see this.
|
||||||
.addListener(new ChannelFutureListener() {
|
http2Client.encoder().writeData(ctx(), 3, Unpooled.buffer(), 0, true, newPromise())
|
||||||
@Override
|
.addListener((ChannelFutureListener) future -> {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
clientDataWriteException.set(future.cause());
|
||||||
clientHeadersWriteException.set(future.cause());
|
clientDataWrite.countDown();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// It is expected that this write should fail locally and the remote peer will never see this.
|
http2Client.flush(ctx());
|
||||||
http2Client.encoder().writeData(ctx(), 3, Unpooled.buffer(), 0, true, newPromise())
|
|
||||||
.addListener(new ChannelFutureListener() {
|
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
clientDataWriteException.set(future.cause());
|
|
||||||
clientDataWrite.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(clientDataWrite.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(clientDataWrite.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -314,33 +276,24 @@ public class Http2ConnectionRoundtripTest {
|
||||||
assertNotNull("Data on closed stream should fail!", clientDataWriteException.get());
|
assertNotNull("Data on closed stream should fail!", clientDataWriteException.get());
|
||||||
|
|
||||||
// Set the maxHeaderListSize to the max value so we can send the headers.
|
// Set the maxHeaderListSize to the max value so we can send the headers.
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
http2Server.encoder().writeSettings(serverCtx(),
|
||||||
public void run() throws Http2Exception {
|
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
||||||
http2Server.encoder().writeSettings(serverCtx(),
|
.maxHeaderListSize(Http2CodecUtil.MAX_HEADER_LIST_SIZE),
|
||||||
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
serverNewPromise());
|
||||||
.maxHeaderListSize(Http2CodecUtil.MAX_HEADER_LIST_SIZE),
|
http2Server.flush(serverCtx());
|
||||||
serverNewPromise());
|
|
||||||
http2Server.flush(serverCtx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(clientSettingsLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(clientSettingsLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
assertTrue(serverSettingsAckLatch2.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch2.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, true,
|
||||||
public void run() throws Http2Exception {
|
newPromise()).addListener((ChannelFutureListener) future -> {
|
||||||
http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, true,
|
clientHeadersWriteException2.set(future.cause());
|
||||||
newPromise()).addListener(new ChannelFutureListener() {
|
clientHeadersLatch.countDown();
|
||||||
@Override
|
});
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
http2Client.flush(ctx());
|
||||||
clientHeadersWriteException2.set(future.cause());
|
|
||||||
clientHeadersLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(clientHeadersLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(clientHeadersLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -371,69 +324,54 @@ public class Http2ConnectionRoundtripTest {
|
||||||
final byte[] data = new byte[] {1, 2, 3, 4, 5};
|
final byte[] data = new byte[] {1, 2, 3, 4, 5};
|
||||||
final ByteArrayOutputStream out = new ByteArrayOutputStream(data.length);
|
final ByteArrayOutputStream out = new ByteArrayOutputStream(data.length);
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
serverSettingsAckLatch1.countDown();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
serverSettingsAckLatch2.countDown();
|
||||||
serverSettingsAckLatch1.countDown();
|
return null;
|
||||||
serverSettingsAckLatch2.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(serverListener).onSettingsAckRead(any(ChannelHandlerContext.class));
|
}).when(serverListener).onSettingsAckRead(any(ChannelHandlerContext.class));
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) in -> {
|
||||||
@Override
|
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
||||||
public Integer answer(InvocationOnMock in) throws Throwable {
|
int padding = (Integer) in.getArguments()[3];
|
||||||
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
int processedBytes = buf.readableBytes() + padding;
|
||||||
int padding = (Integer) in.getArguments()[3];
|
|
||||||
int processedBytes = buf.readableBytes() + padding;
|
|
||||||
|
|
||||||
buf.readBytes(out, buf.readableBytes());
|
buf.readBytes(out, buf.readableBytes());
|
||||||
serverDataLatch.countDown();
|
serverDataLatch.countDown();
|
||||||
return processedBytes;
|
return processedBytes;
|
||||||
}
|
|
||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), anyBoolean());
|
any(ByteBuf.class), eq(0), anyBoolean());
|
||||||
|
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
|
|
||||||
// The server initially reduces the connection flow control window to 0.
|
// The server initially reduces the connection flow control window to 0.
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
http2Server.encoder().writeSettings(serverCtx(),
|
||||||
public void run() throws Http2Exception {
|
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
||||||
http2Server.encoder().writeSettings(serverCtx(),
|
.initialWindowSize(0),
|
||||||
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
serverNewPromise());
|
||||||
.initialWindowSize(0),
|
http2Server.flush(serverCtx());
|
||||||
serverNewPromise());
|
|
||||||
http2Server.flush(serverCtx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
||||||
// The client should now attempt to send data, but the window size is 0 so it will be queued in the flow
|
// The client should now attempt to send data, but the window size is 0 so it will be queued in the flow
|
||||||
// controller.
|
// controller.
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
http2Client.encoder().writeData(ctx(), 3, Unpooled.wrappedBuffer(data), 0, true, newPromise());
|
||||||
newPromise());
|
http2Client.flush(ctx());
|
||||||
http2Client.encoder().writeData(ctx(), 3, Unpooled.wrappedBuffer(data), 0, true, newPromise());
|
clientWriteDataLatch.countDown();
|
||||||
http2Client.flush(ctx());
|
|
||||||
clientWriteDataLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(clientWriteDataLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(clientWriteDataLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
||||||
// Now the server opens up the connection window to allow the client to send the pending data.
|
// Now the server opens up the connection window to allow the client to send the pending data.
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
http2Server.encoder().writeSettings(serverCtx(),
|
||||||
public void run() throws Http2Exception {
|
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
||||||
http2Server.encoder().writeSettings(serverCtx(),
|
.initialWindowSize(data.length),
|
||||||
new Http2Settings().copyFrom(http2Server.decoder().localSettings())
|
serverNewPromise());
|
||||||
.initialWindowSize(data.length),
|
http2Server.flush(serverCtx());
|
||||||
serverNewPromise());
|
|
||||||
http2Server.flush(serverCtx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch2.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch2.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -454,14 +392,11 @@ public class Http2ConnectionRoundtripTest {
|
||||||
bootstrapEnv(1, 1, 2, 0);
|
bootstrapEnv(1, 1, 2, 0);
|
||||||
|
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writePriority(ctx(), 5, 3, (short) 14, false, newPromise());
|
||||||
public void run() throws Http2Exception {
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
||||||
http2Client.encoder().writePriority(ctx(), 5, 3, (short) 14, false, newPromise());
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
http2Client.flush(ctx());
|
||||||
newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -486,15 +421,12 @@ public class Http2ConnectionRoundtripTest {
|
||||||
bootstrapEnv(1, 1, 1, 0);
|
bootstrapEnv(1, 1, 1, 0);
|
||||||
|
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0, false,
|
http2Client.encoder().frameWriter().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
||||||
newPromise());
|
newPromise());
|
||||||
http2Client.encoder().frameWriter().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
http2Client.flush(ctx());
|
||||||
newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -525,24 +457,18 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
final int streamId = 3;
|
final int streamId = 3;
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), streamId, headers, CONNECTION_STREAM_ID,
|
||||||
public void run() throws Http2Exception {
|
DEFAULT_PRIORITY_WEIGHT, false, 0, false, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), streamId, headers, CONNECTION_STREAM_ID,
|
http2Client.encoder().writeRstStream(ctx(), streamId, Http2Error.CANCEL.code(), newPromise());
|
||||||
DEFAULT_PRIORITY_WEIGHT, false, 0, false, newPromise());
|
http2Client.flush(ctx());
|
||||||
http2Client.encoder().writeRstStream(ctx(), streamId, Http2Error.CANCEL.code(), newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
if (streamId == (Integer) invocationOnMock.getArgument(1)) {
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
serverGotRstLatch.countDown();
|
||||||
if (streamId == (Integer) invocationOnMock.getArgument(1)) {
|
|
||||||
serverGotRstLatch.countDown();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}).when(serverListener).onRstStreamRead(any(ChannelHandlerContext.class), eq(streamId), anyLong());
|
}).when(serverListener).onRstStreamRead(any(ChannelHandlerContext.class), eq(streamId), anyLong());
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -552,19 +478,13 @@ public class Http2ConnectionRoundtripTest {
|
||||||
anyShort(), anyBoolean(), anyInt(), eq(false));
|
anyShort(), anyBoolean(), anyInt(), eq(false));
|
||||||
|
|
||||||
// Now have the server attempt to send a headers frame simulating some asynchronous work.
|
// Now have the server attempt to send a headers frame simulating some asynchronous work.
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
http2Server.encoder().writeHeaders(serverCtx(), streamId, headers, 0, true, serverNewPromise())
|
||||||
public void run() throws Http2Exception {
|
.addListener((ChannelFutureListener) future -> {
|
||||||
http2Server.encoder().writeHeaders(serverCtx(), streamId, headers, 0, true, serverNewPromise())
|
serverWriteHeadersCauseRef.set(future.cause());
|
||||||
.addListener(new ChannelFutureListener() {
|
serverWriteHeadersLatch.countDown();
|
||||||
@Override
|
});
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
http2Server.flush(serverCtx());
|
||||||
serverWriteHeadersCauseRef.set(future.cause());
|
|
||||||
serverWriteHeadersLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
http2Server.flush(serverCtx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverWriteHeadersLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverWriteHeadersLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -586,22 +506,14 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
// Create a latch to track when the close occurs.
|
// Create a latch to track when the close occurs.
|
||||||
final CountDownLatch closeLatch = new CountDownLatch(1);
|
final CountDownLatch closeLatch = new CountDownLatch(1);
|
||||||
clientChannel.closeFuture().addListener(new ChannelFutureListener() {
|
clientChannel.closeFuture().addListener((ChannelFutureListener) future -> closeLatch.countDown());
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
closeLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a single stream by sending a HEADERS frame to the server.
|
// Create a single stream by sending a HEADERS frame to the server.
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
http2Client.flush(ctx());
|
||||||
newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the server to create the stream.
|
// Wait for the server to create the stream.
|
||||||
|
@ -632,21 +544,13 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
// Create a latch to track when the close occurs.
|
// Create a latch to track when the close occurs.
|
||||||
final CountDownLatch closeLatch = new CountDownLatch(1);
|
final CountDownLatch closeLatch = new CountDownLatch(1);
|
||||||
clientChannel.closeFuture().addListener(new ChannelFutureListener() {
|
clientChannel.closeFuture().addListener((ChannelFutureListener) future -> closeLatch.countDown());
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
closeLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a single stream by sending a HEADERS frame to the server.
|
// Create a single stream by sending a HEADERS frame to the server.
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
http2Client.flush(ctx());
|
||||||
newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the server to create the stream.
|
// Wait for the server to create the stream.
|
||||||
|
@ -690,37 +594,34 @@ public class Http2ConnectionRoundtripTest {
|
||||||
bootstrapEnv(1, 1, 2, 1);
|
bootstrapEnv(1, 1, 2, 1);
|
||||||
|
|
||||||
final ChannelPromise emptyDataPromise = newPromise();
|
final ChannelPromise emptyDataPromise = newPromise();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, false,
|
ByteBuf emptyBuf = Unpooled.buffer();
|
||||||
newPromise());
|
emptyBuf.release();
|
||||||
ByteBuf emptyBuf = Unpooled.buffer();
|
switch (mode) {
|
||||||
emptyBuf.release();
|
case SINGLE_END_OF_STREAM:
|
||||||
switch (mode) {
|
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, true, emptyDataPromise);
|
||||||
case SINGLE_END_OF_STREAM:
|
break;
|
||||||
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, true, emptyDataPromise);
|
case SECOND_END_OF_STREAM:
|
||||||
break;
|
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
|
||||||
case SECOND_END_OF_STREAM:
|
http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, true, newPromise());
|
||||||
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
|
break;
|
||||||
http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, true, newPromise());
|
case SINGLE_WITH_TRAILERS:
|
||||||
break;
|
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
|
||||||
case SINGLE_WITH_TRAILERS:
|
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0,
|
||||||
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
|
(short) 16, false, 0, true, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0,
|
break;
|
||||||
(short) 16, false, 0, true, newPromise());
|
case SECOND_WITH_TRAILERS:
|
||||||
break;
|
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
|
||||||
case SECOND_WITH_TRAILERS:
|
http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, false, newPromise());
|
||||||
http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
|
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0,
|
||||||
http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, false, newPromise());
|
(short) 16, false, 0, true, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0,
|
break;
|
||||||
(short) 16, false, 0, true, newPromise());
|
default:
|
||||||
break;
|
throw new Error();
|
||||||
default:
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
}
|
||||||
|
http2Client.flush(ctx());
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -739,38 +640,35 @@ public class Http2ConnectionRoundtripTest {
|
||||||
final ChannelPromise dataPromise = newPromise();
|
final ChannelPromise dataPromise = newPromise();
|
||||||
final ChannelPromise assertPromise = newPromise();
|
final ChannelPromise assertPromise = newPromise();
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, false,
|
clientChannel.pipeline().addFirst(new ChannelOutboundHandlerAdapter() {
|
||||||
newPromise());
|
@Override
|
||||||
clientChannel.pipeline().addFirst(new ChannelOutboundHandlerAdapter() {
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
@Override
|
ReferenceCountUtil.release(msg);
|
||||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
|
||||||
ReferenceCountUtil.release(msg);
|
|
||||||
|
|
||||||
// Ensure we update the window size so we will try to write the rest of the frame while
|
// Ensure we update the window size so we will try to write the rest of the frame while
|
||||||
// processing the flush.
|
// processing the flush.
|
||||||
http2Client.encoder().flowController().initialWindowSize(8);
|
http2Client.encoder().flowController().initialWindowSize(8);
|
||||||
promise.setFailure(new IllegalStateException());
|
promise.setFailure(new IllegalStateException());
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
http2Client.encoder().flowController().initialWindowSize(4);
|
|
||||||
http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, false, dataPromise);
|
|
||||||
assertTrue(http2Client.encoder().flowController()
|
|
||||||
.hasFlowControlled(http2Client.connection().stream(3)));
|
|
||||||
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
|
|
||||||
try {
|
|
||||||
// The Frame should have been removed after the write failed.
|
|
||||||
assertFalse(http2Client.encoder().flowController()
|
|
||||||
.hasFlowControlled(http2Client.connection().stream(3)));
|
|
||||||
assertPromise.setSuccess();
|
|
||||||
} catch (Throwable error) {
|
|
||||||
assertPromise.setFailure(error);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
http2Client.encoder().flowController().initialWindowSize(4);
|
||||||
|
http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, false, dataPromise);
|
||||||
|
assertTrue(http2Client.encoder().flowController()
|
||||||
|
.hasFlowControlled(http2Client.connection().stream(3)));
|
||||||
|
|
||||||
|
http2Client.flush(ctx());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// The Frame should have been removed after the write failed.
|
||||||
|
assertFalse(http2Client.encoder().flowController()
|
||||||
|
.hasFlowControlled(http2Client.connection().stream(3)));
|
||||||
|
assertPromise.setSuccess();
|
||||||
|
} catch (Throwable error) {
|
||||||
|
assertPromise.setFailure(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -790,22 +688,14 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
// Create a latch to track when the close occurs.
|
// Create a latch to track when the close occurs.
|
||||||
final CountDownLatch closeLatch = new CountDownLatch(1);
|
final CountDownLatch closeLatch = new CountDownLatch(1);
|
||||||
clientChannel.closeFuture().addListener(new ChannelFutureListener() {
|
clientChannel.closeFuture().addListener((ChannelFutureListener) future -> closeLatch.countDown());
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
closeLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a single stream by sending a HEADERS frame to the server.
|
// Create a single stream by sending a HEADERS frame to the server.
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false,
|
http2Client.flush(ctx());
|
||||||
newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the server to create the stream.
|
// Wait for the server to create the stream.
|
||||||
|
@ -837,24 +727,18 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
// Create a single stream by sending a HEADERS frame to the server.
|
// Create a single stream by sending a HEADERS frame to the server.
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
||||||
public void run() throws Http2Exception {
|
true, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
http2Client.flush(ctx());
|
||||||
true, newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), MAX_VALUE + 1, headers, 0, (short) 16, false, 0,
|
||||||
public void run() throws Http2Exception {
|
true, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), MAX_VALUE + 1, headers, 0, (short) 16, false, 0,
|
http2Client.flush(ctx());
|
||||||
true, newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(goAwayLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(goAwayLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -871,23 +755,17 @@ public class Http2ConnectionRoundtripTest {
|
||||||
setServerGracefulShutdownTime(10000);
|
setServerGracefulShutdownTime(10000);
|
||||||
|
|
||||||
final CountDownLatch clientGoAwayLatch = new CountDownLatch(1);
|
final CountDownLatch clientGoAwayLatch = new CountDownLatch(1);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
clientGoAwayLatch.countDown();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
return null;
|
||||||
clientGoAwayLatch.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
|
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
|
||||||
|
|
||||||
// Create a single stream by sending a HEADERS frame to the server.
|
// Create a single stream by sending a HEADERS frame to the server.
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
||||||
public void run() throws Http2Exception {
|
false, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
http2Client.flush(ctx());
|
||||||
false, newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -895,12 +773,9 @@ public class Http2ConnectionRoundtripTest {
|
||||||
// Server has received the headers, so the stream is open
|
// Server has received the headers, so the stream is open
|
||||||
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
||||||
runInChannel(serverChannel, new Http2Runnable() {
|
runInChannel(serverChannel, () -> {
|
||||||
@Override
|
http2Server.encoder().writeGoAway(serverCtx(), 3, NO_ERROR.code(), EMPTY_BUFFER, serverNewPromise());
|
||||||
public void run() throws Http2Exception {
|
http2Server.flush(serverCtx());
|
||||||
http2Server.encoder().writeGoAway(serverCtx(), 3, NO_ERROR.code(), EMPTY_BUFFER, serverNewPromise());
|
|
||||||
http2Server.flush(serverCtx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// wait for the client to receive the GO_AWAY.
|
// wait for the client to receive the GO_AWAY.
|
||||||
|
@ -910,20 +785,12 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
final AtomicReference<ChannelFuture> clientWriteAfterGoAwayFutureRef = new AtomicReference<>();
|
final AtomicReference<ChannelFuture> clientWriteAfterGoAwayFutureRef = new AtomicReference<>();
|
||||||
final CountDownLatch clientWriteAfterGoAwayLatch = new CountDownLatch(1);
|
final CountDownLatch clientWriteAfterGoAwayLatch = new CountDownLatch(1);
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
ChannelFuture f = http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0,
|
||||||
public void run() throws Http2Exception {
|
true, newPromise());
|
||||||
ChannelFuture f = http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0,
|
clientWriteAfterGoAwayFutureRef.set(f);
|
||||||
true, newPromise());
|
http2Client.flush(ctx());
|
||||||
clientWriteAfterGoAwayFutureRef.set(f);
|
f.addListener((ChannelFutureListener) future -> clientWriteAfterGoAwayLatch.countDown());
|
||||||
http2Client.flush(ctx());
|
|
||||||
f.addListener(new ChannelFutureListener() {
|
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
clientWriteAfterGoAwayLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the client's write operation to complete.
|
// Wait for the client's write operation to complete.
|
||||||
|
@ -950,12 +817,9 @@ public class Http2ConnectionRoundtripTest {
|
||||||
bootstrapEnv(1, 1, 2, 1, 1);
|
bootstrapEnv(1, 1, 2, 1, 1);
|
||||||
|
|
||||||
final CountDownLatch clientGoAwayLatch = new CountDownLatch(1);
|
final CountDownLatch clientGoAwayLatch = new CountDownLatch(1);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
clientGoAwayLatch.countDown();
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
return null;
|
||||||
clientGoAwayLatch.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
|
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
|
||||||
|
|
||||||
// We want both sides to do graceful shutdown during the test.
|
// We want both sides to do graceful shutdown during the test.
|
||||||
|
@ -965,30 +829,19 @@ public class Http2ConnectionRoundtripTest {
|
||||||
final Http2Headers headers = dummyHeaders();
|
final Http2Headers headers = dummyHeaders();
|
||||||
final AtomicReference<ChannelFuture> clientWriteAfterGoAwayFutureRef = new AtomicReference<>();
|
final AtomicReference<ChannelFuture> clientWriteAfterGoAwayFutureRef = new AtomicReference<>();
|
||||||
final CountDownLatch clientWriteAfterGoAwayLatch = new CountDownLatch(1);
|
final CountDownLatch clientWriteAfterGoAwayLatch = new CountDownLatch(1);
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) invocationOnMock -> {
|
||||||
@Override
|
ChannelFuture f = http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0,
|
||||||
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
true, newPromise());
|
||||||
ChannelFuture f = http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0,
|
clientWriteAfterGoAwayFutureRef.set(f);
|
||||||
true, newPromise());
|
f.addListener((ChannelFutureListener) future -> clientWriteAfterGoAwayLatch.countDown());
|
||||||
clientWriteAfterGoAwayFutureRef.set(f);
|
http2Client.flush(ctx());
|
||||||
f.addListener(new ChannelFutureListener() {
|
return null;
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
clientWriteAfterGoAwayLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
|
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
|
||||||
|
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
||||||
public void run() throws Http2Exception {
|
true, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
http2Client.flush(ctx());
|
||||||
true, newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
@ -996,12 +849,9 @@ public class Http2ConnectionRoundtripTest {
|
||||||
// Server has received the headers, so the stream is open
|
// Server has received the headers, so the stream is open
|
||||||
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
||||||
runInChannel(serverChannel, new Http2Runnable() {
|
runInChannel(serverChannel, () -> {
|
||||||
@Override
|
http2Server.encoder().writeGoAway(serverCtx(), 3, NO_ERROR.code(), EMPTY_BUFFER, serverNewPromise());
|
||||||
public void run() throws Http2Exception {
|
http2Server.flush(serverCtx());
|
||||||
http2Server.encoder().writeGoAway(serverCtx(), 3, NO_ERROR.code(), EMPTY_BUFFER, serverNewPromise());
|
|
||||||
http2Server.flush(serverCtx());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the client's write operation to complete.
|
// Wait for the client's write operation to complete.
|
||||||
|
@ -1033,16 +883,13 @@ public class Http2ConnectionRoundtripTest {
|
||||||
// Create a buffer filled with random bytes.
|
// Create a buffer filled with random bytes.
|
||||||
final ByteBuf data = randomBytes(length);
|
final ByteBuf data = randomBytes(length);
|
||||||
final ByteArrayOutputStream out = new ByteArrayOutputStream(length);
|
final ByteArrayOutputStream out = new ByteArrayOutputStream(length);
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) in -> {
|
||||||
@Override
|
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
||||||
public Integer answer(InvocationOnMock in) throws Throwable {
|
int padding = (Integer) in.getArguments()[3];
|
||||||
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
int processedBytes = buf.readableBytes() + padding;
|
||||||
int padding = (Integer) in.getArguments()[3];
|
|
||||||
int processedBytes = buf.readableBytes() + padding;
|
|
||||||
|
|
||||||
buf.readBytes(out, buf.readableBytes());
|
buf.readBytes(out, buf.readableBytes());
|
||||||
return processedBytes;
|
return processedBytes;
|
||||||
}
|
|
||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), anyBoolean());
|
any(ByteBuf.class), eq(0), anyBoolean());
|
||||||
try {
|
try {
|
||||||
|
@ -1050,18 +897,15 @@ public class Http2ConnectionRoundtripTest {
|
||||||
bootstrapEnv(length, 1, 2, 1);
|
bootstrapEnv(length, 1, 2, 1);
|
||||||
|
|
||||||
// Create the stream and send all of the data at once.
|
// Create the stream and send all of the data at once.
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
||||||
public void run() throws Http2Exception {
|
false, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0,
|
http2Client.encoder().writeData(ctx(), 3, data.retainedDuplicate(), 0, false, newPromise());
|
||||||
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,
|
||||||
true, newPromise());
|
true, newPromise());
|
||||||
http2Client.flush(ctx());
|
http2Client.flush(ctx());
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the trailers to be received.
|
// Wait for the trailers to be received.
|
||||||
|
@ -1110,44 +954,38 @@ public class Http2ConnectionRoundtripTest {
|
||||||
|
|
||||||
// Collect all the data buffers as we receive them at the server.
|
// Collect all the data buffers as we receive them at the server.
|
||||||
final StringBuilder[] receivedData = new StringBuilder[numStreams];
|
final StringBuilder[] receivedData = new StringBuilder[numStreams];
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) in -> {
|
||||||
@Override
|
int streamId = (Integer) in.getArguments()[1];
|
||||||
public Integer answer(InvocationOnMock in) throws Throwable {
|
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
||||||
int streamId = (Integer) in.getArguments()[1];
|
int padding = (Integer) in.getArguments()[3];
|
||||||
ByteBuf buf = (ByteBuf) in.getArguments()[2];
|
int processedBytes = buf.readableBytes() + padding;
|
||||||
int padding = (Integer) in.getArguments()[3];
|
|
||||||
int processedBytes = buf.readableBytes() + padding;
|
|
||||||
|
|
||||||
int streamIndex = (streamId - 3) / 2;
|
int streamIndex = (streamId - 3) / 2;
|
||||||
StringBuilder builder = receivedData[streamIndex];
|
StringBuilder builder = receivedData[streamIndex];
|
||||||
if (builder == null) {
|
if (builder == null) {
|
||||||
builder = new StringBuilder(dataAsHex.length());
|
builder = new StringBuilder(dataAsHex.length());
|
||||||
receivedData[streamIndex] = builder;
|
receivedData[streamIndex] = builder;
|
||||||
}
|
|
||||||
builder.append(ByteBufUtil.hexDump(buf));
|
|
||||||
return processedBytes;
|
|
||||||
}
|
}
|
||||||
|
builder.append(ByteBufUtil.hexDump(buf));
|
||||||
|
return processedBytes;
|
||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||||
try {
|
try {
|
||||||
bootstrapEnv(numStreams * length, 1, numStreams * 4, numStreams);
|
bootstrapEnv(numStreams * length, 1, numStreams * 4, numStreams);
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
int upperLimit = 3 + 2 * numStreams;
|
||||||
public void run() throws Http2Exception {
|
for (int streamId = 3; streamId < upperLimit; streamId += 2) {
|
||||||
int upperLimit = 3 + 2 * numStreams;
|
// Send a bunch of data on each stream.
|
||||||
for (int streamId = 3; streamId < upperLimit; streamId += 2) {
|
http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16,
|
||||||
// Send a bunch of data on each stream.
|
false, 0, false, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16,
|
http2Client.encoder().writePing(ctx(), false, pingData,
|
||||||
false, 0, false, newPromise());
|
newPromise());
|
||||||
http2Client.encoder().writePing(ctx(), false, pingData,
|
http2Client.encoder().writeData(ctx(), streamId, data.retainedSlice(), 0,
|
||||||
newPromise());
|
false, newPromise());
|
||||||
http2Client.encoder().writeData(ctx(), streamId, data.retainedSlice(), 0,
|
// Write trailers.
|
||||||
false, newPromise());
|
http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16,
|
||||||
// Write trailers.
|
false, 0, true, newPromise());
|
||||||
http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16,
|
http2Client.flush(ctx());
|
||||||
false, 0, true, newPromise());
|
|
||||||
http2Client.flush(ctx());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Wait for all frames to be received.
|
// Wait for all frames to be received.
|
||||||
|
@ -1270,15 +1108,11 @@ public class Http2ConnectionRoundtripTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void mockFlowControl(Http2FrameListener listener) throws Http2Exception {
|
private static void mockFlowControl(Http2FrameListener listener) throws Http2Exception {
|
||||||
doAnswer(new Answer<Integer>() {
|
doAnswer((Answer<Integer>) invocation -> {
|
||||||
@Override
|
ByteBuf buf = (ByteBuf) invocation.getArguments()[2];
|
||||||
public Integer answer(InvocationOnMock invocation) throws Throwable {
|
int padding = (Integer) invocation.getArguments()[3];
|
||||||
ByteBuf buf = (ByteBuf) invocation.getArguments()[2];
|
int processedBytes = buf.readableBytes() + padding;
|
||||||
int padding = (Integer) invocation.getArguments()[3];
|
return processedBytes;
|
||||||
int processedBytes = buf.readableBytes() + padding;
|
|
||||||
return processedBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
}).when(listener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
}).when(listener).onDataRead(any(ChannelHandlerContext.class), anyInt(),
|
||||||
any(ByteBuf.class), anyInt(), anyBoolean());
|
any(ByteBuf.class), anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
@ -1294,12 +1128,9 @@ public class Http2ConnectionRoundtripTest {
|
||||||
private static void setGracefulShutdownTime(Channel channel, final Http2ConnectionHandler handler,
|
private static void setGracefulShutdownTime(Channel channel, final Http2ConnectionHandler handler,
|
||||||
final long millis) throws InterruptedException {
|
final long millis) throws InterruptedException {
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
runInChannel(channel, new Http2Runnable() {
|
runInChannel(channel, () -> {
|
||||||
@Override
|
handler.gracefulShutdownTimeoutMillis(millis);
|
||||||
public void run() throws Http2Exception {
|
latch.countDown();
|
||||||
handler.gracefulShutdownTimeoutMillis(millis);
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(latch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
assertTrue(latch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
|
||||||
|
|
|
@ -573,15 +573,12 @@ public class Http2FrameCodecTest {
|
||||||
final Promise<Void> listenerExecuted = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
|
final Promise<Void> listenerExecuted = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
|
||||||
|
|
||||||
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers(), false).stream(stream))
|
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers(), false).stream(stream))
|
||||||
.addListener(new ChannelFutureListener() {
|
.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
assertTrue(future.isSuccess());
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
assertTrue(isStreamIdValid(stream.id()));
|
||||||
assertTrue(future.isSuccess());
|
listenerExecuted.setSuccess(null);
|
||||||
assertTrue(isStreamIdValid(stream.id()));
|
}
|
||||||
listenerExecuted.setSuccess(null);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
ByteBuf data = Unpooled.buffer().writeZero(100);
|
ByteBuf data = Unpooled.buffer().writeZero(100);
|
||||||
ChannelFuture f = channel.writeAndFlush(new DefaultHttp2DataFrame(data).stream(stream));
|
ChannelFuture f = channel.writeAndFlush(new DefaultHttp2DataFrame(data).stream(stream));
|
||||||
assertTrue(f.isSuccess());
|
assertTrue(f.isSuccess());
|
||||||
|
@ -735,12 +732,9 @@ public class Http2FrameCodecTest {
|
||||||
Http2FrameStream idleStream = frameCodec.newStream();
|
Http2FrameStream idleStream = frameCodec.newStream();
|
||||||
|
|
||||||
final Set<Http2FrameStream> activeStreams = new HashSet<>();
|
final Set<Http2FrameStream> activeStreams = new HashSet<>();
|
||||||
frameCodec.forEachActiveStream(new Http2FrameStreamVisitor() {
|
frameCodec.forEachActiveStream(stream -> {
|
||||||
@Override
|
activeStreams.add(stream);
|
||||||
public boolean visit(Http2FrameStream stream) {
|
return true;
|
||||||
activeStreams.add(stream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertEquals(2, activeStreams.size());
|
assertEquals(2, activeStreams.size());
|
||||||
|
@ -758,13 +752,10 @@ public class Http2FrameCodecTest {
|
||||||
|
|
||||||
final AtomicBoolean listenerExecuted = new AtomicBoolean();
|
final AtomicBoolean listenerExecuted = new AtomicBoolean();
|
||||||
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2))
|
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2))
|
||||||
.addListener(new ChannelFutureListener() {
|
.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
assertTrue(future.isSuccess());
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
assertEquals(State.OPEN, stream2.state());
|
||||||
assertTrue(future.isSuccess());
|
listenerExecuted.set(true);
|
||||||
assertEquals(State.OPEN, stream2.state());
|
|
||||||
listenerExecuted.set(true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(listenerExecuted.get());
|
assertTrue(listenerExecuted.get());
|
||||||
|
@ -795,15 +786,12 @@ public class Http2FrameCodecTest {
|
||||||
// Simulate consuming the frame and update the flow-controller.
|
// Simulate consuming the frame and update the flow-controller.
|
||||||
Http2DataFrame data = (Http2DataFrame) msg;
|
Http2DataFrame data = (Http2DataFrame) msg;
|
||||||
ctx.writeAndFlush(new DefaultHttp2WindowUpdateFrame(data.initialFlowControlledBytes())
|
ctx.writeAndFlush(new DefaultHttp2WindowUpdateFrame(data.initialFlowControlledBytes())
|
||||||
.stream(data.stream())).addListener(new ChannelFutureListener() {
|
.stream(data.stream())).addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
Throwable cause = future.cause();
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
if (cause != null) {
|
||||||
Throwable cause = future.cause();
|
ctx.fireExceptionCaught(cause);
|
||||||
if (cause != null) {
|
}
|
||||||
ctx.fireExceptionCaught(cause);
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ReferenceCountUtil.release(msg);
|
ReferenceCountUtil.release(msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,24 +97,10 @@ public class Http2FrameRoundtripTest {
|
||||||
when(ctx.alloc()).thenReturn(alloc);
|
when(ctx.alloc()).thenReturn(alloc);
|
||||||
when(ctx.executor()).thenReturn(executor);
|
when(ctx.executor()).thenReturn(executor);
|
||||||
when(ctx.channel()).thenReturn(channel);
|
when(ctx.channel()).thenReturn(channel);
|
||||||
doAnswer(new Answer<ByteBuf>() {
|
doAnswer((Answer<ByteBuf>) in -> Unpooled.buffer()).when(alloc).buffer();
|
||||||
@Override
|
doAnswer((Answer<ByteBuf>) in -> Unpooled.buffer((Integer) in.getArguments()[0])).when(alloc).buffer(anyInt());
|
||||||
public ByteBuf answer(InvocationOnMock in) throws Throwable {
|
doAnswer((Answer<ChannelPromise>) invocation ->
|
||||||
return Unpooled.buffer();
|
new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).when(ctx).newPromise();
|
||||||
}
|
|
||||||
}).when(alloc).buffer();
|
|
||||||
doAnswer(new Answer<ByteBuf>() {
|
|
||||||
@Override
|
|
||||||
public ByteBuf answer(InvocationOnMock in) throws Throwable {
|
|
||||||
return Unpooled.buffer((Integer) in.getArguments()[0]);
|
|
||||||
}
|
|
||||||
}).when(alloc).buffer(anyInt());
|
|
||||||
doAnswer(new Answer<ChannelPromise>() {
|
|
||||||
@Override
|
|
||||||
public ChannelPromise answer(InvocationOnMock invocation) throws Throwable {
|
|
||||||
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE);
|
|
||||||
}
|
|
||||||
}).when(ctx).newPromise();
|
|
||||||
|
|
||||||
writer = new DefaultHttp2FrameWriter(new DefaultHttp2HeadersEncoder(NEVER_SENSITIVE, newTestEncoder()));
|
writer = new DefaultHttp2FrameWriter(new DefaultHttp2HeadersEncoder(NEVER_SENSITIVE, newTestEncoder()));
|
||||||
reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(false, newTestDecoder()));
|
reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(false, newTestDecoder()));
|
||||||
|
|
|
@ -245,12 +245,7 @@ public class Http2MultiplexCodecTest {
|
||||||
frameInboundWriter.writeInboundData(channel.stream().id(), tenBytes, 0, true);
|
frameInboundWriter.writeInboundData(channel.stream().id(), tenBytes, 0, true);
|
||||||
|
|
||||||
// Verify we marked the bytes as consumed
|
// Verify we marked the bytes as consumed
|
||||||
verify(flowController).consumeBytes(argThat(new ArgumentMatcher<Http2Stream>() {
|
verify(flowController).consumeBytes(argThat(http2Stream -> http2Stream.id() == channel.stream().id()), eq(10));
|
||||||
@Override
|
|
||||||
public boolean matches(Http2Stream http2Stream) {
|
|
||||||
return http2Stream.id() == channel.stream().id();
|
|
||||||
}
|
|
||||||
}), eq(10));
|
|
||||||
|
|
||||||
// headers and data frame
|
// headers and data frame
|
||||||
verifyFramesMultiplexedToCorrectChannel(channel, handler, 2);
|
verifyFramesMultiplexedToCorrectChannel(channel, handler, 2);
|
||||||
|
@ -459,13 +454,9 @@ public class Http2MultiplexCodecTest {
|
||||||
Http2Headers headers = new DefaultHttp2Headers();
|
Http2Headers headers = new DefaultHttp2Headers();
|
||||||
when(frameWriter.writeHeaders(eqMultiplexCodecCtx(), anyInt(),
|
when(frameWriter.writeHeaders(eqMultiplexCodecCtx(), anyInt(),
|
||||||
eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
||||||
any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(8)).setFailure(
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
new StreamException(childChannel.stream().id(), Http2Error.STREAM_CLOSED, "Stream Closed")));
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(8)).setFailure(
|
|
||||||
new StreamException(childChannel.stream().id(), Http2Error.STREAM_CLOSED, "Stream Closed"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()));
|
ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()));
|
||||||
|
|
||||||
parentChannel.flush();
|
parentChannel.flush();
|
||||||
|
@ -521,13 +512,9 @@ public class Http2MultiplexCodecTest {
|
||||||
Http2Headers headers = new DefaultHttp2Headers();
|
Http2Headers headers = new DefaultHttp2Headers();
|
||||||
when(frameWriter.writeHeaders(eqMultiplexCodecCtx(), anyInt(),
|
when(frameWriter.writeHeaders(eqMultiplexCodecCtx(), anyInt(),
|
||||||
eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
||||||
any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(8)).setFailure(
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
new Http2NoMoreStreamIdsException()));
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(8)).setFailure(
|
|
||||||
new Http2NoMoreStreamIdsException());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
|
ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
|
||||||
parentChannel.flush();
|
parentChannel.flush();
|
||||||
|
@ -554,12 +541,9 @@ public class Http2MultiplexCodecTest {
|
||||||
// Create a promise before actually doing the close, because otherwise we would be adding a listener to a future
|
// Create a promise before actually doing the close, because otherwise we would be adding a listener to a future
|
||||||
// that is already completed because we are using EmbeddedChannel which executes code in the JUnit thread.
|
// that is already completed because we are using EmbeddedChannel which executes code in the JUnit thread.
|
||||||
ChannelPromise p = childChannel.newPromise();
|
ChannelPromise p = childChannel.newPromise();
|
||||||
p.addListener(new ChannelFutureListener() {
|
p.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
channelOpen.set(future.channel().isOpen());
|
||||||
public void operationComplete(ChannelFuture future) {
|
channelActive.set(future.channel().isActive());
|
||||||
channelOpen.set(future.channel().isOpen());
|
|
||||||
channelActive.set(future.channel().isActive());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
childChannel.close(p).syncUninterruptibly();
|
childChannel.close(p).syncUninterruptibly();
|
||||||
|
|
||||||
|
@ -579,12 +563,9 @@ public class Http2MultiplexCodecTest {
|
||||||
final AtomicBoolean channelOpen = new AtomicBoolean(true);
|
final AtomicBoolean channelOpen = new AtomicBoolean(true);
|
||||||
final AtomicBoolean channelActive = new AtomicBoolean(true);
|
final AtomicBoolean channelActive = new AtomicBoolean(true);
|
||||||
|
|
||||||
childChannel.closeFuture().addListener(new ChannelFutureListener() {
|
childChannel.closeFuture().addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
channelOpen.set(future.channel().isOpen());
|
||||||
public void operationComplete(ChannelFuture future) {
|
channelActive.set(future.channel().isActive());
|
||||||
channelOpen.set(future.channel().isOpen());
|
|
||||||
channelActive.set(future.channel().isActive());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
childChannel.close().syncUninterruptibly();
|
childChannel.close().syncUninterruptibly();
|
||||||
|
|
||||||
|
@ -609,23 +590,17 @@ public class Http2MultiplexCodecTest {
|
||||||
Http2Headers headers = new DefaultHttp2Headers();
|
Http2Headers headers = new DefaultHttp2Headers();
|
||||||
when(frameWriter.writeHeaders(eqMultiplexCodecCtx(), anyInt(),
|
when(frameWriter.writeHeaders(eqMultiplexCodecCtx(), anyInt(),
|
||||||
eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
||||||
any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock -> {
|
||||||
@Override
|
ChannelPromise promise = invocationOnMock.getArgument(8);
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
writePromises.offer(promise);
|
||||||
ChannelPromise promise = invocationOnMock.getArgument(8);
|
return promise;
|
||||||
writePromises.offer(promise);
|
});
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ChannelFuture f = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
|
ChannelFuture f = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
|
||||||
assertFalse(f.isDone());
|
assertFalse(f.isDone());
|
||||||
f.addListener(new ChannelFutureListener() {
|
f.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
channelOpen.set(future.channel().isOpen());
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
channelActive.set(future.channel().isActive());
|
||||||
channelOpen.set(future.channel().isOpen());
|
|
||||||
channelActive.set(future.channel().isActive());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ChannelPromise first = writePromises.poll();
|
ChannelPromise first = writePromises.poll();
|
||||||
|
@ -794,12 +769,9 @@ public class Http2MultiplexCodecTest {
|
||||||
public void endOfStreamDoesNotDiscardData() {
|
public void endOfStreamDoesNotDiscardData() {
|
||||||
AtomicInteger numReads = new AtomicInteger(1);
|
AtomicInteger numReads = new AtomicInteger(1);
|
||||||
final AtomicBoolean shouldDisableAutoRead = new AtomicBoolean();
|
final AtomicBoolean shouldDisableAutoRead = new AtomicBoolean();
|
||||||
Consumer<ChannelHandlerContext> ctxConsumer = new Consumer<ChannelHandlerContext>() {
|
Consumer<ChannelHandlerContext> ctxConsumer = obj -> {
|
||||||
@Override
|
if (shouldDisableAutoRead.get()) {
|
||||||
public void accept(ChannelHandlerContext obj) {
|
obj.channel().config().setAutoRead(false);
|
||||||
if (shouldDisableAutoRead.get()) {
|
|
||||||
obj.channel().config().setAutoRead(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LastInboundHandler inboundHandler = new LastInboundHandler(ctxConsumer);
|
LastInboundHandler inboundHandler = new LastInboundHandler(ctxConsumer);
|
||||||
|
@ -859,13 +831,10 @@ public class Http2MultiplexCodecTest {
|
||||||
AtomicInteger numReads = new AtomicInteger(1);
|
AtomicInteger numReads = new AtomicInteger(1);
|
||||||
final AtomicInteger channelReadCompleteCount = new AtomicInteger(0);
|
final AtomicInteger channelReadCompleteCount = new AtomicInteger(0);
|
||||||
final AtomicBoolean shouldDisableAutoRead = new AtomicBoolean();
|
final AtomicBoolean shouldDisableAutoRead = new AtomicBoolean();
|
||||||
Consumer<ChannelHandlerContext> ctxConsumer = new Consumer<ChannelHandlerContext>() {
|
Consumer<ChannelHandlerContext> ctxConsumer = obj -> {
|
||||||
@Override
|
channelReadCompleteCount.incrementAndGet();
|
||||||
public void accept(ChannelHandlerContext obj) {
|
if (shouldDisableAutoRead.get()) {
|
||||||
channelReadCompleteCount.incrementAndGet();
|
obj.channel().config().setAutoRead(false);
|
||||||
if (shouldDisableAutoRead.get()) {
|
|
||||||
obj.channel().config().setAutoRead(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LastInboundHandler inboundHandler = new LastInboundHandler(ctxConsumer);
|
LastInboundHandler inboundHandler = new LastInboundHandler(ctxConsumer);
|
||||||
|
@ -922,13 +891,10 @@ public class Http2MultiplexCodecTest {
|
||||||
final AtomicInteger numReads = new AtomicInteger(1);
|
final AtomicInteger numReads = new AtomicInteger(1);
|
||||||
final AtomicInteger channelReadCompleteCount = new AtomicInteger(0);
|
final AtomicInteger channelReadCompleteCount = new AtomicInteger(0);
|
||||||
final AtomicBoolean shouldDisableAutoRead = new AtomicBoolean();
|
final AtomicBoolean shouldDisableAutoRead = new AtomicBoolean();
|
||||||
Consumer<ChannelHandlerContext> ctxConsumer = new Consumer<ChannelHandlerContext>() {
|
Consumer<ChannelHandlerContext> ctxConsumer = obj -> {
|
||||||
@Override
|
channelReadCompleteCount.incrementAndGet();
|
||||||
public void accept(ChannelHandlerContext obj) {
|
if (shouldDisableAutoRead.get()) {
|
||||||
channelReadCompleteCount.incrementAndGet();
|
obj.channel().config().setAutoRead(false);
|
||||||
if (shouldDisableAutoRead.get()) {
|
|
||||||
obj.channel().config().setAutoRead(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final LastInboundHandler inboundHandler = new LastInboundHandler(ctxConsumer);
|
final LastInboundHandler inboundHandler = new LastInboundHandler(ctxConsumer);
|
||||||
|
|
|
@ -70,14 +70,11 @@ public final class Http2TestUtil {
|
||||||
* Runs the given operation within the event loop thread of the given {@link Channel}.
|
* Runs the given operation within the event loop thread of the given {@link Channel}.
|
||||||
*/
|
*/
|
||||||
static void runInChannel(Channel channel, final Http2Runnable runnable) {
|
static void runInChannel(Channel channel, final Http2Runnable runnable) {
|
||||||
channel.eventLoop().execute(new Runnable() {
|
channel.eventLoop().execute(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
runnable.run();
|
||||||
try {
|
} catch (Http2Exception e) {
|
||||||
runnable.run();
|
throw new RuntimeException(e);
|
||||||
} catch (Http2Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -477,12 +474,9 @@ public final class Http2TestUtil {
|
||||||
public ChannelPromise unvoid() {
|
public ChannelPromise unvoid() {
|
||||||
ChannelPromise promise =
|
ChannelPromise promise =
|
||||||
new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
|
new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
|
||||||
promise.addListener(new ChannelFutureListener() {
|
promise.addListener((ChannelFutureListener) future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
channel().pipeline().fireExceptionCaught(future.cause());
|
||||||
if (!future.isSuccess()) {
|
|
||||||
channel().pipeline().fireExceptionCaught(future.cause());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
|
@ -575,103 +569,63 @@ public final class Http2TestUtil {
|
||||||
final ConcurrentLinkedQueue<ByteBuf> buffers = new ConcurrentLinkedQueue<>();
|
final ConcurrentLinkedQueue<ByteBuf> buffers = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
Http2FrameWriter frameWriter = Mockito.mock(Http2FrameWriter.class);
|
Http2FrameWriter frameWriter = Mockito.mock(Http2FrameWriter.class);
|
||||||
doAnswer(new Answer() {
|
doAnswer(invocationOnMock -> {
|
||||||
@Override
|
for (;;) {
|
||||||
public Object answer(InvocationOnMock invocationOnMock) {
|
ByteBuf buf = buffers.poll();
|
||||||
for (;;) {
|
if (buf == null) {
|
||||||
ByteBuf buf = buffers.poll();
|
break;
|
||||||
if (buf == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf.release();
|
|
||||||
}
|
}
|
||||||
return null;
|
buf.release();
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}).when(frameWriter).close();
|
}).when(frameWriter).close();
|
||||||
|
|
||||||
when(frameWriter.configuration()).thenReturn(configuration);
|
when(frameWriter.configuration()).thenReturn(configuration);
|
||||||
when(frameWriter.writeSettings(any(ChannelHandlerContext.class), any(Http2Settings.class),
|
when(frameWriter.writeSettings(any(ChannelHandlerContext.class), any(Http2Settings.class),
|
||||||
any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(2)).setSuccess());
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(2)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writeSettingsAck(any(ChannelHandlerContext.class), any(ChannelPromise.class)))
|
when(frameWriter.writeSettingsAck(any(ChannelHandlerContext.class), any(ChannelPromise.class)))
|
||||||
.thenAnswer(new Answer<ChannelFuture>() {
|
.thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(1)).setSuccess());
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(1)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writeGoAway(any(ChannelHandlerContext.class), anyInt(),
|
when(frameWriter.writeGoAway(any(ChannelHandlerContext.class), anyInt(),
|
||||||
anyLong(), any(ByteBuf.class), any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
anyLong(), any(ByteBuf.class), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
|
||||||
@Override
|
buffers.offer((ByteBuf) invocationOnMock.getArgument(3));
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
return ((ChannelPromise) invocationOnMock.getArgument(4)).setSuccess();
|
||||||
buffers.offer((ByteBuf) invocationOnMock.getArgument(3));
|
});
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(4)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class), anyInt(),
|
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class), anyInt(),
|
||||||
anyBoolean(), any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
anyBoolean(), any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess());
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
|
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
|
||||||
any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
|
||||||
any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(8)).setSuccess());
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(8)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writeData(any(ChannelHandlerContext.class), anyInt(), any(ByteBuf.class), anyInt(),
|
when(frameWriter.writeData(any(ChannelHandlerContext.class), anyInt(), any(ByteBuf.class), anyInt(),
|
||||||
anyBoolean(), any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
|
||||||
@Override
|
buffers.offer((ByteBuf) invocationOnMock.getArgument(2));
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
|
||||||
buffers.offer((ByteBuf) invocationOnMock.getArgument(2));
|
});
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writeRstStream(any(ChannelHandlerContext.class), anyInt(),
|
when(frameWriter.writeRstStream(any(ChannelHandlerContext.class), anyInt(),
|
||||||
anyLong(), any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
|
anyLong(), any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(3)).setSuccess());
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(3)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writeWindowUpdate(any(ChannelHandlerContext.class), anyInt(), anyInt(),
|
when(frameWriter.writeWindowUpdate(any(ChannelHandlerContext.class), anyInt(), anyInt(),
|
||||||
any(ChannelPromise.class))).then(new Answer<ChannelFuture>() {
|
any(ChannelPromise.class))).then((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(3)).setSuccess());
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(3)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writePushPromise(any(ChannelHandlerContext.class), anyInt(), anyInt(), any(Http2Headers.class),
|
when(frameWriter.writePushPromise(any(ChannelHandlerContext.class), anyInt(), anyInt(), any(Http2Headers.class),
|
||||||
anyInt(), anyChannelPromise())).thenAnswer(new Answer<ChannelFuture>() {
|
anyInt(), anyChannelPromise())).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
|
||||||
@Override
|
((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess());
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
when(frameWriter.writeFrame(any(ChannelHandlerContext.class), anyByte(), anyInt(), any(Http2Flags.class),
|
when(frameWriter.writeFrame(any(ChannelHandlerContext.class), anyByte(), anyInt(), any(Http2Flags.class),
|
||||||
any(ByteBuf.class), anyChannelPromise())).thenAnswer(new Answer<ChannelFuture>() {
|
any(ByteBuf.class), anyChannelPromise())).thenAnswer(invocationOnMock -> {
|
||||||
@Override
|
buffers.offer((ByteBuf) invocationOnMock.getArgument(4));
|
||||||
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
|
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
|
||||||
buffers.offer((ByteBuf) invocationOnMock.getArgument(4));
|
});
|
||||||
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return frameWriter;
|
return frameWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -337,12 +337,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||||
public void testRequestWithBody() throws Exception {
|
public void testRequestWithBody() throws Exception {
|
||||||
final String text = "foooooogoooo";
|
final String text = "foooooogoooo";
|
||||||
final List<String> receivedBuffers = Collections.synchronizedList(new ArrayList<>());
|
final List<String> receivedBuffers = Collections.synchronizedList(new ArrayList<>());
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) in -> {
|
||||||
@Override
|
receivedBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
|
||||||
public Void answer(InvocationOnMock in) throws Throwable {
|
return null;
|
||||||
receivedBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), eq(true));
|
any(ByteBuf.class), eq(0), eq(true));
|
||||||
bootstrapEnv(3, 1, 0);
|
bootstrapEnv(3, 1, 0);
|
||||||
|
@ -380,12 +377,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||||
public void testRequestWithBodyAndTrailingHeaders() throws Exception {
|
public void testRequestWithBodyAndTrailingHeaders() throws Exception {
|
||||||
final String text = "foooooogoooo";
|
final String text = "foooooogoooo";
|
||||||
final List<String> receivedBuffers = Collections.synchronizedList(new ArrayList<>());
|
final List<String> receivedBuffers = Collections.synchronizedList(new ArrayList<>());
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) in -> {
|
||||||
@Override
|
receivedBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
|
||||||
public Void answer(InvocationOnMock in) throws Throwable {
|
return null;
|
||||||
receivedBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), eq(false));
|
any(ByteBuf.class), eq(0), eq(false));
|
||||||
bootstrapEnv(4, 1, 1);
|
bootstrapEnv(4, 1, 1);
|
||||||
|
@ -432,12 +426,9 @@ public class HttpToHttp2ConnectionHandlerTest {
|
||||||
final String text = "foooooo";
|
final String text = "foooooo";
|
||||||
final String text2 = "goooo";
|
final String text2 = "goooo";
|
||||||
final List<String> receivedBuffers = Collections.synchronizedList(new ArrayList<>());
|
final List<String> receivedBuffers = Collections.synchronizedList(new ArrayList<>());
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer((Answer<Void>) in -> {
|
||||||
@Override
|
receivedBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
|
||||||
public Void answer(InvocationOnMock in) throws Throwable {
|
return null;
|
||||||
receivedBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
|
||||||
any(ByteBuf.class), eq(0), eq(false));
|
any(ByteBuf.class), eq(0), eq(false));
|
||||||
bootstrapEnv(4, 1, 1);
|
bootstrapEnv(4, 1, 1);
|
||||||
|
|
|
@ -148,12 +148,9 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).
|
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).
|
||||||
scheme(new AsciiString("https")).authority(new AsciiString("example.org"))
|
scheme(new AsciiString("https")).authority(new AsciiString("example.org"))
|
||||||
.path(new AsciiString("/some/path/resource2"));
|
.path(new AsciiString("/some/path/resource2"));
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -184,12 +181,9 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
.add(HttpHeaderNames.COOKIE, "a=b")
|
.add(HttpHeaderNames.COOKIE, "a=b")
|
||||||
.add(HttpHeaderNames.COOKIE, "c=d")
|
.add(HttpHeaderNames.COOKIE, "c=d")
|
||||||
.add(HttpHeaderNames.COOKIE, "e=f");
|
.add(HttpHeaderNames.COOKIE, "e=f");
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -219,12 +213,9 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
.path(new AsciiString("/some/path/resource2"))
|
.path(new AsciiString("/some/path/resource2"))
|
||||||
.add(HttpHeaderNames.COOKIE, "a=b; c=d")
|
.add(HttpHeaderNames.COOKIE, "a=b; c=d")
|
||||||
.add(HttpHeaderNames.COOKIE, "e=f");
|
.add(HttpHeaderNames.COOKIE, "e=f");
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -246,12 +237,9 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
.path(new AsciiString("/some/path/resource2"))
|
.path(new AsciiString("/some/path/resource2"))
|
||||||
.add(new AsciiString("çã".getBytes(CharsetUtil.UTF_8)),
|
.add(new AsciiString("çã".getBytes(CharsetUtil.UTF_8)),
|
||||||
new AsciiString("Ãã".getBytes(CharsetUtil.UTF_8)));
|
new AsciiString("Ãã".getBytes(CharsetUtil.UTF_8)));
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitResponses();
|
awaitResponses();
|
||||||
assertTrue(isStreamError(clientException));
|
assertTrue(isStreamError(clientException));
|
||||||
|
@ -271,14 +259,11 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
||||||
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path(
|
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path(
|
||||||
new AsciiString("/some/path/resource2"));
|
new AsciiString("/some/path/resource2"));
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, true,
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
newPromiseClient());
|
||||||
clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, true,
|
clientChannel.flush();
|
||||||
newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -305,17 +290,14 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path(
|
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path(
|
||||||
new AsciiString("/some/path/resource2"));
|
new AsciiString("/some/path/resource2"));
|
||||||
final int midPoint = text.length() / 2;
|
final int midPoint = text.length() / 2;
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientHandler.encoder().writeData(
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
ctxClient(), 3, content.retainedSlice(0, midPoint), 0, false, newPromiseClient());
|
||||||
clientHandler.encoder().writeData(
|
clientHandler.encoder().writeData(
|
||||||
ctxClient(), 3, content.retainedSlice(0, midPoint), 0, false, newPromiseClient());
|
ctxClient(), 3, content.retainedSlice(midPoint, text.length() - midPoint),
|
||||||
clientHandler.encoder().writeData(
|
0, true, newPromiseClient());
|
||||||
ctxClient(), 3, content.retainedSlice(midPoint, text.length() - midPoint),
|
clientChannel.flush();
|
||||||
0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -341,15 +323,12 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
||||||
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path(
|
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path(
|
||||||
new AsciiString("/some/path/resource2"));
|
new AsciiString("/some/path/resource2"));
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientHandler.encoder().writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient());
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
clientHandler.encoder().writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient());
|
||||||
clientHandler.encoder().writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient());
|
clientHandler.encoder().writeData(ctxClient(), 3, content.retain(), 0, true, newPromiseClient());
|
||||||
clientHandler.encoder().writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient());
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeData(ctxClient(), 3, content.retain(), 0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -383,15 +362,12 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
.set(new AsciiString("foo"), new AsciiString("goo"))
|
.set(new AsciiString("foo"), new AsciiString("goo"))
|
||||||
.set(new AsciiString("foo2"), new AsciiString("goo2"))
|
.set(new AsciiString("foo2"), new AsciiString("goo2"))
|
||||||
.add(new AsciiString("foo2"), new AsciiString("goo3"));
|
.add(new AsciiString("foo2"), new AsciiString("goo3"));
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, false,
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
newPromiseClient());
|
||||||
clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, false,
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers2, 0, true, newPromiseClient());
|
||||||
newPromiseClient());
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers2, 0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -428,19 +404,16 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
new AsciiString("/some/path/resource"));
|
new AsciiString("/some/path/resource"));
|
||||||
final Http2Headers http2Headers2 = new DefaultHttp2Headers().method(new AsciiString("PUT")).path(
|
final Http2Headers http2Headers2 = new DefaultHttp2Headers().method(new AsciiString("PUT")).path(
|
||||||
new AsciiString("/some/path/resource2"));
|
new AsciiString("/some/path/resource2"));
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientHandler.encoder().writeHeaders(ctxClient(), 5, http2Headers2, 3, (short) 123, true, 0,
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
false, newPromiseClient());
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 5, http2Headers2, 3, (short) 123, true, 0,
|
clientChannel.flush(); // Headers are queued in the flow controller and so flush them.
|
||||||
false, newPromiseClient());
|
clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, true,
|
||||||
clientChannel.flush(); // Headers are queued in the flow controller and so flush them.
|
newPromiseClient());
|
||||||
clientHandler.encoder().writeData(ctxClient(), 3, content.retainedDuplicate(), 0, true,
|
clientHandler.encoder().writeData(ctxClient(), 5, content2.retainedDuplicate(), 0, true,
|
||||||
newPromiseClient());
|
newPromiseClient());
|
||||||
clientHandler.encoder().writeData(ctxClient(), 5, content2.retainedDuplicate(), 0, true,
|
clientChannel.flush();
|
||||||
newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> httpObjectCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> httpObjectCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -485,12 +458,9 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
||||||
final Http2Headers http2Headers3 = new DefaultHttp2Headers().method(new AsciiString("GET"))
|
final Http2Headers http2Headers3 = new DefaultHttp2Headers().method(new AsciiString("GET"))
|
||||||
.path(new AsciiString("/push/test"));
|
.path(new AsciiString("/push/test"));
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers3, 0, true, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers3, 0, true, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -507,17 +477,14 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
final Http2Headers http2Headers2 = new DefaultHttp2Headers()
|
final Http2Headers http2Headers2 = new DefaultHttp2Headers()
|
||||||
.scheme(new AsciiString("https"))
|
.scheme(new AsciiString("https"))
|
||||||
.authority(new AsciiString("example.org"));
|
.authority(new AsciiString("example.org"));
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2Headers, 0, false, newPromiseServer());
|
||||||
public void run() throws Http2Exception {
|
serverHandler.encoder().writePushPromise(ctxServer(), 3, 2, http2Headers2, 0, newPromiseServer());
|
||||||
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2Headers, 0, false, newPromiseServer());
|
serverHandler.encoder().writeData(ctxServer(), 3, content.retainedDuplicate(), 0, true,
|
||||||
serverHandler.encoder().writePushPromise(ctxServer(), 3, 2, http2Headers2, 0, newPromiseServer());
|
newPromiseServer());
|
||||||
serverHandler.encoder().writeData(ctxServer(), 3, content.retainedDuplicate(), 0, true,
|
serverHandler.encoder().writeData(ctxServer(), 5, content2.retainedDuplicate(), 0, true,
|
||||||
newPromiseServer());
|
newPromiseServer());
|
||||||
serverHandler.encoder().writeData(ctxServer(), 5, content2.retainedDuplicate(), 0, true,
|
serverConnectedChannel.flush();
|
||||||
newPromiseServer());
|
|
||||||
serverConnectedChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
awaitResponses();
|
awaitResponses();
|
||||||
ArgumentCaptor<FullHttpMessage> responseCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
ArgumentCaptor<FullHttpMessage> responseCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
|
||||||
|
@ -553,12 +520,9 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
final FullHttpMessage response2 = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
final FullHttpMessage response2 = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
||||||
public void run() throws Http2Exception {
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
awaitRequests();
|
awaitRequests();
|
||||||
|
@ -566,26 +530,20 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
|
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
|
||||||
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0);
|
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0);
|
||||||
final Http2Headers http2HeadersResponse = new DefaultHttp2Headers().status(new AsciiString("100"));
|
final Http2Headers http2HeadersResponse = new DefaultHttp2Headers().status(new AsciiString("100"));
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2HeadersResponse, 0, false,
|
||||||
public void run() throws Http2Exception {
|
newPromiseServer());
|
||||||
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2HeadersResponse, 0, false,
|
serverConnectedChannel.flush();
|
||||||
newPromiseServer());
|
|
||||||
serverConnectedChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
awaitResponses();
|
awaitResponses();
|
||||||
httpHeaders = request2.headers();
|
httpHeaders = request2.headers();
|
||||||
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length());
|
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length());
|
||||||
httpHeaders.remove(HttpHeaderNames.EXPECT);
|
httpHeaders.remove(HttpHeaderNames.EXPECT);
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeData(ctxClient(), 3, payload.retainedDuplicate(), 0, true,
|
||||||
public void run() {
|
newPromiseClient());
|
||||||
clientHandler.encoder().writeData(ctxClient(), 3, payload.retainedDuplicate(), 0, true,
|
clientChannel.flush();
|
||||||
newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
awaitRequests2();
|
awaitRequests2();
|
||||||
|
@ -595,13 +553,10 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
|
||||||
|
|
||||||
final Http2Headers http2HeadersResponse2 = new DefaultHttp2Headers().status(new AsciiString("200"));
|
final Http2Headers http2HeadersResponse2 = new DefaultHttp2Headers().status(new AsciiString("200"));
|
||||||
runInChannel(serverConnectedChannel, new Http2Runnable() {
|
runInChannel(serverConnectedChannel, () -> {
|
||||||
@Override
|
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2HeadersResponse2, 0, true,
|
||||||
public void run() throws Http2Exception {
|
newPromiseServer());
|
||||||
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2HeadersResponse2, 0, true,
|
serverConnectedChannel.flush();
|
||||||
newPromiseServer());
|
|
||||||
serverConnectedChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
awaitResponses2();
|
awaitResponses2();
|
||||||
|
@ -633,12 +588,9 @@ public class InboundHttp2ToHttpAdapterTest {
|
||||||
public void propagateSettings() throws Exception {
|
public void propagateSettings() throws Exception {
|
||||||
boostrapEnv(1, 1, 2);
|
boostrapEnv(1, 1, 2);
|
||||||
final Http2Settings settings = new Http2Settings().pushEnabled(true);
|
final Http2Settings settings = new Http2Settings().pushEnabled(true);
|
||||||
runInChannel(clientChannel, new Http2Runnable() {
|
runInChannel(clientChannel, () -> {
|
||||||
@Override
|
clientHandler.encoder().writeSettings(ctxClient(), settings, newPromiseClient());
|
||||||
public void run() {
|
clientChannel.flush();
|
||||||
clientHandler.encoder().writeSettings(ctxClient(), settings, newPromiseClient());
|
|
||||||
clientChannel.flush();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
assertTrue(settingsLatch.await(5, SECONDS));
|
assertTrue(settingsLatch.await(5, SECONDS));
|
||||||
ArgumentCaptor<Http2Settings> settingsCaptor = ArgumentCaptor.forClass(Http2Settings.class);
|
ArgumentCaptor<Http2Settings> settingsCaptor = ArgumentCaptor.forClass(Http2Settings.class);
|
||||||
|
|
|
@ -46,10 +46,7 @@ public class LastInboundHandler extends ChannelDuplexHandler {
|
||||||
void accept(T obj);
|
void accept(T obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Consumer<Object> NOOP_CONSUMER = new Consumer<Object>() {
|
private static final Consumer<Object> NOOP_CONSUMER = obj -> {
|
||||||
@Override
|
|
||||||
public void accept(Object obj) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
@ -130,12 +130,7 @@ public class StreamBufferingEncoderTest {
|
||||||
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
||||||
when(channel.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
when(channel.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
|
||||||
when(executor.inEventLoop()).thenReturn(true);
|
when(executor.inEventLoop()).thenReturn(true);
|
||||||
doAnswer(new Answer<ChannelPromise>() {
|
doAnswer((Answer<ChannelPromise>) invocation -> newPromise()).when(ctx).newPromise();
|
||||||
@Override
|
|
||||||
public ChannelPromise answer(InvocationOnMock invocation) throws Throwable {
|
|
||||||
return newPromise();
|
|
||||||
}
|
|
||||||
}).when(ctx).newPromise();
|
|
||||||
when(ctx.executor()).thenReturn(executor);
|
when(ctx.executor()).thenReturn(executor);
|
||||||
when(channel.isActive()).thenReturn(false);
|
when(channel.isActive()).thenReturn(false);
|
||||||
when(channel.config()).thenReturn(config);
|
when(channel.config()).thenReturn(config);
|
||||||
|
@ -519,17 +514,14 @@ public class StreamBufferingEncoderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Answer<ChannelFuture> successAnswer() {
|
private Answer<ChannelFuture> successAnswer() {
|
||||||
return new Answer<ChannelFuture>() {
|
return invocation -> {
|
||||||
@Override
|
for (Object a : invocation.getArguments()) {
|
||||||
public ChannelFuture answer(InvocationOnMock invocation) throws Throwable {
|
ReferenceCountUtil.safeRelease(a);
|
||||||
for (Object a : invocation.getArguments()) {
|
|
||||||
ReferenceCountUtil.safeRelease(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelPromise future = newPromise();
|
|
||||||
future.setSuccess();
|
|
||||||
return future;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChannelPromise future = newPromise();
|
||||||
|
future.setSuccess();
|
||||||
|
return future;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,17 +83,14 @@ public class UniformStreamByteDistributorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Answer<Void> writeAnswer() {
|
private Answer<Void> writeAnswer() {
|
||||||
return new Answer<Void>() {
|
return in -> {
|
||||||
@Override
|
Http2Stream stream = in.getArgument(0);
|
||||||
public Void answer(InvocationOnMock in) throws Throwable {
|
int numBytes = in.getArgument(1);
|
||||||
Http2Stream stream = in.getArgument(0);
|
TestStreamByteDistributorStreamState state = stateMap.get(stream.id());
|
||||||
int numBytes = in.getArgument(1);
|
state.pendingBytes -= numBytes;
|
||||||
TestStreamByteDistributorStreamState state = stateMap.get(stream.id());
|
state.hasFrame = state.pendingBytes > 0;
|
||||||
state.pendingBytes -= numBytes;
|
distributor.updateStreamableBytes(state);
|
||||||
state.hasFrame = state.pendingBytes > 0;
|
return null;
|
||||||
distributor.updateStreamableBytes(state);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,13 +79,10 @@ public class WeightedFairQueueByteDistributorDependencyTreeTest extends
|
||||||
final Http2Stream streamB = connection.local().createStream(5, false);
|
final Http2Stream streamB = connection.local().createStream(5, false);
|
||||||
final Http2Stream streamC = connection.local().createStream(7, false);
|
final Http2Stream streamC = connection.local().createStream(7, false);
|
||||||
setPriority(streamB.id(), streamA.id(), DEFAULT_PRIORITY_WEIGHT, false);
|
setPriority(streamB.id(), streamA.id(), DEFAULT_PRIORITY_WEIGHT, false);
|
||||||
connection.forEachActiveStream(new Http2StreamVisitor() {
|
connection.forEachActiveStream(stream -> {
|
||||||
@Override
|
streamA.close();
|
||||||
public boolean visit(Http2Stream stream) throws Http2Exception {
|
setPriority(streamB.id(), streamC.id(), DEFAULT_PRIORITY_WEIGHT, false);
|
||||||
streamA.close();
|
return true;
|
||||||
setPriority(streamB.id(), streamC.id(), DEFAULT_PRIORITY_WEIGHT, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,33 +29,30 @@ import io.netty.util.NetUtil;
|
||||||
*/
|
*/
|
||||||
public interface Socks5AddressEncoder {
|
public interface Socks5AddressEncoder {
|
||||||
|
|
||||||
Socks5AddressEncoder DEFAULT = new Socks5AddressEncoder() {
|
Socks5AddressEncoder DEFAULT = (addrType, addrValue, out) -> {
|
||||||
@Override
|
final byte typeVal = addrType.byteValue();
|
||||||
public void encodeAddress(Socks5AddressType addrType, String addrValue, ByteBuf out) throws Exception {
|
if (typeVal == Socks5AddressType.IPv4.byteValue()) {
|
||||||
final byte typeVal = addrType.byteValue();
|
if (addrValue != null) {
|
||||||
if (typeVal == Socks5AddressType.IPv4.byteValue()) {
|
out.writeBytes(NetUtil.createByteArrayFromIpAddressString(addrValue));
|
||||||
if (addrValue != null) {
|
|
||||||
out.writeBytes(NetUtil.createByteArrayFromIpAddressString(addrValue));
|
|
||||||
} else {
|
|
||||||
out.writeInt(0);
|
|
||||||
}
|
|
||||||
} else if (typeVal == Socks5AddressType.DOMAIN.byteValue()) {
|
|
||||||
if (addrValue != null) {
|
|
||||||
out.writeByte(addrValue.length());
|
|
||||||
out.writeCharSequence(addrValue, CharsetUtil.US_ASCII);
|
|
||||||
} else {
|
|
||||||
out.writeByte(0);
|
|
||||||
}
|
|
||||||
} else if (typeVal == Socks5AddressType.IPv6.byteValue()) {
|
|
||||||
if (addrValue != null) {
|
|
||||||
out.writeBytes(NetUtil.createByteArrayFromIpAddressString(addrValue));
|
|
||||||
} else {
|
|
||||||
out.writeLong(0);
|
|
||||||
out.writeLong(0);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new EncoderException("unsupported addrType: " + (addrType.byteValue() & 0xFF));
|
out.writeInt(0);
|
||||||
}
|
}
|
||||||
|
} else if (typeVal == Socks5AddressType.DOMAIN.byteValue()) {
|
||||||
|
if (addrValue != null) {
|
||||||
|
out.writeByte(addrValue.length());
|
||||||
|
out.writeCharSequence(addrValue, CharsetUtil.US_ASCII);
|
||||||
|
} else {
|
||||||
|
out.writeByte(0);
|
||||||
|
}
|
||||||
|
} else if (typeVal == Socks5AddressType.IPv6.byteValue()) {
|
||||||
|
if (addrValue != null) {
|
||||||
|
out.writeBytes(NetUtil.createByteArrayFromIpAddressString(addrValue));
|
||||||
|
} else {
|
||||||
|
out.writeLong(0);
|
||||||
|
out.writeLong(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new EncoderException("unsupported addrType: " + (addrType.byteValue() & 0xFF));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -72,31 +72,28 @@ public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter
|
||||||
/**
|
/**
|
||||||
* Cumulate {@link ByteBuf}s by merge them into one {@link ByteBuf}'s, using memory copies.
|
* Cumulate {@link ByteBuf}s by merge them into one {@link ByteBuf}'s, using memory copies.
|
||||||
*/
|
*/
|
||||||
public static final Cumulator MERGE_CUMULATOR = new Cumulator() {
|
public static final Cumulator MERGE_CUMULATOR = (alloc, cumulation, in) -> {
|
||||||
@Override
|
try {
|
||||||
public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) {
|
final ByteBuf buffer;
|
||||||
try {
|
if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes()
|
||||||
final ByteBuf buffer;
|
|| cumulation.refCnt() > 1 || cumulation.isReadOnly()) {
|
||||||
if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes()
|
// Expand cumulation (by replace it) when either there is not more room in the buffer
|
||||||
|| cumulation.refCnt() > 1 || cumulation.isReadOnly()) {
|
// or if the refCnt is greater then 1 which may happen when the user use slice().retain() or
|
||||||
// Expand cumulation (by replace it) when either there is not more room in the buffer
|
// duplicate().retain() or if its read-only.
|
||||||
// or if the refCnt is greater then 1 which may happen when the user use slice().retain() or
|
//
|
||||||
// duplicate().retain() or if its read-only.
|
// See:
|
||||||
//
|
// - https://github.com/netty/netty/issues/2327
|
||||||
// See:
|
// - https://github.com/netty/netty/issues/1764
|
||||||
// - https://github.com/netty/netty/issues/2327
|
buffer = expandCumulation(alloc, cumulation, in.readableBytes());
|
||||||
// - https://github.com/netty/netty/issues/1764
|
} else {
|
||||||
buffer = expandCumulation(alloc, cumulation, in.readableBytes());
|
buffer = cumulation;
|
||||||
} else {
|
|
||||||
buffer = cumulation;
|
|
||||||
}
|
|
||||||
buffer.writeBytes(in);
|
|
||||||
return buffer;
|
|
||||||
} finally {
|
|
||||||
// We must release in in all cases as otherwise it may produce a leak if writeBytes(...) throw
|
|
||||||
// for whatever release (for example because of OutOfMemoryError)
|
|
||||||
in.release();
|
|
||||||
}
|
}
|
||||||
|
buffer.writeBytes(in);
|
||||||
|
return buffer;
|
||||||
|
} finally {
|
||||||
|
// We must release in in all cases as otherwise it may produce a leak if writeBytes(...) throw
|
||||||
|
// for whatever release (for example because of OutOfMemoryError)
|
||||||
|
in.release();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,39 +102,36 @@ public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter
|
||||||
* Be aware that {@link CompositeByteBuf} use a more complex indexing implementation so depending on your use-case
|
* Be aware that {@link CompositeByteBuf} use a more complex indexing implementation so depending on your use-case
|
||||||
* and the decoder implementation this may be slower then just use the {@link #MERGE_CUMULATOR}.
|
* and the decoder implementation this may be slower then just use the {@link #MERGE_CUMULATOR}.
|
||||||
*/
|
*/
|
||||||
public static final Cumulator COMPOSITE_CUMULATOR = new Cumulator() {
|
public static final Cumulator COMPOSITE_CUMULATOR = (alloc, cumulation, in) -> {
|
||||||
@Override
|
ByteBuf buffer;
|
||||||
public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) {
|
try {
|
||||||
ByteBuf buffer;
|
if (cumulation.refCnt() > 1) {
|
||||||
try {
|
// Expand cumulation (by replace it) when the refCnt is greater then 1 which may happen when the
|
||||||
if (cumulation.refCnt() > 1) {
|
// user use slice().retain() or duplicate().retain().
|
||||||
// Expand cumulation (by replace it) when the refCnt is greater then 1 which may happen when the
|
//
|
||||||
// user use slice().retain() or duplicate().retain().
|
// See:
|
||||||
//
|
// - https://github.com/netty/netty/issues/2327
|
||||||
// See:
|
// - https://github.com/netty/netty/issues/1764
|
||||||
// - https://github.com/netty/netty/issues/2327
|
buffer = expandCumulation(alloc, cumulation, in.readableBytes());
|
||||||
// - https://github.com/netty/netty/issues/1764
|
buffer.writeBytes(in);
|
||||||
buffer = expandCumulation(alloc, cumulation, in.readableBytes());
|
} else {
|
||||||
buffer.writeBytes(in);
|
CompositeByteBuf composite;
|
||||||
|
if (cumulation instanceof CompositeByteBuf) {
|
||||||
|
composite = (CompositeByteBuf) cumulation;
|
||||||
} else {
|
} else {
|
||||||
CompositeByteBuf composite;
|
composite = alloc.compositeBuffer(Integer.MAX_VALUE);
|
||||||
if (cumulation instanceof CompositeByteBuf) {
|
composite.addComponent(true, cumulation);
|
||||||
composite = (CompositeByteBuf) cumulation;
|
|
||||||
} else {
|
|
||||||
composite = alloc.compositeBuffer(Integer.MAX_VALUE);
|
|
||||||
composite.addComponent(true, cumulation);
|
|
||||||
}
|
|
||||||
composite.addComponent(true, in);
|
|
||||||
in = null;
|
|
||||||
buffer = composite;
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
} finally {
|
|
||||||
if (in != null) {
|
|
||||||
// We must release if the ownership was not transferred as otherwise it may produce a leak if
|
|
||||||
// writeBytes(...) throw for whatever release (for example because of OutOfMemoryError).
|
|
||||||
in.release();
|
|
||||||
}
|
}
|
||||||
|
composite.addComponent(true, in);
|
||||||
|
in = null;
|
||||||
|
buffer = composite;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
} finally {
|
||||||
|
if (in != null) {
|
||||||
|
// We must release if the ownership was not transferred as otherwise it may produce a leak if
|
||||||
|
// writeBytes(...) throw for whatever release (for example because of OutOfMemoryError).
|
||||||
|
in.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,11 +28,8 @@ import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
*/
|
*/
|
||||||
final class CodecOutputList extends AbstractList<Object> implements RandomAccess {
|
final class CodecOutputList extends AbstractList<Object> implements RandomAccess {
|
||||||
|
|
||||||
private static final CodecOutputListRecycler NOOP_RECYCLER = new CodecOutputListRecycler() {
|
private static final CodecOutputListRecycler NOOP_RECYCLER = object -> {
|
||||||
@Override
|
// drop on the floor and let the GC handle it.
|
||||||
public void recycle(CodecOutputList object) {
|
|
||||||
// drop on the floor and let the GC handle it.
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final FastThreadLocal<CodecOutputLists> CODEC_OUTPUT_LISTS_POOL =
|
private static final FastThreadLocal<CodecOutputLists> CODEC_OUTPUT_LISTS_POOL =
|
||||||
|
|
|
@ -64,12 +64,7 @@ public class DefaultHeaders<K, V, T extends Headers<K, V, T>> implements Headers
|
||||||
void validateName(K name);
|
void validateName(K name);
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
NameValidator NOT_NULL = new NameValidator() {
|
NameValidator NOT_NULL = name -> checkNotNull(name, "name");
|
||||||
@Override
|
|
||||||
public void validateName(Object name) {
|
|
||||||
checkNotNull(name, "name");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
@ -210,12 +210,9 @@ public abstract class MessageAggregator<I, S, C extends ByteBufHolder, O extends
|
||||||
// Cache the write listener for reuse.
|
// Cache the write listener for reuse.
|
||||||
ChannelFutureListener listener = continueResponseWriteListener;
|
ChannelFutureListener listener = continueResponseWriteListener;
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
continueResponseWriteListener = listener = new ChannelFutureListener() {
|
continueResponseWriteListener = listener = future -> {
|
||||||
@Override
|
if (!future.isSuccess()) {
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
ctx.fireExceptionCaught(future.cause());
|
||||||
if (!future.isSuccess()) {
|
|
||||||
ctx.fireExceptionCaught(future.cause());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,12 +42,9 @@ abstract class ByteBufChecksum implements Checksum {
|
||||||
CRC32_UPDATE_METHOD = updateByteBuffer(new CRC32());
|
CRC32_UPDATE_METHOD = updateByteBuffer(new CRC32());
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ByteProcessor updateProcessor = new ByteProcessor() {
|
private final ByteProcessor updateProcessor = value -> {
|
||||||
@Override
|
update(value);
|
||||||
public boolean process(byte value) throws Exception {
|
return true;
|
||||||
update(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Method updateByteBuffer(Checksum checksum) {
|
private static Method updateByteBuffer(Checksum checksum) {
|
||||||
|
|
|
@ -33,12 +33,7 @@ import static io.netty.handler.codec.compression.Bzip2Constants.*;
|
||||||
* 7. Huffman encode and write data - {@link #close(ByteBuf)} (through {@link Bzip2HuffmanStageEncoder})
|
* 7. Huffman encode and write data - {@link #close(ByteBuf)} (through {@link Bzip2HuffmanStageEncoder})
|
||||||
*/
|
*/
|
||||||
final class Bzip2BlockCompressor {
|
final class Bzip2BlockCompressor {
|
||||||
private final ByteProcessor writeProcessor = new ByteProcessor() {
|
private final ByteProcessor writeProcessor = this::write;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) throws Exception {
|
|
||||||
return write(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A writer that provides bit-level writes.
|
* A writer that provides bit-level writes.
|
||||||
|
|
|
@ -184,12 +184,9 @@ public class Bzip2Encoder extends MessageToByteEncoder<ByteBuf> {
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
return finishEncode(ctx, promise);
|
return finishEncode(ctx, promise);
|
||||||
} else {
|
} else {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
ChannelFuture f = finishEncode(ctx(), promise);
|
||||||
public void run() {
|
f.addListener(new ChannelPromiseNotifier(promise));
|
||||||
ChannelFuture f = finishEncode(ctx(), promise);
|
|
||||||
f.addListener(new ChannelPromiseNotifier(promise));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
@ -198,20 +195,12 @@ public class Bzip2Encoder extends MessageToByteEncoder<ByteBuf> {
|
||||||
@Override
|
@Override
|
||||||
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
|
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
|
||||||
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
||||||
f.addListener(new ChannelFutureListener() {
|
f.addListener((ChannelFutureListener) f1 -> ctx.close(promise));
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture f) throws Exception {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!f.isDone()) {
|
if (!f.isDone()) {
|
||||||
// Ensure the channel is closed even if the write operation completes in time.
|
// Ensure the channel is closed even if the write operation completes in time.
|
||||||
ctx.executor().schedule(new Runnable() {
|
ctx.executor().schedule(() -> {
|
||||||
@Override
|
ctx.close(promise);
|
||||||
public void run() {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,12 +252,9 @@ public class JZlibEncoder extends ZlibEncoder {
|
||||||
return finishEncode(ctx, promise);
|
return finishEncode(ctx, promise);
|
||||||
} else {
|
} else {
|
||||||
final ChannelPromise p = ctx.newPromise();
|
final ChannelPromise p = ctx.newPromise();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
ChannelFuture f = finishEncode(ctx(), p);
|
||||||
public void run() {
|
f.addListener(new ChannelPromiseNotifier(promise));
|
||||||
ChannelFuture f = finishEncode(ctx(), p);
|
|
||||||
f.addListener(new ChannelPromiseNotifier(promise));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -342,20 +339,12 @@ public class JZlibEncoder extends ZlibEncoder {
|
||||||
final ChannelHandlerContext ctx,
|
final ChannelHandlerContext ctx,
|
||||||
final ChannelPromise promise) {
|
final ChannelPromise promise) {
|
||||||
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
||||||
f.addListener(new ChannelFutureListener() {
|
f.addListener((ChannelFutureListener) f1 -> ctx.close(promise));
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture f) throws Exception {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!f.isDone()) {
|
if (!f.isDone()) {
|
||||||
// Ensure the channel is closed even if the write operation completes in time.
|
// Ensure the channel is closed even if the write operation completes in time.
|
||||||
ctx.executor().schedule(new Runnable() {
|
ctx.executor().schedule(() -> {
|
||||||
@Override
|
ctx.close(promise);
|
||||||
public void run() {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,12 +163,9 @@ public class JdkZlibEncoder extends ZlibEncoder {
|
||||||
return finishEncode(ctx, promise);
|
return finishEncode(ctx, promise);
|
||||||
} else {
|
} else {
|
||||||
final ChannelPromise p = ctx.newPromise();
|
final ChannelPromise p = ctx.newPromise();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
ChannelFuture f = finishEncode(ctx(), p);
|
||||||
public void run() {
|
f.addListener(new ChannelPromiseNotifier(promise));
|
||||||
ChannelFuture f = finishEncode(ctx(), p);
|
|
||||||
f.addListener(new ChannelPromiseNotifier(promise));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -262,20 +259,12 @@ public class JdkZlibEncoder extends ZlibEncoder {
|
||||||
@Override
|
@Override
|
||||||
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
|
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
|
||||||
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
||||||
f.addListener(new ChannelFutureListener() {
|
f.addListener((ChannelFutureListener) f1 -> ctx.close(promise));
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture f) throws Exception {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!f.isDone()) {
|
if (!f.isDone()) {
|
||||||
// Ensure the channel is closed even if the write operation completes in time.
|
// Ensure the channel is closed even if the write operation completes in time.
|
||||||
ctx.executor().schedule(new Runnable() {
|
ctx.executor().schedule(() -> {
|
||||||
@Override
|
ctx.close(promise);
|
||||||
public void run() {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,12 +364,9 @@ public class Lz4FrameEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
return finishEncode(ctx, promise);
|
return finishEncode(ctx, promise);
|
||||||
} else {
|
} else {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
ChannelFuture f = finishEncode(ctx(), promise);
|
||||||
public void run() {
|
f.addListener(new ChannelPromiseNotifier(promise));
|
||||||
ChannelFuture f = finishEncode(ctx(), promise);
|
|
||||||
f.addListener(new ChannelPromiseNotifier(promise));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
@ -378,20 +375,12 @@ public class Lz4FrameEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||||
@Override
|
@Override
|
||||||
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
|
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
|
||||||
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
|
||||||
f.addListener(new ChannelFutureListener() {
|
f.addListener((ChannelFutureListener) f1 -> ctx.close(promise));
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture f) throws Exception {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!f.isDone()) {
|
if (!f.isDone()) {
|
||||||
// Ensure the channel is closed even if the write operation completes in time.
|
// Ensure the channel is closed even if the write operation completes in time.
|
||||||
ctx.executor().schedule(new Runnable() {
|
ctx.executor().schedule(() -> {
|
||||||
@Override
|
ctx.close(promise);
|
||||||
public void run() {
|
|
||||||
ctx.close(promise);
|
|
||||||
}
|
|
||||||
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
}, 10, TimeUnit.SECONDS); // FIXME: Magic number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,24 +270,18 @@ public class Lz4FrameEncoderTest extends AbstractEncoderTest {
|
||||||
clientChannel = bs.connect(serverChannel.localAddress()).syncUninterruptibly().channel();
|
clientChannel = bs.connect(serverChannel.localAddress()).syncUninterruptibly().channel();
|
||||||
|
|
||||||
final Channel finalClientChannel = clientChannel;
|
final Channel finalClientChannel = clientChannel;
|
||||||
clientChannel.eventLoop().execute(new Runnable() {
|
clientChannel.eventLoop().execute(() -> {
|
||||||
@Override
|
finalClientChannel.close();
|
||||||
public void run() {
|
final int size = 27;
|
||||||
finalClientChannel.close();
|
ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(size, size);
|
||||||
final int size = 27;
|
finalClientChannel.writeAndFlush(buf.writerIndex(buf.writerIndex() + size))
|
||||||
ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(size, size);
|
.addListener((ChannelFutureListener) future -> {
|
||||||
finalClientChannel.writeAndFlush(buf.writerIndex(buf.writerIndex() + size))
|
|
||||||
.addListener(new ChannelFutureListener() {
|
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
try {
|
try {
|
||||||
writeFailCauseRef.set(future.cause());
|
writeFailCauseRef.set(future.cause());
|
||||||
} finally {
|
} finally {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
latch.await();
|
latch.await();
|
||||||
Throwable writeFailCause = writeFailCauseRef.get();
|
Throwable writeFailCause = writeFailCauseRef.get();
|
||||||
|
|
|
@ -29,20 +29,10 @@ public interface BooleanSupplier {
|
||||||
/**
|
/**
|
||||||
* A supplier which always returns {@code false} and never throws.
|
* A supplier which always returns {@code false} and never throws.
|
||||||
*/
|
*/
|
||||||
BooleanSupplier FALSE_SUPPLIER = new BooleanSupplier() {
|
BooleanSupplier FALSE_SUPPLIER = () -> false;
|
||||||
@Override
|
|
||||||
public boolean get() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A supplier which always returns {@code true} and never throws.
|
* A supplier which always returns {@code true} and never throws.
|
||||||
*/
|
*/
|
||||||
BooleanSupplier TRUE_SUPPLIER = new BooleanSupplier() {
|
BooleanSupplier TRUE_SUPPLIER = () -> true;
|
||||||
@Override
|
|
||||||
public boolean get() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,42 +103,22 @@ public interface ByteProcessor {
|
||||||
/**
|
/**
|
||||||
* Aborts on a {@code CR ('\r')} or a {@code LF ('\n')}.
|
* Aborts on a {@code CR ('\r')} or a {@code LF ('\n')}.
|
||||||
*/
|
*/
|
||||||
ByteProcessor FIND_CRLF = new ByteProcessor() {
|
ByteProcessor FIND_CRLF = value -> value != CARRIAGE_RETURN && value != LINE_FEED;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) {
|
|
||||||
return value != CARRIAGE_RETURN && value != LINE_FEED;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts on a byte which is neither a {@code CR ('\r')} nor a {@code LF ('\n')}.
|
* Aborts on a byte which is neither a {@code CR ('\r')} nor a {@code LF ('\n')}.
|
||||||
*/
|
*/
|
||||||
ByteProcessor FIND_NON_CRLF = new ByteProcessor() {
|
ByteProcessor FIND_NON_CRLF = value -> value == CARRIAGE_RETURN || value == LINE_FEED;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) {
|
|
||||||
return value == CARRIAGE_RETURN || value == LINE_FEED;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts on a linear whitespace (a ({@code ' '} or a {@code '\t'}).
|
* Aborts on a linear whitespace (a ({@code ' '} or a {@code '\t'}).
|
||||||
*/
|
*/
|
||||||
ByteProcessor FIND_LINEAR_WHITESPACE = new ByteProcessor() {
|
ByteProcessor FIND_LINEAR_WHITESPACE = value -> value != SPACE && value != HTAB;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) {
|
|
||||||
return value != SPACE && value != HTAB;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts on a byte which is not a linear whitespace (neither {@code ' '} nor {@code '\t'}).
|
* Aborts on a byte which is not a linear whitespace (neither {@code ' '} nor {@code '\t'}).
|
||||||
*/
|
*/
|
||||||
ByteProcessor FIND_NON_LINEAR_WHITESPACE = new ByteProcessor() {
|
ByteProcessor FIND_NON_LINEAR_WHITESPACE = value -> value == SPACE || value == HTAB;
|
||||||
@Override
|
|
||||||
public boolean process(byte value) {
|
|
||||||
return value == SPACE || value == HTAB;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
|
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
|
||||||
|
|
|
@ -250,59 +250,56 @@ public final class NetUtil {
|
||||||
// As a SecurityManager may prevent reading the somaxconn file we wrap this in a privileged block.
|
// As a SecurityManager may prevent reading the somaxconn file we wrap this in a privileged block.
|
||||||
//
|
//
|
||||||
// See https://github.com/netty/netty/issues/3680
|
// See https://github.com/netty/netty/issues/3680
|
||||||
SOMAXCONN = AccessController.doPrivileged(new PrivilegedAction<Integer>() {
|
SOMAXCONN = AccessController.doPrivileged((PrivilegedAction<Integer>) () -> {
|
||||||
@Override
|
// Determine the default somaxconn (server socket backlog) value of the platform.
|
||||||
public Integer run() {
|
// The known defaults:
|
||||||
// Determine the default somaxconn (server socket backlog) value of the platform.
|
// - Windows NT Server 4.0+: 200
|
||||||
// The known defaults:
|
// - Linux and Mac OS X: 128
|
||||||
// - Windows NT Server 4.0+: 200
|
int somaxconn = PlatformDependent.isWindows() ? 200 : 128;
|
||||||
// - Linux and Mac OS X: 128
|
File file = new File("/proc/sys/net/core/somaxconn");
|
||||||
int somaxconn = PlatformDependent.isWindows() ? 200 : 128;
|
BufferedReader in = null;
|
||||||
File file = new File("/proc/sys/net/core/somaxconn");
|
try {
|
||||||
BufferedReader in = null;
|
// file.exists() may throw a SecurityException if a SecurityManager is used, so execute it in the
|
||||||
try {
|
// try / catch block.
|
||||||
// file.exists() may throw a SecurityException if a SecurityManager is used, so execute it in the
|
// See https://github.com/netty/netty/issues/4936
|
||||||
// try / catch block.
|
if (file.exists()) {
|
||||||
// See https://github.com/netty/netty/issues/4936
|
in = new BufferedReader(new FileReader(file));
|
||||||
if (file.exists()) {
|
somaxconn = Integer.parseInt(in.readLine());
|
||||||
in = new BufferedReader(new FileReader(file));
|
if (logger.isDebugEnabled()) {
|
||||||
somaxconn = Integer.parseInt(in.readLine());
|
logger.debug("{}: {}", file, somaxconn);
|
||||||
if (logger.isDebugEnabled()) {
|
}
|
||||||
logger.debug("{}: {}", file, somaxconn);
|
} else {
|
||||||
}
|
// Try to get from sysctl
|
||||||
} else {
|
Integer tmp = null;
|
||||||
// Try to get from sysctl
|
if (SystemPropertyUtil.getBoolean("io.netty.net.somaxconn.trySysctl", false)) {
|
||||||
Integer tmp = null;
|
tmp = sysctlGetInt("kern.ipc.somaxconn");
|
||||||
if (SystemPropertyUtil.getBoolean("io.netty.net.somaxconn.trySysctl", false)) {
|
if (tmp == null) {
|
||||||
tmp = sysctlGetInt("kern.ipc.somaxconn");
|
tmp = sysctlGetInt("kern.ipc.soacceptqueue");
|
||||||
if (tmp == null) {
|
if (tmp != null) {
|
||||||
tmp = sysctlGetInt("kern.ipc.soacceptqueue");
|
|
||||||
if (tmp != null) {
|
|
||||||
somaxconn = tmp;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
somaxconn = tmp;
|
somaxconn = tmp;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
somaxconn = tmp;
|
||||||
if (tmp == null) {
|
|
||||||
logger.debug("Failed to get SOMAXCONN from sysctl and file {}. Default: {}", file,
|
|
||||||
somaxconn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
logger.debug("Failed to get SOMAXCONN from sysctl and file {}. Default: {}", file, somaxconn, e);
|
if (tmp == null) {
|
||||||
} finally {
|
logger.debug("Failed to get SOMAXCONN from sysctl and file {}. Default: {}", file,
|
||||||
if (in != null) {
|
somaxconn);
|
||||||
try {
|
}
|
||||||
in.close();
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Ignored.
|
logger.debug("Failed to get SOMAXCONN from sysctl and file {}. Default: {}", file, somaxconn, e);
|
||||||
}
|
} finally {
|
||||||
|
if (in != null) {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignored.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return somaxconn;
|
|
||||||
}
|
}
|
||||||
|
return somaxconn;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,8 @@ public abstract class Recycler<T> {
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class);
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static final Handle NOOP_HANDLE = new Handle() {
|
private static final Handle NOOP_HANDLE = object -> {
|
||||||
@Override
|
// NOOP
|
||||||
public void recycle(Object object) {
|
|
||||||
// NOOP
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE);
|
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE);
|
||||||
private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement();
|
private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement();
|
||||||
|
|
|
@ -103,12 +103,8 @@ public abstract class ResourceLeakDetectorFactory {
|
||||||
DefaultResourceLeakDetectorFactory() {
|
DefaultResourceLeakDetectorFactory() {
|
||||||
String customLeakDetector;
|
String customLeakDetector;
|
||||||
try {
|
try {
|
||||||
customLeakDetector = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
customLeakDetector = AccessController.doPrivileged((PrivilegedAction<String>) () ->
|
||||||
@Override
|
SystemPropertyUtil.get("io.netty.customResourceLeakDetector"));
|
||||||
public String run() {
|
|
||||||
return SystemPropertyUtil.get("io.netty.customResourceLeakDetector");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable cause) {
|
} catch (Throwable cause) {
|
||||||
logger.error("Could not access System property: io.netty.customResourceLeakDetector", cause);
|
logger.error("Could not access System property: io.netty.customResourceLeakDetector", cause);
|
||||||
customLeakDetector = null;
|
customLeakDetector = null;
|
||||||
|
|
|
@ -114,12 +114,9 @@ public final class ThreadDeathWatcher {
|
||||||
// See:
|
// See:
|
||||||
// - https://github.com/netty/netty/issues/7290
|
// - https://github.com/netty/netty/issues/7290
|
||||||
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||||
@Override
|
watcherThread.setContextClassLoader(null);
|
||||||
public Void run() {
|
return null;
|
||||||
watcherThread.setContextClassLoader(null);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watcherThread.start();
|
watcherThread.start();
|
||||||
|
|
|
@ -29,20 +29,10 @@ public interface UncheckedBooleanSupplier extends BooleanSupplier {
|
||||||
/**
|
/**
|
||||||
* A supplier which always returns {@code false} and never throws.
|
* A supplier which always returns {@code false} and never throws.
|
||||||
*/
|
*/
|
||||||
UncheckedBooleanSupplier FALSE_SUPPLIER = new UncheckedBooleanSupplier() {
|
UncheckedBooleanSupplier FALSE_SUPPLIER = () -> false;
|
||||||
@Override
|
|
||||||
public boolean get() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A supplier which always returns {@code true} and never throws.
|
* A supplier which always returns {@code true} and never throws.
|
||||||
*/
|
*/
|
||||||
UncheckedBooleanSupplier TRUE_SUPPLIER = new UncheckedBooleanSupplier() {
|
UncheckedBooleanSupplier TRUE_SUPPLIER = () -> true;
|
||||||
@Override
|
|
||||||
public boolean get() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,7 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
|
||||||
static final long START_TIME = System.nanoTime();
|
static final long START_TIME = System.nanoTime();
|
||||||
|
|
||||||
private static final Comparator<RunnableScheduledFutureNode<?>> SCHEDULED_FUTURE_TASK_COMPARATOR =
|
private static final Comparator<RunnableScheduledFutureNode<?>> SCHEDULED_FUTURE_TASK_COMPARATOR =
|
||||||
new Comparator<RunnableScheduledFutureNode<?>>() {
|
Comparable::compareTo;
|
||||||
@Override
|
|
||||||
public int compare(RunnableScheduledFutureNode<?> o1, RunnableScheduledFutureNode<?> o2) {
|
|
||||||
return o1.compareTo(o2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private PriorityQueue<RunnableScheduledFutureNode<?>> scheduledTaskQueue;
|
private PriorityQueue<RunnableScheduledFutureNode<?>> scheduledTaskQueue;
|
||||||
|
|
||||||
|
@ -234,12 +229,7 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
|
||||||
if (inEventLoop()) {
|
if (inEventLoop()) {
|
||||||
add0(task);
|
add0(task);
|
||||||
} else {
|
} else {
|
||||||
execute(new Runnable() {
|
execute(() -> add0(task));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
add0(task);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
@ -258,12 +248,7 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
|
||||||
if (inEventLoop()) {
|
if (inEventLoop()) {
|
||||||
scheduledTaskQueue().removeTyped(task);
|
scheduledTaskQueue().removeTyped(task);
|
||||||
} else {
|
} else {
|
||||||
execute(new Runnable() {
|
execute(() -> removeScheduled(task));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
removeScheduled(task);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -429,12 +429,7 @@ public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
safeExecute(executor, new Runnable() {
|
safeExecute(executor, this::notifyListenersNow);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
notifyListenersNow();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -459,12 +454,7 @@ public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
safeExecute(executor, new Runnable() {
|
safeExecute(executor, () -> notifyListener0(future, listener));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
notifyListener0(future, listener);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyListenersNow() {
|
private void notifyListenersNow() {
|
||||||
|
@ -662,21 +652,11 @@ public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
|
||||||
if (listeners instanceof GenericProgressiveFutureListener[]) {
|
if (listeners instanceof GenericProgressiveFutureListener[]) {
|
||||||
final GenericProgressiveFutureListener<?>[] array =
|
final GenericProgressiveFutureListener<?>[] array =
|
||||||
(GenericProgressiveFutureListener<?>[]) listeners;
|
(GenericProgressiveFutureListener<?>[]) listeners;
|
||||||
safeExecute(executor, new Runnable() {
|
safeExecute(executor, () -> notifyProgressiveListeners0(self, array, progress, total));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
notifyProgressiveListeners0(self, array, progress, total);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
final GenericProgressiveFutureListener<ProgressiveFuture<V>> l =
|
final GenericProgressiveFutureListener<ProgressiveFuture<V>> l =
|
||||||
(GenericProgressiveFutureListener<ProgressiveFuture<V>>) listeners;
|
(GenericProgressiveFutureListener<ProgressiveFuture<V>>) listeners;
|
||||||
safeExecute(executor, new Runnable() {
|
safeExecute(executor, () -> notifyProgressiveListener0(self, l, progress, total));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
notifyProgressiveListener0(self, l, progress, total);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,12 +46,9 @@ public final class GlobalEventExecutor extends AbstractScheduledEventExecutor {
|
||||||
static {
|
static {
|
||||||
INSTANCE = new GlobalEventExecutor();
|
INSTANCE = new GlobalEventExecutor();
|
||||||
QUIET_PERIOD_TASK = new RunnableScheduledFutureAdapter<>(
|
QUIET_PERIOD_TASK = new RunnableScheduledFutureAdapter<>(
|
||||||
INSTANCE, INSTANCE.newPromise(), Executors.callable(new Runnable() {
|
INSTANCE, INSTANCE.newPromise(), Executors.callable(() -> {
|
||||||
@Override
|
// NOOP
|
||||||
public void run() {
|
}, null), deadlineNanos(SCHEDULE_QUIET_PERIOD_INTERVAL), -SCHEDULE_QUIET_PERIOD_INTERVAL);
|
||||||
// NOOP
|
|
||||||
}
|
|
||||||
}, null), deadlineNanos(SCHEDULE_QUIET_PERIOD_INTERVAL), -SCHEDULE_QUIET_PERIOD_INTERVAL);
|
|
||||||
|
|
||||||
INSTANCE.scheduledTaskQueue().add(QUIET_PERIOD_TASK);
|
INSTANCE.scheduledTaskQueue().add(QUIET_PERIOD_TASK);
|
||||||
}
|
}
|
||||||
|
@ -228,12 +225,9 @@ public final class GlobalEventExecutor extends AbstractScheduledEventExecutor {
|
||||||
// See:
|
// See:
|
||||||
// - https://github.com/netty/netty/issues/7290
|
// - https://github.com/netty/netty/issues/7290
|
||||||
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||||
@Override
|
t.setContextClassLoader(null);
|
||||||
public Void run() {
|
return null;
|
||||||
t.setContextClassLoader(null);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set the thread before starting it as otherwise inEventLoop() may return false and so produce
|
// Set the thread before starting it as otherwise inEventLoop() may return false and so produce
|
||||||
|
|
|
@ -154,12 +154,9 @@ public class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
|
final FutureListener<Object> terminationListener = future -> {
|
||||||
@Override
|
if (terminatedChildren.incrementAndGet() == children.length) {
|
||||||
public void operationComplete(Future<Object> future) throws Exception {
|
terminationFuture.setSuccess(null);
|
||||||
if (terminatedChildren.incrementAndGet() == children.length) {
|
|
||||||
terminationFuture.setSuccess(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,8 @@ import java.util.concurrent.locks.LockSupport;
|
||||||
* Expose helper methods which create different {@link RejectedExecutionHandler}s.
|
* Expose helper methods which create different {@link RejectedExecutionHandler}s.
|
||||||
*/
|
*/
|
||||||
public final class RejectedExecutionHandlers {
|
public final class RejectedExecutionHandlers {
|
||||||
private static final RejectedExecutionHandler REJECT = new RejectedExecutionHandler() {
|
private static final RejectedExecutionHandler REJECT = (task, executor) -> {
|
||||||
@Override
|
throw new RejectedExecutionException();
|
||||||
public void rejected(Runnable task, SingleThreadEventExecutor executor) {
|
|
||||||
throw new RejectedExecutionException();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private RejectedExecutionHandlers() { }
|
private RejectedExecutionHandlers() { }
|
||||||
|
@ -49,24 +46,21 @@ public final class RejectedExecutionHandlers {
|
||||||
public static RejectedExecutionHandler backoff(final int retries, long backoffAmount, TimeUnit unit) {
|
public static RejectedExecutionHandler backoff(final int retries, long backoffAmount, TimeUnit unit) {
|
||||||
ObjectUtil.checkPositive(retries, "retries");
|
ObjectUtil.checkPositive(retries, "retries");
|
||||||
final long backOffNanos = unit.toNanos(backoffAmount);
|
final long backOffNanos = unit.toNanos(backoffAmount);
|
||||||
return new RejectedExecutionHandler() {
|
return (task, executor) -> {
|
||||||
@Override
|
if (!executor.inEventLoop()) {
|
||||||
public void rejected(Runnable task, SingleThreadEventExecutor executor) {
|
for (int i = 0; i < retries; i++) {
|
||||||
if (!executor.inEventLoop()) {
|
// Try to wake up the executor so it will empty its task queue.
|
||||||
for (int i = 0; i < retries; i++) {
|
executor.wakeup(false);
|
||||||
// Try to wake up the executor so it will empty its task queue.
|
|
||||||
executor.wakeup(false);
|
|
||||||
|
|
||||||
LockSupport.parkNanos(backOffNanos);
|
LockSupport.parkNanos(backOffNanos);
|
||||||
if (executor.offerTask(task)) {
|
if (executor.offerTask(task)) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Either we tried to add the task from within the EventLoop or we was not able to add it even with
|
|
||||||
// backoff.
|
|
||||||
throw new RejectedExecutionException();
|
|
||||||
}
|
}
|
||||||
|
// Either we tried to add the task from within the EventLoop or we was not able to add it even with
|
||||||
|
// backoff.
|
||||||
|
throw new RejectedExecutionException();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,17 +59,11 @@ public class SingleThreadEventExecutor extends AbstractScheduledEventExecutor im
|
||||||
private static final int ST_SHUTDOWN = 4;
|
private static final int ST_SHUTDOWN = 4;
|
||||||
private static final int ST_TERMINATED = 5;
|
private static final int ST_TERMINATED = 5;
|
||||||
|
|
||||||
private static final Runnable WAKEUP_TASK = new Runnable() {
|
private static final Runnable WAKEUP_TASK = () -> {
|
||||||
@Override
|
// Do nothing.
|
||||||
public void run() {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
private static final Runnable NOOP_TASK = new Runnable() {
|
private static final Runnable NOOP_TASK = () -> {
|
||||||
@Override
|
// Do nothing.
|
||||||
public void run() {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
|
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
|
||||||
|
@ -467,12 +461,7 @@ public class SingleThreadEventExecutor extends AbstractScheduledEventExecutor im
|
||||||
if (inEventLoop()) {
|
if (inEventLoop()) {
|
||||||
shutdownHooks.add(task);
|
shutdownHooks.add(task);
|
||||||
} else {
|
} else {
|
||||||
execute(new Runnable() {
|
execute(() -> shutdownHooks.add(task));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
shutdownHooks.add(task);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,12 +472,7 @@ public class SingleThreadEventExecutor extends AbstractScheduledEventExecutor im
|
||||||
if (inEventLoop()) {
|
if (inEventLoop()) {
|
||||||
shutdownHooks.remove(task);
|
shutdownHooks.remove(task);
|
||||||
} else {
|
} else {
|
||||||
execute(new Runnable() {
|
execute(() -> shutdownHooks.remove(task));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
shutdownHooks.remove(task);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,66 +838,63 @@ public class SingleThreadEventExecutor extends AbstractScheduledEventExecutor im
|
||||||
|
|
||||||
private void doStartThread() {
|
private void doStartThread() {
|
||||||
assert thread == null;
|
assert thread == null;
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
thread = Thread.currentThread();
|
||||||
public void run() {
|
if (interrupted) {
|
||||||
thread = Thread.currentThread();
|
thread.interrupt();
|
||||||
if (interrupted) {
|
}
|
||||||
thread.interrupt();
|
|
||||||
|
boolean success = false;
|
||||||
|
updateLastExecutionTime();
|
||||||
|
try {
|
||||||
|
SingleThreadEventExecutor.this.run();
|
||||||
|
success = true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
logger.warn("Unexpected exception from an event executor: ", t);
|
||||||
|
} finally {
|
||||||
|
for (;;) {
|
||||||
|
int oldState = state;
|
||||||
|
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
|
||||||
|
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if confirmShutdown() was called at the end of the loop.
|
||||||
|
if (success && gracefulShutdownStartTime == 0) {
|
||||||
|
if (logger.isErrorEnabled()) {
|
||||||
|
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
|
||||||
|
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
|
||||||
|
"be called before run() implementation terminates.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean success = false;
|
|
||||||
updateLastExecutionTime();
|
|
||||||
try {
|
try {
|
||||||
SingleThreadEventExecutor.this.run();
|
// Run all remaining tasks and shutdown hooks.
|
||||||
success = true;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
logger.warn("Unexpected exception from an event executor: ", t);
|
|
||||||
} finally {
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int oldState = state;
|
if (confirmShutdown()) {
|
||||||
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
|
|
||||||
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
// Check if confirmShutdown() was called at the end of the loop.
|
|
||||||
if (success && gracefulShutdownStartTime == 0) {
|
|
||||||
if (logger.isErrorEnabled()) {
|
|
||||||
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
|
|
||||||
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
|
|
||||||
"be called before run() implementation terminates.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Run all remaining tasks and shutdown hooks.
|
cleanup();
|
||||||
for (;;) {
|
|
||||||
if (confirmShutdown()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
// Lets remove all FastThreadLocals for the Thread as we are about to terminate and notify
|
||||||
cleanup();
|
// the future. The user may block on the future and once it unblocks the JVM may terminate
|
||||||
} finally {
|
// and start unloading classes.
|
||||||
// Lets remove all FastThreadLocals for the Thread as we are about to terminate and notify
|
// See https://github.com/netty/netty/issues/6596.
|
||||||
// the future. The user may block on the future and once it unblocks the JVM may terminate
|
FastThreadLocal.removeAll();
|
||||||
// and start unloading classes.
|
|
||||||
// See https://github.com/netty/netty/issues/6596.
|
|
||||||
FastThreadLocal.removeAll();
|
|
||||||
|
|
||||||
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
|
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
|
||||||
threadLock.release();
|
threadLock.release();
|
||||||
if (!taskQueue.isEmpty()) {
|
if (!taskQueue.isEmpty()) {
|
||||||
if (logger.isWarnEnabled()) {
|
if (logger.isWarnEnabled()) {
|
||||||
logger.warn("An event executor terminated with " +
|
logger.warn("An event executor terminated with " +
|
||||||
"non-empty task queue (" + taskQueue.size() + ')');
|
"non-empty task queue (" + taskQueue.size() + ')');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
terminationFuture.setSuccess(null);
|
|
||||||
}
|
}
|
||||||
|
terminationFuture.setSuccess(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,20 +45,17 @@ final class CleanerJava6 implements Cleaner {
|
||||||
Throwable error = null;
|
Throwable error = null;
|
||||||
final ByteBuffer direct = ByteBuffer.allocateDirect(1);
|
final ByteBuffer direct = ByteBuffer.allocateDirect(1);
|
||||||
try {
|
try {
|
||||||
Object mayBeCleanerField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
Object mayBeCleanerField = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
Field cleanerField1 = direct.getClass().getDeclaredField("cleaner");
|
||||||
try {
|
if (!PlatformDependent.hasUnsafe()) {
|
||||||
Field cleanerField = direct.getClass().getDeclaredField("cleaner");
|
// We need to make it accessible if we do not use Unsafe as we will access it via
|
||||||
if (!PlatformDependent.hasUnsafe()) {
|
// reflection.
|
||||||
// We need to make it accessible if we do not use Unsafe as we will access it via
|
cleanerField1.setAccessible(true);
|
||||||
// reflection.
|
|
||||||
cleanerField.setAccessible(true);
|
|
||||||
}
|
|
||||||
return cleanerField;
|
|
||||||
} catch (Throwable cause) {
|
|
||||||
return cause;
|
|
||||||
}
|
}
|
||||||
|
return cleanerField1;
|
||||||
|
} catch (Throwable cause) {
|
||||||
|
return cause;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (mayBeCleanerField instanceof Throwable) {
|
if (mayBeCleanerField instanceof Throwable) {
|
||||||
|
@ -119,15 +116,12 @@ final class CleanerJava6 implements Cleaner {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
|
private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
|
||||||
Throwable cause = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
|
Throwable cause = AccessController.doPrivileged((PrivilegedAction<Throwable>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Throwable run() {
|
freeDirectBuffer0(buffer);
|
||||||
try {
|
return null;
|
||||||
freeDirectBuffer0(buffer);
|
} catch (Throwable cause1) {
|
||||||
return null;
|
return cause1;
|
||||||
} catch (Throwable cause) {
|
|
||||||
return cause;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (cause != null) {
|
if (cause != null) {
|
||||||
|
|
|
@ -37,18 +37,15 @@ final class CleanerJava9 implements Cleaner {
|
||||||
final Throwable error;
|
final Throwable error;
|
||||||
if (PlatformDependent0.hasUnsafe()) {
|
if (PlatformDependent0.hasUnsafe()) {
|
||||||
final ByteBuffer buffer = ByteBuffer.allocateDirect(1);
|
final ByteBuffer buffer = ByteBuffer.allocateDirect(1);
|
||||||
Object maybeInvokeMethod = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
Object maybeInvokeMethod = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
// See https://bugs.openjdk.java.net/browse/JDK-8171377
|
||||||
try {
|
Method m = PlatformDependent0.UNSAFE.getClass().getDeclaredMethod(
|
||||||
// See https://bugs.openjdk.java.net/browse/JDK-8171377
|
"invokeCleaner", ByteBuffer.class);
|
||||||
Method m = PlatformDependent0.UNSAFE.getClass().getDeclaredMethod(
|
m.invoke(PlatformDependent0.UNSAFE, buffer);
|
||||||
"invokeCleaner", ByteBuffer.class);
|
return m;
|
||||||
m.invoke(PlatformDependent0.UNSAFE, buffer);
|
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||||
return m;
|
return e;
|
||||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -91,16 +88,13 @@ final class CleanerJava9 implements Cleaner {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
|
private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
|
||||||
Exception error = AccessController.doPrivileged(new PrivilegedAction<Exception>() {
|
Exception error = AccessController.doPrivileged((PrivilegedAction<Exception>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Exception run() {
|
INVOKE_CLEANER.invoke(PlatformDependent0.UNSAFE, buffer);
|
||||||
try {
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
INVOKE_CLEANER.invoke(PlatformDependent0.UNSAFE, buffer);
|
return e;
|
||||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
PlatformDependent0.throwException(error);
|
PlatformDependent0.throwException(error);
|
||||||
|
|
|
@ -322,18 +322,15 @@ public final class NativeLibraryLoader {
|
||||||
|
|
||||||
private static void loadLibraryByHelper(final Class<?> helper, final String name, final boolean absolute)
|
private static void loadLibraryByHelper(final Class<?> helper, final String name, final boolean absolute)
|
||||||
throws UnsatisfiedLinkError {
|
throws UnsatisfiedLinkError {
|
||||||
Object ret = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
Object ret = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
// Invoke the helper to load the native library, if succeed, then the native
|
||||||
try {
|
// library belong to the specified ClassLoader.
|
||||||
// Invoke the helper to load the native library, if succeed, then the native
|
Method method = helper.getMethod("loadLibrary", String.class, boolean.class);
|
||||||
// library belong to the specified ClassLoader.
|
method.setAccessible(true);
|
||||||
Method method = helper.getMethod("loadLibrary", String.class, boolean.class);
|
return method.invoke(null, name, absolute);
|
||||||
method.setAccessible(true);
|
} catch (Exception e) {
|
||||||
return method.invoke(null, name, absolute);
|
return e;
|
||||||
} catch (Exception e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (ret instanceof Throwable) {
|
if (ret instanceof Throwable) {
|
||||||
|
@ -368,20 +365,17 @@ public final class NativeLibraryLoader {
|
||||||
try {
|
try {
|
||||||
// The helper class is NOT found in target ClassLoader, we have to define the helper class.
|
// The helper class is NOT found in target ClassLoader, we have to define the helper class.
|
||||||
final byte[] classBinary = classToByteArray(helper);
|
final byte[] classBinary = classToByteArray(helper);
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
return AccessController.doPrivileged((PrivilegedAction<Class<?>>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Class<?> run() {
|
// Define the helper class in the target ClassLoader,
|
||||||
try {
|
// then we can call the helper to load the native library.
|
||||||
// Define the helper class in the target ClassLoader,
|
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class,
|
||||||
// then we can call the helper to load the native library.
|
byte[].class, int.class, int.class);
|
||||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class,
|
defineClass.setAccessible(true);
|
||||||
byte[].class, int.class, int.class);
|
return (Class<?>) defineClass.invoke(loader, helper.getName(), classBinary, 0,
|
||||||
defineClass.setAccessible(true);
|
classBinary.length);
|
||||||
return (Class<?>) defineClass.invoke(loader, helper.getName(), classBinary, 0,
|
} catch (Exception e) {
|
||||||
classBinary.length);
|
throw new IllegalStateException("Define class failed!", e);
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalStateException("Define class failed!", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (ClassNotFoundException | Error | RuntimeException e2) {
|
} catch (ClassNotFoundException | Error | RuntimeException e2) {
|
||||||
|
|
|
@ -42,47 +42,44 @@ public final class ObjectCleaner {
|
||||||
private static final Set<AutomaticCleanerReference> LIVE_SET = ConcurrentHashMap.newKeySet();
|
private static final Set<AutomaticCleanerReference> LIVE_SET = ConcurrentHashMap.newKeySet();
|
||||||
private static final ReferenceQueue<Object> REFERENCE_QUEUE = new ReferenceQueue<>();
|
private static final ReferenceQueue<Object> REFERENCE_QUEUE = new ReferenceQueue<>();
|
||||||
private static final AtomicBoolean CLEANER_RUNNING = new AtomicBoolean(false);
|
private static final AtomicBoolean CLEANER_RUNNING = new AtomicBoolean(false);
|
||||||
private static final Runnable CLEANER_TASK = new Runnable() {
|
private static final Runnable CLEANER_TASK = () -> {
|
||||||
@Override
|
boolean interrupted = false;
|
||||||
public void run() {
|
for (;;) {
|
||||||
boolean interrupted = false;
|
// Keep on processing as long as the LIVE_SET is not empty and once it becomes empty
|
||||||
for (;;) {
|
// See if we can let this thread complete.
|
||||||
// Keep on processing as long as the LIVE_SET is not empty and once it becomes empty
|
while (!LIVE_SET.isEmpty()) {
|
||||||
// See if we can let this thread complete.
|
final AutomaticCleanerReference reference;
|
||||||
while (!LIVE_SET.isEmpty()) {
|
try {
|
||||||
final AutomaticCleanerReference reference;
|
reference = (AutomaticCleanerReference) REFERENCE_QUEUE.remove(REFERENCE_QUEUE_POLL_TIMEOUT_MS);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
// Just consume and move on
|
||||||
|
interrupted = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (reference != null) {
|
||||||
try {
|
try {
|
||||||
reference = (AutomaticCleanerReference) REFERENCE_QUEUE.remove(REFERENCE_QUEUE_POLL_TIMEOUT_MS);
|
reference.cleanup();
|
||||||
} catch (InterruptedException ex) {
|
} catch (Throwable ignored) {
|
||||||
// Just consume and move on
|
// ignore exceptions, and don't log in case the logger throws an exception, blocks, or has
|
||||||
interrupted = true;
|
// other unexpected side effects.
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (reference != null) {
|
|
||||||
try {
|
|
||||||
reference.cleanup();
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
// ignore exceptions, and don't log in case the logger throws an exception, blocks, or has
|
|
||||||
// other unexpected side effects.
|
|
||||||
}
|
|
||||||
LIVE_SET.remove(reference);
|
|
||||||
}
|
}
|
||||||
|
LIVE_SET.remove(reference);
|
||||||
}
|
}
|
||||||
CLEANER_RUNNING.set(false);
|
}
|
||||||
|
CLEANER_RUNNING.set(false);
|
||||||
|
|
||||||
// Its important to first access the LIVE_SET and then CLEANER_RUNNING to ensure correct
|
// Its important to first access the LIVE_SET and then CLEANER_RUNNING to ensure correct
|
||||||
// behavior in multi-threaded environments.
|
// behavior in multi-threaded environments.
|
||||||
if (LIVE_SET.isEmpty() || !CLEANER_RUNNING.compareAndSet(false, true)) {
|
if (LIVE_SET.isEmpty() || !CLEANER_RUNNING.compareAndSet(false, true)) {
|
||||||
// There was nothing added after we set STARTED to false or some other cleanup Thread
|
// There was nothing added after we set STARTED to false or some other cleanup Thread
|
||||||
// was started already so its safe to let this Thread complete now.
|
// was started already so its safe to let this Thread complete now.
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (interrupted) {
|
|
||||||
// As we caught the InterruptedException above we should mark the Thread as interrupted.
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (interrupted) {
|
||||||
|
// As we caught the InterruptedException above we should mark the Thread as interrupted.
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,12 +105,9 @@ public final class ObjectCleaner {
|
||||||
// See:
|
// See:
|
||||||
// - https://github.com/netty/netty/issues/7290
|
// - https://github.com/netty/netty/issues/7290
|
||||||
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
// - https://bugs.openjdk.java.net/browse/JDK-7008595
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||||
@Override
|
cleanupThread.setContextClassLoader(null);
|
||||||
public Void run() {
|
return null;
|
||||||
cleanupThread.setContextClassLoader(null);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
cleanupThread.setName(CLEANER_THREAD_NAME);
|
cleanupThread.setName(CLEANER_THREAD_NAME);
|
||||||
|
|
||||||
|
|
|
@ -99,11 +99,8 @@ public final class PlatformDependent {
|
||||||
|
|
||||||
public static final boolean BIG_ENDIAN_NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
public static final boolean BIG_ENDIAN_NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||||
|
|
||||||
private static final Cleaner NOOP = new Cleaner() {
|
private static final Cleaner NOOP = buffer -> {
|
||||||
@Override
|
// NOOP
|
||||||
public void freeDirectBuffer(ByteBuffer buffer) {
|
|
||||||
// NOOP
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -775,12 +772,9 @@ public final class PlatformDependent {
|
||||||
// jctools goes through its own process of initializing unsafe; of
|
// jctools goes through its own process of initializing unsafe; of
|
||||||
// course, this requires permissions which might not be granted to calling code, so we
|
// course, this requires permissions which might not be granted to calling code, so we
|
||||||
// must mark this block as privileged too
|
// must mark this block as privileged too
|
||||||
unsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
unsafe = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
// force JCTools to initialize unsafe
|
||||||
public Object run() {
|
return UnsafeAccess.UNSAFE;
|
||||||
// force JCTools to initialize unsafe
|
|
||||||
return UnsafeAccess.UNSAFE;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,25 +80,22 @@ final class PlatformDependent0 {
|
||||||
direct = ByteBuffer.allocateDirect(1);
|
direct = ByteBuffer.allocateDirect(1);
|
||||||
|
|
||||||
// attempt to access field Unsafe#theUnsafe
|
// attempt to access field Unsafe#theUnsafe
|
||||||
final Object maybeUnsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
final Object maybeUnsafe = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
try {
|
// We always want to try using Unsafe as the access still works on java9 as well and
|
||||||
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
// we need it for out native-transports and many optimizations.
|
||||||
// We always want to try using Unsafe as the access still works on java9 as well and
|
Throwable cause = ReflectionUtil.trySetAccessible(unsafeField, false);
|
||||||
// we need it for out native-transports and many optimizations.
|
if (cause != null) {
|
||||||
Throwable cause = ReflectionUtil.trySetAccessible(unsafeField, false);
|
return cause;
|
||||||
if (cause != null) {
|
}
|
||||||
return cause;
|
// the unsafe instance
|
||||||
}
|
return unsafeField.get(null);
|
||||||
// the unsafe instance
|
} catch (NoSuchFieldException | SecurityException
|
||||||
return unsafeField.get(null);
|
| IllegalAccessException | NoClassDefFoundError e) {
|
||||||
} catch (NoSuchFieldException | SecurityException
|
return e;
|
||||||
| IllegalAccessException | NoClassDefFoundError e) {
|
} // Also catch NoClassDefFoundError in case someone uses for example OSGI and it made
|
||||||
return e;
|
// Unsafe unloadable.
|
||||||
} // Also catch NoClassDefFoundError in case someone uses for example OSGI and it made
|
|
||||||
// Unsafe unloadable.
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// the conditional check here can not be replaced with checking that maybeUnsafe
|
// the conditional check here can not be replaced with checking that maybeUnsafe
|
||||||
|
@ -119,16 +116,13 @@ final class PlatformDependent0 {
|
||||||
// http://www.mail-archive.com/jdk6-dev@openjdk.java.net/msg00698.html
|
// http://www.mail-archive.com/jdk6-dev@openjdk.java.net/msg00698.html
|
||||||
if (unsafe != null) {
|
if (unsafe != null) {
|
||||||
final Unsafe finalUnsafe = unsafe;
|
final Unsafe finalUnsafe = unsafe;
|
||||||
final Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
final Object maybeException = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
finalUnsafe.getClass().getDeclaredMethod(
|
||||||
try {
|
"copyMemory", Object.class, long.class, Object.class, long.class, long.class);
|
||||||
finalUnsafe.getClass().getDeclaredMethod(
|
return null;
|
||||||
"copyMemory", Object.class, long.class, Object.class, long.class, long.class);
|
} catch (NoSuchMethodException | SecurityException e) {
|
||||||
return null;
|
return e;
|
||||||
} catch (NoSuchMethodException | SecurityException e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -146,24 +140,21 @@ final class PlatformDependent0 {
|
||||||
final Unsafe finalUnsafe = unsafe;
|
final Unsafe finalUnsafe = unsafe;
|
||||||
|
|
||||||
// attempt to access field Buffer#address
|
// attempt to access field Buffer#address
|
||||||
final Object maybeAddressField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
final Object maybeAddressField = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
final Field field = Buffer.class.getDeclaredField("address");
|
||||||
try {
|
// Use Unsafe to read value of the address field. This way it will not fail on JDK9+ which
|
||||||
final Field field = Buffer.class.getDeclaredField("address");
|
// will forbid changing the access level via reflection.
|
||||||
// Use Unsafe to read value of the address field. This way it will not fail on JDK9+ which
|
final long offset = finalUnsafe.objectFieldOffset(field);
|
||||||
// will forbid changing the access level via reflection.
|
final long address = finalUnsafe.getLong(direct, offset);
|
||||||
final long offset = finalUnsafe.objectFieldOffset(field);
|
|
||||||
final long address = finalUnsafe.getLong(direct, offset);
|
|
||||||
|
|
||||||
// if direct really is a direct buffer, address will be non-zero
|
// if direct really is a direct buffer, address will be non-zero
|
||||||
if (address == 0) {
|
if (address == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
return field;
|
|
||||||
} catch (NoSuchFieldException | SecurityException e) {
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
return field;
|
||||||
|
} catch (NoSuchFieldException | SecurityException e) {
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -205,20 +196,17 @@ final class PlatformDependent0 {
|
||||||
long address = -1;
|
long address = -1;
|
||||||
try {
|
try {
|
||||||
final Object maybeDirectBufferConstructor =
|
final Object maybeDirectBufferConstructor =
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
final Constructor<?> constructor =
|
||||||
try {
|
direct.getClass().getDeclaredConstructor(long.class, int.class);
|
||||||
final Constructor<?> constructor =
|
Throwable cause = ReflectionUtil.trySetAccessible(constructor, true);
|
||||||
direct.getClass().getDeclaredConstructor(long.class, int.class);
|
if (cause != null) {
|
||||||
Throwable cause = ReflectionUtil.trySetAccessible(constructor, true);
|
return cause;
|
||||||
if (cause != null) {
|
|
||||||
return cause;
|
|
||||||
}
|
|
||||||
return constructor;
|
|
||||||
} catch (NoSuchMethodException | SecurityException e) {
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
return constructor;
|
||||||
|
} catch (NoSuchMethodException | SecurityException e) {
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -299,33 +287,27 @@ final class PlatformDependent0 {
|
||||||
UNALIGNED = unaligned;
|
UNALIGNED = unaligned;
|
||||||
|
|
||||||
if (javaVersion() >= 9) {
|
if (javaVersion() >= 9) {
|
||||||
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
Object maybeException = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
// Java9 has jdk.internal.misc.Unsafe and not all methods are propagated to
|
||||||
try {
|
// sun.misc.Unsafe
|
||||||
// Java9 has jdk.internal.misc.Unsafe and not all methods are propagated to
|
Class<?> internalUnsafeClass = getClassLoader(PlatformDependent0.class)
|
||||||
// sun.misc.Unsafe
|
.loadClass("jdk.internal.misc.Unsafe");
|
||||||
Class<?> internalUnsafeClass = getClassLoader(PlatformDependent0.class)
|
Method method = internalUnsafeClass.getDeclaredMethod("getUnsafe");
|
||||||
.loadClass("jdk.internal.misc.Unsafe");
|
return method.invoke(null);
|
||||||
Method method = internalUnsafeClass.getDeclaredMethod("getUnsafe");
|
} catch (Throwable e) {
|
||||||
return method.invoke(null);
|
return e;
|
||||||
} catch (Throwable e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!(maybeException instanceof Throwable)) {
|
if (!(maybeException instanceof Throwable)) {
|
||||||
internalUnsafe = maybeException;
|
internalUnsafe = maybeException;
|
||||||
final Object finalInternalUnsafe = internalUnsafe;
|
final Object finalInternalUnsafe = internalUnsafe;
|
||||||
maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
maybeException = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Object run() {
|
return finalInternalUnsafe.getClass().getDeclaredMethod(
|
||||||
try {
|
"allocateUninitializedArray", Class.class, int.class);
|
||||||
return finalInternalUnsafe.getClass().getDeclaredMethod(
|
} catch (NoSuchMethodException | SecurityException e) {
|
||||||
"allocateUninitializedArray", Class.class, int.class);
|
return e;
|
||||||
} catch (NoSuchMethodException | SecurityException e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -746,12 +728,7 @@ final class PlatformDependent0 {
|
||||||
if (System.getSecurityManager() == null) {
|
if (System.getSecurityManager() == null) {
|
||||||
return clazz.getClassLoader();
|
return clazz.getClassLoader();
|
||||||
} else {
|
} else {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) clazz::getClassLoader);
|
||||||
@Override
|
|
||||||
public ClassLoader run() {
|
|
||||||
return clazz.getClassLoader();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,12 +736,8 @@ final class PlatformDependent0 {
|
||||||
if (System.getSecurityManager() == null) {
|
if (System.getSecurityManager() == null) {
|
||||||
return Thread.currentThread().getContextClassLoader();
|
return Thread.currentThread().getContextClassLoader();
|
||||||
} else {
|
} else {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () ->
|
||||||
@Override
|
Thread.currentThread().getContextClassLoader());
|
||||||
public ClassLoader run() {
|
|
||||||
return Thread.currentThread().getContextClassLoader();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,12 +745,7 @@ final class PlatformDependent0 {
|
||||||
if (System.getSecurityManager() == null) {
|
if (System.getSecurityManager() == null) {
|
||||||
return ClassLoader.getSystemClassLoader();
|
return ClassLoader.getSystemClassLoader();
|
||||||
} else {
|
} else {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) ClassLoader::getSystemClassLoader);
|
||||||
@Override
|
|
||||||
public ClassLoader run() {
|
|
||||||
return ClassLoader.getSystemClassLoader();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,12 +48,9 @@ public final class SocketUtils {
|
||||||
public static void connect(final Socket socket, final SocketAddress remoteAddress, final int timeout)
|
public static void connect(final Socket socket, final SocketAddress remoteAddress, final int timeout)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
|
||||||
@Override
|
socket.connect(remoteAddress, timeout);
|
||||||
public Void run() throws IOException {
|
return null;
|
||||||
socket.connect(remoteAddress, timeout);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
|
@ -62,12 +59,9 @@ public final class SocketUtils {
|
||||||
|
|
||||||
public static void bind(final Socket socket, final SocketAddress bindpoint) throws IOException {
|
public static void bind(final Socket socket, final SocketAddress bindpoint) throws IOException {
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
|
||||||
@Override
|
socket.bind(bindpoint);
|
||||||
public Void run() throws IOException {
|
return null;
|
||||||
socket.bind(bindpoint);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
|
@ -77,12 +71,8 @@ public final class SocketUtils {
|
||||||
public static boolean connect(final SocketChannel socketChannel, final SocketAddress remoteAddress)
|
public static boolean connect(final SocketChannel socketChannel, final SocketAddress remoteAddress)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
|
return AccessController.doPrivileged((PrivilegedExceptionAction<Boolean>) () ->
|
||||||
@Override
|
socketChannel.connect(remoteAddress));
|
||||||
public Boolean run() throws IOException {
|
|
||||||
return socketChannel.connect(remoteAddress);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
}
|
}
|
||||||
|
@ -90,12 +80,9 @@ public final class SocketUtils {
|
||||||
|
|
||||||
public static void bind(final SocketChannel socketChannel, final SocketAddress address) throws IOException {
|
public static void bind(final SocketChannel socketChannel, final SocketAddress address) throws IOException {
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
|
||||||
@Override
|
socketChannel.bind(address);
|
||||||
public Void run() throws IOException {
|
return null;
|
||||||
socketChannel.bind(address);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
|
@ -104,12 +91,8 @@ public final class SocketUtils {
|
||||||
|
|
||||||
public static SocketChannel accept(final ServerSocketChannel serverSocketChannel) throws IOException {
|
public static SocketChannel accept(final ServerSocketChannel serverSocketChannel) throws IOException {
|
||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<SocketChannel>() {
|
return AccessController.doPrivileged(
|
||||||
@Override
|
(PrivilegedExceptionAction<SocketChannel>) serverSocketChannel::accept);
|
||||||
public SocketChannel run() throws IOException {
|
|
||||||
return serverSocketChannel.accept();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
}
|
}
|
||||||
|
@ -117,12 +100,9 @@ public final class SocketUtils {
|
||||||
|
|
||||||
public static void bind(final DatagramChannel networkChannel, final SocketAddress address) throws IOException {
|
public static void bind(final DatagramChannel networkChannel, final SocketAddress address) throws IOException {
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
|
||||||
@Override
|
networkChannel.bind(address);
|
||||||
public Void run() throws IOException {
|
return null;
|
||||||
networkChannel.bind(address);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (IOException) e.getCause();
|
throw (IOException) e.getCause();
|
||||||
|
@ -130,22 +110,13 @@ public final class SocketUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SocketAddress localSocketAddress(final ServerSocket socket) {
|
public static SocketAddress localSocketAddress(final ServerSocket socket) {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<SocketAddress>() {
|
return AccessController.doPrivileged((PrivilegedAction<SocketAddress>) socket::getLocalSocketAddress);
|
||||||
@Override
|
|
||||||
public SocketAddress run() {
|
|
||||||
return socket.getLocalSocketAddress();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InetAddress addressByName(final String hostname) throws UnknownHostException {
|
public static InetAddress addressByName(final String hostname) throws UnknownHostException {
|
||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<InetAddress>() {
|
return AccessController.doPrivileged((PrivilegedExceptionAction<InetAddress>) () ->
|
||||||
@Override
|
InetAddress.getByName(hostname));
|
||||||
public InetAddress run() throws UnknownHostException {
|
|
||||||
return InetAddress.getByName(hostname);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (UnknownHostException) e.getCause();
|
throw (UnknownHostException) e.getCause();
|
||||||
}
|
}
|
||||||
|
@ -153,52 +124,29 @@ public final class SocketUtils {
|
||||||
|
|
||||||
public static InetAddress[] allAddressesByName(final String hostname) throws UnknownHostException {
|
public static InetAddress[] allAddressesByName(final String hostname) throws UnknownHostException {
|
||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<InetAddress[]>() {
|
return AccessController.doPrivileged((PrivilegedExceptionAction<InetAddress[]>) () ->
|
||||||
@Override
|
InetAddress.getAllByName(hostname));
|
||||||
public InetAddress[] run() throws UnknownHostException {
|
|
||||||
return InetAddress.getAllByName(hostname);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (UnknownHostException) e.getCause();
|
throw (UnknownHostException) e.getCause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InetSocketAddress socketAddress(final String hostname, final int port) {
|
public static InetSocketAddress socketAddress(final String hostname, final int port) {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<InetSocketAddress>() {
|
return AccessController.doPrivileged((PrivilegedAction<InetSocketAddress>) () ->
|
||||||
@Override
|
new InetSocketAddress(hostname, port));
|
||||||
public InetSocketAddress run() {
|
|
||||||
return new InetSocketAddress(hostname, port);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Enumeration<InetAddress> addressesFromNetworkInterface(final NetworkInterface intf) {
|
public static Enumeration<InetAddress> addressesFromNetworkInterface(final NetworkInterface intf) {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Enumeration<InetAddress>>() {
|
return AccessController.doPrivileged((PrivilegedAction<Enumeration<InetAddress>>) intf::getInetAddresses);
|
||||||
@Override
|
|
||||||
public Enumeration<InetAddress> run() {
|
|
||||||
return intf.getInetAddresses();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InetAddress loopbackAddress() {
|
public static InetAddress loopbackAddress() {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<InetAddress>() {
|
return AccessController.doPrivileged((PrivilegedAction<InetAddress>) InetAddress::getLoopbackAddress);
|
||||||
@Override
|
|
||||||
public InetAddress run() {
|
|
||||||
return InetAddress.getLoopbackAddress();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] hardwareAddressFromNetworkInterface(final NetworkInterface intf) throws SocketException {
|
public static byte[] hardwareAddressFromNetworkInterface(final NetworkInterface intf) throws SocketException {
|
||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<byte[]>() {
|
return AccessController.doPrivileged((PrivilegedExceptionAction<byte[]>) intf::getHardwareAddress);
|
||||||
@Override
|
|
||||||
public byte[] run() throws SocketException {
|
|
||||||
return intf.getHardwareAddress();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
throw (SocketException) e.getCause();
|
throw (SocketException) e.getCause();
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,12 +68,7 @@ public final class SystemPropertyUtil {
|
||||||
if (System.getSecurityManager() == null) {
|
if (System.getSecurityManager() == null) {
|
||||||
value = System.getProperty(key);
|
value = System.getProperty(key);
|
||||||
} else {
|
} else {
|
||||||
value = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
value = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty(key));
|
||||||
@Override
|
|
||||||
public String run() {
|
|
||||||
return System.getProperty(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
logger.warn("Unable to retrieve a system property '{}'; default values will be used.", key, e);
|
logger.warn("Unable to retrieve a system property '{}'; default values will be used.", key, e);
|
||||||
|
|
|
@ -35,19 +35,16 @@ class Log4J2Logger extends ExtendedLoggerWrapper implements InternalLogger {
|
||||||
// Older Log4J2 versions have only log methods that takes the format + varargs. So we should not use
|
// Older Log4J2 versions have only log methods that takes the format + varargs. So we should not use
|
||||||
// Log4J2 if the version is too old.
|
// Log4J2 if the version is too old.
|
||||||
// See https://github.com/netty/netty/issues/8217
|
// See https://github.com/netty/netty/issues/8217
|
||||||
VARARGS_ONLY = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
VARARGS_ONLY = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
|
||||||
@Override
|
try {
|
||||||
public Boolean run() {
|
Logger.class.getMethod("debug", String.class, Object.class);
|
||||||
try {
|
return false;
|
||||||
Logger.class.getMethod("debug", String.class, Object.class);
|
} catch (NoSuchMethodException ignore) {
|
||||||
return false;
|
// Log4J2 version too old.
|
||||||
} catch (NoSuchMethodException ignore) {
|
return true;
|
||||||
// Log4J2 version too old.
|
} catch (SecurityException ignore) {
|
||||||
return true;
|
// We could not detect the version so we will use Log4J2 if its on the classpath.
|
||||||
} catch (SecurityException ignore) {
|
return false;
|
||||||
// We could not detect the version so we will use Log4J2 if its on the classpath.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,19 +98,16 @@ public class AbstractReferenceCountedTest {
|
||||||
|
|
||||||
for (int a = 0; a < threads; a++) {
|
for (int a = 0; a < threads; a++) {
|
||||||
final int retainCnt = ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE);
|
final int retainCnt = ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE);
|
||||||
futures.add(service.submit(new Runnable() {
|
futures.add(service.submit(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
retainLatch.await();
|
||||||
try {
|
try {
|
||||||
retainLatch.await();
|
referenceCounted.retain(retainCnt);
|
||||||
try {
|
} catch (IllegalReferenceCountException e) {
|
||||||
referenceCounted.retain(retainCnt);
|
refCountExceptions.incrementAndGet();
|
||||||
} catch (IllegalReferenceCountException e) {
|
|
||||||
refCountExceptions.incrementAndGet();
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -147,21 +144,18 @@ public class AbstractReferenceCountedTest {
|
||||||
for (int a = 0; a < threads; a++) {
|
for (int a = 0; a < threads; a++) {
|
||||||
final AtomicInteger releaseCnt = new AtomicInteger(0);
|
final AtomicInteger releaseCnt = new AtomicInteger(0);
|
||||||
|
|
||||||
futures.add(service.submit(new Runnable() {
|
futures.add(service.submit(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
releaseLatch.await();
|
||||||
try {
|
try {
|
||||||
releaseLatch.await();
|
if (referenceCounted.release(releaseCnt.incrementAndGet())) {
|
||||||
try {
|
releasedCount.incrementAndGet();
|
||||||
if (referenceCounted.release(releaseCnt.incrementAndGet())) {
|
|
||||||
releasedCount.incrementAndGet();
|
|
||||||
}
|
|
||||||
} catch (IllegalReferenceCountException e) {
|
|
||||||
refCountExceptions.incrementAndGet();
|
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (IllegalReferenceCountException e) {
|
||||||
Thread.currentThread().interrupt();
|
refCountExceptions.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,12 +79,7 @@ public class ConstantPoolTest {
|
||||||
assertThat(array.length, is(5));
|
assertThat(array.length, is(5));
|
||||||
|
|
||||||
// Sort by name
|
// Sort by name
|
||||||
Arrays.sort(array, new Comparator<TestConstant>() {
|
Arrays.sort(array, (o1, o2) -> o1.name().compareTo(o2.name()));
|
||||||
@Override
|
|
||||||
public int compare(TestConstant o1, TestConstant o2) {
|
|
||||||
return o1.name().compareTo(o2.name());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assertThat(array[0], is(sameInstance(a)));
|
assertThat(array[0], is(sameInstance(a)));
|
||||||
assertThat(array[1], is(sameInstance(b)));
|
assertThat(array[1], is(sameInstance(b)));
|
||||||
|
|
|
@ -35,12 +35,9 @@ public class HashedWheelTimerTest {
|
||||||
public void testScheduleTimeoutShouldNotRunBeforeDelay() throws InterruptedException {
|
public void testScheduleTimeoutShouldNotRunBeforeDelay() throws InterruptedException {
|
||||||
final Timer timer = new HashedWheelTimer();
|
final Timer timer = new HashedWheelTimer();
|
||||||
final CountDownLatch barrier = new CountDownLatch(1);
|
final CountDownLatch barrier = new CountDownLatch(1);
|
||||||
final Timeout timeout = timer.newTimeout(new TimerTask() {
|
final Timeout timeout = timer.newTimeout(timeout1 -> {
|
||||||
@Override
|
fail("This should not have run");
|
||||||
public void run(Timeout timeout) throws Exception {
|
barrier.countDown();
|
||||||
fail("This should not have run");
|
|
||||||
barrier.countDown();
|
|
||||||
}
|
|
||||||
}, 10, TimeUnit.SECONDS);
|
}, 10, TimeUnit.SECONDS);
|
||||||
assertFalse(barrier.await(3, TimeUnit.SECONDS));
|
assertFalse(barrier.await(3, TimeUnit.SECONDS));
|
||||||
assertFalse("timer should not expire", timeout.isExpired());
|
assertFalse("timer should not expire", timeout.isExpired());
|
||||||
|
@ -51,12 +48,7 @@ public class HashedWheelTimerTest {
|
||||||
public void testScheduleTimeoutShouldRunAfterDelay() throws InterruptedException {
|
public void testScheduleTimeoutShouldRunAfterDelay() throws InterruptedException {
|
||||||
final Timer timer = new HashedWheelTimer();
|
final Timer timer = new HashedWheelTimer();
|
||||||
final CountDownLatch barrier = new CountDownLatch(1);
|
final CountDownLatch barrier = new CountDownLatch(1);
|
||||||
final Timeout timeout = timer.newTimeout(new TimerTask() {
|
final Timeout timeout = timer.newTimeout(timeout1 -> barrier.countDown(), 2, TimeUnit.SECONDS);
|
||||||
@Override
|
|
||||||
public void run(Timeout timeout) throws Exception {
|
|
||||||
barrier.countDown();
|
|
||||||
}
|
|
||||||
}, 2, TimeUnit.SECONDS);
|
|
||||||
assertTrue(barrier.await(3, TimeUnit.SECONDS));
|
assertTrue(barrier.await(3, TimeUnit.SECONDS));
|
||||||
assertTrue("timer should expire", timeout.isExpired());
|
assertTrue("timer should expire", timeout.isExpired());
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
@ -67,12 +59,7 @@ public class HashedWheelTimerTest {
|
||||||
final CountDownLatch latch = new CountDownLatch(3);
|
final CountDownLatch latch = new CountDownLatch(3);
|
||||||
final Timer timerProcessed = new HashedWheelTimer();
|
final Timer timerProcessed = new HashedWheelTimer();
|
||||||
for (int i = 0; i < 3; i ++) {
|
for (int i = 0; i < 3; i ++) {
|
||||||
timerProcessed.newTimeout(new TimerTask() {
|
timerProcessed.newTimeout(timeout -> latch.countDown(), 1, TimeUnit.MILLISECONDS);
|
||||||
@Override
|
|
||||||
public void run(final Timeout timeout) throws Exception {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}, 1, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
latch.await();
|
latch.await();
|
||||||
|
@ -80,10 +67,7 @@ public class HashedWheelTimerTest {
|
||||||
|
|
||||||
final Timer timerUnprocessed = new HashedWheelTimer();
|
final Timer timerUnprocessed = new HashedWheelTimer();
|
||||||
for (int i = 0; i < 5; i ++) {
|
for (int i = 0; i < 5; i ++) {
|
||||||
timerUnprocessed.newTimeout(new TimerTask() {
|
timerUnprocessed.newTimeout(timeout -> {
|
||||||
@Override
|
|
||||||
public void run(Timeout timeout) throws Exception {
|
|
||||||
}
|
|
||||||
}, 5, TimeUnit.SECONDS);
|
}, 5, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
Thread.sleep(1000L); // sleep for a second
|
Thread.sleep(1000L); // sleep for a second
|
||||||
|
@ -95,12 +79,7 @@ public class HashedWheelTimerTest {
|
||||||
final CountDownLatch latch = new CountDownLatch(3);
|
final CountDownLatch latch = new CountDownLatch(3);
|
||||||
final Timer timer = new HashedWheelTimer();
|
final Timer timer = new HashedWheelTimer();
|
||||||
for (int i = 0; i < 3; i ++) {
|
for (int i = 0; i < 3; i ++) {
|
||||||
timer.newTimeout(new TimerTask() {
|
timer.newTimeout(timeout -> latch.countDown(), 1, TimeUnit.MILLISECONDS);
|
||||||
@Override
|
|
||||||
public void run(Timeout timeout) throws Exception {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}, 1, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
latch.await();
|
latch.await();
|
||||||
|
@ -143,12 +122,8 @@ public class HashedWheelTimerTest {
|
||||||
int scheduledTasks = 100000;
|
int scheduledTasks = 100000;
|
||||||
for (int i = 0; i < scheduledTasks; i++) {
|
for (int i = 0; i < scheduledTasks; i++) {
|
||||||
final long start = System.nanoTime();
|
final long start = System.nanoTime();
|
||||||
timer.newTimeout(new TimerTask() {
|
timer.newTimeout(timeout1 -> queue.add(
|
||||||
@Override
|
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)), timeout, TimeUnit.MILLISECONDS);
|
||||||
public void run(final Timeout timeout) throws Exception {
|
|
||||||
queue.add(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start));
|
|
||||||
}
|
|
||||||
}, timeout, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < scheduledTasks; i++) {
|
for (int i = 0; i < scheduledTasks; i++) {
|
||||||
|
@ -234,31 +209,18 @@ public class HashedWheelTimerTest {
|
||||||
public void testOverflow() throws InterruptedException {
|
public void testOverflow() throws InterruptedException {
|
||||||
final HashedWheelTimer timer = new HashedWheelTimer();
|
final HashedWheelTimer timer = new HashedWheelTimer();
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
Timeout timeout = timer.newTimeout(new TimerTask() {
|
Timeout timeout = timer.newTimeout(timeout1 -> latch.countDown(), Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
@Override
|
|
||||||
public void run(Timeout timeout) {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
||||||
assertFalse(latch.await(1, TimeUnit.SECONDS));
|
assertFalse(latch.await(1, TimeUnit.SECONDS));
|
||||||
timeout.cancel();
|
timeout.cancel();
|
||||||
timer.stop();
|
timer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TimerTask createNoOpTimerTask() {
|
private static TimerTask createNoOpTimerTask() {
|
||||||
return new TimerTask() {
|
return timeout -> {
|
||||||
@Override
|
|
||||||
public void run(final Timeout timeout) throws Exception {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TimerTask createCountDownLatchTimerTask(final CountDownLatch latch) {
|
private static TimerTask createCountDownLatchTimerTask(final CountDownLatch latch) {
|
||||||
return new TimerTask() {
|
return timeout -> latch.countDown();
|
||||||
@Override
|
|
||||||
public void run(final Timeout timeout) throws Exception {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,17 +102,14 @@ public class NettyRuntimeTests {
|
||||||
final NettyRuntime.AvailableProcessorsHolder holder,
|
final NettyRuntime.AvailableProcessorsHolder holder,
|
||||||
final CyclicBarrier barrier,
|
final CyclicBarrier barrier,
|
||||||
final AtomicReference<IllegalStateException> reference) {
|
final AtomicReference<IllegalStateException> reference) {
|
||||||
return new Runnable() {
|
return () -> {
|
||||||
@Override
|
await(barrier);
|
||||||
public void run() {
|
try {
|
||||||
await(barrier);
|
holder.availableProcessors();
|
||||||
try {
|
} catch (final IllegalStateException e) {
|
||||||
holder.availableProcessors();
|
reference.set(e);
|
||||||
} catch (final IllegalStateException e) {
|
|
||||||
reference.set(e);
|
|
||||||
}
|
|
||||||
await(barrier);
|
|
||||||
}
|
}
|
||||||
|
await(barrier);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,28 +117,22 @@ public class NettyRuntimeTests {
|
||||||
public void testRacingGetAndSet() throws InterruptedException {
|
public void testRacingGetAndSet() throws InterruptedException {
|
||||||
final NettyRuntime.AvailableProcessorsHolder holder = new NettyRuntime.AvailableProcessorsHolder();
|
final NettyRuntime.AvailableProcessorsHolder holder = new NettyRuntime.AvailableProcessorsHolder();
|
||||||
final CyclicBarrier barrier = new CyclicBarrier(3);
|
final CyclicBarrier barrier = new CyclicBarrier(3);
|
||||||
final Thread get = new Thread(new Runnable() {
|
final Thread get = new Thread(() -> {
|
||||||
@Override
|
await(barrier);
|
||||||
public void run() {
|
holder.availableProcessors();
|
||||||
await(barrier);
|
await(barrier);
|
||||||
holder.availableProcessors();
|
|
||||||
await(barrier);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
get.start();
|
get.start();
|
||||||
|
|
||||||
final AtomicReference<IllegalStateException> setException = new AtomicReference<>();
|
final AtomicReference<IllegalStateException> setException = new AtomicReference<>();
|
||||||
final Thread set = new Thread(new Runnable() {
|
final Thread set = new Thread(() -> {
|
||||||
@Override
|
await(barrier);
|
||||||
public void run() {
|
try {
|
||||||
await(barrier);
|
holder.setAvailableProcessors(2048);
|
||||||
try {
|
} catch (final IllegalStateException e) {
|
||||||
holder.setAvailableProcessors(2048);
|
setException.set(e);
|
||||||
} catch (final IllegalStateException e) {
|
|
||||||
setException.set(e);
|
|
||||||
}
|
|
||||||
await(barrier);
|
|
||||||
}
|
}
|
||||||
|
await(barrier);
|
||||||
});
|
});
|
||||||
set.start();
|
set.start();
|
||||||
|
|
||||||
|
|
|
@ -41,13 +41,10 @@ public class RecyclerTest {
|
||||||
final Recycler<HandledObject> recycler = newRecycler(1024);
|
final Recycler<HandledObject> recycler = newRecycler(1024);
|
||||||
final AtomicBoolean collected = new AtomicBoolean();
|
final AtomicBoolean collected = new AtomicBoolean();
|
||||||
final AtomicReference<HandledObject> reference = new AtomicReference<>();
|
final AtomicReference<HandledObject> reference = new AtomicReference<>();
|
||||||
Thread thread = new Thread(new Runnable() {
|
Thread thread = new Thread(() -> {
|
||||||
@Override
|
HandledObject object = recycler.get();
|
||||||
public void run() {
|
// Store a reference to the HandledObject to ensure it is not collected when the run method finish.
|
||||||
HandledObject object = recycler.get();
|
reference.set(object);
|
||||||
// Store a reference to the HandledObject to ensure it is not collected when the run method finish.
|
|
||||||
reference.set(object);
|
|
||||||
}
|
|
||||||
}) {
|
}) {
|
||||||
@Override
|
@Override
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
|
@ -86,23 +83,15 @@ public class RecyclerTest {
|
||||||
Recycler<HandledObject> recycler = newRecycler(1024);
|
Recycler<HandledObject> recycler = newRecycler(1024);
|
||||||
final HandledObject object = recycler.get();
|
final HandledObject object = recycler.get();
|
||||||
final AtomicReference<IllegalStateException> exceptionStore = new AtomicReference<>();
|
final AtomicReference<IllegalStateException> exceptionStore = new AtomicReference<>();
|
||||||
final Thread thread1 = new Thread(new Runnable() {
|
final Thread thread1 = new Thread(object::recycle);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
object.recycle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread1.start();
|
thread1.start();
|
||||||
thread1.join();
|
thread1.join();
|
||||||
|
|
||||||
final Thread thread2 = new Thread(new Runnable() {
|
final Thread thread2 = new Thread(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
object.recycle();
|
||||||
try {
|
} catch (IllegalStateException e) {
|
||||||
object.recycle();
|
exceptionStore.set(e);
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
exceptionStore.set(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thread2.start();
|
thread2.start();
|
||||||
|
|
|
@ -46,12 +46,9 @@ public class ThreadDeathWatcherTest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final Runnable task = new Runnable() {
|
final Runnable task = () -> {
|
||||||
@Override
|
if (!t.isAlive()) {
|
||||||
public void run() {
|
latch.countDown();
|
||||||
if (!t.isAlive()) {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,12 +88,7 @@ public class ThreadDeathWatcherTest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final Runnable task = new Runnable() {
|
final Runnable task = () -> run.set(true);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
run.set(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
|
@ -121,16 +113,10 @@ public class ThreadDeathWatcherTest {
|
||||||
public void testThreadGroup() throws InterruptedException {
|
public void testThreadGroup() throws InterruptedException {
|
||||||
final ThreadGroup group = new ThreadGroup("group");
|
final ThreadGroup group = new ThreadGroup("group");
|
||||||
final AtomicReference<ThreadGroup> capturedGroup = new AtomicReference<>();
|
final AtomicReference<ThreadGroup> capturedGroup = new AtomicReference<>();
|
||||||
final Thread thread = new Thread(group, new Runnable() {
|
final Thread thread = new Thread(group, () -> {
|
||||||
@Override
|
final Thread t = ThreadDeathWatcher.threadFactory.newThread(() -> {
|
||||||
public void run() {
|
});
|
||||||
final Thread t = ThreadDeathWatcher.threadFactory.newThread(new Runnable() {
|
capturedGroup.set(t.getThreadGroup());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
capturedGroup.set(t.getThreadGroup());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
thread.join();
|
thread.join();
|
||||||
|
|
|
@ -27,11 +27,7 @@ import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
public class AbstractScheduledEventExecutorTest {
|
public class AbstractScheduledEventExecutorTest {
|
||||||
private static final Runnable TEST_RUNNABLE = new Runnable() {
|
private static final Runnable TEST_RUNNABLE = () -> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final Callable<?> TEST_CALLABLE = Executors.callable(TEST_RUNNABLE);
|
private static final Callable<?> TEST_CALLABLE = Executors.callable(TEST_RUNNABLE);
|
||||||
|
|
|
@ -157,12 +157,7 @@ public class DefaultPromiseTest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GlobalEventExecutor.INSTANCE.execute(new Runnable() {
|
GlobalEventExecutor.INSTANCE.execute(() -> promise.setSuccess(null));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
promise.setSuccess(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
promise.addListener(listener1).addListener(listener2).addListener(listener3);
|
promise.addListener(listener1).addListener(listener2).addListener(listener3);
|
||||||
|
|
||||||
|
@ -217,12 +212,7 @@ public class DefaultPromiseTest {
|
||||||
final Map<Thread, DefaultPromise<Void>> promises = new HashMap<>();
|
final Map<Thread, DefaultPromise<Void>> promises = new HashMap<>();
|
||||||
for (int i = 0; i < numberOfAttempts; i++) {
|
for (int i = 0; i < numberOfAttempts; i++) {
|
||||||
final DefaultPromise<Void> promise = new DefaultPromise<>(executor);
|
final DefaultPromise<Void> promise = new DefaultPromise<>(executor);
|
||||||
final Thread thread = new Thread(new Runnable() {
|
final Thread thread = new Thread(() -> promise.setSuccess(null));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
promise.setSuccess(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
promises.put(thread, promise);
|
promises.put(thread, promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,12 +268,7 @@ public class DefaultPromiseTest {
|
||||||
final CountDownLatch latch = new CountDownLatch(promiseChainLength);
|
final CountDownLatch latch = new CountDownLatch(promiseChainLength);
|
||||||
|
|
||||||
if (runTestInExecutorThread) {
|
if (runTestInExecutorThread) {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> testStackOverFlowChainedFuturesA(executor, p, latch));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
testStackOverFlowChainedFuturesA(executor, p, latch);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
testStackOverFlowChainedFuturesA(executor, p, latch);
|
testStackOverFlowChainedFuturesA(executor, p, latch);
|
||||||
}
|
}
|
||||||
|
@ -299,14 +284,11 @@ public class DefaultPromiseTest {
|
||||||
for (int i = 0; i < p.length; i ++) {
|
for (int i = 0; i < p.length; i ++) {
|
||||||
final int finalI = i;
|
final int finalI = i;
|
||||||
p[i] = new DefaultPromise<>(executor);
|
p[i] = new DefaultPromise<>(executor);
|
||||||
p[i].addListener(new FutureListener<Void>() {
|
p[i].addListener((FutureListener<Void>) future -> {
|
||||||
@Override
|
if (finalI + 1 < p.length) {
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
p[finalI + 1].setSuccess(null);
|
||||||
if (finalI + 1 < p.length) {
|
|
||||||
p[finalI + 1].setSuccess(null);
|
|
||||||
}
|
|
||||||
latch.countDown();
|
|
||||||
}
|
}
|
||||||
|
latch.countDown();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,12 +302,7 @@ public class DefaultPromiseTest {
|
||||||
final CountDownLatch latch = new CountDownLatch(promiseChainLength);
|
final CountDownLatch latch = new CountDownLatch(promiseChainLength);
|
||||||
|
|
||||||
if (runTestInExecutorThread) {
|
if (runTestInExecutorThread) {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> testStackOverFlowChainedFuturesA(executor, p, latch));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
testStackOverFlowChainedFuturesA(executor, p, latch);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
testStackOverFlowChainedFuturesA(executor, p, latch);
|
testStackOverFlowChainedFuturesA(executor, p, latch);
|
||||||
}
|
}
|
||||||
|
@ -341,20 +318,12 @@ public class DefaultPromiseTest {
|
||||||
for (int i = 0; i < p.length; i ++) {
|
for (int i = 0; i < p.length; i ++) {
|
||||||
final int finalI = i;
|
final int finalI = i;
|
||||||
p[i] = new DefaultPromise<>(executor);
|
p[i] = new DefaultPromise<>(executor);
|
||||||
p[i].addListener(new FutureListener<Void>() {
|
p[i].addListener((FutureListener<Void>) future -> future.addListener((FutureListener<Void>) future1 -> {
|
||||||
@Override
|
if (finalI + 1 < p.length) {
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
p[finalI + 1].setSuccess(null);
|
||||||
future.addListener(new FutureListener<Void>() {
|
|
||||||
@Override
|
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
|
||||||
if (finalI + 1 < p.length) {
|
|
||||||
p[finalI + 1].setSuccess(null);
|
|
||||||
}
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
latch.countDown();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
p[0].setSuccess(null);
|
p[0].setSuccess(null);
|
||||||
|
@ -379,12 +348,7 @@ public class DefaultPromiseTest {
|
||||||
final Promise<Void> promise = new DefaultPromise<>(executor);
|
final Promise<Void> promise = new DefaultPromise<>(executor);
|
||||||
|
|
||||||
// Add a listener before completion so "lateListener" is used next time we add a listener.
|
// Add a listener before completion so "lateListener" is used next time we add a listener.
|
||||||
promise.addListener(new FutureListener<Void>() {
|
promise.addListener((FutureListener<Void>) future -> assertTrue(state.compareAndSet(0, 1)));
|
||||||
@Override
|
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
|
||||||
assertTrue(state.compareAndSet(0, 1));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Simulate write operation completing, which will execute listeners in another thread.
|
// Simulate write operation completing, which will execute listeners in another thread.
|
||||||
if (cause == null) {
|
if (cause == null) {
|
||||||
|
@ -394,12 +358,9 @@ public class DefaultPromiseTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a "late listener"
|
// Add a "late listener"
|
||||||
promise.addListener(new FutureListener<Void>() {
|
promise.addListener((FutureListener<Void>) future -> {
|
||||||
@Override
|
assertTrue(state.compareAndSet(1, 2));
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
latch1.countDown();
|
||||||
assertTrue(state.compareAndSet(1, 2));
|
|
||||||
latch1.countDown();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for the listeners and late listeners to be completed.
|
// Wait for the listeners and late listeners to be completed.
|
||||||
|
@ -408,27 +369,16 @@ public class DefaultPromiseTest {
|
||||||
|
|
||||||
// This is the important listener. A late listener that is added after all late listeners
|
// This is the important listener. A late listener that is added after all late listeners
|
||||||
// have completed, and needs to update state before a read operation (on the same executor).
|
// have completed, and needs to update state before a read operation (on the same executor).
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> promise.addListener((FutureListener<Void>) future -> {
|
||||||
@Override
|
assertTrue(state.compareAndSet(2, 3));
|
||||||
public void run() {
|
latch2.countDown();
|
||||||
promise.addListener(new FutureListener<Void>() {
|
}));
|
||||||
@Override
|
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
|
||||||
assertTrue(state.compareAndSet(2, 3));
|
|
||||||
latch2.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Simulate a read operation being queued up in the executor.
|
// Simulate a read operation being queued up in the executor.
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
// This is the key, we depend upon the state being set in the next listener.
|
||||||
public void run() {
|
assertEquals(3, state.get());
|
||||||
// This is the key, we depend upon the state being set in the next listener.
|
latch2.countDown();
|
||||||
assertEquals(3, state.get());
|
|
||||||
latch2.countDown();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
latch2.await();
|
latch2.await();
|
||||||
|
@ -440,17 +390,8 @@ public class DefaultPromiseTest {
|
||||||
private static void testPromiseListenerAddWhenComplete(Throwable cause) throws InterruptedException {
|
private static void testPromiseListenerAddWhenComplete(Throwable cause) throws InterruptedException {
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final Promise<Void> promise = new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
|
final Promise<Void> promise = new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
|
||||||
promise.addListener(new FutureListener<Void>() {
|
promise.addListener((FutureListener<Void>) future ->
|
||||||
@Override
|
promise.addListener((FutureListener<Void>) future1 -> latch.countDown()));
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
|
||||||
promise.addListener(new FutureListener<Void>() {
|
|
||||||
@Override
|
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (cause == null) {
|
if (cause == null) {
|
||||||
promise.setSuccess(null);
|
promise.setSuccess(null);
|
||||||
} else {
|
} else {
|
||||||
|
@ -463,29 +404,16 @@ public class DefaultPromiseTest {
|
||||||
EventExecutor executor = new TestEventExecutor();
|
EventExecutor executor = new TestEventExecutor();
|
||||||
int expectedCount = numListenersBefore + 2;
|
int expectedCount = numListenersBefore + 2;
|
||||||
final CountDownLatch latch = new CountDownLatch(expectedCount);
|
final CountDownLatch latch = new CountDownLatch(expectedCount);
|
||||||
final FutureListener<Void> listener = new FutureListener<Void>() {
|
final FutureListener<Void> listener = future -> latch.countDown();
|
||||||
@Override
|
|
||||||
public void operationComplete(Future<Void> future) throws Exception {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
final Promise<Void> promise = new DefaultPromise<>(executor);
|
final Promise<Void> promise = new DefaultPromise<>(executor);
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
for (int i = 0; i < numListenersBefore; i++) {
|
||||||
public void run() {
|
|
||||||
for (int i = 0; i < numListenersBefore; i++) {
|
|
||||||
promise.addListener(listener);
|
|
||||||
}
|
|
||||||
promise.setSuccess(null);
|
|
||||||
|
|
||||||
GlobalEventExecutor.INSTANCE.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
promise.addListener(listener);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
promise.addListener(listener);
|
promise.addListener(listener);
|
||||||
}
|
}
|
||||||
|
promise.setSuccess(null);
|
||||||
|
|
||||||
|
GlobalEventExecutor.INSTANCE.execute(() -> promise.addListener(listener));
|
||||||
|
promise.addListener(listener);
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue("Should have notified " + expectedCount + " listeners",
|
assertTrue("Should have notified " + expectedCount + " listeners",
|
||||||
|
|
|
@ -55,30 +55,22 @@ public class DefaultThreadFactoryTest {
|
||||||
// holder for the thread factory, plays the role of a global singleton
|
// holder for the thread factory, plays the role of a global singleton
|
||||||
final AtomicReference<DefaultThreadFactory> factory = new AtomicReference<>();
|
final AtomicReference<DefaultThreadFactory> factory = new AtomicReference<>();
|
||||||
final AtomicInteger counter = new AtomicInteger();
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
final Runnable task = new Runnable() {
|
final Runnable task = counter::incrementAndGet;
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
counter.incrementAndGet();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final AtomicReference<Throwable> interrupted = new AtomicReference<>();
|
final AtomicReference<Throwable> interrupted = new AtomicReference<>();
|
||||||
|
|
||||||
// create the thread factory, since we are running the thread group brother, the thread
|
// create the thread factory, since we are running the thread group brother, the thread
|
||||||
// factory will now forever be tied to that group
|
// factory will now forever be tied to that group
|
||||||
// we then create a thread from the factory to run a "task" for us
|
// we then create a thread from the factory to run a "task" for us
|
||||||
final Thread first = new Thread(new ThreadGroup("brother"), new Runnable() {
|
final Thread first = new Thread(new ThreadGroup("brother"), () -> {
|
||||||
@Override
|
factory.set(new DefaultThreadFactory("test", false, Thread.NORM_PRIORITY, null));
|
||||||
public void run() {
|
final Thread t = factory.get().newThread(task);
|
||||||
factory.set(new DefaultThreadFactory("test", false, Thread.NORM_PRIORITY, null));
|
t.start();
|
||||||
final Thread t = factory.get().newThread(task);
|
try {
|
||||||
t.start();
|
t.join();
|
||||||
try {
|
} catch (InterruptedException e) {
|
||||||
t.join();
|
interrupted.set(e);
|
||||||
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
||||||
interrupted.set(e);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
first.start();
|
first.start();
|
||||||
|
@ -89,17 +81,14 @@ public class DefaultThreadFactoryTest {
|
||||||
// now we will use factory again, this time from a sibling thread group sister
|
// now we will use factory again, this time from a sibling thread group sister
|
||||||
// if DefaultThreadFactory is "sticky" about thread groups, a security manager
|
// if DefaultThreadFactory is "sticky" about thread groups, a security manager
|
||||||
// that forbids sibling thread groups from messing with each other will strike this down
|
// that forbids sibling thread groups from messing with each other will strike this down
|
||||||
final Thread second = new Thread(new ThreadGroup("sister"), new Runnable() {
|
final Thread second = new Thread(new ThreadGroup("sister"), () -> {
|
||||||
@Override
|
final Thread t = factory.get().newThread(task);
|
||||||
public void run() {
|
t.start();
|
||||||
final Thread t = factory.get().newThread(task);
|
try {
|
||||||
t.start();
|
t.join();
|
||||||
try {
|
} catch (InterruptedException e) {
|
||||||
t.join();
|
interrupted.set(e);
|
||||||
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
||||||
interrupted.set(e);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
second.start();
|
second.start();
|
||||||
|
@ -119,12 +108,7 @@ public class DefaultThreadFactoryTest {
|
||||||
public void testDefaultThreadFactoryStickyThreadGroupConstructor() throws InterruptedException {
|
public void testDefaultThreadFactoryStickyThreadGroupConstructor() throws InterruptedException {
|
||||||
final ThreadGroup sticky = new ThreadGroup("sticky");
|
final ThreadGroup sticky = new ThreadGroup("sticky");
|
||||||
runStickyThreadGroupTest(
|
runStickyThreadGroupTest(
|
||||||
new Callable<DefaultThreadFactory>() {
|
() -> new DefaultThreadFactory("test", false, Thread.NORM_PRIORITY, sticky),
|
||||||
@Override
|
|
||||||
public DefaultThreadFactory call() throws Exception {
|
|
||||||
return new DefaultThreadFactory("test", false, Thread.NORM_PRIORITY, sticky);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sticky);
|
sticky);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,21 +119,13 @@ public class DefaultThreadFactoryTest {
|
||||||
final ThreadGroup sticky = new ThreadGroup("sticky");
|
final ThreadGroup sticky = new ThreadGroup("sticky");
|
||||||
|
|
||||||
runStickyThreadGroupTest(
|
runStickyThreadGroupTest(
|
||||||
new Callable<DefaultThreadFactory>() {
|
() -> {
|
||||||
@Override
|
final AtomicReference<DefaultThreadFactory> factory =
|
||||||
public DefaultThreadFactory call() throws Exception {
|
new AtomicReference<>();
|
||||||
final AtomicReference<DefaultThreadFactory> factory =
|
final Thread thread = new Thread(sticky, () -> factory.set(new DefaultThreadFactory("test")));
|
||||||
new AtomicReference<>();
|
thread.start();
|
||||||
final Thread thread = new Thread(sticky, new Runnable() {
|
thread.join();
|
||||||
@Override
|
return factory.get();
|
||||||
public void run() {
|
|
||||||
factory.set(new DefaultThreadFactory("test"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.start();
|
|
||||||
thread.join();
|
|
||||||
return factory.get();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
sticky);
|
sticky);
|
||||||
}
|
}
|
||||||
|
@ -174,12 +150,7 @@ public class DefaultThreadFactoryTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
runStickyThreadGroupTest(
|
runStickyThreadGroupTest(
|
||||||
new Callable<DefaultThreadFactory>() {
|
() -> new DefaultThreadFactory("test"),
|
||||||
@Override
|
|
||||||
public DefaultThreadFactory call() throws Exception {
|
|
||||||
return new DefaultThreadFactory("test");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sticky);
|
sticky);
|
||||||
} finally {
|
} finally {
|
||||||
System.setSecurityManager(current);
|
System.setSecurityManager(current);
|
||||||
|
@ -192,23 +163,17 @@ public class DefaultThreadFactoryTest {
|
||||||
final AtomicReference<ThreadGroup> captured = new AtomicReference<>();
|
final AtomicReference<ThreadGroup> captured = new AtomicReference<>();
|
||||||
final AtomicReference<Throwable> exception = new AtomicReference<>();
|
final AtomicReference<Throwable> exception = new AtomicReference<>();
|
||||||
|
|
||||||
final Thread first = new Thread(new ThreadGroup("wrong"), new Runnable() {
|
final Thread first = new Thread(new ThreadGroup("wrong"), () -> {
|
||||||
@Override
|
final DefaultThreadFactory factory;
|
||||||
public void run() {
|
try {
|
||||||
final DefaultThreadFactory factory;
|
factory = callable.call();
|
||||||
try {
|
} catch (Exception e) {
|
||||||
factory = callable.call();
|
exception.set(e);
|
||||||
} catch (Exception e) {
|
throw new RuntimeException(e);
|
||||||
exception.set(e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
final Thread t = factory.newThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
captured.set(t.getThreadGroup());
|
|
||||||
}
|
}
|
||||||
|
final Thread t = factory.newThread(() -> {
|
||||||
|
});
|
||||||
|
captured.set(t.getThreadGroup());
|
||||||
});
|
});
|
||||||
first.start();
|
first.start();
|
||||||
first.join();
|
first.join();
|
||||||
|
@ -227,17 +192,11 @@ public class DefaultThreadFactoryTest {
|
||||||
final AtomicReference<ThreadGroup> firstCaptured = new AtomicReference<>();
|
final AtomicReference<ThreadGroup> firstCaptured = new AtomicReference<>();
|
||||||
|
|
||||||
final ThreadGroup firstGroup = new ThreadGroup("first");
|
final ThreadGroup firstGroup = new ThreadGroup("first");
|
||||||
final Thread first = new Thread(firstGroup, new Runnable() {
|
final Thread first = new Thread(firstGroup, () -> {
|
||||||
@Override
|
factory.set(new DefaultThreadFactory("sticky", false, Thread.NORM_PRIORITY, null));
|
||||||
public void run() {
|
final Thread t = factory.get().newThread(() -> {
|
||||||
factory.set(new DefaultThreadFactory("sticky", false, Thread.NORM_PRIORITY, null));
|
});
|
||||||
final Thread t = factory.get().newThread(new Runnable() {
|
firstCaptured.set(t.getThreadGroup());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
firstCaptured.set(t.getThreadGroup());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
first.start();
|
first.start();
|
||||||
first.join();
|
first.join();
|
||||||
|
@ -247,16 +206,10 @@ public class DefaultThreadFactoryTest {
|
||||||
final AtomicReference<ThreadGroup> secondCaptured = new AtomicReference<>();
|
final AtomicReference<ThreadGroup> secondCaptured = new AtomicReference<>();
|
||||||
|
|
||||||
final ThreadGroup secondGroup = new ThreadGroup("second");
|
final ThreadGroup secondGroup = new ThreadGroup("second");
|
||||||
final Thread second = new Thread(secondGroup, new Runnable() {
|
final Thread second = new Thread(secondGroup, () -> {
|
||||||
@Override
|
final Thread t = factory.get().newThread(() -> {
|
||||||
public void run() {
|
});
|
||||||
final Thread t = factory.get().newThread(new Runnable() {
|
secondCaptured.set(t.getThreadGroup());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
secondCaptured.set(t.getThreadGroup());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
second.start();
|
second.start();
|
||||||
second.join();
|
second.join();
|
||||||
|
|
|
@ -82,14 +82,11 @@ public class FastThreadLocalTest {
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleSetRemove() throws Exception {
|
public void testMultipleSetRemove() throws Exception {
|
||||||
final FastThreadLocal<String> threadLocal = new FastThreadLocal<>();
|
final FastThreadLocal<String> threadLocal = new FastThreadLocal<>();
|
||||||
final Runnable runnable = new Runnable() {
|
final Runnable runnable = () -> {
|
||||||
@Override
|
threadLocal.set("1");
|
||||||
public void run() {
|
threadLocal.remove();
|
||||||
threadLocal.set("1");
|
threadLocal.set("2");
|
||||||
threadLocal.remove();
|
threadLocal.remove();
|
||||||
threadLocal.set("2");
|
|
||||||
threadLocal.remove();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
final int sizeWhenStart = ObjectCleaner.getLiveSetCount();
|
final int sizeWhenStart = ObjectCleaner.getLiveSetCount();
|
||||||
|
@ -110,18 +107,15 @@ public class FastThreadLocalTest {
|
||||||
public void testMultipleSetRemove_multipleThreadLocal() throws Exception {
|
public void testMultipleSetRemove_multipleThreadLocal() throws Exception {
|
||||||
final FastThreadLocal<String> threadLocal = new FastThreadLocal<>();
|
final FastThreadLocal<String> threadLocal = new FastThreadLocal<>();
|
||||||
final FastThreadLocal<String> threadLocal2 = new FastThreadLocal<>();
|
final FastThreadLocal<String> threadLocal2 = new FastThreadLocal<>();
|
||||||
final Runnable runnable = new Runnable() {
|
final Runnable runnable = () -> {
|
||||||
@Override
|
threadLocal.set("1");
|
||||||
public void run() {
|
threadLocal.remove();
|
||||||
threadLocal.set("1");
|
threadLocal.set("2");
|
||||||
threadLocal.remove();
|
threadLocal.remove();
|
||||||
threadLocal.set("2");
|
threadLocal2.set("1");
|
||||||
threadLocal.remove();
|
threadLocal2.remove();
|
||||||
threadLocal2.set("1");
|
threadLocal2.set("2");
|
||||||
threadLocal2.remove();
|
threadLocal2.remove();
|
||||||
threadLocal2.set("2");
|
|
||||||
threadLocal2.remove();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
final int sizeWhenStart = ObjectCleaner.getLiveSetCount();
|
final int sizeWhenStart = ObjectCleaner.getLiveSetCount();
|
||||||
|
@ -165,16 +159,13 @@ public class FastThreadLocalTest {
|
||||||
final TestFastThreadLocal threadLocal = new TestFastThreadLocal();
|
final TestFastThreadLocal threadLocal = new TestFastThreadLocal();
|
||||||
final TestFastThreadLocal threadLocal2 = new TestFastThreadLocal();
|
final TestFastThreadLocal threadLocal2 = new TestFastThreadLocal();
|
||||||
|
|
||||||
Runnable runnable = new Runnable() {
|
Runnable runnable = () -> {
|
||||||
@Override
|
if (callGet) {
|
||||||
public void run() {
|
assertEquals(Thread.currentThread().getName(), threadLocal.get());
|
||||||
if (callGet) {
|
assertEquals(Thread.currentThread().getName(), threadLocal2.get());
|
||||||
assertEquals(Thread.currentThread().getName(), threadLocal.get());
|
} else {
|
||||||
assertEquals(Thread.currentThread().getName(), threadLocal2.get());
|
threadLocal.set(Thread.currentThread().getName());
|
||||||
} else {
|
threadLocal2.set(Thread.currentThread().getName());
|
||||||
threadLocal.set(Thread.currentThread().getName());
|
|
||||||
threadLocal2.set(Thread.currentThread().getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Thread thread = fastThreadLocal ? new FastThreadLocalThread(runnable) : new Thread(runnable);
|
Thread thread = fastThreadLocal ? new FastThreadLocalThread(runnable) : new Thread(runnable);
|
||||||
|
|
|
@ -99,16 +99,10 @@ public class GlobalEventExecutorTest {
|
||||||
public void testThreadGroup() throws InterruptedException {
|
public void testThreadGroup() throws InterruptedException {
|
||||||
final ThreadGroup group = new ThreadGroup("group");
|
final ThreadGroup group = new ThreadGroup("group");
|
||||||
final AtomicReference<ThreadGroup> capturedGroup = new AtomicReference<>();
|
final AtomicReference<ThreadGroup> capturedGroup = new AtomicReference<>();
|
||||||
final Thread thread = new Thread(group, new Runnable() {
|
final Thread thread = new Thread(group, () -> {
|
||||||
@Override
|
final Thread t = e.threadFactory.newThread(() -> {
|
||||||
public void run() {
|
});
|
||||||
final Thread t = e.threadFactory.newThread(new Runnable() {
|
capturedGroup.set(t.getThreadGroup());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
capturedGroup.set(t.getThreadGroup());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
thread.join();
|
thread.join();
|
||||||
|
|
|
@ -68,14 +68,11 @@ public class NonStickyEventExecutorGroupTest {
|
||||||
final AtomicReference<Throwable> error = new AtomicReference<>();
|
final AtomicReference<Throwable> error = new AtomicReference<>();
|
||||||
List<Thread> threadList = new ArrayList<>(threads);
|
List<Thread> threadList = new ArrayList<>(threads);
|
||||||
for (int i = 0 ; i < threads; i++) {
|
for (int i = 0 ; i < threads; i++) {
|
||||||
Thread thread = new Thread(new Runnable() {
|
Thread thread = new Thread(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
execute(nonStickyGroup, startLatch);
|
||||||
try {
|
} catch (Throwable cause) {
|
||||||
execute(nonStickyGroup, startLatch);
|
error.compareAndSet(null, cause);
|
||||||
} catch (Throwable cause) {
|
|
||||||
error.compareAndSet(null, cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
threadList.add(thread);
|
threadList.add(thread);
|
||||||
|
@ -106,12 +103,9 @@ public class NonStickyEventExecutorGroupTest {
|
||||||
final CountDownLatch firstCompleted = new CountDownLatch(1);
|
final CountDownLatch firstCompleted = new CountDownLatch(1);
|
||||||
final CountDownLatch latch = new CountDownLatch(2);
|
final CountDownLatch latch = new CountDownLatch(2);
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
firstCompleted.countDown();
|
||||||
public void run() {
|
latch.countDown();
|
||||||
firstCompleted.countDown();
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
Assert.assertTrue(firstCompleted.await(1, TimeUnit.SECONDS));
|
Assert.assertTrue(firstCompleted.await(1, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
@ -135,23 +129,20 @@ public class NonStickyEventExecutorGroupTest {
|
||||||
|
|
||||||
for (int i = 1 ; i <= tasks; i++) {
|
for (int i = 1 ; i <= tasks; i++) {
|
||||||
final int id = i;
|
final int id = i;
|
||||||
futures.add(executor.submit(new Runnable() {
|
futures.add(executor.submit(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
if (cause.get() == null) {
|
||||||
try {
|
int lastId = last.get();
|
||||||
if (cause.get() == null) {
|
if (lastId >= id) {
|
||||||
int lastId = last.get();
|
cause.compareAndSet(null, new AssertionError(
|
||||||
if (lastId >= id) {
|
"Out of order execution id(" + id + ") >= lastId(" + lastId + ')'));
|
||||||
cause.compareAndSet(null, new AssertionError(
|
}
|
||||||
"Out of order execution id(" + id + ") >= lastId(" + lastId + ')'));
|
if (!last.compareAndSet(lastId, id)) {
|
||||||
}
|
cause.compareAndSet(null, new AssertionError("Concurrent execution of tasks"));
|
||||||
if (!last.compareAndSet(lastId, id)) {
|
|
||||||
cause.compareAndSet(null, new AssertionError("Concurrent execution of tasks"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,13 +178,9 @@ public class PromiseCombinerTest {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static void mockListener(final Promise<Void> p, final GenericFutureListenerConsumer consumer) {
|
private static void mockListener(final Promise<Void> p, final GenericFutureListenerConsumer consumer) {
|
||||||
doAnswer(new Answer<Promise<Void>>() {
|
doAnswer(invocation -> {
|
||||||
@SuppressWarnings({ "unchecked", "raw-types" })
|
consumer.accept((GenericFutureListener) invocation.getArgument(0));
|
||||||
@Override
|
return p;
|
||||||
public Promise<Void> answer(InvocationOnMock invocation) throws Throwable {
|
|
||||||
consumer.accept((GenericFutureListener) invocation.getArgument(0));
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}).when(p).addListener(any(GenericFutureListener.class));
|
}).when(p).addListener(any(GenericFutureListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,8 @@ public class SingleThreadEventExecutorTest {
|
||||||
|
|
||||||
private static void executeShouldFail(Executor executor) {
|
private static void executeShouldFail(Executor executor) {
|
||||||
try {
|
try {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
// Noop.
|
||||||
public void run() {
|
|
||||||
// Noop.
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
} catch (RejectedExecutionException expected) {
|
} catch (RejectedExecutionException expected) {
|
||||||
|
@ -133,34 +130,28 @@ public class SingleThreadEventExecutorTest {
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
final Promise<Void> promise = executor.newPromise();
|
final Promise<Void> promise = executor.newPromise();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
Set<Callable<Boolean>> set = Collections.singleton(() -> {
|
||||||
try {
|
promise.setFailure(new AssertionError("Should never execute the Callable"));
|
||||||
Set<Callable<Boolean>> set = Collections.singleton(new Callable<Boolean>() {
|
return Boolean.TRUE;
|
||||||
@Override
|
});
|
||||||
public Boolean call() throws Exception {
|
if (any) {
|
||||||
promise.setFailure(new AssertionError("Should never execute the Callable"));
|
if (timeout) {
|
||||||
return Boolean.TRUE;
|
executor.invokeAny(set, 10, TimeUnit.SECONDS);
|
||||||
}
|
|
||||||
});
|
|
||||||
if (any) {
|
|
||||||
if (timeout) {
|
|
||||||
executor.invokeAny(set, 10, TimeUnit.SECONDS);
|
|
||||||
} else {
|
|
||||||
executor.invokeAny(set);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (timeout) {
|
executor.invokeAny(set);
|
||||||
executor.invokeAll(set, 10, TimeUnit.SECONDS);
|
}
|
||||||
} else {
|
} else {
|
||||||
executor.invokeAll(set);
|
if (timeout) {
|
||||||
}
|
executor.invokeAll(set, 10, TimeUnit.SECONDS);
|
||||||
|
} else {
|
||||||
|
executor.invokeAll(set);
|
||||||
}
|
}
|
||||||
promise.setFailure(new AssertionError("Should never reach here"));
|
|
||||||
} catch (Throwable cause) {
|
|
||||||
promise.setFailure(cause);
|
|
||||||
}
|
}
|
||||||
|
promise.setFailure(new AssertionError("Should never reach here"));
|
||||||
|
} catch (Throwable cause) {
|
||||||
|
promise.setFailure(cause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
promise.syncUninterruptibly();
|
promise.syncUninterruptibly();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue