From 058f8a74a25277ddfd200ad56aa8279653ae7554 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Jul 2014 14:19:54 +0200 Subject: [PATCH 0001/1949] Port refactored Netty Channel pool on master --- .../netty/channel/DefaultChannelPool.java | 320 ++++++++++-------- 1 file changed, 183 insertions(+), 137 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index 54308e010a..a1c1c9f4ed 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -27,144 +27,207 @@ import io.netty.util.internal.chmv8.ConcurrentHashMapV8; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; /** * A simple implementation of {@link ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ public class DefaultChannelPool implements ChannelPool { - private final static Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); + private final ConcurrentHashMapV8> connectionsPool = new ConcurrentHashMapV8>(); - private final ConcurrentHashMapV8 channel2IdleChannel = new ConcurrentHashMapV8(); - private final ConcurrentHashMapV8 channel2CreationDate = new ConcurrentHashMapV8(); - private final AtomicBoolean closed = new AtomicBoolean(false); + private final ConcurrentHashMapV8 channel2Creation = new ConcurrentHashMapV8(); + private final AtomicInteger size = new AtomicInteger(); + private final AtomicBoolean isClosed = new AtomicBoolean(false); private final Timer nettyTimer; private final boolean sslConnectionPoolEnabled; private final int maxTotalConnections; + private final boolean maxTotalConnectionsDisabled; private final int maxConnectionPerHost; - private final int maxConnectionLifeTimeInMs; + private final boolean maxConnectionPerHostDisabled; + private final int maxConnectionTTL; + private final boolean maxConnectionTTLDisabled; private final long maxIdleTime; + private final boolean maxIdleTimeDisabled; + private final long cleanerPeriod; - public DefaultChannelPool(AsyncHttpClientConfig config, Timer nettyTimer) { + public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { this(config.getMaxTotalConnections(),// config.getMaxConnectionPerHost(),// config.getIdleConnectionInPoolTimeoutInMs(),// - config.isSslConnectionPoolEnabled(),// config.getMaxConnectionLifeTimeInMs(),// - nettyTimer); + config.isSslConnectionPoolEnabled(),// + hashedWheelTimer); } public DefaultChannelPool(// int maxTotalConnections,// int maxConnectionPerHost,// long maxIdleTime,// + int maxConnectionTTL,// boolean sslConnectionPoolEnabled,// - int maxConnectionLifeTimeInMs,// Timer nettyTimer) { this.maxTotalConnections = maxTotalConnections; + maxTotalConnectionsDisabled = maxTotalConnections <= 0; this.maxConnectionPerHost = maxConnectionPerHost; + maxConnectionPerHostDisabled = maxConnectionPerHost <= 0; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + this.maxConnectionTTL = maxConnectionTTL; + maxConnectionTTLDisabled = maxConnectionTTL <= 0; this.nettyTimer = nettyTimer; - if (maxIdleTime > 0L) { + maxIdleTimeDisabled = maxIdleTime <= 0; + + cleanerPeriod = Math.min(maxConnectionTTLDisabled ? Long.MAX_VALUE : maxConnectionTTL, maxIdleTimeDisabled ? Long.MAX_VALUE + : maxIdleTime); + + if (!maxConnectionTTLDisabled || !maxIdleTimeDisabled) scheduleNewIdleChannelDetector(new IdleChannelDetector()); - } } private void scheduleNewIdleChannelDetector(TimerTask task) { - nettyTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); + nettyTimer.newTimeout(task, cleanerPeriod, TimeUnit.MILLISECONDS); } - private static final class IdleChannel { + private static final class ChannelCreation { + final long creationTime; final String key; + + ChannelCreation(long creationTime, String key) { + this.creationTime = creationTime; + this.key = key; + } + } + + private static final class IdleChannel { final Channel channel; final long start; - IdleChannel(String key, Channel channel) { - if (key == null) - throw new NullPointerException("key"); + IdleChannel(Channel channel, long start) { if (channel == null) throw new NullPointerException("channel"); - this.key = key; this.channel = channel; - this.start = millisTime(); + this.start = start; } @Override + // only depends on channel public boolean equals(Object o) { return this == o || (o instanceof IdleChannel && channel.equals(IdleChannel.class.cast(o).channel)); } @Override public int hashCode() { - return channel != null ? channel.hashCode() : 0; + return channel.hashCode(); } } - private class IdleChannelDetector implements TimerTask { + private boolean isTTLExpired(Channel channel, long now) { + if (maxConnectionTTLDisabled) + return false; - @Override - public void run(Timeout timeout) throws Exception { - try { - if (closed.get()) - return; + ChannelCreation creation = channel2Creation.get(channel); + return creation == null || now - creation.creationTime >= maxConnectionTTL; + } - if (LOGGER.isDebugEnabled()) { - Set keys = connectionsPool.keySet(); + private boolean isRemotelyClosed(Channel channel) { + return !channel.isOpen(); + } - for (String s : keys) { - LOGGER.debug("Entry count for : {} : {}", s, connectionsPool.get(s).size()); - } - } + private final class IdleChannelDetector implements TimerTask { - List channelsInTimeout = new ArrayList(); - long currentTime = millisTime(); + private boolean isIdleTimeoutExpired(IdleChannel idleChannel, long now) { + return !maxIdleTimeDisabled && now - idleChannel.start >= maxIdleTime; + } - for (IdleChannel idleChannel : channel2IdleChannel.values()) { - long age = currentTime - idleChannel.start; - if (age > maxIdleTime) { + private List expiredChannels(ConcurrentLinkedQueue pool, long now) { + // lazy create + List idleTimeoutChannels = null; + for (IdleChannel idleChannel : pool) { + if (isTTLExpired(idleChannel.channel, now) || isIdleTimeoutExpired(idleChannel, now) + || isRemotelyClosed(idleChannel.channel)) { + LOGGER.debug("Adding Candidate expired Channel {}", idleChannel.channel); + if (idleTimeoutChannels == null) + idleTimeoutChannels = new ArrayList(); + idleTimeoutChannels.add(idleChannel); + } + } - LOGGER.debug("Adding Candidate Idle Channel {}", idleChannel.channel); + return idleTimeoutChannels != null ? idleTimeoutChannels : Collections. emptyList(); + } - // store in an unsynchronized list to minimize the impact on the ConcurrentHashMap. - channelsInTimeout.add(idleChannel); - } - } - long endConcurrentLoop = millisTime(); - - for (IdleChannel idleChannel : channelsInTimeout) { - Object attachment = Channels.getDefaultAttribute(idleChannel.channel); - if (attachment != null) { - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; - - if (!future.isDone() && !future.isCancelled()) { - LOGGER.debug("Future not in appropriate state %s\n", future); - continue; - } - } - } + private boolean isChannelCloseable(Channel channel) { + boolean closeable = true; + Object attachment = Channels.getDefaultAttribute(channel); + if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; + closeable = !future.isDone() || !future.isCancelled(); + if (!closeable) + LOGGER.error("Future not in appropriate state %s, not closing", future); + } + return true; + } - if (remove(idleChannel)) { + private final List closeChannels(List candidates) { + + // lazy create, only if we have a non-closeable channel + List closedChannels = null; + for (int i = 0; i < candidates.size(); i++) { + IdleChannel idleChannel = candidates.get(i); + if (!isChannelCloseable(idleChannel.channel)) + if (closedChannels == null) { + // first non closeable to be skipped, copy all previously skipped closeable channels + closedChannels = new ArrayList(candidates.size()); + for (int j = 0; j < i; j++) + closedChannels.add(candidates.get(j)); + } else { LOGGER.debug("Closing Idle Channel {}", idleChannel.channel); close(idleChannel.channel); + if (closedChannels != null) { + closedChannels.add(idleChannel); + } } - } + } + + return closedChannels != null ? closedChannels : candidates; + } + + public void run(Timeout timeout) throws Exception { - if (LOGGER.isTraceEnabled()) { - int openChannels = 0; - for (ConcurrentLinkedQueue hostChannels : connectionsPool.values()) { - openChannels += hostChannels.size(); + if (isClosed.get()) + return; + + try { + if (LOGGER.isDebugEnabled()) { + for (String key : connectionsPool.keySet()) { + LOGGER.debug("Entry count for : {} : {}", key, connectionsPool.get(key).size()); } - LOGGER.trace(String.format("%d channel open, %d idle channels closed (times: 1st-loop=%d, 2nd-loop=%d).\n", openChannels, - channelsInTimeout.size(), endConcurrentLoop - currentTime, millisTime() - endConcurrentLoop)); } + + long start = millisTime(); + int totalCount = size.get(); + int closedCount = 0; + + for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue + List candidateExpiredChannels = expiredChannels(pool, start); + List closedChannels = closeChannels(candidateExpiredChannels); + pool.removeAll(closedChannels); + int poolClosedCount = closedChannels.size(); + size.addAndGet(-poolClosedCount); + closedCount += poolClosedCount; + } + + long duration = millisTime() - start; + + LOGGER.debug("Closed {} connections out of {} in {}ms", closedCount, totalCount, duration); + } catch (Throwable t) { LOGGER.error("uncaught exception!", t); } @@ -173,137 +236,120 @@ public void run(Timeout timeout) throws Exception { } } + private boolean addIdleChannel(ConcurrentLinkedQueue idleConnectionForKey, String key, Channel channel, long now) { + + // FIXME computing CLQ.size is not efficient + if (maxConnectionPerHostDisabled || idleConnectionForKey.size() < maxConnectionPerHost) { + IdleChannel idleChannel = new IdleChannel(channel, now); + return idleConnectionForKey.add(idleChannel); + } + LOGGER.debug("Maximum number of requests per key reached {} for {}", maxConnectionPerHost, key); + return false; + } + /** * {@inheritDoc} */ - public boolean offer(String uri, Channel channel) { - if (closed.get() || (!sslConnectionPoolEnabled && uri.startsWith("https"))) + public boolean offer(String key, Channel channel) { + if (isClosed.get() || (!sslConnectionPoolEnabled && key.startsWith("https"))) return false; - Long createTime = channel2CreationDate.get(channel); - if (createTime == null) { - channel2CreationDate.putIfAbsent(channel, millisTime()); + long now = millisTime(); - } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < millisTime()) { - LOGGER.debug("Channel {} expired", channel); + if (isTTLExpired(channel, now)) return false; - } - - LOGGER.debug("Adding uri: {} for channel {}", uri, channel); - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(uri); - if (pooledConnectionForKey == null) { + ConcurrentLinkedQueue idleConnectionForKey = connectionsPool.get(key); + if (idleConnectionForKey == null) { ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); - pooledConnectionForKey = connectionsPool.putIfAbsent(uri, newPool); - if (pooledConnectionForKey == null) - pooledConnectionForKey = newPool; + idleConnectionForKey = connectionsPool.putIfAbsent(key, newPool); + if (idleConnectionForKey == null) + idleConnectionForKey = newPool; } - boolean added; - int size = pooledConnectionForKey.size(); - if (maxConnectionPerHost == -1 || size < maxConnectionPerHost) { - IdleChannel idleChannel = new IdleChannel(uri, channel); - synchronized (pooledConnectionForKey) { - added = pooledConnectionForKey.add(idleChannel); - - if (channel2IdleChannel.put(channel, idleChannel) != null) { - LOGGER.error("Channel {} already exists in the connections pool!", channel); - } - } - } else { - LOGGER.debug("Maximum number of requests per host reached {} for {}", maxConnectionPerHost, uri); - added = false; + boolean added = addIdleChannel(idleConnectionForKey, key, channel, now); + if (added) { + size.incrementAndGet(); + channel2Creation.putIfAbsent(channel, new ChannelCreation(now, key)); } + return added; } /** * {@inheritDoc} */ - public Channel poll(String uri) { - if (!sslConnectionPoolEnabled && uri.startsWith("https")) { + public Channel poll(String key) { + if (!sslConnectionPoolEnabled && key.startsWith("https")) return null; - } IdleChannel idleChannel = null; - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(uri); + ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(key); if (pooledConnectionForKey != null) { - boolean poolEmpty = false; - while (!poolEmpty && idleChannel == null) { - if (pooledConnectionForKey.size() > 0) { - synchronized (pooledConnectionForKey) { - idleChannel = pooledConnectionForKey.poll(); - if (idleChannel != null) { - channel2IdleChannel.remove(idleChannel.channel); - } - } - } + while (idleChannel == null) { + idleChannel = pooledConnectionForKey.poll(); - if (idleChannel == null) { - poolEmpty = true; - } else if (!idleChannel.channel.isActive() || !idleChannel.channel.isOpen()) { + if (idleChannel == null) + // pool is empty + break; + else if (isRemotelyClosed(idleChannel.channel)) { idleChannel = null; - LOGGER.trace("Channel not connected or not opened!"); + LOGGER.trace("Channel not connected or not opened, probably remotely closed!"); } } } - return idleChannel != null ? idleChannel.channel : null; - } - - private boolean remove(IdleChannel pooledChannel) { - if (pooledChannel == null || closed.get()) - return false; - - boolean isRemoved = false; - ConcurrentLinkedQueue pooledConnectionForHost = connectionsPool.get(pooledChannel.key); - if (pooledConnectionForHost != null) { - isRemoved = pooledConnectionForHost.remove(pooledChannel); - } - return isRemoved |= channel2IdleChannel.remove(pooledChannel.channel) != null; + if (idleChannel != null) { + size.decrementAndGet(); + return idleChannel.channel; + } else + return null; } /** * {@inheritDoc} */ public boolean removeAll(Channel channel) { - channel2CreationDate.remove(channel); - return !closed.get() && remove(channel2IdleChannel.get(channel)); + ChannelCreation creation = channel2Creation.remove(channel); + return !isClosed.get() && creation != null && connectionsPool.get(creation.key).remove(channel); } /** * {@inheritDoc} */ public boolean canCacheConnection() { - return !closed.get() && (maxTotalConnections == -1 || channel2IdleChannel.size() < maxTotalConnections); + // FIXME: doesn't honor per host limit + // FIXME: doesn't account for borrowed channels + return !isClosed.get() && (maxTotalConnectionsDisabled || size.get() < maxTotalConnections); } /** * {@inheritDoc} */ public void destroy() { - if (closed.getAndSet(true)) + if (isClosed.getAndSet(true)) return; - for (Channel channel : channel2IdleChannel.keySet()) { - close(channel); + for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + for (IdleChannel idleChannel : pool) + close(idleChannel.channel); } + connectionsPool.clear(); - channel2IdleChannel.clear(); - channel2CreationDate.clear(); + channel2Creation.clear(); + size.set(0); } private void close(Channel channel) { try { Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); - channel2CreationDate.remove(channel); + channel2Creation.remove(channel); channel.close(); } catch (Throwable t) { // noop } } - public final String toString() { - return String.format("NettyConnectionPool: {pool-size: %d}", channel2IdleChannel.size()); + public String toString() { + return String.format("NettyConnectionPool: {pool-size: %d}", size.get()); } } From cc92c540c5f704b686f0c6cecf5800686e868259 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Jul 2014 14:34:53 +0200 Subject: [PATCH 0002/1949] Refactor Netty provider config --- .../netty/NettyAsyncHttpProviderConfig.java | 213 ++++++++---------- .../providers/netty/channel/Channels.java | 35 +-- .../netty/NettyAsyncProviderBasicTest.java | 6 +- 3 files changed, 104 insertions(+), 150 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index ac75499993..b03b6ef31b 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -22,8 +22,6 @@ import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; @@ -38,67 +36,9 @@ /** * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. */ -public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig { +public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig, Object> { - private final static Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProviderConfig.class); - - /** - * Allow configuring the Netty's event loop. - */ - private EventLoopGroup eventLoopGroup; - - private AdditionalChannelInitializer httpAdditionalChannelInitializer; - private AdditionalChannelInitializer wsAdditionalChannelInitializer; - private AdditionalChannelInitializer httpsAdditionalChannelInitializer; - private AdditionalChannelInitializer wssAdditionalChannelInitializer; - - /** - * HttpClientCodec's maxInitialLineLength - */ - private int maxInitialLineLength = 4096; - - /** - * HttpClientCodec's maxHeaderSize - */ - private int maxHeaderSize = 8192; - - /** - * HttpClientCodec's maxChunkSize - */ - private int maxChunkSize = 8192; - - /** - * Use direct {@link java.nio.ByteBuffer} - */ - public final static String USE_DIRECT_BYTEBUFFER = "bufferFactory"; - - /** - * Allow nested request from any {@link org.asynchttpclient.AsyncHandler} - */ - public final static String DISABLE_NESTED_REQUEST = "disableNestedRequest"; - - /** - * See {@link java.net.Socket#setReuseAddress(boolean)} - */ - public final static String REUSE_ADDRESS = ChannelOption.SO_REUSEADDR.name(); - - private final Map properties = new HashMap(); - - private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); - - private ChannelPool channelPool; - - private boolean disableZeroCopy; - - private Timer nettyTimer; - - private long handshakeTimeoutInMillis; - - private SSLEngineFactory sslEngineFactory; - - public NettyAsyncHttpProviderConfig() { - properties.put(REUSE_ADDRESS, Boolean.FALSE); - } + private final Map, Object> properties = new HashMap, Object>(); /** * Add a property that will be used when the AsyncHttpClient initialize its @@ -108,16 +48,14 @@ public NettyAsyncHttpProviderConfig() { * @param value the value of the property * @return this instance of AsyncHttpProviderConfig */ - public NettyAsyncHttpProviderConfig addProperty(String name, Object value) { - - if (name.equals(REUSE_ADDRESS)// - && value == Boolean.TRUE// - && System.getProperty("os.name").toLowerCase().contains("win")) { - LOGGER.warn("Can't enable {} on Windows", REUSE_ADDRESS); - } else { - properties.put(name, value); - } + public NettyAsyncHttpProviderConfig addProperty(ChannelOption name, Object value) { + properties.put(name, value); + return this; + } + @SuppressWarnings("unchecked") + public NettyAsyncHttpProviderConfig addChannelOption(ChannelOption name, T value) { + properties.put((ChannelOption) name, value); return this; } @@ -127,7 +65,7 @@ public NettyAsyncHttpProviderConfig addProperty(String name, Object value) { * @param name * @return this instance of AsyncHttpProviderConfig */ - public Object getProperty(String name) { + public Object getProperty(ChannelOption name) { return properties.get(name); } @@ -137,7 +75,7 @@ public Object getProperty(String name) { * @param name * @return true if removed */ - public Object removeProperty(String name) { + public Object removeProperty(ChannelOption name) { return properties.remove(name); } @@ -146,40 +84,79 @@ public Object removeProperty(String name) { * * @return a the curent entry set. */ - public Set> propertiesSet() { + public Set, Object>> propertiesSet() { return properties.entrySet(); } - public EventLoopGroup getEventLoopGroup() { - return eventLoopGroup; - } + public static interface AdditionalChannelInitializer { - public void setEventLoopGroup(EventLoopGroup eventLoopGroup) { - this.eventLoopGroup = eventLoopGroup; + void initChannel(Channel ch) throws Exception; } - public int getMaxInitialLineLength() { - return maxInitialLineLength; - } + public static interface ResponseBodyPartFactory { - public void setMaxInitialLineLength(int maxInitialLineLength) { - this.maxInitialLineLength = maxInitialLineLength; + NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last); } - public int getMaxHeaderSize() { - return maxHeaderSize; + public static class EagerResponseBodyPartFactory implements ResponseBodyPartFactory { + + @Override + public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { + return new EagerResponseBodyPart(buf, last); + } } - public void setMaxHeaderSize(int maxHeaderSize) { - this.maxHeaderSize = maxHeaderSize; + public static class LazyResponseBodyPartFactory implements ResponseBodyPartFactory { + + @Override + public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { + return new LazyResponseBodyPart(buf, last); + } } - public int getMaxChunkSize() { - return maxChunkSize; + /** + * Allow configuring the Netty's event loop. + */ + private EventLoopGroup eventLoopGroup; + + private AdditionalChannelInitializer httpAdditionalChannelInitializer; + private AdditionalChannelInitializer wsAdditionalChannelInitializer; + private AdditionalChannelInitializer httpsAdditionalChannelInitializer; + private AdditionalChannelInitializer wssAdditionalChannelInitializer; + + /** + * HttpClientCodec's maxInitialLineLength + */ + private int maxInitialLineLength = 4096; + + /** + * HttpClientCodec's maxHeaderSize + */ + private int maxHeaderSize = 8192; + + /** + * HttpClientCodec's maxChunkSize + */ + private int maxChunkSize = 8192; + + private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); + + private ChannelPool channelPool; + + private boolean disableZeroCopy; + + private Timer nettyTimer; + + private long handshakeTimeoutInMillis; + + private SSLEngineFactory sslEngineFactory; + + public EventLoopGroup getEventLoopGroup() { + return eventLoopGroup; } - public void setMaxChunkSize(int maxChunkSize) { - this.maxChunkSize = maxChunkSize; + public void setEventLoopGroup(EventLoopGroup eventLoopGroup) { + this.eventLoopGroup = eventLoopGroup; } public AdditionalChannelInitializer getHttpAdditionalChannelInitializer() { @@ -214,6 +191,30 @@ public void setWssAdditionalChannelInitializer(AdditionalChannelInitializer wssA this.wssAdditionalChannelInitializer = wssAdditionalChannelInitializer; } + public int getMaxInitialLineLength() { + return maxInitialLineLength; + } + + public void setMaxInitialLineLength(int maxInitialLineLength) { + this.maxInitialLineLength = maxInitialLineLength; + } + + public int getMaxHeaderSize() { + return maxHeaderSize; + } + + public void setMaxHeaderSize(int maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; + } + + public int getMaxChunkSize() { + return maxChunkSize; + } + + public void setMaxChunkSize(int maxChunkSize) { + this.maxChunkSize = maxChunkSize; + } + public ResponseBodyPartFactory getBodyPartFactory() { return bodyPartFactory; } @@ -253,7 +254,7 @@ public long getHandshakeTimeoutInMillis() { public void setHandshakeTimeoutInMillis(long handshakeTimeoutInMillis) { this.handshakeTimeoutInMillis = handshakeTimeoutInMillis; } - + public SSLEngineFactory getSslEngineFactory() { return sslEngineFactory; } @@ -261,30 +262,4 @@ public SSLEngineFactory getSslEngineFactory() { public void setSslEngineFactory(SSLEngineFactory sslEngineFactory) { this.sslEngineFactory = sslEngineFactory; } - - public static interface AdditionalChannelInitializer { - - void initChannel(Channel ch) throws Exception; - } - - public static interface ResponseBodyPartFactory { - - NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last); - } - - public static class EagerResponseBodyPartFactory implements ResponseBodyPartFactory { - - @Override - public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new EagerResponseBodyPart(buf, last); - } - } - - public static class LazyResponseBodyPartFactory implements ResponseBodyPartFactory { - - @Override - public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new LazyResponseBodyPart(buf, last); - } - } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 34f9338bf7..1c1eb6ed04 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -63,10 +63,7 @@ import javax.net.ssl.SSLEngine; import java.io.IOException; -import java.lang.reflect.Field; import java.security.GeneralSecurityException; -import java.util.HashMap; -import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -162,31 +159,13 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig freeConnections = null; } - Map> optionMap = new HashMap>(); - for (Field field : ChannelOption.class.getDeclaredFields()) { - if (field.getType().isAssignableFrom(ChannelOption.class)) { - field.setAccessible(true); - try { - optionMap.put(field.getName(), (ChannelOption) field.get(null)); - } catch (IllegalAccessException ex) { - throw new Error(ex); - } - } - } - - if (nettyProviderConfig != null) { - for (Entry entry : nettyProviderConfig.propertiesSet()) { - ChannelOption key = optionMap.get(entry.getKey()); - if (key != null) { - Object value = entry.getValue(); - plainBootstrap.option(key, value); - webSocketBootstrap.option(key, value); - secureBootstrap.option(key, value); - secureWebSocketBootstrap.option(key, value); - } else { - throw new IllegalArgumentException("Unknown config property " + entry.getKey()); - } - } + for (Entry, Object> entry : nettyProviderConfig.propertiesSet()) { + ChannelOption key = entry.getKey(); + Object value = entry.getValue(); + plainBootstrap.option(key, value); + webSocketBootstrap.option(key, value); + secureBootstrap.option(key, value); + secureWebSocketBootstrap.option(key, value); } int timeOut = config.getConnectionTimeoutInMs() > 0 ? config.getConnectionTimeoutInMs() : Integer.MAX_VALUE; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java index eeb0008d6f..79c5112869 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java @@ -17,6 +17,8 @@ import org.asynchttpclient.AsyncHttpProviderConfig; import org.asynchttpclient.async.AsyncProvidersBasicTest; +import io.netty.channel.ChannelOption; + public class NettyAsyncProviderBasicTest extends AsyncProvidersBasicTest { @Override @@ -26,9 +28,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Override protected AsyncHttpProviderConfig getProviderConfig() { - final NettyAsyncHttpProviderConfig config = new NettyAsyncHttpProviderConfig(); - config.addProperty("TCP_NODELAY", true); - return config; + return new NettyAsyncHttpProviderConfig().addChannelOption(ChannelOption.TCP_NODELAY, Boolean.TRUE); } @Override From 226995db6e973ce7c4dd916f9b7bf97f94732e09 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Jul 2014 15:02:08 +0200 Subject: [PATCH 0003/1949] fix build --- .../extras/registry/AsyncHttpClientRegistryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java index ffd8afad0f..c4e94ed128 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java @@ -38,7 +38,7 @@ public void setUp() { @BeforeClass public void setUpBeforeTest() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, AbstractAsyncHttpClientFactoryTest.TEST_CLIENT_CLASS_NAME); } @AfterClass @@ -100,14 +100,14 @@ public void testCustomAsyncHttpClientRegistry() { @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testNonExistentAsyncHttpClientRegistry() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, "org.asynchttpclient.NonExistentAsyncRegistry"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, AbstractAsyncHttpClientFactoryTest.NON_EXISTENT_CLIENT_CLASS_NAME); AsyncHttpClientRegistryImpl.getInstance(); Assert.fail("Should never have reached here"); } @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testBadAsyncHttpClientRegistry() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClientRegistry"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, AbstractAsyncHttpClientFactoryTest.BAD_CLIENT_CLASS_NAME); AsyncHttpClientRegistryImpl.getInstance(); Assert.fail("Should never have reached here"); } From 442c1469709dff25016444bb2b74493b12d94fcf Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 11:49:17 -0700 Subject: [PATCH 0004/1949] [master] + rework the fix for the issue #525 https://github.com/AsyncHttpClient/async-http-client/pull/525 "Move the hostname verification to after the SSL handshake has completed" --- .../providers/grizzly/ConnectionManager.java | 68 ++++++------------- .../grizzly/GrizzlyAsyncHttpProvider.java | 7 +- .../grizzly/filters/SwitchingSSLFilter.java | 67 ++++++++++++++++-- 3 files changed, 84 insertions(+), 58 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index 3130f83f51..b83618df63 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Sonatype, Inc. All rights reserved. + * Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. @@ -21,7 +21,6 @@ import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.Base64; import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.Grizzly; @@ -30,19 +29,14 @@ import org.glassfish.grizzly.connectionpool.EndpointKey; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.impl.FutureImpl; -import org.glassfish.grizzly.ssl.SSLBaseFilter; -import org.glassfish.grizzly.ssl.SSLFilter; -import org.glassfish.grizzly.ssl.SSLUtils; import org.glassfish.grizzly.utils.Futures; import org.glassfish.grizzly.utils.IdleTimeoutFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; import java.io.IOException; -import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -52,6 +46,7 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +import org.asynchttpclient.providers.grizzly.filters.SwitchingSSLFilter; public class ConnectionManager { @@ -66,15 +61,13 @@ public class ConnectionManager { private final FilterChainBuilder secureBuilder; private final FilterChainBuilder nonSecureBuilder; private final boolean asyncConnect; - private final SSLFilter sslFilter; // ------------------------------------------------------------ Constructors ConnectionManager(final GrizzlyAsyncHttpProvider provider,// final ConnectionPool connectionPool,// final FilterChainBuilder secureBuilder,// - final FilterChainBuilder nonSecureBuilder,// - final SSLFilter sslFilter) { + final FilterChainBuilder nonSecureBuilder) { this.provider = provider; final AsyncHttpClientConfig config = provider.getClientConfig(); @@ -95,18 +88,26 @@ public class ConnectionManager { AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); asyncConnect = providerConfig instanceof GrizzlyAsyncHttpProviderConfig ? GrizzlyAsyncHttpProviderConfig.class.cast(providerConfig) .isAsyncConnectMode() : false; - this.sslFilter = sslFilter; } // ---------------------------------------------------------- Public Methods public void doTrackedConnection(final Request request,// final GrizzlyResponseFuture requestFuture,// - final CompletionHandler connectHandler) throws IOException { + CompletionHandler completionHandler) throws IOException { final EndpointKey key = getEndPointKey(request, requestFuture.getProxyServer()); - CompletionHandler handler = wrapHandler(request, getVerifier(), connectHandler, sslFilter); + + final HostnameVerifier verifier = getVerifier(); + final UriComponents uri = request.getURI(); + + if (Utils.isSecure(uri) && verifier != null) { + completionHandler = + SwitchingSSLFilter.wrapWithHostnameVerifierHandler( + completionHandler, verifier, uri.getHost()); + } + if (asyncConnect) { - connectionPool.take(key, handler); + connectionPool.take(key, completionHandler); } else { IOException ioe = null; GrizzlyFuture future = connectionPool.take(key); @@ -114,18 +115,18 @@ public void doTrackedConnection(final Request request,// // No explicit timeout when calling get() here as the Grizzly // endpoint pool will time it out based on the connect timeout // setting. - handler.completed(future.get()); + completionHandler.completed(future.get()); } catch (CancellationException e) { - handler.cancelled(); + completionHandler.cancelled(); } catch (ExecutionException ee) { final Throwable cause = ee.getCause(); if (cause instanceof ConnectionPool.MaxCapacityException) { ioe = (IOException) cause; } else { - handler.failed(ee.getCause()); + completionHandler.failed(ee.getCause()); } } catch (Exception ie) { - handler.failed(ie); + completionHandler.failed(ie); } if (ioe != null) { throw ioe; @@ -144,37 +145,6 @@ public Connection obtainConnection(final Request request, final GrizzlyResponseF // --------------------------------------------------Package Private Methods - static CompletionHandler wrapHandler(final Request request, final HostnameVerifier verifier, - final CompletionHandler delegate, final SSLFilter sslFilter) { - final UriComponents uri = request.getURI(); - if (Utils.isSecure(uri) && verifier != null) { - SSLBaseFilter.HandshakeListener handshakeListener = new SSLBaseFilter.HandshakeListener() { - @Override - public void onStart(Connection connection) { - // do nothing - LOGGER.debug("SSL Handshake onStart: "); - } - - @Override - public void onComplete(Connection connection) { - sslFilter.removeHandshakeListener(this); - - final String host = uri.getHost(); - final SSLSession session = SSLUtils.getSSLEngine(connection).getSession(); - LOGGER.debug("SSL Handshake onComplete: session = {}, id = {}, isValid = {}, host = {}", session.toString(), Base64.encode(session.getId()), session.isValid(), host); - - if (!verifier.verify(host, session)) { - connection.close(); // XXX what's the correct way to kill a connection? - IOException e = new ConnectException("Host name verification failed for host " + host); - delegate.failed(e); - } - } - }; - sslFilter.addHandshakeListener(handshakeListener); - } - return delegate; - } - static void markConnectionAsDoNotCache(final Connection c) { DO_NOT_CACHE.set(c, Boolean.TRUE); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 2e1d77ee37..9d3151957a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -259,8 +259,9 @@ public void onTimeout(Connection connection) { } } final SSLEngineConfigurator configurator = new SSLEngineConfigurator(context, true, false, false); - final SwitchingSSLFilter filter = new SwitchingSSLFilter(configurator); - secure.add(filter); + final SwitchingSSLFilter sslFilter = new SwitchingSSLFilter(configurator); + secure.add(sslFilter); + GrizzlyAsyncHttpProviderConfig providerConfig = (GrizzlyAsyncHttpProviderConfig) clientConfig.getAsyncHttpProviderConfig(); boolean npnEnabled = NextProtoNegSupport.isEnabled(); @@ -335,7 +336,7 @@ public void onTimeout(Connection connection) { } else { pool = null; } - connectionManager = new ConnectionManager(this, pool, secure, nonSecure, filter); + connectionManager = new ConnectionManager(this, pool, secure, nonSecure); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java index 3085c950e8..c8075ca630 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Sonatype, Inc. All rights reserved. + * Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. @@ -13,7 +13,15 @@ package org.asynchttpclient.providers.grizzly.filters; +import java.io.IOException; +import java.net.ConnectException; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLSession; import org.asynchttpclient.providers.grizzly.filters.events.SSLSwitchingEvent; +import org.asynchttpclient.util.Base64; +import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.EmptyCompletionHandler; import org.glassfish.grizzly.Grizzly; @@ -25,11 +33,9 @@ import org.glassfish.grizzly.filterchain.NextAction; import org.glassfish.grizzly.ssl.SSLEngineConfigurator; import org.glassfish.grizzly.ssl.SSLFilter; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLHandshakeException; - -import java.io.IOException; +import org.glassfish.grizzly.ssl.SSLUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * SSL Filter that may be present within the FilterChain and may be @@ -45,6 +51,8 @@ public final class SwitchingSSLFilter extends SSLFilter { private static final Attribute HANDSHAKE_ERROR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(SwitchingSSLFilter.class .getName() + "-HANDSHAKE-ERROR"); + private final static Logger LOGGER = LoggerFactory.getLogger(SwitchingSSLFilter.class); + // ------------------------------------------------------------ Constructors public SwitchingSSLFilter(final SSLEngineConfigurator clientConfig) { @@ -161,4 +169,51 @@ private static void setError(final Connection c, Throwable t) { private static void enableRead(final Connection c) throws IOException { c.enableIOEvent(IOEvent.READ); } + + // ================= HostnameVerifier section ======================== + + public static CompletionHandler wrapWithHostnameVerifierHandler( + final CompletionHandler delegateCompletionHandler, + final HostnameVerifier verifier, final String host) { + + return new CompletionHandler() { + + public void cancelled() { + if (delegateCompletionHandler != null) { + delegateCompletionHandler.cancelled(); + } + } + + public void failed(final Throwable throwable) { + if (delegateCompletionHandler != null) { + delegateCompletionHandler.failed(throwable); + } + } + + public void completed(final Connection connection) { + final SSLSession session = SSLUtils.getSSLEngine(connection).getSession(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("SSL Handshake onComplete: session = {}, id = {}, isValid = {}, host = {}", + session.toString(), Base64.encode(session.getId()), session.isValid(), host); + } + + if (!verifier.verify(host, session)) { + connection.terminateSilently(); + + if (delegateCompletionHandler != null) { + IOException e = new ConnectException("Host name verification failed for host " + host); + delegateCompletionHandler.failed(e); + } + } else if (delegateCompletionHandler != null) { + delegateCompletionHandler.completed(connection); + } + } + + public void updated(final Connection connection) { + if (delegateCompletionHandler != null) { + delegateCompletionHandler.updated(connection); + } + } + }; + } } From f171c9a13a150824f0b4d898dcbc03ddd2af6e4a Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 12:08:15 -0700 Subject: [PATCH 0005/1949] [master] + rework (#2) the fix for the issue #525 https://github.com/AsyncHttpClient/async-http-client/pull/525 "Move the hostname verification to after the SSL handshake has completed" --- .../grizzly/filters/SwitchingSSLFilter.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java index c8075ca630..b0449e82d2 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java @@ -191,20 +191,26 @@ public void failed(final Throwable throwable) { } public void completed(final Connection connection) { - final SSLSession session = SSLUtils.getSSLEngine(connection).getSession(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("SSL Handshake onComplete: session = {}, id = {}, isValid = {}, host = {}", - session.toString(), Base64.encode(session.getId()), session.isValid(), host); - } + if (getHandshakeError(connection) == null) { + final SSLSession session = SSLUtils.getSSLEngine(connection).getSession(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("SSL Handshake onComplete: session = {}, id = {}, isValid = {}, host = {}", + session.toString(), Base64.encode(session.getId()), session.isValid(), host); + } + + if (!verifier.verify(host, session)) { + connection.terminateSilently(); - if (!verifier.verify(host, session)) { - connection.terminateSilently(); - - if (delegateCompletionHandler != null) { - IOException e = new ConnectException("Host name verification failed for host " + host); - delegateCompletionHandler.failed(e); + if (delegateCompletionHandler != null) { + IOException e = new ConnectException("Host name verification failed for host " + host); + delegateCompletionHandler.failed(e); + } + + return; } - } else if (delegateCompletionHandler != null) { + } + + if (delegateCompletionHandler != null) { delegateCompletionHandler.completed(connection); } } From 4393106266c50f98d7b88b1092d4512d4dec60f1 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 23:40:43 -0700 Subject: [PATCH 0006/1949] [master] fix issue #608 https://github.com/AsyncHttpClient/async-http-client/issues/608 "Grizzly provider can't deal with wss + proxy" --- providers/grizzly/pom.xml | 2 +- .../filters/AsyncHttpClientFilter.java | 11 +++++--- .../grizzly/filters/ProxyFilter.java | 25 ++++++++++++------- .../websocket/GrizzlyProxyTunnellingTest.java | 5 ---- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/providers/grizzly/pom.xml b/providers/grizzly/pom.xml index b55f00865e..269aea00ba 100644 --- a/providers/grizzly/pom.xml +++ b/providers/grizzly/pom.xml @@ -14,7 +14,7 @@ - 2.3.14 + 2.3.16 1.1 diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index f1be2da91d..21dc88c516 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -469,10 +469,13 @@ private static boolean isWSRequest(final UriComponents requestUri) { private static void convertToUpgradeRequest(final HttpTxContext ctx) { - UriComponents originalUri = ctx.getRequestUri(); - String newScheme = originalUri.getScheme().equalsIgnoreCase("https") ? "wss" : "ws"; - ctx.setWsRequestURI(originalUri); - ctx.setRequestUri(originalUri.withNewScheme(newScheme)); + final UriComponents requestUri = ctx.getRequestUri(); + + ctx.setWsRequestURI(requestUri); + ctx.setRequestUri(requestUri.withNewScheme( + "ws".equals(requestUri.getScheme()) + ? "http" + : "https")); } private void addGeneralHeaders(final Request request, final HttpRequestPacket requestPacket) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java index f233d40e1f..ded8031daf 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Sonatype, Inc. All rights reserved. + * Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. @@ -29,6 +29,7 @@ import org.glassfish.grizzly.http.util.Header; import java.io.IOException; +import org.glassfish.grizzly.http.HttpPacket; /** * This Filter will be placed in the FilterChain when a request is being @@ -56,15 +57,21 @@ public ProxyFilter(final ProxyServer proxyServer, final AsyncHttpClientConfig co @Override public NextAction handleWrite(FilterChainContext ctx) throws IOException { - org.glassfish.grizzly.http.HttpContent content = ctx.getMessage(); - HttpRequestPacket request = (HttpRequestPacket) content.getHttpHeader(); - HttpTxContext context = HttpTxContext.get(ctx); - assert (context != null); - Request req = context.getRequest(); - if (!secure) { - request.setRequestURI(req.getURI().toUrl()); + final Object msg = ctx.getMessage(); + if (HttpPacket.isHttp(msg)) { + HttpPacket httpPacket = (HttpPacket) msg; + final HttpRequestPacket request = (HttpRequestPacket) httpPacket.getHttpHeader(); + if (!request.isCommitted()) { + HttpTxContext context = HttpTxContext.get(ctx); + assert (context != null); + Request req = context.getRequest(); + if (!secure) { + request.setRequestURI(req.getURI().toUrl()); + } + addProxyHeaders(getRealm(req), request); + } } - addProxyHeaders(getRealm(req), request); + return ctx.getInvokeAction(); } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java index 6d69758e71..0d864e1fc2 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java @@ -25,9 +25,4 @@ public class GrizzlyProxyTunnellingTest extends ProxyTunnellingTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - - @Test(timeOut = 60000, enabled = false) - public void echoText() throws Exception { - // FIXME - } } From ee3f56dad3c15d40cc8df7a0c96b0daab45073d6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 22:55:44 +0200 Subject: [PATCH 0007/1949] Refactor Netty channel pool, port #624 on master, close #201, close #623 --- .../netty/NettyAsyncHttpProvider.java | 13 +- .../netty/NettyAsyncHttpProviderConfig.java | 2 +- .../netty/channel/ChannelManager.java | 168 ++++++++++++++++++ .../providers/netty/channel/Channels.java | 156 ++++++---------- .../netty/channel/{ => pool}/ChannelPool.java | 30 ++-- .../{ => pool}/DefaultChannelPool.java | 136 ++++++-------- .../NoopChannelPool.java} | 12 +- .../providers/netty/handler/HttpProtocol.java | 20 +-- .../providers/netty/handler/Processor.java | 2 +- .../providers/netty/handler/Protocol.java | 12 +- .../netty/request/NettyConnectListener.java | 48 ++++- .../netty/request/NettyRequestSender.java | 93 +++++----- .../netty/NettyConnectionPoolTest.java | 18 +- 13 files changed, 401 insertions(+), 309 deletions(-) create mode 100644 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/{ => pool}/ChannelPool.java (55%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/{ => pool}/DefaultChannelPool.java (68%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/{NonChannelPool.java => pool/NoopChannelPool.java} (73%) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java index 01d71e1baf..5fb2104212 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java @@ -32,7 +32,6 @@ public class NettyAsyncHttpProvider implements AsyncHttpProvider { private static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); - private final AsyncHttpClientConfig config; private final NettyAsyncHttpProviderConfig nettyConfig; private final AtomicBoolean closed = new AtomicBoolean(false); private final Channels channels; @@ -40,9 +39,8 @@ public class NettyAsyncHttpProvider implements AsyncHttpProvider { public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { - this.config = config; nettyConfig = config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig ? // - NettyAsyncHttpProviderConfig.class.cast(config.getAsyncHttpProviderConfig()) + (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig() : new NettyAsyncHttpProviderConfig(); channels = new Channels(config, nettyConfig); @@ -50,15 +48,6 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { channels.configureProcessor(requestSender, closed); } - @Override - public String toString() { - int availablePermits = channels.freeConnections != null ? channels.freeConnections.availablePermits() : 0; - return String.format("NettyAsyncHttpProvider4:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s", - config.getMaxTotalConnections() - availablePermits,// - channels.openChannels.toString(),// - channels.channelPool.toString()); - } - @Override public void close() { if (closed.compareAndSet(false, true)) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index b03b6ef31b..554e1643c1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -18,7 +18,7 @@ import org.asynchttpclient.AsyncHttpProviderConfig; import org.asynchttpclient.SSLEngineFactory; -import org.asynchttpclient.providers.netty.channel.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java new file mode 100644 index 0000000000..637a619c6f --- /dev/null +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package org.asynchttpclient.providers.netty.channel; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.Channel; +import io.netty.channel.group.ChannelGroup; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; + +public class ChannelManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); + + private final ChannelPool channelPool; + private final boolean maxTotalConnectionsEnabled; + private final Semaphore freeChannels; + private final ChannelGroup openChannels; + private final int maxConnectionsPerHost; + private final boolean maxConnectionsPerHostEnabled; + private final ConcurrentHashMap freeChannelsPerHost; + private final ConcurrentHashMap channel2KeyPool; + + public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { + this.channelPool = channelPool; + + maxTotalConnectionsEnabled = config.getMaxTotalConnections() > 0; + + if (maxTotalConnectionsEnabled) { + openChannels = new CleanupChannelGroup("asyncHttpClient") { + @Override + public boolean remove(Object o) { + boolean removed = super.remove(o); + if (removed) { + freeChannels.release(); + if (maxConnectionsPerHostEnabled) { + String poolKey = channel2KeyPool.remove(Channel.class.cast(o)); + if (poolKey != null) { + Semaphore freeChannelsForHost = freeChannelsPerHost.get(poolKey); + if (freeChannelsForHost != null) + freeChannelsForHost.release(); + } + } + } + return removed; + } + }; + freeChannels = new Semaphore(config.getMaxTotalConnections()); + } else { + openChannels = new CleanupChannelGroup("asyncHttpClient"); + freeChannels = null; + } + + maxConnectionsPerHost = config.getMaxConnectionPerHost(); + maxConnectionsPerHostEnabled = config.getMaxConnectionPerHost() > 0; + + if (maxConnectionsPerHostEnabled) { + freeChannelsPerHost = new ConcurrentHashMap(); + channel2KeyPool = new ConcurrentHashMap(); + } else { + freeChannelsPerHost = null; + channel2KeyPool = null; + } + } + + public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { + if (keepAlive && channel.isActive()) { + LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); + channelPool.offer(channel, poolKey); + if (maxConnectionsPerHostEnabled) + channel2KeyPool.putIfAbsent(channel, poolKey); + Channels.setDiscard(channel); + } else { + // not offered + closeChannel(channel); + } + } + + public Channel poll(String uri) { + return channelPool.poll(uri); + } + + public boolean removeAll(Channel connection) { + return channelPool.removeAll(connection); + } + + private boolean tryAcquireGlobal() { + return !maxTotalConnectionsEnabled || freeChannels.tryAcquire(); + } + + private Semaphore getFreeConnectionsForHost(String poolKey) { + Semaphore freeConnections = freeChannelsPerHost.get(poolKey); + if (freeConnections == null) { + // lazy create the semaphore + Semaphore newFreeConnections = new Semaphore(maxConnectionsPerHost); + freeConnections = freeChannelsPerHost.putIfAbsent(poolKey, newFreeConnections); + if (freeConnections == null) + freeConnections = newFreeConnections; + } + return freeConnections; + } + + private boolean tryAcquirePerHost(String poolKey) { + return !maxConnectionsPerHostEnabled || getFreeConnectionsForHost(poolKey).tryAcquire(); + } + + public boolean preemptChannel(String poolKey) { + return channelPool.isOpen() && tryAcquireGlobal() && tryAcquirePerHost(poolKey); + } + + public void destroy() { + channelPool.destroy(); + openChannels.close(); + + for (Channel channel : openChannels) { + Object attachment = Channels.getDefaultAttribute(channel); + if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; + future.cancelTimeouts(); + } + } + } + + public void closeChannel(Channel channel) { + removeAll(channel); + Channels.setDiscard(channel); + + // The channel may have already been removed if a timeout occurred, and this method may be called just after. + if (channel != null) { + LOGGER.debug("Closing Channel {} ", channel); + try { + channel.close(); + } catch (Throwable t) { + LOGGER.debug("Error closing a connection", t); + } + openChannels.remove(channel); + } + } + + public void abortChannelPreemption(String poolKey) { + if (maxTotalConnectionsEnabled) + freeChannels.release(); + if (maxConnectionsPerHostEnabled) + getFreeConnectionsForHost(poolKey).release(); + } + + public void registerOpenChannel(Channel channel) { + openChannels.add(channel); + } +} \ No newline at end of file diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 1c1eb6ed04..3dfc57f9be 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -25,13 +25,14 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ConnectionPoolKeyStrategy; import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.DiscardEvent; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.DefaultChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.NoopChannelPool; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.handler.Processor; import org.asynchttpclient.providers.netty.request.NettyRequestSender; -import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.SslUtils; import org.slf4j.Logger; @@ -43,7 +44,6 @@ import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; -import io.netty.channel.group.ChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.HttpClientCodec; @@ -65,7 +65,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Map.Entry; -import java.util.concurrent.Semaphore; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -95,20 +95,7 @@ public class Channels { private final Bootstrap webSocketBootstrap; private final Bootstrap secureWebSocketBootstrap; - public final ChannelPool channelPool; - public final Semaphore freeConnections; - public final boolean trackConnections; - public final ChannelGroup openChannels = new CleanupChannelGroup("asyncHttpClient") { - @Override - public boolean remove(Object o) { - boolean removed = super.remove(o); - if (removed && trackConnections) { - freeConnections.release(); - } - return removed; - } - }; - + public final ChannelManager channelManager; private final boolean allowStopNettyTimer; private final Timer nettyTimer; private final long handshakeTimeoutInMillis; @@ -147,17 +134,10 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig if (config.isAllowPoolingConnection()) { cp = new DefaultChannelPool(config, nettyTimer); } else { - cp = new NonChannelPool(); + cp = new NoopChannelPool(); } } - this.channelPool = cp; - if (config.getMaxTotalConnections() != -1) { - trackConnections = true; - freeConnections = new Semaphore(config.getMaxTotalConnections()); - } else { - trackConnections = false; - freeConnections = null; - } + this.channelManager = new ChannelManager(config, cp); for (Entry, Object> entry : nettyProviderConfig.propertiesSet()) { ChannelOption key = entry.getKey(); @@ -182,11 +162,11 @@ private Timer newNettyTimer() { } public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException { - + SSLEngine sslEngine = null; if (nettyProviderConfig.getSslEngineFactory() != null) { sslEngine = nettyProviderConfig.getSslEngineFactory().newSSLEngine(); - + } else { SSLContext sslContext = config.getSSLContext(); if (sslContext == null) @@ -195,11 +175,11 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep sslEngine = sslContext.createSSLEngine(peerHost, peerPort); sslEngine.setUseClientMode(true); } - + SslHandler sslHandler = new SslHandler(sslEngine); if (handshakeTimeoutInMillis > 0) sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); - + return sslHandler; } @@ -244,8 +224,7 @@ protected void initChannel(Channel ch) throws Exception { protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline()// - .addLast(SSL_HANDLER, new SslInitializer(Channels.this)) - .addLast(HTTP_HANDLER, newHttpClientCodec()); + .addLast(SSL_HANDLER, new SslInitializer(Channels.this)).addLast(HTTP_HANDLER, newHttpClientCodec()); if (config.isCompressionEnabled()) { pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); @@ -281,15 +260,7 @@ public Bootstrap getBootstrap(UriComponents uri, boolean useSSl, boolean useProx } public void close() { - channelPool.destroy(); - for (Channel channel : openChannels) { - Object attribute = getDefaultAttribute(channel); - if (attribute instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attribute; - future.cancelTimeouts(); - } - } - openChannels.close(); + channelManager.destroy(); if (allowReleaseEventLoopGroup) eventLoopGroup.shutdownGracefully(); @@ -354,7 +325,7 @@ public static void upgradePipelineForWebSockets(Channel channel) { } public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { - final Channel channel = channelPool.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); + final Channel channel = channelManager.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); if (channel != null) { LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); @@ -368,82 +339,48 @@ public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, return channel; } - public boolean acquireConnection(AsyncHandler asyncHandler) throws IOException { + public boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) throws IOException { - if (!channelPool.canCacheConnection()) { - IOException ex = new IOException("Too many connections " + config.getMaxTotalConnections()); + boolean channelPreempted = false; + if (channelManager.preemptChannel(poolKey)) { + channelPreempted = true; + } else { + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); try { asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("!connectionsPool.canCacheConnection()", t); + } catch (Exception e) { + LOGGER.warn("asyncHandler.onThrowable crashed", e); } throw ex; } - - if (trackConnections) { - if (freeConnections.tryAcquire()) { - return true; - } else { - IOException ex = new IOException("Too many connections " + config.getMaxTotalConnections()); - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("!connectionsPool.canCacheConnection()", t); - } - throw ex; - } - } - - return false; - } - - public void registerChannel(Channel channel) { - openChannels.add(channel); - } - - public boolean offerToPool(String key, Channel channel) { - return channelPool.offer(key, channel); + return channelPreempted; } - public void releaseFreeConnections() { - freeConnections.release(); + public void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { + channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); } - public void removeFromPool(Channel channel) { - channelPool.removeAll(channel); + public void abortChannelPreemption(String poolKey) { + channelManager.abortChannelPreemption(poolKey); } public void closeChannel(Channel channel) { - removeFromPool(channel); - finishChannel(channel); + channelManager.closeChannel(channel); } - public void finishChannel(Channel channel) { - setDefaultAttribute(channel, DiscardEvent.INSTANCE); - - // The channel may have already been removed if a timeout occurred, and - // this method may be called just after. - if (channel == null) - return; - - LOGGER.debug("Closing Channel {} ", channel); - try { - channel.close(); - } catch (Throwable t) { - LOGGER.debug("Error closing a connection", t); - } + public final Callable> newDrainCallable(final NettyResponseFuture future, final Channel channel, + final boolean keepAlive, final String poolKey) { - openChannels.remove(channel); + return new Callable>() { + public NettyResponseFuture call() throws Exception { + channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); + return null; + } + }; } public void drainChannel(final Channel channel, final NettyResponseFuture future) { - setDefaultAttribute(channel, new Callback(future) { - public void call() throws Exception { - if (!(future.isKeepAlive() && channel.isActive() && channelPool.offer(getPoolKey(future), channel))) { - finishChannel(channel); - } - } - }); + setDefaultAttribute(channel, newDrainCallable(future, channel, future.isKeepAlive(), getPoolKey(future))); } public String getPoolKey(NettyResponseFuture future) { @@ -451,17 +388,16 @@ public String getPoolKey(NettyResponseFuture future) { } public void removeAll(Channel channel) { - channelPool.removeAll(channel); + channelManager.removeAll(channel); } public void abort(NettyResponseFuture future, Throwable t) { + Channel channel = future.channel(); - if (channel != null && openChannels.contains(channel)) { - closeChannel(channel); - openChannels.remove(channel); - } + if (channel != null) + channelManager.closeChannel(channel); - if (!future.isCancelled() && !future.isDone()) { + if (!future.isDone()) { LOGGER.debug("Aborting Future {}\n", future); LOGGER.debug(t.getMessage(), t); } @@ -485,4 +421,12 @@ public static Object getDefaultAttribute(Channel channel) { public static void setDefaultAttribute(Channel channel, Object o) { channel.attr(DEFAULT_ATTRIBUTE).set(o); } + + public static void setDiscard(Channel channel) { + setDefaultAttribute(channel, DiscardEvent.INSTANCE); + } + + public void registerOpenChannel(Channel channel) { + channelManager.registerOpenChannel(channel); + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java similarity index 55% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java index 39f5c7a5af..4f1d96ba16 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java @@ -14,47 +14,47 @@ * under the License. * */ -package org.asynchttpclient.providers.netty.channel; +package org.asynchttpclient.providers.netty.channel.pool; import io.netty.channel.Channel; public interface ChannelPool { /** - * Add a connection to the pool + * Add a channel to the pool * - * @param uri a uri used to retrieve the cached connection - * @param connection an I/O connection + * @param poolKey a key used to retrieve the cached channel + * @param channel an I/O channel * @return true if added. */ - boolean offer(String uri, Channel connection); + boolean offer(Channel channel, String poolKey); /** - * Remove the connection associated with the uri. + * Remove the channel associated with the uri. * * @param uri the uri used when invoking addConnection - * @return the connection associated with the uri + * @return the channel associated with the uri */ Channel poll(String uri); /** - * Remove all connections from the cache. A connection might have been associated with several uri. + * Remove all channels from the cache. A channel might have been associated with several uri. * - * @param connection a connection - * @return the true if the connection has been removed + * @param channel a channel + * @return the true if the channel has been removed */ - boolean removeAll(Channel connection); + boolean removeAll(Channel channel); /** - * Return true if a connection can be cached. A implementation can decide based on some rules to allow caching + * Return true if a channel can be cached. A implementation can decide based on some rules to allow caching * Calling this method is equivalent of checking the returned value of {@link ChannelPool#offer(Object, Object)} * - * @return true if a connection can be cached. + * @return true if a channel can be cached. */ - boolean canCacheConnection(); + boolean isOpen(); /** - * Destroy all connections that has been cached by this instance. + * Destroy all channels that has been cached by this instance. */ void destroy(); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java similarity index 68% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index a1c1c9f4ed..f46a63d310 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java @@ -1,21 +1,22 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, * software distributed under the Apache License Version 2.0 is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ -package org.asynchttpclient.providers.netty.channel; +package org.asynchttpclient.providers.netty.channel.pool; import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.DiscardEvent; +import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,33 +25,27 @@ import io.netty.util.Timeout; import io.netty.util.Timer; import io.netty.util.TimerTask; -import io.netty.util.internal.chmv8.ConcurrentHashMapV8; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; /** - * A simple implementation of {@link ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} + * A simple implementation of {@link com.ning.http.client.providers.netty.pool.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ -public class DefaultChannelPool implements ChannelPool { +public final class DefaultChannelPool implements ChannelPool { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); - private final ConcurrentHashMapV8> connectionsPool = new ConcurrentHashMapV8>(); - private final ConcurrentHashMapV8 channel2Creation = new ConcurrentHashMapV8(); - private final AtomicInteger size = new AtomicInteger(); + private final ConcurrentHashMap> poolsPerKey = new ConcurrentHashMap>(); + private final ConcurrentHashMap channel2Creation = new ConcurrentHashMap(); private final AtomicBoolean isClosed = new AtomicBoolean(false); private final Timer nettyTimer; private final boolean sslConnectionPoolEnabled; - private final int maxTotalConnections; - private final boolean maxTotalConnectionsDisabled; - private final int maxConnectionPerHost; - private final boolean maxConnectionPerHostDisabled; private final int maxConnectionTTL; private final boolean maxConnectionTTLDisabled; private final long maxIdleTime; @@ -58,8 +53,7 @@ public class DefaultChannelPool implements ChannelPool { private final long cleanerPeriod; public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { - this(config.getMaxTotalConnections(),// - config.getMaxConnectionPerHost(),// + this(config.getMaxConnectionPerHost(),// config.getIdleConnectionInPoolTimeoutInMs(),// config.getMaxConnectionLifeTimeInMs(),// config.isSslConnectionPoolEnabled(),// @@ -67,16 +61,11 @@ public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) } public DefaultChannelPool(// - int maxTotalConnections,// int maxConnectionPerHost,// long maxIdleTime,// int maxConnectionTTL,// boolean sslConnectionPoolEnabled,// Timer nettyTimer) { - this.maxTotalConnections = maxTotalConnections; - maxTotalConnectionsDisabled = maxTotalConnections <= 0; - this.maxConnectionPerHost = maxConnectionPerHost; - maxConnectionPerHostDisabled = maxConnectionPerHost <= 0; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; this.maxConnectionTTL = maxConnectionTTL; @@ -97,11 +86,11 @@ private void scheduleNewIdleChannelDetector(TimerTask task) { private static final class ChannelCreation { final long creationTime; - final String key; + final String poolKey; - ChannelCreation(long creationTime, String key) { + ChannelCreation(long creationTime, String poolKey) { this.creationTime = creationTime; - this.key = key; + this.poolKey = poolKey; } } @@ -137,7 +126,7 @@ private boolean isTTLExpired(Channel channel, long now) { } private boolean isRemotelyClosed(Channel channel) { - return !channel.isOpen(); + return !channel.isActive(); } private final class IdleChannelDetector implements TimerTask { @@ -163,12 +152,10 @@ private List expiredChannels(ConcurrentLinkedQueue poo } private boolean isChannelCloseable(Channel channel) { - boolean closeable = true; Object attachment = Channels.getDefaultAttribute(channel); if (attachment instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attachment; - closeable = !future.isDone() || !future.isCancelled(); - if (!closeable) + if (!future.isDone()) LOGGER.error("Future not in appropriate state %s, not closing", future); } return true; @@ -204,23 +191,23 @@ public void run(Timeout timeout) throws Exception { return; try { - if (LOGGER.isDebugEnabled()) { - for (String key : connectionsPool.keySet()) { - LOGGER.debug("Entry count for : {} : {}", key, connectionsPool.get(key).size()); + if (LOGGER.isDebugEnabled()) + for (String key : poolsPerKey.keySet()) { + LOGGER.debug("Entry count for : {} : {}", key, poolsPerKey.get(key).size()); } - } long start = millisTime(); - int totalCount = size.get(); int closedCount = 0; + int totalCount = 0; - for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue - List candidateExpiredChannels = expiredChannels(pool, start); - List closedChannels = closeChannels(candidateExpiredChannels); + if (LOGGER.isDebugEnabled()) + totalCount += pool.size(); + + List closedChannels = closeChannels(expiredChannels(pool, start)); pool.removeAll(closedChannels); int poolClosedCount = closedChannels.size(); - size.addAndGet(-poolClosedCount); closedCount += poolClosedCount; } @@ -236,22 +223,23 @@ public void run(Timeout timeout) throws Exception { } } - private boolean addIdleChannel(ConcurrentLinkedQueue idleConnectionForKey, String key, Channel channel, long now) { - - // FIXME computing CLQ.size is not efficient - if (maxConnectionPerHostDisabled || idleConnectionForKey.size() < maxConnectionPerHost) { - IdleChannel idleChannel = new IdleChannel(channel, now); - return idleConnectionForKey.add(idleChannel); + private ConcurrentLinkedQueue getPoolForKey(String key) { + ConcurrentLinkedQueue pool = poolsPerKey.get(key); + if (pool == null) { + // lazy init pool + ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); + pool = poolsPerKey.putIfAbsent(key, newPool); + if (pool == null) + pool = newPool; } - LOGGER.debug("Maximum number of requests per key reached {} for {}", maxConnectionPerHost, key); - return false; + return pool; } - + /** * {@inheritDoc} */ - public boolean offer(String key, Channel channel) { - if (isClosed.get() || (!sslConnectionPoolEnabled && key.startsWith("https"))) + public boolean offer(Channel channel, String poolKey) { + if (isClosed.get() || (!sslConnectionPoolEnabled && poolKey.startsWith("https"))) return false; long now = millisTime(); @@ -259,19 +247,9 @@ public boolean offer(String key, Channel channel) { if (isTTLExpired(channel, now)) return false; - ConcurrentLinkedQueue idleConnectionForKey = connectionsPool.get(key); - if (idleConnectionForKey == null) { - ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); - idleConnectionForKey = connectionsPool.putIfAbsent(key, newPool); - if (idleConnectionForKey == null) - idleConnectionForKey = newPool; - } - - boolean added = addIdleChannel(idleConnectionForKey, key, channel, now); - if (added) { - size.incrementAndGet(); - channel2Creation.putIfAbsent(channel, new ChannelCreation(now, key)); - } + boolean added = getPoolForKey(poolKey).add(new IdleChannel(channel, now)); + if (added) + channel2Creation.putIfAbsent(channel, new ChannelCreation(now, poolKey)); return added; } @@ -279,12 +257,12 @@ public boolean offer(String key, Channel channel) { /** * {@inheritDoc} */ - public Channel poll(String key) { - if (!sslConnectionPoolEnabled && key.startsWith("https")) + public Channel poll(String poolKey) { + if (!sslConnectionPoolEnabled && poolKey.startsWith("https")) return null; IdleChannel idleChannel = null; - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(key); + ConcurrentLinkedQueue pooledConnectionForKey = poolsPerKey.get(poolKey); if (pooledConnectionForKey != null) { while (idleChannel == null) { idleChannel = pooledConnectionForKey.poll(); @@ -298,11 +276,7 @@ else if (isRemotelyClosed(idleChannel.channel)) { } } } - if (idleChannel != null) { - size.decrementAndGet(); - return idleChannel.channel; - } else - return null; + return idleChannel != null ? idleChannel.channel : null; } /** @@ -310,16 +284,14 @@ else if (isRemotelyClosed(idleChannel.channel)) { */ public boolean removeAll(Channel channel) { ChannelCreation creation = channel2Creation.remove(channel); - return !isClosed.get() && creation != null && connectionsPool.get(creation.key).remove(channel); + return !isClosed.get() && creation != null && poolsPerKey.get(creation.poolKey).remove(channel); } /** * {@inheritDoc} */ - public boolean canCacheConnection() { - // FIXME: doesn't honor per host limit - // FIXME: doesn't account for borrowed channels - return !isClosed.get() && (maxTotalConnectionsDisabled || size.get() < maxTotalConnections); + public boolean isOpen() { + return !isClosed.get(); } /** @@ -329,27 +301,23 @@ public void destroy() { if (isClosed.getAndSet(true)) return; - for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { for (IdleChannel idleChannel : pool) close(idleChannel.channel); } - connectionsPool.clear(); + poolsPerKey.clear(); channel2Creation.clear(); - size.set(0); } private void close(Channel channel) { try { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + // FIXME pity to have to do this here + Channels.setDiscard(channel); channel2Creation.remove(channel); channel.close(); } catch (Throwable t) { // noop } } - - public String toString() { - return String.format("NettyConnectionPool: {pool-size: %d}", size.get()); - } -} +} \ No newline at end of file diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/NonChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java similarity index 73% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/NonChannelPool.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java index c3a929ba24..f8d684ad84 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/NonChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java @@ -13,25 +13,25 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.asynchttpclient.providers.netty.channel; +package org.asynchttpclient.providers.netty.channel.pool; import io.netty.channel.Channel; -public class NonChannelPool implements ChannelPool { +public class NoopChannelPool implements ChannelPool { - public boolean offer(String uri, Channel connection) { + public boolean offer(Channel channel, String poolKey) { return false; } - public Channel poll(String uri) { + public Channel poll(String poolKey) { return null; } - public boolean removeAll(Channel connection) { + public boolean removeAll(Channel channel) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return true; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 9bd2b36ee9..377dd130cd 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -168,16 +168,13 @@ private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsens } } - private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean lastValidChunk) throws IOException { - if (lastValidChunk && future.isKeepAlive()) { + private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { + + boolean keepAlive = future.isKeepAlive(); + if (expectOtherChunks && keepAlive) channels.drainChannel(channel, future); - } else { - if (future.isKeepAlive() && channel.isActive() && channels.offerToPool(channels.getPoolKey(future), channel)) { - markAsDone(future, channel); - return; - } - channels.finishChannel(channel); - } + else + channels.tryToOfferChannelToPool(channel, keepAlive, channels.getPoolKey(future)); markAsDone(future, channel); } @@ -383,11 +380,12 @@ private boolean handleResponseAndExit(final Channel channel, final NettyResponse @Override public void handle(final Channel channel, final NettyResponseFuture future, final Object e) throws Exception { + future.touch(); // The connect timeout occurred. - if (future.isCancelled() || future.isDone()) { - channels.finishChannel(channel); + if (future.isDone()) { + channels.closeChannel(channel); return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 9d31b94d36..7c69daeba7 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -115,7 +115,7 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { } Channel channel = ctx.channel(); - channels.removeFromPool(channel); + channels.removeAll(channel); Object attachment = Channels.getDefaultAttribute(channel); LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 0c482212df..59ff36c90e 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -32,7 +32,6 @@ import org.asynchttpclient.filter.FilterContext; import org.asynchttpclient.filter.FilterException; import org.asynchttpclient.filter.ResponseFilter; -import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; @@ -50,6 +49,7 @@ import java.io.IOException; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; public abstract class Protocol { @@ -91,7 +91,7 @@ public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpP public abstract void onClose(Channel channel); - protected boolean handleRedirectAndExit(Request request, NettyResponseFuture future, HttpResponse response, final Channel channel) + protected boolean handleRedirectAndExit(Request request, final NettyResponseFuture future, HttpResponse response, final Channel channel) throws Exception { io.netty.handler.codec.http.HttpResponseStatus status = response.getStatus(); @@ -147,13 +147,7 @@ protected boolean handleRedirectAndExit(Request request, NettyResponseFuture } } - Callback callback = new Callback(future) { - public void call() throws Exception { - if (!(initialConnectionKeepAlive && channel.isActive() && channels.offerToPool(initialPoolKey, channel))) { - channels.finishChannel(channel); - } - } - }; + Callable> callback = channels.newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); if (HttpHeaders.isTransferEncodingChunked(response)) { // We must make sure there is no bytes left before diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 45f5ef4bfc..05b36fd230 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -47,15 +47,41 @@ final class NettyConnectListener implements ChannelFutureListener { private final AsyncHttpClientConfig config; private final NettyRequestSender requestSender; private final NettyResponseFuture future; - - public NettyConnectListener(AsyncHttpClientConfig config, NettyRequestSender requestSender, NettyResponseFuture future) { + private final Channels channels; + private final boolean channelPreempted; + private final String poolKey; + + public NettyConnectListener(AsyncHttpClientConfig config,// + NettyRequestSender requestSender,// + NettyResponseFuture future,// + Channels channels,// + boolean channelPreempted,// + String poolKey) { this.requestSender = requestSender; this.config = config; this.future = future; + this.channels = channels; + this.channelPreempted = channelPreempted; + this.poolKey = poolKey; + } + + private void abortChannelPreemption(String poolKey) { + if (channelPreempted) + channels.abortChannelPreemption(poolKey); } - public NettyResponseFuture future() { - return future; + private void writeRequest(Channel channel) { + + LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); + + if (future.isDone()) { + abortChannelPreemption(poolKey); + return; + } + + channels.registerOpenChannel(channel); + future.attachChannel(channel, false); + requestSender.writeRequest(future, channel); } public void onFutureSuccess(final Channel channel) throws ConnectException { @@ -72,24 +98,28 @@ public void operationComplete(Future handshakeFuture) throws Ex SSLEngine engine = sslHandler.engine(); SSLSession session = engine.getSession(); - LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), Base64.encode(session.getId()), session.isValid(), host); - if (!hostnameVerifier.verify(host, session)) { + LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), + Base64.encode(session.getId()), session.isValid(), host); + if (hostnameVerifier.verify(host, session)) { + writeRequest(channel); + } else { + abortChannelPreemption(poolKey); ConnectException exception = new ConnectException("HostnameVerifier exception"); future.abort(exception); throw exception; - } else { - requestSender.writeRequest(future, channel); } } } }); } else { - requestSender.writeRequest(future, channel); + writeRequest(channel); } } public void onFutureFailure(Channel channel, Throwable cause) { + abortChannelPreemption(poolKey); + boolean canRetry = future.canRetry(); LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", channel, canRetry); if (canRetry// diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 2fdaab8d50..71bb2d1b1c 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -78,39 +78,40 @@ public NettyRequestSender(AtomicBoolean closed,// public boolean retry(NettyResponseFuture future, Channel channel) { - boolean success = false; + if (closed.get()) + return false; - if (!closed.get()) { - channels.removeAll(channel); + channels.removeAll(channel); - if (future == null) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) - future = (NettyResponseFuture) attachment; - } + if (future == null) { + Object attachment = Channels.getDefaultAttribute(channel); + if (attachment instanceof NettyResponseFuture) + future = (NettyResponseFuture) attachment; + } - if (future != null && future.canBeReplayed()) { - future.setState(NettyResponseFuture.STATE.RECONNECTED); - future.getAndSetStatusReceived(false); + if (future != null && future.canBeReplayed()) { + future.setState(NettyResponseFuture.STATE.RECONNECTED); + future.getAndSetStatusReceived(false); - LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + } - try { - sendNextRequest(future.getRequest(), future); - success = true; - } catch (IOException iox) { - future.setState(NettyResponseFuture.STATE.CLOSED); - future.abort(iox); - LOGGER.error("Remotely Closed, unable to recover", iox); - } - } else { - LOGGER.debug("Unable to recover future {}\n", future); + try { + sendNextRequest(future.getRequest(), future); + return true; + + } catch (IOException iox) { + future.setState(NettyResponseFuture.STATE.CLOSED); + future.abort(iox); + LOGGER.error("Remotely Closed, unable to recover", iox); + return false; } + } else { + LOGGER.debug("Unable to recover future {}\n", future); + return false; } - return success; } public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture future, IOException e, Channel channel) @@ -218,35 +219,35 @@ private ListenableFuture sendRequestWithNewChannel(// // Do not throw an exception when we need an extra connection for a redirect // FIXME why? This violate the max connection per host handling, right? - boolean acquiredConnection = !reclaimCache && channels.acquireConnection(asyncHandler); Bootstrap bootstrap = channels.getBootstrap(request.getURI(), useSSl, useProxy); - NettyConnectListener connectListener = new NettyConnectListener(config, this, future); - ChannelFuture channelFuture; - try { - channelFuture = connect(request, uri, proxy, useProxy, bootstrap); + boolean channelPreempted = false; + String poolKey = null; + + // Do not throw an exception when we need an extra connection for a redirect. + if (!reclaimCache) { - } catch (Throwable t) { - if (acquiredConnection) { - channels.releaseFreeConnections(); - } - channels.abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); - return connectListener.future(); + // only compute when maxConnectionPerHost is enabled + // FIXME clean up + if (config.getMaxConnectionPerHost() > 0) + poolKey = channels.getPoolKey(future); + + channelPreempted = channels.preemptChannel(asyncHandler, poolKey); } - channelFuture.addListener(connectListener); + try { + ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap); + channelFuture.addListener(new NettyConnectListener(config, this, future, channels, channelPreempted, poolKey)); - LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", connectListener.future().getNettyRequest().getHttpRequest(), - channelFuture.channel()); + } catch (Throwable t) { + if (channelPreempted) + channels.abortChannelPreemption(poolKey); - if (!connectListener.future().isCancelled() || !connectListener.future().isDone()) { - channels.registerChannel(channelFuture.channel()); - connectListener.future().attachChannel(channelFuture.channel(), false); - } else if (acquiredConnection) { - channels.releaseFreeConnections(); + channels.abort(future, t.getCause() == null ? t : t.getCause()); } - return connectListener.future(); + + return future; } private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java index 156aeb9699..ea3f0d573c 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java @@ -19,7 +19,7 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; import org.asynchttpclient.async.ConnectionPoolTest; -import org.asynchttpclient.providers.netty.channel.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; import org.testng.annotations.Test; import io.netty.channel.Channel; @@ -38,19 +38,19 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { public void testInvalidConnectionsPool() { ChannelPool cp = new ChannelPool() { - public boolean offer(String key, Channel connection) { + public boolean offer(Channel channel, String poolKey) { return false; } - public Channel poll(String connection) { + public Channel poll(String poolKey) { return null; } - public boolean removeAll(Channel connection) { + public boolean removeAll(Channel channel) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return false; } @@ -82,19 +82,19 @@ public void destroy() { public void testValidConnectionsPool() { ChannelPool cp = new ChannelPool() { - public boolean offer(String key, Channel connection) { + public boolean offer(Channel channel, String poolKey) { return true; } - public Channel poll(String connection) { + public Channel poll(String poolKey) { return null; } - public boolean removeAll(Channel connection) { + public boolean removeAll(Channel channel) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return true; } From 6be39c58d044680bad36e2619e82ca9eb266be84 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 01:35:36 +0200 Subject: [PATCH 0008/1949] Properly compute Realm URI, close #626 --- .../java/org/asynchttpclient/util/AuthenticatorUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index a74d71a659..594eafa1a3 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -12,6 +12,7 @@ */ package org.asynchttpclient.util; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.ProxyServer; @@ -37,12 +38,11 @@ private static String computeRealmURI(Realm realm) { return "/"; } else { UriComponents uri = realm.getUri(); - boolean omitQuery = realm.isOmitQuery() && MiscUtils.isNonEmpty(uri.getQuery()); if (realm.isUseAbsoluteURI()) { - return omitQuery ? uri.withNewQuery(null).toUrl() : uri.toUrl(); + return realm.isOmitQuery() && MiscUtils.isNonEmpty(uri.getQuery()) ? uri.withNewQuery(null).toUrl() : uri.toUrl(); } else { - String path = uri.getPath(); - return omitQuery ? path : path + "?" + uri.getQuery(); + String path = getNonEmptyPath(uri); + return realm.isOmitQuery() || !MiscUtils.isNonEmpty(uri.getQuery()) ? path : path + "?" + uri.getQuery(); } } } From e9452c3b3ccbb27e6450093801d08f22123dc304 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 02:08:19 +0200 Subject: [PATCH 0009/1949] Make ThrottleRequestFilter properly release Semaphore, close #567 --- .../extra/AsyncHandlerWrapper.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java index c9b2f0ae7b..3ce9527270 100644 --- a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java +++ b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java @@ -8,18 +8,27 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; public class AsyncHandlerWrapper implements AsyncHandler { - private final static Logger logger = LoggerFactory.getLogger(AsyncHandlerWrapper.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncHandlerWrapper.class); private final AsyncHandler asyncHandler; private final Semaphore available; + private final AtomicBoolean complete = new AtomicBoolean(false); public AsyncHandlerWrapper(AsyncHandler asyncHandler, Semaphore available) { this.asyncHandler = asyncHandler; this.available = available; } + private void complete() { + if (complete.compareAndSet(false, true)) + available.release(); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); + } + /** * {@inheritDoc} */ @@ -28,10 +37,7 @@ public void onThrowable(Throwable t) { try { asyncHandler.onThrowable(t); } finally { - available.release(); - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); - } + complete(); } } @@ -64,10 +70,10 @@ public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { */ @Override public T onCompleted() throws Exception { - available.release(); - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status {}", available.availablePermits()); + try { + return asyncHandler.onCompleted(); + } finally { + complete(); } - return asyncHandler.onCompleted(); } -} \ No newline at end of file +} From baeb431b22ba1ccc83ee21218c46810d7633cad4 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 16 Jul 2014 21:44:31 -0700 Subject: [PATCH 0010/1949] [master] + minor threads cleanup, use ioThreads config value, fix tests --- .../grizzly/GrizzlyAsyncHttpProvider.java | 19 +++++++++ .../providers/grizzly/Utils.java | 16 ++++++++ .../GrizzlyFeedableBodyGeneratorTest.java | 40 +++++++++---------- .../GrizzlyNoTransferEncodingTest.java | 14 +++---- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 9d3151957a..fa6a759e53 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -73,7 +73,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.glassfish.grizzly.nio.RoundRobinConnectionDistributor; import org.glassfish.grizzly.spdy.SpdyVersion; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -305,6 +307,23 @@ public void onTimeout(Connection connection) { secure.add(new WebSocketClientFilter()); clientTransport.getAsyncQueueIO().getWriter().setMaxPendingBytesPerConnection(AUTO_SIZE); + + clientTransport.setNIOChannelDistributor( + new RoundRobinConnectionDistributor(clientTransport, false, false)); + + final int kernelThreadsCount = + clientConfig.getIoThreadMultiplier() * + Runtime.getRuntime().availableProcessors(); + + clientTransport.setSelectorRunnersCount(kernelThreadsCount); + clientTransport.setKernelThreadPoolConfig( + ThreadPoolConfig.defaultConfig() + .setCorePoolSize(kernelThreadsCount) + .setMaxPoolSize(kernelThreadsCount) + .setPoolName("grizzly-ahc-kernel") +// .setPoolName(Utils.discoverTestName("grizzly-ahc-kernel")) // uncomment for tests to track down the leaked threads + ); + if (providerConfig != null) { final TransportCustomizer customizer = (TransportCustomizer) providerConfig.getProperty(Property.TRANSPORT_CUSTOMIZER); if (customizer != null) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java index 4a4a434cca..8b7ae72a1a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java @@ -84,4 +84,20 @@ public static boolean isSpdyConnection(final Connection c) { Boolean result = SPDY.get(c); return result != null ? result : false; } + + static String discoverTestName(final String defaultName) { + final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + final int strackTraceLen = stackTrace.length; + + if (stackTrace[strackTraceLen - 1].getClassName().contains("surefire")) { + for (int i = strackTraceLen - 2; i >= 0; i--) { + if (stackTrace[i].getClassName().contains("org.asynchttpclient.async")) { + return "grizzly-kernel-" + + stackTrace[i].getClassName() + "." + stackTrace[i].getMethodName(); + } + } + } + + return defaultName; + } } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 9e6a500c63..1aac4fcfce 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -13,24 +13,6 @@ package org.asynchttpclient.providers.grizzly; -import org.asynchttpclient.AsyncCompletionHandler; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.RequestBuilder; -import org.glassfish.grizzly.Buffer; -import org.glassfish.grizzly.http.server.HttpHandler; -import org.glassfish.grizzly.http.server.HttpServer; -import org.glassfish.grizzly.http.server.NetworkListener; -import org.glassfish.grizzly.http.server.Request; -import org.glassfish.grizzly.http.server.Response; -import org.glassfish.grizzly.memory.Buffers; -import org.glassfish.grizzly.ssl.SSLContextConfigurator; -import org.glassfish.grizzly.ssl.SSLEngineConfigurator; -import org.glassfish.grizzly.utils.Charsets; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; - import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -42,14 +24,30 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import org.asynchttpclient.AsyncCompletionHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.DefaultAsyncHttpClient; +import org.asynchttpclient.RequestBuilder; import org.asynchttpclient.providers.grizzly.FeedableBodyGenerator.NonBlockingFeeder; - +import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.server.NetworkListener; import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.grizzly.memory.Buffers; import static org.glassfish.grizzly.memory.MemoryManager.DEFAULT_MEMORY_MANAGER; +import org.glassfish.grizzly.ssl.SSLContextConfigurator; +import org.glassfish.grizzly.ssl.SSLEngineConfigurator; +import org.glassfish.grizzly.utils.Charsets; import static org.testng.Assert.assertNull; import static org.testng.Assert.fail; import static org.testng.AssertJUnit.assertEquals; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; public class GrizzlyFeedableBodyGeneratorTest { @@ -67,7 +65,7 @@ public class GrizzlyFeedableBodyGeneratorTest { // ------------------------------------------------------------------- Setup - @BeforeTest + @BeforeMethod public void setup() throws Exception { generateTempFile(); server = new HttpServer(); @@ -91,7 +89,7 @@ public void setup() throws Exception { // --------------------------------------------------------------- Tear Down - @AfterTest + @AfterMethod public void tearDown() { if (!tempFile.delete()) { tempFile.deleteOnExit(); diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java index 8655f47753..ea02d5fc57 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java @@ -13,21 +13,21 @@ package org.asynchttpclient.providers.grizzly; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.DefaultAsyncHttpClient; import org.glassfish.grizzly.http.server.HttpHandler; import org.glassfish.grizzly.http.server.HttpServer; import org.glassfish.grizzly.http.server.NetworkListener; +import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; import org.glassfish.grizzly.http.server.Request; import org.glassfish.grizzly.http.server.Response; import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; public class GrizzlyNoTransferEncodingTest { private static final String TEST_MESSAGE = "Hello World!"; @@ -37,7 +37,7 @@ public class GrizzlyNoTransferEncodingTest { // ------------------------------------------------------------------- Setup - @BeforeTest + @BeforeMethod public void setup() throws Exception { server = new HttpServer(); final NetworkListener listener = @@ -70,7 +70,7 @@ public void service(final Request request, // --------------------------------------------------------------- Tear Down - @AfterTest + @AfterMethod public void tearDown() { server.shutdownNow(); server = null; From 25bf191ea9faa5ef1fa092c9fe954117b193fa28 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 10:23:58 +0200 Subject: [PATCH 0011/1949] Drop requestCompressionLevel config parameter, close #627 --- .../AsyncHttpClientConfig.java | 35 ------------------- .../AsyncHttpClientConfigBean.java | 6 ---- .../AsyncHttpClientConfigDefaults.java | 5 --- .../SimpleAsyncHttpClient.java | 5 --- .../providers/netty/channel/Channels.java | 5 --- 5 files changed, 56 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 422f560af9..2668db7550 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -98,7 +98,6 @@ public class AsyncHttpClientConfig { protected List requestFilters; protected List responseFilters; protected List ioExceptionFilters; - protected int requestCompressionLevel; protected int maxRequestRetry; protected boolean allowSslConnectionPool; protected boolean disableUrlEncodingForBoundRequests; @@ -140,7 +139,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, // List requestFilters, // List responseFilters, // List ioExceptionFilters, // - int requestCompressionLevel, // int maxRequestRetry, // boolean allowSslConnectionCaching, // boolean disableUrlEncodingForBoundRequests, // @@ -174,7 +172,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, // this.requestFilters = requestFilters; this.responseFilters = responseFilters; this.ioExceptionFilters = ioExceptionFilters; - this.requestCompressionLevel = requestCompressionLevel; this.maxRequestRetry = maxRequestRetry; this.allowSslConnectionPool = allowSslConnectionCaching; this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; @@ -394,15 +391,6 @@ public List getIOExceptionFilters() { return Collections.unmodifiableList(ioExceptionFilters); } - /** - * Return the compression level, or -1 if no compression is used. - * - * @return the compression level, or -1 if no compression is use - */ - public int getRequestCompressionLevel() { - return requestCompressionLevel; - } - /** * Return the number of time the library will retry when an {@link java.io.IOException} is throw by the remote server * @@ -560,7 +548,6 @@ public static class Builder { private boolean useProxySelector = defaultUseProxySelector(); private boolean allowPoolingConnection = defaultAllowPoolingConnection(); private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); - private int requestCompressionLevel = defaultRequestCompressionLevel(); private int maxRequestRetry = defaultMaxRequestRetry(); private int ioThreadMultiplier = defaultIoThreadMultiplier(); private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); @@ -887,26 +874,6 @@ public Builder removeIOExceptionFilter(IOExceptionFilter ioExceptionFilter) { return this; } - /** - * Return the compression level, or -1 if no compression is used. - * - * @return the compression level, or -1 if no compression is use - */ - public int getRequestCompressionLevel() { - return requestCompressionLevel; - } - - /** - * Set the compression level, or -1 if no compression is used. - * - * @param requestCompressionLevel compression level, or -1 if no compression is use - * @return this - */ - public Builder setRequestCompressionLevel(int requestCompressionLevel) { - this.requestCompressionLevel = requestCompressionLevel; - return this; - } - /** * Set the number of times a request will be retried when an {@link java.io.IOException} occurs because of a Network exception. * @@ -1123,7 +1090,6 @@ public Builder(AsyncHttpClientConfig prototype) { responseFilters.addAll(prototype.getResponseFilters()); ioExceptionFilters.addAll(prototype.getIOExceptionFilters()); - requestCompressionLevel = prototype.getRequestCompressionLevel(); disableUrlEncodingForBoundRequests = prototype.isDisableUrlEncodingForBoundRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); @@ -1188,7 +1154,6 @@ public Thread newThread(Runnable r) { requestFilters, // responseFilters, // ioExceptionFilters, // - requestCompressionLevel, // maxRequestRetry, // allowSslConnectionPool, // disableUrlEncodingForBoundRequests, // diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 6c677b075e..254d00403d 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -59,7 +59,6 @@ void configureDefaults() { userAgent = defaultUserAgent(); allowPoolingConnection = defaultAllowPoolingConnection(); useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); - requestCompressionLevel = defaultRequestCompressionLevel(); maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowSslConnectionPool = defaultAllowSslConnectionPool(); @@ -201,11 +200,6 @@ public AsyncHttpClientConfigBean addIoExceptionFilters(IOExceptionFilter ioExcep return this; } - public AsyncHttpClientConfigBean setRequestCompressionLevel(int requestCompressionLevel) { - this.requestCompressionLevel = requestCompressionLevel; - return this; - } - public AsyncHttpClientConfigBean setMaxRequestRetry(int maxRequestRetry) { this.maxRequestRetry = maxRequestRetry; return this; diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index fa05cec469..47af64f89b 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -97,11 +97,6 @@ public static boolean defaultUseRelativeURIsWithSSLProxies() { return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); } - // unused/broken, left there for compatibility, fixed in Netty 4 - public static int defaultRequestCompressionLevel() { - return Integer.getInteger(ASYNC_CLIENT + "requestCompressionLevel", -1); - } - public static int defaultMaxRequestRetry() { return Integer.getInteger(ASYNC_CLIENT + "maxRequestRetry", 5); } diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index d601d4d82c..ad739b546a 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -565,11 +565,6 @@ public Builder setSSLContext(final SSLContext sslContext) { return this; } - public Builder setRequestCompressionLevel(int requestCompressionLevel) { - configBuilder.setRequestCompressionLevel(requestCompressionLevel); - return this; - } - public Builder setRealmNtlmDomain(String domain) { realm().setNtlmDomain(domain); return this; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 3dfc57f9be..54376e29b1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -107,11 +107,6 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig this.config = config; this.nettyProviderConfig = nettyProviderConfig; - // FIXME https://github.com/netty/netty/issues/2132 - if (config.getRequestCompressionLevel() > 0) { - LOGGER.warn("Request was enabled but Netty actually doesn't support this feature, see https://github.com/netty/netty/issues/2132"); - } - // check if external EventLoopGroup is defined allowReleaseEventLoopGroup = nettyProviderConfig.getEventLoopGroup() == null; eventLoopGroup = allowReleaseEventLoopGroup ? new NioEventLoopGroup() : nettyProviderConfig.getEventLoopGroup(); From 8f289c3a94009715bafc8e3c1ea0c12f0079bb2d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 12:39:28 +0200 Subject: [PATCH 0012/1949] Add missing Host header port when using a virtual host, close #632 --- .../netty/request/NettyRequestFactory.java | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index d777c9d1c6..0af2bddfc6 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -88,20 +88,9 @@ else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithS } } - private String hostHeader(Request request, UriComponents uri, Realm realm) { - - String hostHeader = null; - + private String hostHeader(Request request, UriComponents uri) { String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - - if (host != null) { - if (request.getVirtualHost() != null || uri.getPort() == -1) - hostHeader = host; - else - hostHeader = host + ":" + uri.getPort(); - } - - return hostHeader; + return uri.getPort() == -1 ? host : host + ":" + uri.getPort(); } private String authorizationHeader(Request request, UriComponents uri, ProxyServer proxyServer, Realm realm) throws IOException { @@ -148,9 +137,6 @@ else if (request.getVirtualHost() != null) else host = uri.getHost(); - if (host == null) - host = "127.0.0.1"; - try { authorizationHeader = "Negotiate " + SpnegoEngine.instance().generateToken(host); } catch (Throwable e) { @@ -318,12 +304,11 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean httpRequest.headers().set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); } - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - - String hostHeader = hostHeader(request, uri, realm); + String hostHeader = hostHeader(request, uri); if (hostHeader != null) httpRequest.headers().set(HttpHeaders.Names.HOST, hostHeader); + Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); String authorizationHeader = authorizationHeader(request, uri, proxyServer, realm); if (authorizationHeader != null) // don't override authorization but append From 2da66bf266376470e18db04e472989aea34321ed Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:11:07 +0200 Subject: [PATCH 0013/1949] Revert #632 --- .../providers/netty/request/NettyRequestFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 0af2bddfc6..55bbc81b85 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -90,7 +90,7 @@ else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithS private String hostHeader(Request request, UriComponents uri) { String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - return uri.getPort() == -1 ? host : host + ":" + uri.getPort(); + return request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); } private String authorizationHeader(Request request, UriComponents uri, ProxyServer proxyServer, Realm realm) throws IOException { From 2834f03eeb3ec91464139daa96643d58de873c92 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:23:01 +0200 Subject: [PATCH 0014/1949] NettyResponseFuture.get timeout shouldn't cancel http request, close #370 --- .../netty/future/NettyResponseFuture.java | 200 +++++++----------- .../netty/request/NettyRequestSender.java | 6 +- .../timeout/RequestTimeoutTimerTask.java | 8 +- 3 files changed, 90 insertions(+), 124 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 0af60186d3..e95e5bfff6 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -18,7 +18,6 @@ import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ConnectionPoolKeyStrategy; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; @@ -54,14 +53,12 @@ */ public final class NettyResponseFuture extends AbstractListenableFuture { - private static final Logger logger = LoggerFactory.getLogger(NettyResponseFuture.class); - public static final String MAX_RETRY = "org.asynchttpclient.providers.netty.maxRetry"; + private static final Logger LOGGER = LoggerFactory.getLogger(NettyResponseFuture.class); public enum STATE { NEW, POOLED, RECONNECTED, CLOSED, } - private final int requestTimeoutInMs; private volatile boolean requestTimeoutReached; private volatile boolean idleConnectionTimeoutReached; private final long start = millisTime(); @@ -105,37 +102,22 @@ public NettyResponseFuture(UriComponents uri,// Request request,// AsyncHandler asyncHandler,// NettyRequest nettyRequest,// - int requestTimeoutInMs,// - AsyncHttpClientConfig config,// + int maxRetry,// ConnectionPoolKeyStrategy connectionPoolKeyStrategy,// ProxyServer proxyServer) { this.asyncHandler = asyncHandler; - this.requestTimeoutInMs = requestTimeoutInMs; this.request = request; this.nettyRequest = nettyRequest; this.uri = uri; this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; this.proxyServer = proxyServer; - - maxRetry = Integer.getInteger(MAX_RETRY, config.getMaxRequestRetry()); - } - - public UriComponents getURI() { - return uri; - } - - public void setURI(UriComponents uri) { - this.uri = uri; + this.maxRetry = maxRetry; } - public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { - return connectionPoolKeyStrategy; - } - - public ProxyServer getProxyServer() { - return proxyServer; - } + /*********************************************/ + /** java.util.concurrent.Future **/ + /*********************************************/ @Override public boolean isDone() { @@ -147,10 +129,6 @@ public boolean isCancelled() { return isCancelled.get(); } - public void setAsyncHandler(AsyncHandler asyncHandler) { - this.asyncHandler = asyncHandler; - } - @Override public boolean cancel(boolean force) { cancelTimeouts(); @@ -168,7 +146,7 @@ public boolean cancel(boolean force) { try { asyncHandler.onThrowable(new CancellationException()); } catch (Throwable t) { - logger.warn("cancel", t); + LOGGER.warn("cancel", t); } } latch.countDown(); @@ -176,91 +154,22 @@ public boolean cancel(boolean force) { return true; } - /** - * Is the Future still valid - * - * @return true if response has expired and should be terminated. - */ - public boolean hasExpired() { - return requestTimeoutReached || idleConnectionTimeoutReached; - } - - public void setRequestTimeoutReached() { - this.requestTimeoutReached = true; - } - - public boolean isRequestTimeoutReached() { - return requestTimeoutReached; - } - - public void setIdleConnectionTimeoutReached() { - this.idleConnectionTimeoutReached = true; - } - - public boolean isIdleConnectionTimeoutReached() { - return idleConnectionTimeoutReached; - } - @Override public V get() throws InterruptedException, ExecutionException { - try { - return get(requestTimeoutInMs, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - cancelTimeouts(); - throw new ExecutionException(e); - } - } - - public void cancelTimeouts() { - if (timeoutsHolder != null) { - timeoutsHolder.cancel(); - timeoutsHolder = null; - } + if (!isDone()) + latch.await(); + return getContent(); } @Override public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, ExecutionException { - if (!isDone() && !isCancelled()) { - boolean expired = false; - if (l == -1) { - latch.await(); - } else { - expired = !latch.await(l, tu); - } - - if (expired) { - isCancelled.set(true); - try { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); - channel.close(); - } catch (Throwable t) { - // Ignore - } - TimeoutException te = new TimeoutException(String.format("No response received after %s %s", l, tu.name().toLowerCase())); - if (!onThrowableCalled.getAndSet(true)) { - try { - try { - asyncHandler.onThrowable(te); - } catch (Throwable t) { - logger.debug("asyncHandler.onThrowable", t); - } - throw new ExecutionException(te); - } finally { - cancelTimeouts(); - } - } - } - isDone.set(true); - - ExecutionException e = exEx.getAndSet(null); - if (e != null) { - throw e; - } - } + if (!isDone() && !latch.await(l, tu)) + throw new TimeoutException(); return getContent(); } private V getContent() throws ExecutionException { + // FIXME why lose the exception??? ExecutionException e = exEx.getAndSet(null); if (e != null) { throw e; @@ -278,7 +187,7 @@ private V getContent() throws ExecutionException { try { asyncHandler.onThrowable(ex); } catch (Throwable t) { - logger.debug("asyncHandler.onThrowable", t); + LOGGER.debug("asyncHandler.onThrowable", t); } throw new RuntimeException(ex); } finally { @@ -291,6 +200,10 @@ private V getContent() throws ExecutionException { return update; } + /*********************************************/ + /** org.asynchttpclient.ListenableFuture **/ + /*********************************************/ + public final void done() { try { @@ -325,13 +238,74 @@ public final void abort(final Throwable t) { try { asyncHandler.onThrowable(t); } catch (Throwable te) { - logger.debug("asyncHandler.onThrowable", te); + LOGGER.debug("asyncHandler.onThrowable", te); } } latch.countDown(); runListeners(); } + @Override + public void touch() { + touch.set(millisTime()); + } + + /*********************************************/ + /** INTERNAL **/ + /*********************************************/ + + public UriComponents getURI() { + return uri; + } + + public void setURI(UriComponents uri) { + this.uri = uri; + } + + public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { + return connectionPoolKeyStrategy; + } + + public ProxyServer getProxyServer() { + return proxyServer; + } + + public void setAsyncHandler(AsyncHandler asyncHandler) { + this.asyncHandler = asyncHandler; + } + + /** + * Is the Future still valid + * + * @return true if response has expired and should be terminated. + */ + public boolean hasExpired() { + return requestTimeoutReached || idleConnectionTimeoutReached; + } + + public void setRequestTimeoutReached() { + this.requestTimeoutReached = true; + } + + public boolean isRequestTimeoutReached() { + return requestTimeoutReached; + } + + public void setIdleConnectionTimeoutReached() { + this.idleConnectionTimeoutReached = true; + } + + public boolean isIdleConnectionTimeoutReached() { + return idleConnectionTimeoutReached; + } + + public void cancelTimeouts() { + if (timeoutsHolder != null) { + timeoutsHolder.cancel(); + timeoutsHolder = null; + } + } + public final Request getRequest() { return request; } @@ -408,11 +382,6 @@ public void setStreamWasAlreadyConsumed(boolean streamWasAlreadyConsumed) { this.streamWasAlreadyConsumed = streamWasAlreadyConsumed; } - @Override - public void touch() { - touch.set(millisTime()); - } - public long getLastTouch() { return touch.get(); } @@ -470,9 +439,9 @@ public boolean canRetry() { } public SocketAddress getChannelRemoteAddress() { - return channel() != null? channel().remoteAddress(): null; + return channel() != null ? channel().remoteAddress() : null; } - + public void setRequest(Request request) { this.request = request; } @@ -492,10 +461,6 @@ public long getStart() { return start; } - public long getRequestTimeoutInMs() { - return requestTimeoutInMs; - } - @Override public String toString() { return "NettyResponseFuture{" + // @@ -503,7 +468,6 @@ public String toString() { ",\n\tisDone=" + isDone + // ",\n\tisCancelled=" + isCancelled + // ",\n\tasyncHandler=" + asyncHandler + // - ",\n\trequestTimeoutInMs=" + requestTimeoutInMs + // ",\n\tnettyRequest=" + nettyRequest + // ",\n\tcontent=" + content + // ",\n\turi=" + uri + // diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 71bb2d1b1c..ff18a9d5b8 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -253,14 +253,12 @@ private ListenableFuture sendRequestWithNewChannel(// private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { - int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); NettyResponseFuture f = new NettyResponseFuture(// uri,// request,// asyncHandler,// nettyRequest,// - requestTimeout,// - config,// + config.getMaxRequestRetry(),// request.getConnectionPoolKeyStrategy(),// proxyServer); @@ -388,7 +386,7 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); if (requestTimeoutInMs != -1) { Timeout requestTimeout = channels.newTimeoutInMs(new RequestTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, - closed), requestTimeoutInMs); + closed, requestTimeoutInMs), requestTimeoutInMs); timeoutsHolder.requestTimeout = requestTimeout; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 13cae2eb43..cb4d2ca509 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -26,12 +26,16 @@ public class RequestTimeoutTimerTask extends TimeoutTimerTask { + private final long requestTimeout; + public RequestTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// Channels channels,// TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed) { + AtomicBoolean clientClosed,// + long requestTimeout) { super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); + this.requestTimeout = requestTimeout; } @Override @@ -45,7 +49,7 @@ public void run(Timeout timeout) throws Exception { } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms"; + String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + requestTimeout + " ms"; long age = millisTime() - nettyResponseFuture.getStart(); expire(message, age); nettyResponseFuture.setRequestTimeoutReached(); From 1196a96816d912ad4b454acb25a848fa0f9cdd86 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:45:19 +0200 Subject: [PATCH 0015/1949] NettyResponseFuture.getContent shouldn't lose registered exception, close #271 --- .../providers/netty/future/NettyResponseFuture.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index e95e5bfff6..f5078b1d21 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -169,16 +169,15 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, } private V getContent() throws ExecutionException { - // FIXME why lose the exception??? - ExecutionException e = exEx.getAndSet(null); - if (e != null) { + + ExecutionException e = exEx.get(); + if (e != null) throw e; - } V update = content.get(); // No more retry currentRetry.set(maxRetry); - if (exEx.get() == null && !contentProcessed.getAndSet(true)) { + if (!contentProcessed.getAndSet(true)) { try { update = asyncHandler.onCompleted(); } catch (Throwable ex) { From 712c04aef1c0588ce1cff0e5d7ba9ba5a9569556 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 16:16:47 +0200 Subject: [PATCH 0016/1949] Make NettyResponseFuture done and abort mutually exclusive, close #247 --- .../providers/netty/future/NettyResponseFuture.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index f5078b1d21..1418c3c4a5 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -205,14 +205,14 @@ private V getContent() throws ExecutionException { public final void done() { - try { - cancelTimeouts(); + cancelTimeouts(); - if (exEx.get() != null) { - return; - } + if (isDone.getAndSet(true) || isCancelled.get()) + return; + + try { getContent(); - isDone.set(true); + } catch (ExecutionException t) { return; } catch (RuntimeException t) { @@ -227,6 +227,7 @@ public final void done() { } public final void abort(final Throwable t) { + cancelTimeouts(); if (isDone.get() || isCancelled.getAndSet(true)) From b06e0868826df349b8796800c453ec2d44259dd3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:13:24 +0200 Subject: [PATCH 0017/1949] Rename AsyncHttpClientConfig parameters, close #622 --- .../AsyncHttpClientConfig.java | 427 ++++++++---------- .../AsyncHttpClientConfigBean.java | 64 +-- .../AsyncHttpClientConfigDefaults.java | 38 +- .../SimpleAsyncHttpClient.java | 39 +- .../util/AsyncHttpProviderUtils.java | 4 +- .../async/AsyncProvidersBasicTest.java | 6 +- .../async/AuthTimeoutTest.java | 2 +- .../asynchttpclient/async/BasicAuthTest.java | 2 +- .../asynchttpclient/async/BasicHttpsTest.java | 4 +- .../asynchttpclient/async/BodyChunkTest.java | 6 +- .../async/BodyDeferringAsyncHandlerTest.java | 2 +- .../asynchttpclient/async/ChunkingTest.java | 8 +- .../async/ConnectionPoolTest.java | 8 +- .../async/FilePartLargeFileTest.java | 2 +- .../async/IdleStateHandlerTest.java | 2 +- .../async/MaxConnectionsInThreads.java | 4 +- .../async/MaxTotalConnectionTest.java | 6 +- .../async/NoNullResponseTest.java | 4 +- .../async/PerRequestTimeoutTest.java | 6 +- .../async/PutLargeFileTest.java | 2 +- .../org/asynchttpclient/async/RC10KTest.java | 2 +- .../async/RedirectConnectionUsageTest.java | 8 +- .../asynchttpclient/async/RemoteSiteTest.java | 16 +- .../async/SimpleAsyncHttpClientTest.java | 16 +- .../async/TransferListenerTest.java | 2 +- .../providers/grizzly/ConnectionManager.java | 10 +- .../providers/grizzly/EventHandler.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 4 +- .../grizzly/GrizzlyConnectionPoolTest.java | 4 +- .../GrizzlyFeedableBodyGeneratorTest.java | 4 +- .../GrizzlyNoTransferEncodingTest.java | 6 +- .../GrizzlyUnexpectingTimeoutTest.java | 2 +- .../netty/channel/ChannelManager.java | 16 +- .../providers/netty/channel/Channels.java | 6 +- .../channel/pool/DefaultChannelPool.java | 8 +- .../netty/request/NettyRequestSender.java | 8 +- .../NettyRequestThrottleTimeoutTest.java | 2 +- .../netty/RetryNonBlockingIssue.java | 16 +- 38 files changed, 360 insertions(+), 408 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 2668db7550..265008c2bb 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -34,24 +34,12 @@ import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; /** * Configuration class to use with a {@link AsyncHttpClient}. System property can be also used to configure this * object default behavior by doing: *

* -Dorg.asynchttpclient.AsyncHttpClientConfig.nameOfTheProperty - * ex: - *

- * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxTotalConnections - * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxTotalConnections - * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxConnectionsPerHost - * -Dorg.asynchttpclient.AsyncHttpClientConfig.connectionTimeoutInMs - * -Dorg.asynchttpclient.AsyncHttpClientConfig.idleConnectionInPoolTimeoutInMs - * -Dorg.asynchttpclient.AsyncHttpClientConfig.requestTimeoutInMs - * -Dorg.asynchttpclient.AsyncHttpClientConfig.redirectsEnabled - * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxRedirects */ public class AsyncHttpClientConfig { @@ -78,115 +66,122 @@ public class AsyncHttpClientConfig { AHC_VERSION = prop.getProperty("ahc.version", "UNKNOWN"); } - protected int maxTotalConnections; - protected int maxConnectionPerHost; - protected int connectionTimeOutInMs; - protected int webSocketIdleTimeoutInMs; - protected int idleConnectionInPoolTimeoutInMs; - protected int idleConnectionTimeoutInMs; - protected int requestTimeoutInMs; + protected int connectionTimeout; + + protected int maxConnections; + protected int maxConnectionsPerHost; + + protected int requestTimeout; + protected int readTimeout; + protected int webSocketReadTimeout; + + protected boolean allowPoolingConnections; + protected boolean allowPoolingSslConnections; + protected int pooledConnectionIdleTimeout; + protected int connectionTTL; + + protected SSLContext sslContext; + protected HostnameVerifier hostnameVerifier; + protected boolean acceptAnyCertificate; + protected boolean followRedirect; protected int maxRedirects; + protected boolean removeQueryParamOnRedirect; + protected boolean strict302Handling; + + protected ProxyServerSelector proxyServerSelector; + protected boolean useRelativeURIsWithSSLProxies; + protected boolean compressionEnabled; protected String userAgent; - protected boolean allowPoolingConnection; protected ExecutorService applicationThreadPool; - protected ProxyServerSelector proxyServerSelector; - protected SSLContext sslContext; - protected AsyncHttpProviderConfig providerConfig; protected Realm realm; protected List requestFilters; protected List responseFilters; protected List ioExceptionFilters; protected int maxRequestRetry; - protected boolean allowSslConnectionPool; protected boolean disableUrlEncodingForBoundRequests; - protected boolean removeQueryParamOnRedirect; - protected HostnameVerifier hostnameVerifier; protected int ioThreadMultiplier; - protected boolean strict302Handling; - protected int maxConnectionLifeTimeInMs; - protected boolean useRelativeURIsWithSSLProxies; + protected TimeConverter timeConverter; + protected AsyncHttpProviderConfig providerConfig; + + // AHC 2 specific protected boolean spdyEnabled; protected int spdyInitialWindowSize; protected int spdyMaxConcurrentStreams; - protected TimeConverter timeConverter; - protected boolean acceptAnyCertificate; protected AsyncHttpClientConfig() { } - private AsyncHttpClientConfig(int maxTotalConnections, // - int maxConnectionPerHost, // - int connectionTimeOutInMs, // - int webSocketTimeoutInMs, // - int idleConnectionInPoolTimeoutInMs, // - int idleConnectionTimeoutInMs, // - int requestTimeoutInMs, // - int connectionMaxLifeTimeInMs, // + private AsyncHttpClientConfig(int connectionTimeout,// + int maxConnections,// + int maxConnectionsPerHost,// + int requestTimeout,// + int readTimeout,// + int webSocketIdleTimeout,// + boolean allowPoolingConnection,// + boolean allowSslConnectionPool,// + int idleConnectionInPoolTimeout,// + int maxConnectionLifeTime,// + SSLContext sslContext, // + HostnameVerifier hostnameVerifier,// + boolean acceptAnyCertificate, // boolean followRedirect, // int maxRedirects, // - boolean compressionEnabled, // - String userAgent, // - boolean keepAlive, // - ScheduledExecutorService reaper, // - ExecutorService applicationThreadPool, // + boolean removeQueryParamOnRedirect,// + boolean strict302Handling, // + ExecutorService applicationThreadPool,// ProxyServerSelector proxyServerSelector, // - SSLContext sslContext, // - SSLEngineFactory sslEngineFactory, // - AsyncHttpProviderConfig providerConfig, // - Realm realm, // - List requestFilters, // - List responseFilters, // - List ioExceptionFilters, // + boolean useRelativeURIsWithSSLProxies, // + boolean compressionEnabled, // + String userAgent,// + Realm realm,// + List requestFilters,// + List responseFilters,// + List ioExceptionFilters,// int maxRequestRetry, // - boolean allowSslConnectionCaching, // boolean disableUrlEncodingForBoundRequests, // - boolean removeQueryParamOnRedirect, // - HostnameVerifier hostnameVerifier, // int ioThreadMultiplier, // - boolean strict302Handling, // - boolean useRelativeURIsWithSSLProxies, // + TimeConverter timeConverter,// + AsyncHttpProviderConfig providerConfig,// boolean spdyEnabled, // int spdyInitialWindowSize, // - int spdyMaxConcurrentStreams, // - TimeConverter timeConverter, // - boolean acceptAnyCertificate) { - - this.maxTotalConnections = maxTotalConnections; - this.maxConnectionPerHost = maxConnectionPerHost; - this.connectionTimeOutInMs = connectionTimeOutInMs; - this.webSocketIdleTimeoutInMs = webSocketTimeoutInMs; - this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; - this.requestTimeoutInMs = requestTimeoutInMs; - this.maxConnectionLifeTimeInMs = connectionMaxLifeTimeInMs; + int spdyMaxConcurrentStreams) { + + this.connectionTimeout = connectionTimeout; + this.maxConnections = maxConnections; + this.maxConnectionsPerHost = maxConnectionsPerHost; + this.requestTimeout = requestTimeout; + this.readTimeout = readTimeout; + this.webSocketReadTimeout = webSocketIdleTimeout; + this.allowPoolingConnections = allowPoolingConnection; + this.allowPoolingSslConnections = allowSslConnectionPool; + this.pooledConnectionIdleTimeout = idleConnectionInPoolTimeout; + this.connectionTTL = maxConnectionLifeTime; + this.sslContext = sslContext; + this.hostnameVerifier = hostnameVerifier; + this.acceptAnyCertificate = acceptAnyCertificate; this.followRedirect = followRedirect; this.maxRedirects = maxRedirects; + this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; + this.strict302Handling = strict302Handling; + this.proxyServerSelector = proxyServerSelector; + this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; this.compressionEnabled = compressionEnabled; this.userAgent = userAgent; - this.allowPoolingConnection = keepAlive; - this.sslContext = sslContext; - this.providerConfig = providerConfig; + this.applicationThreadPool = applicationThreadPool == null ? Executors.newCachedThreadPool() : applicationThreadPool; this.realm = realm; this.requestFilters = requestFilters; this.responseFilters = responseFilters; this.ioExceptionFilters = ioExceptionFilters; this.maxRequestRetry = maxRequestRetry; - this.allowSslConnectionPool = allowSslConnectionCaching; - this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; - this.hostnameVerifier = hostnameVerifier; - this.ioThreadMultiplier = ioThreadMultiplier; - this.strict302Handling = strict302Handling; - this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; - this.applicationThreadPool = applicationThreadPool; - this.proxyServerSelector = proxyServerSelector; this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests; + this.ioThreadMultiplier = ioThreadMultiplier; + this.timeConverter = timeConverter; + this.providerConfig = providerConfig; this.spdyEnabled = spdyEnabled; this.spdyInitialWindowSize = spdyInitialWindowSize; this.spdyMaxConcurrentStreams = spdyMaxConcurrentStreams; - this.timeConverter = timeConverter; - this.acceptAnyCertificate = acceptAnyCertificate; } @@ -195,8 +190,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, // * * @return the maximum number of connections an {@link AsyncHttpClient} can handle. */ - public int getMaxTotalConnections() { - return maxTotalConnections; + public int getMaxConnections() { + return maxConnections; } /** @@ -204,8 +199,8 @@ public int getMaxTotalConnections() { * * @return the maximum number of connections per host an {@link AsyncHttpClient} can handle. */ - public int getMaxConnectionPerHost() { - return maxConnectionPerHost; + public int getMaxConnectionsPerHost() { + return maxConnectionsPerHost; } /** @@ -213,16 +208,16 @@ public int getMaxConnectionPerHost() { * * @return the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host */ - public int getConnectionTimeoutInMs() { - return connectionTimeOutInMs; + public int getConnectionTimeout() { + return connectionTimeout; } /** * Return the maximum time, in milliseconds, a {@link org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. * @return the maximum time, in milliseconds, a {@link org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. */ - public int getWebSocketIdleTimeoutInMs() { - return webSocketIdleTimeoutInMs; + public int getWebSocketReadTimeout() { + return webSocketReadTimeout; } /** @@ -230,8 +225,8 @@ public int getWebSocketIdleTimeoutInMs() { * * @return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle. */ - public int getIdleConnectionTimeoutInMs() { - return idleConnectionTimeoutInMs; + public int getReadTimeout() { + return readTimeout; } /** @@ -241,8 +236,8 @@ public int getIdleConnectionTimeoutInMs() { * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection * in pool. */ - public int getIdleConnectionInPoolTimeoutInMs() { - return idleConnectionInPoolTimeoutInMs; + public int getPooledConnectionIdleTimeout() { + return pooledConnectionIdleTimeout; } /** @@ -250,8 +245,8 @@ public int getIdleConnectionInPoolTimeoutInMs() { * * @return the maximum time in millisecond an {@link AsyncHttpClient} wait for a response */ - public int getRequestTimeoutInMs() { - return requestTimeoutInMs; + public int getRequestTimeout() { + return requestTimeout; } /** @@ -277,8 +272,8 @@ public int getMaxRedirects() { * * @return true if keep-alive is enabled */ - public boolean isAllowPoolingConnection() { - return allowPoolingConnection; + public boolean isAllowPoolingConnections() { + return allowPoolingConnections; } /** @@ -405,8 +400,8 @@ public int getMaxRequestRetry() { * * @return true is enabled. */ - public boolean isSslConnectionPoolEnabled() { - return allowSslConnectionPool; + public boolean isAllowPoolingSslConnections() { + return allowPoolingSslConnections; } /** @@ -511,8 +506,8 @@ public boolean isUseRelativeURIsWithSSLProxies() { * * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible. */ - public int getMaxConnectionLifeTimeInMs() { - return maxConnectionLifeTimeInMs; + public int getConnectionTTL() { + return connectionTTL; } /** @@ -532,103 +527,102 @@ public boolean isAcceptAnyCertificate() { * Builder for an {@link AsyncHttpClient} */ public static class Builder { - private int maxTotalConnections = defaultMaxTotalConnections(); - private int maxConnectionPerHost = defaultMaxConnectionPerHost(); - private int connectionTimeOutInMs = defaultConnectionTimeOutInMs(); - private int webSocketIdleTimeoutInMs = defaultWebSocketIdleTimeoutInMs(); - private int idleConnectionInPoolTimeoutInMs = defaultIdleConnectionInPoolTimeoutInMs(); - private int idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); - private int requestTimeoutInMs = defaultRequestTimeoutInMs(); - private int maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); + private int connectionTimeout = defaultConnectionTimeout(); + private int maxConnections = defaultMaxConnections(); + private int maxConnectionsPerHost = defaultMaxConnectionsPerHost(); + private int requestTimeout = defaultRequestTimeout(); + private int readTimeout = defaultReadTimeout(); + private int webSocketReadTimeout = defaultWebSocketReadTimeout(); + private boolean allowPoolingConnections = defaultAllowPoolingConnections(); + private boolean allowPoolingSslConnections = defaultAllowPoolingSslConnections(); + private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); + private int connectionTTL = defaultConnectionTTL(); + private SSLContext sslContext; + private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); + private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); private boolean followRedirect = defaultFollowRedirect(); private int maxRedirects = defaultMaxRedirects(); - private boolean compressionEnabled = defaultCompressionEnabled(); - private String userAgent = defaultUserAgent(); - private boolean useProxyProperties = defaultUseProxyProperties(); - private boolean useProxySelector = defaultUseProxySelector(); - private boolean allowPoolingConnection = defaultAllowPoolingConnection(); - private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); - private int maxRequestRetry = defaultMaxRequestRetry(); - private int ioThreadMultiplier = defaultIoThreadMultiplier(); - private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); - private boolean disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); private boolean strict302Handling = defaultStrict302Handling(); - private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); - private boolean spdyEnabled = defaultSpdyEnabled(); - private int spdyInitialWindowSize = defaultSpdyInitialWindowSize(); - private int spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); - private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); - - private ScheduledExecutorService reaper; - private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; - private SSLContext sslContext; - private SSLEngineFactory sslEngineFactory; - private AsyncHttpProviderConfig providerConfig; + private boolean useProxySelector = defaultUseProxySelector(); + private boolean useProxyProperties = defaultUseProxyProperties(); + private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + private boolean compressionEnabled = defaultCompressionEnabled(); + private String userAgent = defaultUserAgent(); + private ExecutorService applicationThreadPool; private Realm realm; private final List requestFilters = new LinkedList(); private final List responseFilters = new LinkedList(); private final List ioExceptionFilters = new LinkedList(); + private int maxRequestRetry = defaultMaxRequestRetry(); + private boolean disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); + private int ioThreadMultiplier = defaultIoThreadMultiplier(); private TimeConverter timeConverter; - + private AsyncHttpProviderConfig providerConfig; + + // AHC 2 + private boolean spdyEnabled = defaultSpdyEnabled(); + private int spdyInitialWindowSize = defaultSpdyInitialWindowSize(); + private int spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); + public Builder() { } /** * Set the maximum number of connections an {@link AsyncHttpClient} can handle. * - * @param maxTotalConnections the maximum number of connections an {@link AsyncHttpClient} can handle. + * @param maxConnections the maximum number of connections an {@link AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaxConnectionsTotal(int maxTotalConnections) { - this.maxTotalConnections = maxTotalConnections; + public Builder setMaxConnections(int maxConnections) { + this.maxConnections = maxConnections; return this; } /** * Set the maximum number of connections per hosts an {@link AsyncHttpClient} can handle. * - * @param maxConnectionPerHost the maximum number of connections per host an {@link AsyncHttpClient} can handle. + * @param maxConnectionsPerHost the maximum number of connections per host an {@link AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaxConnectionsPerHost(int maxConnectionPerHost) { - this.maxConnectionPerHost = maxConnectionPerHost; + public Builder setMaxConnectionsPerHost(int maxConnectionsPerHost) { + this.maxConnectionsPerHost = maxConnectionsPerHost; return this; } /** * Set the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host * - * @param connectionTimeOutInMs the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host + * @param connectionTimeout the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host * @return a {@link Builder} */ - public Builder setConnectionTimeoutInMs(int connectionTimeOutInMs) { - this.connectionTimeOutInMs = connectionTimeOutInMs; + public Builder setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; return this; } /** * Set the maximum time in millisecond an {@link org.asynchttpclient.websocket.WebSocket} can stay idle. * - * @param webSocketIdleTimeoutInMs + * @param webSocketIdleTimeout * the maximum time in millisecond an {@link org.asynchttpclient.websocket.WebSocket} can stay idle. * @return a {@link Builder} */ - public Builder setWebSocketIdleTimeoutInMs(int webSocketIdleTimeoutInMs) { - this.webSocketIdleTimeoutInMs = webSocketIdleTimeoutInMs; + public Builder setWebSocketReadTimeout(int webSocketReadTimeout) { + this.webSocketReadTimeout = webSocketReadTimeout; return this; } /** * Set the maximum time in millisecond an {@link AsyncHttpClient} can stay idle. * - * @param idleConnectionTimeoutInMs + * @param readTimeout * the maximum time in millisecond an {@link AsyncHttpClient} can stay idle. * @return a {@link Builder} */ - public Builder setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; + public Builder setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; return this; } @@ -636,24 +630,24 @@ public Builder setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { * Set the maximum time in millisecond an {@link AsyncHttpClient} will keep connection * idle in pool. * - * @param idleConnectionInPoolTimeoutInMs + * @param pooledConnectionIdleTimeout * the maximum time in millisecond an {@link AsyncHttpClient} will keep connection * idle in pool. * @return a {@link Builder} */ - public Builder setIdleConnectionInPoolTimeoutInMs(int idleConnectionInPoolTimeoutInMs) { - this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; + public Builder setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) { + this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout; return this; } /** * Set the maximum time in millisecond an {@link AsyncHttpClient} wait for a response * - * @param requestTimeoutInMs the maximum time in millisecond an {@link AsyncHttpClient} wait for a response + * @param requestTimeout the maximum time in millisecond an {@link AsyncHttpClient} wait for a response * @return a {@link Builder} */ - public Builder setRequestTimeoutInMs(int requestTimeoutInMs) { - this.requestTimeoutInMs = requestTimeoutInMs; + public Builder setRequestTimeout(int requestTimeout) { + this.requestTimeout = requestTimeout; return this; } @@ -704,22 +698,11 @@ public Builder setUserAgent(String userAgent) { /** * Set true if connection can be pooled by a {@link ConnectionsPool}. Default is true. * - * @param allowPoolingConnection true if connection can be pooled by a {@link ConnectionsPool} + * @param allowPoolingConnections true if connection can be pooled by a {@link ConnectionsPool} * @return a {@link Builder} */ - public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { - this.allowPoolingConnection = allowPoolingConnection; - return this; - } - - /** - * Set the{@link ScheduledExecutorService} used to expire idle connections. - * - * @param reaper the{@link ScheduledExecutorService} used to expire idle connections. - * @return a {@link Builder} - */ - public Builder setScheduledExecutorService(ScheduledExecutorService reaper) { - this.reaper = reaper; + public Builder setAllowPoolingConnections(boolean allowPoolingConnections) { + this.allowPoolingConnections = allowPoolingConnections; return this; } @@ -758,17 +741,6 @@ public Builder setProxyServer(ProxyServer proxyServer) { return this; } - /** - * Set the {@link SSLEngineFactory} for secure connection. - * - * @param sslEngineFactory the {@link SSLEngineFactory} for secure connection - * @return a {@link Builder} - */ - public Builder setSSLEngineFactory(SSLEngineFactory sslEngineFactory) { - this.sslEngineFactory = sslEngineFactory; - return this; - } - /** * Set the {@link SSLContext} for secure connection. * @@ -776,8 +748,6 @@ public Builder setSSLEngineFactory(SSLEngineFactory sslEngineFactory) { * @return a {@link Builder} */ public Builder setSSLContext(final SSLContext sslContext) { - // reset previously set value so it will be lazily recreated - this.sslEngineFactory = null; this.sslContext = sslContext; return this; } @@ -888,11 +858,11 @@ public Builder setMaxRequestRetry(int maxRequestRetry) { /** * Return true is if connections pooling is enabled. * - * @param allowSslConnectionPool true if enabled + * @param pooledConnectionIdleTimeout true if enabled * @return this */ - public Builder setAllowSslConnectionPool(boolean allowSslConnectionPool) { - this.allowSslConnectionPool = allowSslConnectionPool; + public Builder setAllowPoolingSslConnections(boolean allowPoolingSslConnections) { + this.allowPoolingSslConnections = allowPoolingSslConnections; return this; } @@ -982,11 +952,11 @@ public Builder setStrict302Handling(final boolean strict302Handling) { /** * Set the maximum time in millisecond connection can be added to the pool for further reuse * - * @param maxConnectionLifeTimeInMs the maximum time in millisecond connection can be added to the pool for further reuse + * @param connectionTTL the maximum time in millisecond connection can be added to the pool for further reuse * @return a {@link Builder} */ - public Builder setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + public Builder setConnectionTTL(int connectionTTL) { + this.connectionTTL = connectionTTL; return this; } @@ -1064,18 +1034,18 @@ public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { * @param prototype the configuration to use as a prototype. */ public Builder(AsyncHttpClientConfig prototype) { - allowPoolingConnection = prototype.isAllowPoolingConnection(); + allowPoolingConnections = prototype.isAllowPoolingConnections(); providerConfig = prototype.getAsyncHttpProviderConfig(); - connectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); - idleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); - idleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); - maxConnectionPerHost = prototype.getMaxConnectionPerHost(); - maxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); + connectionTimeout = prototype.getConnectionTimeout(); + pooledConnectionIdleTimeout = prototype.getPooledConnectionIdleTimeout(); + readTimeout = prototype.getReadTimeout(); + maxConnectionsPerHost = prototype.getMaxConnectionsPerHost(); + connectionTTL = prototype.getConnectionTTL(); maxRedirects = prototype.getMaxRedirects(); - maxTotalConnections = prototype.getMaxTotalConnections(); + maxConnections = prototype.getMaxConnections(); proxyServerSelector = prototype.getProxyServerSelector(); realm = prototype.getRealm(); - requestTimeoutInMs = prototype.getRequestTimeoutInMs(); + requestTimeout = prototype.getRequestTimeout(); sslContext = prototype.getSSLContext(); userAgent = prototype.getUserAgent(); followRedirect = prototype.isFollowRedirect(); @@ -1093,13 +1063,16 @@ public Builder(AsyncHttpClientConfig prototype) { disableUrlEncodingForBoundRequests = prototype.isDisableUrlEncodingForBoundRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); - allowSslConnectionPool = prototype.isAllowPoolingConnection(); + allowPoolingSslConnections = prototype.isAllowPoolingConnections(); removeQueryParamOnRedirect = prototype.isRemoveQueryParamOnRedirect(); hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); - useRelativeURIsWithSSLProxies = prototype.isUseRelativeURIsWithSSLProxies(); - timeConverter = prototype.getTimeConverter(); - acceptAnyCertificate = prototype.isAcceptAnyCertificate(); + timeConverter = prototype.timeConverter; + acceptAnyCertificate = prototype.acceptAnyCertificate; + + spdyEnabled = prototype.isSpdyEnabled(); + spdyInitialWindowSize = prototype.getSpdyInitialWindowSize(); + spdyMaxConcurrentStreams = prototype.getSpdyMaxConcurrentStreams(); } /** @@ -1109,16 +1082,6 @@ public Builder(AsyncHttpClientConfig prototype) { */ public AsyncHttpClientConfig build() { - if (reaper == null) { - reaper = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = new Thread(r, "AsyncHttpClient-Reaper"); - t.setDaemon(true); - return t; - } - }); - } - if (proxyServerSelector == null && useProxySelector) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); } @@ -1131,42 +1094,40 @@ public Thread newThread(Runnable r) { proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR; } - return new AsyncHttpClientConfig(maxTotalConnections, // - maxConnectionPerHost, // - connectionTimeOutInMs, // - webSocketIdleTimeoutInMs, // - idleConnectionInPoolTimeoutInMs, // - idleConnectionTimeoutInMs, // - requestTimeoutInMs, // - maxConnectionLifeTimeInMs, // + return new AsyncHttpClientConfig(connectionTimeout,// + maxConnections,// + maxConnectionsPerHost,// + requestTimeout,// + readTimeout,// + webSocketReadTimeout,// + allowPoolingConnections,// + allowPoolingSslConnections,// + pooledConnectionIdleTimeout,// + connectionTTL,// + sslContext, // + hostnameVerifier,// + acceptAnyCertificate, // followRedirect, // maxRedirects, // - compressionEnabled, // - userAgent, // - allowPoolingConnection, // - reaper, // + removeQueryParamOnRedirect,// + strict302Handling, // applicationThreadPool, // proxyServerSelector, // - sslContext, // - sslEngineFactory, // - providerConfig, // - realm, // + useRelativeURIsWithSSLProxies, // + compressionEnabled, // + userAgent,// + realm,// requestFilters, // - responseFilters, // - ioExceptionFilters, // + responseFilters,// + ioExceptionFilters,// maxRequestRetry, // - allowSslConnectionPool, // disableUrlEncodingForBoundRequests, // - removeQueryParamOnRedirect, // - hostnameVerifier, // ioThreadMultiplier, // - strict302Handling, // - useRelativeURIsWithSSLProxies, // + timeConverter,// + providerConfig, // spdyEnabled, // spdyInitialWindowSize, // - spdyMaxConcurrentStreams, // - timeConverter, // - acceptAnyCertificate); + spdyMaxConcurrentStreams); } } } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 254d00403d..e276b9f10a 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -45,36 +45,38 @@ void configureFilters() { } void configureDefaults() { - maxTotalConnections = defaultMaxTotalConnections(); - maxConnectionPerHost = defaultMaxConnectionPerHost(); - connectionTimeOutInMs = defaultConnectionTimeOutInMs(); - webSocketIdleTimeoutInMs = defaultWebSocketIdleTimeoutInMs(); - idleConnectionInPoolTimeoutInMs = defaultIdleConnectionInPoolTimeoutInMs(); - idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); - requestTimeoutInMs = defaultRequestTimeoutInMs(); - maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); + maxConnections = defaultMaxConnections(); + maxConnectionsPerHost = defaultMaxConnectionsPerHost(); + connectionTimeout = defaultConnectionTimeout(); + webSocketReadTimeout = defaultWebSocketReadTimeout(); + pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); + readTimeout = defaultReadTimeout(); + requestTimeout = defaultRequestTimeout(); + connectionTTL = defaultConnectionTTL(); followRedirect = defaultFollowRedirect(); maxRedirects = defaultMaxRedirects(); compressionEnabled = defaultCompressionEnabled(); userAgent = defaultUserAgent(); - allowPoolingConnection = defaultAllowPoolingConnection(); + allowPoolingConnections = defaultAllowPoolingConnections(); useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); - allowSslConnectionPool = defaultAllowSslConnectionPool(); + allowPoolingSslConnections = defaultAllowPoolingSslConnections(); disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); hostnameVerifier = defaultHostnameVerifier(); - spdyEnabled = defaultSpdyEnabled(); - spdyInitialWindowSize = defaultSpdyInitialWindowSize(); - spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); acceptAnyCertificate = defaultAcceptAnyCertificate(); + if (defaultUseProxySelector()) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); } else if (defaultUseProxyProperties()) { proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties()); } + // AHC 2 + spdyEnabled = defaultSpdyEnabled(); + spdyInitialWindowSize = defaultSpdyInitialWindowSize(); + spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); } void configureExecutors() { @@ -87,38 +89,38 @@ public Thread newThread(Runnable r) { }); } - public AsyncHttpClientConfigBean setMaxTotalConnections(int maxTotalConnections) { - this.maxTotalConnections = maxTotalConnections; + public AsyncHttpClientConfigBean setMaxTotalConnections(int maxConnections) { + this.maxConnections = maxConnections; return this; } - public AsyncHttpClientConfigBean setMaxConnectionPerHost(int maxConnectionPerHost) { - this.maxConnectionPerHost = maxConnectionPerHost; + public AsyncHttpClientConfigBean setMaxConnectionsPerHost(int maxConnectionsPerHost) { + this.maxConnectionsPerHost = maxConnectionsPerHost; return this; } - public AsyncHttpClientConfigBean setConnectionTimeOutInMs(int connectionTimeOutInMs) { - this.connectionTimeOutInMs = connectionTimeOutInMs; + public AsyncHttpClientConfigBean setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; return this; } - public AsyncHttpClientConfigBean setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + public AsyncHttpClientConfigBean setConnectionTTL(int connectionTTL) { + this.connectionTTL = connectionTTL; return this; } - public AsyncHttpClientConfigBean setIdleConnectionInPoolTimeoutInMs(int idleConnectionInPoolTimeoutInMs) { - this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; + public AsyncHttpClientConfigBean setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) { + this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout; return this; } - public AsyncHttpClientConfigBean setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; + public AsyncHttpClientConfigBean setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; return this; } - public AsyncHttpClientConfigBean setRequestTimeoutInMs(int requestTimeoutInMs) { - this.requestTimeoutInMs = requestTimeoutInMs; + public AsyncHttpClientConfigBean setRequestTimeout(int requestTimeout) { + this.requestTimeout = requestTimeout; return this; } @@ -147,8 +149,8 @@ public AsyncHttpClientConfigBean setUserAgent(String userAgent) { return this; } - public AsyncHttpClientConfigBean setAllowPoolingConnection(boolean allowPoolingConnection) { - this.allowPoolingConnection = allowPoolingConnection; + public AsyncHttpClientConfigBean setAllowPoolingConnections(boolean allowPoolingConnections) { + this.allowPoolingConnections = allowPoolingConnections; return this; } @@ -205,8 +207,8 @@ public AsyncHttpClientConfigBean setMaxRequestRetry(int maxRequestRetry) { return this; } - public AsyncHttpClientConfigBean setAllowSslConnectionPool(boolean allowSslConnectionPool) { - this.allowSslConnectionPool = allowSslConnectionPool; + public AsyncHttpClientConfigBean setAllowPoolingSslConnections(boolean allowPoolingSslConnections) { + this.allowPoolingSslConnections = allowPoolingSslConnections; return this; } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 47af64f89b..e64f1a54b5 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -25,36 +25,36 @@ private AsyncHttpClientConfigDefaults() { public static final String ASYNC_CLIENT = AsyncHttpClientConfig.class.getName() + "."; - public static int defaultMaxTotalConnections() { - return Integer.getInteger(ASYNC_CLIENT + "maxTotalConnections", -1); + public static int defaultMaxConnections() { + return Integer.getInteger(ASYNC_CLIENT + "maxConnections", -1); } - public static int defaultMaxConnectionPerHost() { + public static int defaultMaxConnectionsPerHost() { return Integer.getInteger(ASYNC_CLIENT + "maxConnectionsPerHost", -1); } - public static int defaultConnectionTimeOutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "connectionTimeoutInMs", 60 * 1000); + public static int defaultConnectionTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "connectionTimeout", 60 * 1000); } - public static int defaultIdleConnectionInPoolTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "idleConnectionInPoolTimeoutInMs", 60 * 1000); + public static int defaultPooledConnectionIdleTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "pooledConnectionIdleTimeout", 60 * 1000); } - public static int defaultIdleConnectionTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "idleConnectionTimeoutInMs", 60 * 1000); + public static int defaultReadTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "readTimeout", 60 * 1000); } - public static int defaultRequestTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "requestTimeoutInMs", 60 * 1000); + public static int defaultRequestTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "requestTimeout", 60 * 1000); } - public static int defaultWebSocketIdleTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "webSocketTimoutInMS", 15 * 60 * 1000); + public static int defaultWebSocketReadTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "webSocketReadTimeout", 15 * 60 * 1000); } - public static int defaultMaxConnectionLifeTimeInMs() { - return Integer.getInteger(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); + public static int defaultConnectionTTL() { + return Integer.getInteger(ASYNC_CLIENT + "connectionTTL", -1); } public static boolean defaultFollowRedirect() { @@ -89,8 +89,8 @@ public static boolean defaultStrict302Handling() { return Boolean.getBoolean(ASYNC_CLIENT + "strict302Handling"); } - public static boolean defaultAllowPoolingConnection() { - return getBoolean(ASYNC_CLIENT + "allowPoolingConnection", true); + public static boolean defaultAllowPoolingConnections() { + return getBoolean(ASYNC_CLIENT + "allowPoolingConnections", true); } public static boolean defaultUseRelativeURIsWithSSLProxies() { @@ -101,8 +101,8 @@ public static int defaultMaxRequestRetry() { return Integer.getInteger(ASYNC_CLIENT + "maxRequestRetry", 5); } - public static boolean defaultAllowSslConnectionPool() { - return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); + public static boolean defaultAllowPoolingSslConnections() { + return getBoolean(ASYNC_CLIENT + "allowPoolingSslConnections", true); } public static boolean defaultDisableUrlEncodingForBoundRequests() { diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index ad739b546a..25b9be4075 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -31,7 +31,6 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; /** * Simple implementation of {@link AsyncHttpClient} and it's related builders ({@link AsyncHttpClientConfig}, @@ -42,9 +41,9 @@ * {@link AsyncHandler} are required. As simple as: *

  * SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()
- * .setIdleConnectionInPoolTimeoutInMs(100)
+ * .setIdleConnectionInPoolTimeout(100)
  * .setMaximumConnectionsTotal(50)
- * .setRequestTimeoutInMs(5 * 60 * 1000)
+ * .setRequestTimeout(5 * 60 * 1000)
  * .setUrl(getTargetUrl())
  * .setHeader("Content-Type", "text/html").build();
  * 

@@ -500,28 +499,28 @@ public Builder setFollowRedirect(boolean followRedirect) { return this; } - public Builder setMaxConnectionsTotal(int defaultMaxTotalConnections) { - configBuilder.setMaxConnectionsTotal(defaultMaxTotalConnections); + public Builder setMaxConnections(int defaultMaxConnections) { + configBuilder.setMaxConnections(defaultMaxConnections); return this; } - public Builder setMaxConnectionsPerHost(int defaultMaxConnectionPerHost) { - configBuilder.setMaxConnectionsPerHost(defaultMaxConnectionPerHost); + public Builder setMaxConnectionsPerHost(int defaultMaxConnectionsPerHost) { + configBuilder.setMaxConnectionsPerHost(defaultMaxConnectionsPerHost); return this; } - public Builder setConnectionTimeoutInMs(int connectionTimeuot) { - configBuilder.setConnectionTimeoutInMs(connectionTimeuot); + public Builder setConnectionTimeout(int connectionTimeuot) { + configBuilder.setConnectionTimeout(connectionTimeuot); return this; } - public Builder setIdleConnectionInPoolTimeoutInMs(int defaultIdleConnectionInPoolTimeoutInMs) { - configBuilder.setIdleConnectionInPoolTimeoutInMs(defaultIdleConnectionInPoolTimeoutInMs); + public Builder setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) { + configBuilder.setPooledConnectionIdleTimeout(pooledConnectionIdleTimeout); return this; } - public Builder setRequestTimeoutInMs(int defaultRequestTimeoutInMs) { - configBuilder.setRequestTimeoutInMs(defaultRequestTimeoutInMs); + public Builder setRequestTimeout(int defaultRequestTimeout) { + configBuilder.setRequestTimeout(defaultRequestTimeout); return this; } @@ -540,13 +539,8 @@ public Builder setUserAgent(String userAgent) { return this; } - public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { - configBuilder.setAllowPoolingConnection(allowPoolingConnection); - return this; - } - - public Builder setScheduledExecutorService(ScheduledExecutorService reaper) { - configBuilder.setScheduledExecutorService(reaper); + public Builder setAllowPoolingConnections(boolean allowPoolingConnections) { + configBuilder.setAllowPoolingConnections(allowPoolingConnections); return this; } @@ -555,11 +549,6 @@ public Builder setExecutorService(ExecutorService applicationThreadPool) { return this; } - public Builder setSSLEngineFactory(SSLEngineFactory sslEngineFactory) { - configBuilder.setSSLEngineFactory(sslEngineFactory); - return this; - } - public Builder setSSLContext(final SSLContext sslContext) { configBuilder.setSSLContext(sslContext); return this; diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index 49ed3a4f45..d0066c2adf 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -138,11 +138,11 @@ public static String parseCharset(String contentType) { } public static String keepAliveHeaderValue(AsyncHttpClientConfig config) { - return config.isAllowPoolingConnection() ? "keep-alive" : "close"; + return config.isAllowPoolingConnections() ? "keep-alive" : "close"; } public static int requestTimeout(AsyncHttpClientConfig config, Request request) { - return request.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); + return request.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeout(); } public static boolean followRedirect(AsyncHttpClientConfig config, Request request) { diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index d8f8936d33..301074edc6 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -357,7 +357,7 @@ public Response onCompleted(Response response) throws Exception { // TODO: fix test @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncStatusHEADContentLenghtTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(120 * 1000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(120 * 1000).build()); try { final CountDownLatch l = new CountDownLatch(1); Request request = new RequestBuilder("HEAD").setUrl(getTargetUrl()).build(); @@ -1226,7 +1226,7 @@ public void onThrowable(Throwable t) { @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetDelayHandlerTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(5 * 1000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(5 * 1000).build()); try { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("LockThread", "true"); @@ -1486,7 +1486,7 @@ public void testAsyncHttpProviderConfig() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void idleRequestTimeoutTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(5000).setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(5000).setRequestTimeout(10000).build()); try { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("Content-Type", "application/x-www-form-urlencoded"); diff --git a/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java index cb532d74a9..13d54d417e 100644 --- a/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java @@ -211,7 +211,7 @@ protected void inspectException(Throwable t) { } private AsyncHttpClient newClient() { - return getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + return getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); } protected Future execute(AsyncHttpClient client, Server server, boolean preemptive) throws IOException { diff --git a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java index 2c0c3c553c..958361c6b2 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java @@ -350,7 +350,7 @@ public void basicAuthAsyncConfigTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void basicAuthFileNoKeepAliveTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(false).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(false).build()); try { Future f = client.preparePost(getTargetUrl())// diff --git a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java index 513786fc91..9f13a7b51b 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java @@ -81,7 +81,7 @@ public void multipleSSLRequestsTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleSSLWithoutCacheTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowSslConnectionPool(false).build()); + AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowPoolingSslConnections(false).build()); try { String body = "hello there"; c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); @@ -139,7 +139,7 @@ public void failInstantlyIfHostNamesDiffer() throws Exception { public boolean verify(String arg0, SSLSession arg1) { return false; } - }).setRequestTimeoutInMs(20000); + }).setRequestTimeout(20000); client = getAsyncHttpClient(builder.build()); diff --git a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java index 4dbc04bfb9..727e0d67a0 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java @@ -35,9 +35,9 @@ public abstract class BodyChunkTest extends AbstractBasicTest { public void negativeContentTypeTest() throws Exception { AsyncHttpClientConfig.Builder confbuilder = new AsyncHttpClientConfig.Builder(); - confbuilder = confbuilder.setConnectionTimeoutInMs(100); - confbuilder = confbuilder.setMaxConnectionsTotal(50); - confbuilder = confbuilder.setRequestTimeoutInMs(5 * 60 * 1000); // 5 minutes + confbuilder = confbuilder.setConnectionTimeout(100); + confbuilder = confbuilder.setMaxConnections(50); + confbuilder = confbuilder.setRequestTimeout(5 * 60 * 1000); // 5 minutes // Create client AsyncHttpClient client = getAsyncHttpClient(confbuilder.build()); diff --git a/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java index 2b7c26ee16..baf91d11e2 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java @@ -109,7 +109,7 @@ public AbstractHandler configureHandler() throws Exception { public AsyncHttpClientConfig getAsyncHttpClientConfig() { // for this test brevity's sake, we are limiting to 1 retries - return new AsyncHttpClientConfig.Builder().setMaxRequestRetry(0).setRequestTimeoutInMs(10000).build(); + return new AsyncHttpClientConfig.Builder().setMaxRequestRetry(0).setRequestTimeout(10000).build(); } @Test(groups = { "standalone", "default_provider" }) diff --git a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java index 8d8845faa7..0566ecdbaa 100644 --- a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java @@ -45,11 +45,11 @@ abstract public class ChunkingTest extends AbstractBasicTest { public void testCustomChunking() throws Exception { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); - bc.setAllowPoolingConnection(true); + bc.setAllowPoolingConnections(true); bc.setMaxConnectionsPerHost(1); - bc.setMaxConnectionsTotal(1); - bc.setConnectionTimeoutInMs(1000); - bc.setRequestTimeoutInMs(1000); + bc.setMaxConnections(1); + bc.setConnectionTimeout(1000); + bc.setRequestTimeout(1000); bc.setFollowRedirect(true); AsyncHttpClient c = getAsyncHttpClient(bc.build()); diff --git a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java index be3dc83020..86ea33b6dc 100644 --- a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java @@ -42,7 +42,7 @@ public abstract class ConnectionPoolTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnections() { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); int i; @@ -64,7 +64,7 @@ public void testMaxTotalConnections() { @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnectionsException() { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); int i; @@ -132,7 +132,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaxConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; @@ -160,7 +160,7 @@ public void multipleMaxConnectionOpenTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTestWithQuery() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaxConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; diff --git a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java index 470eeaaf8e..9783fc4fcf 100644 --- a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java @@ -62,7 +62,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutImageFile() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100 * 6000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100 * 6000).build()); try { Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", LARGE_IMAGE_FILE, "application/octet-stream", StandardCharsets.UTF_8.name())).execute().get(); assertEquals(response.getStatusCode(), 200); diff --git a/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java index 929ec24856..cefa7083aa 100644 --- a/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java @@ -61,7 +61,7 @@ public void setUpGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void idleStateTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(10 * 1000).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(10 * 1000).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { diff --git a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java index 31b6ddc359..4f626fd3f9 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java @@ -51,8 +51,8 @@ public void testMaxConnectionsWithinThreads() { String[] urls = new String[] { servletEndpointUri.toString(), servletEndpointUri.toString() }; - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000) - .setAllowPoolingConnection(true).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000) + .setAllowPoolingConnections(true).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); try { final Boolean[] caughtError = new Boolean[] { Boolean.FALSE }; diff --git a/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java index 245abb9de9..d12b98c613 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java @@ -39,7 +39,7 @@ public abstract class MaxTotalConnectionTest extends AbstractBasicTest { public void testMaxTotalConnectionsExceedingException() { String[] urls = new String[] { "http://google.com", "http://github.com/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); try { boolean caughtError = false; for (int i = 0; i < urls.length; i++) { @@ -61,7 +61,7 @@ public void testMaxTotalConnectionsExceedingException() { public void testMaxTotalConnections() { String[] urls = new String[] { "http://google.com", "http://lenta.ru" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(2).setMaxConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(2).setMaxConnectionsPerHost(1).build()); try { for (String url : urls) { try { @@ -82,7 +82,7 @@ public void testMaxTotalConnections() { public void testMaxTotalConnectionsCorrectExceptionHandling() { String[] urls = new String[] { "http://google.com", "http://github.com/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); try { List> futures = new ArrayList>(); boolean caughtError = false; diff --git a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java index 0e27a0fb86..8ce64afc51 100644 --- a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java @@ -56,8 +56,8 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Exception { } private AsyncHttpClient create() throws GeneralSecurityException { - final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnection(true).setConnectionTimeoutInMs(10000) - .setIdleConnectionInPoolTimeoutInMs(60000).setRequestTimeoutInMs(10000).setMaxConnectionsPerHost(-1).setMaxConnectionsTotal(-1); + final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnections(true).setConnectionTimeout(10000) + .setPooledConnectionIdleTimeout(60000).setRequestTimeout(10000).setMaxConnectionsPerHost(-1).setMaxConnections(-1); return getAsyncHttpClient(configBuilder.build()); } diff --git a/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java index f6cc5764ec..9063a8f87e 100644 --- a/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java @@ -115,7 +115,7 @@ public void testRequestTimeout() throws IOException { @Test(groups = { "standalone", "default_provider" }) public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100).build()); try { Future responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(-1).execute(); Response response = responseFuture.get(); @@ -132,7 +132,7 @@ public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { @Test(groups = { "standalone", "default_provider" }) public void testGlobalRequestTimeout() throws IOException { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100).build()); try { Future responseFuture = client.prepareGet(getTargetUrl()).execute(); Response response = responseFuture.get(2000, TimeUnit.MILLISECONDS); @@ -153,7 +153,7 @@ public void testGlobalRequestTimeout() throws IOException { public void testGlobalIdleTimeout() throws IOException { final long times[] = new long[] { -1, -1 }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).build()); try { Future responseFuture = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { @Override diff --git a/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java index 0d37f66e5c..51400e3040 100644 --- a/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java @@ -41,7 +41,7 @@ public void testPutLargeFile() throws Exception { int timeout = (int) file.length() / 1000; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(timeout).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(timeout).build()); try { Response response = client.preparePut(getTargetUrl()).setBody(file).execute().get(); assertEquals(response.getStatusCode(), 200); diff --git a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java index a52ccd4157..e3a1993058 100644 --- a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java @@ -99,7 +99,7 @@ public void handle(String s, Request r, HttpServletRequest req, HttpServletRespo @Test(timeOut = 10 * 60 * 1000, groups = "scalability") public void rc10kProblem() throws IOException, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxConnectionsPerHost(C10K).setAllowPoolingConnection(true).build()); + AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxConnectionsPerHost(C10K).setAllowPoolingConnections(true).build()); try { List> resps = new ArrayList>(C10K); int i = 0; diff --git a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java index 8241e49f4d..26bfbfc2f9 100644 --- a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java @@ -74,11 +74,11 @@ public void setUp() throws Exception { public void testGetRedirectFinalUrl() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// + .setAllowPoolingConnections(true)// .setMaxConnectionsPerHost(1)// - .setMaxConnectionsTotal(1)// - .setConnectionTimeoutInMs(1000)// - .setRequestTimeoutInMs(1000)// + .setMaxConnections(1)// + .setConnectionTimeout(1000)// + .setRequestTimeout(1000)// .setFollowRedirect(true)// .build(); diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index 36a735b610..f5b46b21fb 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -53,7 +53,7 @@ public abstract class RemoteSiteTest extends AbstractBasicTest { @Test(groups = { "online", "default_provider" }) public void testGoogleCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://www.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -64,7 +64,7 @@ public void testGoogleCom() throws Exception { @Test(groups = { "online", "default_provider" }) public void testMailGoogleCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://mail.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -77,7 +77,7 @@ public void testMailGoogleCom() throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) // FIXME public void testMicrosoftCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -90,7 +90,7 @@ public void testMicrosoftCom() throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) // FIXME public void testWwwMicrosoftCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://www.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -103,7 +103,7 @@ public void testWwwMicrosoftCom() throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) // FIXME public void testUpdateMicrosoftCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://update.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -115,7 +115,7 @@ public void testUpdateMicrosoftCom() throws Exception { @Test(groups = { "online", "default_provider" }) public void testGoogleComWithTimeout() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -154,8 +154,8 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) public void invalidStreamTest2() throws Exception { - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirect(true) - .setAllowPoolingConnection(false).setMaxRedirects(6).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).setFollowRedirect(true) + .setAllowPoolingConnections(false).setMaxRedirects(6).build(); AsyncHttpClient c = getAsyncHttpClient(config); try { diff --git a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java index c4aa459a2b..a7f4615795 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java @@ -49,8 +49,8 @@ public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void inpuStreamBodyConsumerTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(50).setRequestTimeout(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))); @@ -65,8 +65,8 @@ public void inpuStreamBodyConsumerTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void stringBuilderBodyConsumerTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(50).setRequestTimeout(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { StringBuilder s = new StringBuilder(); Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); @@ -82,8 +82,8 @@ public void stringBuilderBodyConsumerTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void byteArrayOutputStreamBodyConsumerTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(50).setRequestTimeout(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { ByteArrayOutputStream o = new ByteArrayOutputStream(10); Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new OutputStreamBodyConsumer(o)); @@ -117,8 +117,8 @@ public void requestByteArrayOutputStreamBodyConsumerTest() throws Exception { */ @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutZeroBytesFileTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(50).setRequestTimeout(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") .build(); try { File tmpfile = File.createTempFile("testPutZeroBytesFile", ".tmp"); diff --git a/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java b/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java index 3b1763e768..90ffb19938 100644 --- a/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java @@ -147,7 +147,7 @@ public void basicPutFileTest() throws Exception { File file = createTempFile(1024 * 100 * 10); int timeout = (int) (file.length() / 1000); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(timeout).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(timeout).build()); try { TransferCompletionHandler tl = new TransferCompletionHandler(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index b83618df63..f887b9624e 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java @@ -75,11 +75,11 @@ public class ConnectionManager { this.connectionPool = connectionPool; canDestroyPool = false; } else { - this.connectionPool = new ConnectionPool(config.getMaxConnectionPerHost(),// - config.getMaxTotalConnections(),// + this.connectionPool = new ConnectionPool(config.getMaxConnectionsPerHost(),// + config.getMaxConnections(),// null,// - config.getConnectionTimeoutInMs(),// - config.getIdleConnectionInPoolTimeoutInMs(),// + config.getConnectionTimeout(),// + config.getPooledConnectionIdleTimeout(),// 2000); canDestroyPool = true; } @@ -211,7 +211,7 @@ private static int getPort(final UriComponents uri, final int p) { private Connection obtainConnection0(final Request request, final GrizzlyResponseFuture requestFuture) throws ExecutionException, InterruptedException, TimeoutException, IOException { - final int cTimeout = provider.getClientConfig().getConnectionTimeoutInMs(); + final int cTimeout = provider.getClientConfig().getConnectionTimeout(); final FutureImpl future = Futures.createSafeFuture(); final CompletionHandler ch = Futures.toCompletionHandler(future, createConnectionCompletionHandler(request, requestFuture, null)); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index dd8d457fd6..620606a399 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -277,7 +277,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { ws.onConnect(); WebSocketHolder.set(ctx.getConnection(), context.getProtocolHandler(), ws); ((WebSocketUpgradeHandler) context.getHandler()).onSuccess(context.getWebSocket()); - final int wsTimeout = context.getProvider().getClientConfig().getWebSocketIdleTimeoutInMs(); + final int wsTimeout = context.getProvider().getClientConfig().getWebSocketReadTimeout(); IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), ((wsTimeout <= 0) ? IdleTimeoutFilter.FOREVER : wsTimeout), TimeUnit.MILLISECONDS); context.result(handler.onCompleted()); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index fa6a759e53..3bc8ed5f80 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -214,7 +214,7 @@ void initializeTransport(final AsyncHttpClientConfig clientConfig) { final FilterChainBuilder secure = FilterChainBuilder.stateless(); secure.add(new TransportFilter()); - final int timeout = clientConfig.getRequestTimeoutInMs(); + final int timeout = clientConfig.getRequestTimeout(); if (timeout > 0) { int delay = 500; //noinspection ConstantConditions @@ -232,7 +232,7 @@ public long getTimeout(FilterChainContext ctx) { final HttpTxContext context = HttpTxContext.get(ctx); if (context != null) { if (context.isWSRequest()) { - return clientConfig.getWebSocketIdleTimeoutInMs(); + return clientConfig.getWebSocketReadTimeout(); } int requestTimeout = AsyncHttpProviderUtils.requestTimeout(clientConfig, context.getRequest()); if (requestTimeout > 0) { diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java index acf6c92a3a..be0aed7b7f 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java @@ -40,8 +40,8 @@ public void testMaxTotalConnectionsException() { @Override @Test public void multipleMaxConnectionOpenTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000) - .setMaxConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000) + .setMaxConnections(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 1aac4fcfce..2beca1a78f 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -135,7 +135,7 @@ private void doSimpleFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) - .setMaxConnectionsTotal(60) + .setMaxConnections(60) .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = @@ -238,7 +238,7 @@ private void doNonBlockingFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) - .setMaxConnectionsTotal(60) + .setMaxConnections(60) .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java index ea02d5fc57..116a186459 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java @@ -87,9 +87,9 @@ public void testNoTransferEncoding() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setCompressionEnabled(true) .setFollowRedirect(false) - .setConnectionTimeoutInMs(15000) - .setRequestTimeoutInMs(15000) - .setAllowPoolingConnection(false) + .setConnectionTimeout(15000) + .setRequestTimeout(15000) + .setAllowPoolingConnections(false) .setDisableUrlEncodingForBoundRequests(true) .setIOThreadMultiplier(2) // 2 is default .build(); diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java index 743255d00b..3829983aae 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java @@ -82,7 +82,7 @@ public void unexpectingTimeoutTest() throws IOException { final AtomicInteger counts = new AtomicInteger(); final int timeout = 100; - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(timeout).build()); + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(timeout).build()); try { Future responseFuture = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { @Override diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 637a619c6f..dd36702b85 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -31,7 +31,7 @@ public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); private final ChannelPool channelPool; - private final boolean maxTotalConnectionsEnabled; + private final boolean maxConnectionsEnabled; private final Semaphore freeChannels; private final ChannelGroup openChannels; private final int maxConnectionsPerHost; @@ -42,9 +42,9 @@ public class ChannelManager { public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { this.channelPool = channelPool; - maxTotalConnectionsEnabled = config.getMaxTotalConnections() > 0; + maxConnectionsEnabled = config.getMaxConnections() > 0; - if (maxTotalConnectionsEnabled) { + if (maxConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @Override public boolean remove(Object o) { @@ -63,14 +63,14 @@ public boolean remove(Object o) { return removed; } }; - freeChannels = new Semaphore(config.getMaxTotalConnections()); + freeChannels = new Semaphore(config.getMaxConnections()); } else { openChannels = new CleanupChannelGroup("asyncHttpClient"); freeChannels = null; } - maxConnectionsPerHost = config.getMaxConnectionPerHost(); - maxConnectionsPerHostEnabled = config.getMaxConnectionPerHost() > 0; + maxConnectionsPerHost = config.getMaxConnectionsPerHost(); + maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; if (maxConnectionsPerHostEnabled) { freeChannelsPerHost = new ConcurrentHashMap(); @@ -103,7 +103,7 @@ public boolean removeAll(Channel connection) { } private boolean tryAcquireGlobal() { - return !maxTotalConnectionsEnabled || freeChannels.tryAcquire(); + return !maxConnectionsEnabled || freeChannels.tryAcquire(); } private Semaphore getFreeConnectionsForHost(String poolKey) { @@ -156,7 +156,7 @@ public void closeChannel(Channel channel) { } public void abortChannelPreemption(String poolKey) { - if (maxTotalConnectionsEnabled) + if (maxConnectionsEnabled) freeChannels.release(); if (maxConnectionsPerHostEnabled) getFreeConnectionsForHost(poolKey).release(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 54376e29b1..304d2d7931 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -126,7 +126,7 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig ChannelPool cp = nettyProviderConfig.getChannelPool(); if (cp == null) { - if (config.isAllowPoolingConnection()) { + if (config.isAllowPoolingConnections()) { cp = new DefaultChannelPool(config, nettyTimer); } else { cp = new NoopChannelPool(); @@ -143,7 +143,7 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig secureWebSocketBootstrap.option(key, value); } - int timeOut = config.getConnectionTimeoutInMs() > 0 ? config.getConnectionTimeoutInMs() : Integer.MAX_VALUE; + int timeOut = config.getConnectionTimeout() > 0 ? config.getConnectionTimeout() : Integer.MAX_VALUE; plainBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); webSocketBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); secureBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); @@ -340,7 +340,7 @@ public boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) thro if (channelManager.preemptChannel(poolKey)) { channelPreempted = true; } else { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); try { asyncHandler.onThrowable(ex); } catch (Exception e) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index f46a63d310..88e9b72556 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java @@ -53,10 +53,10 @@ public final class DefaultChannelPool implements ChannelPool { private final long cleanerPeriod; public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { - this(config.getMaxConnectionPerHost(),// - config.getIdleConnectionInPoolTimeoutInMs(),// - config.getMaxConnectionLifeTimeInMs(),// - config.isSslConnectionPoolEnabled(),// + this(config.getMaxConnectionsPerHost(),// + config.getPooledConnectionIdleTimeout(),// + config.getConnectionTTL(),// + config.isAllowPoolingSslConnections(),// hashedWheelTimer); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index ff18a9d5b8..5997c6b77d 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -230,7 +230,7 @@ private ListenableFuture sendRequestWithNewChannel(// // only compute when maxConnectionPerHost is enabled // FIXME clean up - if (config.getMaxConnectionPerHost() > 0) + if (config.getMaxConnectionsPerHost() > 0) poolKey = channels.getPoolKey(future); channelPreempted = channels.preemptChannel(asyncHandler, poolKey); @@ -390,11 +390,11 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { timeoutsHolder.requestTimeout = requestTimeout; } - int idleConnectionTimeoutInMs = config.getIdleConnectionTimeoutInMs(); - if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs < requestTimeoutInMs) { + int readTimeout = config.getReadTimeout(); + if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs Timeout idleConnectionTimeout = channels.newTimeoutInMs(new IdleConnectionTimeoutTimerTask(nettyResponseFuture, channels, - timeoutsHolder, closed, requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); + timeoutsHolder, closed, requestTimeoutInMs, readTimeout), readTimeout); timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; } nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java index ef02fa7896..6c333eae1b 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java @@ -82,7 +82,7 @@ public void testRequestTimeout() throws IOException { final Semaphore requestThrottle = new Semaphore(1); final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setCompressionEnabled(true) - .setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); + .setAllowPoolingConnections(true).setMaxConnections(1).build()); int samples = 10; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java index 7c29f993e3..c5d1798595 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java @@ -88,10 +88,10 @@ private ListenableFuture testMethodRequest(AsyncHttpClient client, int public void testRetryNonBlocking() throws IOException, InterruptedException, ExecutionException { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaxConnectionsTotal(100)// - .setConnectionTimeoutInMs(60000)// - .setRequestTimeoutInMs(30000)// + .setAllowPoolingConnections(true)// + .setMaxConnections(100)// + .setConnectionTimeout(60000)// + .setRequestTimeout(30000)// .build(); AsyncHttpClient client = getAsyncHttpClient(config); @@ -124,10 +124,10 @@ public void testRetryNonBlocking() throws IOException, InterruptedException, Exe public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedException, ExecutionException { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaxConnectionsTotal(100)// - .setConnectionTimeoutInMs(60000)// - .setRequestTimeoutInMs(30000)// + .setAllowPoolingConnections(true)// + .setMaxConnections(100)// + .setConnectionTimeout(60000)// + .setRequestTimeout(30000)// .build(); AsyncHttpClient client = getAsyncHttpClient(config); From 800cd02544d6ca0ab926f9af1c8c7ada41397ab1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:16:10 +0200 Subject: [PATCH 0018/1949] Rename webSocketReadTimeout into webSocketTimeout --- .../AsyncHttpClientConfig.java | 20 +++++++++---------- .../AsyncHttpClientConfigBean.java | 2 +- .../AsyncHttpClientConfigDefaults.java | 4 ++-- .../providers/grizzly/EventHandler.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 265008c2bb..5146b997a6 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -73,7 +73,7 @@ public class AsyncHttpClientConfig { protected int requestTimeout; protected int readTimeout; - protected int webSocketReadTimeout; + protected int webSocketTimeout; protected boolean allowPoolingConnections; protected boolean allowPoolingSslConnections; @@ -118,7 +118,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// int maxConnectionsPerHost,// int requestTimeout,// int readTimeout,// - int webSocketIdleTimeout,// + int webSocketTimeout,// boolean allowPoolingConnection,// boolean allowSslConnectionPool,// int idleConnectionInPoolTimeout,// @@ -153,7 +153,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// this.maxConnectionsPerHost = maxConnectionsPerHost; this.requestTimeout = requestTimeout; this.readTimeout = readTimeout; - this.webSocketReadTimeout = webSocketIdleTimeout; + this.webSocketTimeout = webSocketTimeout; this.allowPoolingConnections = allowPoolingConnection; this.allowPoolingSslConnections = allowSslConnectionPool; this.pooledConnectionIdleTimeout = idleConnectionInPoolTimeout; @@ -216,8 +216,8 @@ public int getConnectionTimeout() { * Return the maximum time, in milliseconds, a {@link org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. * @return the maximum time, in milliseconds, a {@link org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. */ - public int getWebSocketReadTimeout() { - return webSocketReadTimeout; + public int getWebSocketTimeout() { + return webSocketTimeout; } /** @@ -532,7 +532,7 @@ public static class Builder { private int maxConnectionsPerHost = defaultMaxConnectionsPerHost(); private int requestTimeout = defaultRequestTimeout(); private int readTimeout = defaultReadTimeout(); - private int webSocketReadTimeout = defaultWebSocketReadTimeout(); + private int webSocketTimeout = defaultWebSocketTimeout(); private boolean allowPoolingConnections = defaultAllowPoolingConnections(); private boolean allowPoolingSslConnections = defaultAllowPoolingSslConnections(); private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); @@ -605,12 +605,12 @@ public Builder setConnectionTimeout(int connectionTimeout) { /** * Set the maximum time in millisecond an {@link org.asynchttpclient.websocket.WebSocket} can stay idle. * - * @param webSocketIdleTimeout + * @param webSocketTimeout * the maximum time in millisecond an {@link org.asynchttpclient.websocket.WebSocket} can stay idle. * @return a {@link Builder} */ - public Builder setWebSocketReadTimeout(int webSocketReadTimeout) { - this.webSocketReadTimeout = webSocketReadTimeout; + public Builder setWebSocketTimeout(int webSocketTimeout) { + this.webSocketTimeout = webSocketTimeout; return this; } @@ -1099,7 +1099,7 @@ public AsyncHttpClientConfig build() { maxConnectionsPerHost,// requestTimeout,// readTimeout,// - webSocketReadTimeout,// + webSocketTimeout,// allowPoolingConnections,// allowPoolingSslConnections,// pooledConnectionIdleTimeout,// diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index e276b9f10a..d68c6a8984 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -48,7 +48,7 @@ void configureDefaults() { maxConnections = defaultMaxConnections(); maxConnectionsPerHost = defaultMaxConnectionsPerHost(); connectionTimeout = defaultConnectionTimeout(); - webSocketReadTimeout = defaultWebSocketReadTimeout(); + webSocketTimeout = defaultWebSocketTimeout(); pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); readTimeout = defaultReadTimeout(); requestTimeout = defaultRequestTimeout(); diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index e64f1a54b5..8ecd353491 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -49,8 +49,8 @@ public static int defaultRequestTimeout() { return Integer.getInteger(ASYNC_CLIENT + "requestTimeout", 60 * 1000); } - public static int defaultWebSocketReadTimeout() { - return Integer.getInteger(ASYNC_CLIENT + "webSocketReadTimeout", 15 * 60 * 1000); + public static int defaultWebSocketTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "webSocketTimeout", 15 * 60 * 1000); } public static int defaultConnectionTTL() { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 620606a399..6a99e9335a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -277,7 +277,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { ws.onConnect(); WebSocketHolder.set(ctx.getConnection(), context.getProtocolHandler(), ws); ((WebSocketUpgradeHandler) context.getHandler()).onSuccess(context.getWebSocket()); - final int wsTimeout = context.getProvider().getClientConfig().getWebSocketReadTimeout(); + final int wsTimeout = context.getProvider().getClientConfig().getWebSocketTimeout(); IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), ((wsTimeout <= 0) ? IdleTimeoutFilter.FOREVER : wsTimeout), TimeUnit.MILLISECONDS); context.result(handler.onCompleted()); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 3bc8ed5f80..9215900d30 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -232,7 +232,7 @@ public long getTimeout(FilterChainContext ctx) { final HttpTxContext context = HttpTxContext.get(ctx); if (context != null) { if (context.isWSRequest()) { - return clientConfig.getWebSocketReadTimeout(); + return clientConfig.getWebSocketTimeout(); } int requestTimeout = AsyncHttpProviderUtils.requestTimeout(clientConfig, context.getRequest()); if (requestTimeout > 0) { From 6e340549e2591e52684d450199cdceaceedd71ba Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:25:52 +0200 Subject: [PATCH 0019/1949] Rename IdleConnectionTimeout into ReadTimeout --- .../netty/request/NettyRequestSender.java | 6 ++--- ...merTask.java => ReadTimeoutTimerTask.java} | 24 +++++++++---------- .../netty/request/timeout/TimeoutsHolder.java | 8 +++---- 3 files changed, 19 insertions(+), 19 deletions(-) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/{IdleConnectionTimeoutTimerTask.java => ReadTimeoutTimerTask.java} (71%) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 5997c6b77d..79b76edb3d 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -33,7 +33,7 @@ import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.timeout.IdleConnectionTimeoutTimerTask; +import org.asynchttpclient.providers.netty.request.timeout.ReadTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.RequestTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; import org.asynchttpclient.uri.UriComponents; @@ -393,9 +393,9 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { int readTimeout = config.getReadTimeout(); if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs - Timeout idleConnectionTimeout = channels.newTimeoutInMs(new IdleConnectionTimeoutTimerTask(nettyResponseFuture, channels, + Timeout idleConnectionTimeout = channels.newTimeoutInMs(new ReadTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, closed, requestTimeoutInMs, readTimeout), readTimeout); - timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; + timeoutsHolder.readTimeout = idleConnectionTimeout; } nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); } catch (RejectedExecutionException ex) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java similarity index 71% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java index bea473c9d8..6199c9cd9b 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -24,20 +24,20 @@ import java.util.concurrent.atomic.AtomicBoolean; -public class IdleConnectionTimeoutTimerTask extends TimeoutTimerTask { +public class ReadTimeoutTimerTask extends TimeoutTimerTask { - private final long idleConnectionTimeout; + private final long readTimeout; private final long requestTimeoutInstant; - public IdleConnectionTimeoutTimerTask(// + public ReadTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// Channels channels,// TimeoutsHolder timeoutsHolder,// AtomicBoolean clientClosed,// long requestTimeout,// - long idleConnectionTimeout) { + long readTimeout) { super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); - this.idleConnectionTimeout = idleConnectionTimeout; + this.readTimeout = readTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; } @@ -52,23 +52,23 @@ public void run(Timeout timeout) throws Exception { long now = millisTime(); - long currentIdleConnectionTimeoutInstant = idleConnectionTimeout + nettyResponseFuture.getLastTouch(); - long durationBeforeCurrentIdleConnectionTimeout = currentIdleConnectionTimeoutInstant - now; + long currentReadTimeoutInstant = readTimeout + nettyResponseFuture.getLastTouch(); + long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; - if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { + if (durationBeforeCurrentReadTimeout <= 0L) { // idleConnectionTimeout reached - String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + idleConnectionTimeout + " ms"; + String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); expire(message, durationSinceLastTouch); nettyResponseFuture.setIdleConnectionTimeoutReached(); - } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { + } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.idleConnectionTimeout = channels.newTimeoutInMs(this, durationBeforeCurrentIdleConnectionTimeout); + timeoutsHolder.readTimeout = channels.newTimeoutInMs(this, durationBeforeCurrentReadTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner - timeoutsHolder.idleConnectionTimeout = null; + timeoutsHolder.readTimeout = null; } } else { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java index a27e903510..d032672a4a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java @@ -23,7 +23,7 @@ public class TimeoutsHolder { private final AtomicBoolean cancelled = new AtomicBoolean(); public volatile Timeout requestTimeout; - public volatile Timeout idleConnectionTimeout; + public volatile Timeout readTimeout; public void cancel() { if (cancelled.compareAndSet(false, true)) { @@ -31,9 +31,9 @@ public void cancel() { requestTimeout.cancel(); requestTimeout = null; } - if (idleConnectionTimeout != null) { - idleConnectionTimeout.cancel(); - idleConnectionTimeout = null; + if (readTimeout != null) { + readTimeout.cancel(); + readTimeout = null; } } } From 1fb3b426ef513a76b4d4a64f09d999b597dd136c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Jul 2014 16:42:01 +0200 Subject: [PATCH 0020/1949] Unused parameter --- .../providers/netty/channel/pool/DefaultChannelPool.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index 88e9b72556..3a04157660 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java @@ -53,15 +53,13 @@ public final class DefaultChannelPool implements ChannelPool { private final long cleanerPeriod; public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { - this(config.getMaxConnectionsPerHost(),// - config.getPooledConnectionIdleTimeout(),// + this(config.getPooledConnectionIdleTimeout(),// config.getConnectionTTL(),// config.isAllowPoolingSslConnections(),// hashedWheelTimer); } - public DefaultChannelPool(// - int maxConnectionPerHost,// + public DefaultChannelPool( long maxIdleTime,// int maxConnectionTTL,// boolean sslConnectionPoolEnabled,// From d091dfb6cc011cd77b0ee23cb7d09a93170b9bc6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 13:05:57 +0200 Subject: [PATCH 0021/1949] Minor clean up --- .../netty/future/StackTraceInspector.java | 38 +++++++++---------- .../netty/request/NettyConnectListener.java | 13 +++---- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java index 94abc067b2..80d99fa1be 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java @@ -14,57 +14,57 @@ public class StackTraceInspector { - private static boolean exceptionInMethod(Throwable cause, String className, String methodName) { + private static boolean exceptionInMethod(Throwable t, String className, String methodName) { try { - for (StackTraceElement element : cause.getStackTrace()) { + for (StackTraceElement element : t.getStackTrace()) { if (element.getClassName().equals(className) && element.getMethodName().equals(methodName)) return true; } - } catch (Throwable t) { + } catch (Throwable ignore) { } return false; } - private static boolean abortOnConnectCloseException(Throwable cause) { + private static boolean abortOnConnectCloseException(Throwable t) { - if (exceptionInMethod(cause, "sun.nio.ch.SocketChannelImpl", "checkConnect")) + if (exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect")) return true; - if (cause.getCause() != null) - return abortOnConnectCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnConnectCloseException(t.getCause()); return false; } - public static boolean abortOnDisconnectException(Throwable cause) { + public static boolean abortOnDisconnectException(Throwable t) { - if (exceptionInMethod(cause, "io.netty.handler.ssl.SslHandler", "disconnect")) + if (exceptionInMethod(t, "io.netty.handler.ssl.SslHandler", "disconnect")) return true; - if (cause.getCause() != null) - return abortOnConnectCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnConnectCloseException(t.getCause()); return false; } - public static boolean abortOnReadCloseException(Throwable cause) { + public static boolean abortOnReadCloseException(Throwable t) { - if (exceptionInMethod(cause, "sun.nio.ch.SocketDispatcher", "read")) + if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "read")) return true; - if (cause.getCause() != null) - return abortOnReadCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnReadCloseException(t.getCause()); return false; } - public static boolean abortOnWriteCloseException(Throwable cause) { + public static boolean abortOnWriteCloseException(Throwable t) { - if (exceptionInMethod(cause, "sun.nio.ch.SocketDispatcher", "write")) + if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "write")) return true; - if (cause.getCause() != null) - return abortOnWriteCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnWriteCloseException(t.getCause()); return false; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 05b36fd230..c1ca441e1f 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -124,7 +124,7 @@ public void onFutureFailure(Channel channel, Throwable cause) { LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", channel, canRetry); if (canRetry// && cause != null// - && (StackTraceInspector.abortOnDisconnectException(cause) || cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW)) { + && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { LOGGER.debug("Retrying {} ", future.getNettyRequest()); if (requestSender.retry(future, channel)) { @@ -135,19 +135,18 @@ public void onFutureFailure(Channel channel, Throwable cause) { LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, channel); boolean printCause = cause != null && cause.getMessage() != null; - String printedCause = printCause ? cause.getMessage() + " to " + future.getURI().toString() : future.getURI().toString(); + String url = future.getURI().toUrl(); + String printedCause = printCause ? cause.getMessage() + " to " + url : url; ConnectException e = new ConnectException(printedCause); - if (cause != null) { + if (cause != null) e.initCause(cause); - } future.abort(e); } public final void operationComplete(ChannelFuture f) throws Exception { - if (f.isSuccess()) { + if (f.isSuccess()) onFutureSuccess(f.channel()); - } else { + else onFutureFailure(f.channel(), f.cause()); - } } } From e507109646ce70df7e6b095e5dab5ad563f42b8f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 13:28:19 +0200 Subject: [PATCH 0022/1949] Optimize stack scan, close #635 --- .../netty/future/StackTraceInspector.java | 26 ++++++++----------- .../providers/netty/handler/Processor.java | 2 +- .../netty/request/ProgressListener.java | 3 +-- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java index 80d99fa1be..d47878b419 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java @@ -47,24 +47,20 @@ public static boolean abortOnDisconnectException(Throwable t) { return false; } - public static boolean abortOnReadCloseException(Throwable t) { + public static boolean abortOnReadOrWriteException(Throwable t) { - if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "read")) - return true; - - if (t.getCause() != null) - return abortOnReadCloseException(t.getCause()); - - return false; - } - - public static boolean abortOnWriteCloseException(Throwable t) { - - if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "write")) - return true; + try { + for (StackTraceElement element : t.getStackTrace()) { + String className = element.getClassName(); + String methodName = element.getMethodName(); + if (className.equals("sun.nio.ch.SocketDispatcher") && (methodName.equals("read") || methodName.equals("write"))) + return true; + } + } catch (Throwable ignore) { + } if (t.getCause() != null) - return abortOnWriteCloseException(t.getCause()); + return abortOnReadOrWriteException(t.getCause()); return false; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 7c69daeba7..f1d6a1d3e0 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -183,7 +183,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep } } - if (StackTraceInspector.abortOnReadCloseException(cause) || StackTraceInspector.abortOnWriteCloseException(cause)) { + if (StackTraceInspector.abortOnReadOrWriteException(cause)) { LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java index ad31a075bc..78c9f35919 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java @@ -61,8 +61,7 @@ private boolean abortOnThrowable(Throwable cause, Channel channel) { } catch (RuntimeException ex) { LOGGER.debug(ex.getMessage(), ex); } - } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadCloseException(cause) - || StackTraceInspector.abortOnWriteCloseException(cause)) { + } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { if (LOGGER.isDebugEnabled()) LOGGER.debug(cause.getMessage(), cause); From e1c7f4aeef9e07c98d33f8d1121dbd77559efb6b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 13:32:18 +0200 Subject: [PATCH 0023/1949] minor clean up --- .../netty/future/StackTraceInspector.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java index d47878b419..f4a6589768 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java @@ -26,25 +26,13 @@ private static boolean exceptionInMethod(Throwable t, String className, String m } private static boolean abortOnConnectCloseException(Throwable t) { - - if (exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect")) - return true; - - if (t.getCause() != null) - return abortOnConnectCloseException(t.getCause()); - - return false; + return exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect") + || (t.getCause() != null && abortOnConnectCloseException(t.getCause())); } public static boolean abortOnDisconnectException(Throwable t) { - - if (exceptionInMethod(t, "io.netty.handler.ssl.SslHandler", "disconnect")) - return true; - - if (t.getCause() != null) - return abortOnConnectCloseException(t.getCause()); - - return false; + return exceptionInMethod(t, "io.netty.handler.ssl.SslHandler", "disconnect") + || (t.getCause() != null && abortOnConnectCloseException(t.getCause())); } public static boolean abortOnReadOrWriteException(Throwable t) { From c3589e01b878030dddad8ebefb8ed5eef8a375fc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 14:32:55 +0200 Subject: [PATCH 0024/1949] NettyResponseFuture.get should always block on the latch, close #489 --- .../providers/netty/future/NettyResponseFuture.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 1418c3c4a5..9d2a692f77 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -156,14 +156,13 @@ public boolean cancel(boolean force) { @Override public V get() throws InterruptedException, ExecutionException { - if (!isDone()) - latch.await(); + latch.await(); return getContent(); } @Override public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, ExecutionException { - if (!isDone() && !latch.await(l, tu)) + if (!latch.await(l, tu)) throw new TimeoutException(); return getContent(); } From 4ae7bc92e8a7b0e6b45e535ac2488bd1e8b929ff Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 15:01:30 +0200 Subject: [PATCH 0025/1949] minor clean up --- .../util/AuthenticatorUtils.java | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index 594eafa1a3..0da1666af1 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -50,38 +50,30 @@ private static String computeRealmURI(Realm realm) { public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException { StringBuilder builder = new StringBuilder().append("Digest "); - construct(builder, "username", realm.getPrincipal()); - construct(builder, "realm", realm.getRealmName()); - construct(builder, "nonce", realm.getNonce()); - construct(builder, "uri", computeRealmURI(realm)); - builder.append("algorithm").append('=').append(realm.getAlgorithm()).append(", "); + append(builder, "username", realm.getPrincipal(), true); + append(builder, "realm", realm.getRealmName(), true); + append(builder, "nonce", realm.getNonce(), true); + append(builder, "uri", computeRealmURI(realm), true); + append(builder, "algorithm", realm.getAlgorithm(), false); - construct(builder, "response", realm.getResponse()); + append(builder, "response", realm.getResponse(), true); if (isNonEmpty(realm.getOpaque())) - construct(builder, "opaque", realm.getOpaque()); - builder.append("qop").append('=').append(realm.getQop()).append(", "); - builder.append("nc").append('=').append(realm.getNc()).append(", "); - construct(builder, "cnonce", realm.getCnonce(), true); + append(builder, "opaque", realm.getOpaque(), true); + append(builder, "qop", realm.getQop(), false); + append(builder, "nc", realm.getNc(), false); + append(builder, "cnonce", realm.getCnonce(), true); + builder.setLength(builder.length() - 2); // remove tailing ", " return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); } - public static String computeDigestAuthentication(ProxyServer proxy) { - try { - StringBuilder builder = new StringBuilder().append("Digest "); - construct(builder, "username", proxy.getPrincipal(), true); - return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private static StringBuilder construct(StringBuilder builder, String name, String value) { - return construct(builder, name, value, false); - } + private static StringBuilder append(StringBuilder builder, String name, String value, boolean quoted) { + builder.append(name).append('='); + if (quoted) + builder.append('"').append(value).append('"'); + else + builder.append(value); - private static StringBuilder construct(StringBuilder builder, String name, String value, boolean tail) { - return builder.append(name).append('=').append('"').append(value).append(tail ? "\"" : "\", "); + return builder.append(", "); } } From 399d78c9dd79d30d3e5e63363d1e27ad1bd2cd84 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 22 Jul 2014 11:58:28 -0700 Subject: [PATCH 0026/1949] [master] + fix issue #637 https://github.com/AsyncHttpClient/async-http-client/issues/637 "AHC with Grizzly provider not handling SSL Connect/tunnelling with Proxy" --- .../providers/grizzly/EventHandler.java | 15 +++++++++++++++ .../filters/AsyncHttpClientEventFilter.java | 8 ++++++++ .../providers/grizzly/filters/ProxyFilter.java | 2 +- .../providers/grizzly/filters/TunnelFilter.java | 4 ++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 6a99e9335a..2de816a312 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -55,6 +55,8 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.http.HttpRequestPacket; public final class EventHandler { @@ -304,6 +306,19 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { } + public boolean onHttpHeaderParsed(final HttpHeader httpHeader, + final Buffer buffer, final FilterChainContext ctx) { + final HttpRequestPacket request = ((HttpResponsePacket) httpHeader).getRequest(); + if (Method.CONNECT.equals(request.getMethod())) { + // finish request/response processing, because Grizzly itself + // treats CONNECT traffic as part of request-response processing + // and we don't want it be treated like that + httpHeader.setExpectContent(false); + } + + return false; + } + @SuppressWarnings("rawtypes") public boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java index 6afb87197a..687984e6a8 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java @@ -22,6 +22,7 @@ import java.io.IOException; import org.asynchttpclient.providers.grizzly.filters.events.GracefulCloseEvent; +import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.filterchain.FilterChainEvent; import org.glassfish.grizzly.filterchain.NextAction; import org.glassfish.grizzly.http.HttpResponsePacket; @@ -111,6 +112,13 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx eventHandler.onHttpHeadersParsed(httpHeader, ctx); } + @Override + protected boolean onHttpHeaderParsed(final HttpHeader httpHeader, + final Buffer buffer, final FilterChainContext ctx) { + super.onHttpHeaderParsed(httpHeader, buffer, ctx); + return eventHandler.onHttpHeaderParsed(httpHeader, buffer, ctx); + } + @Override protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) { return eventHandler.onHttpPacketParsed(httpHeader, ctx); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java index ded8031daf..4b30c7c6cf 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java @@ -100,7 +100,7 @@ private String generateAuthHeader(final Realm realm) { case BASIC: return computeBasicAuthentication(realm); case DIGEST: - return computeDigestAuthentication(proxyServer); + return computeDigestAuthentication(realm); case NTLM: return NTLM_ENGINE.generateType1Msg("NTLM " + realm.getNtlmDomain(), realm.getNtlmHost()); default: diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java index ed9723fa96..aae301883f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Sonatype, Inc. All rights reserved. + * Copyright (c) 2013-2014 Sonatype, Inc. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. @@ -94,7 +94,7 @@ public NextAction handleEvent(FilterChainContext ctx, FilterChainEvent event) th suspendedContext.resume(ctx.getInvokeAction()); // Stop further event processing. - ctx.getStopAction(); + return ctx.getStopAction(); } return ctx.getInvokeAction(); } From 34a95f04c22198b6575c9fd82f0f2ef117e1cbed Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 22 Jul 2014 21:37:16 -0700 Subject: [PATCH 0027/1949] [master] + fix issue #631 https://github.com/AsyncHttpClient/async-http-client/issues/631 "Grizzly provider aggressively set cookie missing domain and path to /" --- .../providers/grizzly/EventHandler.java | 6 +++--- .../grizzly/filters/AsyncHttpClientFilter.java | 12 ++++-------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 2de816a312..50675690ac 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -185,7 +185,7 @@ public void onInitialLineParsed(HttpHeader httpHeader, FilterChainContext ctx) { try { context.result(handler.onCompleted()); context.done(); - } catch (Exception e) { + } catch (Throwable e) { context.abort(e); } } @@ -289,7 +289,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { "WebSocket protocol error: unexpected HTTP response status during handshake."); context.result(null); } - } catch (Exception e) { + } catch (Throwable e) { httpHeader.setSkipRemainder(true); context.abort(e); } @@ -341,7 +341,7 @@ public boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) if (handler != null) { try { context.result(handler.onCompleted()); - } catch (Exception e) { + } catch (Throwable e) { context.abort(e); } } else { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 21dc88c516..7d7f002699 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -520,17 +520,13 @@ private void addCookies(final Request request, final HttpRequestPacket requestPa } } - private static void convertCookies(final Collection cookies, final org.glassfish.grizzly.http.Cookie[] gCookies) { + private static void convertCookies(final Collection cookies, + final org.glassfish.grizzly.http.Cookie[] gCookies) { int idx = 0; if (!cookies.isEmpty()) { for (final Cookie cookie : cookies) { - final org.glassfish.grizzly.http.Cookie gCookie = new org.glassfish.grizzly.http.Cookie(cookie.getName(), cookie.getValue()); - gCookie.setDomain(cookie.getDomain()); - gCookie.setPath(cookie.getPath()); - gCookie.setMaxAge(cookie.getMaxAge()); - gCookie.setSecure(cookie.isSecure()); - gCookies[idx] = gCookie; - idx++; + gCookies[idx++] = new org.glassfish.grizzly.http.Cookie( + cookie.getName(), cookie.getValue()); } } } From dd92f36a0ff9cfa56d5b93aec9a24e7adfcfd1c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 23 Jul 2014 18:26:23 +0200 Subject: [PATCH 0028/1949] Make AHC 1.9 and AHC2 code converge, close #638 --- .../providers/netty/DiscardEvent.java | 0 .../netty/NettyAsyncHttpProvider.java | 56 +- .../netty/NettyAsyncHttpProviderConfig.java | 51 +- .../netty/channel/ChannelManager.java | 298 ++++++++- .../providers/netty/channel/Channels.java | 406 +------------ .../CleanupChannelGroup.java | 2 +- .../netty/channel/SslInitializer.java | 10 +- .../netty/channel/pool/ChannelPool.java | 21 +- .../channel/pool/DefaultChannelPool.java | 0 .../netty/channel/pool/NoopChannelPool.java | 20 +- .../netty/future/NettyResponseFuture.java | 54 +- .../netty/future/StackTraceInspector.java | 0 .../providers/netty/handler/HttpProtocol.java | 318 +++++----- .../providers/netty/handler/Processor.java | 127 ++-- .../providers/netty/handler/Protocol.java | 102 ++-- .../netty/handler/WebSocketProtocol.java | 109 ++-- .../netty/request/NettyConnectListener.java | 38 +- .../providers/netty/request/NettyRequest.java | 22 +- .../netty/request/NettyRequestFactory.java | 56 +- .../netty/request/NettyRequestSender.java | 572 ++++++++++-------- .../netty/request/ProgressListener.java | 37 +- .../netty/request/body/BodyChunkedInput.java | 5 +- .../netty/request/body/BodyFileRegion.java | 5 +- .../request/body/FeedableBodyGenerator.java | 5 +- .../netty/request/body/NettyBody.java | 20 +- .../netty/request/body/NettyBodyBody.java | 20 +- .../request/body/NettyByteArrayBody.java | 20 +- .../netty/request/body/NettyFileBody.java | 20 +- .../request/body/NettyInputStreamBody.java | 20 +- .../request/body/NettyMultipartBody.java | 29 +- .../request/timeout/ReadTimeoutTimerTask.java | 36 +- .../timeout/RequestTimeoutTimerTask.java | 35 +- .../request/timeout/TimeoutTimerTask.java | 44 +- .../netty/request/timeout/TimeoutsHolder.java | 20 +- .../netty/response/EagerResponseBodyPart.java | 4 +- .../netty/response/LazyResponseBodyPart.java | 0 .../netty/response/NettyResponse.java | 46 +- .../netty/response/NettyResponseBodyPart.java | 20 +- .../netty/response/ResponseHeaders.java | 20 +- .../netty/response/ResponseStatus.java | 23 +- .../{ByteBufUtil.java => ByteBufUtils.java} | 4 +- .../util/{HttpUtil.java => HttpUtils.java} | 4 +- .../providers/netty/ws/NettyWebSocket.java | 5 +- ...WebSocketUtil.java => WebSocketUtils.java} | 7 +- 44 files changed, 1290 insertions(+), 1421 deletions(-) mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/{util => channel}/CleanupChannelGroup.java (98%) mode change 100644 => 100755 mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/{ByteBufUtil.java => ByteBufUtils.java} (96%) mode change 100644 => 100755 rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/{HttpUtil.java => HttpUtils.java} (96%) mode change 100644 => 100755 mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/{WebSocketUtil.java => WebSocketUtils.java} (91%) mode change 100644 => 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java old mode 100644 new mode 100755 index 5fb2104212..9f65646fe5 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java @@ -1,41 +1,44 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timer; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; import org.asynchttpclient.ListenableFuture; import org.asynchttpclient.Request; -import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; - public class NettyAsyncHttpProvider implements AsyncHttpProvider { private static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); private final NettyAsyncHttpProviderConfig nettyConfig; private final AtomicBoolean closed = new AtomicBoolean(false); - private final Channels channels; + private final ChannelManager channelManager; private final NettyRequestSender requestSender; + private final boolean allowStopNettyTimer; + private final Timer nettyTimer; public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { @@ -43,16 +46,29 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig() : new NettyAsyncHttpProviderConfig(); - channels = new Channels(config, nettyConfig); - requestSender = new NettyRequestSender(closed, config, nettyConfig, channels); - channels.configureProcessor(requestSender, closed); + allowStopNettyTimer = nettyConfig.getNettyTimer() == null; + nettyTimer = allowStopNettyTimer ? newNettyTimer() : nettyConfig.getNettyTimer(); + + channelManager = new ChannelManager(config, nettyConfig, nettyTimer); + requestSender = new NettyRequestSender(config, nettyConfig, channelManager, nettyTimer, closed); + channelManager.configureBootstraps(requestSender, closed); + } + + private Timer newNettyTimer() { + HashedWheelTimer timer = new HashedWheelTimer(); + timer.start(); + return timer; } @Override public void close() { if (closed.compareAndSet(false, true)) { try { - channels.close(); + channelManager.close(); + + if (allowStopNettyTimer) + nettyTimer.stop(); + } catch (Throwable t) { LOGGER.warn("Unexpected error on close", t); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java old mode 100644 new mode 100755 index 554e1643c1..f066ab51d5 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -1,18 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty; @@ -127,17 +124,17 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { /** * HttpClientCodec's maxInitialLineLength */ - private int maxInitialLineLength = 4096; + private int httpClientCodecMaxInitialLineLength = 4096; /** * HttpClientCodec's maxHeaderSize */ - private int maxHeaderSize = 8192; + private int httpClientCodecMaxHeaderSize = 8192; /** * HttpClientCodec's maxChunkSize */ - private int maxChunkSize = 8192; + private int httpClientCodecMaxChunkSize = 8192; private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); @@ -191,28 +188,28 @@ public void setWssAdditionalChannelInitializer(AdditionalChannelInitializer wssA this.wssAdditionalChannelInitializer = wssAdditionalChannelInitializer; } - public int getMaxInitialLineLength() { - return maxInitialLineLength; + public int getHttpClientCodecMaxInitialLineLength() { + return httpClientCodecMaxInitialLineLength; } - public void setMaxInitialLineLength(int maxInitialLineLength) { - this.maxInitialLineLength = maxInitialLineLength; + public void setHttpClientCodecMaxInitialLineLength(int httpClientCodecMaxInitialLineLength) { + this.httpClientCodecMaxInitialLineLength = httpClientCodecMaxInitialLineLength; } - public int getMaxHeaderSize() { - return maxHeaderSize; + public int getHttpClientCodecMaxHeaderSize() { + return httpClientCodecMaxHeaderSize; } - public void setMaxHeaderSize(int maxHeaderSize) { - this.maxHeaderSize = maxHeaderSize; + public void setHttpClientCodecMaxHeaderSize(int httpClientCodecMaxHeaderSize) { + this.httpClientCodecMaxHeaderSize = httpClientCodecMaxHeaderSize; } - public int getMaxChunkSize() { - return maxChunkSize; + public int getHttpClientCodecMaxChunkSize() { + return httpClientCodecMaxChunkSize; } - public void setMaxChunkSize(int maxChunkSize) { - this.maxChunkSize = maxChunkSize; + public void setHttpClientCodecMaxChunkSize(int httpClientCodecMaxChunkSize) { + this.httpClientCodecMaxChunkSize = httpClientCodecMaxChunkSize; } public ResponseBodyPartFactory getBodyPartFactory() { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java old mode 100644 new mode 100755 index dd36702b85..047dfc2a26 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -13,37 +13,104 @@ */ package org.asynchttpclient.providers.netty.channel; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isWebSocket; +import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; import io.netty.channel.group.ChannelGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpContentDecompressor; +import io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder; +import io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; +import io.netty.handler.ssl.SslHandler; +import io.netty.handler.stream.ChunkedWriteHandler; +import io.netty.util.Timer; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.Callback; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.DefaultChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.NoopChannelPool; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.handler.HttpProtocol; +import org.asynchttpclient.providers.netty.handler.Processor; +import org.asynchttpclient.providers.netty.handler.WebSocketProtocol; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.asynchttpclient.uri.UriComponents; +import org.asynchttpclient.util.SslUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); + public static final String HTTP_HANDLER = "httpHandler"; + public static final String SSL_HANDLER = "sslHandler"; + public static final String HTTP_PROCESSOR = "httpProcessor"; + public static final String WS_PROCESSOR = "wsProcessor"; + public static final String DEFLATER_HANDLER = "deflater"; + public static final String INFLATER_HANDLER = "inflater"; + public static final String CHUNKED_WRITER_HANDLER = "chunkedWriter"; + public static final String WS_DECODER_HANDLER = "ws-decoder"; + public static final String WS_ENCODER_HANDLER = "ws-encoder"; + + private final AsyncHttpClientConfig config; + private final NettyAsyncHttpProviderConfig nettyConfig; + + private final EventLoopGroup eventLoopGroup; + private final boolean allowReleaseEventLoopGroup; + + private final Bootstrap plainBootstrap; + private final Bootstrap secureBootstrap; + private final Bootstrap webSocketBootstrap; + private final Bootstrap secureWebSocketBootstrap; + + private final long handshakeTimeoutInMillis; private final ChannelPool channelPool; private final boolean maxConnectionsEnabled; private final Semaphore freeChannels; private final ChannelGroup openChannels; - private final int maxConnectionsPerHost; private final boolean maxConnectionsPerHostEnabled; private final ConcurrentHashMap freeChannelsPerHost; private final ConcurrentHashMap channel2KeyPool; - public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { + private Processor wsProcessor; + + public ChannelManager(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, Timer nettyTimer) { + + this.config = config; + this.nettyConfig = nettyConfig; + + ChannelPool channelPool = nettyConfig.getChannelPool(); + if (channelPool == null && config.isAllowPoolingConnections()) { + channelPool = new DefaultChannelPool(config, nettyTimer); + } else if (channelPool == null) { + channelPool = new NoopChannelPool(); + } this.channelPool = channelPool; maxConnectionsEnabled = config.getMaxConnections() > 0; - + maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; + if (maxConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @Override @@ -69,9 +136,6 @@ public boolean remove(Object o) { freeChannels = null; } - maxConnectionsPerHost = config.getMaxConnectionsPerHost(); - maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; - if (maxConnectionsPerHostEnabled) { freeChannelsPerHost = new ConcurrentHashMap(); channel2KeyPool = new ConcurrentHashMap(); @@ -79,6 +143,104 @@ public boolean remove(Object o) { freeChannelsPerHost = null; channel2KeyPool = null; } + + handshakeTimeoutInMillis = nettyConfig.getHandshakeTimeoutInMillis(); + + // check if external EventLoopGroup is defined + allowReleaseEventLoopGroup = nettyConfig.getEventLoopGroup() == null; + eventLoopGroup = allowReleaseEventLoopGroup ? new NioEventLoopGroup() : nettyConfig.getEventLoopGroup(); + if (!(eventLoopGroup instanceof NioEventLoopGroup)) + throw new IllegalArgumentException("Only Nio is supported"); + + plainBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + secureBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + webSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + secureWebSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + + if (config.getConnectionTimeout() > 0) + nettyConfig.addChannelOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getConnectionTimeout()); + for (Entry, Object> entry : nettyConfig.propertiesSet()) { + ChannelOption key = entry.getKey(); + Object value = entry.getValue(); + plainBootstrap.option(key, value); + webSocketBootstrap.option(key, value); + secureBootstrap.option(key, value); + secureWebSocketBootstrap.option(key, value); + } + } + + public void configureBootstraps(NettyRequestSender requestSender, AtomicBoolean closed) { + + HttpProtocol httpProtocol = new HttpProtocol(this, config, nettyConfig, requestSender); + final Processor httpProcessor = new Processor(config, this, requestSender, httpProtocol); + + WebSocketProtocol wsProtocol = new WebSocketProtocol(this, config, nettyConfig, requestSender); + wsProcessor = new Processor(config, this, requestSender, wsProtocol); + + plainBootstrap.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline().addLast(HTTP_HANDLER, newHttpClientCodec()); + + if (config.isCompressionEnabled()) { + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + } + pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// + .addLast(HTTP_PROCESSOR, httpProcessor); + + if (nettyConfig.getHttpAdditionalChannelInitializer() != null) { + nettyConfig.getHttpAdditionalChannelInitializer().initChannel(ch); + } + } + }); + + webSocketBootstrap.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline()// + .addLast(HTTP_HANDLER, newHttpClientCodec())// + .addLast(WS_PROCESSOR, wsProcessor); + + if (nettyConfig.getWsAdditionalChannelInitializer() != null) { + nettyConfig.getWsAdditionalChannelInitializer().initChannel(ch); + } + } + }); + + secureBootstrap.handler(new ChannelInitializer() { + + @Override + protected void initChannel(Channel ch) throws Exception { + + ChannelPipeline pipeline = ch.pipeline()// + .addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)).addLast(HTTP_HANDLER, newHttpClientCodec()); + + if (config.isCompressionEnabled()) { + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + } + pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// + .addLast(HTTP_PROCESSOR, httpProcessor); + + if (nettyConfig.getHttpsAdditionalChannelInitializer() != null) { + nettyConfig.getHttpsAdditionalChannelInitializer().initChannel(ch); + } + } + }); + + secureWebSocketBootstrap.handler(new ChannelInitializer() { + + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline()// + .addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this))// + .addLast(HTTP_HANDLER, newHttpClientCodec())// + .addLast(WS_PROCESSOR, wsProcessor); + + if (nettyConfig.getWssAdditionalChannelInitializer() != null) { + nettyConfig.getWssAdditionalChannelInitializer().initChannel(ch); + } + } + }); } public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { @@ -110,26 +272,26 @@ private Semaphore getFreeConnectionsForHost(String poolKey) { Semaphore freeConnections = freeChannelsPerHost.get(poolKey); if (freeConnections == null) { // lazy create the semaphore - Semaphore newFreeConnections = new Semaphore(maxConnectionsPerHost); + Semaphore newFreeConnections = new Semaphore(config.getMaxConnectionsPerHost()); freeConnections = freeChannelsPerHost.putIfAbsent(poolKey, newFreeConnections); if (freeConnections == null) freeConnections = newFreeConnections; } return freeConnections; } - + private boolean tryAcquirePerHost(String poolKey) { return !maxConnectionsPerHostEnabled || getFreeConnectionsForHost(poolKey).tryAcquire(); } - + public boolean preemptChannel(String poolKey) { return channelPool.isOpen() && tryAcquireGlobal() && tryAcquirePerHost(poolKey); } - public void destroy() { + public void close() { channelPool.destroy(); openChannels.close(); - + for (Channel channel : openChannels) { Object attachment = Channels.getDefaultAttribute(channel); if (attachment instanceof NettyResponseFuture) { @@ -137,13 +299,17 @@ public void destroy() { future.cancelTimeouts(); } } + + if (allowReleaseEventLoopGroup) + eventLoopGroup.shutdownGracefully(); } public void closeChannel(Channel channel) { removeAll(channel); Channels.setDiscard(channel); - // The channel may have already been removed if a timeout occurred, and this method may be called just after. + // The channel may have already been removed if a timeout occurred, and + // this method may be called just after. if (channel != null) { LOGGER.debug("Closing Channel {} ", channel); try { @@ -165,4 +331,96 @@ public void abortChannelPreemption(String poolKey) { public void registerOpenChannel(Channel channel) { openChannels.add(channel); } -} \ No newline at end of file + + private HttpClientCodec newHttpClientCodec() { + return new HttpClientCodec(// + nettyConfig.getHttpClientCodecMaxInitialLineLength(),// + nettyConfig.getHttpClientCodecMaxHeaderSize(),// + nettyConfig.getHttpClientCodecMaxChunkSize(),// + false); + } + + public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException { + + SSLEngine sslEngine = null; + if (nettyConfig.getSslEngineFactory() != null) { + sslEngine = nettyConfig.getSslEngineFactory().newSSLEngine(); + + } else { + SSLContext sslContext = config.getSSLContext(); + if (sslContext == null) + sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); + + sslEngine = sslContext.createSSLEngine(peerHost, peerPort); + sslEngine.setUseClientMode(true); + } + + SslHandler sslHandler = new SslHandler(sslEngine); + if (handshakeTimeoutInMillis > 0) + sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); + + return sslHandler; + } + + public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host, int port) throws IOException, GeneralSecurityException { + if (pipeline.get(HTTP_HANDLER) != null) + pipeline.remove(HTTP_HANDLER); + + if (isSecure(scheme)) + if (pipeline.get(SSL_HANDLER) == null) { + pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); + pipeline.addFirst(SSL_HANDLER, createSslHandler(host, port)); + } else { + pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); + } + + else + pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); + + if (isWebSocket(scheme)) + pipeline.replace(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); + } + + public String getPoolKey(NettyResponseFuture future) { + return future.getConnectionPoolKeyStrategy().getKey(future.getURI(), future.getProxyServer()); + } + + /** + * Always make sure the channel who got cached support the proper protocol. + * It could only occurs when a HttpMethod. CONNECT is used against a proxy + * that requires upgrading from http to https. + */ + public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { + + boolean isSecure = isSecure(scheme); + if (pipeline.get(SSL_HANDLER) != null) { + if (!isSecure) + pipeline.remove(SSL_HANDLER); + + } else if (isSecure) + pipeline.addFirst(SSL_HANDLER, new SslInitializer(this)); + } + + public Bootstrap getBootstrap(UriComponents uri, boolean useProxy, boolean useSSl) { + return uri.getScheme().startsWith(WEBSOCKET) && !useProxy ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : // + (useSSl ? secureBootstrap : plainBootstrap); + } + + public void upgradePipelineForWebSockets(ChannelPipeline pipeline) { + pipeline.replace(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); + pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); + } + + public final Callback newDrainCallback(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, final String poolKey) { + + return new Callback(future) { + public void call() throws Exception { + tryToOfferChannelToPool(channel, keepAlive, poolKey); + } + }; + } + + public void drainChannel(final Channel channel, final NettyResponseFuture future) { + Channels.setDefaultAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); + } +} diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java old mode 100644 new mode 100755 index 304d2d7931..eda10d57d9 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -1,409 +1,29 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.channel; -import static org.asynchttpclient.providers.netty.handler.Processor.newHttpProcessor; -import static org.asynchttpclient.providers.netty.handler.Processor.newWsProcessor; -import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; - -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.ConnectionPoolKeyStrategy; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.channel.pool.DefaultChannelPool; -import org.asynchttpclient.providers.netty.channel.pool.NoopChannelPool; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.handler.Processor; -import org.asynchttpclient.providers.netty.request.NettyRequestSender; -import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.SslUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpContentDecompressor; -import io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder; -import io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; import io.netty.handler.ssl.SslHandler; -import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.util.Attribute; import io.netty.util.AttributeKey; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timeout; -import io.netty.util.Timer; -import io.netty.util.TimerTask; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; +import org.asynchttpclient.providers.netty.DiscardEvent; public class Channels { - private static final Logger LOGGER = LoggerFactory.getLogger(Channels.class); - public static final String HTTP_HANDLER = "httpHandler"; - public static final String SSL_HANDLER = "sslHandler"; - public static final String HTTP_PROCESSOR = "httpProcessor"; - public static final String WS_PROCESSOR = "wsProcessor"; - public static final String DEFLATER_HANDLER = "deflater"; - public static final String INFLATER_HANDLER = "inflater"; - public static final String CHUNKED_WRITER_HANDLER = "chunkedWriter"; - public static final String WS_DECODER_HANDLER = "ws-decoder"; - public static final String WS_ENCODER_HANDLER = "ws-encoder"; - private static final AttributeKey DEFAULT_ATTRIBUTE = AttributeKey.valueOf("default"); - private final AsyncHttpClientConfig config; - private final NettyAsyncHttpProviderConfig nettyProviderConfig; - - private final EventLoopGroup eventLoopGroup; - private final boolean allowReleaseEventLoopGroup; - - private final Bootstrap plainBootstrap; - private final Bootstrap secureBootstrap; - private final Bootstrap webSocketBootstrap; - private final Bootstrap secureWebSocketBootstrap; - - public final ChannelManager channelManager; - private final boolean allowStopNettyTimer; - private final Timer nettyTimer; - private final long handshakeTimeoutInMillis; - - private Processor wsProcessor; - - public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyProviderConfig) { - - this.config = config; - this.nettyProviderConfig = nettyProviderConfig; - - // check if external EventLoopGroup is defined - allowReleaseEventLoopGroup = nettyProviderConfig.getEventLoopGroup() == null; - eventLoopGroup = allowReleaseEventLoopGroup ? new NioEventLoopGroup() : nettyProviderConfig.getEventLoopGroup(); - - // check if external HashedWheelTimer is defined - allowStopNettyTimer = nettyProviderConfig.getNettyTimer() == null; - nettyTimer = allowStopNettyTimer ? newNettyTimer() : nettyProviderConfig.getNettyTimer(); - handshakeTimeoutInMillis = nettyProviderConfig.getHandshakeTimeoutInMillis(); - - if (!(eventLoopGroup instanceof NioEventLoopGroup)) - throw new IllegalArgumentException("Only Nio is supported"); - - plainBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - secureBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - webSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - secureWebSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - - ChannelPool cp = nettyProviderConfig.getChannelPool(); - if (cp == null) { - if (config.isAllowPoolingConnections()) { - cp = new DefaultChannelPool(config, nettyTimer); - } else { - cp = new NoopChannelPool(); - } - } - this.channelManager = new ChannelManager(config, cp); - - for (Entry, Object> entry : nettyProviderConfig.propertiesSet()) { - ChannelOption key = entry.getKey(); - Object value = entry.getValue(); - plainBootstrap.option(key, value); - webSocketBootstrap.option(key, value); - secureBootstrap.option(key, value); - secureWebSocketBootstrap.option(key, value); - } - - int timeOut = config.getConnectionTimeout() > 0 ? config.getConnectionTimeout() : Integer.MAX_VALUE; - plainBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - webSocketBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - secureBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - secureWebSocketBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - } - - private Timer newNettyTimer() { - HashedWheelTimer nettyTimer = new HashedWheelTimer(); - nettyTimer.start(); - return nettyTimer; - } - - public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException { - - SSLEngine sslEngine = null; - if (nettyProviderConfig.getSslEngineFactory() != null) { - sslEngine = nettyProviderConfig.getSslEngineFactory().newSSLEngine(); - - } else { - SSLContext sslContext = config.getSSLContext(); - if (sslContext == null) - sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); - - sslEngine = sslContext.createSSLEngine(peerHost, peerPort); - sslEngine.setUseClientMode(true); - } - - SslHandler sslHandler = new SslHandler(sslEngine); - if (handshakeTimeoutInMillis > 0) - sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); - - return sslHandler; - } - - public void configureProcessor(NettyRequestSender requestSender, AtomicBoolean closed) { - - final Processor httpProcessor = newHttpProcessor(config, nettyProviderConfig, requestSender, this, closed); - wsProcessor = newWsProcessor(config, nettyProviderConfig, requestSender, this, closed); - - plainBootstrap.handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline().addLast(HTTP_HANDLER, newHttpClientCodec()); - - if (config.isCompressionEnabled()) { - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); - } - pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// - .addLast(HTTP_PROCESSOR, httpProcessor); - - if (nettyProviderConfig.getHttpAdditionalChannelInitializer() != null) { - nettyProviderConfig.getHttpAdditionalChannelInitializer().initChannel(ch); - } - } - }); - - webSocketBootstrap.handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline()// - .addLast(HTTP_HANDLER, newHttpClientCodec())// - .addLast(WS_PROCESSOR, wsProcessor); - - if (nettyProviderConfig.getWsAdditionalChannelInitializer() != null) { - nettyProviderConfig.getWsAdditionalChannelInitializer().initChannel(ch); - } - } - }); - - secureBootstrap.handler(new ChannelInitializer() { - - @Override - protected void initChannel(Channel ch) throws Exception { - - ChannelPipeline pipeline = ch.pipeline()// - .addLast(SSL_HANDLER, new SslInitializer(Channels.this)).addLast(HTTP_HANDLER, newHttpClientCodec()); - - if (config.isCompressionEnabled()) { - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); - } - pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// - .addLast(HTTP_PROCESSOR, httpProcessor); - - if (nettyProviderConfig.getHttpsAdditionalChannelInitializer() != null) { - nettyProviderConfig.getHttpsAdditionalChannelInitializer().initChannel(ch); - } - } - }); - - secureWebSocketBootstrap.handler(new ChannelInitializer() { - - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline()// - .addLast(SSL_HANDLER, new SslInitializer(Channels.this))// - .addLast(HTTP_HANDLER, newHttpClientCodec())// - .addLast(WS_PROCESSOR, wsProcessor); - - if (nettyProviderConfig.getWssAdditionalChannelInitializer() != null) { - nettyProviderConfig.getWssAdditionalChannelInitializer().initChannel(ch); - } - } - }); - } - - public Bootstrap getBootstrap(UriComponents uri, boolean useSSl, boolean useProxy) { - return (uri.getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) - : (useSSl ? secureBootstrap : plainBootstrap); - } - - public void close() { - channelManager.destroy(); - - if (allowReleaseEventLoopGroup) - eventLoopGroup.shutdownGracefully(); - - if (allowStopNettyTimer) - nettyTimer.stop(); - } - - /** - * Always make sure the channel who got cached support the proper protocol. It could only occurs when a HttpMethod. - * CONNECT is used against a proxy that requires upgrading from http to https. - */ - public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { - - boolean isSecure = isSecure(scheme); - if (pipeline.get(SSL_HANDLER) != null) { - if (!isSecure) - pipeline.remove(SSL_HANDLER); - - } else if (isSecure) - pipeline.addFirst(SSL_HANDLER, new SslInitializer(Channels.this)); - } - - protected HttpClientCodec newHttpClientCodec() { - if (nettyProviderConfig != null) { - return new HttpClientCodec(// - nettyProviderConfig.getMaxInitialLineLength(),// - nettyProviderConfig.getMaxHeaderSize(),// - nettyProviderConfig.getMaxChunkSize(),// - false); - - } else { - return new HttpClientCodec(); - } - } - - public void upgradeProtocol(ChannelPipeline p, String scheme, String host, int port) throws IOException, GeneralSecurityException { - if (p.get(HTTP_HANDLER) != null) { - p.remove(HTTP_HANDLER); - } - - if (isSecure(scheme)) { - if (p.get(SSL_HANDLER) == null) { - p.addFirst(HTTP_HANDLER, newHttpClientCodec()); - p.addFirst(SSL_HANDLER, createSslHandler(host, port)); - } else { - p.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); - } - - } else { - p.addFirst(HTTP_HANDLER, newHttpClientCodec()); - } - - if (isWebSocket(scheme)) { - p.replace(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); - } - } - - public static void upgradePipelineForWebSockets(Channel channel) { - channel.pipeline().replace(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); - channel.pipeline().addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); - } - - public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { - final Channel channel = channelManager.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); - - if (channel != null) { - LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); - - try { - verifyChannelPipeline(channel.pipeline(), uri.getScheme()); - } catch (Exception ex) { - LOGGER.debug(ex.getMessage(), ex); - } - } - return channel; - } - - public boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) throws IOException { - - boolean channelPreempted = false; - if (channelManager.preemptChannel(poolKey)) { - channelPreempted = true; - } else { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); - try { - asyncHandler.onThrowable(ex); - } catch (Exception e) { - LOGGER.warn("asyncHandler.onThrowable crashed", e); - } - throw ex; - } - return channelPreempted; - } - - public void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { - channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); - } - - public void abortChannelPreemption(String poolKey) { - channelManager.abortChannelPreemption(poolKey); - } - - public void closeChannel(Channel channel) { - channelManager.closeChannel(channel); - } - - public final Callable> newDrainCallable(final NettyResponseFuture future, final Channel channel, - final boolean keepAlive, final String poolKey) { - - return new Callable>() { - public NettyResponseFuture call() throws Exception { - channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); - return null; - } - }; - } - - public void drainChannel(final Channel channel, final NettyResponseFuture future) { - setDefaultAttribute(channel, newDrainCallable(future, channel, future.isKeepAlive(), getPoolKey(future))); - } - - public String getPoolKey(NettyResponseFuture future) { - return future.getConnectionPoolKeyStrategy().getKey(future.getURI(), future.getProxyServer()); - } - - public void removeAll(Channel channel) { - channelManager.removeAll(channel); - } - - public void abort(NettyResponseFuture future, Throwable t) { - - Channel channel = future.channel(); - if (channel != null) - channelManager.closeChannel(channel); - - if (!future.isDone()) { - LOGGER.debug("Aborting Future {}\n", future); - LOGGER.debug(t.getMessage(), t); - } - - future.abort(t); - } - - public Timeout newTimeoutInMs(TimerTask task, long delayInMs) { - return nettyTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); - } - public static SslHandler getSslHandler(Channel channel) { return channel.pipeline().get(SslHandler.class); } @@ -420,8 +40,8 @@ public static void setDefaultAttribute(Channel channel, Object o) { public static void setDiscard(Channel channel) { setDefaultAttribute(channel, DiscardEvent.INSTANCE); } - - public void registerOpenChannel(Channel channel) { - channelManager.registerOpenChannel(channel); + + public static boolean isChannelValid(Channel channel) { + return channel != null && channel.isOpen() && channel.isActive(); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/CleanupChannelGroup.java old mode 100644 new mode 100755 similarity index 98% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/CleanupChannelGroup.java index 853ea319e9..edd0c2643a --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/CleanupChannelGroup.java @@ -25,7 +25,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.asynchttpclient.providers.netty.util; +package org.asynchttpclient.providers.netty.channel; import io.netty.channel.Channel; import io.netty.channel.group.ChannelGroupFuture; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java old mode 100644 new mode 100755 index e0df603cd0..31819ee86b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java @@ -30,10 +30,10 @@ */ public class SslInitializer extends ChannelOutboundHandlerAdapter { - private final Channels channels; + private final ChannelManager channelManager; - public SslInitializer(Channels channels) { - this.channels = channels; + public SslInitializer(ChannelManager channelManager) { + this.channelManager = channelManager; } @Override @@ -44,9 +44,9 @@ public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, Sock String peerHost = remoteInetSocketAddress.getHostName(); int peerPort = remoteInetSocketAddress.getPort(); - SslHandler sslHandler = channels.createSslHandler(peerHost, peerPort); + SslHandler sslHandler = channelManager.createSslHandler(peerHost, peerPort); - ctx.pipeline().replace(Channels.SSL_HANDLER, Channels.SSL_HANDLER, sslHandler); + ctx.pipeline().replace(ChannelManager.SSL_HANDLER, ChannelManager.SSL_HANDLER, sslHandler); ctx.connect(remoteAddress, localAddress, promise); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java old mode 100644 new mode 100755 index 4f1d96ba16..ef1fbd9973 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java @@ -1,18 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.channel.pool; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java old mode 100644 new mode 100755 index f8d684ad84..ad7fe1ccb3 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.channel.pool; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 9d2a692f77..ab5a1f04e9 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -1,35 +1,19 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.future; import static org.asynchttpclient.util.DateUtils.millisTime; - -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.ConnectionPoolKeyStrategy; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.Request; -import org.asynchttpclient.listenable.AbstractListenableFuture; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.request.NettyRequest; -import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; -import org.asynchttpclient.uri.UriComponents; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; @@ -46,6 +30,18 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.ConnectionPoolKeyStrategy; +import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.Request; +import org.asynchttpclient.listenable.AbstractListenableFuture; +import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.request.NettyRequest; +import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; +import org.asynchttpclient.uri.UriComponents; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A {@link Future} that can be used to track when an asynchronous HTTP request has been fully processed. * @@ -137,7 +133,7 @@ public boolean cancel(boolean force) { return false; try { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + Channels.setDiscard(channel); channel.close(); } catch (Throwable t) { // Ignore @@ -452,8 +448,8 @@ public void setRequest(Request request) { * @return true if that {@link Future} cannot be recovered. */ public boolean canBeReplayed() { - return !isDone() && canRetry() && !isCancelled() - && !(channel != null && channel.isOpen() && !uri.getScheme().equalsIgnoreCase("https")) && !isInAuth(); + return !isDone() && canRetry() + && !(Channels.isChannelValid(channel) && !uri.getScheme().equalsIgnoreCase("https")) && !isInAuth(); } public long getStart() { @@ -474,7 +470,7 @@ public String toString() { ",\n\thttpHeaders=" + httpHeaders + // ",\n\texEx=" + exEx + // ",\n\tredirectCount=" + redirectCount + // - ",\n\timeoutsHolder=" + timeoutsHolder + // + ",\n\ttimeoutsHolder=" + timeoutsHolder + // ",\n\tinAuth=" + inAuth + // ",\n\tstatusReceived=" + statusReceived + // ",\n\ttouch=" + touch + // diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java old mode 100644 new mode 100755 index 377dd130cd..380121278c --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.handler; @@ -19,16 +17,25 @@ import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isNTLM; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getDefaultPort; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.LastHttpContent; + +import java.io.IOException; +import java.util.List; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHandler.STATE; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.HttpResponseHeaders; -import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; import org.asynchttpclient.Request; @@ -37,6 +44,7 @@ import org.asynchttpclient.ntlm.NTLMEngineException; import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequest; @@ -46,37 +54,19 @@ import org.asynchttpclient.providers.netty.response.ResponseStatus; import org.asynchttpclient.spnego.SpnegoEngine; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpContent; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.LastHttpContent; -import java.io.IOException; -import java.util.List; - -final class HttpProtocol extends Protocol { +public final class HttpProtocol extends Protocol { - private static final Logger LOGGER = LoggerFactory.getLogger(HttpProtocol.class); - - public HttpProtocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, - NettyRequestSender requestSender) { - super(channels, config, nettyConfig, requestSender); + public HttpProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { + super(channelManager, config, nettyConfig, requestSender); } private Realm.RealmBuilder newRealmBuilder(Realm realm) { return realm != null ? new Realm.RealmBuilder().clone(realm) : new Realm.RealmBuilder(); } - private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { + private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, + NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { UriComponents uri = request.getURI(); String host = request.getVirtualHost() == null ? uri.getHost() : request.getVirtualHost(); @@ -96,21 +86,21 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe if (isNTLM(proxyAuth)) { return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); } - channels.abort(future, throwable); + requestSender.abort(future, throwable); return null; } } private String authorizationHeaderName(boolean proxyInd) { - return proxyInd? HttpHeaders.Names.PROXY_AUTHORIZATION: HttpHeaders.Names.AUTHORIZATION; + return proxyInd ? HttpHeaders.Names.PROXY_AUTHORIZATION : HttpHeaders.Names.AUTHORIZATION; } - + private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); } - private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, - Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { + private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, + NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { boolean useRealm = proxyServer == null && realm != null; @@ -143,13 +133,12 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p } } - private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { + private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, + NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { future.getAndSetAuth(false); headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION); - addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), - proxyServer.getNtlmDomain(), proxyServer.getHost(), proxyInd); + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost(), proxyInd); return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) @@ -157,8 +146,8 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer .setMethodName(request.getMethod()).build(); } - private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, - String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { + private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, String password, String domain, String workstation, + boolean proxyInd) throws NTLMEngineException { headers.remove(authorizationHeaderName(proxyInd)); if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { @@ -172,19 +161,17 @@ private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean keepAlive = future.isKeepAlive(); if (expectOtherChunks && keepAlive) - channels.drainChannel(channel, future); + channelManager.drainChannel(channel, future); else - channels.tryToOfferChannelToPool(channel, keepAlive, channels.getPoolKey(future)); + channelManager.tryToOfferChannelToPool(channel, keepAlive, channelManager.getPoolKey(future)); markAsDone(future, channel); } - private final boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart bodyPart) - throws Exception { - boolean state = handler.onBodyPartReceived(bodyPart) != STATE.CONTINUE; - if (bodyPart.isUnderlyingConnectionToBeClosed()) { + private boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, NettyResponseBodyPart bodyPart) throws Exception { + boolean interrupt = handler.onBodyPartReceived(bodyPart) != STATE.CONTINUE; + if (bodyPart.isUnderlyingConnectionToBeClosed()) future.setKeepAlive(false); - } - return state; + return interrupt; } private void markAsDone(NettyResponseFuture future, final Channel channel) { @@ -194,33 +181,39 @@ private void markAsDone(NettyResponseFuture future, final Channel channel) { future.done(); } catch (Throwable t) { // Never propagate exception once we know we are done. - LOGGER.debug(t.getMessage(), t); + logger.debug(t.getMessage(), t); } if (!future.isKeepAlive() || !channel.isActive()) { - channels.closeChannel(channel); + channelManager.closeChannel(channel); } } - private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Request request, HttpResponse response, - final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws Exception { - if (statusCode == UNAUTHORIZED.code() && realm != null) { + private boolean exitAfterHandling401(// + final Channel channel,// + final NettyResponseFuture future,// + HttpResponse response,// + final Request request,// + int statusCode,// + Realm realm,// + ProxyServer proxyServer) throws Exception { + + if (statusCode == UNAUTHORIZED.code() && realm != null && !future.getAndSetAuth(true)) { - List authenticateHeaders = response.headers().getAll(HttpHeaders.Names.WWW_AUTHENTICATE); + List wwwAuthHeaders = response.headers().getAll(HttpHeaders.Names.WWW_AUTHENTICATE); - if (!authenticateHeaders.isEmpty() && !future.getAndSetAuth(true)) { + if (!wwwAuthHeaders.isEmpty()) { future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; - // NTLM - boolean negociate = authenticateHeaders.contains("Negotiate"); - if (!authenticateHeaders.contains("Kerberos") && (isNTLM(authenticateHeaders) || negociate)) { - newRealm = ntlmChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, false); - // SPNEGO KERBEROS + boolean negociate = wwwAuthHeaders.contains("Negotiate"); + if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || negociate)) { + // NTLM + newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, request.getHeaders(), realm, future, false); } else if (negociate) { - newRealm = kerberosChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, false); - if (newRealm == null) { + newRealm = kerberosChallenge(wwwAuthHeaders, request, proxyServer, request.getHeaders(), realm, future, false); + // SPNEGO KERBEROS + if (newRealm == null) return true; - } } else { newRealm = new Realm.RealmBuilder()// .clone(realm)// @@ -228,28 +221,27 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req .setUri(request.getURI())// .setMethodName(request.getMethod())// .setUsePreemptiveAuth(true)// - .parseWWWAuthenticateHeader(authenticateHeaders.get(0))// + .parseWWWAuthenticateHeader(wwwAuthHeaders.get(0))// .build(); } Realm nr = newRealm; final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(nr).build(); - LOGGER.debug("Sending authentication to {}", request.getURI()); + logger.debug("Sending authentication to {}", request.getURI()); Callback callback = new Callback(future) { public void call() throws Exception { - channels.drainChannel(channel, future); + channelManager.drainChannel(channel, future); requestSender.sendNextRequest(nextRequest, future); } }; - if (future.isKeepAlive() && HttpHeaders.isTransferEncodingChunked(response)) { + if (future.isKeepAlive() && HttpHeaders.isTransferEncodingChunked(response)) // We must make sure there is no bytes left // before executing the next request. Channels.setDefaultAttribute(channel, callback); - } else { + else callback.call(); - } return true; } @@ -258,7 +250,7 @@ public void call() throws Exception { return false; } - private boolean handleContinueAndExit(final Channel channel, final NettyResponseFuture future, int statusCode) { + private boolean exitAfterHandling100(final Channel channel, final NettyResponseFuture future, int statusCode) { if (statusCode == CONTINUE.code()) { future.setHeadersAlreadyWrittenOnContinue(true); future.setDontWriteBodyBecauseExpectContinue(false); @@ -270,27 +262,31 @@ private boolean handleContinueAndExit(final Channel channel, final NettyResponse return false; } - private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// - Realm realm,// - final Request request,// + private boolean exitAfterHandling407(// + NettyResponseFuture future,// HttpResponse response,// - final NettyResponseFuture future,// + Request request,// + int statusCode,// + Realm realm,// ProxyServer proxyServer) throws Exception { - if (statusCode == PROXY_AUTHENTICATION_REQUIRED.code() && realm != null) { - List proxyAuthenticateHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); - if (!proxyAuthenticateHeaders.isEmpty() && !future.getAndSetAuth(true)) { - LOGGER.debug("Sending proxy authentication to {}", request.getURI()); + if (statusCode == PROXY_AUTHENTICATION_REQUIRED.code() && realm != null && !future.getAndSetAuth(true)) { + + List proxyAuthHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); + + if (!proxyAuthHeaders.isEmpty()) { + logger.debug("Sending proxy authentication to {}", request.getURI()); future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; + FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); - boolean negociate = proxyAuthenticateHeaders.contains("Negotiate"); - if (!proxyAuthenticateHeaders.contains("Kerberos") && (isNTLM(proxyAuthenticateHeaders) || negociate)) { - newRealm = ntlmProxyChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, true); + boolean negociate = proxyAuthHeaders.contains("Negotiate"); + if (!proxyAuthHeaders.contains("Kerberos") && (isNTLM(proxyAuthHeaders) || negociate)) { + newRealm = ntlmProxyChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); // SPNEGO KERBEROS } else if (negociate) { - newRealm = kerberosChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, true); + newRealm = kerberosChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); if (newRealm == null) return true; } else { @@ -300,13 +296,13 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// .setOmitQuery(true)// .setMethodName(HttpMethod.CONNECT.name())// .setUsePreemptiveAuth(true)// - .parseProxyAuthenticateHeader(proxyAuthenticateHeaders.get(0))// + .parseProxyAuthenticateHeader(proxyAuthHeaders.get(0))// .build(); } future.setReuseChannel(true); future.setConnectAllowed(true); - Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(newRealm).build(); + Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(requestHeaders).setRealm(newRealm).build(); requestSender.sendNextRequest(nextRequest, future); return true; } @@ -314,27 +310,32 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// return false; } - private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Request request, HttpRequest httpRequest, - HttpResponse response, final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws IOException { - if (statusCode == OK.code() && httpRequest.getMethod() == HttpMethod.CONNECT) { + private boolean exitAfterHandlingConnect(// + final Channel channel,// + final NettyResponseFuture future,// + final Request request,// + ProxyServer proxyServer,// + int statusCode,// + HttpRequest httpRequest) throws IOException { - LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); + if (statusCode == OK.code() && httpRequest.getMethod() == HttpMethod.CONNECT) { - if (future.isKeepAlive()) { + if (future.isKeepAlive()) future.attachChannel(channel, true); - } try { UriComponents requestURI = request.getURI(); String scheme = requestURI.getScheme(); - LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); String host = requestURI.getHost(); - int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); - - channels.upgradeProtocol(channel.pipeline(), scheme, host, port); + int port = getDefaultPort(requestURI); + + logger.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); + channelManager.upgradeProtocol(channel.pipeline(), scheme, host, port); + } catch (Throwable ex) { - channels.abort(future, ex); + requestSender.abort(future, ex); } + future.setReuseChannel(true); future.setConnectAllowed(false); requestSender.sendNextRequest(new RequestBuilder(future.getRequest()).build(), future); @@ -344,18 +345,29 @@ private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Reques return false; } - private boolean handleHanderAndExit(Channel channel, NettyResponseFuture future, AsyncHandler handler, HttpResponseStatus status, - HttpResponseHeaders responseHeaders, HttpResponse response) throws Exception { - if (!future.getAndSetStatusReceived(true) - && (handler.onStatusReceived(status) != STATE.CONTINUE || handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE)) { + private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, ResponseStatus status) + throws IOException, Exception { + if (!future.getAndSetStatusReceived(true) && handler.onStatusReceived(status) != STATE.CONTINUE) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); return true; } return false; } - private boolean handleResponseAndExit(final Channel channel, final NettyResponseFuture future, AsyncHandler handler, - HttpRequest httpRequest, ProxyServer proxyServer, HttpResponse response) throws Exception { + private boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, ResponseHeaders responseHeaders) + throws IOException, Exception { + if (!response.headers().isEmpty() && handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE) { + finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); + return true; + } + return false; + } + + private boolean handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture future, AsyncHandler handler) throws Exception { + + HttpRequest httpRequest = future.getNettyRequest().getHttpRequest(); + ProxyServer proxyServer = future.getProxyServer(); + logger.debug("\n\nRequest {}\n\nResponse {}\n", httpRequest, response); // store the original headers so we can re-send all them to // the handler in case of trailing headers @@ -363,19 +375,20 @@ private boolean handleResponseAndExit(final Channel channel, final NettyResponse future.setKeepAlive(!HttpHeaders.Values.CLOSE.equalsIgnoreCase(response.headers().get(HttpHeaders.Names.CONNECTION))); - HttpResponseStatus status = new ResponseStatus(future.getURI(), response, config); + ResponseStatus status = new ResponseStatus(future.getURI(), config, response); int statusCode = response.getStatus().code(); Request request = future.getRequest(); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); - - return handleResponseFiltersReplayRequestAndExit(channel, future, status, responseHeaders)// - || handleUnauthorizedAndExit(statusCode, realm, request, response, future, proxyServer, channel)// - || handleContinueAndExit(channel, future, statusCode)// - || handleProxyAuthenticationRequiredAndExit(statusCode, realm, request, response, future, proxyServer) - || handleConnectOKAndExit(statusCode, realm, request, httpRequest, response, future, proxyServer, channel)// - || handleRedirectAndExit(request, future, response, channel)// - || handleHanderAndExit(channel, future, handler, status, responseHeaders, response); + ResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); + + return exitAfterProcessingFilters(channel, future, handler, status, responseHeaders) + || exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer) || // + exitAfterHandling407(future, response, request, statusCode, realm, proxyServer) || // + exitAfterHandling100(channel, future, statusCode) || // + exitAfterHandlingRedirect(channel, future, response, request, statusCode) || // + exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, httpRequest) || // + exitAfterHandlingStatus(channel, future, response, handler, status) || // + exitAfterHandlingHeaders(channel, future, response, handler, responseHeaders); } @Override @@ -385,59 +398,54 @@ public void handle(final Channel channel, final NettyResponseFuture future, f // The connect timeout occurred. if (future.isDone()) { - channels.closeChannel(channel); + channelManager.closeChannel(channel); return; } NettyRequest nettyRequest = future.getNettyRequest(); AsyncHandler handler = future.getAsyncHandler(); - ProxyServer proxyServer = future.getProxyServer(); try { if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - LOGGER.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest.getHttpRequest(), response); + logger.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest.getHttpRequest(), response); + // FIXME why do we buffer the response? I don't remember... future.setPendingResponse(response); return; - } - if (e instanceof HttpContent) { + } else if (e instanceof HttpContent) { HttpResponse response = future.getPendingResponse(); future.setPendingResponse(null); - if (handler != null) { - if (response != null - && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest(), proxyServer, response)) { - return; - } + if (response != null && handleHttpResponse(response, channel, future, handler)) + return; - HttpContent chunk = (HttpContent) e; + HttpContent chunk = (HttpContent) e; - boolean interrupt = false; - boolean last = chunk instanceof LastHttpContent; + boolean interrupt = false; + boolean last = chunk instanceof LastHttpContent; - if (last) { - LastHttpContent lastChunk = (LastHttpContent) chunk; - HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); - if (!trailingHeaders.isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), trailingHeaders); - interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; - } - } - - ByteBuf buf = chunk.content(); - try { - if (!interrupt && (buf.readableBytes() > 0 || last)) { - NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, last); - interrupt = updateBodyAndInterrupt(future, handler, part); - } - } finally { - // FIXME we shouldn't need this, should we? But a leak was reported there without it?! - buf.release(); + // Netty 4: the last chunk is not empty + if (last) { + LastHttpContent lastChunk = (LastHttpContent) chunk; + HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); + if (!trailingHeaders.isEmpty()) { + ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), trailingHeaders); + interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; } + } - if (interrupt || last) { - finishUpdate(future, channel, !last); + ByteBuf buf = chunk.content(); + try { + if (!interrupt && (buf.readableBytes() > 0 || last)) { + NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, last); + interrupt = updateBodyAndInterrupt(future, handler, part); } + } finally { + // FIXME we shouldn't need this, should we? But a leak was reported there without it?! + buf.release(); } + + if (interrupt || last) + finishUpdate(future, channel, !last); } } catch (Exception t) { if (hasIOExceptionFilters// @@ -447,9 +455,9 @@ && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest() } try { - channels.abort(future, t); + requestSender.abort(future, t); } catch (Exception abortException) { - LOGGER.debug("Abort failed", abortException); + logger.debug("Abort failed", abortException); } finally { finishUpdate(future, channel, false); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java old mode 100644 new mode 100755 index f1d6a1d3e0..8cbd848de6 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -1,32 +1,19 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.handler; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.Callback; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.future.StackTraceInspector; -import org.asynchttpclient.providers.netty.request.NettyRequestSender; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import static org.asynchttpclient.util.AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; @@ -36,62 +23,57 @@ import java.io.IOException; import java.nio.channels.ClosedChannelException; -import java.util.concurrent.atomic.AtomicBoolean; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.Callback; +import org.asynchttpclient.providers.netty.DiscardEvent; +import org.asynchttpclient.providers.netty.channel.ChannelManager; +import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.future.StackTraceInspector; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Sharable public class Processor extends ChannelInboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class); + public static final IOException CHANNEL_CLOSED_EXCEPTION = new IOException("Channel Closed"); + static { + CHANNEL_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); + } + private final AsyncHttpClientConfig config; + private final ChannelManager channelManager; private final NettyRequestSender requestSender; - private final Channels channels; - private final AtomicBoolean closed; private final Protocol protocol; - public static Processor newHttpProcessor(AsyncHttpClientConfig config,// - NettyAsyncHttpProviderConfig nettyConfig,// - NettyRequestSender requestSender,// - Channels channels,// - AtomicBoolean isClose) { - HttpProtocol protocol = new HttpProtocol(channels, config, nettyConfig, requestSender); - return new Processor(config, nettyConfig, requestSender, channels, isClose, protocol); - } - - public static Processor newWsProcessor(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, - NettyRequestSender requestSender, Channels channels, AtomicBoolean isClose) { - WebSocketProtocol protocol = new WebSocketProtocol(channels, config, nettyConfig, requestSender); - return new Processor(config, nettyConfig, requestSender, channels, isClose, protocol); - } - - private Processor(AsyncHttpClientConfig config,// - NettyAsyncHttpProviderConfig nettyConfig,// + public Processor(AsyncHttpClientConfig config,// + ChannelManager channelManager,// NettyRequestSender requestSender,// - Channels channels,// - AtomicBoolean isClose,// Protocol protocol) { this.config = config; + this.channelManager = channelManager; this.requestSender = requestSender; - this.channels = channels; - this.closed = isClose; this.protocol = protocol; } @Override - public void channelRead(final ChannelHandlerContext ctx, Object e) throws Exception { + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { Channel channel = ctx.channel(); Object attribute = Channels.getDefaultAttribute(channel); - if (attribute instanceof Callback && e instanceof LastHttpContent) { + if (attribute instanceof Callback && msg instanceof LastHttpContent) { Callback ac = (Callback) attribute; ac.call(); Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); } else if (attribute instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attribute; - - protocol.handle(channel, future, e); + protocol.handle(channel, future, msg); } else if (attribute != DiscardEvent.INSTANCE) { try { @@ -104,9 +86,11 @@ public void channelRead(final ChannelHandlerContext ctx, Object e) throws Except public void channelInactive(ChannelHandlerContext ctx) throws Exception { - if (closed.get()) { + if (requestSender.isClosed()) return; - } + + Channel channel = ctx.channel(); + channelManager.removeAll(channel); try { super.channelInactive(ctx); @@ -114,8 +98,6 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { LOGGER.trace("super.channelClosed", ex); } - Channel channel = ctx.channel(); - channels.removeAll(channel); Object attachment = Channels.getDefaultAttribute(channel); LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); @@ -128,20 +110,16 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { NettyResponseFuture future = NettyResponseFuture.class.cast(attachment); future.touch(); - if (!config.getIOExceptionFilters().isEmpty() - && requestSender.applyIoExceptionFiltersAndReplayRequest(future, new IOException("Channel Closed"), channel)) { + if (!config.getIOExceptionFilters().isEmpty() && requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) return; - } protocol.onClose(channel); - if (future != null && !future.isDone() && !future.isCancelled()) { - if (!requestSender.retry(future, channel)) { - channels.abort(future, AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION); - } - } else { - channels.closeChannel(channel); - } + if (future == null || future.isDone()) + channelManager.closeChannel(channel); + + else if (!requestSender.retry(future, channel)) + requestSender.abort(future, REMOTELY_CLOSED_EXCEPTION); } } @@ -149,9 +127,8 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception { Throwable cause = e.getCause() != null ? e.getCause() : e; - if (cause instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) { + if (cause instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) return; - } Channel channel = ctx.channel(); NettyResponseFuture future = null; @@ -167,12 +144,11 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep if (cause instanceof IOException) { - // FIXME why drop the original exception and create a new one? - if (!config.getIOExceptionFilters().isEmpty()) { - if (requestSender.applyIoExceptionFiltersAndReplayRequest(future, new IOException("Channel Closed"), channel)) { + // FIXME why drop the original exception and throw a new one? + if (!config.getIOExceptionFilters().isEmpty()) + if (requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) return; - } - } else { + else { // Close the channel so the recovering can occur try { channel.close(); @@ -194,18 +170,17 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep cause = t; } - if (future != null) { + if (future != null) try { LOGGER.debug("Was unable to recover Future: {}", future); - channels.abort(future, cause); + requestSender.abort(future, cause); } catch (Throwable t) { LOGGER.error(t.getMessage(), t); } - } protocol.onError(channel, e); - channels.closeChannel(channel); + channelManager.closeChannel(channel); // FIXME not really sure // ctx.fireChannelRead(e); ctx.close(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java old mode 100644 new mode 100755 index 59ff36c90e..8eb8363a47 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, * software distributed under the Apache License Version 2.0 is distributed on an @@ -16,8 +17,16 @@ import static io.netty.handler.codec.http.HttpResponseStatus.MOVED_PERMANENTLY; import static io.netty.handler.codec.http.HttpResponseStatus.SEE_OTHER; import static io.netty.handler.codec.http.HttpResponseStatus.TEMPORARY_REDIRECT; -import static org.asynchttpclient.providers.netty.util.HttpUtil.HTTP; -import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; +import static org.asynchttpclient.providers.netty.util.HttpUtils.HTTP; +import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.followRedirect; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpResponse; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; @@ -32,30 +41,21 @@ import org.asynchttpclient.filter.FilterContext; import org.asynchttpclient.filter.FilterException; import org.asynchttpclient.filter.ResponseFilter; +import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpResponse; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.Callable; - public abstract class Protocol { - private final Logger logger = LoggerFactory.getLogger(getClass()); + protected final Logger logger = LoggerFactory.getLogger(getClass()); - protected final Channels channels; + protected final ChannelManager channelManager; protected final AsyncHttpClientConfig config; protected final NettyAsyncHttpProviderConfig nettyConfig; protected final NettyRequestSender requestSender; @@ -64,18 +64,17 @@ public abstract class Protocol { protected final boolean hasIOExceptionFilters; private final TimeConverter timeConverter; - public static final Set REDIRECT_STATUSES = new HashSet(); - + public static final Set REDIRECT_STATUSES = new HashSet(); static { - REDIRECT_STATUSES.add(MOVED_PERMANENTLY); - REDIRECT_STATUSES.add(FOUND); - REDIRECT_STATUSES.add(SEE_OTHER); - REDIRECT_STATUSES.add(TEMPORARY_REDIRECT); + REDIRECT_STATUSES.add(MOVED_PERMANENTLY.code()); + REDIRECT_STATUSES.add(FOUND.code()); + REDIRECT_STATUSES.add(SEE_OTHER.code()); + REDIRECT_STATUSES.add(TEMPORARY_REDIRECT.code()); } - public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, + public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { - this.channels = channels; + this.channelManager = channelManager; this.config = config; this.requestSender = requestSender; this.nettyConfig = nettyConfig; @@ -91,12 +90,14 @@ public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpP public abstract void onClose(Channel channel); - protected boolean handleRedirectAndExit(Request request, final NettyResponseFuture future, HttpResponse response, final Channel channel) - throws Exception { - - io.netty.handler.codec.http.HttpResponseStatus status = response.getStatus(); + protected boolean exitAfterHandlingRedirect(// + Channel channel,// + NettyResponseFuture future,// + HttpResponse response,// + Request request,// + int statusCode) throws Exception { - if (AsyncHttpProviderUtils.followRedirect(config, request) && REDIRECT_STATUSES.contains(status)) { + if (followRedirect(config, request) && REDIRECT_STATUSES.contains(statusCode)) { if (future.incrementAndGetCurrentRedirectCount() >= config.getMaxRedirects()) { throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); @@ -104,7 +105,8 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu // We must allow 401 handling again. future.getAndSetAuth(false); - String location = response.headers().get(HttpHeaders.Names.LOCATION); + HttpHeaders responseHeaders = response.headers(); + String location = responseHeaders.get(HttpHeaders.Names.LOCATION); UriComponents uri = UriComponents.create(future.getURI(), location); if (!uri.equals(future.getURI())) { @@ -113,15 +115,14 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu if (!config.isRemoveQueryParamOnRedirect()) requestBuilder.addQueryParams(future.getRequest().getQueryParams()); - // FIXME why not do that for 301 and 307 too? - // FIXME I think condition is wrong - if ((status.equals(FOUND) || status.equals(SEE_OTHER)) && !(status.equals(FOUND) && config.isStrict302Handling())) { - requestBuilder.setMethod(HttpMethod.GET.name()); - } + // if we are to strictly handle 302, we should keep the original method (which browsers don't) + // 303 must force GET + if ((statusCode == FOUND.code() && !config.isStrict302Handling()) || statusCode == SEE_OTHER.code()) + requestBuilder.setMethod("GET"); // in case of a redirect from HTTP to HTTPS, future attributes might change final boolean initialConnectionKeepAlive = future.isKeepAlive(); - final String initialPoolKey = channels.getPoolKey(future); + final String initialPoolKey = channelManager.getPoolKey(future); future.setURI(uri); String newUrl = uri.toString(); @@ -131,23 +132,13 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu logger.debug("Redirecting to {}", newUrl); - if (future.getHttpHeaders().contains(HttpHeaders.Names.SET_COOKIE2)) { - for (String cookieStr : future.getHttpHeaders().getAll(HttpHeaders.Names.SET_COOKIE2)) { - Cookie c = CookieDecoder.decode(cookieStr, timeConverter); - if (c != null) { - requestBuilder.addOrReplaceCookie(c); - } - } - } else if (future.getHttpHeaders().contains(HttpHeaders.Names.SET_COOKIE)) { - for (String cookieStr : future.getHttpHeaders().getAll(HttpHeaders.Names.SET_COOKIE)) { - Cookie c = CookieDecoder.decode(cookieStr, timeConverter); - if (c != null) { - requestBuilder.addOrReplaceCookie(c); - } - } + for (String cookieStr : responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE)) { + Cookie c = CookieDecoder.decode(cookieStr, timeConverter); + if (c != null) + requestBuilder.addOrReplaceCookie(c); } - Callable> callback = channels.newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); + Callback callback = channelManager.newDrainCallback(future, channel, initialConnectionKeepAlive, initialPoolKey); if (HttpHeaders.isTransferEncodingChunked(response)) { // We must make sure there is no bytes left before @@ -170,14 +161,15 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu return false; } - protected boolean handleResponseFiltersReplayRequestAndExit(// + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected boolean exitAfterProcessingFilters(// Channel channel,// NettyResponseFuture future,// + AsyncHandler handler, // HttpResponseStatus status,// HttpResponseHeaders responseHeaders) throws IOException { if (hasResponseFilters) { - AsyncHandler handler = future.getAsyncHandler(); FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) .responseStatus(status).responseHeaders(responseHeaders).build(); @@ -189,7 +181,7 @@ protected boolean handleResponseFiltersReplayRequestAndExit(// throw new NullPointerException("FilterContext is null"); } } catch (FilterException efe) { - channels.abort(future, efe); + requestSender.abort(future, efe); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java old mode 100644 new mode 100755 index 5aa2ce0663..8859822341 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -1,21 +1,31 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.handler; import static io.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS; +import static org.asynchttpclient.providers.netty.ws.WebSocketUtils.getAcceptKey; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; + +import java.io.IOException; +import java.util.Locale; import org.asynchttpclient.AsyncHandler.STATE; import org.asynchttpclient.AsyncHttpClientConfig; @@ -24,6 +34,7 @@ import org.asynchttpclient.Request; import org.asynchttpclient.providers.netty.DiscardEvent; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequestSender; @@ -31,33 +42,16 @@ import org.asynchttpclient.providers.netty.response.ResponseHeaders; import org.asynchttpclient.providers.netty.response.ResponseStatus; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; -import org.asynchttpclient.providers.netty.ws.WebSocketUtil; import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.LastHttpContent; -import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; +public final class WebSocketProtocol extends Protocol { -import java.io.IOException; -import java.util.Locale; - -final class WebSocketProtocol extends Protocol { - - private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketProtocol.class); - - public WebSocketProtocol(Channels channels,// + public WebSocketProtocol(ChannelManager channelManager,// AsyncHttpClientConfig config,// NettyAsyncHttpProviderConfig nettyConfig,// NettyRequestSender requestSender) { - super(channels, config, nettyConfig, requestSender); + super(channelManager, config, nettyConfig, requestSender); } // We don't need to synchronize as replacing the "ws-decoder" will @@ -67,27 +61,27 @@ private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { try { h.onSuccess(new NettyWebSocket(channel)); } catch (Exception ex) { - LOGGER.warn("onSuccess unexpected exception", ex); + logger.warn("onSuccess unexpected exception", ex); } } } @Override public void handle(Channel channel, NettyResponseFuture future, Object e) throws Exception { - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(future.getAsyncHandler()); + WebSocketUpgradeHandler handler = WebSocketUpgradeHandler.class.cast(future.getAsyncHandler()); Request request = future.getRequest(); if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - HttpResponseStatus status = new ResponseStatus(future.getURI(), response, config); + HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); - if (handleResponseFiltersReplayRequestAndExit(channel, future, status, responseHeaders)) { + if (exitAfterProcessingFilters(channel, future, handler, status, responseHeaders)) { return; } future.setHttpHeaders(response.headers()); - if (handleRedirectAndExit(request, future, response, channel)) + if (exitAfterHandlingRedirect(channel, future, response, request, response.getStatus().code())) return; boolean validStatus = response.getStatus().equals(SWITCHING_PROTOCOLS); @@ -99,45 +93,45 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr boolean validConnection = c != null && c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); - status = new ResponseStatus(future.getURI(), response, config); - final boolean statusReceived = h.onStatusReceived(status) == STATE.UPGRADE; + status = new ResponseStatus(future.getURI(), config, response); + final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; if (!statusReceived) { try { - h.onCompleted(); + handler.onCompleted(); } finally { future.done(); } return; } - final boolean headerOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; + final boolean headerOK = handler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; if (!headerOK || !validStatus || !validUpgrade || !validConnection) { - channels.abort(future, new IOException("Invalid handshake response")); + requestSender.abort(future, new IOException("Invalid handshake response")); return; } String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHttpRequest().headers() + String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers() .get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { - channels.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); + requestSender.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); } - Channels.upgradePipelineForWebSockets(channel); + channelManager.upgradePipelineForWebSockets(channel.pipeline()); - invokeOnSucces(channel, h); + invokeOnSucces(channel, handler); future.done(); } else if (e instanceof WebSocketFrame) { final WebSocketFrame frame = (WebSocketFrame) e; - NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - invokeOnSucces(channel, h); + NettyWebSocket webSocket = NettyWebSocket.class.cast(handler.onCompleted()); + invokeOnSucces(channel, handler); if (webSocket != null) { if (frame instanceof CloseWebSocketFrame) { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + Channels.setDiscard(channel); CloseWebSocketFrame closeFrame = CloseWebSocketFrame.class.cast(frame); webSocket.onClose(closeFrame.statusCode(), closeFrame.reasonText()); } else { @@ -145,7 +139,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (buf != null && buf.readableBytes() > 0) { try { NettyResponseBodyPart rp = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, frame.isFinalFragment()); - h.onBodyPartReceived(rp); + handler.onBodyPartReceived(rp); if (frame instanceof BinaryWebSocketFrame) { webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); @@ -158,12 +152,12 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr } } } else { - LOGGER.debug("UpgradeHandler returned a null NettyWebSocket "); + logger.debug("UpgradeHandler returned a null NettyWebSocket "); } } else if (e instanceof LastHttpContent) { // FIXME what to do with this kind of messages? } else { - LOGGER.error("Invalid message {}", e); + logger.error("Invalid message {}", e); } } @@ -171,7 +165,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr public void onError(Channel channel, Throwable e) { try { Object attribute = Channels.getDefaultAttribute(channel); - LOGGER.warn("onError {}", e); + logger.warn("onError {}", e); if (!(attribute instanceof NettyResponseFuture)) { return; } @@ -185,17 +179,16 @@ public void onError(Channel channel, Throwable e) { webSocket.close(); } } catch (Throwable t) { - LOGGER.error("onError", t); + logger.error("onError", t); } } @Override public void onClose(Channel channel) { - LOGGER.trace("onClose {}"); + logger.trace("onClose {}"); Object attribute = Channels.getDefaultAttribute(channel); - if (!(attribute instanceof NettyResponseFuture)) { + if (!(attribute instanceof NettyResponseFuture)) return; - } try { NettyResponseFuture nettyResponse = NettyResponseFuture.class.cast(attribute); @@ -203,11 +196,11 @@ public void onClose(Channel channel) { NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); // FIXME How could this test not succeed, we just checked above that attribute is a NettyResponseFuture???? - LOGGER.trace("Connection was closed abnormally (that is, with no close frame being sent)."); + logger.trace("Connection was closed abnormally (that is, with no close frame being sent)."); if (attribute != DiscardEvent.INSTANCE && webSocket != null) webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); } catch (Throwable t) { - LOGGER.error("onError", t); + logger.error("onError", t); } } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java old mode 100644 new mode 100755 index c1ca441e1f..b4254bc088 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -1,24 +1,23 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; + import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.future.StackTraceInspector; @@ -34,6 +33,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; + import java.net.ConnectException; import java.nio.channels.ClosedChannelException; @@ -47,27 +47,27 @@ final class NettyConnectListener implements ChannelFutureListener { private final AsyncHttpClientConfig config; private final NettyRequestSender requestSender; private final NettyResponseFuture future; - private final Channels channels; + private final ChannelManager channelManager; private final boolean channelPreempted; private final String poolKey; public NettyConnectListener(AsyncHttpClientConfig config,// - NettyRequestSender requestSender,// NettyResponseFuture future,// - Channels channels,// + NettyRequestSender requestSender,// + ChannelManager channelManager,// boolean channelPreempted,// String poolKey) { - this.requestSender = requestSender; this.config = config; this.future = future; - this.channels = channels; + this.requestSender = requestSender; + this.channelManager = channelManager; this.channelPreempted = channelPreempted; this.poolKey = poolKey; } private void abortChannelPreemption(String poolKey) { if (channelPreempted) - channels.abortChannelPreemption(poolKey); + channelManager.abortChannelPreemption(poolKey); } private void writeRequest(Channel channel) { @@ -79,7 +79,7 @@ private void writeRequest(Channel channel) { return; } - channels.registerOpenChannel(channel); + channelManager.registerOpenChannel(channel); future.attachChannel(channel, false); requestSender.writeRequest(future, channel); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java old mode 100644 new mode 100755 index 11eea6d69a..aec5d2fd03 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request; @@ -19,7 +17,7 @@ import io.netty.handler.codec.http.HttpRequest; -public class NettyRequest { +public final class NettyRequest { private final HttpRequest httpRequest; private final NettyBody body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java old mode 100644 new mode 100755 index 55bbc81b85..2b26b06e2e --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -1,25 +1,29 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isNTLM; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isWebSocket; +import static org.asynchttpclient.providers.netty.ws.WebSocketUtils.getKey; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.constructUserAgent; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.keepAliveHeaderValue; +import static org.asynchttpclient.util.AuthenticatorUtils.computeBasicAuthentication; +import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultFullHttpRequest; @@ -53,11 +57,8 @@ import org.asynchttpclient.providers.netty.request.body.NettyFileBody; import org.asynchttpclient.providers.netty.request.body.NettyInputStreamBody; import org.asynchttpclient.providers.netty.request.body.NettyMultipartBody; -import org.asynchttpclient.providers.netty.ws.WebSocketUtil; import org.asynchttpclient.spnego.SpnegoEngine; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.AuthenticatorUtils; import org.asynchttpclient.util.UTF8UrlEncoder; public final class NettyRequestFactory { @@ -74,7 +75,7 @@ public NettyRequestFactory(AsyncHttpClientConfig config, NettyAsyncHttpProviderC private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod method) { if (method == HttpMethod.CONNECT) - return AsyncHttpProviderUtils.getAuthority(uri); + return getAuthority(uri); else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) return uri.toString(); @@ -101,12 +102,12 @@ private String authorizationHeader(Request request, UriComponents uri, ProxyServ switch (realm.getAuthScheme()) { case BASIC: - authorizationHeader = AuthenticatorUtils.computeBasicAuthentication(realm); + authorizationHeader = computeBasicAuthentication(realm); break; case DIGEST: if (isNonEmpty(realm.getNonce())) { try { - authorizationHeader = AuthenticatorUtils.computeDigestAuthentication(realm); + authorizationHeader = computeDigestAuthentication(realm); } catch (NoSuchAlgorithmException e) { throw new SecurityException(e); } @@ -177,7 +178,7 @@ private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer } } } else { - proxyAuthorization = AuthenticatorUtils.computeBasicAuthentication(proxyServer); + proxyAuthorization = computeBasicAuthentication(proxyServer); } } @@ -228,8 +229,7 @@ private NettyBody body(Request request, HttpMethod method) throws IOException { } else if (request.getBodyGenerator() instanceof FileBodyGenerator) { FileBodyGenerator fileBodyGenerator = (FileBodyGenerator) request.getBodyGenerator(); - nettyBody = new NettyFileBody(fileBodyGenerator.getFile(), fileBodyGenerator.getRegionSeek(), - fileBodyGenerator.getRegionLength(), nettyConfig); + nettyBody = new NettyFileBody(fileBodyGenerator.getFile(), fileBodyGenerator.getRegionSeek(), fileBodyGenerator.getRegionLength(), nettyConfig); } else if (request.getBodyGenerator() instanceof InputStreamBodyGenerator) { nettyBody = new NettyInputStreamBody(InputStreamBodyGenerator.class.cast(request.getBodyGenerator()).getInputStream()); @@ -295,13 +295,12 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean if (method != HttpMethod.CONNECT && webSocket) { httpRequest.headers().set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); httpRequest.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - httpRequest.headers().set(HttpHeaders.Names.ORIGIN, - "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); - httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); + httpRequest.headers().set(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); + httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey()); httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); } else if (!httpRequest.headers().contains(HttpHeaders.Names.CONNECTION)) { - httpRequest.headers().set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); + httpRequest.headers().set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); } String hostHeader = hostHeader(request, uri); @@ -324,8 +323,7 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean // Add default user agent if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT)) { - String userAgent = config.getUserAgent() != null ? config.getUserAgent() : AsyncHttpProviderUtils.constructUserAgent( - NettyAsyncHttpProvider.class, config); + String userAgent = config.getUserAgent() != null ? config.getUserAgent() : constructUserAgent(NettyAsyncHttpProvider.class, config); httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, userAgent); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java old mode 100644 new mode 100755 index 79b76edb3d..5dd4ee7674 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -1,22 +1,40 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request; -import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getDefaultPort; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.requestTimeout; +import static org.asynchttpclient.util.ProxyUtils.avoidProxy; +import static org.asynchttpclient.util.ProxyUtils.getProxyServer; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHandlerExtensions; @@ -31,133 +49,150 @@ import org.asynchttpclient.filter.IOExceptionFilter; import org.asynchttpclient.listener.TransferCompletionHandler; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.timeout.ReadTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.RequestTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.ProxyUtils; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.util.Timeout; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; - -public class NettyRequestSender { +public final class NettyRequestSender { private static final Logger LOGGER = LoggerFactory.getLogger(NettyRequestSender.class); - private final AtomicBoolean closed; private final AsyncHttpClientConfig config; - private final Channels channels; + private final ChannelManager channelManager; + private final Timer nettyTimer; + private final AtomicBoolean closed; private final NettyRequestFactory requestFactory; - public NettyRequestSender(AtomicBoolean closed,// - AsyncHttpClientConfig config,// + public NettyRequestSender(AsyncHttpClientConfig config,// NettyAsyncHttpProviderConfig nettyConfig,// - Channels channels) { - this.closed = closed; + ChannelManager channelManager,// + Timer nettyTimer,// + AtomicBoolean closed) { this.config = config; - this.channels = channels; + this.channelManager = channelManager; + this.nettyTimer = nettyTimer; + this.closed = closed; requestFactory = new NettyRequestFactory(config, nettyConfig); } - public boolean retry(NettyResponseFuture future, Channel channel) { + public ListenableFuture sendRequest(final Request request,// + final AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache) throws IOException { if (closed.get()) - return false; + throw new IOException("Closed"); - channels.removeAll(channel); + UriComponents uri = request.getURI(); - if (future == null) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) - future = (NettyResponseFuture) attachment; - } + // FIXME really useful? Why not do this check when building the request? + if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) + throw new IOException("WebSocket method must be a GET"); - if (future != null && future.canBeReplayed()) { - future.setState(NettyResponseFuture.STATE.RECONNECTED); - future.getAndSetStatusReceived(false); + ProxyServer proxyServer = getProxyServer(config, request); + boolean resultOfAConnect = future != null && future.getNettyRequest() != null && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; + boolean useProxy = proxyServer != null && !resultOfAConnect; - LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } + if (useProxy && isSecure(uri)) + // SSL proxy, have to handle CONNECT + if (future != null && future.isConnectAllowed()) + // CONNECT forced + return sendRequestWithCertainForceConnect(request, asyncHandler, future, reclaimCache, uri, proxyServer, true, true); + else + return sendRequestThroughSslProxy(request, asyncHandler, future, reclaimCache, uri, proxyServer); + else + return sendRequestWithCertainForceConnect(request, asyncHandler, future, reclaimCache, uri, proxyServer, useProxy, false); + } - try { - sendNextRequest(future.getRequest(), future); - return true; - - } catch (IOException iox) { - future.setState(NettyResponseFuture.STATE.CLOSED); - future.abort(iox); - LOGGER.error("Remotely Closed, unable to recover", iox); - return false; - } - } else { - LOGGER.debug("Unable to recover future {}\n", future); - return false; - } + /** + * We know for sure if we have to force to connect or not, so we can build + * the HttpRequest right away This reduces the probability of having a + * pooled channel closed by the server by the time we build the request + */ + private ListenableFuture sendRequestWithCertainForceConnect(// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache,// + UriComponents uri,// + ProxyServer proxyServer,// + boolean useProxy,// + boolean forceConnect) throws IOException { + + NettyResponseFuture newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, forceConnect); + + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + + if (Channels.isChannelValid(channel)) + return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); + else + return sendRequestWithNewChannel(request, uri, proxyServer, useProxy, newFuture, asyncHandler, reclaimCache); } - public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture future, IOException e, Channel channel) - throws IOException { + /** + * Using CONNECT depends on wither we can fetch a valid channel or not Loop + * until we get a valid channel from the pool and it's still valid once the + * request is built + */ + private ListenableFuture sendRequestThroughSslProxy(// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache,// + UriComponents uri,// + ProxyServer proxyServer) throws IOException { - boolean replayed = false; + NettyResponseFuture newFuture = null; + for (int i = 0; i < 3; i++) { + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + if (Channels.isChannelValid(channel)) + if (newFuture == null) + newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, false); - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()) - .ioException(e).build(); - for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - channels.abort(future, efe); - } + if (Channels.isChannelValid(channel)) + // if the channel is still active, we can use it, otherwise try + // gain + return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); + else + // pool is empty + break; } - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - replayed = true; - } - return replayed; + newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, true); + return sendRequestWithNewChannel(request, uri, proxyServer, true, newFuture, asyncHandler, reclaimCache); } - public void sendNextRequest(final Request request, final NettyResponseFuture f) throws IOException { - sendRequest(request, f.getAsyncHandler(), f, true); - } + private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture originalFuture, + UriComponents uri, ProxyServer proxy, boolean forceConnect) throws IOException { - // FIXME is this useful? Can't we do that when building the request? - private final boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { - return request.getMethod().equals(HttpMethod.GET.name()) && asyncHandler instanceof WebSocketUpgradeHandler; + NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); + + if (originalFuture == null) { + return newNettyResponseFuture(uri, request, asyncHandler, nettyRequest, proxy); + } else { + originalFuture.setNettyRequest(nettyRequest); + originalFuture.setRequest(request); + return originalFuture; + } } private Channel getCachedChannel(NettyResponseFuture future, UriComponents uri, ConnectionPoolKeyStrategy poolKeyGen, ProxyServer proxyServer) { - if (future != null && future.reuseChannel() && isChannelValid(future.channel())) + if (future != null && future.reuseChannel() && Channels.isChannelValid(future.channel())) return future.channel(); else - return channels.pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); + return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); } - private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, - NettyResponseFuture future, AsyncHandler asyncHandler, Channel channel) throws IOException { + private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, NettyResponseFuture future, + AsyncHandler asyncHandler, Channel channel) throws IOException { future.setState(NettyResponseFuture.STATE.POOLED); future.attachChannel(channel, false); @@ -186,26 +221,6 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur return future; } - private InetSocketAddress remoteAddress(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy) { - if (request.getInetAddress() != null) - return new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getDefaultPort(uri)); - - else if (!useProxy || ProxyUtils.avoidProxy(proxy, uri.getHost())) - return new InetSocketAddress(uri.getHost(), AsyncHttpProviderUtils.getDefaultPort(uri)); - - else - return new InetSocketAddress(proxy.getHost(), proxy.getPort()); - } - - private ChannelFuture connect(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy, Bootstrap bootstrap) { - InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); - - if (request.getLocalAddress() != null) - return bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); - else - return bootstrap.connect(remoteAddress); - } - private ListenableFuture sendRequestWithNewChannel(// Request request,// UriComponents uri,// @@ -217,43 +232,43 @@ private ListenableFuture sendRequestWithNewChannel(// boolean useSSl = isSecure(uri) && !useProxy; - // Do not throw an exception when we need an extra connection for a redirect + // Do not throw an exception when we need an extra connection for a + // redirect // FIXME why? This violate the max connection per host handling, right? - Bootstrap bootstrap = channels.getBootstrap(request.getURI(), useSSl, useProxy); - + Bootstrap bootstrap = channelManager.getBootstrap(request.getURI(), useProxy, useSSl); boolean channelPreempted = false; String poolKey = null; - - // Do not throw an exception when we need an extra connection for a redirect. + + // Do not throw an exception when we need an extra connection for a + // redirect. if (!reclaimCache) { // only compute when maxConnectionPerHost is enabled // FIXME clean up if (config.getMaxConnectionsPerHost() > 0) - poolKey = channels.getPoolKey(future); + poolKey = channelManager.getPoolKey(future); - channelPreempted = channels.preemptChannel(asyncHandler, poolKey); + channelPreempted = preemptChannel(asyncHandler, poolKey); } try { ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap); - channelFuture.addListener(new NettyConnectListener(config, this, future, channels, channelPreempted, poolKey)); + channelFuture.addListener(new NettyConnectListener(config, future, this, channelManager, channelPreempted, poolKey)); } catch (Throwable t) { if (channelPreempted) - channels.abortChannelPreemption(poolKey); + channelManager.abortChannelPreemption(poolKey); - channels.abort(future, t.getCause() == null ? t : t.getCause()); + abort(future, t.getCause() == null ? t : t.getCause()); } return future; } - private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, - NettyRequest nettyRequest, ProxyServer proxyServer) { + private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { - NettyResponseFuture f = new NettyResponseFuture(// + NettyResponseFuture future = new NettyResponseFuture(// uri,// request,// asyncHandler,// @@ -263,110 +278,76 @@ private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Req proxyServer); String expectHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT); - if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { - f.setDontWriteBodyBecauseExpectContinue(true); - } - return f; + if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) + future.setDontWriteBodyBecauseExpectContinue(true); + return future; } - private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, - NettyResponseFuture originalFuture, UriComponents uri, ProxyServer proxy, boolean forceConnect) throws IOException { - - NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); + public void writeRequest(NettyResponseFuture future, Channel channel) { + try { + // if the channel is dead because it was pooled and the remote + // server decided to close it, + // we just let it go and the channelInactive do its work + if (!Channels.isChannelValid(channel)) + return; - if (originalFuture == null) { - return newNettyResponseFuture(uri, request, asyncHandler, nettyRequest, proxy); - } else { - originalFuture.setNettyRequest(nettyRequest); - originalFuture.setRequest(request); - return originalFuture; - } - } + NettyRequest nettyRequest = future.getNettyRequest(); + HttpRequest httpRequest = nettyRequest.getHttpRequest(); + AsyncHandler handler = future.getAsyncHandler(); - private boolean isChannelValid(Channel channel) { - return channel != null && channel.isOpen() && channel.isActive(); - } + if (handler instanceof TransferCompletionHandler) + configureTransferAdapter(handler, httpRequest); - private ListenableFuture sendRequestThroughSslProxy(// - Request request,// - AsyncHandler asyncHandler,// - NettyResponseFuture future,// - boolean reclaimCache,// - UriComponents uri,// - ProxyServer proxyServer) throws IOException { + if (!future.isHeadersAlreadyWrittenOnContinue()) { + try { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); - // Using CONNECT depends on wither we can fetch a valid channel or not + channel.writeAndFlush(httpRequest, channel.newProgressivePromise()).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true, 0L)); + } catch (Throwable cause) { + // FIXME why not notify? + LOGGER.debug(cause.getMessage(), cause); + try { + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } + return; + } + } - // Loop until we get a valid channel from the pool and it's still valid once the request is built - NettyResponseFuture newFuture = null; - for (int i = 0; i < 3; i++) { - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); - if (isChannelValid(channel)) { - if (newFuture == null) - newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, false); + if (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) && nettyRequest.getBody() != null) + nettyRequest.getBody().write(channel, future, config); - if (isChannelValid(channel)) - // if the channel is still active, we can use it, otherwise try gain - return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); - } else - // pool is empty - break; + } catch (Throwable ioe) { + try { + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } } - newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, true); - return sendRequestWithNewChannel(request, uri, proxyServer, true, newFuture, asyncHandler, reclaimCache); + scheduleTimeouts(future); } - private ListenableFuture sendRequestWithCertainForceConnect(// - Request request,// - AsyncHandler asyncHandler,// - NettyResponseFuture future,// - boolean reclaimCache,// - UriComponents uri,// - ProxyServer proxyServer,// - boolean useProxy,// - boolean forceConnect) throws IOException { - // We know for sure if we have to force to connect or not, so we can build the HttpRequest right away - // This reduces the probability of having a pooled channel closed by the server by the time we build the request - NettyResponseFuture newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, forceConnect); + private InetSocketAddress remoteAddress(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy) { + if (request.getInetAddress() != null) + return new InetSocketAddress(request.getInetAddress(), getDefaultPort(uri)); - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + else if (!useProxy || avoidProxy(proxy, uri.getHost())) + return new InetSocketAddress(uri.getHost(), getDefaultPort(uri)); - if (isChannelValid(channel)) - return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); else - return sendRequestWithNewChannel(request, uri, proxyServer, useProxy, newFuture, asyncHandler, reclaimCache); + return new InetSocketAddress(proxy.getHost(), proxy.getPort()); } - public ListenableFuture sendRequest(final Request request,// - final AsyncHandler asyncHandler,// - NettyResponseFuture future,// - boolean reclaimCache) throws IOException { - - if (closed.get()) { - throw new IOException("Closed"); - } - - // FIXME really useful? Why not do this check when building the request? - if (request.getURI().getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { - throw new IOException("WebSocket method must be a GET"); - } - - UriComponents uri = request.getURI(); - ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - boolean resultOfAConnect = future != null && future.getNettyRequest() != null - && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; - boolean useProxy = proxyServer != null && !resultOfAConnect; + private ChannelFuture connect(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy, Bootstrap bootstrap) { + InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); - if (useProxy && isSecure(uri)) { - // SSL proxy, have to handle CONNECT - if (future != null && future.isConnectAllowed()) - // CONNECT forced - return sendRequestWithCertainForceConnect(request, asyncHandler, future, reclaimCache, uri, proxyServer, true, true); - else - return sendRequestThroughSslProxy(request, asyncHandler, future, reclaimCache, uri, proxyServer); - } else - return sendRequestWithCertainForceConnect(request, asyncHandler, future, reclaimCache, uri, proxyServer, useProxy, false); + if (request.getLocalAddress() != null) + return bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); + else + return bootstrap.connect(remoteAddress); } private void configureTransferAdapter(AsyncHandler handler, HttpRequest httpRequest) { @@ -382,88 +363,163 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { try { nettyResponseFuture.touch(); - int requestTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, nettyResponseFuture.getRequest()); + int requestTimeoutInMs = requestTimeout(config, nettyResponseFuture.getRequest()); TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); if (requestTimeoutInMs != -1) { - Timeout requestTimeout = channels.newTimeoutInMs(new RequestTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, - closed, requestTimeoutInMs), requestTimeoutInMs); + Timeout requestTimeout = newTimeout(new RequestTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, requestTimeoutInMs), requestTimeoutInMs); timeoutsHolder.requestTimeout = requestTimeout; } int readTimeout = config.getReadTimeout(); if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { - // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs - Timeout idleConnectionTimeout = channels.newTimeoutInMs(new ReadTimeoutTimerTask(nettyResponseFuture, channels, - timeoutsHolder, closed, requestTimeoutInMs, readTimeout), readTimeout); + // no need for a idleConnectionTimeout that's less than the + // requestTimeoutInMs + Timeout idleConnectionTimeout = newTimeout(new ReadTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, requestTimeoutInMs, readTimeout), readTimeout); timeoutsHolder.readTimeout = idleConnectionTimeout; } nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); } catch (RejectedExecutionException ex) { - channels.abort(nettyResponseFuture, ex); + abort(nettyResponseFuture, ex); } } - public final void writeRequest(NettyResponseFuture future, Channel channel) { - try { - // if the channel is dead because it was pooled and the remote server decided to close it, - // we just let it go and the channelInactive do its work - if (!channel.isOpen() || !channel.isActive()) { - return; + public Timeout newTimeout(TimerTask task, long delay) { + return nettyTimer.newTimeout(task, delay, TimeUnit.MILLISECONDS); + } + + public void abort(NettyResponseFuture future, Throwable t) { + + Channel channel = future.channel(); + if (channel != null) + channelManager.closeChannel(channel); + + if (!future.isDone()) { + LOGGER.debug("Aborting Future {}\n", future); + LOGGER.debug(t.getMessage(), t); + } + + future.abort(t); + } + + public boolean retry(NettyResponseFuture future, Channel channel) { + + if (isClosed()) + return false; + + channelManager.removeAll(channel); + + if (future == null) { + Object attachment = Channels.getDefaultAttribute(channel); + if (attachment instanceof NettyResponseFuture) + future = (NettyResponseFuture) attachment; + } + + if (future != null && future.canBeReplayed()) { + future.setState(NettyResponseFuture.STATE.RECONNECTED); + future.getAndSetStatusReceived(false); + + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); } - NettyRequest nettyRequest = future.getNettyRequest(); - HttpRequest httpRequest = nettyRequest.getHttpRequest(); - AsyncHandler handler = future.getAsyncHandler(); + try { + sendNextRequest(future.getRequest(), future); + return true; - if (handler instanceof TransferCompletionHandler) { - configureTransferAdapter(handler, httpRequest); + } catch (IOException iox) { + future.setState(NettyResponseFuture.STATE.CLOSED); + future.abort(iox); + LOGGER.error("Remotely Closed, unable to recover", iox); + return false; } + } else { + LOGGER.debug("Unable to recover future {}\n", future); + return false; + } + } - if (!future.isHeadersAlreadyWrittenOnContinue()) { - try { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); - } - channel.writeAndFlush(httpRequest, channel.newProgressivePromise()).addListener( - new ProgressListener(config, future.getAsyncHandler(), future, true, 0L)); - } catch (Throwable cause) { - // FIXME why not notify? - LOGGER.debug(cause.getMessage(), cause); - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; + public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture future, IOException e, Channel channel) throws IOException { + + boolean replayed = false; + + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(e).build(); + for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { + try { + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); } + } catch (FilterException efe) { + abort(future, efe); } + } - if (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) - && nettyRequest.getBody() != null) - nettyRequest.getBody().write(channel, future, config); + if (fc.replayRequest() && future.canBeReplayed()) { + replayRequest(future, fc, channel); + replayed = true; + } + return replayed; + } + + public void sendNextRequest(final Request request, final NettyResponseFuture future) throws IOException { + sendRequest(request, future.getAsyncHandler(), future, true); + } + + // FIXME is this useful? Can't we do that when building the request? + private boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { + return request.getMethod().equals(HttpMethod.GET.name()) && asyncHandler instanceof WebSocketUpgradeHandler; + } + + private Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { + final Channel channel = channelManager.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); + + if (channel != null) { + LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); - } catch (Throwable ioe) { try { - channel.close(); - } catch (RuntimeException ex) { + channelManager.verifyChannelPipeline(channel.pipeline(), uri.getScheme()); + } catch (Exception ex) { LOGGER.debug(ex.getMessage(), ex); } } + return channel; + } - scheduleTimeouts(future); + private boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) throws IOException { + + boolean channelPreempted = false; + if (channelManager.preemptChannel(poolKey)) { + channelPreempted = true; + } else { + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); + try { + asyncHandler.onThrowable(ex); + } catch (Exception e) { + LOGGER.warn("asyncHandler.onThrowable crashed", e); + } + throw ex; + } + return channelPreempted; } + @SuppressWarnings({ "rawtypes", "unchecked" }) public void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { + Request newRequest = fc.getRequest(); future.setAsyncHandler(fc.getAsyncHandler()); future.setState(NettyResponseFuture.STATE.NEW); future.touch(); LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } - channels.drainChannel(channel, future); + + channelManager.drainChannel(channel, future); sendNextRequest(newRequest, future); } + + public boolean isClosed() { + return closed.get(); + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java old mode 100644 new mode 100755 index 78c9f35919..8e1b7fe2cd --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request; @@ -41,8 +39,11 @@ public class ProgressListener implements ChannelProgressiveFutureListener { private final long expectedTotal; private long lastProgress = 0L; - public ProgressListener(AsyncHttpClientConfig config, AsyncHandler asyncHandler, NettyResponseFuture future, - boolean notifyHeaders, long expectedTotal) { + public ProgressListener(AsyncHttpClientConfig config,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean notifyHeaders,// + long expectedTotal) { this.config = config; this.asyncHandler = asyncHandler; this.future = future; @@ -83,7 +84,8 @@ private boolean abortOnThrowable(Throwable cause, Channel channel) { @Override public void operationComplete(ChannelProgressiveFuture cf) { - // The write operation failed. If the channel was cached, it means it got asynchronously closed. + // The write operation failed. If the channel was cached, it means it + // got asynchronously closed. // Let's retry a second time. if (!abortOnThrowable(cf.cause(), cf.channel())) { @@ -91,9 +93,10 @@ public void operationComplete(ChannelProgressiveFuture cf) { future.touch(); /** - * We need to make sure we aren't in the middle of an authorization process before publishing events as we - * will re-publish again the same event after the authorization, - * causing unpredictable behavior. + * We need to make sure we aren't in the middle of an authorization + * process before publishing events as we will re-publish again the + * same event after the authorization, causing unpredictable + * behavior. */ Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : config.getRealm(); boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java old mode 100644 new mode 100755 index 271046a3e7..e48d6d8a13 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, * software distributed under the Apache License Version 2.0 is distributed on an diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java old mode 100644 new mode 100755 index 857b610784..49fabeef29 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, * software distributed under the Apache License Version 2.0 is distributed on an diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java old mode 100644 new mode 100755 index 97bdc34701..dbff022523 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, * software distributed under the Apache License Version 2.0 is distributed on an diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java old mode 100644 new mode 100755 index c35606d17b..cea79857c3 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java old mode 100644 new mode 100755 index fb9108e7b1..7dac353e5b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java old mode 100644 new mode 100755 index eb2e9e9bfb..953461fb84 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java old mode 100644 new mode 100755 index 5360943b26..3043bd3e32 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java old mode 100644 new mode 100755 index e848c21e39..4412cd9bf4 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java old mode 100644 new mode 100755 index 742ed21657..0c69440533 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java @@ -1,34 +1,33 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.multipart.MultipartUtils.newMultipartBody; + +import java.util.List; + import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.multipart.MultipartBody; -import org.asynchttpclient.multipart.MultipartUtils; import org.asynchttpclient.multipart.Part; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import java.util.List; - public class NettyMultipartBody extends NettyBodyBody { private final String contentType; public NettyMultipartBody(List parts, FluentCaseInsensitiveStringsMap headers, NettyAsyncHttpProviderConfig nettyConfig) { - this(MultipartUtils.newMultipartBody(parts, headers), nettyConfig); + this(newMultipartBody(parts, headers), nettyConfig); } private NettyMultipartBody(MultipartBody body, NettyAsyncHttpProviderConfig nettyConfig) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java old mode 100644 new mode 100755 index 6199c9cd9b..c500bdd369 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -1,28 +1,23 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.timeout; import static org.asynchttpclient.util.DateUtils.millisTime; - -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; - import io.netty.util.Timeout; -import java.util.concurrent.atomic.AtomicBoolean; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; public class ReadTimeoutTimerTask extends TimeoutTimerTask { @@ -31,19 +26,18 @@ public class ReadTimeoutTimerTask extends TimeoutTimerTask { public ReadTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// - Channels channels,// + NettyRequestSender requestSender,// TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed,// long requestTimeout,// long readTimeout) { - super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); + super(nettyResponseFuture, requestSender, timeoutsHolder); this.readTimeout = readTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; } @Override public void run(Timeout timeout) throws Exception { - if (clientClosed.get()) { + if (requestSender.isClosed()) { timeoutsHolder.cancel(); return; } @@ -64,7 +58,7 @@ public void run(Timeout timeout) throws Exception { } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.readTimeout = channels.newTimeoutInMs(this, durationBeforeCurrentReadTimeout); + timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java old mode 100644 new mode 100755 index cb4d2ca509..51c72d1574 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -1,28 +1,23 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.timeout; import static org.asynchttpclient.util.DateUtils.millisTime; - -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; - import io.netty.util.Timeout; -import java.util.concurrent.atomic.AtomicBoolean; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; public class RequestTimeoutTimerTask extends TimeoutTimerTask { @@ -30,11 +25,10 @@ public class RequestTimeoutTimerTask extends TimeoutTimerTask { public RequestTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// - Channels channels,// + NettyRequestSender requestSender,// TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed,// long requestTimeout) { - super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); + super(nettyResponseFuture, requestSender, timeoutsHolder); this.requestTimeout = requestTimeout; } @@ -44,9 +38,8 @@ public void run(Timeout timeout) throws Exception { // in any case, cancel possible idleConnectionTimeout timeoutsHolder.cancel(); - if (clientClosed.get()) { + if (requestSender.isClosed()) return; - } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + requestTimeout + " ms"; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java old mode 100644 new mode 100755 index e599e5d871..b774b7763a --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java @@ -1,52 +1,46 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.timeout; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.util.TimerTask; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; + +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class TimeoutTimerTask implements TimerTask { private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutTimerTask.class); protected final NettyResponseFuture nettyResponseFuture; - protected final Channels channels; + protected final NettyRequestSender requestSender; protected final TimeoutsHolder timeoutsHolder; - protected final AtomicBoolean clientClosed; public TimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// - Channels channels,// - TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed) { + NettyRequestSender requestSender,// + TimeoutsHolder timeoutsHolder) { this.nettyResponseFuture = nettyResponseFuture; - this.channels = channels; + this.requestSender = requestSender; this.timeoutsHolder = timeoutsHolder; - this.clientClosed = clientClosed; } protected void expire(String message, long ms) { LOGGER.debug("{} for {} after {} ms", message, nettyResponseFuture, ms); - channels.abort(nettyResponseFuture, new TimeoutException(message)); + requestSender.abort(nettyResponseFuture, new TimeoutException(message)); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java old mode 100644 new mode 100755 index d032672a4a..9e6f1cb22f --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.request.timeout; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java old mode 100644 new mode 100755 index aad1f2e5af..afccb511ee --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.providers.netty.response; -import org.asynchttpclient.providers.netty.util.ByteBufUtil; +import static org.asynchttpclient.providers.netty.util.ByteBufUtils.*; import io.netty.buffer.ByteBuf; @@ -32,7 +32,7 @@ public class EagerResponseBodyPart extends NettyResponseBodyPart { public EagerResponseBodyPart(ByteBuf buf, boolean last) { super(last); - bytes = ByteBufUtil.byteBuf2Bytes(buf); + bytes = byteBuf2Bytes(buf); } /** diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java old mode 100644 new mode 100755 index 94eb15d70d..17d593541e --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java @@ -1,30 +1,20 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.response; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.HttpResponseHeaders; -import org.asynchttpclient.HttpResponseStatus; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.cookie.CookieDecoder; -import org.asynchttpclient.date.TimeConverter; -import org.asynchttpclient.providers.ResponseBase; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.MiscUtils; - +import static org.asynchttpclient.util.AsyncHttpProviderUtils.contentToBytes; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import io.netty.handler.codec.http.HttpHeaders; import java.io.ByteArrayInputStream; @@ -35,6 +25,14 @@ import java.util.Collections; import java.util.List; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.HttpResponseHeaders; +import org.asynchttpclient.HttpResponseStatus; +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.cookie.CookieDecoder; +import org.asynchttpclient.date.TimeConverter; +import org.asynchttpclient.providers.ResponseBase; + /** * Wrapper around the {@link org.asynchttpclient.Response} API. */ @@ -58,7 +56,7 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { // should be fine; except that it may split multi-byte chars (last char may become '?') charset = calculateCharset(charset); - byte[] b = AsyncHttpProviderUtils.contentToBytes(bodyParts, maxLength); + byte[] b = contentToBytes(bodyParts, maxLength); return new String(b, charset); } @@ -66,11 +64,11 @@ protected List buildCookies() { List setCookieHeaders = headers.getHeaders().get(HttpHeaders.Names.SET_COOKIE2); - if (!MiscUtils.isNonEmpty(setCookieHeaders)) { + if (!isNonEmpty(setCookieHeaders)) { setCookieHeaders = headers.getHeaders().get(HttpHeaders.Names.SET_COOKIE); } - if (MiscUtils.isNonEmpty(setCookieHeaders)) { + if (isNonEmpty(setCookieHeaders)) { List cookies = new ArrayList(); for (String value : setCookieHeaders) { Cookie c = CookieDecoder.decode(value, timeConverter); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java old mode 100644 new mode 100755 index 2c50ce6a79..76399a14e6 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java @@ -1,17 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.response; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java old mode 100644 new mode 100755 index 5f9f56da92..a40068965f --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java @@ -1,17 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.response; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java old mode 100644 new mode 100755 index 996038de10..1c74721d23 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java @@ -1,18 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient.providers.netty.response; @@ -34,7 +31,7 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public ResponseStatus(UriComponents uri, HttpResponse response, AsyncHttpClientConfig config) { + public ResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { super(uri, config); this.response = response; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtils.java old mode 100644 new mode 100755 similarity index 96% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtil.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtils.java index 9c6bb8d7a7..f370ac153b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtils.java @@ -19,11 +19,11 @@ import java.util.List; -public final class ByteBufUtil { +public final class ByteBufUtils { public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - private ByteBufUtil() { + private ByteBufUtils() { } public static byte[] byteBuf2Bytes(ByteBuf buf) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java old mode 100644 new mode 100755 similarity index 96% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java index 906bc7e8eb..b7ab94e3fc --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java @@ -18,14 +18,14 @@ import org.asynchttpclient.uri.UriComponents; -public final class HttpUtil { +public final class HttpUtils { public static final String HTTPS = "https"; public static final String HTTP = "http"; public static final String WEBSOCKET = "ws"; public static final String WEBSOCKET_SSL = "wss"; - private HttpUtil() { + private HttpUtils() { } public static boolean isNTLM(List auth) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java old mode 100644 new mode 100755 index e9c32e6f28..2a87ac293b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, * software distributed under the Apache License Version 2.0 is distributed on an diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtils.java old mode 100644 new mode 100755 similarity index 91% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtils.java index 4097ab31d6..c308edaea4 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtils.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * * This program is licensed to you under the Apache License Version 2.0, * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, * software distributed under the Apache License Version 2.0 is distributed on an @@ -19,7 +20,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -public final class WebSocketUtil { +public final class WebSocketUtils { public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; From 5ee604e48ed96f306cbea6fc4dfd83702fe8553b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 10:59:37 +0200 Subject: [PATCH 0029/1949] Would would write schemes not in lowercase? --- .../org/asynchttpclient/providers/netty/util/HttpUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java index b7ab94e3fc..e13b7ee51b 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java @@ -33,11 +33,11 @@ public static boolean isNTLM(List auth) { } public static boolean isWebSocket(String scheme) { - return WEBSOCKET.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + return WEBSOCKET.equals(scheme) || WEBSOCKET_SSL.equals(scheme); } public static boolean isSecure(String scheme) { - return HTTPS.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + return HTTPS.equals(scheme) || WEBSOCKET_SSL.equals(scheme); } public static boolean isSecure(UriComponents uri) { From 743e728f885ac0413e1a246c4f7e46828db4ae68 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 11:28:24 +0200 Subject: [PATCH 0030/1949] Rename DefaultAttribute into Attribute --- .../netty/channel/ChannelManager.java | 35 ++++++++++++------- .../providers/netty/channel/Channels.java | 11 ++---- .../channel/pool/DefaultChannelPool.java | 6 ++-- .../providers/netty/handler/HttpProtocol.java | 2 +- .../providers/netty/handler/Processor.java | 20 +++++------ .../providers/netty/handler/Protocol.java | 2 +- .../netty/handler/WebSocketProtocol.java | 4 +-- .../netty/request/NettyConnectListener.java | 4 +-- .../netty/request/NettyRequestSender.java | 8 ++--- 9 files changed, 48 insertions(+), 44 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 047dfc2a26..647ced78fe 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -293,9 +293,9 @@ public void close() { openChannels.close(); for (Channel channel : openChannels) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attribute; future.cancelTimeouts(); } } @@ -362,16 +362,24 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep return sslHandler; } + public SslHandler getSslHandler(ChannelPipeline pipeline) { + return (SslHandler) pipeline.get(SSL_HANDLER); + } + + private boolean isSslHandlerConfigured(ChannelPipeline pipeline) { + return pipeline.get(SSL_HANDLER) != null; + } + public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host, int port) throws IOException, GeneralSecurityException { if (pipeline.get(HTTP_HANDLER) != null) pipeline.remove(HTTP_HANDLER); if (isSecure(scheme)) - if (pipeline.get(SSL_HANDLER) == null) { + if (isSslHandlerConfigured(pipeline)) { + pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); + } else { pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); pipeline.addFirst(SSL_HANDLER, createSslHandler(host, port)); - } else { - pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); } else @@ -392,13 +400,14 @@ public String getPoolKey(NettyResponseFuture future) { */ public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { - boolean isSecure = isSecure(scheme); - if (pipeline.get(SSL_HANDLER) != null) { - if (!isSecure) - pipeline.remove(SSL_HANDLER); + boolean sslHandlerConfigured = isSslHandlerConfigured(pipeline); + + if (isSecure(scheme)) { + if (!sslHandlerConfigured) + pipeline.addFirst(SSL_HANDLER, new SslInitializer(this)); - } else if (isSecure) - pipeline.addFirst(SSL_HANDLER, new SslInitializer(this)); + } else if (sslHandlerConfigured) + pipeline.remove(SSL_HANDLER); } public Bootstrap getBootstrap(UriComponents uri, boolean useProxy, boolean useSSl) { @@ -421,6 +430,6 @@ public void call() throws Exception { } public void drainChannel(final Channel channel, final NettyResponseFuture future) { - Channels.setDefaultAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); + Channels.setAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index eda10d57d9..a193ae5f01 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -14,7 +14,6 @@ package org.asynchttpclient.providers.netty.channel; import io.netty.channel.Channel; -import io.netty.handler.ssl.SslHandler; import io.netty.util.Attribute; import io.netty.util.AttributeKey; @@ -24,21 +23,17 @@ public class Channels { private static final AttributeKey DEFAULT_ATTRIBUTE = AttributeKey.valueOf("default"); - public static SslHandler getSslHandler(Channel channel) { - return channel.pipeline().get(SslHandler.class); - } - - public static Object getDefaultAttribute(Channel channel) { + public static Object getAttribute(Channel channel) { Attribute attr = channel.attr(DEFAULT_ATTRIBUTE); return attr != null ? attr.get() : null; } - public static void setDefaultAttribute(Channel channel, Object o) { + public static void setAttribute(Channel channel, Object o) { channel.attr(DEFAULT_ATTRIBUTE).set(o); } public static void setDiscard(Channel channel) { - setDefaultAttribute(channel, DiscardEvent.INSTANCE); + setAttribute(channel, DiscardEvent.INSTANCE); } public static boolean isChannelValid(Channel channel) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index 3a04157660..c5cbbaad49 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java @@ -150,9 +150,9 @@ private List expiredChannels(ConcurrentLinkedQueue poo } private boolean isChannelCloseable(Channel channel) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attribute; if (!future.isDone()) LOGGER.error("Future not in appropriate state %s, not closing", future); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 380121278c..17d739f515 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -239,7 +239,7 @@ public void call() throws Exception { if (future.isKeepAlive() && HttpHeaders.isTransferEncodingChunked(response)) // We must make sure there is no bytes left // before executing the next request. - Channels.setDefaultAttribute(channel, callback); + Channels.setAttribute(channel, callback); else callback.call(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 8cbd848de6..87a1a357df 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -64,12 +64,12 @@ public Processor(AsyncHttpClientConfig config,// public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { Channel channel = ctx.channel(); - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); if (attribute instanceof Callback && msg instanceof LastHttpContent) { Callback ac = (Callback) attribute; ac.call(); - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + Channels.setAttribute(channel, DiscardEvent.INSTANCE); } else if (attribute instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attribute; @@ -98,16 +98,16 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { LOGGER.trace("super.channelClosed", ex); } - Object attachment = Channels.getDefaultAttribute(channel); - LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); + Object attribute = Channels.getAttribute(channel); + LOGGER.debug("Channel Closed: {} with attribute {}", channel, attribute); - if (attachment instanceof Callback) { - Callback callback = (Callback) attachment; - Channels.setDefaultAttribute(channel, callback.future()); + if (attribute instanceof Callback) { + Callback callback = (Callback) attribute; + Channels.setAttribute(channel, callback.future()); callback.call(); - } else if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = NettyResponseFuture.class.cast(attachment); + } else if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = NettyResponseFuture.class.cast(attribute); future.touch(); if (!config.getIOExceptionFilters().isEmpty() && requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) @@ -136,7 +136,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); try { - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); if (attribute instanceof NettyResponseFuture) { future = (NettyResponseFuture) attribute; future.attachChannel(null, false); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 8eb8363a47..cffa03e2da 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -144,7 +144,7 @@ protected boolean exitAfterHandlingRedirect(// // We must make sure there is no bytes left before // executing the next request. // FIXME investigate this - Channels.setDefaultAttribute(channel, callback); + Channels.setAttribute(channel, callback); } else { // FIXME don't understand: this offers the connection to the pool, or even closes it, while the // request has not been sent, right? diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 8859822341..ba1ad04b02 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -164,7 +164,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr @Override public void onError(Channel channel, Throwable e) { try { - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); logger.warn("onError {}", e); if (!(attribute instanceof NettyResponseFuture)) { return; @@ -186,7 +186,7 @@ public void onError(Channel channel, Throwable e) { @Override public void onClose(Channel channel) { logger.trace("onClose {}"); - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); if (!(attribute instanceof NettyResponseFuture)) return; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index b4254bc088..6268c6acc8 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -85,9 +85,9 @@ private void writeRequest(Channel channel) { } public void onFutureSuccess(final Channel channel) throws ConnectException { - Channels.setDefaultAttribute(channel, future); + Channels.setAttribute(channel, future); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); - final SslHandler sslHandler = Channels.getSslHandler(channel); + final SslHandler sslHandler = channelManager.getSslHandler(channel.pipeline()); if (hostnameVerifier != null && sslHandler != null) { final String host = future.getURI().getHost(); sslHandler.handshakeFuture().addListener(new GenericFutureListener>() { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 5dd4ee7674..9d4d2e54d0 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -198,7 +198,7 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur future.attachChannel(channel, false); LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", channel, future.getNettyRequest().getHttpRequest()); - Channels.setDefaultAttribute(channel, future); + Channels.setAttribute(channel, future); try { writeRequest(future, channel); @@ -409,9 +409,9 @@ public boolean retry(NettyResponseFuture future, Channel channel) { channelManager.removeAll(channel); if (future == null) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) - future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) + future = (NettyResponseFuture) attribute; } if (future != null && future.canBeReplayed()) { From e57085973be212c20dc5af95c5aa2e9fc49790c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:16:40 +0200 Subject: [PATCH 0031/1949] clean up --- .../org/asynchttpclient/SSLEngineFactory.java | 20 +++++------ .../netty/NettyAsyncHttpProviderConfig.java | 35 ++++++++++++------- .../netty/channel/ChannelManager.java | 4 +-- .../netty/request/body/NettyBodyBody.java | 9 ++--- .../netty/request/body/NettyFileBody.java | 26 +++++++------- 5 files changed, 51 insertions(+), 43 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java b/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java index 0289a0e109..a7152bbb4a 100644 --- a/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java +++ b/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java @@ -1,17 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * Ning licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ package org.asynchttpclient; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index f066ab51d5..9c1c6ed330 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -31,7 +31,8 @@ import java.util.Set; /** - * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. + * This class can be used to pass Netty's internal configuration options. See + * Netty documentation for more information. */ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig, Object> { @@ -41,8 +42,10 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig name, Object value) { @@ -122,24 +125,19 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { private AdditionalChannelInitializer wssAdditionalChannelInitializer; /** - * HttpClientCodec's maxInitialLineLength + * Allow configuring Netty's HttpClientCodecs. */ private int httpClientCodecMaxInitialLineLength = 4096; - - /** - * HttpClientCodec's maxHeaderSize - */ private int httpClientCodecMaxHeaderSize = 8192; - - /** - * HttpClientCodec's maxChunkSize - */ private int httpClientCodecMaxChunkSize = 8192; private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); private ChannelPool channelPool; + /** + * Allow one to disable zero copy for bodies and use chunking instead + */ private boolean disableZeroCopy; private Timer nettyTimer; @@ -148,6 +146,11 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { private SSLEngineFactory sslEngineFactory; + /** + * chunkedFileChunkSize + */ + private int chunkedFileChunkSize = 8192; + public EventLoopGroup getEventLoopGroup() { return eventLoopGroup; } @@ -259,4 +262,12 @@ public SSLEngineFactory getSslEngineFactory() { public void setSslEngineFactory(SSLEngineFactory sslEngineFactory) { this.sslEngineFactory = sslEngineFactory; } + + public int getChunkedFileChunkSize() { + return chunkedFileChunkSize; + } + + public void setChunkedFileChunkSize(int chunkedFileChunkSize) { + this.chunkedFileChunkSize = chunkedFileChunkSize; + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 647ced78fe..bca5bdd1c1 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -362,11 +362,11 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep return sslHandler; } - public SslHandler getSslHandler(ChannelPipeline pipeline) { + public static SslHandler getSslHandler(ChannelPipeline pipeline) { return (SslHandler) pipeline.get(SSL_HANDLER); } - private boolean isSslHandlerConfigured(ChannelPipeline pipeline) { + public static boolean isSslHandlerConfigured(ChannelPipeline pipeline) { return pipeline.get(SSL_HANDLER) != null; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java index 7dac353e5b..43c39cfea7 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -18,6 +18,7 @@ import org.asynchttpclient.BodyGenerator; import org.asynchttpclient.RandomAccessBody; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; @@ -38,11 +39,11 @@ public class NettyBodyBody implements NettyBody { private static final Logger LOGGER = LoggerFactory.getLogger(NettyBodyBody.class); private final Body body; - private final boolean disableZeroCopy; + private final NettyAsyncHttpProviderConfig nettyConfig; public NettyBodyBody(Body body, NettyAsyncHttpProviderConfig nettyConfig) { this.body = body; - disableZeroCopy = nettyConfig.isDisableZeroCopy(); + this.nettyConfig = nettyConfig; } public Body getBody() { @@ -61,9 +62,9 @@ public String getContentType() { @Override public void write(final Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { - Object msg; - if (Channels.getSslHandler(channel) == null && body instanceof RandomAccessBody && !disableZeroCopy) { + Object msg; + if (!ChannelManager.isSslHandlerConfigured(channel.pipeline()) && body instanceof RandomAccessBody && !nettyConfig.isDisableZeroCopy()) { msg = new BodyFileRegion((RandomAccessBody) body); } else { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java index 3043bd3e32..7b5234e5cd 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java @@ -13,14 +13,6 @@ */ package org.asynchttpclient.providers.netty.request.body; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.ProgressListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelProgressiveFuture; @@ -33,16 +25,22 @@ import java.io.IOException; import java.io.RandomAccessFile; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.ProgressListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class NettyFileBody implements NettyBody { private static final Logger LOGGER = LoggerFactory.getLogger(NettyFileBody.class); - public final static int MAX_BUFFERED_BYTES = 8192; - private final File file; private final long offset; private final long length; - private final boolean disableZeroCopy; + private final NettyAsyncHttpProviderConfig nettyConfig; public NettyFileBody(File file, NettyAsyncHttpProviderConfig nettyConfig) throws IOException { this(file, 0, file.length(), nettyConfig); @@ -55,7 +53,7 @@ public NettyFileBody(File file, long offset, long length, NettyAsyncHttpProvider this.file = file; this.offset = offset; this.length = length; - disableZeroCopy = nettyConfig.isDisableZeroCopy(); + this.nettyConfig = nettyConfig; } public File getFile() { @@ -82,8 +80,8 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien try { ChannelFuture writeFuture; - if (Channels.getSslHandler(channel) != null || disableZeroCopy) { - writeFuture = channel.write(new ChunkedFile(raf, offset, length, MAX_BUFFERED_BYTES), channel.newProgressivePromise()); + if (ChannelManager.isSslHandlerConfigured(channel.pipeline()) || nettyConfig.isDisableZeroCopy()) { + writeFuture = channel.write(new ChunkedFile(raf, offset, length, nettyConfig.getChunkedFileChunkSize()), channel.newProgressivePromise()); } else { FileRegion region = new DefaultFileRegion(raf.getChannel(), offset, length); writeFuture = channel.write(region, channel.newProgressivePromise()); From 92023dabaacceee52c56d1702bec45fe11aad664 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:37:01 +0200 Subject: [PATCH 0032/1949] Make transferEncoding configurable, fix FilePart constructors, close #647 --- .../multipart/AbstractFilePart.java | 9 ++++--- .../multipart/ByteArrayPart.java | 11 +++++--- .../asynchttpclient/multipart/FilePart.java | 27 ++++++++++--------- .../asynchttpclient/multipart/PartBase.java | 6 ++--- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index a4d5f4e9b9..8e711d3a98 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java @@ -55,9 +55,12 @@ public abstract class AbstractFilePart extends PartBase { * @param charset * the charset encoding for this part */ - public AbstractFilePart(String name, String contentType, String charset, String contentId) { - super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset, - DEFAULT_TRANSFER_ENCODING, contentId); + public AbstractFilePart(String name, String contentType, String charset, String contentId, String transfertEncoding) { + super(name,// + contentType == null ? DEFAULT_CONTENT_TYPE : contentType,// + charset,// + contentId,// + transfertEncoding == null ? DEFAULT_TRANSFER_ENCODING : transfertEncoding); } protected void visitDispositionHeader(PartVisitor visitor) throws IOException { diff --git a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java index a7cd65337e..bc4660cb8e 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java @@ -37,14 +37,17 @@ public ByteArrayPart(String name, byte[] bytes, String contentType, String chars } public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId) { - super(name, contentType, charset, contentId); - if (bytes == null) { + this(name, bytes, contentType, charset, fileName, contentId, null); + } + + public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + super(name, contentType, charset, contentId, transferEncoding); + if (bytes == null) throw new NullPointerException("bytes"); - } this.bytes = bytes; setFileName(fileName); } - + @Override protected void sendData(OutputStream out) throws IOException { out.write(bytes); diff --git a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java index ed4cb93f09..3ea77ed562 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java @@ -31,36 +31,37 @@ public class FilePart extends AbstractFilePart { private final File file; public FilePart(String name, File file) { - this(name, file, null, null); + this(name, file, null); } public FilePart(String name, File file, String contentType) { - this(name, file, null, contentType, null); + this(name, file, contentType, null); } public FilePart(String name, File file, String contentType, String charset) { - this(name, file, null, contentType, charset, null); + this(name, file, contentType, charset, null); } public FilePart(String name, File file, String contentType, String charset, String fileName) { - this(name, file, null, contentType, charset, fileName); + this(name, file, contentType, charset, fileName, null); } public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId) { - super(name, contentType, charset, contentId); - this.file = file; - if (file == null) { + this(name, file, contentType, charset, fileName, contentId, null); + } + + public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + super(name, contentType, charset, contentId, transferEncoding); + if (file == null) throw new NullPointerException("file"); - } - if (!file.isFile()) { + if (!file.isFile()) throw new IllegalArgumentException("File is not a normal file " + file.getAbsolutePath()); - } - if (!file.canRead()) { + if (!file.canRead()) throw new IllegalArgumentException("File is not readable " + file.getAbsolutePath()); - } + this.file = file; setFileName(fileName != null ? fileName : file.getName()); } - + @Override protected void sendData(OutputStream out) throws IOException { if (getDataLength() == 0) { diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index 2d9d274705..6273fce8ed 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java @@ -55,15 +55,15 @@ public abstract class PartBase implements Part { * @param name The name of the part, or null * @param contentType The content type, or null * @param charSet The character encoding, or null - * @param transferEncoding The transfer encoding, or null * @param contentId The content id, or null + * @param transferEncoding The transfer encoding, or null */ - public PartBase(String name, String contentType, String charSet, String transferEncoding, String contentId) { + public PartBase(String name, String contentType, String charSet, String contentId, String transferEncoding) { this.name = name; this.contentType = contentType; this.charSet = charSet; - this.transferEncoding = transferEncoding; this.contentId = contentId; + this.transferEncoding = transferEncoding; } protected void visitStart(PartVisitor visitor, byte[] boundary) throws IOException { From 2a57096f0dc86d65028cf6ed5a19c454c81f5b68 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 17:14:19 +0200 Subject: [PATCH 0033/1949] Drop useless broken test --- .../async/AsyncStreamHandlerTest.java | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java index 835bdf31be..4bd4d6fe6a 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java @@ -327,47 +327,6 @@ public String onCompleted() throws Exception { } } - @Test(groups = { "online", "default_provider" }) - public void asyncStream302WithBody() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); - final AtomicReference statusCode = new AtomicReference(0); - final AtomicReference headers = new AtomicReference(); - try { - Future f = c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { - - public STATE onStatusReceived(HttpResponseStatus status) throws Exception { - statusCode.set(status.getStatusCode()); - return STATE.CONTINUE; - } - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - headers.set(content.getHeaders()); - return STATE.CONTINUE; - } - - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - return STATE.CONTINUE; - } - - @Override - public String onCompleted() throws Exception { - return null; - } - }); - - f.get(20, TimeUnit.SECONDS); - assertEquals(statusCode.get().intValue(), 302); - FluentCaseInsensitiveStringsMap h = headers.get(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH)); - - } finally { - c.close(); - } - } - @Test(groups = { "online", "default_provider" }) public void asyncStream302RedirectWithBody() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); From 98b66cbdd1594dbb61f2d1479f87e2eda35fd755 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 17:18:36 +0200 Subject: [PATCH 0034/1949] Fix RemoteSiteTest.testGoogleComWithTimeout, redirect depends on geoloc --- api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index f5b46b21fb..7e8ad5f21c 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -119,7 +119,7 @@ public void testGoogleComWithTimeout() throws Exception { try { Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); - assertEquals(response.getStatusCode(), 302); + assertTrue(response.getStatusCode() == 301 || response.getStatusCode() == 302); } finally { c.close(); } From 06a727f9f435bc5a7cac1efcca060bcd59605ec5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 08:53:43 +0200 Subject: [PATCH 0035/1949] Rename handshakeTimeoutInMillis into handshakeTimeout --- .../providers/netty/NettyAsyncHttpProviderConfig.java | 2 +- .../providers/netty/channel/ChannelManager.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 9c1c6ed330..185d7ea275 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -247,7 +247,7 @@ public void setNettyTimer(Timer nettyTimer) { this.nettyTimer = nettyTimer; } - public long getHandshakeTimeoutInMillis() { + public long getHandshakeTimeout() { return handshakeTimeoutInMillis; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index bca5bdd1c1..6fb3b03f3b 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -83,7 +83,7 @@ public class ChannelManager { private final Bootstrap webSocketBootstrap; private final Bootstrap secureWebSocketBootstrap; - private final long handshakeTimeoutInMillis; + private final long handshakeTimeout; private final ChannelPool channelPool; private final boolean maxConnectionsEnabled; @@ -144,7 +144,7 @@ public boolean remove(Object o) { channel2KeyPool = null; } - handshakeTimeoutInMillis = nettyConfig.getHandshakeTimeoutInMillis(); + handshakeTimeout = nettyConfig.getHandshakeTimeout(); // check if external EventLoopGroup is defined allowReleaseEventLoopGroup = nettyConfig.getEventLoopGroup() == null; @@ -356,8 +356,8 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep } SslHandler sslHandler = new SslHandler(sslEngine); - if (handshakeTimeoutInMillis > 0) - sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); + if (handshakeTimeout > 0) + sslHandler.setHandshakeTimeoutMillis(handshakeTimeout); return sslHandler; } From a48e469214b450a38bc3734a240d6e9f01560199 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 09:48:18 +0200 Subject: [PATCH 0036/1949] Rename Netty response elements --- .../netty/NettyAsyncHttpProviderConfig.java | 8 ++++---- .../providers/netty/handler/HttpProtocol.java | 14 +++++++------- .../providers/netty/handler/WebSocketProtocol.java | 10 +++++----- ...dyPart.java => EagerNettyResponseBodyPart.java} | 4 ++-- ...odyPart.java => LazyNettyResponseBodyPart.java} | 4 ++-- ...ponseHeaders.java => NettyResponseHeaders.java} | 6 +++--- ...esponseStatus.java => NettyResponseStatus.java} | 4 ++-- .../providers/netty/NettyAsyncResponseTest.java | 8 ++++---- 8 files changed, 29 insertions(+), 29 deletions(-) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{EagerResponseBodyPart.java => EagerNettyResponseBodyPart.java} (93%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{LazyResponseBodyPart.java => LazyNettyResponseBodyPart.java} (93%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{ResponseHeaders.java => NettyResponseHeaders.java} (90%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{ResponseStatus.java => NettyResponseStatus.java} (93%) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 185d7ea275..36659292ad 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -16,8 +16,8 @@ import org.asynchttpclient.AsyncHttpProviderConfig; import org.asynchttpclient.SSLEngineFactory; import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; -import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import io.netty.buffer.ByteBuf; @@ -102,7 +102,7 @@ public static class EagerResponseBodyPartFactory implements ResponseBodyPartFact @Override public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new EagerResponseBodyPart(buf, last); + return new EagerNettyResponseBodyPart(buf, last); } } @@ -110,7 +110,7 @@ public static class LazyResponseBodyPartFactory implements ResponseBodyPartFacto @Override public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new LazyResponseBodyPart(buf, last); + return new LazyNettyResponseBodyPart(buf, last); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 17d739f515..98be1659cb 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -50,8 +50,8 @@ import org.asynchttpclient.providers.netty.request.NettyRequest; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.ResponseHeaders; -import org.asynchttpclient.providers.netty.response.ResponseStatus; +import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; +import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.asynchttpclient.spnego.SpnegoEngine; import org.asynchttpclient.uri.UriComponents; @@ -345,7 +345,7 @@ private boolean exitAfterHandlingConnect(// return false; } - private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, ResponseStatus status) + private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, NettyResponseStatus status) throws IOException, Exception { if (!future.getAndSetStatusReceived(true) && handler.onStatusReceived(status) != STATE.CONTINUE) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); @@ -354,7 +354,7 @@ private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture return false; } - private boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, ResponseHeaders responseHeaders) + private boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, NettyResponseHeaders responseHeaders) throws IOException, Exception { if (!response.headers().isEmpty() && handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); @@ -375,11 +375,11 @@ private boolean handleHttpResponse(final HttpResponse response, final Channel ch future.setKeepAlive(!HttpHeaders.Values.CLOSE.equalsIgnoreCase(response.headers().get(HttpHeaders.Names.CONNECTION))); - ResponseStatus status = new ResponseStatus(future.getURI(), config, response); + NettyResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); int statusCode = response.getStatus().code(); Request request = future.getRequest(); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - ResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); + NettyResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); return exitAfterProcessingFilters(channel, future, handler, status, responseHeaders) || exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer) || // @@ -428,7 +428,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f LastHttpContent lastChunk = (LastHttpContent) chunk; HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); if (!trailingHeaders.isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), trailingHeaders); + NettyResponseHeaders responseHeaders = new NettyResponseHeaders(future.getHttpHeaders(), trailingHeaders); interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index ba1ad04b02..e8e0917338 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -39,8 +39,8 @@ import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.ResponseHeaders; -import org.asynchttpclient.providers.netty.response.ResponseStatus; +import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; +import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; @@ -73,8 +73,8 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); + HttpResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); + HttpResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); if (exitAfterProcessingFilters(channel, future, handler, status, responseHeaders)) { return; @@ -93,7 +93,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr boolean validConnection = c != null && c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); - status = new ResponseStatus(future.getURI(), config, response); + status = new NettyResponseStatus(future.getURI(), config, response); final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; if (!statusReceived) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerNettyResponseBodyPart.java similarity index 93% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerNettyResponseBodyPart.java index afccb511ee..e993bd4975 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerNettyResponseBodyPart.java @@ -26,11 +26,11 @@ * A callback class used when an HTTP response body is received. * Bytes are eagerly fetched from the ByteBuf */ -public class EagerResponseBodyPart extends NettyResponseBodyPart { +public class EagerNettyResponseBodyPart extends NettyResponseBodyPart { private final byte[] bytes; - public EagerResponseBodyPart(ByteBuf buf, boolean last) { + public EagerNettyResponseBodyPart(ByteBuf buf, boolean last) { super(last); bytes = byteBuf2Bytes(buf); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyNettyResponseBodyPart.java similarity index 93% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyNettyResponseBodyPart.java index 31091bd605..d3f136b9f1 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyNettyResponseBodyPart.java @@ -22,13 +22,13 @@ /** * A callback class used when an HTTP response body is received. */ -public class LazyResponseBodyPart extends NettyResponseBodyPart { +public class LazyNettyResponseBodyPart extends NettyResponseBodyPart { private static final String ERROR_MESSAGE = "This implementation is intended for one to directly read from the underlying ByteBuf and release after usage. Not for the fainted heart!"; private final ByteBuf buf; - public LazyResponseBodyPart(ByteBuf buf, boolean last) { + public LazyNettyResponseBodyPart(ByteBuf buf, boolean last) { super(last); this.buf = buf; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseHeaders.java similarity index 90% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseHeaders.java index a40068965f..375f0cd3bf 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseHeaders.java @@ -23,18 +23,18 @@ /** * A class that represent the HTTP headers. */ -public class ResponseHeaders extends HttpResponseHeaders { +public class NettyResponseHeaders extends HttpResponseHeaders { private final HttpHeaders responseHeaders; private final HttpHeaders trailingHeaders; private final FluentCaseInsensitiveStringsMap headers; // FIXME unused AsyncHttpProvider provider - public ResponseHeaders(HttpHeaders responseHeaders) { + public NettyResponseHeaders(HttpHeaders responseHeaders) { this(responseHeaders, null); } - public ResponseHeaders(HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { + public NettyResponseHeaders(HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { super(traillingHeaders != null); this.responseHeaders = responseHeaders; this.trailingHeaders = traillingHeaders; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseStatus.java similarity index 93% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseStatus.java index 1c74721d23..f869f35d1a 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseStatus.java @@ -27,11 +27,11 @@ /** * A class that represent the HTTP response' status line (code + text) */ -public class ResponseStatus extends HttpResponseStatus { +public class NettyResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public ResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { + public NettyResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { super(uri, config); this.response = response; } diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java index f35b77dafb..9158571853 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java @@ -19,7 +19,7 @@ import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.cookie.Cookie; import org.asynchttpclient.providers.netty.response.NettyResponse; -import org.asynchttpclient.providers.netty.response.ResponseStatus; +import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.testng.annotations.Test; import java.text.SimpleDateFormat; @@ -42,7 +42,7 @@ public void testCookieParseExpires() { Date date = new Date(System.currentTimeMillis() + 60000); final String cookieDef = String.format("efmembercheck=true; expires=%s; path=/; domain=.eclipse.org", sdf.format(date)); - NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders() { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders() { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -60,7 +60,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { @Test(groups = "standalone") public void testCookieParseMaxAge() { final String cookieDef = "efmembercheck=true; max-age=60; path=/; domain=.eclipse.org"; - NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders() { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders() { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -76,7 +76,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { @Test(groups = "standalone") public void testCookieParseWeirdExpiresValue() { final String cookieDef = "efmembercheck=true; expires=60; path=/; domain=.eclipse.org"; - NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders() { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders() { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); From e19c611843dc12b2702045896e4c992dba78e6ca Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 10:01:05 +0200 Subject: [PATCH 0037/1949] Fix log --- .../providers/netty/request/NettyConnectListener.java | 1 - .../providers/netty/request/NettyRequestSender.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 6268c6acc8..b463d70d55 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -126,7 +126,6 @@ public void onFutureFailure(Channel channel, Throwable cause) { && cause != null// && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { - LOGGER.debug("Retrying {} ", future.getNettyRequest()); if (requestSender.retry(future, channel)) { return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 9d4d2e54d0..207d0596e6 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -418,7 +418,7 @@ public boolean retry(NettyResponseFuture future, Channel channel) { future.setState(NettyResponseFuture.STATE.RECONNECTED); future.getAndSetStatusReceived(false); - LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest().getHttpRequest()); if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); } From 41e4c4716cb0876be4b5f97639572be86312a9e2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 14:18:38 +0200 Subject: [PATCH 0038/1949] Make acceptAnyCertificate doesn't disable HostnameVerifier, close #649 --- .../AsyncHttpClientConfig.java | 35 ++++++++++--------- .../AsyncHttpClientConfigBean.java | 1 - .../AsyncHttpClientConfigDefaults.java | 4 --- .../util/AllowAllHostnameVerifier.java | 22 ------------ 4 files changed, 19 insertions(+), 43 deletions(-) delete mode 100644 api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 5146b997a6..8f1aefbf30 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -17,15 +17,6 @@ import static org.asynchttpclient.AsyncHttpClientConfigDefaults.*; -import org.asynchttpclient.date.TimeConverter; -import org.asynchttpclient.filter.IOExceptionFilter; -import org.asynchttpclient.filter.RequestFilter; -import org.asynchttpclient.filter.ResponseFilter; -import org.asynchttpclient.util.ProxyUtils; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; - import java.io.IOException; import java.io.InputStream; import java.util.Collections; @@ -35,6 +26,16 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; + +import org.asynchttpclient.date.TimeConverter; +import org.asynchttpclient.filter.IOExceptionFilter; +import org.asynchttpclient.filter.RequestFilter; +import org.asynchttpclient.filter.ResponseFilter; +import org.asynchttpclient.util.DefaultHostnameVerifier; +import org.asynchttpclient.util.ProxyUtils; + /** * Configuration class to use with a {@link AsyncHttpClient}. System property can be also used to configure this * object default behavior by doing: @@ -538,7 +539,7 @@ public static class Builder { private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); private int connectionTTL = defaultConnectionTTL(); private SSLContext sslContext; - private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); + private HostnameVerifier hostnameVerifier; private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); private boolean followRedirect = defaultFollowRedirect(); private int maxRedirects = defaultMaxRedirects(); @@ -1082,17 +1083,19 @@ public Builder(AsyncHttpClientConfig prototype) { */ public AsyncHttpClientConfig build() { - if (proxyServerSelector == null && useProxySelector) { + if (proxyServerSelector == null && useProxySelector) proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); - } - if (proxyServerSelector == null && useProxyProperties) { + if (proxyServerSelector == null && useProxyProperties) proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties()); - } - if (proxyServerSelector == null) { + if (proxyServerSelector == null) proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR; - } + + if (acceptAnyCertificate) + hostnameVerifier = null; + else if (hostnameVerifier == null) + hostnameVerifier = new DefaultHostnameVerifier(); return new AsyncHttpClientConfig(connectionTimeout,// maxConnections,// diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index d68c6a8984..150187cea6 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -65,7 +65,6 @@ void configureDefaults() { disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); - hostnameVerifier = defaultHostnameVerifier(); acceptAnyCertificate = defaultAcceptAnyCertificate(); if (defaultUseProxySelector()) { diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 8ecd353491..83fdcedf3e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -113,10 +113,6 @@ public static boolean defaultRemoveQueryParamOnRedirect() { return getBoolean(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); } - public static HostnameVerifier defaultHostnameVerifier() { - return new DefaultHostnameVerifier(); - } - public static boolean defaultSpdyEnabled() { return Boolean.getBoolean(ASYNC_CLIENT + "spdyEnabled"); } diff --git a/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java b/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java deleted file mode 100644 index d32424daf9..0000000000 --- a/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ -package org.asynchttpclient.util; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; - -public class AllowAllHostnameVerifier implements HostnameVerifier { - public boolean verify(String s, SSLSession sslSession) { - return true; - } -} From cec8290eb87c56100656f40c85416a0432ded6e1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 14:58:52 +0200 Subject: [PATCH 0039/1949] minor clean up --- .../request/timeout/ReadTimeoutTimerTask.java | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java index c500bdd369..df77acd780 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -37,36 +37,31 @@ public ReadTimeoutTimerTask(// @Override public void run(Timeout timeout) throws Exception { - if (requestSender.isClosed()) { + + if (requestSender.isClosed() || nettyResponseFuture.isDone()) { timeoutsHolder.cancel(); return; } - if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - - long now = millisTime(); + long now = millisTime(); - long currentReadTimeoutInstant = readTimeout + nettyResponseFuture.getLastTouch(); - long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; + long currentReadTimeoutInstant = readTimeout + nettyResponseFuture.getLastTouch(); + long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; - if (durationBeforeCurrentReadTimeout <= 0L) { - // idleConnectionTimeout reached - String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; - long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); - expire(message, durationSinceLastTouch); - nettyResponseFuture.setIdleConnectionTimeoutReached(); + if (durationBeforeCurrentReadTimeout <= 0L) { + // idleConnectionTimeout reached + String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; + long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); + expire(message, durationSinceLastTouch); + nettyResponseFuture.setIdleConnectionTimeoutReached(); - } else if (currentReadTimeoutInstant < requestTimeoutInstant) { - // reschedule - timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); - - } else { - // otherwise, no need to reschedule: requestTimeout will happen sooner - timeoutsHolder.readTimeout = null; - } + } else if (currentReadTimeoutInstant < requestTimeoutInstant) { + // reschedule + timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); } else { - timeoutsHolder.cancel(); + // otherwise, no need to reschedule: requestTimeout will happen sooner + timeoutsHolder.readTimeout = null; } } } From eaf6109e3081d56df0da99b305d80d8d00bac3e9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:17:23 +0200 Subject: [PATCH 0040/1949] Fix NPE when passing a null charset, close #651 --- .../asynchttpclient/multipart/StringPart.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java index a6d60b7153..9ed500a561 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java @@ -18,6 +18,8 @@ import java.nio.channels.WritableByteChannel; import java.nio.charset.Charset; +import org.asynchttpclient.util.StandardCharsets; + public class StringPart extends PartBase { /** @@ -28,7 +30,7 @@ public class StringPart extends PartBase { /** * Default charset of string parameters */ - public static final String DEFAULT_CHARSET = "US-ASCII"; + public static final Charset DEFAULT_CHARSET = StandardCharsets.US_ASCII; /** * Default transfer encoding of string parameters @@ -40,6 +42,10 @@ public class StringPart extends PartBase { */ private final byte[] content; + private static Charset charsetOrDefault(String charset) { + return charset == null ? DEFAULT_CHARSET : Charset.forName(charset); + } + public StringPart(String name, String value, String charset) { this(name, value, charset, null); } @@ -58,15 +64,13 @@ public StringPart(String name, String value, String charset) { */ public StringPart(String name, String value, String charset, String contentId) { - super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId); - if (value == null) { + super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset).name(), DEFAULT_TRANSFER_ENCODING, contentId); + if (value == null) throw new NullPointerException("value"); - } - if (value.indexOf(0) != -1) { + if (value.indexOf(0) != -1) // See RFC 2048, 2.8. "8bit Data" throw new IllegalArgumentException("NULs may not be present in string parts"); - } - content = value.getBytes(Charset.forName(charset)); + content = value.getBytes(charsetOrDefault(charset)); } /** From cb4b4c4cd8d77b30fb5704b31321e21bdca5cf76 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:30:33 +0200 Subject: [PATCH 0041/1949] comment --- .../providers/netty/request/body/BodyChunkedInput.java | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java index e48d6d8a13..a9b50bd404 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java @@ -51,6 +51,7 @@ public ByteBuf readChunk(ChannelHandlerContext ctx) throws Exception { if (endOfInput) { return null; } else { + // FIXME pass a visitor so we can directly pass a pooled ByteBuf ByteBuffer buffer = ByteBuffer.allocate(chunkSize); long r = body.read(buffer); if (r < 0L) { From 30e106a242ea8d407406bb6e85d72dd02098547b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:40:40 +0200 Subject: [PATCH 0042/1949] Clean up warnings --- .../org/asynchttpclient/AsyncHttpClientConfigDefaults.java | 4 ---- .../java/org/asynchttpclient/util/ProxyHostnameChecker.java | 1 + .../test/java/org/asynchttpclient/async/util/TestUtils.java | 1 - .../asynchttpclient/websocket/CloseCodeReasonMessageTest.java | 4 ++-- .../providers/netty/request/NettyConnectListener.java | 2 +- .../providers/netty/request/NettyRequestSender.java | 2 ++ .../providers/netty/request/body/NettyBodyBody.java | 1 - 7 files changed, 6 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 83fdcedf3e..36991bfa2d 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -14,10 +14,6 @@ import static org.asynchttpclient.util.MiscUtils.getBoolean; -import org.asynchttpclient.util.DefaultHostnameVerifier; - -import javax.net.ssl.HostnameVerifier; - public final class AsyncHttpClientConfigDefaults { private AsyncHttpClientConfigDefaults() { diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java b/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java index 1355d9084f..3796911298 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java +++ b/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java @@ -33,6 +33,7 @@ public ProxyHostnameChecker() { private Object getHostnameChecker() { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { + @SuppressWarnings("unchecked") final Class hostnameCheckerClass = (Class) classLoader.loadClass("sun.security.util.HostnameChecker"); final Method instanceMethod = hostnameCheckerClass.getMethod("getInstance", Byte.TYPE); return instanceMethod.invoke(null, TYPE_TLS); diff --git a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java index 7c9b46c50b..ad87080b85 100644 --- a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java +++ b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java @@ -3,7 +3,6 @@ import static org.testng.Assert.assertEquals; import org.apache.commons.io.FileUtils; -import org.asynchttpclient.async.HostnameVerifierTest; import org.asynchttpclient.util.StandardCharsets; import org.eclipse.jetty.security.ConstraintMapping; import org.eclipse.jetty.security.ConstraintSecurityHandler; diff --git a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java index a2b1519d9d..d5640b10ef 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java @@ -109,7 +109,7 @@ public void wrongStatusCode() throws Throwable { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference throwable = new AtomicReference(); - WebSocket websocket = c.prepareGet("http://apache.org").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + c.prepareGet("http://apache.org").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -149,7 +149,7 @@ public void wrongProtocolCode() throws Throwable { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference throwable = new AtomicReference(); - WebSocket websocket = c.prepareGet("ws://www.google.com").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + c.prepareGet("ws://www.google.com").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index b463d70d55..b6d4ee27a7 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -87,7 +87,7 @@ private void writeRequest(Channel channel) { public void onFutureSuccess(final Channel channel) throws ConnectException { Channels.setAttribute(channel, future); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); - final SslHandler sslHandler = channelManager.getSslHandler(channel.pipeline()); + final SslHandler sslHandler = ChannelManager.getSslHandler(channel.pipeline()); if (hostnameVerifier != null && sslHandler != null) { final String host = future.getURI().getHost(); sslHandler.handshakeFuture().addListener(new GenericFutureListener>() { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 207d0596e6..68da7ab765 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -141,6 +141,7 @@ private ListenableFuture sendRequestWithCertainForceConnect(// * until we get a valid channel from the pool and it's still valid once the * request is built */ + @SuppressWarnings("unused") private ListenableFuture sendRequestThroughSslProxy(// Request request,// AsyncHandler asyncHandler,// @@ -443,6 +444,7 @@ public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture fu boolean replayed = false; + @SuppressWarnings({ "unchecked", "rawtypes" }) FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(e).build(); for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { try { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java index 43c39cfea7..94adb45b88 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -19,7 +19,6 @@ import org.asynchttpclient.RandomAccessBody; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.channel.ChannelManager; -import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; import org.asynchttpclient.providers.netty.request.body.FeedableBodyGenerator.FeedListener; From 2ca8a3d0edf4842a1c07be6889467bfc9d727a87 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:56:47 +0200 Subject: [PATCH 0043/1949] Have Parts take a java.nio.Charset instead of a String, close #652 --- .../multipart/AbstractFilePart.java | 3 ++- .../multipart/ByteArrayPart.java | 9 +++++---- .../asynchttpclient/multipart/FilePart.java | 15 ++++++++------- .../org/asynchttpclient/multipart/Part.java | 3 ++- .../asynchttpclient/multipart/PartBase.java | 19 ++++++++++--------- .../asynchttpclient/multipart/StringPart.java | 10 +++++----- .../async/AsyncProvidersBasicTest.java | 2 +- .../async/FastUnauthorizedUploadTest.java | 2 +- .../async/FilePartLargeFileTest.java | 4 ++-- .../async/MultipartUploadTest.java | 14 +++++++------- .../async/SimpleAsyncHttpClientTest.java | 4 ++-- .../multipart/MultipartBodyTest.java | 7 ++++--- 12 files changed, 49 insertions(+), 43 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index 8e711d3a98..c3a2533603 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java @@ -16,6 +16,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.charset.Charset; /** * This class is an adaptation of the Apache HttpClient implementation @@ -55,7 +56,7 @@ public abstract class AbstractFilePart extends PartBase { * @param charset * the charset encoding for this part */ - public AbstractFilePart(String name, String contentType, String charset, String contentId, String transfertEncoding) { + public AbstractFilePart(String name, String contentType, Charset charset, String contentId, String transfertEncoding) { super(name,// contentType == null ? DEFAULT_CONTENT_TYPE : contentType,// charset,// diff --git a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java index bc4660cb8e..f3dc0f11c7 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; public class ByteArrayPart extends AbstractFilePart { @@ -28,19 +29,19 @@ public ByteArrayPart(String name, byte[] bytes, String contentType) { this(name, bytes, contentType, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset) { this(name, bytes, contentType, charset, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset, String fileName) { this(name, bytes, contentType, charset, fileName, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset, String fileName, String contentId) { this(name, bytes, contentType, charset, fileName, contentId, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset, String fileName, String contentId, String transferEncoding) { super(name, contentType, charset, contentId, transferEncoding); if (bytes == null) throw new NullPointerException("bytes"); diff --git a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java index 3ea77ed562..359ec21f72 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java @@ -12,9 +12,6 @@ */ package org.asynchttpclient.multipart; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -23,6 +20,10 @@ import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FilePart extends AbstractFilePart { @@ -38,19 +39,19 @@ public FilePart(String name, File file, String contentType) { this(name, file, contentType, null); } - public FilePart(String name, File file, String contentType, String charset) { + public FilePart(String name, File file, String contentType, Charset charset) { this(name, file, contentType, charset, null); } - public FilePart(String name, File file, String contentType, String charset, String fileName) { + public FilePart(String name, File file, String contentType, Charset charset, String fileName) { this(name, file, contentType, charset, fileName, null); } - public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId) { + public FilePart(String name, File file, String contentType, Charset charset, String fileName, String contentId) { this(name, file, contentType, charset, fileName, contentId, null); } - public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + public FilePart(String name, File file, String contentType, Charset charset, String fileName, String contentId, String transferEncoding) { super(name, contentType, charset, contentId, transferEncoding); if (file == null) throw new NullPointerException("file"); diff --git a/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index 66758c7df8..4a5a2d90b8 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/multipart/Part.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; public interface Part { @@ -89,7 +90,7 @@ public interface Part { * * @return the character encoding, or null to exclude the character encoding header */ - String getCharSet(); + Charset getCharset(); /** * Return the transfer encoding of this part. diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index 6273fce8ed..a241df72a9 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.Charset; public abstract class PartBase implements Part { @@ -32,7 +33,7 @@ public abstract class PartBase implements Part { /** * The charset (part of Content-Type header) */ - private final String charSet; + private final Charset charset; /** * The Content-Transfer-Encoding header value. @@ -54,14 +55,14 @@ public abstract class PartBase implements Part { * * @param name The name of the part, or null * @param contentType The content type, or null - * @param charSet The character encoding, or null + * @param charset The character encoding, or null * @param contentId The content id, or null * @param transferEncoding The transfer encoding, or null */ - public PartBase(String name, String contentType, String charSet, String contentId, String transferEncoding) { + public PartBase(String name, String contentType, Charset charset, String contentId, String transferEncoding) { this.name = name; this.contentType = contentType; - this.charSet = charSet; + this.charset = charset; this.contentId = contentId; this.transferEncoding = transferEncoding; } @@ -89,10 +90,10 @@ protected void visitContentTypeHeader(PartVisitor visitor) throws IOException { visitor.withBytes(CRLF_BYTES); visitor.withBytes(CONTENT_TYPE_BYTES); visitor.withBytes(contentType.getBytes(US_ASCII)); - String charSet = getCharSet(); + Charset charSet = getCharset(); if (charSet != null) { visitor.withBytes(CHARSET_BYTES); - visitor.withBytes(charSet.getBytes(US_ASCII)); + visitor.withBytes(charset.name().getBytes(US_ASCII)); } } } @@ -186,7 +187,7 @@ public String toString() { .append(getClass().getSimpleName())// .append(" name=").append(getName())// .append(" contentType=").append(getContentType())// - .append(" charset=").append(getCharSet())// + .append(" charset=").append(getCharset())// .append(" tranferEncoding=").append(getTransferEncoding())// .append(" contentId=").append(getContentId())// .append(" dispositionType=").append(getDispositionType())// @@ -204,8 +205,8 @@ public String getContentType() { } @Override - public String getCharSet() { - return this.charSet; + public Charset getCharset() { + return this.charset; } @Override diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java index 9ed500a561..eb6b90b329 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java @@ -42,11 +42,11 @@ public class StringPart extends PartBase { */ private final byte[] content; - private static Charset charsetOrDefault(String charset) { - return charset == null ? DEFAULT_CHARSET : Charset.forName(charset); + private static Charset charsetOrDefault(Charset charset) { + return charset == null ? DEFAULT_CHARSET : charset; } - public StringPart(String name, String value, String charset) { + public StringPart(String name, String value, Charset charset) { this(name, value, charset, null); } @@ -62,9 +62,9 @@ public StringPart(String name, String value, String charset) { * @param contentId * the content id */ - public StringPart(String name, String value, String charset, String contentId) { + public StringPart(String name, String value, Charset charset, String contentId) { - super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset).name(), DEFAULT_TRANSFER_ENCODING, contentId); + super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset), DEFAULT_TRANSFER_ENCODING, contentId); if (value == null) throw new NullPointerException("value"); if (value.indexOf(0) != -1) diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 301074edc6..b4ae251628 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -659,7 +659,7 @@ public void asyncDoPostMultiPartTest() throws Exception { try { final CountDownLatch l = new CountDownLatch(1); - Part p = new StringPart("foo", "bar", StandardCharsets.UTF_8.name()); + Part p = new StringPart("foo", "bar", StandardCharsets.UTF_8); client.preparePost(getTargetUrl()).addBodyPart(p).execute(new AsyncCompletionHandlerAdapter() { diff --git a/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java b/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java index 18011253cc..59ab429241 100644 --- a/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java @@ -53,7 +53,7 @@ public void testUnauthorizedWhileUploading() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8.name())).execute() + Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8)).execute() .get(); assertEquals(response.getStatusCode(), 401); } finally { diff --git a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java index 9783fc4fcf..b2f378f9c7 100644 --- a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java @@ -64,7 +64,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H public void testPutImageFile() throws Exception { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100 * 6000).build()); try { - Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", LARGE_IMAGE_FILE, "application/octet-stream", StandardCharsets.UTF_8.name())).execute().get(); + Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", LARGE_IMAGE_FILE, "application/octet-stream", StandardCharsets.UTF_8)).execute().get(); assertEquals(response.getStatusCode(), 200); } finally { client.close(); @@ -77,7 +77,7 @@ public void testPutLargeTextFile() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8.name())).execute().get(); + Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8)).execute().get(); assertEquals(response.getStatusCode(), 200); } finally { client.close(); diff --git a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java index 1222e4408d..ad063a9782 100644 --- a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java @@ -174,16 +174,16 @@ public void testSendingSmallFilesAndByteArray() { RequestBuilder builder = new RequestBuilder("POST"); builder.setUrl("http://localhost" + ":" + port1 + "/upload/bob"); - builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", StandardCharsets.UTF_8.name())); + builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", StandardCharsets.UTF_8)); builder.addBodyPart(new FilePart("file2", testResource2File, "application/x-gzip", null)); - builder.addBodyPart(new StringPart("Name", "Dominic", StandardCharsets.UTF_8.name())); - builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", StandardCharsets.UTF_8.name())); + builder.addBodyPart(new StringPart("Name", "Dominic", StandardCharsets.UTF_8)); + builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", StandardCharsets.UTF_8)); - builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); - builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); - builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); + builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET)); + builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET)); + builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET)); - builder.addBodyPart(new ByteArrayPart("file4", expectedContents.getBytes(StandardCharsets.UTF_8), "text/plain", StandardCharsets.UTF_8.name(), "bytearray.txt")); + builder.addBodyPart(new ByteArrayPart("file4", expectedContents.getBytes(StandardCharsets.UTF_8), "text/plain", StandardCharsets.UTF_8, "bytearray.txt")); Request r = builder.build(); diff --git a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java index a7f4615795..59b4caa6ae 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java @@ -307,7 +307,7 @@ public void testCloseMasterInvalidDerived() throws Exception { public void testMultiPartPut() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl() + "/multipart").build(); try { - Response response = client.put(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")).get(); + Response response = client.put(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8, "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); @@ -331,7 +331,7 @@ public void testMultiPartPut() throws Exception { public void testMultiPartPost() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl() + "/multipart").build(); try { - Response response = client.post(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")).get(); + Response response = client.post(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8, "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); diff --git a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java index 9de0bfa50f..40aa2db636 100644 --- a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java +++ b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java @@ -12,9 +12,10 @@ */ package org.asynchttpclient.multipart; +import static org.asynchttpclient.util.StandardCharsets.UTF_8; + import org.asynchttpclient.Body; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.util.StandardCharsets; import org.testng.Assert; import org.testng.annotations.Test; @@ -37,10 +38,10 @@ public void testBasics() { parts.add(new FilePart("filePart", testFile)); // add a byte array - parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")); + parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(UTF_8), "application/test", UTF_8, "fileName")); // add a string - parts.add(new StringPart("stringPart", "testString", StandardCharsets.UTF_8.name())); + parts.add(new StringPart("stringPart", "testString", UTF_8)); compareContentLength(parts); } From 54950d775882c72dce5e64cfc5d2fddd08e7390e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 13:32:08 +0200 Subject: [PATCH 0044/1949] minor clean up --- .../providers/netty/ws/NettyWebSocket.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 2a87ac293b..2c2940b168 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -196,29 +196,28 @@ public void onTextFragment(String message, boolean last) { } } - for (WebSocketListener l : listeners) { - if (l instanceof WebSocketTextListener) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) { + WebSocketTextListener textListener = (WebSocketTextListener) listener; try { if (!last) { - WebSocketTextListener.class.cast(l).onFragment(message, last); + textListener.onFragment(message, last); } else { if (textBuffer.length() > 0) { - WebSocketTextListener.class.cast(l).onFragment(message, last); - - WebSocketTextListener.class.cast(l).onMessage(textBuffer.append(message).toString()); + textListener.onFragment(message, last); + textListener.onMessage(textBuffer.append(message).toString()); } else { - WebSocketTextListener.class.cast(l).onMessage(message); + textListener.onMessage(message); } } } catch (Exception ex) { - l.onError(ex); + listener.onError(ex); } } } - if (last) { + if (last) textBuffer.setLength(0); - } } public void onError(Throwable t) { From 6807f5b146314fa09007706e2808178a8f396918 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 11:58:32 +0200 Subject: [PATCH 0045/1949] minor clean up --- .../providers/netty/handler/WebSocketProtocol.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index e8e0917338..fbacb05374 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -86,12 +86,10 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr boolean validStatus = response.getStatus().equals(SWITCHING_PROTOCOLS); boolean validUpgrade = response.headers().get(HttpHeaders.Names.UPGRADE) != null; - String c = response.headers().get(HttpHeaders.Names.CONNECTION); - if (c == null) { - c = response.headers().get(HttpHeaders.Names.CONNECTION.toLowerCase(Locale.ENGLISH)); - } - - boolean validConnection = c != null && c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); + String connection = response.headers().get(HttpHeaders.Names.CONNECTION); + if (connection == null) + connection = response.headers().get(HttpHeaders.Names.CONNECTION.toLowerCase(Locale.ENGLISH)); + boolean validConnection = HttpHeaders.Values.UPGRADE.equalsIgnoreCase(connection); status = new NettyResponseStatus(future.getURI(), config, response); final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; From 4996b444ea42e3bdfd5f7fb9d650c5d00e99cc0e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:19:17 +0200 Subject: [PATCH 0046/1949] RandomAccessBody.transferTo count is actually unused (Long.MAX_VALUE) --- api/src/main/java/org/asynchttpclient/Body.java | 1 + .../main/java/org/asynchttpclient/RandomAccessBody.java | 4 +--- .../org/asynchttpclient/generators/FileBodyGenerator.java | 8 +++----- .../java/org/asynchttpclient/multipart/MultipartBody.java | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Body.java b/api/src/main/java/org/asynchttpclient/Body.java index 5a39306b2d..9ee63021da 100644 --- a/api/src/main/java/org/asynchttpclient/Body.java +++ b/api/src/main/java/org/asynchttpclient/Body.java @@ -36,6 +36,7 @@ public interface Body extends Closeable { * @return The non-negative number of bytes actually read or {@code -1} if the body has been read completely. * @throws IOException If the chunk could not be read. */ + // FIXME introduce a visitor pattern so that Netty can pass a pooled buffer long read(ByteBuffer buffer) throws IOException; /** diff --git a/api/src/main/java/org/asynchttpclient/RandomAccessBody.java b/api/src/main/java/org/asynchttpclient/RandomAccessBody.java index 6cdc699485..fa74e9e684 100644 --- a/api/src/main/java/org/asynchttpclient/RandomAccessBody.java +++ b/api/src/main/java/org/asynchttpclient/RandomAccessBody.java @@ -26,13 +26,11 @@ public interface RandomAccessBody extends Body { * * @param position * The zero-based byte index from which to start the transfer, must not be negative. - * @param count - * The maximum number of bytes to transfer, must not be negative. * @param target * The destination channel to transfer the body chunk to, must not be {@code null}. * @return The non-negative number of bytes actually transferred. * @throws IOException * If the body chunk could not be transferred. */ - long transferTo(long position, long count, WritableByteChannel target) throws IOException; + long transferTo(long position, WritableByteChannel target) throws IOException; } diff --git a/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java b/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java index 007a993206..dd97ec217b 100644 --- a/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java +++ b/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java @@ -25,6 +25,7 @@ /** * Creates a request body from the contents of a file. */ +//Not used by Netty public class FileBodyGenerator implements BodyGenerator { private final File file; @@ -89,11 +90,8 @@ public long read(ByteBuffer buffer) throws IOException { return channel.read(buffer); } - public long transferTo(long position, long count, WritableByteChannel target) throws IOException { - if (count > length) { - count = length; - } - return channel.transferTo(position, count, target); + public long transferTo(long position, WritableByteChannel target) throws IOException { + return channel.transferTo(position, length, target); } public void close() throws IOException { diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java index 1515409364..1b732b9390 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java @@ -69,7 +69,7 @@ public String getContentType() { } // RandomAccessBody API, suited for HTTP but not for HTTPS - public long transferTo(long position, long count, WritableByteChannel target) throws IOException { + public long transferTo(long position, WritableByteChannel target) throws IOException { long overallLength = 0; From 6fd6367156fc8f129e1c50395eb626a05131cf77 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:22:01 +0200 Subject: [PATCH 0047/1949] Remove useless synchronized --- .../multipart/MultipartUtils.java | 78 +++++++++---------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java index b546d1f7ba..d1f3ace5dc 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java @@ -110,50 +110,48 @@ public static long writeBytesToChannel(WritableByteChannel target, byte[] bytes) int written = 0; int maxSpin = 0; - synchronized (bytes) { - ByteBuffer message = ByteBuffer.wrap(bytes); - - if (target instanceof SocketChannel) { - final Selector selector = Selector.open(); - try { - final SocketChannel channel = (SocketChannel) target; - channel.register(selector, SelectionKey.OP_WRITE); - - while (written < bytes.length) { - selector.select(1000); - maxSpin++; - final Set selectedKeys = selector.selectedKeys(); - - for (SelectionKey key : selectedKeys) { - if (key.isWritable()) { - written += target.write(message); - maxSpin = 0; - } - } - if (maxSpin >= 10) { - throw new IOException("Unable to write on channel " + target); + ByteBuffer message = ByteBuffer.wrap(bytes); + + if (target instanceof SocketChannel) { + final Selector selector = Selector.open(); + try { + final SocketChannel channel = (SocketChannel) target; + channel.register(selector, SelectionKey.OP_WRITE); + + while (written < bytes.length) { + selector.select(1000); + maxSpin++; + final Set selectedKeys = selector.selectedKeys(); + + for (SelectionKey key : selectedKeys) { + if (key.isWritable()) { + written += target.write(message); + maxSpin = 0; } } - } finally { - selector.close(); + if (maxSpin >= 10) { + throw new IOException("Unable to write on channel " + target); + } } - } else { - while ((target.isOpen()) && (written < bytes.length)) { - long nWrite = target.write(message); - written += nWrite; - if (nWrite == 0 && maxSpin++ < 10) { - LOGGER.info("Waiting for writing..."); - try { - bytes.wait(1000); - } catch (InterruptedException e) { - LOGGER.trace(e.getMessage(), e); - } - } else { - if (maxSpin >= 10) { - throw new IOException("Unable to write on channel " + target); - } - maxSpin = 0; + } finally { + selector.close(); + } + } else { + while ((target.isOpen()) && (written < bytes.length)) { + long nWrite = target.write(message); + written += nWrite; + if (nWrite == 0 && maxSpin++ < 10) { + LOGGER.info("Waiting for writing..."); + try { + bytes.wait(1000); + } catch (InterruptedException e) { + LOGGER.trace(e.getMessage(), e); + } + } else { + if (maxSpin >= 10) { + throw new IOException("Unable to write on channel " + target); } + maxSpin = 0; } } } From f22ad62066cfd1bf3d7415251af2c2732db34acf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:23:36 +0200 Subject: [PATCH 0048/1949] Fix build --- .../providers/netty/request/body/BodyFileRegion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java index 49fabeef29..010625f95b 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java @@ -52,7 +52,7 @@ public long transfered() { @Override public long transferTo(WritableByteChannel target, long position) throws IOException { - long written = body.transferTo(position, Long.MAX_VALUE, target); + long written = body.transferTo(position, target); if (written > 0) { transfered += written; } From b5af568f378e5b037f74610787eb957bf0bfd162 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:37:44 +0200 Subject: [PATCH 0049/1949] Only set Content-Length is strictly positive --- .../providers/netty/request/NettyRequestFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 2b26b06e2e..fa971cf010 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -281,7 +281,7 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean } if (body != null) { - if (body.getContentLength() >= 0) + if (body.getContentLength() > 0) httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); else httpRequest.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); From 613a83a3b6285bcacb0be27cb98222ec070ec40a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 13:43:53 +0200 Subject: [PATCH 0050/1949] closeSilently --- .../main/java/org/asynchttpclient/Body.java | 7 ---- .../org/asynchttpclient/BodyConsumer.java | 9 +----- .../SimpleAsyncHttpClient.java | 32 ++++++++----------- .../ResumableRandomAccessFileListener.java | 14 +++----- .../PropertiesBasedResumableProcessor.java | 17 ++++------ .../org/asynchttpclient/util/MiscUtils.java | 11 ++++++- .../multipart/MultipartBodyTest.java | 2 -- .../netty/request/body/BodyFileRegion.java | 10 +++--- .../netty/request/body/NettyBodyBody.java | 29 +++++++---------- .../netty/request/body/NettyFileBody.java | 19 ++--------- .../request/body/NettyInputStreamBody.java | 8 ++--- 11 files changed, 56 insertions(+), 102 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Body.java b/api/src/main/java/org/asynchttpclient/Body.java index 9ee63021da..422e365e2f 100644 --- a/api/src/main/java/org/asynchttpclient/Body.java +++ b/api/src/main/java/org/asynchttpclient/Body.java @@ -38,11 +38,4 @@ public interface Body extends Closeable { */ // FIXME introduce a visitor pattern so that Netty can pass a pooled buffer long read(ByteBuffer buffer) throws IOException; - - /** - * Releases any resources associated with this body. - * - * @throws IOException - */ - void close() throws IOException; } diff --git a/api/src/main/java/org/asynchttpclient/BodyConsumer.java b/api/src/main/java/org/asynchttpclient/BodyConsumer.java index 0e93652bb1..190c586ae7 100644 --- a/api/src/main/java/org/asynchttpclient/BodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/BodyConsumer.java @@ -25,15 +25,8 @@ public interface BodyConsumer extends Closeable { /** * Consume the received bytes. * - * @param byteBuffer a {@link ByteBuffer} represntation of the response's chunk. + * @param byteBuffer a {@link ByteBuffer} representation of the response's chunk. * @throws IOException */ void consume(ByteBuffer byteBuffer) throws IOException; - - /** - * Invoked when all the response bytes has been processed. - * - * @throws IOException - */ - void close() throws IOException; } diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 25b9be4075..e90cee8f6b 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -12,17 +12,7 @@ */ package org.asynchttpclient; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.multipart.Part; -import org.asynchttpclient.resumable.ResumableAsyncHandler; -import org.asynchttpclient.resumable.ResumableIOExceptionFilter; -import org.asynchttpclient.simple.HeaderMap; -import org.asynchttpclient.simple.SimpleAHCTransferListener; -import org.asynchttpclient.uri.UriComponents; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.net.ssl.SSLContext; +import static org.asynchttpclient.util.MiscUtils.closeSilently; import java.io.Closeable; import java.io.IOException; @@ -32,6 +22,16 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import javax.net.ssl.SSLContext; + +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.multipart.Part; +import org.asynchttpclient.resumable.ResumableAsyncHandler; +import org.asynchttpclient.resumable.ResumableIOExceptionFilter; +import org.asynchttpclient.simple.HeaderMap; +import org.asynchttpclient.simple.SimpleAHCTransferListener; +import org.asynchttpclient.uri.UriComponents; + /** * Simple implementation of {@link AsyncHttpClient} and it's related builders ({@link AsyncHttpClientConfig}, * {@link Realm}, {@link ProxyServer} and {@link AsyncHandler}. You can @@ -64,7 +64,6 @@ */ public class SimpleAsyncHttpClient implements Closeable { - private final static Logger logger = LoggerFactory.getLogger(SimpleAsyncHttpClient.class); private final AsyncHttpClientConfig config; private final RequestBuilder requestBuilder; private AsyncHttpClient asyncHttpClient; @@ -778,13 +777,8 @@ public Response onCompleted(Response response) throws Exception { } private void closeConsumer() { - try { - if (bodyConsumer != null) { - bodyConsumer.close(); - } - } catch (IOException ex) { - logger.warn("Unable to close a BodyConsumer {}", bodyConsumer); - } + if (bodyConsumer != null) + closeSilently(bodyConsumer); } @Override diff --git a/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java b/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java index e8a63a0f6c..7b0dd64b95 100644 --- a/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java +++ b/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java @@ -12,6 +12,8 @@ */ package org.asynchttpclient.extra; +import static org.asynchttpclient.util.MiscUtils.closeSilently; + import org.asynchttpclient.resumable.ResumableListener; import java.io.IOException; @@ -52,13 +54,7 @@ public void onBytesReceived(ByteBuffer buffer) throws IOException { * {@inheritDoc} */ public void onAllBytesReceived() { - if (file != null) { - try { - file.close(); - } catch (IOException e) { - ; - } - } + closeSilently(file); } /** @@ -68,9 +64,7 @@ public long length() { try { return file.length(); } catch (IOException e) { - ; + return 0; } - return 0; } - } diff --git a/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java b/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java index 9f6959f608..030a95fb7f 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java +++ b/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java @@ -12,18 +12,19 @@ */ package org.asynchttpclient.resumable; -import org.asynchttpclient.util.StandardCharsets; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.asynchttpclient.util.MiscUtils.closeSilently; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.IOException; import java.util.Map; import java.util.Scanner; import java.util.concurrent.ConcurrentHashMap; +import org.asynchttpclient.util.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A {@link org.asynchttpclient.resumable.ResumableAsyncHandler.ResumableProcessor} which use a properties file * to store the download index information. @@ -81,12 +82,8 @@ public void save(Map map) { } catch (Throwable e) { log.warn(e.getMessage(), e); } finally { - if (os != null) { - try { - os.close(); - } catch (IOException ignored) { - } - } + if (os != null) + closeSilently(os); } } diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtils.java b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java index db508f8513..1943f9939b 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java @@ -12,6 +12,8 @@ */ package org.asynchttpclient.util; +import java.io.Closeable; +import java.io.IOException; import java.util.Collection; import java.util.Map; @@ -46,6 +48,13 @@ public static boolean getBoolean(String systemPropName, boolean defaultValue) { } public static T withDefault(T value, T defaults) { - return value != null? value : value; + return value != null ? value : value; + } + + public static void closeSilently(Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + } } } diff --git a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java index 40aa2db636..3eeb05bbe6 100644 --- a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java +++ b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java @@ -62,8 +62,6 @@ private static File getTestfile() { private static void compareContentLength(final List parts) { Assert.assertNotNull(parts); // get expected values - - // get real bytes final Body multipartBody = MultipartUtils.newMultipartBody(parts, new FluentCaseInsensitiveStringsMap()); final long expectedContentLength = multipartBody.getContentLength(); try { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java index 010625f95b..b1d02275e4 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java @@ -13,6 +13,9 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; + + import org.asynchttpclient.RandomAccessBody; import io.netty.channel.FileRegion; @@ -20,7 +23,6 @@ import java.io.IOException; import java.nio.channels.WritableByteChannel; - /** * Adapts a {@link RandomAccessBody} to Netty's {@link FileRegion}. */ @@ -61,10 +63,6 @@ public long transferTo(WritableByteChannel target, long position) throws IOExcep @Override protected void deallocate() { - try { - body.close(); - } catch (IOException e) { - // we tried - } + closeSilently(body); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java index 94adb45b88..96957591ab 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -13,6 +13,15 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelProgressiveFuture; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.stream.ChunkedWriteHandler; + +import java.io.IOException; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Body; import org.asynchttpclient.BodyGenerator; @@ -22,21 +31,9 @@ import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; import org.asynchttpclient.providers.netty.request.body.FeedableBodyGenerator.FeedListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelProgressiveFuture; -import io.netty.handler.codec.http.LastHttpContent; -import io.netty.handler.stream.ChunkedWriteHandler; - -import java.io.IOException; public class NettyBodyBody implements NettyBody { - private static final Logger LOGGER = LoggerFactory.getLogger(NettyBodyBody.class); - private final Body body; private final NettyAsyncHttpProviderConfig nettyConfig; @@ -63,7 +60,7 @@ public String getContentType() { public void write(final Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { Object msg; - if (!ChannelManager.isSslHandlerConfigured(channel.pipeline()) && body instanceof RandomAccessBody && !nettyConfig.isDisableZeroCopy()) { + if (body instanceof RandomAccessBody && !ChannelManager.isSslHandlerConfigured(channel.pipeline()) && !nettyConfig.isDisableZeroCopy()) { msg = new BodyFileRegion((RandomAccessBody) body); } else { @@ -83,11 +80,7 @@ public void onContentAdded() { writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { public void operationComplete(ChannelProgressiveFuture cf) { - try { - body.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(body); super.operationComplete(cf); } }); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java index 7b5234e5cd..44a5349a7e 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java @@ -13,6 +13,7 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelProgressiveFuture; @@ -30,13 +31,9 @@ import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class NettyFileBody implements NettyBody { - private static final Logger LOGGER = LoggerFactory.getLogger(NettyFileBody.class); - private final File file; private final long offset; private final long length; @@ -88,23 +85,13 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien } writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { public void operationComplete(ChannelProgressiveFuture cf) { - try { - // FIXME probably useless in Netty 4 - raf.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(raf); super.operationComplete(cf); } }); channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } catch (IOException ex) { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - } - } + closeSilently(raf); throw ex; } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java index 4412cd9bf4..9f7d841996 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java @@ -13,6 +13,8 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; @@ -69,11 +71,7 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien channel.write(new ChunkedStream(is), channel.newProgressivePromise()).addListener( new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { public void operationComplete(ChannelProgressiveFuture cf) { - try { - is.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(is); super.operationComplete(cf); } }); From f822b0a68601684dbb36e40c5bef1e2a9774d68f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:06:50 +0200 Subject: [PATCH 0051/1949] minor clean up --- .../providers/netty/ws/NettyWebSocket.java | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 2c2940b168..a9f6eefe63 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -34,7 +34,8 @@ import java.util.concurrent.ConcurrentLinkedQueue; public class NettyWebSocket implements WebSocket { - private final static Logger logger = LoggerFactory.getLogger(NettyWebSocket.class); + + private static final Logger LOGGER = LoggerFactory.getLogger(NettyWebSocket.class); private final Channel channel; private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); @@ -150,29 +151,28 @@ public void onBinaryFragment(byte[] message, boolean last) { if (byteBuffer.size() > maxBufferSize) { byteBuffer.reset(); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); onError(e); - this.close(); + close(); return; } } - for (WebSocketListener l : listeners) { - if (l instanceof WebSocketByteListener) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) { + WebSocketByteListener byteListener = (WebSocketByteListener) listener; try { if (!last) { - WebSocketByteListener.class.cast(l).onFragment(message, last); + byteListener.onFragment(message, last); + } else if (byteBuffer.size() > 0) { + byteBuffer.write(message); + byteListener.onFragment(message, last); + byteListener.onMessage(byteBuffer.toByteArray()); } else { - if (byteBuffer.size() > 0) { - byteBuffer.write(message); - WebSocketByteListener.class.cast(l).onFragment(message, last); - WebSocketByteListener.class.cast(l).onMessage(byteBuffer.toByteArray()); - } else { - WebSocketByteListener.class.cast(l).onMessage(message); - } + byteListener.onMessage(message); } } catch (Exception ex) { - l.onError(ex); + listener.onError(ex); } } } @@ -189,9 +189,9 @@ public void onTextFragment(String message, boolean last) { if (textBuffer.length() > maxBufferSize) { textBuffer.setLength(0); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); onError(e); - this.close(); + close(); return; } } @@ -202,13 +202,11 @@ public void onTextFragment(String message, boolean last) { try { if (!last) { textListener.onFragment(message, last); + } else if (textBuffer.length() > 0) { + textListener.onFragment(message, last); + textListener.onMessage(textBuffer.append(message).toString()); } else { - if (textBuffer.length() > 0) { - textListener.onFragment(message, last); - textListener.onMessage(textBuffer.append(message).toString()); - } else { - textListener.onMessage(message); - } + textListener.onMessage(message); } } catch (Exception ex) { listener.onError(ex); @@ -221,11 +219,11 @@ public void onTextFragment(String message, boolean last) { } public void onError(Throwable t) { - for (WebSocketListener l : listeners) { + for (WebSocketListener listener : listeners) { try { - l.onError(t); + listener.onError(t); } catch (Throwable t2) { - logger.error("", t2); + LOGGER.error("", t2); } } @@ -236,14 +234,14 @@ public void onClose() { } public void onClose(int code, String reason) { - for (WebSocketListener l : listeners) { + for (WebSocketListener listener : listeners) { try { - if (l instanceof WebSocketCloseCodeReasonListener) { - WebSocketCloseCodeReasonListener.class.cast(l).onClose(this, code, reason); + if (listener instanceof WebSocketCloseCodeReasonListener) { + WebSocketCloseCodeReasonListener.class.cast(listener).onClose(this, code, reason); } - l.onClose(this); + listener.onClose(this); } catch (Throwable t) { - l.onError(t); + listener.onError(t); } } } From d7db2b79b8f9aeb2f4fbe01c3d69a62a07aead21 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:19:37 +0200 Subject: [PATCH 0052/1949] minor clean up --- .../websocket/WebSocketUpgradeHandler.java | 87 +++++-------------- .../providers/netty/ws/NettyWebSocket.java | 7 +- 2 files changed, 24 insertions(+), 70 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java index 69e7664d76..bbf13b0167 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java @@ -27,22 +27,13 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, AsyncHandler { private WebSocket webSocket; - private final ConcurrentLinkedQueue l; - @SuppressWarnings("unused") - private final String protocol; - @SuppressWarnings("unused") - private final long maxByteSize; - @SuppressWarnings("unused") - private final long maxTextSize; + private final ConcurrentLinkedQueue listeners; private final AtomicBoolean ok = new AtomicBoolean(false); private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); private int status; - private WebSocketUpgradeHandler(Builder b) { - l = b.l; - protocol = b.protocol; - maxByteSize = b.maxByteSize; - maxTextSize = b.maxTextSize; + public WebSocketUpgradeHandler(ConcurrentLinkedQueue listeners) { + this.listeners = listeners; } /** @@ -93,8 +84,9 @@ public final STATE onHeadersReceived(HttpResponseHeaders headers) throws Excepti public final WebSocket onCompleted() throws Exception { if (status != 101) { - for (WebSocketListener w : l) { - w.onError(new IllegalStateException(String.format("Invalid Status Code %d", status))); + IllegalStateException e = new IllegalStateException("Invalid Status Code " + status); + for (WebSocketListener listener : listeners) { + listener.onError(e); } return null; } @@ -111,9 +103,9 @@ public final WebSocket onCompleted() throws Exception { @Override public final void onSuccess(WebSocket webSocket) { this.webSocket = webSocket; - for (WebSocketListener w : l) { - webSocket.addWebSocketListener(w); - w.onOpen(webSocket); + for (WebSocketListener listener : listeners) { + webSocket.addWebSocketListener(listener); + listener.onOpen(webSocket); } ok.set(true); } @@ -123,11 +115,11 @@ public final void onSuccess(WebSocket webSocket) { */ @Override public final void onFailure(Throwable t) { - for (WebSocketListener w : l) { + for (WebSocketListener listener : listeners) { if (!ok.get() && webSocket != null) { - webSocket.addWebSocketListener(w); + webSocket.addWebSocketListener(listener); } - w.onError(t); + listener.onError(t); } } @@ -136,13 +128,13 @@ public final void onClose(WebSocket webSocket, int status, String reasonPhrase) if (this.webSocket == null) this.webSocket = webSocket; - for (WebSocketListener w : l) { + for (WebSocketListener listener : listeners) { if (webSocket != null) { - webSocket.addWebSocketListener(w); + webSocket.addWebSocketListener(listener); } - w.onClose(webSocket); - if (w instanceof WebSocketCloseCodeReasonListener) { - WebSocketCloseCodeReasonListener.class.cast(w).onClose(webSocket, status, reasonPhrase); + listener.onClose(webSocket); + if (listener instanceof WebSocketCloseCodeReasonListener) { + WebSocketCloseCodeReasonListener.class.cast(listener).onClose(webSocket, status, reasonPhrase); } } } @@ -151,10 +143,8 @@ public final void onClose(WebSocket webSocket, int status, String reasonPhrase) * Build a {@link WebSocketUpgradeHandler} */ public final static class Builder { - private ConcurrentLinkedQueue l = new ConcurrentLinkedQueue(); - private String protocol = ""; - private long maxByteSize = 8192; - private long maxTextSize = 8192; + + private ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); /** * Add a {@link WebSocketListener} that will be added to the {@link WebSocket} @@ -163,7 +153,7 @@ public final static class Builder { * @return this */ public Builder addWebSocketListener(WebSocketListener listener) { - l.add(listener); + listeners.add(listener); return this; } @@ -174,40 +164,7 @@ public Builder addWebSocketListener(WebSocketListener listener) { * @return this */ public Builder removeWebSocketListener(WebSocketListener listener) { - l.remove(listener); - return this; - } - - /** - * Set the WebSocket protocol. - * - * @param protocol the WebSocket protocol. - * @return this - */ - public Builder setProtocol(String protocol) { - this.protocol = protocol; - return this; - } - - /** - * Set the max size of the WebSocket byte message that will be sent. - * - * @param maxByteSize max size of the WebSocket byte message - * @return this - */ - public Builder setMaxByteSize(long maxByteSize) { - this.maxByteSize = maxByteSize; - return this; - } - - /** - * Set the max size of the WebSocket text message that will be sent. - * - * @param maxTextSize max size of the WebSocket byte message - * @return this - */ - public Builder setMaxTextSize(long maxTextSize) { - this.maxTextSize = maxTextSize; + listeners.remove(listener); return this; } @@ -217,7 +174,7 @@ public Builder setMaxTextSize(long maxTextSize) { * @return a {@link WebSocketUpgradeHandler} */ public WebSocketUpgradeHandler build() { - return new WebSocketUpgradeHandler(this); + return new WebSocketUpgradeHandler(listeners); } } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index a9f6eefe63..eaadbf589e 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -103,11 +103,8 @@ public int getMaxBufferSize() { return maxBufferSize; } - public void setMaxBufferSize(int bufferSize) { - maxBufferSize = bufferSize; - - if (maxBufferSize < 8192) - maxBufferSize = 8192; + public void setMaxBufferSize(int maxBufferSize) { + this.maxBufferSize = Math.max(maxBufferSize, 8192); } @Override From 55d6f217fe87cc3ce84613ea62ed92202da52f98 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:42:26 +0200 Subject: [PATCH 0053/1949] WebSocketUpgradeHandler doesn't need to be threadsafe --- .../websocket/WebSocketUpgradeHandler.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java index bbf13b0167..c8fef8a02f 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java @@ -12,27 +12,28 @@ */ package org.asynchttpclient.websocket; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.UpgradeHandler; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; - /** * An {@link AsyncHandler} which is able to execute WebSocket upgrade. Use the Builder for configuring WebSocket options. */ public class WebSocketUpgradeHandler implements UpgradeHandler, AsyncHandler { private WebSocket webSocket; - private final ConcurrentLinkedQueue listeners; + private final List listeners; private final AtomicBoolean ok = new AtomicBoolean(false); private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); private int status; - public WebSocketUpgradeHandler(ConcurrentLinkedQueue listeners) { + public WebSocketUpgradeHandler(List listeners) { this.listeners = listeners; } @@ -144,7 +145,7 @@ public final void onClose(WebSocket webSocket, int status, String reasonPhrase) */ public final static class Builder { - private ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); + private List listeners = new ArrayList(); /** * Add a {@link WebSocketListener} that will be added to the {@link WebSocket} From e67c8625e57034de8948f5e3c30ddf40bae2dc96 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 01:58:12 +0200 Subject: [PATCH 0054/1949] Turn NettyWebSocket into an abstract class and introduce a Factory, close #656 --- .../websocket/WebSocketUpgradeHandler.java | 6 +- .../netty/NettyAsyncHttpProviderConfig.java | 46 +++-- .../netty/handler/WebSocketProtocol.java | 7 +- .../netty/ws/DefaultNettyWebSocket.java | 124 ++++++++++++++ .../providers/netty/ws/NettyWebSocket.java | 162 ++++-------------- 5 files changed, 202 insertions(+), 143 deletions(-) create mode 100644 providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java index c8fef8a02f..b612c9b0ac 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java @@ -30,7 +30,7 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, Async private WebSocket webSocket; private final List listeners; private final AtomicBoolean ok = new AtomicBoolean(false); - private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); + private boolean onSuccessCalled; private int status; public WebSocketUpgradeHandler(List listeners) { @@ -46,7 +46,9 @@ public final void onThrowable(Throwable t) { } public boolean touchSuccess() { - return onSuccessCalled.getAndSet(true); + boolean prev = onSuccessCalled; + onSuccessCalled = true; + return prev; } /** diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 36659292ad..95eed7889f 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -13,13 +13,6 @@ */ package org.asynchttpclient.providers.netty; -import org.asynchttpclient.AsyncHttpProviderConfig; -import org.asynchttpclient.SSLEngineFactory; -import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; - import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; @@ -30,6 +23,15 @@ import java.util.Map; import java.util.Set; +import org.asynchttpclient.AsyncHttpProviderConfig; +import org.asynchttpclient.SSLEngineFactory; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; +import org.asynchttpclient.providers.netty.ws.DefaultNettyWebSocket; +import org.asynchttpclient.providers.netty.ws.NettyWebSocket; + /** * This class can be used to pass Netty's internal configuration options. See * Netty documentation for more information. @@ -114,6 +116,18 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { } } + public static interface NettyWebSocketFactory { + NettyWebSocket newNettyWebSocket(Channel channel); + } + + public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { + + @Override + public NettyWebSocket newNettyWebSocket(Channel channel) { + return new DefaultNettyWebSocket(channel); + } + } + /** * Allow configuring the Netty's event loop. */ @@ -142,7 +156,7 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { private Timer nettyTimer; - private long handshakeTimeoutInMillis; + private long handshakeTimeout; private SSLEngineFactory sslEngineFactory; @@ -151,6 +165,8 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { */ private int chunkedFileChunkSize = 8192; + private NettyWebSocketFactory nettyWebSocketFactory = new DefaultNettyWebSocketFactory(); + public EventLoopGroup getEventLoopGroup() { return eventLoopGroup; } @@ -248,11 +264,11 @@ public void setNettyTimer(Timer nettyTimer) { } public long getHandshakeTimeout() { - return handshakeTimeoutInMillis; + return handshakeTimeout; } - public void setHandshakeTimeoutInMillis(long handshakeTimeoutInMillis) { - this.handshakeTimeoutInMillis = handshakeTimeoutInMillis; + public void setHandshakeTimeout(long handshakeTimeout) { + this.handshakeTimeout = handshakeTimeout; } public SSLEngineFactory getSslEngineFactory() { @@ -270,4 +286,12 @@ public int getChunkedFileChunkSize() { public void setChunkedFileChunkSize(int chunkedFileChunkSize) { this.chunkedFileChunkSize = chunkedFileChunkSize; } + + public NettyWebSocketFactory getNettyWebSocketFactory() { + return nettyWebSocketFactory; + } + + public void setNettyWebSocketFactory(NettyWebSocketFactory nettyWebSocketFactory) { + this.nettyWebSocketFactory = nettyWebSocketFactory; + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index fbacb05374..bdedadd68c 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -42,7 +42,6 @@ import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; -import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; public final class WebSocketProtocol extends Protocol { @@ -59,7 +58,7 @@ public WebSocketProtocol(ChannelManager channelManager,// private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { if (!h.touchSuccess()) { try { - h.onSuccess(new NettyWebSocket(channel)); + h.onSuccess(nettyConfig.getNettyWebSocketFactory().newNettyWebSocket(channel)); } catch (Exception ex) { logger.warn("onSuccess unexpected exception", ex); } @@ -140,9 +139,9 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr handler.onBodyPartReceived(rp); if (frame instanceof BinaryWebSocketFrame) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); + webSocket.onBinaryFragment(rp); } else { - webSocket.onTextFragment(buf.toString(StandardCharsets.UTF_8), frame.isFinalFragment()); + webSocket.onTextFragment(rp); } } finally { buf.release(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java new file mode 100644 index 0000000000..11b8cfd133 --- /dev/null +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package org.asynchttpclient.providers.netty.ws; + + +import io.netty.channel.Channel; + +import java.io.ByteArrayOutputStream; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.util.StandardCharsets; +import org.asynchttpclient.websocket.WebSocketByteListener; +import org.asynchttpclient.websocket.WebSocketListener; +import org.asynchttpclient.websocket.WebSocketTextListener; + +public class DefaultNettyWebSocket extends NettyWebSocket { + + private final StringBuilder textBuffer = new StringBuilder(); + private final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); + + public DefaultNettyWebSocket(Channel channel) { + super(channel, new ConcurrentLinkedQueue()); + } + + public void onBinaryFragment(HttpResponseBodyPart part) { + + boolean last = part.isLast(); + byte[] message = part.getBodyPartBytes(); + + if (!last) { + try { + byteBuffer.write(message); + } catch (Exception ex) { + byteBuffer.reset(); + onError(ex); + return; + } + + if (byteBuffer.size() > maxBufferSize) { + byteBuffer.reset(); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); + onError(e); + close(); + return; + } + } + + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) { + WebSocketByteListener byteListener = (WebSocketByteListener) listener; + try { + if (!last) { + byteListener.onFragment(message, last); + } else if (byteBuffer.size() > 0) { + byteBuffer.write(message); + byteListener.onFragment(message, last); + byteListener.onMessage(byteBuffer.toByteArray()); + } else { + byteListener.onMessage(message); + } + } catch (Exception ex) { + listener.onError(ex); + } + } + } + + if (last) { + byteBuffer.reset(); + } + } + + public void onTextFragment(HttpResponseBodyPart part) { + + boolean last = part.isLast(); + // FIXME this is so wrong! there's a chance the fragment is not valid UTF-8 because a char is truncated + String message = new String(part.getBodyPartBytes(), StandardCharsets.UTF_8); + + if (!last) { + textBuffer.append(message); + + if (textBuffer.length() > maxBufferSize) { + textBuffer.setLength(0); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); + onError(e); + close(); + return; + } + } + + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) { + WebSocketTextListener textlistener = (WebSocketTextListener) listener; + try { + if (!last) { + textlistener.onFragment(message, last); + } else if (textBuffer.length() > 0) { + textlistener.onFragment(message, last); + textlistener.onMessage(textBuffer.append(message).toString()); + } else { + textlistener.onMessage(message); + } + } catch (Exception ex) { + listener.onError(ex); + } + } + } + + if (last) { + textBuffer.setLength(0); + } + } +} diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index eaadbf589e..c0d2a8d977 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -14,43 +14,39 @@ package org.asynchttpclient.providers.netty.ws; import static io.netty.buffer.Unpooled.wrappedBuffer; - -import org.asynchttpclient.websocket.WebSocket; -import org.asynchttpclient.websocket.WebSocketByteListener; -import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; -import org.asynchttpclient.websocket.WebSocketListener; -import org.asynchttpclient.websocket.WebSocketTextListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import java.io.ByteArrayOutputStream; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.Collection; + +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.websocket.WebSocket; +import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; +import org.asynchttpclient.websocket.WebSocketListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class NettyWebSocket implements WebSocket { +public abstract class NettyWebSocket implements WebSocket { private static final Logger LOGGER = LoggerFactory.getLogger(NettyWebSocket.class); - private final Channel channel; - private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); - - private final StringBuilder textBuffer = new StringBuilder(); - private final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); - private int maxBufferSize = 128000000; + protected final Channel channel; + protected final Collection listeners; + protected int maxBufferSize = 128000000; - public NettyWebSocket(Channel channel) { + public NettyWebSocket(Channel channel, Collection listeners) { this.channel = channel; + this.listeners = listeners; } @Override public WebSocket sendMessage(byte[] message) { - channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -66,7 +62,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.writeAndFlush(new TextWebSocketFrame(message)); + channel.write(new TextWebSocketFrame(message)); return this; } @@ -77,13 +73,13 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); + channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } @@ -102,11 +98,11 @@ public WebSocket removeWebSocketListener(WebSocketListener l) { public int getMaxBufferSize() { return maxBufferSize; } - + public void setMaxBufferSize(int maxBufferSize) { this.maxBufferSize = Math.max(maxBufferSize, 8192); } - + @Override public boolean isOpen() { return channel.isOpen(); @@ -114,105 +110,16 @@ public boolean isOpen() { @Override public void close() { - onClose(); - listeners.clear(); - try { - channel.writeAndFlush(new CloseWebSocketFrame()); - channel.closeFuture().awaitUninterruptibly(); - } finally { - channel.close(); + if (channel.isOpen()) { + onClose(); + listeners.clear(); + channel.write(new CloseWebSocketFrame()).addListener(ChannelFutureListener.CLOSE); } } public void close(int statusCode, String reason) { onClose(statusCode, reason); listeners.clear(); - try { - channel.writeAndFlush(new CloseWebSocketFrame()); - channel.closeFuture().awaitUninterruptibly(); - } finally { - channel.close(); - } - } - - public void onBinaryFragment(byte[] message, boolean last) { - - if (!last) { - try { - byteBuffer.write(message); - } catch (Exception ex) { - byteBuffer.reset(); - onError(ex); - return; - } - - if (byteBuffer.size() > maxBufferSize) { - byteBuffer.reset(); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketByteListener) { - WebSocketByteListener byteListener = (WebSocketByteListener) listener; - try { - if (!last) { - byteListener.onFragment(message, last); - } else if (byteBuffer.size() > 0) { - byteBuffer.write(message); - byteListener.onFragment(message, last); - byteListener.onMessage(byteBuffer.toByteArray()); - } else { - byteListener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) { - byteBuffer.reset(); - } - } - - public void onTextFragment(String message, boolean last) { - - if (!last) { - textBuffer.append(message); - - if (textBuffer.length() > maxBufferSize) { - textBuffer.setLength(0); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketTextListener) { - WebSocketTextListener textListener = (WebSocketTextListener) listener; - try { - if (!last) { - textListener.onFragment(message, last); - } else if (textBuffer.length() > 0) { - textListener.onFragment(message, last); - textListener.onMessage(textBuffer.append(message).toString()); - } else { - textListener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) - textBuffer.setLength(0); } public void onError(Throwable t) { @@ -222,29 +129,32 @@ public void onError(Throwable t) { } catch (Throwable t2) { LOGGER.error("", t2); } - } } - public void onClose() { + protected void onClose() { onClose(1000, "Normal closure; the connection successfully completed whatever purpose for which it was created."); } public void onClose(int code, String reason) { - for (WebSocketListener listener : listeners) { + for (WebSocketListener l : listeners) { try { - if (listener instanceof WebSocketCloseCodeReasonListener) { - WebSocketCloseCodeReasonListener.class.cast(listener).onClose(this, code, reason); + if (l instanceof WebSocketCloseCodeReasonListener) { + WebSocketCloseCodeReasonListener.class.cast(l).onClose(this, code, reason); } - listener.onClose(this); + l.onClose(this); } catch (Throwable t) { - listener.onError(t); + l.onError(t); } } } @Override public String toString() { - return "NettyWebSocket{" + "channel=" + channel + '}'; + return "NettyWebSocket{channel=" + channel + '}'; } + + public abstract void onBinaryFragment(HttpResponseBodyPart part); + + public abstract void onTextFragment(HttpResponseBodyPart part); } From 920694d95d2a553f12c95b5cb84d0c8f6551926d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:54:46 +0200 Subject: [PATCH 0055/1949] Better log --- .../providers/netty/request/NettyConnectListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index b6d4ee27a7..571803a658 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -72,7 +72,7 @@ private void abortChannelPreemption(String poolKey) { private void writeRequest(Channel channel) { - LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); + LOGGER.debug("Request using non cached Channel '{}':\n{}\n", channel, future.getNettyRequest().getHttpRequest()); if (future.isDone()) { abortChannelPreemption(poolKey); From d6503ff1160debae0c7bfcc633776ffd5dcdf6d2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:55:04 +0200 Subject: [PATCH 0056/1949] Remove duplicate log --- .../asynchttpclient/providers/netty/handler/HttpProtocol.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 98be1659cb..531c3c6246 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -47,7 +47,6 @@ import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.NettyRequest; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; @@ -402,12 +401,10 @@ public void handle(final Channel channel, final NettyResponseFuture future, f return; } - NettyRequest nettyRequest = future.getNettyRequest(); AsyncHandler handler = future.getAsyncHandler(); try { if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - logger.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest.getHttpRequest(), response); // FIXME why do we buffer the response? I don't remember... future.setPendingResponse(response); return; From 148f202ff0f7e48a1cd5d8b81318f95fa782a60f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 12:14:40 +0200 Subject: [PATCH 0057/1949] WebSocket messaged have to be flushed --- .../providers/netty/ws/NettyWebSocket.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index c0d2a8d977..97068be924 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -46,7 +46,7 @@ public NettyWebSocket(Channel channel, Collection listeners) @Override public WebSocket sendMessage(byte[] message) { - channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -62,7 +62,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.write(new TextWebSocketFrame(message)); + channel.writeAndFlush(new TextWebSocketFrame(message)); return this; } @@ -73,13 +73,13 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } From 056127bbf40eff00970c523b63fea0b3e2ee8ea5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 12:15:50 +0200 Subject: [PATCH 0058/1949] Ensured Netty provider uses CONNECT when proxying ws, port #657 on master --- .../AsyncHttpClientConfig.java | 28 +++++++-------- .../AsyncHttpClientConfigBean.java | 2 +- .../AsyncHttpClientConfigDefaults.java | 6 ++-- .../util/AsyncHttpProviderUtils.java | 17 +++------ .../websocket/ProxyTunnellingTest.java | 36 +++++++++++-------- .../filters/AsyncHttpClientFilter.java | 8 +++-- .../providers/netty/handler/HttpProtocol.java | 2 +- .../netty/handler/WebSocketProtocol.java | 8 +++-- .../netty/request/NettyRequestFactory.java | 11 +++--- .../netty/request/NettyRequestSender.java | 3 +- .../providers/netty/util/HttpUtils.java | 4 +++ 11 files changed, 68 insertions(+), 57 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 8f1aefbf30..2a14d03f32 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -91,7 +91,7 @@ public class AsyncHttpClientConfig { protected boolean strict302Handling; protected ProxyServerSelector proxyServerSelector; - protected boolean useRelativeURIsWithSSLProxies; + protected boolean useRelativeURIsWithConnectProxies; protected boolean compressionEnabled; protected String userAgent; @@ -133,7 +133,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// boolean strict302Handling, // ExecutorService applicationThreadPool,// ProxyServerSelector proxyServerSelector, // - boolean useRelativeURIsWithSSLProxies, // + boolean useRelativeURIsWithConnectProxies, // boolean compressionEnabled, // String userAgent,// Realm realm,// @@ -167,7 +167,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; this.strict302Handling = strict302Handling; this.proxyServerSelector = proxyServerSelector; - this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; + this.useRelativeURIsWithConnectProxies = useRelativeURIsWithConnectProxies; this.compressionEnabled = compressionEnabled; this.userAgent = userAgent; this.applicationThreadPool = applicationThreadPool == null ? Executors.newCachedThreadPool() : applicationThreadPool; @@ -493,13 +493,13 @@ public boolean isStrict302Handling() { } /** - * @returntrue if AHC should use relative URIs instead of absolute ones when talking with a SSL proxy, - * otherwise false. + * @returntrue if AHC should use relative URIs instead of absolute ones when talking with a SSL proxy + * or WebSocket proxy, otherwise false. * - * @since 1.7.12 + * @since 1.8.13 */ - public boolean isUseRelativeURIsWithSSLProxies() { - return useRelativeURIsWithSSLProxies; + public boolean isUseRelativeURIsWithConnectProxies() { + return useRelativeURIsWithConnectProxies; } /** @@ -548,7 +548,7 @@ public static class Builder { private ProxyServerSelector proxyServerSelector = null; private boolean useProxySelector = defaultUseProxySelector(); private boolean useProxyProperties = defaultUseProxyProperties(); - private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + private boolean useRelativeURIsWithConnectProxies = defaultUseRelativeURIsWithConnectProxies(); private boolean compressionEnabled = defaultCompressionEnabled(); private String userAgent = defaultUserAgent(); private ExecutorService applicationThreadPool; @@ -962,15 +962,15 @@ public Builder setConnectionTTL(int connectionTTL) { } /** - * Configures this AHC instance to use relative URIs instead of absolute ones when talking with a SSL proxy. + * Configures this AHC instance to use relative URIs instead of absolute ones when talking with a SSL or WebSocket proxy. * - * @param useRelativeURIsWithSSLProxies + * @param useRelativeURIsWithConnectProxies * @return this * * @since 1.7.2 */ - public Builder setUseRelativeURIsWithSSLProxies(boolean useRelativeURIsWithSSLProxies) { - this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; + public Builder setUseRelativeURIsWithConnectProxies(boolean useRelativeURIsWithConnectProxies) { + this.useRelativeURIsWithConnectProxies = useRelativeURIsWithConnectProxies; return this; } @@ -1116,7 +1116,7 @@ else if (hostnameVerifier == null) strict302Handling, // applicationThreadPool, // proxyServerSelector, // - useRelativeURIsWithSSLProxies, // + useRelativeURIsWithConnectProxies, // compressionEnabled, // userAgent,// realm,// diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 150187cea6..0bb496f28e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -58,7 +58,7 @@ void configureDefaults() { compressionEnabled = defaultCompressionEnabled(); userAgent = defaultUserAgent(); allowPoolingConnections = defaultAllowPoolingConnections(); - useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + useRelativeURIsWithConnectProxies = defaultUseRelativeURIsWithConnectProxies(); maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowPoolingSslConnections = defaultAllowPoolingSslConnections(); diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 36991bfa2d..6733cd5c10 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -66,7 +66,7 @@ public static boolean defaultCompressionEnabled() { } public static String defaultUserAgent() { - return System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); + return System.getProperty(ASYNC_CLIENT + "userAgent", "AHC/2.0"); } public static int defaultIoThreadMultiplier() { @@ -89,8 +89,8 @@ public static boolean defaultAllowPoolingConnections() { return getBoolean(ASYNC_CLIENT + "allowPoolingConnections", true); } - public static boolean defaultUseRelativeURIsWithSSLProxies() { - return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); + public static boolean defaultUseRelativeURIsWithConnectProxies() { + return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithConnectProxies", true); } public static int defaultMaxRequestRetry() { diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index d0066c2adf..46371cb8ac 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -14,17 +14,16 @@ import static org.asynchttpclient.util.MiscUtils.isNonEmpty; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.AsyncHttpProvider; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.Request; -import org.asynchttpclient.uri.UriComponents; - import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.List; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.Request; +import org.asynchttpclient.uri.UriComponents; + /** * {@link org.asynchttpclient.AsyncHttpProvider} common utilities. */ @@ -113,12 +112,6 @@ public final static String getNonEmptyPath(UriComponents uri) { return isNonEmpty(uri.getPath()) ? uri.getPath() : "/"; } - public static String constructUserAgent(Class httpProvider, AsyncHttpClientConfig config) { - return new StringBuilder("AHC (").append(httpProvider.getSimpleName()).append(" - ").append(System.getProperty("os.name")) - .append(" - ").append(System.getProperty("os.version")).append(" - ").append(System.getProperty("java.version")) - .append(" - ").append(Runtime.getRuntime().availableProcessors()).append(" core(s))").toString(); - } - public static String parseCharset(String contentType) { for (String part : contentType.split(";")) { if (part.trim().startsWith("charset=")) { diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java index cdb6e38cad..1879d19302 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java @@ -17,6 +17,9 @@ import static org.asynchttpclient.async.util.TestUtils.newJettyHttpsServer; import static org.testng.Assert.assertEquals; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProxyServer; @@ -24,13 +27,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.websocket.server.WebSocketHandler; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; +import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - /** * Proxy usage tests. */ @@ -38,8 +37,7 @@ public abstract class ProxyTunnellingTest extends AbstractBasicTest { private Server server2; - @BeforeClass(alwaysRun = true) - public void setUpGlobal() throws Exception { + public void setUpServers(boolean targetHttps) throws Exception { port1 = findFreePort(); server = newJettyHttpServer(port1); server.setHandler(new ConnectHandler()); @@ -47,7 +45,7 @@ public void setUpGlobal() throws Exception { port2 = findFreePort(); - server2 = newJettyHttpsServer(port2); + server2 = targetHttps ? newJettyHttpsServer(port2) : newJettyHttpServer(port2); server2.setHandler(getWebSocketHandler()); server2.start(); @@ -64,27 +62,37 @@ public void configure(WebSocketServletFactory factory) { }; } - @AfterClass(alwaysRun = true) + @AfterMethod(alwaysRun = true) public void tearDownGlobal() throws Exception { server.stop(); server2.stop(); } - protected String getTargetUrl() { - return String.format("wss://127.0.0.1:%d/", port2); + @Test(timeOut = 60000) + public void echoWSText() throws Exception { + runTest(false); } @Test(timeOut = 60000) - public void echoText() throws Exception { + public void echoWSSText() throws Exception { + runTest(true); + } + + private void runTest(boolean secure) throws Exception { + + setUpServers(secure); + + String targetUrl = String.format("%s://127.0.0.1:%d/", secure ? "wss" : "ws", port2); - ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); + // CONNECT happens over HTTP, not HTTPS + ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTP, "127.0.0.1", port1); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).setAcceptAnyCertificate(true).build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = asyncHttpClient.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = asyncHttpClient.prepareGet(targetUrl).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 7d7f002699..e1d4c8f60f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -210,6 +210,7 @@ private boolean sendAsGrizzlyRequest( final Request request = httpTxContext.getRequest(); final UriComponents uri = request.getURI(); boolean secure = Utils.isSecure(uri); + boolean isWebSocket = isWSRequest(httpTxContext.getRequestUri()); // If the request is secure, check to see if an error occurred during // the handshake. We have to do this here, as the error would occur @@ -219,7 +220,8 @@ private boolean sendAsGrizzlyRequest( return true; } - if (isUpgradeRequest(httpTxContext.getHandler()) && isWSRequest(httpTxContext.getRequestUri())) { + + if (isUpgradeRequest(httpTxContext.getHandler()) && isWebSocket) { httpTxContext.setWSRequest(true); convertToUpgradeRequest(httpTxContext); } @@ -238,8 +240,10 @@ private boolean sendAsGrizzlyRequest( if (method == Method.CONNECT) { final int port = uri.getPort(); requestPacket.setRequestURI(uri.getHost() + ':' + (port == -1 ? 443 : port)); - } else { + } else if ((secure || isWebSocket) && config.isUseRelativeURIsWithConnectProxies()) { requestPacket.setRequestURI(getNonEmptyPath(uri)); + } else { + requestPacket.setRequestURI(uri.toUrl()); } final BodyHandler bodyHandler = isPayloadAllowed(method) ? diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 531c3c6246..29770ecc63 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -405,7 +405,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f try { if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - // FIXME why do we buffer the response? I don't remember... + // we buffer the response until we get the LastHttpContent future.setPendingResponse(response); return; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index bdedadd68c..371c943206 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -72,6 +72,12 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; + // we buffer the response until we get the LastHttpContent + future.setPendingResponse(response); + + } else if (e instanceof LastHttpContent) { + HttpResponse response = future.getPendingResponse(); + future.setPendingResponse(null); HttpResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); HttpResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); @@ -151,8 +157,6 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr } else { logger.debug("UpgradeHandler returned a null NettyWebSocket "); } - } else if (e instanceof LastHttpContent) { - // FIXME what to do with this kind of messages? } else { logger.error("Invalid message {}", e); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index fa971cf010..bd2850be64 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -16,9 +16,9 @@ import static org.asynchttpclient.providers.netty.util.HttpUtils.isNTLM; import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; import static org.asynchttpclient.providers.netty.util.HttpUtils.isWebSocket; +import static org.asynchttpclient.providers.netty.util.HttpUtils.useProxyConnect; import static org.asynchttpclient.providers.netty.ws.WebSocketUtils.getKey; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static org.asynchttpclient.util.AsyncHttpProviderUtils.constructUserAgent; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.AsyncHttpProviderUtils.keepAliveHeaderValue; @@ -49,7 +49,6 @@ import org.asynchttpclient.generators.InputStreamBodyGenerator; import org.asynchttpclient.ntlm.NTLMEngine; import org.asynchttpclient.ntlm.NTLMEngineException; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProvider; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.request.body.NettyBody; import org.asynchttpclient.providers.netty.request.body.NettyBodyBody; @@ -77,7 +76,7 @@ private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod if (method == HttpMethod.CONNECT) return getAuthority(uri); - else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) + else if (proxyServer != null && !(useProxyConnect(uri) && config.isUseRelativeURIsWithConnectProxies())) return uri.toString(); else { @@ -322,10 +321,8 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean httpRequest.headers().set(HttpHeaders.Names.ACCEPT, "*/*"); // Add default user agent - if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT)) { - String userAgent = config.getUserAgent() != null ? config.getUserAgent() : constructUserAgent(NettyAsyncHttpProvider.class, config); - httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, userAgent); - } + if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT) && config.getUserAgent() != null) + httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); return nettyRequest; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 68da7ab765..75a3def312 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -15,6 +15,7 @@ import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.useProxyConnect; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getDefaultPort; import static org.asynchttpclient.util.AsyncHttpProviderUtils.requestTimeout; import static org.asynchttpclient.util.ProxyUtils.avoidProxy; @@ -100,7 +101,7 @@ public ListenableFuture sendRequest(final Request request,// boolean resultOfAConnect = future != null && future.getNettyRequest() != null && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; boolean useProxy = proxyServer != null && !resultOfAConnect; - if (useProxy && isSecure(uri)) + if (useProxy && useProxyConnect(uri)) // SSL proxy, have to handle CONNECT if (future != null && future.isConnectAllowed()) // CONNECT forced diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java index e13b7ee51b..baac5bddbd 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java @@ -43,4 +43,8 @@ public static boolean isSecure(String scheme) { public static boolean isSecure(UriComponents uri) { return isSecure(uri.getScheme()); } + + public static boolean useProxyConnect(UriComponents uri) { + return isSecure(uri) || isWebSocket(uri.getScheme()); + } } From 2c38d0148108c4f1aae609a54f14bc8aa6e78818 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 15:02:53 +0200 Subject: [PATCH 0059/1949] Release 1.8.13 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fab0cd307c..2bb2b19ad0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.12 + 1.8.13 ``` From 0e4aa68fb9917f60b88e114b41eb9f3b97b4babe Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 15:59:10 +0200 Subject: [PATCH 0060/1949] Extract Fragment listening concern into dedicated interfaces, close #655 --- .../websocket/DefaultWebSocketListener.java | 14 -- .../WebSocketByteFragmentListener.java | 26 +++ .../websocket/WebSocketByteListener.java | 9 +- .../WebSocketTextFragmentListener.java | 26 +++ .../websocket/WebSocketTextListener.java | 8 - .../websocket/ByteMessageTest.java | 12 -- .../websocket/CloseCodeReasonMessageTest.java | 8 - .../websocket/ProxyTunnellingTest.java | 4 - .../websocket/TextMessageTest.java | 24 --- .../AHCWebSocketListenerAdapter.java | 8 - .../netty/NettyAsyncHttpProviderConfig.java | 3 +- .../netty/ws/DefaultNettyWebSocket.java | 124 ------------ .../providers/netty/ws/NettyWebSocket.java | 186 +++++++++++++++--- 13 files changed, 217 insertions(+), 235 deletions(-) create mode 100644 api/src/main/java/org/asynchttpclient/websocket/WebSocketByteFragmentListener.java create mode 100644 api/src/main/java/org/asynchttpclient/websocket/WebSocketTextFragmentListener.java delete mode 100644 providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java diff --git a/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java b/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java index 864bb32df8..7e465acffa 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java @@ -33,13 +33,6 @@ public class DefaultWebSocketListener implements WebSocketByteListener, WebSocke public void onMessage(byte[] message) { } - /** - * {@inheritDoc} - */ - @Override - public void onFragment(byte[] fragment, boolean last) { - } - // -------------------------------------- Methods from WebSocketPingListener /** @@ -67,13 +60,6 @@ public void onPong(byte[] message) { public void onMessage(String message) { } - /** - * {@inheritDoc} - */ - @Override - public void onFragment(String fragment, boolean last) { - } - // ------------------------------------------ Methods from WebSocketListener /** diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteFragmentListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteFragmentListener.java new file mode 100644 index 0000000000..9988115b25 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteFragmentListener.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package org.asynchttpclient.websocket; + +import org.asynchttpclient.HttpResponseBodyPart; + +/** + * Invoked when WebSocket binary fragments are received. + * + * @param fragment text fragment + */ +public interface WebSocketByteFragmentListener extends WebSocketListener { + + void onFragment(HttpResponseBodyPart fragment); +} diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java index 04dd4075ec..99fb4cede9 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java @@ -19,15 +19,8 @@ public interface WebSocketByteListener extends WebSocketListener { /** * Invoked when bytes are available. + * * @param message a byte array. */ void onMessage(byte[] message); - - /** - * Invoked when bytes of a fragmented message are available. - * - * @param fragment byte[] fragment. - * @param last if this fragment is the last in the series. - */ - void onFragment(byte[] fragment, boolean last); } diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextFragmentListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextFragmentListener.java new file mode 100644 index 0000000000..a71f9364b4 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextFragmentListener.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package org.asynchttpclient.websocket; + +import org.asynchttpclient.HttpResponseBodyPart; + +/** + * Invoked when WebSocket text fragments are received. + * + * @param fragment text fragment + */ +public interface WebSocketTextFragmentListener extends WebSocketListener { + + void onFragment(HttpResponseBodyPart fragment); +} diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java index 2ea133b1ec..7f8242c74d 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java @@ -22,12 +22,4 @@ public interface WebSocketTextListener extends WebSocketListener { * @param message a {@link String} message */ void onMessage(String message); - - /** - * Invoked when WebSocket text fragments are received. - * - * @param fragment text fragment - * @param last if this fragment is the last of the series. - */ - void onFragment(String fragment, boolean last); } diff --git a/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java index 4272b3ac48..d1078047ec 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java @@ -64,9 +64,6 @@ public void onMessage(byte[] message) { latch.countDown(); } - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); websocket.sendMessage("ECHO".getBytes()); @@ -115,9 +112,6 @@ public void onMessage(byte[] message) { latch.countDown(); } - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); websocket.sendMessage("ECHO".getBytes()).sendMessage("ECHO".getBytes()); @@ -167,9 +161,6 @@ public void onMessage(byte[] message) { latch.countDown(); } - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); latch.await(); @@ -215,9 +206,6 @@ public void onMessage(byte[] message) { latch.countDown(); } - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); websocket.stream("ECHO".getBytes(), false); websocket.stream("ECHO".getBytes(), true); diff --git a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java index d5640b10ef..5ab3ca228d 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java @@ -115,10 +115,6 @@ public void wrongStatusCode() throws Throwable { public void onMessage(String message) { } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -155,10 +151,6 @@ public void wrongProtocolCode() throws Throwable { public void onMessage(String message) { } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java index 1879d19302..55c54970e4 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java @@ -100,10 +100,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } diff --git a/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java index 2ec3c20e3d..31d740c5ad 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java @@ -184,10 +184,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -228,10 +224,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -254,10 +246,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -298,10 +286,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { websocket.sendTextMessage("ECHO").sendTextMessage("ECHO"); @@ -340,10 +324,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -386,10 +366,6 @@ public void onMessage(String message) { textLatch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java index 1a2f2122b2..1d2dd1291c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java @@ -128,10 +128,6 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, Str } } } - } else { - if (ahcListener instanceof WebSocketTextListener) { - WebSocketTextListener.class.cast(ahcListener).onFragment(s, last); - } } } catch (Throwable e) { ahcListener.onError(e); @@ -152,10 +148,6 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, byt } } } - } else { - if (ahcListener instanceof WebSocketByteListener) { - WebSocketByteListener.class.cast(ahcListener).onFragment(bytes, last); - } } } catch (Throwable e) { ahcListener.onError(e); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 95eed7889f..38aa908fa9 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -29,7 +29,6 @@ import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.asynchttpclient.providers.netty.ws.DefaultNettyWebSocket; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; /** @@ -124,7 +123,7 @@ public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { @Override public NettyWebSocket newNettyWebSocket(Channel channel) { - return new DefaultNettyWebSocket(channel); + return new NettyWebSocket(channel); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java deleted file mode 100644 index 11b8cfd133..0000000000 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ -package org.asynchttpclient.providers.netty.ws; - - -import io.netty.channel.Channel; - -import java.io.ByteArrayOutputStream; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.util.StandardCharsets; -import org.asynchttpclient.websocket.WebSocketByteListener; -import org.asynchttpclient.websocket.WebSocketListener; -import org.asynchttpclient.websocket.WebSocketTextListener; - -public class DefaultNettyWebSocket extends NettyWebSocket { - - private final StringBuilder textBuffer = new StringBuilder(); - private final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); - - public DefaultNettyWebSocket(Channel channel) { - super(channel, new ConcurrentLinkedQueue()); - } - - public void onBinaryFragment(HttpResponseBodyPart part) { - - boolean last = part.isLast(); - byte[] message = part.getBodyPartBytes(); - - if (!last) { - try { - byteBuffer.write(message); - } catch (Exception ex) { - byteBuffer.reset(); - onError(ex); - return; - } - - if (byteBuffer.size() > maxBufferSize) { - byteBuffer.reset(); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketByteListener) { - WebSocketByteListener byteListener = (WebSocketByteListener) listener; - try { - if (!last) { - byteListener.onFragment(message, last); - } else if (byteBuffer.size() > 0) { - byteBuffer.write(message); - byteListener.onFragment(message, last); - byteListener.onMessage(byteBuffer.toByteArray()); - } else { - byteListener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) { - byteBuffer.reset(); - } - } - - public void onTextFragment(HttpResponseBodyPart part) { - - boolean last = part.isLast(); - // FIXME this is so wrong! there's a chance the fragment is not valid UTF-8 because a char is truncated - String message = new String(part.getBodyPartBytes(), StandardCharsets.UTF_8); - - if (!last) { - textBuffer.append(message); - - if (textBuffer.length() > maxBufferSize) { - textBuffer.setLength(0); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketTextListener) { - WebSocketTextListener textlistener = (WebSocketTextListener) listener; - try { - if (!last) { - textlistener.onFragment(message, last); - } else if (textBuffer.length() > 0) { - textlistener.onFragment(message, last); - textlistener.onMessage(textBuffer.append(message).toString()); - } else { - textlistener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) { - textBuffer.setLength(0); - } - } -} diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 97068be924..34bc1b1c33 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -14,6 +14,7 @@ package org.asynchttpclient.providers.netty.ws; import static io.netty.buffer.Unpooled.wrappedBuffer; +import static org.asynchttpclient.util.StandardCharsets.UTF_8; import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; @@ -22,22 +23,40 @@ import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import org.asynchttpclient.websocket.WebSocket; +import org.asynchttpclient.websocket.WebSocketByteFragmentListener; +import org.asynchttpclient.websocket.WebSocketByteListener; import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; import org.asynchttpclient.websocket.WebSocketListener; +import org.asynchttpclient.websocket.WebSocketTextFragmentListener; +import org.asynchttpclient.websocket.WebSocketTextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public abstract class NettyWebSocket implements WebSocket { +public class NettyWebSocket implements WebSocket { private static final Logger LOGGER = LoggerFactory.getLogger(NettyWebSocket.class); protected final Channel channel; protected final Collection listeners; protected int maxBufferSize = 128000000; + private int bufferSize; + private List _fragments; + private volatile boolean interestedInByteMessages; + private volatile boolean interestedInTextMessages; + + public NettyWebSocket(Channel channel) { + this(channel, new ConcurrentLinkedQueue()); + } public NettyWebSocket(Channel channel, Collection listeners) { this.channel = channel; @@ -46,7 +65,7 @@ public NettyWebSocket(Channel channel, Collection listeners) @Override public WebSocket sendMessage(byte[] message) { - channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -62,7 +81,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.writeAndFlush(new TextWebSocketFrame(message)); + channel.write(new TextWebSocketFrame(message)); return this; } @@ -73,36 +92,24 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); - return this; - } - - @Override - public WebSocket addWebSocketListener(WebSocketListener l) { - listeners.add(l); - return this; - } - - @Override - public WebSocket removeWebSocketListener(WebSocketListener l) { - listeners.remove(l); + channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } public int getMaxBufferSize() { return maxBufferSize; } - + public void setMaxBufferSize(int maxBufferSize) { this.maxBufferSize = Math.max(maxBufferSize, 8192); } - + @Override public boolean isOpen() { return channel.isOpen(); @@ -153,8 +160,141 @@ public void onClose(int code, String reason) { public String toString() { return "NettyWebSocket{channel=" + channel + '}'; } - - public abstract void onBinaryFragment(HttpResponseBodyPart part); - - public abstract void onTextFragment(HttpResponseBodyPart part); + + private boolean hasWebSocketByteListener() { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) + return true; + } + return false; + } + + private boolean hasWebSocketTextListener() { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) + return true; + } + return false; + } + + @Override + public WebSocket addWebSocketListener(WebSocketListener l) { + listeners.add(l); + if (l instanceof WebSocketByteListener) + interestedInByteMessages = true; + else if (l instanceof WebSocketTextListener) + interestedInTextMessages = true; + return this; + } + + @Override + public WebSocket removeWebSocketListener(WebSocketListener l) { + listeners.remove(l); + + if (l instanceof WebSocketByteListener) + interestedInByteMessages = hasWebSocketByteListener(); + else if (l instanceof WebSocketTextListener) + interestedInTextMessages = hasWebSocketTextListener(); + + return this; + } + + private List fragments() { + if (_fragments == null) + _fragments = new ArrayList(2); + return _fragments; + } + + private void bufferFragment(byte[] buffer) { + bufferSize += buffer.length; + if (bufferSize > maxBufferSize) { + onError(new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize)); + reset(); + close(); + } else { + fragments().add(buffer); + } + } + + private void reset() { + fragments().clear(); + bufferSize = 0; + } + + private void notifyByteListeners(byte[] message) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) + WebSocketByteListener.class.cast(listener).onMessage(message); + } + } + + private void notifyTextListeners(byte[] bytes) { + String message = new String(bytes, UTF_8); + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) + WebSocketTextListener.class.cast(listener).onMessage(message); + } + } + + public void onBinaryFragment(HttpResponseBodyPart part) { + + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteFragmentListener) + WebSocketByteFragmentListener.class.cast(listener).onFragment(part); + } + + if (interestedInByteMessages) { + byte[] fragment = NettyResponseBodyPart.class.cast(part).getBodyPartBytes(); + + if (part.isLast()) { + if (bufferSize == 0) { + notifyByteListeners(fragment); + + } else { + bufferFragment(fragment); + notifyByteListeners(fragmentsBytes()); + } + + reset(); + + } else + bufferFragment(fragment); + } + } + + private byte[] fragmentsBytes() { + ByteArrayOutputStream os = new ByteArrayOutputStream(bufferSize); + for (byte[] bytes : _fragments) + try { + os.write(bytes); + } catch (IOException e) { + // yeah, right + } + return os.toByteArray(); + } + + public void onTextFragment(HttpResponseBodyPart part) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextFragmentListener) + WebSocketTextFragmentListener.class.cast(listener).onFragment(part); + } + + if (interestedInTextMessages) { + byte[] fragment = NettyResponseBodyPart.class.cast(part).getBodyPartBytes(); + + if (part.isLast()) { + if (bufferSize == 0) { + notifyTextListeners(fragment); + + } else { + bufferFragment(fragment); + notifyTextListeners(fragmentsBytes()); + } + + reset(); + + } else + bufferFragment(fragment); + } + } } From 5a6c1ea9f1d6a35211f320c345cafd6a3a610597 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:00:25 +0200 Subject: [PATCH 0061/1949] Regression: writeAndFlush --- .../providers/netty/ws/NettyWebSocket.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 34bc1b1c33..98789d0906 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -65,7 +65,7 @@ public NettyWebSocket(Channel channel, Collection listeners) @Override public WebSocket sendMessage(byte[] message) { - channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -81,7 +81,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.write(new TextWebSocketFrame(message)); + channel.writeAndFlush(new TextWebSocketFrame(message)); return this; } @@ -92,13 +92,13 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } @@ -120,7 +120,7 @@ public void close() { if (channel.isOpen()) { onClose(); listeners.clear(); - channel.write(new CloseWebSocketFrame()).addListener(ChannelFutureListener.CLOSE); + channel.writeAndFlush(new CloseWebSocketFrame()).addListener(ChannelFutureListener.CLOSE); } } From ce539ee0954329b92bff5e2237bf1836cb526524 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:03:43 +0200 Subject: [PATCH 0062/1949] Netty websocket streaming, close #518 --- .../providers/netty/ws/NettyWebSocket.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 98789d0906..88357866bd 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -71,12 +71,14 @@ public WebSocket sendMessage(byte[] message) { @Override public WebSocket stream(byte[] fragment, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + channel.writeAndFlush(new BinaryWebSocketFrame(last, 0, wrappedBuffer(fragment))); + return this; } @Override public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + channel.writeAndFlush(new BinaryWebSocketFrame(last, 0, wrappedBuffer(fragment, offset, len))); + return this; } @Override @@ -87,7 +89,8 @@ public WebSocket sendTextMessage(String message) { @Override public WebSocket streamText(String fragment, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + channel.writeAndFlush(new TextWebSocketFrame(last, 0, fragment)); + return this; } @Override From 7a067549012c4474a1a01c8c9beaf45c471962bb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:28:38 +0200 Subject: [PATCH 0063/1949] Notify Pings and Pongs, close #517 --- .../netty/handler/WebSocketProtocol.java | 25 ++++++++++++------- .../providers/netty/ws/NettyWebSocket.java | 18 +++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 371c943206..7dfbbe0690 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -22,6 +22,9 @@ import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import java.io.IOException; @@ -74,7 +77,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr HttpResponse response = (HttpResponse) e; // we buffer the response until we get the LastHttpContent future.setPendingResponse(response); - + } else if (e instanceof LastHttpContent) { HttpResponse response = future.getPendingResponse(); future.setPendingResponse(null); @@ -115,8 +118,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr } String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers() - .get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); + String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { requestSender.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); } @@ -141,13 +143,17 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr ByteBuf buf = frame.content(); if (buf != null && buf.readableBytes() > 0) { try { - NettyResponseBodyPart rp = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, frame.isFinalFragment()); - handler.onBodyPartReceived(rp); + NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, frame.isFinalFragment()); + handler.onBodyPartReceived(part); if (frame instanceof BinaryWebSocketFrame) { - webSocket.onBinaryFragment(rp); - } else { - webSocket.onTextFragment(rp); + webSocket.onBinaryFragment(part); + } else if (frame instanceof TextWebSocketFrame) { + webSocket.onTextFragment(part); + } else if (frame instanceof PingWebSocketFrame) { + webSocket.onPing(part); + } else if (frame instanceof PongWebSocketFrame) { + webSocket.onPong(part); } } finally { buf.release(); @@ -196,7 +202,8 @@ public void onClose(Channel channel) { WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - // FIXME How could this test not succeed, we just checked above that attribute is a NettyResponseFuture???? + // FIXME How could this test not succeed, we just checked above that + // attribute is a NettyResponseFuture???? logger.trace("Connection was closed abnormally (that is, with no close frame being sent)."); if (attribute != DiscardEvent.INSTANCE && webSocket != null) webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 88357866bd..08e14e6183 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -37,6 +37,8 @@ import org.asynchttpclient.websocket.WebSocketByteListener; import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; import org.asynchttpclient.websocket.WebSocketListener; +import org.asynchttpclient.websocket.WebSocketPingListener; +import org.asynchttpclient.websocket.WebSocketPongListener; import org.asynchttpclient.websocket.WebSocketTextFragmentListener; import org.asynchttpclient.websocket.WebSocketTextListener; import org.slf4j.Logger; @@ -300,4 +302,20 @@ public void onTextFragment(HttpResponseBodyPart part) { bufferFragment(fragment); } } + + public void onPing(HttpResponseBodyPart part) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketPingListener) + // bytes are cached in the part + WebSocketPingListener.class.cast(listener).onPing(part.getBodyPartBytes()); + } + } + + public void onPong(HttpResponseBodyPart part) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketPongListener) + // bytes are cached in the part + WebSocketPongListener.class.cast(listener).onPong(part.getBodyPartBytes()); + } + } } From 4e8d62e1a80890d42810799e580681a0c8e6faa1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:41:47 +0200 Subject: [PATCH 0064/1949] Have a config parameter for websocket max buffer size, close #658 --- .../netty/NettyAsyncHttpProviderConfig.java | 24 ++++++++++++------- .../netty/handler/WebSocketProtocol.java | 2 +- .../providers/netty/ws/NettyWebSocket.java | 18 +++++--------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 38aa908fa9..2e105d2031 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -43,10 +43,8 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig name, Object value) { @@ -116,17 +114,17 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { } public static interface NettyWebSocketFactory { - NettyWebSocket newNettyWebSocket(Channel channel); + NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig); } public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { @Override - public NettyWebSocket newNettyWebSocket(Channel channel) { - return new NettyWebSocket(channel); + public NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig) { + return new NettyWebSocket(channel, nettyConfig); } } - + /** * Allow configuring the Netty's event loop. */ @@ -166,6 +164,8 @@ public NettyWebSocket newNettyWebSocket(Channel channel) { private NettyWebSocketFactory nettyWebSocketFactory = new DefaultNettyWebSocketFactory(); + private int webSocketMaxBufferSize = 128000000; + public EventLoopGroup getEventLoopGroup() { return eventLoopGroup; } @@ -293,4 +293,12 @@ public NettyWebSocketFactory getNettyWebSocketFactory() { public void setNettyWebSocketFactory(NettyWebSocketFactory nettyWebSocketFactory) { this.nettyWebSocketFactory = nettyWebSocketFactory; } + + public int getWebSocketMaxBufferSize() { + return webSocketMaxBufferSize; + } + + public void setWebSocketMaxBufferSize(int webSocketMaxBufferSize) { + this.webSocketMaxBufferSize = webSocketMaxBufferSize; + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 7dfbbe0690..117330693d 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -61,7 +61,7 @@ public WebSocketProtocol(ChannelManager channelManager,// private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { if (!h.touchSuccess()) { try { - h.onSuccess(nettyConfig.getNettyWebSocketFactory().newNettyWebSocket(channel)); + h.onSuccess(nettyConfig.getNettyWebSocketFactory().newNettyWebSocket(channel, nettyConfig)); } catch (Exception ex) { logger.warn("onSuccess unexpected exception", ex); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 08e14e6183..d93e3ef8dc 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import org.asynchttpclient.websocket.WebSocket; import org.asynchttpclient.websocket.WebSocketByteFragmentListener; @@ -50,19 +51,20 @@ public class NettyWebSocket implements WebSocket { protected final Channel channel; protected final Collection listeners; - protected int maxBufferSize = 128000000; + protected final int maxBufferSize; private int bufferSize; private List _fragments; private volatile boolean interestedInByteMessages; private volatile boolean interestedInTextMessages; - public NettyWebSocket(Channel channel) { - this(channel, new ConcurrentLinkedQueue()); + public NettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig) { + this(channel, nettyConfig, new ConcurrentLinkedQueue()); } - public NettyWebSocket(Channel channel, Collection listeners) { + public NettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig, Collection listeners) { this.channel = channel; this.listeners = listeners; + maxBufferSize = nettyConfig.getWebSocketMaxBufferSize(); } @Override @@ -107,14 +109,6 @@ public WebSocket sendPong(byte[] payload) { return this; } - public int getMaxBufferSize() { - return maxBufferSize; - } - - public void setMaxBufferSize(int maxBufferSize) { - this.maxBufferSize = Math.max(maxBufferSize, 8192); - } - @Override public boolean isOpen() { return channel.isOpen(); From e1da1c6c8b77b01cc96fbdb01c3ce63eb1fa664e Mon Sep 17 00:00:00 2001 From: oleksiys Date: Fri, 1 Aug 2014 16:13:14 -0700 Subject: [PATCH 0065/1949] [master] + don't add another Host header if it's already set --- .../filters/AsyncHttpClientFilter.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index e1d4c8f60f..7d80c95d99 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -420,15 +420,18 @@ private static FilterChainContext obtainProtocolChainContext(final FilterChainCo return newFilterChainContext; } - private static void addHostHeader(final Request request, final UriComponents uri, final HttpRequestPacket requestPacket) { - String host = request.getVirtualHost(); - if (host != null) { - requestPacket.addHeader(Header.Host, host); - } else { - if (uri.getPort() == -1) { - requestPacket.addHeader(Header.Host, uri.getHost()); + private static void addHostHeader(final Request request, + final UriComponents uri, final HttpRequestPacket requestPacket) { + if (!request.getHeaders().containsKey(Header.Host.toString())) { + String host = request.getVirtualHost(); + if (host != null) { + requestPacket.addHeader(Header.Host, host); } else { - requestPacket.addHeader(Header.Host, uri.getHost() + ':' + uri.getPort()); + if (uri.getPort() == -1) { + requestPacket.addHeader(Header.Host, uri.getHost()); + } else { + requestPacket.addHeader(Header.Host, uri.getHost() + ':' + uri.getPort()); + } } } } From 7d285b5ed15439c376c7ba3c2aa3c89db80274eb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 07:46:20 +0200 Subject: [PATCH 0066/1949] Upgrade Netty 4.0.23.Final, close #667 --- providers/netty/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/pom.xml b/providers/netty/pom.xml index bc9e908b63..57510c4cfc 100644 --- a/providers/netty/pom.xml +++ b/providers/netty/pom.xml @@ -39,7 +39,7 @@ io.netty netty-all - 4.0.20.Final + 4.0.23.Final org.javassist From 550ce1cc02628dadcd5f976c50fce80548064579 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 07:48:21 +0200 Subject: [PATCH 0067/1949] Fix MiscUtils: closeSilently should check for nullity, close #662 --- .../main/java/org/asynchttpclient/util/MiscUtils.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtils.java b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java index 1943f9939b..55b5ba12cd 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java @@ -52,9 +52,10 @@ public static T withDefault(T value, T defaults) { } public static void closeSilently(Closeable closeable) { - try { - closeable.close(); - } catch (IOException e) { - } + if (closeable != null) + try { + closeable.close(); + } catch (IOException e) { + } } } From e33026d481671313fd4c1d35a51c9aa38371e09f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:33:47 +0200 Subject: [PATCH 0068/1949] Append char instead of String --- .../providers/netty/request/NettyRequestFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index bd2850be64..0e24e441a2 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -189,9 +189,9 @@ private byte[] computeBodyFromParams(List params, Charset bodyCharset) { StringBuilder sb = new StringBuilder(); for (Param param : params) { UTF8UrlEncoder.appendEncoded(sb, param.getName()); - sb.append("="); + sb.append('='); UTF8UrlEncoder.appendEncoded(sb, param.getValue()); - sb.append("&"); + sb.append('&'); } sb.setLength(sb.length() - 1); return sb.toString().getBytes(bodyCharset); From 3014f512f2764ceb5b7893684e278fc536867927 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:34:37 +0200 Subject: [PATCH 0069/1949] 0 means empty file, not chunked --- .../providers/netty/request/NettyRequestFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 0e24e441a2..62cf4e89bb 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -280,10 +280,10 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean } if (body != null) { - if (body.getContentLength() > 0) - httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); - else + if (body.getContentLength() < 0) httpRequest.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + else + httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); if (body.getContentType() != null) httpRequest.headers().set(HttpHeaders.Names.CONTENT_TYPE, body.getContentType()); From babb5be9c7dda2adc2fbf646dff952b48f8802ae Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:36:40 +0200 Subject: [PATCH 0070/1949] Don't use replace but addAfter+remove so that first frame is not lost, close #471 --- .../providers/netty/channel/ChannelManager.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 6fb3b03f3b..43d8aa9bd2 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -385,8 +385,10 @@ public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host else pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); - if (isWebSocket(scheme)) - pipeline.replace(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); + if (isWebSocket(scheme)) { + pipeline.addAfter(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); + pipeline.remove(HTTP_PROCESSOR); + } } public String getPoolKey(NettyResponseFuture future) { @@ -416,7 +418,8 @@ public Bootstrap getBootstrap(UriComponents uri, boolean useProxy, boolean useSS } public void upgradePipelineForWebSockets(ChannelPipeline pipeline) { - pipeline.replace(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); + pipeline.addAfter(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); + pipeline.remove(HTTP_HANDLER); pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); } From 429cc63fc92ae720e0de31df4f77f8b202952869 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:38:55 +0200 Subject: [PATCH 0071/1949] minor clean up --- .../netty/request/NettyRequestFactory.java | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 62cf4e89bb..ac3368d5c3 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -266,63 +266,65 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean nettyRequest = new NettyRequest(httpRequest, body); } + HttpHeaders headers = httpRequest.headers(); + if (method != HttpMethod.CONNECT) { // assign headers as configured on request for (Entry> header : request.getHeaders()) { - httpRequest.headers().set(header.getKey(), header.getValue()); + headers.set(header.getKey(), header.getValue()); } if (isNonEmpty(request.getCookies())) - httpRequest.headers().set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); + headers.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); if (config.isCompressionEnabled()) - httpRequest.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); + headers.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); } if (body != null) { if (body.getContentLength() < 0) - httpRequest.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + headers.set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); else - httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); + headers.set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); if (body.getContentType() != null) - httpRequest.headers().set(HttpHeaders.Names.CONTENT_TYPE, body.getContentType()); + headers.set(HttpHeaders.Names.CONTENT_TYPE, body.getContentType()); } // connection header and friends boolean webSocket = isWebSocket(uri.getScheme()); if (method != HttpMethod.CONNECT && webSocket) { - httpRequest.headers().set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); - httpRequest.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - httpRequest.headers().set(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); - httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey()); - httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); - - } else if (!httpRequest.headers().contains(HttpHeaders.Names.CONNECTION)) { - httpRequest.headers().set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); + headers.set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET)// + .set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE)// + .set(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort()))// + .set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey())// + .set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); + + } else if (!headers.contains(HttpHeaders.Names.CONNECTION)) { + headers.set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); } String hostHeader = hostHeader(request, uri); if (hostHeader != null) - httpRequest.headers().set(HttpHeaders.Names.HOST, hostHeader); + headers.set(HttpHeaders.Names.HOST, hostHeader); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); String authorizationHeader = authorizationHeader(request, uri, proxyServer, realm); if (authorizationHeader != null) // don't override authorization but append - httpRequest.headers().add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader); + headers.add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader); String proxyAuthorizationHeader = proxyAuthorizationHeader(request, proxyServer, method); if (proxyAuthorizationHeader != null) - httpRequest.headers().set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader); + headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader); // Add default accept headers - if (!httpRequest.headers().contains(HttpHeaders.Names.ACCEPT)) - httpRequest.headers().set(HttpHeaders.Names.ACCEPT, "*/*"); + if (!headers.contains(HttpHeaders.Names.ACCEPT)) + headers.set(HttpHeaders.Names.ACCEPT, "*/*"); // Add default user agent - if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT) && config.getUserAgent() != null) - httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); + if (!headers.contains(HttpHeaders.Names.USER_AGENT) && config.getUserAgent() != null) + headers.set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); return nettyRequest; } From b01e94ffa0b4295ede2950736b5e132bce45f789 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:58:04 +0200 Subject: [PATCH 0072/1949] Target JDK7, use getHostString instead of getHostName, close #672 --- .../asynchttpclient/providers/netty/channel/SslInitializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java index 31819ee86b..0a938b1f5f 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java @@ -41,7 +41,7 @@ public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, Sock throws Exception { InetSocketAddress remoteInetSocketAddress = (InetSocketAddress) remoteAddress; - String peerHost = remoteInetSocketAddress.getHostName(); + String peerHost = remoteInetSocketAddress.getHostString(); int peerPort = remoteInetSocketAddress.getPort(); SslHandler sslHandler = channelManager.createSslHandler(peerHost, peerPort); From 6918cced9415327adf2d636d66d84bb8d604c6fc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 14:12:35 +0200 Subject: [PATCH 0073/1949] Do not block the WebSocket from receiving bytes or text fragments, close #660 --- .../providers/netty/ws/NettyWebSocket.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index d93e3ef8dc..3cdb818a50 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -179,10 +179,8 @@ private boolean hasWebSocketTextListener() { @Override public WebSocket addWebSocketListener(WebSocketListener l) { listeners.add(l); - if (l instanceof WebSocketByteListener) - interestedInByteMessages = true; - else if (l instanceof WebSocketTextListener) - interestedInTextMessages = true; + interestedInByteMessages = interestedInByteMessages || l instanceof WebSocketByteListener; + interestedInTextMessages = interestedInTextMessages || l instanceof WebSocketTextListener; return this; } @@ -192,7 +190,7 @@ public WebSocket removeWebSocketListener(WebSocketListener l) { if (l instanceof WebSocketByteListener) interestedInByteMessages = hasWebSocketByteListener(); - else if (l instanceof WebSocketTextListener) + if (l instanceof WebSocketTextListener) interestedInTextMessages = hasWebSocketTextListener(); return this; From 21660bae880b13b4909a2e018648e3e9723ef2e2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 14:15:08 +0200 Subject: [PATCH 0074/1949] Wrong javadoc, close #666 --- api/src/main/java/org/asynchttpclient/Request.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index 597931456f..e292e8b5e8 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -34,7 +34,6 @@ * .setPassword(admin) * .setRealmName("MyRealm") * .setScheme(Realm.AuthScheme.DIGEST).build()); - * r.execute(); * */ public interface Request { From b0ec7416912eeb0ca835bdead850f38c7e6e8851 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 15:04:53 +0200 Subject: [PATCH 0075/1949] Add handler callbacks, close #673 --- .../AsyncHandlerExtensions.java | 24 ++++++++++++++--- .../netty/request/NettyConnectListener.java | 27 ++++++++++--------- .../netty/request/NettyRequestSender.java | 19 +++++++++---- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java b/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java index fd4a5bf79e..1d81570b0f 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java @@ -19,7 +19,6 @@ * * More additional hooks might come, such as: *