SslHandler factory, switch to JUnit 5

This commit is contained in:
Jörg Prante 2019-04-30 16:35:45 +02:00
parent ad460a5111
commit ef0c59d3f5
76 changed files with 2041 additions and 678 deletions

View file

@ -37,6 +37,9 @@ subprojects {
}
dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:${project.property('junit.version')}"
testImplementation "org.junit.jupiter:junit-jupiter-params:${project.property('junit.version')}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.property('junit.version')}"
alpnagent "org.mortbay.jetty.alpn:jetty-alpn-agent:${project.property('alpnagent.version')}"
asciidoclet "org.asciidoctor:asciidoclet:${project.property('asciidoclet.version')}"
wagon "org.apache.maven.wagon:wagon-ssh:${project.property('wagon.version')}"
@ -52,9 +55,11 @@ subprojects {
targetCompatibility = JavaVersion.VERSION_1_8
}
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:all,-serial"
options.compilerArgs << "-Xlint:all,-fallthrough"
if (!options.compilerArgs.contains("-processor")) {
options.compilerArgs << '-proc:none'
}
}
jar {
@ -64,10 +69,20 @@ subprojects {
}
test {
useJUnitPlatform()
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
failFast = false
testLogging {
showStandardStreams = false
exceptionFormat = 'full'
events 'PASSED', 'FAILED', 'SKIPPED'
}
afterSuite { desc, result ->
if (!desc.parent) {
println "\nTest result: ${result.resultType}"
println "Test summary: ${result.testCount} tests, " +
"${result.successfulTestCount} succeeded, " +
"${result.failedTestCount} failed, " +
"${result.skippedTestCount} skipped"
}
}
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
jvmArgs "-javaagent:" + configurations.alpnagent.asPath
@ -105,13 +120,13 @@ subprojects {
task javadocJar(type: Jar, dependsOn: classes) {
from javadoc
into "build/tmp"
classifier 'javadoc'
archiveClassifier.set('javadoc')
}
task sourcesJar(type: Jar, dependsOn: classes) {
from sourceSets.main.allSource
into "build/tmp"
classifier 'sources'
archiveClassifier.set('sources')
}
artifacts {
@ -202,7 +217,7 @@ subprojects {
}
spotbugs {
toolVersion = '3.1.3'
toolVersion = '3.1.12'
sourceSets = [sourceSets.main]
ignoreFailures = true
effort = "max"

View file

@ -1,16 +1,24 @@
group = org.xbib
name = netty-http
version = 4.1.35.0
version = 4.1.35.1
# main packages
netty.version = 4.1.35.Final
tcnative.version = 2.0.22.Final
bouncycastle.version = 1.61
alpnagent.version = 2.0.9
# common
xbib-net-url.version = 1.2.2
# server
bouncycastle.version = 1.61
# server-rest
xbib-guice.version = 4.0.4
# test packages
junit.version = 4.12
junit.version = 5.4.2
conscrypt.version = 2.0.0
jackson.version = 2.8.11.1
wagon.version = 3.0.0

View file

View file

View file

@ -1,11 +1,12 @@
dependencies {
compile project(":netty-http-common")
compile "io.netty:netty-handler-proxy:${project.property('netty.version')}"
compile "io.netty:netty-transport-native-epoll:${project.property('netty.version')}"
implementation project(":netty-http-common")
implementation "io.netty:netty-handler-proxy:${project.property('netty.version')}"
implementation "io.netty:netty-transport-native-epoll:${project.property('netty.version')}"
implementation "io.netty:netty-codec-http2:${project.property('netty.version')}"
implementation "org.xbib:net-url:${project.property('xbib-net-url.version')}"
testCompile "io.netty:netty-tcnative-boringssl-static:${project.property('tcnative.version')}"
testCompile "org.conscrypt:conscrypt-openjdk-uber:${project.property('conscrypt.version')}"
testCompile "junit:junit:${project.property('junit.version')}"
testCompile "com.fasterxml.jackson.core:jackson-databind:${project.property('jackson.version')}"
testImplementation "io.netty:netty-tcnative-boringssl-static:${project.property('tcnative.version')}"
testImplementation "org.conscrypt:conscrypt-openjdk-uber:${project.property('conscrypt.version')}"
testImplementation "com.fasterxml.jackson.core:jackson-databind:${project.property('jackson.version')}"
}

View file

@ -199,13 +199,13 @@ public final class Client {
Channel channel;
if (httpAddress != null) {
HttpVersion httpVersion = httpAddress.getVersion();
SslHandlerFactory sslHandlerFactory = new SslHandlerFactory(clientConfig, httpAddress, byteBufAllocator);
ChannelInitializer<Channel> initializer;
SslHandler sslHandler = newSslHandler(clientConfig, byteBufAllocator, httpAddress);
if (httpVersion.majorVersion() == 1) {
initializer = new HttpChannelInitializer(clientConfig, httpAddress, sslHandler,
new Http2ChannelInitializer(clientConfig, httpAddress, sslHandler));
initializer = new HttpChannelInitializer(clientConfig, httpAddress, sslHandlerFactory,
new Http2ChannelInitializer(clientConfig, httpAddress, sslHandlerFactory));
} else {
initializer = new Http2ChannelInitializer(clientConfig, httpAddress, sslHandler);
initializer = new Http2ChannelInitializer(clientConfig, httpAddress, sslHandlerFactory);
}
try {
channel = bootstrap.handler(initializer)
@ -412,15 +412,34 @@ public final class Client {
public void channelCreated(Channel channel) {
HttpAddress httpAddress = channel.attr(pool.getAttributeKey()).get();
HttpVersion httpVersion = httpAddress.getVersion();
SslHandler sslHandler = newSslHandler(clientConfig, byteBufAllocator, httpAddress);
SslHandlerFactory sslHandlerFactory = new SslHandlerFactory(clientConfig, httpAddress, byteBufAllocator);
Http2ChannelInitializer http2ChannelInitializer = new Http2ChannelInitializer(clientConfig, httpAddress, sslHandlerFactory);
if (httpVersion.majorVersion() == 1) {
HttpChannelInitializer initializer = new HttpChannelInitializer(clientConfig, httpAddress, sslHandler,
new Http2ChannelInitializer(clientConfig, httpAddress, sslHandler));
HttpChannelInitializer initializer = new HttpChannelInitializer(clientConfig, httpAddress, sslHandlerFactory,
http2ChannelInitializer);
initializer.initChannel(channel);
} else {
Http2ChannelInitializer initializer = new Http2ChannelInitializer(clientConfig, httpAddress, sslHandler);
initializer.initChannel(channel);
http2ChannelInitializer.initChannel(channel);
}
}
}
public class SslHandlerFactory {
private final ClientConfig clientConfig;
private final HttpAddress httpAddress;
private final ByteBufAllocator allocator;
SslHandlerFactory(ClientConfig clientConfig, HttpAddress httpAddress, ByteBufAllocator allocator) {
this.clientConfig = clientConfig;
this.httpAddress = httpAddress;
this.allocator = allocator;
}
public SslHandler create() {
return newSslHandler(clientConfig, allocator, httpAddress);
}
}
}

View file

@ -10,7 +10,7 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.ssl.ApplicationProtocolNames;
import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
import io.netty.handler.ssl.SslHandler;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.ClientConfig;
import org.xbib.netty.http.client.handler.http2.Http2ChannelInitializer;
import org.xbib.netty.http.common.HttpAddress;
@ -26,7 +26,7 @@ public class HttpChannelInitializer extends ChannelInitializer<Channel> {
private final HttpAddress httpAddress;
private final SslHandler sslHandler;
private final Client.SslHandlerFactory sslHandlerFactory;
private final HttpResponseHandler httpResponseHandler;
@ -34,11 +34,11 @@ public class HttpChannelInitializer extends ChannelInitializer<Channel> {
public HttpChannelInitializer(ClientConfig clientConfig,
HttpAddress httpAddress,
SslHandler sslHandler,
Client.SslHandlerFactory sslHandlerFactory,
Http2ChannelInitializer http2ChannelInitializer) {
this.clientConfig = clientConfig;
this.httpAddress = httpAddress;
this.sslHandler = sslHandler;
this.sslHandlerFactory = sslHandlerFactory;
this.http2ChannelInitializer = http2ChannelInitializer;
this.httpResponseHandler = new HttpResponseHandler();
}
@ -60,7 +60,7 @@ public class HttpChannelInitializer extends ChannelInitializer<Channel> {
private void configureEncrypted(Channel channel) {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(sslHandler);
pipeline.addLast(sslHandlerFactory.create());
if (clientConfig.isEnableNegotiation()) {
ApplicationProtocolNegotiationHandler negotiationHandler =
new ApplicationProtocolNegotiationHandler(ApplicationProtocolNames.HTTP_1_1) {
@ -101,10 +101,6 @@ public class HttpChannelInitializer extends ChannelInitializer<Channel> {
false);
httpObjectAggregator.setMaxCumulationBufferComponents(clientConfig.getMaxCompositeBufferComponents());
pipeline.addLast(httpObjectAggregator);
/*if (clientConfig.isEnableGzip()) {
pipeline.addLast(new HttpChunkContentCompressor(6));
}
pipeline.addLast(new ChunkedWriteHandler());*/
pipeline.addLast(httpResponseHandler);
}
}

View file

@ -12,7 +12,7 @@ import io.netty.handler.codec.http2.Http2Headers;
import io.netty.handler.codec.http2.Http2MultiplexCodec;
import io.netty.handler.codec.http2.Http2MultiplexCodecBuilder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.ssl.SslHandler;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.ClientConfig;
import org.xbib.netty.http.client.handler.http.TrafficLoggingHandler;
import org.xbib.netty.http.client.transport.Transport;
@ -29,14 +29,14 @@ public class Http2ChannelInitializer extends ChannelInitializer<Channel> {
private final HttpAddress httpAddress;
private final SslHandler sslHandler;
private final Client.SslHandlerFactory sslHandlerFactory;
public Http2ChannelInitializer(ClientConfig clientConfig,
HttpAddress httpAddress,
SslHandler sslHandler) {
Client.SslHandlerFactory sslHandlerFactory) {
this.clientConfig = clientConfig;
this.httpAddress = httpAddress;
this.sslHandler = sslHandler;
this.sslHandlerFactory = sslHandlerFactory;
}
@Override
@ -55,7 +55,7 @@ public class Http2ChannelInitializer extends ChannelInitializer<Channel> {
}
private void configureEncrypted(Channel channel) {
channel.pipeline().addLast(sslHandler);
channel.pipeline().addLast(sslHandlerFactory.create());
configureCleartext(channel);
}

View file

@ -80,12 +80,8 @@ public class HttpTransport extends BaseTransport {
logger.log(Level.WARNING, "throwable not null for response " + fullHttpResponse, throwable);
return;
}
if (requests.isEmpty()) {
logger.log(Level.WARNING, "no request present, can not handle response " + fullHttpResponse);
return;
}
// streamID is expected to be null, last request on memory is expected to be current, remove request from memory
Request request = requests.remove(requests.lastKey());
Request request = requests.remove(requests.isEmpty() ? null : requests.lastKey());
if (request != null) {
for (String cookieString : fullHttpResponse.headers().getAll(HttpHeaderNames.SET_COOKIE)) {
Cookie cookie = ClientCookieDecoder.STRICT.decode(cookieString);
@ -140,6 +136,6 @@ public class HttpTransport extends BaseTransport {
@Override
protected String getRequestKey(String channelId, Integer streamId) {
return requests.lastKey();
return requests.isEmpty() ? null : requests.lastKey();
}
}

View file

@ -1,7 +1,7 @@
package org.xbib.netty.http.client.test;
import io.netty.handler.codec.http.FullHttpResponse;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
@ -12,7 +12,7 @@ import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
public class CompletableFutureTest {
class CompletableFutureTest {
private static final Logger logger = Logger.getLogger(CompletableFutureTest.class.getName());
@ -20,7 +20,7 @@ public class CompletableFutureTest {
* Get some weird content from one URL and post it to another URL, by composing completable futures.
*/
@Test
public void testComposeCompletableFutures() throws IOException {
void testComposeCompletableFutures() throws IOException {
Client client = Client.builder().build();
try {
final Function<FullHttpResponse, String> httpResponseStringFunction = response ->

View file

@ -1,8 +1,8 @@
package org.xbib.netty.http.client.test;
import org.conscrypt.Conscrypt;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
@ -11,14 +11,14 @@ import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ConscryptTest extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class ConscryptTest {
private static final Logger logger = Logger.getLogger("");
private static final Logger logger = Logger.getLogger(ConscryptTest.class.getName());
@Test
public void testConscrypt() throws IOException {
void testConscrypt() throws IOException {
Client client = Client.builder()
.enableDebug()
.setJdkSslProvider()
.setSslContextProvider(Conscrypt.newProvider())
.build();

View file

@ -1,7 +1,7 @@
package org.xbib.netty.http.client.test;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
@ -10,9 +10,8 @@ import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*/
public class CookieSetterHttpBinTest extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class CookieSetterHttpBinTest {
private static final Logger logger = Logger.getLogger(CookieSetterHttpBinTest.class.getName());
@ -30,7 +29,7 @@ public class CookieSetterHttpBinTest extends TestBase {
* @throws IOException if test fails
*/
@Test
public void testHttpBinCookies() throws IOException {
void testHttpBinCookies() throws IOException {
Client client = new Client();
try {
Request request = Request.get()

View file

@ -1,8 +1,8 @@
package org.xbib.netty.http.client.test;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.client.Request;
@ -18,17 +18,18 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
@Ignore
public class ElasticsearchTest extends TestBase {
@Disabled
@ExtendWith(NettyHttpExtension.class)
class ElasticsearchTest {
private static final Logger logger = Logger.getLogger(ElasticsearchTest.class.getName());
@Test
@Ignore
public void testElasticsearch() throws IOException {
Client client = Client.builder().enableDebug().build();
void testElasticsearch() throws IOException {
Client client = Client.builder()
.build();
try {
Request request = Request.get().url("http://localhost:9200")
.build()
@ -44,9 +45,9 @@ public class ElasticsearchTest extends TestBase {
}
@Test
@Ignore
public void testElasticsearchCreateDocument() throws IOException {
Client client = Client.builder().enableDebug().build();
void testElasticsearchCreateDocument() throws IOException {
Client client = Client.builder()
.build();
try {
Request request = Request.put().url("http://localhost:9200/test/test/1")
.json("{\"text\":\"Hello World\"}")
@ -63,8 +64,7 @@ public class ElasticsearchTest extends TestBase {
}
@Test
@Ignore
public void testElasticsearchMatchQuery() throws IOException {
void testElasticsearchMatchQuery() throws IOException {
Client client = new Client();
try {
Request request = Request.post().url("http://localhost:9200/test/_search")
@ -85,7 +85,7 @@ public class ElasticsearchTest extends TestBase {
* @throws IOException if test fails
*/
@Test
public void testElasticsearchPooled() throws IOException {
void testElasticsearchPooled() throws IOException {
HttpAddress httpAddress = HttpAddress.http1("localhost", 9200);
int limit = 4;
Client client = Client.builder()

View file

@ -1,8 +1,8 @@
package org.xbib.netty.http.client.test;
import io.netty.handler.codec.http.HttpMethod;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
@ -11,13 +11,15 @@ import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Http1Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class Http1Test {
private static final Logger logger = Logger.getLogger(Http1Test.class.getName());
@Test
public void testHttp1() throws Exception {
Client client = Client.builder().enableDebug().build();
void testHttp1() throws Exception {
Client client = Client.builder()
.build();
try {
Request request = Request.get().url("http://xbib.org").build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
@ -31,8 +33,28 @@ public class Http1Test extends TestBase {
}
@Test
public void testParallelRequests() throws IOException {
Client client = Client.builder().enableDebug().build();
void testSequentialRequests() throws Exception {
Client client = Client.builder()
.build();
try {
Request request1 = Request.get().url("http://xbib.org").build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.content().toString(StandardCharsets.UTF_8)));
client.execute(request1).get();
Request request2 = Request.get().url("http://google.com").setVersion("HTTP/1.1").build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.content().toString(StandardCharsets.UTF_8)));
client.execute(request2).get();
} finally {
client.shutdown();
}
}
@Test
void testParallelRequests() throws IOException {
Client client = Client.builder()
.build();
try {
Request request1 = Request.builder(HttpMethod.GET)
.url("http://xbib.org").setVersion("HTTP/1.1")
@ -58,22 +80,4 @@ public class Http1Test extends TestBase {
client.shutdownGracefully();
}
}
@Test
public void testSequentialRequests() throws Exception {
Client client = Client.builder().enableDebug().build();
try {
Request request1 = Request.get().url("http://xbib.org").build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.content().toString(StandardCharsets.UTF_8)));
client.execute(request1).get();
Request request2 = Request.get().url("http://google.com").setVersion("HTTP/1.1").build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.content().toString(StandardCharsets.UTF_8)));
client.execute(request2).get();
} finally {
client.shutdown();
}
}
}

View file

@ -1,9 +1,8 @@
package org.xbib.netty.http.client.test;
import io.netty.handler.codec.http.HttpMethod;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
@ -12,7 +11,8 @@ import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Http2Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class Http2Test {
private static final Logger logger = Logger.getLogger(Http2Test.class.getName());
@ -29,10 +29,8 @@ public class Http2Test extends TestBase {
* @throws IOException if test fails
*/
@Test
@Ignore
public void testAkamai() throws IOException {
void testAkamai() throws IOException {
Client client = Client.builder()
.enableDebug()
.addServerNameForIdentification("http2.akamai.com")
.build();
try {
@ -53,8 +51,9 @@ public class Http2Test extends TestBase {
}
@Test
public void testWebtide() throws Exception {
Client client = Client.builder().enableDebug().build();
void testWebtide() throws Exception {
Client client = Client.builder()
.build();
client.logDiagnostics(Level.INFO);
try {
Request request = Request.get().url("https://webtide.com").setVersion("HTTP/2.0").build()
@ -69,10 +68,9 @@ public class Http2Test extends TestBase {
}
@Test
public void testHttp2PushIO() throws IOException {
void testHttp2PushIO() throws IOException {
String url = "https://http2-push.io";
Client client = Client.builder()
.enableDebug()
.addServerNameForIdentification("http2-push.io")
.build();
try {
@ -91,7 +89,7 @@ public class Http2Test extends TestBase {
}
@Test
public void testWebtideTwoRequestsOnSameConnection() throws IOException {
void testWebtideTwoRequestsOnSameConnection() throws IOException {
Client client = new Client();
try {
Request request1 = Request.builder(HttpMethod.GET)

View file

@ -1,4 +1,7 @@
package org.xbib.netty.http.server.test;
package org.xbib.netty.http.client.test;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
@ -7,10 +10,10 @@ import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
public class TestBase {
static {
public class NettyHttpExtension implements BeforeAllCallback {
@Override
public void beforeAll(ExtensionContext context) throws Exception {
System.setProperty("io.netty.noUnsafe", Boolean.toString(true));
System.setProperty("io.netty.noKeySetOptimization", Boolean.toString(true));
//System.setProperty("io.netty.recycler.maxCapacity", Integer.toString(0));

View file

@ -1,18 +1,18 @@
package org.xbib.netty.http.client.test;
import io.netty.handler.codec.http.HttpMethod;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.Request;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RequestBuilderTest {
class RequestBuilderTest {
private static final Logger logger = Logger.getLogger(RequestBuilderTest.class.getName());
@Test
public void testSimpleRequest() {
void testSimpleRequest() {
Request request = Request.builder(HttpMethod.GET).content("Hello", "text/plain").build();
logger.log(Level.INFO, request.toString());
}

View file

@ -1,9 +1,8 @@
package org.xbib.netty.http.client.test;
import io.netty.handler.codec.http.HttpMethod;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
@ -12,13 +11,15 @@ import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SecureHttp1Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class SecureHttpTest {
private static final Logger logger = Logger.getLogger(SecureHttp1Test.class.getName());
private static final Logger logger = Logger.getLogger(SecureHttpTest.class.getName());
@Test
public void testHttp1() throws Exception {
Client client = Client.builder().enableDebug().build();
void testHttp1() throws Exception {
Client client = Client.builder()
.build();
try {
Request request = Request.get().url("https://www.google.com/").build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
@ -32,39 +33,9 @@ public class SecureHttp1Test extends TestBase {
}
@Test
@Ignore
public void testParallelRequests() throws IOException {
Client client = Client.builder().enableDebug().build();
try {
Request request1 = Request.builder(HttpMethod.GET)
.url("https://google.com").setVersion("HTTP/1.1")
.build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.headers().entries() +
//msg.content().toString(StandardCharsets.UTF_8) +
" status=" + msg.status().code()));
Request request2 = Request.builder(HttpMethod.GET)
.url("https://google.com").setVersion("HTTP/1.1")
.build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.headers().entries() +
//msg.content().toString(StandardCharsets.UTF_8) +
" status=" + msg.status().code()));
for (int i = 0; i < 10; i++) {
client.execute(request1);
client.execute(request2);
}
} finally {
client.shutdownGracefully();
}
}
@Test
@Ignore
public void testSequentialRequests() throws Exception {
Client client = Client.builder().enableDebug().build();
void testSequentialRequests() throws Exception {
Client client = Client.builder()
.build();
try {
Request request1 = Request.get().url("https://google.com").build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
@ -79,4 +50,33 @@ public class SecureHttp1Test extends TestBase {
client.shutdown();
}
}
@Test
void testParallelRequests() throws IOException {
Client client = Client.builder()
.build();
try {
Request request1 = Request.builder(HttpMethod.GET)
.url("https://google.com").setVersion("HTTP/1.1")
.build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.headers().entries() +
" status=" + msg.status().code()));
Request request2 = Request.builder(HttpMethod.GET)
.url("https://google.com").setVersion("HTTP/1.1")
.build()
.setResponseListener(msg -> logger.log(Level.INFO, "got response: " +
msg.headers().entries() +
" status=" + msg.status().code()));
for (int i = 0; i < 10; i++) {
client.execute(request1);
client.execute(request2);
}
} finally {
client.shutdownGracefully();
}
}
}

View file

@ -1,8 +1,9 @@
package org.xbib.netty.http.client.test;
import org.junit.After;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import java.io.IOException;
@ -10,18 +11,20 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ThreadLeakTest extends TestBase {
@ExtendWith(NettyHttpExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ThreadLeakTest {
private static final Logger logger = Logger.getLogger(ThreadLeakTest.class.getName());
@Test
public void testForLeaks() throws IOException {
void testForLeaks() throws IOException {
Client client = new Client();
client.shutdownGracefully();
}
@After
public void checkThreads() {
@AfterAll
void checkThreads() {
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
logger.log(Level.INFO, "threads = " + threadSet.size() );
threadSet.forEach( thread -> logger.log(Level.INFO, thread.toString()));

View file

@ -1,19 +1,17 @@
package org.xbib.netty.http.client.test;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.Request;
import org.xbib.netty.http.client.RequestBuilder;
import java.net.URI;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
*/
public class URITest {
class URITest {
@Test
public void testURIResolve() {
void testURIResolve() {
URI uri = URI.create("http://localhost");
URI uri2 = uri.resolve("/path");
assertEquals("http://localhost/path", uri2.toString());
@ -23,7 +21,7 @@ public class URITest {
}
@Test
public void testRequestURIs() {
void testRequestURIs() {
RequestBuilder httpRequestBuilder = Request.get();
httpRequestBuilder.url("https://localhost").uri("/path");
assertEquals("/path", httpRequestBuilder.build().relativeUri());

View file

@ -2,8 +2,7 @@ package org.xbib.netty.http.client.test;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.proxy.HttpProxyHandler;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
@ -15,12 +14,12 @@ import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
public class XbibTest extends TestBase {
class XbibTest {
private static final Logger logger = Logger.getLogger("");
private static final Logger logger = Logger.getLogger(XbibTest.class.getName());
@Test
public void testXbibOrgWithDefaults() throws IOException {
void testXbibOrgWithDefaults() throws IOException {
Client client = new Client();
try {
Request request = Request.get().url("http://xbib.org")
@ -36,7 +35,7 @@ public class XbibTest extends TestBase {
}
@Test
public void testXbibOrgWithCompletableFuture() throws IOException {
void testXbibOrgWithCompletableFuture() throws IOException {
Client httpClient = Client.builder()
.setTcpNodelay(true)
.build();
@ -66,7 +65,7 @@ public class XbibTest extends TestBase {
}
@Test
public void testXbibOrgWithProxy() throws IOException {
void testXbibOrgWithProxy() throws IOException {
Client httpClient = Client.builder()
.setHttpProxyHandler(new HttpProxyHandler(new InetSocketAddress("80.241.223.251", 8080)))
.setConnectTimeoutMillis(30000)
@ -87,7 +86,7 @@ public class XbibTest extends TestBase {
}
@Test
public void testXbibOrgWithVeryShortReadTimeout() throws IOException {
void testXbibOrgWithVeryShortReadTimeout() throws IOException {
Client httpClient = Client.builder()
.build();
try {
@ -106,7 +105,7 @@ public class XbibTest extends TestBase {
}
@Test
public void testXbibTwoSequentialRequests() throws IOException {
void testXbibTwoSequentialRequests() throws IOException {
Client httpClient = new Client();
try {
httpClient.execute(Request.get()

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.hacks;
package org.xbib.netty.http.client.test.hacks;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
@ -26,9 +26,7 @@ import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import javax.net.ssl.SNIHostName;
import javax.net.ssl.SNIServerName;
@ -40,13 +38,12 @@ import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
@Ignore
public class Http2FramesTest extends TestBase {
class Http2FramesTest {
private static final Logger logger = Logger.getLogger(Http2FramesTest.class.getName());
@Test
public void testHttp2Frames() throws Exception {
void testHttp2Frames() throws Exception {
final InetSocketAddress inetSocketAddress = new InetSocketAddress("webtide.com", 443);
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.hacks;
package org.xbib.netty.http.client.test.hacks;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
@ -19,10 +19,9 @@ import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.AttributeKey;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -40,8 +39,8 @@ import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
@Ignore
public class SimpleHttp1Test extends TestBase {
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SimpleHttp1Test {
private static final Logger logger = Logger.getLogger(SimpleHttp1Test.class.getName());
@ -62,7 +61,7 @@ public class SimpleHttp1Test extends TestBase {
}
}
@After
@AfterAll
public void checkThreads() {
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
logger.log(Level.INFO, "threads = " + threadSet.size() );
@ -74,7 +73,7 @@ public class SimpleHttp1Test extends TestBase {
}
@Test
public void testHttp1() throws Exception {
void testHttp1() throws Exception {
Client client = new Client();
try {
HttpTransport transport = client.newTransport("xbib.org", 80);

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.hacks;
package org.xbib.netty.http.client.test.hacks;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
@ -35,9 +35,7 @@ import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.util.AttributeKey;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.TestBase;
import org.junit.jupiter.api.Test;
import javax.net.ssl.SSLException;
import java.io.IOException;
@ -53,13 +51,12 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
@Ignore
public class SimpleHttp2Test extends TestBase {
class SimpleHttp2Test {
private static final Logger logger = Logger.getLogger(SimpleHttp2Test.class.getName());
@Test
public void testHttp2WithUpgrade() throws Exception {
void testHttp2WithUpgrade() throws Exception {
Client client = new Client();
try {
Http2Transport transport = client.newTransport("webtide.com", 443);

View file

@ -0,0 +1,17 @@
package org.xbib.netty.http.client.test.pool;
import io.netty.channel.epoll.Epoll;
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;
public class DisableTestCondition implements ExecutionCondition {
@Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
if (Epoll.isAvailable()) {
return ConditionEvaluationResult.enabled("Test enabled");
} else {
return ConditionEvaluationResult.disabled("Test disabled");
}
}
}

View file

@ -0,0 +1,14 @@
package org.xbib.netty.http.client.test.pool;
import org.junit.jupiter.api.extension.ExtendWith;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(DisableTestCondition.class)
public @interface DisabledIfEpolllNotAvailable {
}

View file

@ -17,17 +17,14 @@ import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpVersion;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.client.pool.Pool;
import org.xbib.netty.http.client.pool.BoundedChannelPool;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.Closeable;
import java.util.Collections;
import java.util.List;
@ -40,8 +37,12 @@ import java.util.concurrent.atomic.LongAdder;
import java.util.logging.Level;
import java.util.logging.Logger;
@Ignore
public class EpollTest {
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DisabledIfEpolllNotAvailable
class EpollTest {
private static final Logger logger = Logger.getLogger(EpollTest.class.getName());
@ -64,8 +65,8 @@ public class EpollTest {
private EventLoopGroup eventLoopGroup;
@Before
public void setUp() throws Exception {
@BeforeAll
void setUp() throws Exception {
mockEpollServer = new MockEpollServer(12345, FAIL_EVERY_ATTEMPT);
Semaphore semaphore = new Semaphore(CONCURRENCY);
eventLoopGroup = new EpollEventLoopGroup();
@ -86,15 +87,15 @@ public class EpollTest {
channelPool.prepare(CONCURRENCY);
}
@After
public void tearDown() throws Exception {
@AfterAll
void tearDown() throws Exception {
channelPool.close();
eventLoopGroup.shutdownGracefully();
mockEpollServer.close();
}
@Test
public void testPoolEpoll() throws Exception {
void testPoolEpoll() throws Exception {
LongAdder longAdder = new LongAdder();
ExecutorService executor = Executors.newFixedThreadPool(CONCURRENCY);
for(int i = 0; i < CONCURRENCY; i ++) {
@ -146,7 +147,7 @@ public class EpollTest {
private final AtomicLong reqCounter;
public MockEpollServer(int port, int dropEveryRequest) throws InterruptedException {
MockEpollServer(int port, int dropEveryRequest) throws InterruptedException {
dispatchGroup = new EpollEventLoopGroup();
workerGroup = new EpollEventLoopGroup();
reqCounter = new AtomicLong(0);

View file

@ -16,9 +16,10 @@ import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpVersion;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.client.pool.Pool;
import org.xbib.netty.http.client.pool.BoundedChannelPool;
@ -35,10 +36,11 @@ import java.util.concurrent.atomic.LongAdder;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class NioTest {
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class NioTest {
private static final Logger logger = Logger.getLogger(NioTest.class.getName());
@ -61,8 +63,8 @@ public class NioTest {
private EventLoopGroup eventLoopGroup;
@Before
public void setUp() throws Exception {
@BeforeAll
void setUp() throws Exception {
mockNioServer = new MockNioServer(12345, FAIL_EVERY_ATTEMPT);
Semaphore semaphore = new Semaphore(CONCURRENCY);
eventLoopGroup = new NioEventLoopGroup();
@ -83,15 +85,15 @@ public class NioTest {
channelPool.prepare(CONCURRENCY);
}
@After
public void tearDown() throws Exception {
@AfterAll
void tearDown() throws Exception {
channelPool.close();
eventLoopGroup.shutdownGracefully();
mockNioServer.close();
}
@Test
public void testPoolNio() throws Exception {
void testPoolNio() throws Exception {
LongAdder longAdder = new LongAdder();
ExecutorService executor = Executors.newFixedThreadPool(CONCURRENCY);
for(int i = 0; i < CONCURRENCY; i ++) {
@ -142,7 +144,7 @@ public class NioTest {
private final AtomicLong reqCounter;
public MockNioServer(int port, int dropEveryRequest) throws InterruptedException {
MockNioServer(int port, int dropEveryRequest) throws InterruptedException {
dispatchGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
reqCounter = new AtomicLong(0);

View file

@ -9,16 +9,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.AttributeKey;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.client.pool.BoundedChannelPool;
import org.xbib.netty.http.client.pool.Pool;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -30,11 +27,10 @@ import java.util.concurrent.atomic.LongAdder;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@RunWith(Parameterized.class)
public class PoolTest {
class PoolTest {
private static final Logger logger = Logger.getLogger(PoolTest.class.getName());
@ -42,30 +38,11 @@ public class PoolTest {
private static final int BATCH_SIZE = 0x1000;
private int nodeCount;
private ConcurrentMap<HttpAddress, LongAdder> nodeFreq = new ConcurrentHashMap<>();
@Parameterized.Parameters
public static Collection<Object[]> generateData() {
return Arrays.asList(new Object[][] {
{1, 1},
{10, 1},
{10, 2},
//{10, 5},
//{10, 10},
{100, 1},
{100, 2},
//{100, 5},
//{100, 10},
//{1000, 1},
//{1000, 2},
//{1000, 5},
//{1000, 10}
});
}
public PoolTest(int concurrencyLevel, int nodeCount) throws InterruptedException {
@ParameterizedTest
@ValueSource(ints = {1,10,100})
void testPool(int concurrencyLevel) throws InterruptedException {
ConcurrentMap<HttpAddress, LongAdder> nodeFreq = new ConcurrentHashMap<>();
int nodecount = 2;
ServerBootstrap serverBootstrap = new ServerBootstrap()
.group(new NioEventLoopGroup())
@ -77,9 +54,8 @@ public class PoolTest {
});
Channel serverChannel = serverBootstrap.bind("localhost", 8008).sync().channel();
this.nodeCount = nodeCount;
List<HttpAddress> nodes = new ArrayList<>();
for (int i = 0; i < nodeCount; i ++) {
for (int i = 0; i < nodecount; i ++) {
nodes.add(HttpAddress.http1("localhost", 8008));
}
try (Pool<Channel> pool = new BoundedChannelPool<>(new Semaphore(concurrencyLevel), HttpVersion.HTTP_1_1,
@ -127,25 +103,16 @@ public class PoolTest {
} finally {
serverChannel.close();
long connCountSum = nodeFreq.values().stream().mapToLong(LongAdder::sum).sum();
logger.log(Level.INFO, "concurrency = " + concurrencyLevel + ", nodes = " + nodeCount + " -> rate: " +
logger.log(Level.INFO, "concurrency = " + concurrencyLevel + ", nodes = " + nodecount + " -> rate: " +
connCountSum / TEST_STEP_TIME_SECONDS);
}
}
@Test
public void testNodeFrequency() {
if (nodeCount > 1) {
long connCountSum = nodeFreq.values().stream().mapToLong(LongAdder::sum).sum();
long avgConnCountPerNode = connCountSum / nodeCount;
long avgConnCountPerNode = connCountSum / 2;
for (HttpAddress nodeAddr: nodeFreq.keySet()) {
assertTrue(nodeFreq.get(nodeAddr).sum() > 0);
assertEquals("Node count: " + nodeCount + ", node: " + nodeAddr
+ ", expected connection count: " + avgConnCountPerNode + ", actual: "
+ nodeFreq.get(nodeAddr).sum(),
assertEquals(/*"Node count: " + nodeCount + ", node: " + nodeAddr
+ ", expected connection count: " + avgConnCountPerNode + ", actual: "
+ nodeFreq.get(nodeAddr).sum(),*/
avgConnCountPerNode, nodeFreq.get(nodeAddr).sum(), 1.5 * avgConnCountPerNode);
}
} else {
assertTrue(true);
}
}
}

View file

@ -1,11 +1,12 @@
package org.xbib.netty.http.client.test.pool;
import io.netty.handler.codec.http.HttpVersion;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.net.URL;
import org.xbib.netty.http.client.Client;
import org.xbib.TestBase;
import org.xbib.netty.http.client.listener.ResponseListener;
import org.xbib.netty.http.client.test.NettyHttpExtension;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.client.Request;
@ -18,12 +19,13 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
public class PooledClientTest extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class PooledClientTest {
private static final Logger logger = Logger.getLogger("");
private static final Logger logger = Logger.getLogger(PooledClientTest.class.getName());
@Test
public void testPooledClientWithSingleNode() throws IOException {
void testPooledClientWithSingleNode() throws IOException {
int loop = 10;
int threads = Runtime.getRuntime().availableProcessors();
URL url = URL.from("https://fl-test.hbz-nrw.de/app/fl");

View file

@ -1,17 +1,17 @@
package org.xbib.netty.http.client.test.rest;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.rest.RestClient;
import java.io.IOException;
import java.util.logging.Logger;
public class RestClientTest {
class RestClientTest {
private static final Logger logger = Logger.getLogger(RestClientTest.class.getName());
@Test
public void testSimpleGet() throws IOException {
void testSimpleGet() throws IOException {
String result = RestClient.get("http://xbib.org").asString();
logger.info(result);
}

View file

@ -1,19 +1,20 @@
package org.xbib.netty.http.client.test.retry;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.retry.BackOff;
import org.xbib.netty.http.client.retry.ExponentialBackOff;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests {@link ExponentialBackOff}.
*/
public class ExponentialBackOffTest {
class ExponentialBackOffTest {
@Test
public void testConstructor() {
void testConstructor() {
ExponentialBackOff backOffPolicy = new ExponentialBackOff();
assertEquals(ExponentialBackOff.DEFAULT_INITIAL_INTERVAL_MILLIS,
backOffPolicy.getInitialIntervalMillis());
@ -29,7 +30,7 @@ public class ExponentialBackOffTest {
}
@Test
public void testBuilder() {
void testBuilder() {
ExponentialBackOff backOffPolicy = new ExponentialBackOff.Builder().build();
assertEquals(ExponentialBackOff.DEFAULT_INITIAL_INTERVAL_MILLIS,
backOffPolicy.getInitialIntervalMillis());
@ -64,7 +65,7 @@ public class ExponentialBackOffTest {
}
@Test
public void testBackOff() {
void testBackOff() {
int testInitialInterval = 500;
double testRandomizationFactor = 0.1;
double testMultiplier = 2.0;
@ -90,7 +91,7 @@ public class ExponentialBackOffTest {
}
@Test
public void testGetRandomizedInterval() {
void testGetRandomizedInterval() {
// 33% chance of being 1.
assertEquals(1, ExponentialBackOff.getRandomValueFromInterval(0.5, 0, 2));
assertEquals(1, ExponentialBackOff.getRandomValueFromInterval(0.5, 0.33, 2));
@ -103,14 +104,14 @@ public class ExponentialBackOffTest {
}
@Test
public void testGetElapsedTimeMillis() {
void testGetElapsedTimeMillis() {
ExponentialBackOff backOffPolicy = new ExponentialBackOff.Builder().setNanoClock(new MyNanoClock()).build();
long elapsedTimeMillis = backOffPolicy.getElapsedTimeMillis();
assertEquals("elapsedTimeMillis=" + elapsedTimeMillis, 1000, elapsedTimeMillis);
assertEquals(1000, elapsedTimeMillis);
}
@Test
public void testMaxElapsedTime() {
void testMaxElapsedTime() {
ExponentialBackOff backOffPolicy =
new ExponentialBackOff.Builder().setNanoClock(new MyNanoClock(10000)).build();
assertTrue(backOffPolicy.nextBackOffMillis() != BackOff.STOP);
@ -121,7 +122,7 @@ public class ExponentialBackOffTest {
}
@Test
public void testBackOffOverflow() {
void testBackOffOverflow() {
int testInitialInterval = Integer.MAX_VALUE / 2;
double testMultiplier = 2.1;
int testMaxInterval = Integer.MAX_VALUE;

View file

@ -1,19 +1,19 @@
package org.xbib.netty.http.client.test.retry;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.retry.BackOff;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests {@link MockBackOff}.
*/
public class MockBackOffTest {
class MockBackOffTest {
@Test
public void testNextBackOffMillis() throws IOException {
void testNextBackOffMillis() throws IOException {
subtestNextBackOffMillis(0, new MockBackOff());
subtestNextBackOffMillis(BackOff.STOP, new MockBackOff().setBackOffMillis(BackOff.STOP));
subtestNextBackOffMillis(42, new MockBackOff().setBackOffMillis(42));

View file

@ -1,5 +1,5 @@
dependencies {
compile "org.xbib:net-url:${project.property('xbib-net-url.version')}"
compile "io.netty:netty-codec-http2:${project.property('netty.version')}"
implementation "org.xbib:net-url:${project.property('xbib-net-url.version')}"
implementation "io.netty:netty-codec-http2:${project.property('netty.version')}"
}

View file

@ -0,0 +1,6 @@
dependencies {
implementation project(":netty-http-server")
implementation "io.netty:netty-codec-http2:${project.property('netty.version')}"
implementation "org.xbib:net-url:${project.property('xbib-net-url.version')}"
implementation "org.xbib:guice:${project.property('xbib-guice.version')}"
}

View file

@ -0,0 +1,4 @@
package org.xbib.netty.http.server.rest;
public class Rest {
}

View file

@ -0,0 +1,4 @@
package org.xbib.netty.http.server.rest;
public class RestBuilder {
}

View file

@ -0,0 +1,4 @@
package org.xbib.netty.http.server.rest;
public class RestConfig {
}

View file

@ -0,0 +1,44 @@
package org.xbib.netty.http.server.rest;
import io.netty.bootstrap.Bootstrap;
import java.util.Optional;
/**
* Server name.
*/
public final class RestName {
/**
* The default value for {@code Server} header.
*/
private static final String SERVER_NAME = String.format("RestServer/%s (Java/%s/%s) (Netty/%s)",
httpServerVersion(), javaVendor(), javaVersion(), nettyVersion());
private RestName() {
}
public static String getServerName() {
return SERVER_NAME;
}
private static String httpServerVersion() {
return Optional.ofNullable(Rest.class.getPackage().getImplementationVersion())
.orElse("unknown");
}
private static String javaVendor() {
return Optional.ofNullable(System.getProperty("java.vendor"))
.orElse("unknown");
}
private static String javaVersion() {
return Optional.ofNullable(System.getProperty("java.version"))
.orElse("unknown");
}
private static String nettyVersion() {
return Optional.ofNullable(Bootstrap.class.getPackage().getImplementationVersion())
.orElse("unknown");
}
}

View file

@ -1,10 +1,10 @@
dependencies {
compile project(":netty-http-common")
compile "io.netty:netty-handler:${project.property('netty.version')}"
compile "io.netty:netty-transport-native-epoll:${project.property('netty.version')}"
compile "io.netty:netty-tcnative-boringssl-static:${project.property('tcnative.version')}"
compile "org.bouncycastle:bcpkix-jdk15on:${project.property('bouncycastle.version')}"
testCompile project(":netty-http-client")
testCompile "junit:junit:${project.property('junit.version')}"
implementation project(":netty-http-common")
implementation "io.netty:netty-handler:${project.property('netty.version')}"
implementation "io.netty:netty-transport-native-epoll:${project.property('netty.version')}"
implementation "io.netty:netty-tcnative-boringssl-static:${project.property('tcnative.version')}"
implementation "io.netty:netty-codec-http2:${project.property('netty.version')}"
implementation "org.xbib:net-url:${project.property('xbib-net-url.version')}"
implementation "org.bouncycastle:bcpkix-jdk15on:${project.property('bouncycastle.version')}"
testImplementation project(":netty-http-client")
}

View file

@ -21,7 +21,7 @@ import io.netty.handler.ssl.SslContextBuilder;
import io.netty.util.DomainNameMapping;
import io.netty.util.DomainNameMappingBuilder;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.NamedServer;
import org.xbib.netty.http.server.handler.http.HttpChannelInitializer;
import org.xbib.netty.http.server.handler.http2.Http2ChannelInitializer;
import org.xbib.netty.http.server.transport.HttpServerTransport;
@ -73,7 +73,7 @@ public final class Server {
private final ServerBootstrap bootstrap;
private final Map<String, VirtualServer> virtualServerMap;
private final Map<String, NamedServer> virtualServerMap;
private ChannelFuture channelFuture;
@ -118,11 +118,11 @@ public final class Server {
bootstrap.handler(new LoggingHandler("bootstrap-server", serverConfig.getDebugLogLevel()));
}
this.virtualServerMap = new HashMap<>();
for (VirtualServer virtualServer : serverConfig.getVirtualServers()) {
String name = virtualServer.getName();
virtualServerMap.put(name, virtualServer);
for (String alias : virtualServer.getAliases()) {
virtualServerMap.put(alias, virtualServer);
for (NamedServer namedServer : serverConfig.getNamedServers()) {
String name = namedServer.getName();
virtualServerMap.put(name, namedServer);
for (String alias : namedServer.getAliases()) {
virtualServerMap.put(alias, namedServer);
}
}
DomainNameMapping<SslContext> domainNameMapping = null;
@ -136,8 +136,8 @@ public final class Server {
}
SslContext sslContext = sslContextBuilder.build();
DomainNameMappingBuilder<SslContext> mappingBuilder = new DomainNameMappingBuilder<>(sslContext);
for (VirtualServer virtualServer : serverConfig.getVirtualServers()) {
String name = virtualServer.getName();
for (NamedServer namedServer : serverConfig.getNamedServers()) {
String name = namedServer.getName();
mappingBuilder.add(name == null ? "*" : name, sslContext);
}
domainNameMapping = mappingBuilder.build();
@ -169,11 +169,11 @@ public final class Server {
* the default virtual host
* @return the virtual host with the given name, or null if it doesn't exist
*/
public VirtualServer getVirtualServer(String name) {
public NamedServer getVirtualServer(String name) {
return virtualServerMap.get(name);
}
public VirtualServer getDefaultVirtualServer() {
public NamedServer getDefaultVirtualServer() {
return virtualServerMap.get(null);
}

View file

@ -8,7 +8,8 @@ import io.netty.handler.ssl.CipherSuiteFilter;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.Handler;
import org.xbib.netty.http.server.endpoint.NamedServer;
import org.xbib.netty.http.server.security.tls.SelfSignedCertificate;
import javax.net.ssl.SSLException;
@ -224,8 +225,16 @@ public class ServerBuilder {
return this;
}
public ServerBuilder addVirtualServer(VirtualServer virtualServer) {
this.serverConfig.addVirtualServer(virtualServer);
public ServerBuilder addServer(NamedServer namedServer) {
this.serverConfig.add(namedServer);
return this;
}
public ServerBuilder addHandler(String path, Handler handler, String... methods) {
if (serverConfig.getNamedServers().isEmpty()) {
serverConfig.add(new NamedServer());
}
serverConfig.getNamedServers().getLast().addHandler(path, handler, methods);
return this;
}

View file

@ -10,12 +10,14 @@ import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.NamedServer;
import javax.net.ssl.TrustManagerFactory;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
public class ServerConfig {
@ -117,7 +119,7 @@ public class ServerConfig {
/**
* This is Netty's default.
* See {@link io.netty.handler.codec.MessageAggregator#DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS}.
* See {@link io.netty.handler.codec.MessageAggregator#maxCumulationBufferComponents()}.
*/
int MAX_COMPOSITE_BUFFER_COMPONENTS = 1024;
@ -225,15 +227,15 @@ public class ServerConfig {
private String keyPassword;
private List<VirtualServer> virtualServers;
private Deque<NamedServer> namedServers;
private TrustManagerFactory trustManagerFactory = TRUST_MANAGER_FACTORY;
private KeyStore trustManagerKeyStore = null;
public ServerConfig() {
this.virtualServers = new ArrayList<>();
addVirtualServer(new VirtualServer(null));
this.namedServers = new LinkedList<>();
add(new NamedServer(null));
}
public ServerConfig enableDebug() {
@ -512,13 +514,13 @@ public class ServerConfig {
return keyPassword;
}
public ServerConfig addVirtualServer(VirtualServer virtualServer) {
this.virtualServers.add(virtualServer);
public ServerConfig add(NamedServer namedServer) {
this.namedServers.add(namedServer);
return this;
}
public List<VirtualServer> getVirtualServers() {
return virtualServers;
public Deque<NamedServer> getNamedServers() {
return namedServers;
}
public ServerConfig setTrustManagerFactory(TrustManagerFactory trustManagerFactory) {

View file

@ -12,7 +12,7 @@ public final class ServerName {
/**
* The default value for {@code Server} header.
*/
private static final String SERVER_NAME = String.format("XbibHttpServer/%s (Java/%s/%s) (Netty/%s)",
private static final String SERVER_NAME = String.format("NettyHttpServer/%s (Java/%s/%s) (Netty/%s)",
httpServerVersion(), javaVendor(), javaVersion(), nettyVersion());
private ServerName() {

View file

@ -1,24 +0,0 @@
package org.xbib.netty.http.server.context;
import org.xbib.netty.http.server.transport.ServerRequest;
import org.xbib.netty.http.server.transport.ServerResponse;
import java.io.IOException;
/**
* A {@code ContextHandler} is capable of serving content for resources within its context.
*
* @see VirtualServer#addContext
*/
@FunctionalInterface
public interface ContextHandler {
/**
* Serves the given request using the given response.
*
* @param serverRequest the request to be served
* @param serverResponse the response to be filled
* @throws IOException if an IO error occurs
*/
void serve(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException;
}

View file

@ -1,46 +0,0 @@
package org.xbib.netty.http.server.context;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* The {@code ContextInfo} class holds a single context's information.
*/
public class ContextInfo {
private final VirtualServer virtualServer;
private final Map<String, ContextHandler> methodHandlerMap;
public ContextInfo(VirtualServer virtualServer) {
this.virtualServer = virtualServer;
this.methodHandlerMap = new LinkedHashMap<>();
}
/**
* Returns the map of supported HTTP methods and their corresponding handlers.
*
* @return the map of supported HTTP methods and their corresponding handlers
*/
public Map<String, ContextHandler> getMethodHandlerMap() {
return methodHandlerMap;
}
/**
* Adds (or replaces) a context handler for the given HTTP methods.
*
* @param handler the context handler
* @param methods the HTTP methods supported by the handler (default is "GET")
*/
public void addHandler(ContextHandler handler, String... methods) {
if (methods.length == 0) {
methodHandlerMap.put("GET", handler);
virtualServer.getMethods().add("GET");
} else {
for (String method : methods) {
methodHandlerMap.put(method, handler);
virtualServer.getMethods().add(method);
}
}
}
}

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.server.context;
package org.xbib.netty.http.server.endpoint;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@ -16,19 +16,19 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class ClasspathContextHandler implements ContextHandler {
public class ClasspathHandler implements Handler {
private final ClassLoader classLoader;
private final String prefix;
public ClasspathContextHandler(ClassLoader classLoader, String prefix) {
public ClasspathHandler(ClassLoader classLoader, String prefix) {
this.classLoader = classLoader;
this.prefix = prefix;
}
@Override
public void serve(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
public void handle(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
String contextPath = serverRequest.getContextPath();
URL url = classLoader.getResource(prefix + contextPath);
if (url != null) {

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.server.context;
package org.xbib.netty.http.server.endpoint;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -7,11 +7,11 @@ import java.lang.annotation.Target;
/**
* The {@code Context} annotation decorates methods which are mapped
* to a context (path) within the server, and provide its contents.
* to a context path within the server, and provide its contents.
* The annotated methods must have the same signature and contract
* as {@link ContextHandler#serve}, but can have arbitrary names.
* as {@link Handler#handle}, but can have arbitrary names.
*
* @see VirtualServer#addContexts(Object)
* @see NamedServer#addHandlers(Object)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.server.context;
package org.xbib.netty.http.server.endpoint;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
@ -13,19 +13,19 @@ import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
public class DirectoryContextHandler implements ContextHandler {
public class DirectoryHandler implements Handler {
private Path path;
private ByteBufAllocator allocator;
public DirectoryContextHandler(Path path, ByteBufAllocator allocator) {
public DirectoryHandler(Path path, ByteBufAllocator allocator) {
this.path = path;
this.allocator = allocator;
}
@Override
public void serve(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
public void handle(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
String uri = serverRequest.getRequest().uri();
Path p = path.resolve(uri);
ByteBuf byteBuf = read(allocator, p);

View file

@ -0,0 +1,46 @@
package org.xbib.netty.http.server.endpoint;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* The {@code Endpoint} class holds an endpoint information.
*/
public class Endpoint {
private final NamedServer namedServer;
private final Map<String, Handler> handlerMap;
public Endpoint(NamedServer namedServer) {
this.namedServer = namedServer;
this.handlerMap = new LinkedHashMap<>();
}
/**
* Returns the map of supported HTTP methods and their corresponding handlers.
*
* @return the map of supported HTTP methods and their corresponding handlers
*/
public Map<String, Handler> getHandlerMap() {
return handlerMap;
}
/**
* Adds (or replaces) a handler for the given HTTP methods.
*
* @param handler the handler
* @param methods the HTTP methods supported by the handler (default is "GET")
*/
public void addHandler(Handler handler, String... methods) {
if (methods.length == 0) {
handlerMap.put("GET", handler);
namedServer.getMethods().add("GET");
} else {
for (String method : methods) {
handlerMap.put(method, handler);
namedServer.getMethods().add(method);
}
}
}
}

View file

@ -0,0 +1,24 @@
package org.xbib.netty.http.server.endpoint;
import org.xbib.netty.http.server.transport.ServerRequest;
import org.xbib.netty.http.server.transport.ServerResponse;
import java.io.IOException;
/**
* A {@code Handler} is capable of serving content for resources within its context.
*
* @see NamedServer#addHandler
*/
@FunctionalInterface
public interface Handler {
/**
* Handles the given request by using the given response.
*
* @param serverRequest the request to be served
* @param serverResponse the response to be generated
* @throws IOException if an IO error occurs
*/
void handle(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException;
}

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.server.context;
package org.xbib.netty.http.server.endpoint;
import org.xbib.netty.http.server.transport.ServerRequest;
import org.xbib.netty.http.server.transport.ServerResponse;
@ -8,20 +8,19 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* The {@code MethodContextHandler} services a context
* by invoking a handler method on a specified object.
* The {@code MethodHandler} invokes g a handler method on a specified object.
* The method must have the same signature and contract as
* {@link ContextHandler#serve}, but can have an arbitrary name.
* {@link Handler#handle}, but can have an arbitrary name.
*
* @see VirtualServer#addContexts(Object)
* @see NamedServer#addHandlers(Object)
*/
public class MethodContextHandler implements ContextHandler {
public class MethodHandler implements Handler {
private final Method m;
private final Object obj;
public MethodContextHandler(Method m, Object obj) throws IllegalArgumentException {
public MethodHandler(Method m, Object obj) throws IllegalArgumentException {
this.m = m;
this.obj = obj;
Class<?>[] params = m.getParameterTypes();
@ -34,7 +33,7 @@ public class MethodContextHandler implements ContextHandler {
}
@Override
public void serve(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
public void handle(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
try {
m.invoke(obj, serverRequest, serverResponse);
} catch (InvocationTargetException ite) {

View file

@ -0,0 +1,21 @@
package org.xbib.netty.http.server.endpoint;
public class NamedEndpoint {
private final String name;
private final Endpoint endpoint;
NamedEndpoint(String name, Endpoint endpoint) {
this.name = name;
this.endpoint = endpoint;
}
public String getName() {
return name;
}
public Endpoint getEndpoint() {
return endpoint;
}
}

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.server.context;
package org.xbib.netty.http.server.endpoint;
import java.lang.reflect.Method;
import java.util.Collections;
@ -10,7 +10,7 @@ import java.util.Set;
/**
* The {@code VirtualServer} class represents a virtual server.
*/
public class VirtualServer {
public class NamedServer {
private final String name;
@ -18,28 +18,28 @@ public class VirtualServer {
private final Set<String> methods;
private final ContextInfo emptyContext;
private final Endpoint defaultEndpoint;
private final Map<String, ContextInfo> contexts;
private final Map<String, Endpoint> endpointMap;
private volatile boolean allowGeneratedIndex;
public VirtualServer() {
public NamedServer() {
this(null);
}
/**
* Constructs a VirtualServer with the given name.
* Constructs a {@code NamedServer} with the given name.
*
* @param name the name, or null if it is the default server
*/
public VirtualServer(String name) {
public NamedServer(String name) {
this.name = name;
this.aliases = new HashSet<>();
this.methods = new HashSet<>();
this.contexts = new HashMap<>();
this.emptyContext = new ContextInfo(this);
contexts.put("*", new ContextInfo(this)); // for "OPTIONS *"
this.endpointMap = new HashMap<>();
this.defaultEndpoint = new Endpoint(this);
endpointMap.put("*", new Endpoint(this)); // for "OPTIONS *"
}
/**
@ -105,34 +105,36 @@ public class VirtualServer {
* @param path the context's path (must start with '/')
* @param handler the context handler for the given path
* @param methods the HTTP methods supported by the context handler (default is "GET")
* @return this virtual server
* @throws IllegalArgumentException if path is malformed
*/
public VirtualServer addContext(String path, ContextHandler handler, String... methods) {
public NamedServer addHandler(String path, Handler handler, String... methods) {
if (path == null || !path.startsWith("/") && !path.equals("*")) {
throw new IllegalArgumentException("invalid path: " + path);
}
String s = trimRight(path, '/');
ContextInfo info = new ContextInfo(this);
ContextInfo existing = contexts.putIfAbsent(s, info);
Endpoint info = new Endpoint(this);
Endpoint existing = endpointMap.putIfAbsent(s, info);
info = existing != null ? existing : info;
info.addHandler(handler, methods);
return this;
}
/**
* Adds contexts for all methods of the given object that
* Adds handler for all methods of the given object that
* are annotated with the {@link Context} annotation.
*
* @param o the object whose annotated methods are added
* @return this virtual server
* @throws IllegalArgumentException if a Context-annotated
* method has an {@link Context invalid signature}
*/
public VirtualServer addContexts(Object o) throws IllegalArgumentException {
public NamedServer addHandlers(Object o) throws IllegalArgumentException {
for (Class<?> c = o.getClass(); c != null; c = c.getSuperclass()) {
for (Method m : c.getDeclaredMethods()) {
Context context = m.getAnnotation(Context.class);
if (context != null) {
addContext(context.value(), new MethodContextHandler(m, o), context.methods());
addHandler(context.value(), new MethodHandler(m, o), context.methods());
}
}
}
@ -140,24 +142,24 @@ public class VirtualServer {
}
/**
* Returns the context handler for the given path.
* If a context is not found for the given path, the search is repeated for
* Returns the endpoint for the given path.
* If an endpoint is not found for the given path, the search is repeated for
* its parent path, and so on until a base context is found. If neither the
* given path nor any of its parents has a context, an empty context is returned.
*
* @param path the context's path
* @return the context info for the given path, or an empty context if none exists
*/
public ContextPath getContextPath(String path) {
public NamedEndpoint getNamedEndpoint(String path) {
String s = trimRight(path, '/');
ContextInfo info = null;
Endpoint info = null;
String hook = null;
while (info == null && s != null) {
hook = s;
info = contexts.get(s);
info = endpointMap.get(s);
s = getParentPath(s);
}
return new ContextPath(hook, info != null ? info : emptyContext);
return new NamedEndpoint(hook, info != null ? info : defaultEndpoint);
}
/**
@ -190,24 +192,4 @@ public class VirtualServer {
return slash == -1 ? null : s.substring(0, slash);
}
public class ContextPath {
private final String hook;
private final ContextInfo contextInfo;
ContextPath(String hook, ContextInfo contextInfo) {
this.hook = hook;
this.contextInfo = contextInfo;
}
public String getHook() {
return hook;
}
public ContextInfo getContextInfo() {
return contextInfo;
}
}
}

View file

@ -1,4 +1,4 @@
package org.xbib.netty.http.server.context;
package org.xbib.netty.http.server.endpoint;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@ -13,11 +13,11 @@ import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
public class NioContextHandler implements ContextHandler {
public class NioHandler implements Handler {
private final Path prefix;
public NioContextHandler(Path prefix) {
public NioHandler(Path prefix) {
this.prefix = prefix;
if (!Files.exists(prefix) || !Files.isDirectory(prefix)) {
throw new IllegalArgumentException("prefix: " + prefix + " (not a directory");
@ -25,7 +25,7 @@ public class NioContextHandler implements ContextHandler {
}
@Override
public void serve(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
public void handle(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
String requestPath = serverRequest.getRequestPath();
Path path = prefix.resolve(requestPath.substring(1)); // starts always with '/'
if (Files.exists(path) && Files.isReadable(path)) {

View file

@ -6,8 +6,9 @@ import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.xbib.netty.http.server.Server;
import org.xbib.netty.http.server.context.ContextHandler;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.Handler;
import org.xbib.netty.http.server.endpoint.NamedEndpoint;
import org.xbib.netty.http.server.endpoint.NamedServer;
import java.io.IOException;
import java.util.Arrays;
@ -88,28 +89,28 @@ abstract class BaseServerTransport implements ServerTransport {
protected static void handle(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException {
String method = serverRequest.getRequest().method().name();
String path = serverRequest.getRequest().uri();
VirtualServer virtualServer = serverRequest.getVirtualServer();
VirtualServer.ContextPath contextPath = virtualServer.getContextPath(path);
serverRequest.setContextPath(contextPath.getHook());
Map<String, ContextHandler> methodHandlerMap = contextPath.getContextInfo().getMethodHandlerMap();
NamedServer namedServer = serverRequest.getNamedServer();
NamedEndpoint namedEndpoint = namedServer.getNamedEndpoint(path);
serverRequest.setContextPath(namedEndpoint.getName());
Map<String, Handler> methodHandlerMap = namedEndpoint.getEndpoint().getHandlerMap();
// RFC 2616#5.1.1 - GET and HEAD must be supported
if (method.equals("GET") || method.equals("HEAD") || methodHandlerMap.containsKey(method)) {
ContextHandler handler = methodHandlerMap.get(method);
Handler handler = methodHandlerMap.get(method);
if (handler == null) {
serverResponse.writeError(HttpResponseStatus.NOT_FOUND);
} else {
handler.serve(serverRequest, serverResponse);
handler.handle(serverRequest, serverResponse);
}
} else {
Set<String> methods = new LinkedHashSet<>(METHODS);
// "*" is a special server-wide (no-context) request supported by OPTIONS
boolean isServerOptions = path.equals("*") && method.equals("OPTIONS");
methods.addAll(isServerOptions ? virtualServer.getMethods() : methodHandlerMap.keySet());
methods.addAll(isServerOptions ? namedServer.getMethods() : methodHandlerMap.keySet());
serverResponse.setHeader(HttpHeaderNames.ALLOW, String.join(", ", methods));
if (method.equals("OPTIONS")) { // default OPTIONS handler
serverResponse.setHeader(HttpHeaderNames.CONTENT_LENGTH, "0"); // RFC2616#9.2
serverResponse.write(HttpResponseStatus.OK);
} else if (virtualServer.getMethods().contains(method)) {
} else if (namedServer.getMethods().contains(method)) {
serverResponse.write(HttpResponseStatus.METHOD_NOT_ALLOWED); // supported by server, but not this context (nor built-in)
} else {
serverResponse.writeError(HttpResponseStatus.NOT_IMPLEMENTED); // unsupported method

View file

@ -8,7 +8,7 @@ import io.netty.handler.codec.http2.Http2Settings;
import io.netty.handler.codec.http2.HttpConversionUtil;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.server.Server;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.NamedServer;
import java.io.IOException;
@ -26,13 +26,13 @@ public class Http2ServerTransport extends BaseServerTransport {
@Override
public void requestReceived(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest, Integer sequenceId) throws IOException {
int requestId = requestCounter.incrementAndGet();
VirtualServer virtualServer = server.getVirtualServer(fullHttpRequest.headers().get(HttpHeaderNames.HOST));
if (virtualServer == null) {
virtualServer = server.getDefaultVirtualServer();
NamedServer namedServer = server.getVirtualServer(fullHttpRequest.headers().get(HttpHeaderNames.HOST));
if (namedServer == null) {
namedServer = server.getDefaultVirtualServer();
}
HttpAddress httpAddress = server.getServerConfig().getAddress();
Integer streamId = fullHttpRequest.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());
ServerRequest serverRequest = new ServerRequest(virtualServer, httpAddress, fullHttpRequest,
ServerRequest serverRequest = new ServerRequest(namedServer, httpAddress, fullHttpRequest,
sequenceId, streamId, requestId);
ServerResponse serverResponse = new Http2ServerResponse(serverRequest, ctx);
if (acceptRequest(serverRequest, serverResponse)) {

View file

@ -7,7 +7,7 @@ import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http2.Http2Settings;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.server.Server;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.NamedServer;
import java.io.IOException;
@ -26,12 +26,12 @@ public class HttpServerTransport extends BaseServerTransport {
public void requestReceived(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest, Integer sequenceId)
throws IOException {
int requestId = requestCounter.incrementAndGet();
VirtualServer virtualServer = server.getVirtualServer(fullHttpRequest.headers().get(HttpHeaderNames.HOST));
if (virtualServer == null) {
virtualServer = server.getDefaultVirtualServer();
NamedServer namedServer = server.getVirtualServer(fullHttpRequest.headers().get(HttpHeaderNames.HOST));
if (namedServer == null) {
namedServer = server.getDefaultVirtualServer();
}
HttpAddress httpAddress = server.getServerConfig().getAddress();
ServerRequest serverRequest = new ServerRequest(virtualServer, httpAddress, fullHttpRequest,
ServerRequest serverRequest = new ServerRequest(namedServer, httpAddress, fullHttpRequest,
sequenceId, null, requestId);
ServerResponse serverResponse = new HttpServerResponse(serverRequest, ctx);
if (acceptRequest(serverRequest, serverResponse)) {

View file

@ -2,14 +2,14 @@ package org.xbib.netty.http.server.transport;
import io.netty.handler.codec.http.FullHttpRequest;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.NamedServer;
/**
* The {@code ServerRequest} class encapsulates a single request.
*/
public class ServerRequest {
private final VirtualServer virtualServer;
private final NamedServer namedServer;
private final HttpAddress httpAddress;
@ -23,9 +23,9 @@ public class ServerRequest {
private String contextPath;
public ServerRequest(VirtualServer virtualServer, HttpAddress httpAddress,
public ServerRequest(NamedServer namedServer, HttpAddress httpAddress,
FullHttpRequest httpRequest, Integer sequenceId, Integer streamId, Integer requestId) {
this.virtualServer = virtualServer;
this.namedServer = namedServer;
this.httpAddress = httpAddress;
this.httpRequest = httpRequest;
this.sequenceId = sequenceId;
@ -33,8 +33,8 @@ public class ServerRequest {
this.requestId = requestId;
}
public VirtualServer getVirtualServer() {
return virtualServer;
public NamedServer getNamedServer() {
return namedServer;
}
public void setContextPath(String contextPath) {

View file

@ -2,7 +2,8 @@ package org.xbib.netty.http.server.test;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
import org.xbib.netty.http.client.listener.ResponseListener;
@ -18,18 +19,19 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CleartextHttp1Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class CleartextHttp1Test {
private static final Logger logger = Logger.getLogger(CleartextHttp1Test.class.getName());
@Test
public void testSimpleClearTextHttp1() throws Exception {
void testSimpleClearTextHttp1() throws Exception {
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
Server server = Server.builder()
.bind(httpAddress).build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()));
server.accept();
Client client = Client.builder()
@ -51,23 +53,20 @@ public class CleartextHttp1Test extends TestBase {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "exepecting=1 counter=" + counter.get());
assertEquals(1, counter.get());
}
@Test
public void testPooledClearTextHttp1() throws Exception {
void testPooledClearTextHttp1() throws Exception {
int loop = 4096;
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
Server server = Server.builder()
//.enableDebug()
.bind(httpAddress).build();
server.getDefaultVirtualServer().addContext("/", (request, response) -> {
server.getDefaultVirtualServer().addHandler("/", (request, response) -> {
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain());
});
server.accept();
Client client = Client.builder()
//.enableDebug()
.addPoolNode(httpAddress)
.setPoolNodeConnectionLimit(2)
.build();
@ -96,19 +95,17 @@ public class CleartextHttp1Test extends TestBase {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "expecting=" + loop + " counter=" + counter.get());
assertEquals(loop, counter.get());
}
@Test
public void testMultithreadedPooledClearTextHttp1() throws Exception {
void testMultithreadedPooledClearTextHttp1() throws Exception {
int threads = 4;
int loop = 4 * 1024;
HttpAddress httpAddress = HttpAddress.http1("localhost", 8008);
Server server = Server.builder()
//.enableDebug()
.bind(httpAddress).build();
server.getDefaultVirtualServer().addContext("/", (request, response) -> {
server.getDefaultVirtualServer().addHandler("/", (request, response) -> {
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain());
});
server.accept();
@ -159,7 +156,6 @@ public class CleartextHttp1Test extends TestBase {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "expecting=" + (threads * loop) + " counter=" + counter.get());
assertEquals(threads * loop, counter.get());
}
}

View file

@ -1,7 +1,8 @@
package org.xbib.netty.http.server.test;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
import org.xbib.netty.http.client.listener.ResponseListener;
@ -18,19 +19,20 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CleartextHttp2Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class CleartextHttp2Test {
private static final Logger logger = Logger.getLogger(CleartextHttp2Test.class.getName());
@Test
public void testSimpleCleartextHttp2() throws Exception {
void testSimpleCleartextHttp2() throws Exception {
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
Server server = Server.builder()
.bind(httpAddress)
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()));
server.accept();
Client client = Client.builder()
@ -60,23 +62,19 @@ public class CleartextHttp2Test extends TestBase {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "counter = " + counter.get());
assertEquals(1, counter.get());
}
@Test
public void testPooledClearTextHttp2() throws Exception {
void testPooledClearTextHttp2() throws Exception {
int loop = 4096;
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
Server server = Server.builder()
.bind(httpAddress).build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()));
//server.getDefaultVirtualServer().addContext("/", (request, response) ->
// response.write(request.getRequest().content().toString(StandardCharsets.UTF_8)));
server.accept();
Client client = Client.builder()
//.enableDebug()
.addPoolNode(httpAddress)
.setPoolNodeConnectionLimit(2)
.build();
@ -114,14 +112,14 @@ public class CleartextHttp2Test extends TestBase {
}
@Test
public void testMultithreadPooledClearTextHttp2() throws Exception {
void testMultithreadPooledClearTextHttp2() throws Exception {
int threads = 2;
int loop = 4 * 1024;
HttpAddress httpAddress = HttpAddress.http2("localhost", 8008);
Server server = Server.builder()
.bind(httpAddress)
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(request.getRequest().content().toString(StandardCharsets.UTF_8))
);
server.accept();
@ -176,7 +174,7 @@ public class CleartextHttp2Test extends TestBase {
}
@Test
public void testTwoPooledClearTextHttp2() throws Exception {
void testTwoPooledClearTextHttp2() throws Exception {
int threads = 2;
int loop = 4 * 1024;
@ -184,7 +182,7 @@ public class CleartextHttp2Test extends TestBase {
AtomicInteger counter1 = new AtomicInteger();
Server server1 = Server.builder()
.bind(httpAddress1).build();
server1.getDefaultVirtualServer().addContext("/", (request, response) -> {
server1.getDefaultVirtualServer().addHandler("/", (request, response) -> {
response.write(request.getRequest().content().toString(StandardCharsets.UTF_8));
counter1.incrementAndGet();
});
@ -194,7 +192,7 @@ public class CleartextHttp2Test extends TestBase {
AtomicInteger counter2 = new AtomicInteger();
Server server2 = Server.builder()
.bind(httpAddress2).build();
server2.getDefaultVirtualServer().addContext("/", (request, response) -> {
server2.getDefaultVirtualServer().addHandler("/", (request, response) -> {
response.write(request.getRequest().content().toString(StandardCharsets.UTF_8));
counter2.incrementAndGet();
});
@ -240,9 +238,9 @@ public class CleartextHttp2Test extends TestBase {
});
}
executorService.shutdown();
boolean terminated = executorService.awaitTermination(30, TimeUnit.SECONDS);
boolean terminated = executorService.awaitTermination(60, TimeUnit.SECONDS);
logger.log(Level.INFO, "terminated = " + terminated + ", now waiting for transport to complete");
transport.get(30, TimeUnit.SECONDS);
transport.get(60, TimeUnit.SECONDS);
} finally {
client.shutdownGracefully();
server1.shutdownGracefully();
@ -250,6 +248,6 @@ public class CleartextHttp2Test extends TestBase {
}
logger.log(Level.INFO, "counter1=" + counter1.get() + " counter2=" + counter2.get());
logger.log(Level.INFO, "expecting=" + threads * loop + " counter=" + counter.get());
//assertEquals(threads * loop, counter.get());
assertEquals(threads * loop, counter.get());
}
}

View file

@ -1,5 +1,10 @@
package org.xbib;
package org.xbib.netty.http.server.test;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.security.Security;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
@ -7,9 +12,13 @@ import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
public class TestBase {
public class NettyHttpExtension implements BeforeAllCallback {
static {
@Override
public void beforeAll(ExtensionContext context) {
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
}
System.setProperty("io.netty.noUnsafe", Boolean.toString(true));
System.setProperty("io.netty.noKeySetOptimization", Boolean.toString(true));
//System.setProperty("io.netty.recycler.maxCapacity", Integer.toString(0));

View file

@ -2,8 +2,8 @@ package org.xbib.netty.http.server.test;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
import org.xbib.netty.http.client.listener.ResponseListener;
@ -13,7 +13,6 @@ import org.xbib.netty.http.server.Server;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -21,20 +20,15 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class SecureHttp1Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class SecureHttp1Test {
private static final Logger logger = Logger.getLogger(SecureHttp1Test.class.getName());
static {
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
@Test
public void testSimpleSecureHttp1() throws Exception {
void testSimpleSecureHttp1() throws Exception {
Server server = Server.builder()
.setJdkSslProvider()
.setSelfCert()
@ -51,7 +45,7 @@ public class SecureHttp1Test extends TestBase {
counter.getAndIncrement();
};
try {
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()));
server.accept();
Request request = Request.get().setVersion(HttpVersion.HTTP_1_1)
@ -63,19 +57,18 @@ public class SecureHttp1Test extends TestBase {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "counter=" + counter.get());
assertEquals(1, counter.get());
}
@Test
public void testPooledSecureHttp1() throws Exception {
void testPooledSecureHttp1() throws Exception {
int loop = 4096;
HttpAddress httpAddress = HttpAddress.secureHttp1("localhost", 8143);
Server server = Server.builder()
.setJdkSslProvider()
.setSelfCert()
.bind(httpAddress).build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()));
server.accept();
Client client = Client.builder()
@ -114,7 +107,7 @@ public class SecureHttp1Test extends TestBase {
}
@Test
public void testMultithreadPooledSecureHttp1() throws Exception {
void testMultithreadPooledSecureHttp1() throws Exception {
int threads = 4;
int loop = 4 * 1024;
HttpAddress httpAddress = HttpAddress.secureHttp1("localhost", 8143);
@ -123,7 +116,7 @@ public class SecureHttp1Test extends TestBase {
.setSelfCert()
.bind(httpAddress)
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())
);
server.accept();
@ -147,7 +140,7 @@ public class SecureHttp1Test extends TestBase {
executorService.submit(() -> {
try {
for (int i = 0; i < loop; i++) {
String payload = Integer.toString(t) + "/" + Integer.toString(i);
String payload = t + "/" + i;
Request request = Request.get().setVersion(HttpVersion.HTTP_1_1)
.url(server.getServerConfig().getAddress().base())
.content(payload, "text/plain")
@ -168,13 +161,12 @@ public class SecureHttp1Test extends TestBase {
});
}
executorService.shutdown();
boolean terminated = executorService.awaitTermination(30, TimeUnit.SECONDS);
boolean terminated = executorService.awaitTermination(60, TimeUnit.SECONDS);
logger.log(Level.INFO, "terminated = " + terminated);
} finally {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "expecting=" + (threads * loop) + " counter=" + counter.get());
assertEquals(threads * loop , counter.get());
}
}

View file

@ -1,8 +1,8 @@
package org.xbib.netty.http.server.test;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
import org.xbib.netty.http.client.listener.ResponseListener;
@ -12,7 +12,6 @@ import org.xbib.netty.http.server.Server;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -20,27 +19,22 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class SecureHttp2Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class SecureHttp2Test {
private static final Logger logger = Logger.getLogger(SecureHttp2Test.class.getName());
static {
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
@Test
public void testSimpleSecureHttp2() throws Exception {
void testSimpleSecureHttp2() throws Exception {
HttpAddress httpAddress = HttpAddress.secureHttp2("localhost", 8143);
Server server = Server.builder()
.setJdkSslProvider()
.setSelfCert()
.bind(httpAddress)
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()));
server.accept();
Client client = Client.builder()
@ -57,7 +51,7 @@ public class SecureHttp2Test extends TestBase {
};
try {
Transport transport = client.newTransport(httpAddress);
String payload = Integer.toString(0) + "/" + Integer.toString(0);
String payload = 0 + "/" + 0;
Request request = Request.get()
.setVersion("HTTP/2.0")
.uri("/")
@ -71,12 +65,11 @@ public class SecureHttp2Test extends TestBase {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "counter = " + counter.get());
assertEquals(1, counter.get());
}
@Test
public void testPooledSecureHttp2() throws Exception {
void testPooledSecureHttp2() throws Exception {
int loop = 4096;
HttpAddress httpAddress = HttpAddress.secureHttp2("localhost", 8143);
Server server = Server.builder()
@ -84,7 +77,7 @@ public class SecureHttp2Test extends TestBase {
.setSelfCert()
.bind(httpAddress)
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()));
server.accept();
Client client = Client.builder()
@ -122,12 +115,11 @@ public class SecureHttp2Test extends TestBase {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "counter=" + counter.get());
assertEquals(loop, counter.get());
}
@Test
public void testMultithreadPooledSecureHttp2() throws Exception {
void testMultithreadPooledSecureHttp2() throws Exception {
int threads = 4;
int loop = 4 * 1024;
HttpAddress httpAddress = HttpAddress.secureHttp2("localhost", 8143);
@ -136,7 +128,7 @@ public class SecureHttp2Test extends TestBase {
.setSelfCert()
.bind(httpAddress)
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())
);
server.accept();
@ -163,7 +155,7 @@ public class SecureHttp2Test extends TestBase {
executorService.submit(() -> {
try {
for (int i = 0; i < loop; i++) {
String payload = Integer.toString(t) + "/" + Integer.toString(i);
String payload = t + "/" + i;
Request request = Request.get().setVersion("HTTP/2.0")
.url(server.getServerConfig().getAddress().base())
.content(payload, "text/plain")
@ -181,14 +173,13 @@ public class SecureHttp2Test extends TestBase {
});
}
executorService.shutdown();
boolean terminated = executorService.awaitTermination(30, TimeUnit.SECONDS);
boolean terminated = executorService.awaitTermination(60, TimeUnit.SECONDS);
logger.log(Level.INFO, "terminated = " + terminated + ", now waiting for transport to complete");
transport.get(30, TimeUnit.SECONDS);
transport.get(60, TimeUnit.SECONDS);
} finally {
client.shutdownGracefully();
server.shutdownGracefully();
}
logger.log(Level.INFO, "expected=" + (threads * loop) + " counter=" + counter.get());
assertEquals(threads * loop , counter.get());
}
}

View file

@ -1,16 +1,16 @@
package org.xbib.netty.http.server.test;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.server.security.tls.SelfSignedCertificate;
import java.security.Security;
import java.util.logging.Logger;
public class SelfSignedCertificateTest {
class SelfSignedCertificateTest {
@Test
public void testSelfSignedCertificate() throws Exception {
void testSelfSignedCertificate() throws Exception {
Security.addProvider(new BouncyCastleProvider());
SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate("localhost");
selfSignedCertificate.exportPEM(Logger.getLogger("test"));

View file

@ -1,17 +1,17 @@
package org.xbib.netty.http.server.test;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.server.Server;
@Ignore
public class ServerTest {
@Disabled
class ServerTest {
@Test
public void testServer() throws Exception {
void testServer() throws Exception {
Server server = Server.builder()
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write("Hello World"));
try {
server.accept().channel().closeFuture().sync();

View file

@ -1,12 +1,12 @@
package org.xbib.netty.http.server.test;
import io.netty.handler.codec.http.HttpVersion;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.xbib.netty.http.client.Client;
import org.xbib.netty.http.client.Request;
import org.xbib.netty.http.common.HttpAddress;
import org.xbib.netty.http.server.Server;
import org.xbib.netty.http.server.context.NioContextHandler;
import org.xbib.netty.http.server.context.VirtualServer;
import org.xbib.netty.http.server.endpoint.NioHandler;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@ -16,18 +16,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class StaticFileServerTest {
class StaticFileServerTest {
private static final Logger logger = Logger.getLogger(StaticFileServerTest.class.getName());
@Test
public void testStaticFileServer() throws Exception {
void testStaticFileServer() throws Exception {
Path vartmp = Paths.get("/var/tmp/");
Server server = Server.builder()
.addVirtualServer(new VirtualServer().addContext("/static", new NioContextHandler(vartmp)))
.bind(HttpAddress.http1("localhost", 8008))
.addHandler("/static", new NioHandler(vartmp))
.build();
Client client = Client.builder()
.build();

View file

@ -1,8 +1,10 @@
package org.xbib.netty.http.server.test;
import io.netty.buffer.UnpooledByteBufAllocator;
import org.junit.After;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.server.Server;
import java.io.IOException;
@ -10,16 +12,18 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ThreadLeakTest extends TestBase {
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(NettyHttpExtension.class)
class ThreadLeakTest {
private static final Logger logger = Logger.getLogger(ThreadLeakTest.class.getName());
@Test
public void testForLeaks() throws IOException {
void testForLeaks() throws IOException {
Server server = Server.builder()
.setByteBufAllocator(UnpooledByteBufAllocator.DEFAULT)
.build();
server.getDefaultVirtualServer().addContext("/", (request, response) ->
server.getDefaultVirtualServer().addHandler("/", (request, response) ->
response.write("Hello World"));
try {
server.accept();
@ -28,8 +32,8 @@ public class ThreadLeakTest extends TestBase {
}
}
@After
public void checkThreads() throws Exception {
@AfterAll
void checkThreads() throws Exception {
Thread.sleep(1000L);
System.gc();
Thread.sleep(3000L);

View file

@ -29,9 +29,9 @@ import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder;
import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.netty.http.server.test.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.server.test.NettyHttpExtension;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
@ -39,8 +39,8 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
@Ignore
public class CleartextHttp2Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class CleartextHttp2Test {
private static final Logger clientLogger = Logger.getLogger("client");
private static final Logger serverLogger = Logger.getLogger("server");
@ -56,17 +56,12 @@ public class CleartextHttp2Test extends TestBase {
private CompletableFuture<Boolean> completableFuture;
@Test
public void testHttp2() throws Exception {
void testHttp2() throws Exception {
final InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 8008);
settingsPrefaceFuture = new CompletableFuture<>();
completableFuture = new CompletableFuture<>();
EventLoopGroup serverEventLoopGroup = new NioEventLoopGroup();
EventLoopGroup clientEventLoopGroup = new NioEventLoopGroup();
try {
Http2Connection http2ServerConnection = new DefaultHttp2Connection(true);
ServerBootstrap serverBootstrap = new ServerBootstrap()
@ -132,7 +127,7 @@ public class CleartextHttp2Test extends TestBase {
clientChannel.writeAndFlush(request);
clientLogger.log(level, "waiting");
completableFuture.get(10, TimeUnit.SECONDS);
completableFuture.get(30, TimeUnit.SECONDS);
if (completableFuture.isDone()) {
clientLogger.log(Level.INFO, "done");
}

View file

@ -18,13 +18,15 @@ import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.server.handler.http.HttpPipelinedRequest;
import org.xbib.netty.http.server.handler.http.HttpPipelinedResponse;
import org.xbib.netty.http.server.handler.http.HttpPipeliningHandler;
import org.xbib.netty.http.server.test.TestBase;
import org.xbib.netty.http.server.test.NettyHttpExtension;
import java.nio.channels.ClosedChannelException;
import java.nio.charset.StandardCharsets;
@ -42,26 +44,30 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Ignore
public class HttpPipeliningHandlerTest extends TestBase {
/** flaky */
@Disabled
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(NettyHttpExtension.class)
class HttpPipeliningHandlerTest {
private static final Logger logger = Logger.getLogger(HttpPipeliningHandlerTest.class.getName());
private static Map<String, CountDownLatch> waitingRequests = new ConcurrentHashMap<>();
@After
public void closeResources() {
@AfterAll
void closeResources() {
for (String url : waitingRequests.keySet()) {
finishRequest(url);
}
}
@Test
public void testThatPipeliningWorksWithFastSerializedRequests() {
void testThatPipeliningWorksWithFastSerializedRequests() {
WorkEmulatorHandler handler = new WorkEmulatorHandler();
EmbeddedChannel embeddedChannel = new EmbeddedChannel(new HttpPipeliningHandler(10000),
handler);
@ -75,11 +81,11 @@ public class HttpPipeliningHandlerTest extends TestBase {
for (int i = 0; i < 5; i++) {
assertReadHttpMessageHasContent(embeddedChannel, String.valueOf(i));
}
assertThat(embeddedChannel.isOpen(), is(true));
assertTrue(embeddedChannel.isOpen());
}
@Test
public void testThatPipeliningWorksWhenSlowRequestsInDifferentOrder() {
void testThatPipeliningWorksWhenSlowRequestsInDifferentOrder() {
WorkEmulatorHandler handler = new WorkEmulatorHandler();
EmbeddedChannel embeddedChannel = new EmbeddedChannel(new HttpPipeliningHandler(10000),
handler);
@ -95,11 +101,11 @@ public class HttpPipeliningHandlerTest extends TestBase {
for (int i = 0; i < 5; i++) {
assertReadHttpMessageHasContent(embeddedChannel, String.valueOf(i));
}
assertThat(embeddedChannel.isOpen(), is(true));
assertTrue(embeddedChannel.isOpen());
}
@Test
public void testThatPipeliningWorksWithChunkedRequests() {
void testThatPipeliningWorksWithChunkedRequests() {
WorkEmulatorHandler handler = new WorkEmulatorHandler();
EmbeddedChannel embeddedChannel = new EmbeddedChannel(new AggregateUrisAndHeadersHandler(),
new HttpPipeliningHandler(10000), handler);
@ -115,32 +121,34 @@ public class HttpPipeliningHandlerTest extends TestBase {
for (int i = 0; i < 2; i++) {
assertReadHttpMessageHasContent(embeddedChannel, String.valueOf(i));
}
assertThat(embeddedChannel.isOpen(), is(true));
assertTrue(embeddedChannel.isOpen());
}
@Test(expected = ClosedChannelException.class)
public void testThatPipeliningClosesConnectionWithTooManyEvents() {
WorkEmulatorHandler handler = new WorkEmulatorHandler();
EmbeddedChannel embeddedChannel = new EmbeddedChannel(new HttpPipeliningHandler(2),
handler);
embeddedChannel.writeInbound(createHttpRequest("/0"));
embeddedChannel.writeInbound(createHttpRequest("/1"));
embeddedChannel.writeInbound(createHttpRequest("/2"));
embeddedChannel.writeInbound(createHttpRequest("/3"));
finishRequest("1");
finishRequest("2");
finishRequest("3");
finishRequest("0");
handler.shutdownExecutorService();
embeddedChannel.writeInbound(createHttpRequest("/"));
@Test
void testThatPipeliningClosesConnectionWithTooManyEvents() {
assertThrows(ClosedChannelException.class, () -> {
WorkEmulatorHandler handler = new WorkEmulatorHandler();
EmbeddedChannel embeddedChannel = new EmbeddedChannel(new HttpPipeliningHandler(2),
handler);
embeddedChannel.writeInbound(createHttpRequest("/0"));
embeddedChannel.writeInbound(createHttpRequest("/1"));
embeddedChannel.writeInbound(createHttpRequest("/2"));
embeddedChannel.writeInbound(createHttpRequest("/3"));
finishRequest("1");
finishRequest("2");
finishRequest("3");
finishRequest("0");
handler.shutdownExecutorService();
embeddedChannel.writeInbound(createHttpRequest("/"));
});
}
private void assertReadHttpMessageHasContent(EmbeddedChannel embeddedChannel, String expectedContent) {
FullHttpResponse response = (FullHttpResponse) embeddedChannel.outboundMessages().poll();
assertNotNull("Expected response to exist, maybe you did not wait long enough?", response);
assertNotNull("Expected response to have content " + expectedContent, response.content());
assertNotNull(response);
assertNotNull(response.content());
String data = new String(ByteBufUtil.getBytes(response.content()), StandardCharsets.UTF_8);
assertThat(data, is(expectedContent));
assertEquals(expectedContent, data);
}
private void finishRequest(String url) {
@ -163,7 +171,7 @@ public class HttpPipeliningHandlerTest extends TestBase {
private class WorkEmulatorHandler extends SimpleChannelInboundHandler<HttpPipelinedRequest> {
private final ExecutorService executorService = Executors.newFixedThreadPool(5);
private final ExecutorService executorService = Executors.newFixedThreadPool(8);
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpPipelinedRequest pipelinedRequest) {
@ -181,6 +189,7 @@ public class HttpPipeliningHandlerTest extends TestBase {
httpResponse.headers().add(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
CountDownLatch latch = new CountDownLatch(1);
waitingRequests.put(uri, latch);
// can cause RejectedExecutionException if executorService is too small
executorService.submit(() -> {
try {
latch.await(2, TimeUnit.SECONDS);

View file

@ -25,7 +25,6 @@ import io.netty.handler.codec.http.HttpServerUpgradeHandler;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http2.CleartextHttp2ServerUpgradeHandler;
import io.netty.handler.codec.http2.DefaultHttp2Headers;
//import io.netty.handler.codec.http2.DefaultHttp2PushPromiseFrame;
import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame;
import io.netty.handler.codec.http2.Http2CodecUtil;
import io.netty.handler.codec.http2.Http2ConnectionPrefaceAndSettingsFrameWrittenEvent;
@ -41,9 +40,9 @@ import io.netty.handler.codec.http2.Http2StreamFrameToHttpObjectCodec;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.AsciiString;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.netty.http.server.test.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.server.test.NettyHttpExtension;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
@ -69,8 +68,8 @@ import java.util.logging.Logger;
*
*
*/
@Ignore
public class MultiplexCodecCleartextHttp2Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class MultiplexCodecCleartextHttp2Test {
private static final Logger clientLogger = Logger.getLogger("client");
private static final Logger serverLogger = Logger.getLogger("server");
@ -82,14 +81,11 @@ public class MultiplexCodecCleartextHttp2Test extends TestBase {
private final CompletableFuture<Boolean> responseFuture = new CompletableFuture<>();
@Test
public void testMultiplexHttp2() throws Exception {
void testMultiplexHttp2() throws Exception {
Http2FrameLogger serverFrameLogger = new Http2FrameLogger(LogLevel.INFO, "server");
Http2FrameLogger clientFrameLogger = new Http2FrameLogger(LogLevel.INFO, "client");
EventLoopGroup serverEventLoopGroup = new NioEventLoopGroup();
EventLoopGroup clientEventLoopGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap()
.group(serverEventLoopGroup)

View file

@ -27,9 +27,9 @@ import io.netty.handler.codec.http2.Http2ConnectionPrefaceAndSettingsFrameWritte
import io.netty.handler.codec.http2.Http2Settings;
import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder;
import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.netty.http.server.test.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.server.test.NettyHttpExtension;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
@ -40,8 +40,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
@Ignore
public class MultithreadedCleartextHttp2Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class MultithreadedCleartextHttp2Test {
private static final Logger clientLogger = Logger.getLogger("client");
private static final Logger serverLogger = Logger.getLogger("server");
@ -61,7 +61,7 @@ public class MultithreadedCleartextHttp2Test extends TestBase {
private final AtomicInteger responseCounter = new AtomicInteger();
@Test
public void testMultiThreadedHttp2() throws Exception {
void testMultiThreadedHttp2() throws Exception {
inetSocketAddress = new InetSocketAddress("localhost", 8008);
settingsPrefaceFuture = new CompletableFuture<>();

View file

@ -35,9 +35,9 @@ import io.netty.handler.codec.http2.Http2StreamChannel;
import io.netty.handler.codec.http2.Http2StreamChannelBootstrap;
import io.netty.handler.codec.http2.Http2StreamFrameToHttpObjectCodec;
import io.netty.util.AsciiString;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.netty.http.server.test.TestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.xbib.netty.http.server.test.NettyHttpExtension;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
@ -53,8 +53,8 @@ import java.util.logging.Logger;
* Multithreaded Http2MultiplexCodec demo for cleartext HTTP/2 between a server and a client.
*
*/
@Ignore
public class MultithreadedMultiplexCodecCleartextHttp2Test extends TestBase {
@ExtendWith(NettyHttpExtension.class)
class MultithreadedMultiplexCodecCleartextHttp2Test {
private static final Logger clientLogger = Logger.getLogger("client");
private static final Logger serverLogger = Logger.getLogger("server");
@ -74,7 +74,7 @@ public class MultithreadedMultiplexCodecCleartextHttp2Test extends TestBase {
private final AtomicInteger responseCounter = new AtomicInteger();
@Test
public void testMultithreadedMultiplexHttp2() throws Exception {
void testMultithreadedMultiplexHttp2() throws Exception {
inetSocketAddress = new InetSocketAddress("localhost", 8008);
settingsPrefaceFuture = new CompletableFuture<>();

View file

@ -1,3 +1,4 @@
include 'netty-http-common'
include 'netty-http-client'
include 'netty-http-server'
include 'netty-http-server-rest'