convenience API methods, checkstyle and findbug fixes

This commit is contained in:
Jörg Prante 2017-05-12 01:06:09 +02:00
parent 8f1a7211e6
commit 741228dd76
16 changed files with 164 additions and 96 deletions

View file

@ -56,10 +56,10 @@ page at http://checkstyle.sourceforge.net/config.html -->
<!-- Checks for out of order import statements. --> <!-- Checks for out of order import statements. -->
<property name="severity" value="warning"/> <property name="severity" value="warning"/>
<property name="groups" value="com,io,junit,net,org,java,javax"/> <property name="groups" value="com,io,junit,net,org,javax,java"/>
<!-- This ensures that static imports go last. --> <!-- This ensures that static imports go last. -->
<property name="option" value="under"/> <property name="option" value="under"/>
<property name="tokens" value="STATIC_IMPORT, IMPORT"/> <property name="tokens" value="IMPORT, STATIC_IMPORT"/>
</module> </module>
<!-- <!--

View file

@ -41,10 +41,6 @@ import io.netty.handler.codec.http2.HttpConversionUtil;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
import static io.netty.handler.codec.http2.Http2Exception.connectionError;
/** /**
* A HTTP/2 event adapter for a client. * A HTTP/2 event adapter for a client.
* This event adapter expects {@link Http2Settings} are sent from the server before the * This event adapter expects {@link Http2Settings} are sent from the server before the
@ -80,7 +76,7 @@ public class Http2EventHandler extends Http2EventAdapter {
/** /**
* Handles an inbound {@code SETTINGS} frame. * Handles an inbound {@code SETTINGS} frame.
* After frame is received, the reuqets is sent. * After frame is received, the request is sent.
* *
* @param ctx the context from the handler where the frame was read. * @param ctx the context from the handler where the frame was read.
* @param settings the settings received from the remote endpoint. * @param settings the settings received from the remote endpoint.
@ -214,12 +210,13 @@ public class Http2EventHandler extends Http2EventAdapter {
Http2Stream stream = connection.stream(streamId); Http2Stream stream = connection.stream(streamId);
FullHttpMessage msg = getMessage(stream); FullHttpMessage msg = getMessage(stream);
if (msg == null) { if (msg == null) {
throw connectionError(PROTOCOL_ERROR, "data frame received for unknown stream id %d", streamId); throw Http2Exception.connectionError(Http2Error.PROTOCOL_ERROR,
"data frame received for unknown stream id %d", streamId);
} }
ByteBuf content = msg.content(); ByteBuf content = msg.content();
final int dataReadableBytes = data.readableBytes(); final int dataReadableBytes = data.readableBytes();
if (content.readableBytes() > maxContentLength - dataReadableBytes) { if (content.readableBytes() > maxContentLength - dataReadableBytes) {
throw connectionError(INTERNAL_ERROR, throw Http2Exception.connectionError(Http2Error.INTERNAL_ERROR,
"content length exceeded maximum of %d for stream id %d", maxContentLength, streamId); "content length exceeded maximum of %d for stream id %d", maxContentLength, streamId);
} }
content.writeBytes(data, data.readerIndex(), dataReadableBytes); content.writeBytes(data, data.readerIndex(), dataReadableBytes);
@ -349,7 +346,7 @@ public class Http2EventHandler extends Http2EventAdapter {
} }
} }
/** /**
* The stream is out of scope for the HTTP message flow and will no longer be tracked * The stream is out of scope for the HTTP message flow and will no longer be tracked.
* @param stream The stream to remove associated state with * @param stream The stream to remove associated state with
* @param release {@code true} to call release on the value if it is present. {@code false} to not call release. * @param release {@code true} to call release on the value if it is present. {@code false} to not call release.
*/ */
@ -361,7 +358,7 @@ public class Http2EventHandler extends Http2EventAdapter {
} }
/** /**
* Set final headers and fire a channel read event * Set final headers and fire a channel read event.
* *
* @param ctx The context to fire the event on * @param ctx The context to fire the event on
* @param msg The message to send * @param msg The message to send
@ -390,8 +387,7 @@ public class Http2EventHandler extends Http2EventAdapter {
return msg; return msg;
} }
private void endHeader(ChannelHandlerContext ctx, Http2Stream stream, FullHttpMessage msg, private void endHeader(ChannelHandlerContext ctx, Http2Stream stream, FullHttpMessage msg, boolean endOfStream) {
boolean endOfStream) {
if (endOfStream) { if (endOfStream) {
fireChannelRead(ctx, msg, getMessage(stream) != msg, stream); fireChannelRead(ctx, msg, getMessage(stream) != msg, stream);
} else { } else {

View file

@ -35,12 +35,13 @@ import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.cookie.ClientCookieEncoder; import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
import io.netty.handler.codec.http.cookie.Cookie; import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.ssl.OpenSsl;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import org.xbib.netty.http.client.listener.CookieListener; import org.xbib.netty.http.client.listener.CookieListener;
import org.xbib.netty.http.client.listener.ExceptionListener; import org.xbib.netty.http.client.listener.ExceptionListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpHeadersListener; import org.xbib.netty.http.client.listener.HttpHeadersListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpResponseListener; import org.xbib.netty.http.client.listener.HttpResponseListener;
import org.xbib.netty.http.client.util.InetAddressKey; import org.xbib.netty.http.client.util.InetAddressKey;
import org.xbib.netty.http.client.util.NetworkUtils; import org.xbib.netty.http.client.util.NetworkUtils;
@ -66,6 +67,8 @@ public final class HttpClient implements Closeable {
private static final AtomicInteger streamId = new AtomicInteger(3); private static final AtomicInteger streamId = new AtomicInteger(3);
private static final HttpClient INSTANCE = HttpClient.builder().build();
private final ByteBufAllocator byteBufAllocator; private final ByteBufAllocator byteBufAllocator;
private final EventLoopGroup eventLoopGroup; private final EventLoopGroup eventLoopGroup;
@ -83,11 +86,16 @@ public final class HttpClient implements Closeable {
this.byteBufAllocator = byteBufAllocator; this.byteBufAllocator = byteBufAllocator;
this.eventLoopGroup = eventLoopGroup; this.eventLoopGroup = eventLoopGroup;
this.poolMap = new HttpClientChannelPoolMap(this, httpClientChannelContext, bootstrap, maxConnections); this.poolMap = new HttpClientChannelPoolMap(this, httpClientChannelContext, bootstrap, maxConnections);
logger.log(Level.FINE, () -> "OpenSSL ALPN support: " + OpenSsl.isAlpnSupported());
NetworkUtils.extendSystemProperties(); NetworkUtils.extendSystemProperties();
logger.log(Level.FINE, () -> "local host name = " + NetworkUtils.getLocalHostName("localhost")); logger.log(Level.FINE, () -> "local host name = " + NetworkUtils.getLocalHostName("localhost"));
logger.log(Level.FINE, NetworkUtils::displayNetworkInterfaces); logger.log(Level.FINE, NetworkUtils::displayNetworkInterfaces);
} }
public static HttpClient getInstance() {
return INSTANCE;
}
/** /**
* Create a builder to configure connecting. * Create a builder to configure connecting.
* *
@ -106,73 +114,105 @@ public final class HttpClient implements Closeable {
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder prepareGet() { public HttpRequestBuilder prepareGet() {
return prepareRequest(HttpMethod.GET); return prepareRequest(HttpMethod.GET);
} }
public HttpRequestBuilder prepareGet(String url) {
return prepareRequest(HttpMethod.GET).setURL(url);
}
/** /**
* Prepare a HTTP HEAD request. * Prepare a HTTP HEAD request.
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder prepareHead() { public HttpRequestBuilder prepareHead() {
return prepareRequest(HttpMethod.HEAD); return prepareRequest(HttpMethod.HEAD);
} }
public HttpRequestBuilder prepareHead(String url) {
return prepareRequest(HttpMethod.HEAD).setURL(url);
}
/** /**
* Prepare a HTTP PUT request. * Prepare a HTTP PUT request.
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder preparePut() { public HttpRequestBuilder preparePut() {
return prepareRequest(HttpMethod.PUT); return prepareRequest(HttpMethod.PUT);
} }
public HttpRequestBuilder preparePut(String url) {
return prepareRequest(HttpMethod.PUT).setURL(url);
}
/** /**
* Prepare a HTTP POST request. * Prepare a HTTP POST request.
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder preparePost() { public HttpRequestBuilder preparePost() {
return prepareRequest(HttpMethod.POST); return prepareRequest(HttpMethod.POST);
} }
public HttpRequestBuilder preparePost(String url) {
return prepareRequest(HttpMethod.POST).setURL(url);
}
/** /**
* Prepare a HTTP DELETE request. * Prepare a HTTP DELETE request.
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder prepareDelete() { public HttpRequestBuilder prepareDelete() {
return prepareRequest(HttpMethod.DELETE); return prepareRequest(HttpMethod.DELETE);
} }
public HttpRequestBuilder prepareDelete(String url) {
return prepareRequest(HttpMethod.DELETE).setURL(url);
}
/** /**
* Prepare a HTTP OPTIONS request. * Prepare a HTTP OPTIONS request.
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder prepareOptions() { public HttpRequestBuilder prepareOptions() {
return prepareRequest(HttpMethod.OPTIONS); return prepareRequest(HttpMethod.OPTIONS);
} }
public HttpRequestBuilder prepareOptions(String url) {
return prepareRequest(HttpMethod.OPTIONS).setURL(url);
}
/** /**
* Prepare a HTTP PATCH request. * Prepare a HTTP PATCH request.
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder preparePatch() { public HttpRequestBuilder preparePatch() {
return prepareRequest(HttpMethod.PATCH); return prepareRequest(HttpMethod.PATCH);
} }
public HttpRequestBuilder preparePatch(String url) {
return prepareRequest(HttpMethod.PATCH).setURL(url);
}
/** /**
* Prepare a HTTP TRACE request. * Prepare a HTTP TRACE request.
* *
* @return a request builder * @return a request builder
*/ */
public HttpClientRequestBuilder prepareTrace() { public HttpRequestBuilder prepareTrace() {
return prepareRequest(HttpMethod.TRACE); return prepareRequest(HttpMethod.TRACE);
} }
public HttpRequestBuilder prepareTrace(String url) {
return prepareRequest(HttpMethod.TRACE).setURL(url);
}
public HttpClientChannelPoolMap poolMap() { public HttpClientChannelPoolMap poolMap() {
return poolMap; return poolMap;
} }
@ -258,7 +298,8 @@ public final class HttpClient implements Closeable {
} else if (httpRequest.protocolVersion().majorVersion() == 2) { } else if (httpRequest.protocolVersion().majorVersion() == 2) {
logger.log(Level.FINE, () -> "waiting for HTTP/2 settings"); logger.log(Level.FINE, () -> "waiting for HTTP/2 settings");
settingsPromise.await(httpRequestContext.getTimeout(), TimeUnit.MILLISECONDS); settingsPromise.await(httpRequestContext.getTimeout(), TimeUnit.MILLISECONDS);
logger.log(Level.FINE, () -> "waiting for HTTP/2 responses = " + httpRequestContext.getStreamIdPromiseMap().size()); logger.log(Level.FINE, () -> "waiting for HTTP/2 responses = " +
httpRequestContext.getStreamIdPromiseMap().size());
int timeout = httpRequestContext.getTimeout(); int timeout = httpRequestContext.getTimeout();
for (Map.Entry<Integer, Map.Entry<ChannelFuture, ChannelPromise>> entry : for (Map.Entry<Integer, Map.Entry<ChannelFuture, ChannelPromise>> entry :
httpRequestContext.getStreamIdPromiseMap().entrySet()) { httpRequestContext.getStreamIdPromiseMap().entrySet()) {
@ -267,12 +308,13 @@ public final class HttpClient implements Closeable {
logger.log(Level.FINE, "waiting for channel, stream ID = " + entry.getKey()); logger.log(Level.FINE, "waiting for channel, stream ID = " + entry.getKey());
if (!channelFuture.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS)) { if (!channelFuture.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS)) {
IllegalStateException illegalStateException = IllegalStateException illegalStateException =
new IllegalStateException("time out while waiting to write for stream id " + entry.getKey()); new IllegalStateException("time out while waiting to write for stream id " +
entry.getKey());
if (exceptionListener != null) { if (exceptionListener != null) {
exceptionListener.onException(illegalStateException); exceptionListener.onException(illegalStateException);
httpRequestContext.fail(illegalStateException.getMessage()); httpRequestContext.fail(illegalStateException.getMessage());
final ChannelPool channelPool = final ChannelPool channelPool = channelFuture.channel()
channelFuture.channel().attr(HttpClientChannelContext.CHANNEL_POOL_ATTRIBUTE_KEY).get(); .attr(HttpClientChannelContext.CHANNEL_POOL_ATTRIBUTE_KEY).get();
channelPool.release(channelFuture.channel()); channelPool.release(channelFuture.channel());
} }
throw illegalStateException; throw illegalStateException;
@ -285,13 +327,14 @@ public final class HttpClient implements Closeable {
logger.log(Level.FINE, "waiting for promise of stream ID = " + entry.getKey()); logger.log(Level.FINE, "waiting for promise of stream ID = " + entry.getKey());
if (!promise.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS)) { if (!promise.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS)) {
IllegalStateException illegalStateException = IllegalStateException illegalStateException =
new IllegalStateException("time out while waiting for response on stream id " + entry.getKey()); new IllegalStateException("time out while waiting for response on stream id " +
entry.getKey());
if (exceptionListener != null) { if (exceptionListener != null) {
exceptionListener.onException(illegalStateException); exceptionListener.onException(illegalStateException);
httpRequestContext.fail(illegalStateException.getMessage()); httpRequestContext.fail(illegalStateException.getMessage());
if (channelFuture != null) { if (channelFuture != null) {
final ChannelPool channelPool = final ChannelPool channelPool = channelFuture.channel()
channelFuture.channel().attr(HttpClientChannelContext.CHANNEL_POOL_ATTRIBUTE_KEY).get(); .attr(HttpClientChannelContext.CHANNEL_POOL_ATTRIBUTE_KEY).get();
channelPool.release(channelFuture.channel()); channelPool.release(channelFuture.channel());
} }
} }
@ -303,8 +346,8 @@ public final class HttpClient implements Closeable {
exceptionListener.onException(runtimeException); exceptionListener.onException(runtimeException);
httpRequestContext.fail(runtimeException.getMessage()); httpRequestContext.fail(runtimeException.getMessage());
if (channelFuture != null) { if (channelFuture != null) {
final ChannelPool channelPool = final ChannelPool channelPool = channelFuture.channel()
channelFuture.channel().attr(HttpClientChannelContext.CHANNEL_POOL_ATTRIBUTE_KEY).get(); .attr(HttpClientChannelContext.CHANNEL_POOL_ATTRIBUTE_KEY).get();
channelPool.release(channelFuture.channel()); channelPool.release(channelFuture.channel());
} }
} }

View file

@ -30,9 +30,9 @@ import io.netty.handler.ssl.CipherSuiteFilter;
import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.SslProvider;
import org.xbib.netty.http.client.util.ClientAuthMode; import org.xbib.netty.http.client.util.ClientAuthMode;
import javax.net.ssl.TrustManagerFactory;
import java.io.InputStream; import java.io.InputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import javax.net.ssl.TrustManagerFactory;
/** /**
* *

View file

@ -24,13 +24,13 @@ import io.netty.handler.ssl.SslProvider;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import org.xbib.netty.http.client.listener.CookieListener; import org.xbib.netty.http.client.listener.CookieListener;
import org.xbib.netty.http.client.listener.ExceptionListener; import org.xbib.netty.http.client.listener.ExceptionListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpHeadersListener; import org.xbib.netty.http.client.listener.HttpHeadersListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpResponseListener; import org.xbib.netty.http.client.listener.HttpResponseListener;
import org.xbib.netty.http.client.util.ClientAuthMode; import org.xbib.netty.http.client.util.ClientAuthMode;
import java.io.InputStream;
import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManagerFactory;
import java.io.InputStream;
/** /**
*/ */

View file

@ -21,8 +21,8 @@ import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter; import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.xbib.netty.http.client.util.InetAddressKey;
import org.xbib.netty.http.client.util.ClientAuthMode; import org.xbib.netty.http.client.util.ClientAuthMode;
import org.xbib.netty.http.client.util.InetAddressKey;
import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManagerFactory;

View file

@ -50,15 +50,15 @@ import io.netty.handler.timeout.ReadTimeoutHandler;
import org.xbib.netty.http.client.listener.ExceptionListener; import org.xbib.netty.http.client.listener.ExceptionListener;
import org.xbib.netty.http.client.util.InetAddressKey; import org.xbib.netty.http.client.util.InetAddressKey;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SNIHostName; import javax.net.ssl.SNIHostName;
import javax.net.ssl.SNIServerName; import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLParameters;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Netty HTTP client channel initializer. * Netty HTTP client channel initializer.
@ -259,7 +259,7 @@ class HttpClientChannelInitializer extends ChannelInitializer<SocketChannel> {
} }
@Sharable @Sharable
private class UpgradeRequestHandler extends ChannelInboundHandlerAdapter { private static class UpgradeRequestHandler extends ChannelInboundHandlerAdapter {
/** /**
* Send an upgrade request if channel becomes active. * Send an upgrade request if channel becomes active.
@ -299,7 +299,7 @@ class HttpClientChannelInitializer extends ChannelInitializer<SocketChannel> {
* A Netty handler that logs user events and find expetced ones. * A Netty handler that logs user events and find expetced ones.
*/ */
@Sharable @Sharable
private class UserEventLogger extends ChannelInboundHandlerAdapter { private static class UserEventLogger extends ChannelInboundHandlerAdapter {
@Override @Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
@ -319,7 +319,7 @@ class HttpClientChannelInitializer extends ChannelInitializer<SocketChannel> {
* A Netty handler that logs the I/O traffic of a connection. * A Netty handler that logs the I/O traffic of a connection.
*/ */
@Sharable @Sharable
private final class TrafficLoggingHandler extends LoggingHandler { private static class TrafficLoggingHandler extends LoggingHandler {
TrafficLoggingHandler() { TrafficLoggingHandler() {
super("client", LogLevel.TRACE); super("client", LogLevel.TRACE);

View file

@ -2,6 +2,7 @@ package org.xbib.netty.http.client;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.DefaultHttpRequest;
@ -19,8 +20,8 @@ import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import org.xbib.netty.http.client.listener.CookieListener; import org.xbib.netty.http.client.listener.CookieListener;
import org.xbib.netty.http.client.listener.ExceptionListener; import org.xbib.netty.http.client.listener.ExceptionListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpHeadersListener; import org.xbib.netty.http.client.listener.HttpHeadersListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpResponseListener; import org.xbib.netty.http.client.listener.HttpResponseListener;
import java.io.IOException; import java.io.IOException;
@ -50,6 +51,8 @@ public class HttpClientRequestBuilder implements HttpRequestBuilder, HttpRequest
private static final Logger logger = Logger.getLogger(HttpClientRequestBuilder.class.getName()); private static final Logger logger = Logger.getLogger(HttpClientRequestBuilder.class.getName());
private static final HttpVersion HTTP_2_0 = HttpVersion.valueOf("HTTP/2.0");
private final HttpClient httpClient; private final HttpClient httpClient;
private final ByteBufAllocator byteBufAllocator; private final ByteBufAllocator byteBufAllocator;
@ -96,6 +99,11 @@ public class HttpClientRequestBuilder implements HttpRequestBuilder, HttpRequest
private HttpPushListener httpPushListener; private HttpPushListener httpPushListener;
HttpClientRequestBuilder(HttpMethod httpMethod,
ByteBufAllocator byteBufAllocator, int streamId) {
this(null, httpMethod, byteBufAllocator, streamId);
}
/** /**
* Construct HTTP client request builder. * Construct HTTP client request builder.
* *
@ -114,6 +122,28 @@ public class HttpClientRequestBuilder implements HttpRequestBuilder, HttpRequest
this.cookies = new HashSet<>(); this.cookies = new HashSet<>();
} }
public static HttpRequestBuilder builder(HttpMethod httpMethod) {
return new HttpClientRequestBuilder(httpMethod, UnpooledByteBufAllocator.DEFAULT, 3);
}
@Override
public HttpRequestBuilder setHttp1() {
this.httpVersion = HttpVersion.HTTP_1_1;
return this;
}
@Override
public HttpRequestBuilder setHttp2() {
this.httpVersion = HTTP_2_0;
return this;
}
@Override
public HttpRequestBuilder setVersion(String httpVersion) {
this.httpVersion = HttpVersion.valueOf(httpVersion);
return this;
}
@Override @Override
public HttpRequestBuilder setTimeout(int timeout) { public HttpRequestBuilder setTimeout(int timeout) {
this.timeout = timeout; this.timeout = timeout;
@ -171,12 +201,6 @@ public class HttpClientRequestBuilder implements HttpRequestBuilder, HttpRequest
return this; return this;
} }
@Override
public HttpRequestBuilder setVersion(String httpVersion) {
this.httpVersion = HttpVersion.valueOf(httpVersion);
return this;
}
@Override @Override
public HttpRequestBuilder acceptGzip(boolean gzip) { public HttpRequestBuilder acceptGzip(boolean gzip) {
this.gzip = gzip; this.gzip = gzip;
@ -314,6 +338,14 @@ public class HttpClientRequestBuilder implements HttpRequestBuilder, HttpRequest
@Override @Override
public HttpRequestContext execute() { public HttpRequestContext execute() {
return execute(httpClient);
}
@Override
public HttpRequestContext execute(HttpClient httpClient) {
if (httpClient == null) {
return null;
}
if (httpRequest == null) { if (httpRequest == null) {
httpRequest = build(); httpRequest = build();
} }
@ -378,8 +410,7 @@ public class HttpClientRequestBuilder implements HttpRequestBuilder, HttpRequest
} }
private void content(byte[] buf, AsciiString contentType) throws IOException { private void content(byte[] buf, AsciiString contentType) throws IOException {
ByteBuf buffer = byteBufAllocator.buffer(buf.length).writeBytes(buf); content(byteBufAllocator.buffer(buf.length).writeBytes(buf), contentType);
content(buffer, contentType);
} }
private void content(ByteBuf body, AsciiString contentType) throws IOException { private void content(ByteBuf body, AsciiString contentType) throws IOException {

View file

@ -21,8 +21,8 @@ import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.cookie.Cookie; import io.netty.handler.codec.http.cookie.Cookie;
import org.xbib.netty.http.client.listener.CookieListener; import org.xbib.netty.http.client.listener.CookieListener;
import org.xbib.netty.http.client.listener.ExceptionListener; import org.xbib.netty.http.client.listener.ExceptionListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpHeadersListener; import org.xbib.netty.http.client.listener.HttpHeadersListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpResponseListener; import org.xbib.netty.http.client.listener.HttpResponseListener;
import java.io.IOException; import java.io.IOException;
@ -33,7 +33,9 @@ import java.util.function.Function;
*/ */
public interface HttpRequestBuilder { public interface HttpRequestBuilder {
HttpRequestBuilder setTimeout(int timeout); HttpRequestBuilder setHttp1();
HttpRequestBuilder setHttp2();
HttpRequestBuilder setVersion(String httpVersion); HttpRequestBuilder setVersion(String httpVersion);
@ -81,9 +83,13 @@ public interface HttpRequestBuilder {
HttpRequestBuilder onPushReceived(HttpPushListener httpPushListener); HttpRequestBuilder onPushReceived(HttpPushListener httpPushListener);
HttpRequestBuilder setTimeout(int timeout);
HttpRequest build(); HttpRequest build();
HttpRequestContext execute(); HttpRequestContext execute();
HttpRequestContext execute(HttpClient httpClient);
<T> CompletableFuture<T> execute(Function<FullHttpResponse, T> supplier); <T> CompletableFuture<T> execute(Function<FullHttpResponse, T> supplier);
} }

View file

@ -24,8 +24,8 @@ import io.netty.handler.codec.http2.Http2Headers;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
import org.xbib.netty.http.client.listener.CookieListener; import org.xbib.netty.http.client.listener.CookieListener;
import org.xbib.netty.http.client.listener.ExceptionListener; import org.xbib.netty.http.client.listener.ExceptionListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpHeadersListener; import org.xbib.netty.http.client.listener.HttpHeadersListener;
import org.xbib.netty.http.client.listener.HttpPushListener;
import org.xbib.netty.http.client.listener.HttpResponseListener; import org.xbib.netty.http.client.listener.HttpResponseListener;
import org.xbib.netty.http.client.util.LimitedHashSet; import org.xbib.netty.http.client.util.LimitedHashSet;
@ -91,6 +91,8 @@ public final class HttpRequestContext implements HttpResponseListener, HttpReque
private Map<Integer, FullHttpResponse> httpResponses; private Map<Integer, FullHttpResponse> httpResponses;
private boolean hastimeout;
private Long stopTime; private Long stopTime;
HttpRequestContext(URI uri, HttpRequest httpRequest, AtomicInteger streamId, HttpRequestContext(URI uri, HttpRequest httpRequest, AtomicInteger streamId,
@ -233,11 +235,7 @@ public final class HttpRequestContext implements HttpResponseListener, HttpReque
return false; return false;
} }
boolean secure = "https".equals(uri.getScheme()); boolean secure = "https".equals(uri.getScheme());
boolean secureMatch = (secure && cookie.isSecure()) || (!secure && !cookie.isSecure()); return (secure && cookie.isSecure()) || (!secure && !cookie.isSecure());
if (!secureMatch) {
return false;
}
return true;
} }
public int getTimeout() { public int getTimeout() {
@ -293,11 +291,15 @@ public final class HttpRequestContext implements HttpResponseListener, HttpReque
} }
public HttpRequestContext waitFor(long value, TimeUnit timeUnit) throws InterruptedException { public HttpRequestContext waitFor(long value, TimeUnit timeUnit) throws InterruptedException {
latch.await(value, timeUnit); this.hastimeout = latch.await(value, timeUnit);
stopTime = System.currentTimeMillis(); stopTime = System.currentTimeMillis();
return this; return this;
} }
public boolean isTimeout() {
return hastimeout;
}
public void success(String reason) { public void success(String reason) {
logger.log(Level.FINE, () -> "success because of " + reason); logger.log(Level.FINE, () -> "success because of " + reason);
if (succeeded.compareAndSet(false, true)) { if (succeeded.compareAndSet(false, true)) {

View file

@ -21,8 +21,6 @@ import io.netty.handler.codec.http.HttpVersion;
*/ */
public interface HttpRequestDefaults { public interface HttpRequestDefaults {
int DEFAULT_TIMEOUT_MILLIS = 5000;
HttpVersion DEFAULT_HTTP_VERSION = HttpVersion.HTTP_1_1; HttpVersion DEFAULT_HTTP_VERSION = HttpVersion.HTTP_1_1;
String DEFAULT_USER_AGENT = HttpClientUserAgent.getUserAgent(); String DEFAULT_USER_AGENT = HttpClientUserAgent.getUserAgent();
@ -31,5 +29,7 @@ public interface HttpRequestDefaults {
boolean DEFAULT_FOLLOW_REDIRECT = true; boolean DEFAULT_FOLLOW_REDIRECT = true;
int DEFAULT_TIMEOUT_MILLIS = 5000;
int DEFAULT_MAX_REDIRECT = 10; int DEFAULT_MAX_REDIRECT = 10;
} }

View file

@ -19,7 +19,7 @@ import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http2.Http2Headers; import io.netty.handler.codec.http2.Http2Headers;
/** /**
* This listener can forward HTTP push * This listener can forward HTTP push.
* *
*/ */
@FunctionalInterface @FunctionalInterface

View file

@ -66,7 +66,7 @@ public class InetAddressKey {
host.equals(((InetAddressKey) object).host) && host.equals(((InetAddressKey) object).host) &&
port == ((InetAddressKey) object).port && port == ((InetAddressKey) object).port &&
version.equals(((InetAddressKey) object).version) && version.equals(((InetAddressKey) object).version) &&
secure == ((InetAddressKey) object).secure; secure.equals(((InetAddressKey) object).secure);
} }
@Override @Override

View file

@ -20,6 +20,7 @@ import java.util.LinkedHashSet;
/** /**
* A {@link java.util.Set} with limited size. If the size is exceeded, an exception is thrown. * A {@link java.util.Set} with limited size. If the size is exceeded, an exception is thrown.
* @param <E> the element type
*/ */
public final class LimitedHashSet<E> extends LinkedHashSet<E> { public final class LimitedHashSet<E> extends LinkedHashSet<E> {

View file

@ -206,11 +206,14 @@ public class NetworkUtils {
public static boolean matchesNetwork(NetworkClass given, NetworkClass expected) { public static boolean matchesNetwork(NetworkClass given, NetworkClass expected) {
switch (expected) { switch (expected) {
case ANY: case ANY:
return EnumSet.of(NetworkClass.LOOPBACK, NetworkClass.LOCAL, NetworkClass.PUBLIC, NetworkClass.ANY).contains(given); return EnumSet.of(NetworkClass.LOOPBACK, NetworkClass.LOCAL, NetworkClass.PUBLIC, NetworkClass.ANY)
.contains(given);
case PUBLIC: case PUBLIC:
return EnumSet.of(NetworkClass.LOOPBACK, NetworkClass.LOCAL, NetworkClass.PUBLIC).contains(given); return EnumSet.of(NetworkClass.LOOPBACK, NetworkClass.LOCAL, NetworkClass.PUBLIC)
.contains(given);
case LOCAL: case LOCAL:
return EnumSet.of(NetworkClass.LOOPBACK, NetworkClass.LOCAL).contains(given); return EnumSet.of(NetworkClass.LOOPBACK, NetworkClass.LOCAL)
.contains(given);
case LOOPBACK: case LOOPBACK:
return NetworkClass.LOOPBACK == given; return NetworkClass.LOOPBACK == given;
} }
@ -509,8 +512,12 @@ public class NetworkUtils {
.append(" prefixlen:").append(interfaceAddress.getNetworkPrefixLength()); .append(" prefixlen:").append(interfaceAddress.getNetworkPrefixLength());
} else { } else {
int netmask = 0xFFFFFFFF << (32 - interfaceAddress.getNetworkPrefixLength()); int netmask = 0xFFFFFFFF << (32 - interfaceAddress.getNetworkPrefixLength());
byte[] b = new byte[] { (byte)(netmask >>> 24), (byte)(netmask >>> 16 & 0xFF), byte[] b = new byte[] {
(byte)(netmask >>> 8 & 0xFF), (byte)(netmask & 0xFF) }; (byte) (netmask >>> 24),
(byte) (netmask >>> 16 & 0xFF),
(byte) (netmask >>> 8 & 0xFF),
(byte) (netmask & 0xFF)
};
sb.append("inet ").append(format(address)); sb.append("inet ").append(format(address));
try { try {
sb.append(" netmask:").append(format(InetAddress.getByAddress(b))); sb.append(" netmask:").append(format(InetAddress.getByAddress(b)));

View file

@ -34,39 +34,21 @@ public class AkamaiTest {
@Test @Test
public void testAkamaiHttps() throws Exception { public void testAkamaiHttps() throws Exception {
HttpClient httpClient = HttpClient.getInstance();
// here we see server PUSH_PROMISE as response to headers, a go-away frame is written. httpClient.prepareGet("https://http2.akamai.com/demo/h2_demo_frame.html")
.setHttp2()
/*
----------------INBOUND--------------------
[id: 0x27d23874, L:/192.168.178.23:52376 - R:http2.akamai.com/104.94.191.203:443]
PUSH_PROMISE: streamId=3, promisedStreamId=2, headers=DefaultHttp2Headers[:method: GET,
:path: /resources/push.css, :authority: http2.akamai.com, :scheme: https, host: http2.akamai.com,
user-agent: XbibHttpClient/unknown (Java/Azul Systems, Inc./1.8.0_112) (Netty/4.1.9.Final),
accept-encoding: gzip], padding=0
------------------------------------
2017-05-01 18:53:46.076 AM FEINSTEN [org.xbib.netty.http.client.HttpClientChannelInitializer]
io.netty.handler.codec.http2.Http2FrameLogger log
----------------OUTBOUND--------------------
[id: 0x27d23874, L:/192.168.178.23:52376 - R:http2.akamai.com/104.94.191.203:443]
GO_AWAY: lastStreamId=2, errorCode=1, length=75, bytes=556e7265636f676e697a656420485454...
*/
HttpClient httpClient = HttpClient.builder()
.build();
httpClient.prepareGet()
.setVersion("HTTP/2.0")
.setURL("https://http2.akamai.com/demo/h2_demo_frame.html")
.onException(e -> logger.log(Level.SEVERE, e.getMessage(), e)) .onException(e -> logger.log(Level.SEVERE, e.getMessage(), e))
.onResponse(fullHttpResponse -> { .onResponse(fullHttpResponse -> {
String response = fullHttpResponse.content().toString(StandardCharsets.UTF_8); String response = fullHttpResponse.content().toString(StandardCharsets.UTF_8);
logger.log(Level.INFO, "status = " + fullHttpResponse.status() + " response body = " + response); logger.log(Level.INFO, "status = " + fullHttpResponse.status()
+ " response body = " + response);
}) })
.onPushReceived((headers, fullHttpResponse) -> { .onPushReceived((requestHeaders, fullHttpResponse) -> {
logger.log(Level.INFO, "received push promise: request headers = " + headers String response = fullHttpResponse.content().toString(StandardCharsets.UTF_8);
logger.log(Level.INFO, "received push promise: request headers = " + requestHeaders
+ " status = " + fullHttpResponse.status() + " status = " + fullHttpResponse.status()
+ " response headers = " + fullHttpResponse.headers().entries() + " response headers = " + fullHttpResponse.headers().entries()
+ " response body = " + response
); );
}) })
.execute() .execute()