[httpcomponents-client] 01/09: Imported Upstream version 4.4.1

Emmanuel Bourg ebourg-guest at moszumanska.debian.org
Mon May 11 13:50:13 UTC 2015


This is an automated email from the git hooks/post-receive script.

ebourg-guest pushed a commit to annotated tag debian/4.4.1-1
in repository httpcomponents-client.

commit 460e8d708b6772411d4b13d67dbc935d9f5a40db
Author: Emmanuel Bourg <ebourg at apache.org>
Date:   Mon May 11 14:16:02 2015 +0200

    Imported Upstream version 4.4.1
---
 BUILDING.txt                                       |    19 +-
 LICENSE.txt                                        |   382 +
 NOTICE.txt                                         |     2 +-
 README.txt                                         |     4 +-
 RELEASE_NOTES.txt                                  |   222 +-
 fluent-hc/pom.xml                                  |     8 +-
 .../org/apache/http/client/fluent/FluentAsync.java |     3 +
 .../http/client/fluent/FluentResponseHandling.java |     1 +
 .../java/org/apache/http/client/fluent/Async.java  |     1 +
 .../org/apache/http/client/fluent/Content.java     |    18 +-
 .../http/client/fluent/ContentResponseHandler.java |    36 +-
 .../org/apache/http/client/fluent/Executor.java    |    39 +-
 .../client/fluent/InternalByteArrayEntity.java     |     5 +
 .../fluent/InternalEntityEnclosingHttpRequest.java |     3 +
 .../http/client/fluent/InternalFileEntity.java     |     5 +
 .../http/client/fluent/InternalHttpRequest.java    |    19 +-
 .../client/fluent/InternalInputStreamEntity.java   |     5 +
 .../org/apache/http/client/fluent/Request.java     |    48 +-
 .../org/apache/http/client/fluent/TestFluent.java  |    57 +-
 httpclient-cache/pom.xml                           |    35 +-
 .../http/impl/client/cache/CachingHttpClient.java  |    35 +-
 .../http/client/cache/CacheResponseStatus.java     |     2 +-
 .../apache/http/client/cache/HttpCacheEntry.java   |    88 +-
 .../http/client/cache/HttpCacheUpdateCallback.java |     4 +-
 .../cache/AsynchronousValidationRequest.java       |    11 +-
 .../impl/client/cache/AsynchronousValidator.java   |     1 +
 .../http/impl/client/cache/BasicHttpCache.java     |    26 +-
 .../impl/client/cache/BasicHttpCacheStorage.java   |     4 +
 .../http/impl/client/cache/BasicIdGenerator.java   |     2 +-
 .../apache/http/impl/client/cache/CacheConfig.java |     6 +-
 .../apache/http/impl/client/cache/CacheEntity.java |     9 +
 .../http/impl/client/cache/CacheEntryUpdater.java  |     3 +-
 .../http/impl/client/cache/CacheInvalidator.java   |    26 +-
 .../http/impl/client/cache/CacheKeyGenerator.java  |     2 +-
 .../impl/client/cache/CacheValidityPolicy.java     |     5 +-
 .../impl/client/cache/CacheableRequestPolicy.java  |     5 +-
 .../client/cache/CachedHttpResponseGenerator.java  |    16 +-
 .../cache/CachedResponseSuitabilityChecker.java    |    27 +-
 .../apache/http/impl/client/cache/CachingExec.java |    77 +-
 .../client/cache/CachingHttpClientBuilder.java     |    46 +-
 .../http/impl/client/cache/CombinedEntity.java     |     5 +
 .../impl/client/cache/DefaultFailureCache.java     |     3 +
 .../cache/DefaultHttpCacheEntrySerializer.java     |     2 +
 .../ExponentialBackOffSchedulingStrategy.java      |    28 +-
 .../http/impl/client/cache/FileResource.java       |     3 +
 .../impl/client/cache/FileResourceFactory.java     |     2 +
 .../http/impl/client/cache/HeapResource.java       |     3 +
 .../impl/client/cache/HeapResourceFactory.java     |     2 +
 .../apache/http/impl/client/cache/HttpCache.java   |     2 +-
 .../client/cache/ImmediateSchedulingStrategy.java  |     8 +-
 .../impl/client/cache/ManagedHttpCacheStorage.java |    34 +-
 .../impl/client/cache/OptionsHttp11Response.java   |    11 +
 .../impl/client/cache/ResponseCachingPolicy.java   |     8 +-
 .../impl/client/cache/ResponseProxyHandler.java    |     1 +
 .../http/impl/client/cache/SchedulingStrategy.java |     2 +-
 .../http/impl/client/cache/WarningValue.java       |    14 +-
 .../cache/ehcache/EhcacheHttpCacheStorage.java     |     4 +
 .../cache/memcached/MemcachedCacheEntry.java       |     9 +-
 .../memcached/MemcachedCacheEntryFactory.java      |     4 +-
 .../memcached/MemcachedCacheEntryFactoryImpl.java  |     2 +
 .../cache/memcached/MemcachedCacheEntryImpl.java   |     4 +
 .../cache/memcached/MemcachedHttpCacheStorage.java |    28 +-
 .../cache/memcached/PrefixKeyHashingScheme.java    |     3 +-
 .../cache/memcached/SHA256KeyHashingScheme.java    |     1 +
 .../http/client/cache/TestHttpCacheEntry.java      |    65 +-
 .../impl/client/cache/AbstractProtocolTest.java    |     4 +-
 .../http/impl/client/cache/DummyBackend.java       |     1 +
 .../http/impl/client/cache/HttpTestUtils.java      |    53 +-
 .../http/impl/client/cache/RequestEquivalent.java  |     2 +
 .../http/impl/client/cache/ResponseEquivalent.java |     2 +
 .../impl/client/cache/SimpleHttpCacheStorage.java  |     4 +
 .../cache/TestAsynchronousValidationRequest.java   |   135 +-
 .../client/cache/TestAsynchronousValidator.java    |   100 +-
 .../http/impl/client/cache/TestBasicHttpCache.java |    12 +
 .../impl/client/cache/TestCacheInvalidator.java    |   408 +-
 .../impl/client/cache/TestCacheKeyGenerator.java   |   120 +-
 .../impl/client/cache/TestCacheValidityPolicy.java |    36 +-
 .../client/cache/TestCacheableRequestPolicy.java   |    49 +-
 .../cache/TestCachedHttpResponseGenerator.java     |    79 +-
 .../TestCachedResponseSuitabilityChecker.java      |    88 +-
 .../http/impl/client/cache/TestCachingExec.java    |    38 +-
 .../impl/client/cache/TestCachingExecChain.java    |    15 +-
 .../http/impl/client/cache/TestCombinedEntity.java |    14 +-
 .../cache/TestConditionalRequestBuilder.java       |    36 +-
 ...estExponentialBackingOffSchedulingStrategy.java |    53 +-
 .../cache/TestHttpCacheEntrySerializers.java       |     6 +-
 .../client/cache/TestHttpCacheJiraNumber1147.java  |    51 +-
 .../cache/TestImmediateSchedulingStrategy.java     |    13 +-
 .../impl/client/cache/TestProtocolDeviations.java  |     8 +-
 .../client/cache/TestProtocolRequirements.java     |    15 +-
 .../impl/client/cache/TestRFC5861Compliance.java   |    13 +-
 .../cache/TestRequestProtocolCompliance.java       |     6 +-
 .../client/cache/TestResponseCachingPolicy.java    |   210 +
 .../cache/TestResponseProtocolCompliance.java      |     5 +-
 ...stStaleWhileRevalidationReleasesConnection.java |    41 +-
 .../cache/ehcache/TestEhcacheHttpCacheStorage.java |   121 +-
 .../ehcache/TestEhcacheProtocolRequirements.java   |     2 +-
 .../memcached/TestMemcachedCacheEntryImpl.java     |     4 +-
 .../memcached/TestMemcachedHttpCacheStorage.java   |   461 +-
 .../memcached/TestPrefixKeyHashingScheme.java      |     1 +
 .../cache/memcached/TestSHA256HashingScheme.java   |     2 +-
 httpclient-osgi/pom.xml                            |    14 +-
 .../osgi/impl/HttpProxyConfigurationActivator.java |     5 +
 .../http/osgi/impl/OSGiClientBuilderFactory.java   |     1 +
 .../http/osgi/impl/OSGiCredentialsProvider.java    |     3 +
 .../http/osgi/impl/OSGiHttpRoutePlanner.java       |     9 +-
 .../http/osgi/impl/OSGiProxyConfiguration.java     |    18 +-
 .../org/apache/http/osgi/impl/PropertiesUtils.java |    10 +-
 .../main/resources/OSGI-INF/metatype/metatype.xml  |     2 +-
 .../apache/http/osgi/impl/TestPropertiesUtils.java |    12 +-
 httpclient-win/pom.xml                             |    23 +-
 .../http/examples/client/win/ClientWinAuth.java    |    59 +-
 .../impl/auth/win/CurrentWindowsCredentials.java   |    32 +-
 .../impl/auth/win/WindowsCredentialsProvider.java  |    76 +
 .../impl/auth/win/WindowsNTLMSchemeFactory.java    |    15 +-
 .../http/impl/auth/win/WindowsNegotiateScheme.java |   136 +-
 .../auth/win/WindowsNegotiateSchemeFactory.java    |    15 +-
 .../apache/http/impl/auth/win/package-info.java    |     5 +-
 .../apache/http/impl/client/WinHttpClients.java    |   111 +
 .../impl/auth/win/TestWindowsNegotiateScheme.java  |   140 +
 httpclient/pom.xml                                 |    45 +-
 .../http/examples/client/ClientConfiguration.java  |    15 +-
 ...mSSL.java => ClientCustomPublicSuffixList.java} |    64 +-
 .../http/examples/client/ClientCustomSSL.java      |    22 +-
 .../client/ClientEvictExpiredConnections.java      |    55 +-
 .../http/examples/client/ClientExecuteSOCKS.java   |     4 +-
 .../ClientPreemptiveBasicAuthentication.java       |     2 +-
 .../ClientPreemptiveDigestAuthentication.java      |     3 +-
 .../examples/client/ClientWithRequestFuture.java   |     4 +
 .../examples/client/ClientWithResponseHandler.java |     1 +
 .../apache/http/client/AuthenticationHandler.java  |     4 +-
 .../org/apache/http/client/RedirectHandler.java    |     2 +-
 .../org/apache/http/client/RequestDirector.java    |     9 +-
 .../org/apache/http/client/params/AuthPolicy.java  |     2 +-
 .../client/protocol/RequestAuthenticationBase.java |     2 +-
 .../http/client/protocol/ResponseAuthCache.java    |     4 +-
 .../org/apache/http/client/utils/Idn.java          |     3 +
 .../org/apache/http/client/utils/JdkIdn.java       |     4 +
 .../org/apache/http/client/utils/Punycode.java     |     3 +
 .../org/apache/http/client/utils/Rfc3492Idn.java   |     8 +-
 .../apache/http/conn/ClientConnectionOperator.java |     2 +-
 .../http/conn/MultihomePlainSocketFactory.java     |     2 +-
 .../apache/http/conn/OperatedClientConnection.java |    24 +-
 .../apache/http/conn/params/ConnPerRouteBean.java  |     2 +-
 .../apache/http/conn/params/ConnRouteParams.java   |    22 +-
 .../http/conn/scheme/PlainSocketFactory.java       |     2 +-
 .../apache/http/conn/ssl/PrivateKeyDetails.java    |     3 +
 .../apache/http/conn/ssl/PrivateKeyStrategy.java   |     3 +
 .../apache/http/conn/ssl/SSLContextBuilder.java    |    18 +-
 .../org/apache/http/conn/ssl/SSLContexts.java      |    13 +-
 .../org/apache/http/conn/ssl/SSLSocketFactory.java |    28 +-
 .../org/apache/http/impl/auth/NegotiateScheme.java |    21 +-
 .../impl/client/AbstractAuthenticationHandler.java |     2 +-
 .../http/impl/client/AbstractHttpClient.java       |    52 +-
 .../impl/client/AuthenticationStrategyAdaptor.java |     2 +-
 .../apache/http/impl/client/ClientParamsStack.java |    43 +-
 .../impl/client/CloseableHttpResponseProxy.java    |    27 +-
 .../http/impl/client/DecompressingHttpClient.java  |    10 +-
 .../apache/http/impl/client/DefaultHttpClient.java |     8 +-
 .../http/impl/client/DefaultRequestDirector.java   |    20 +-
 .../http/impl/client/SystemDefaultHttpClient.java  |     2 +-
 .../http/impl/conn/AbstractClientConnAdapter.java  |     4 +-
 .../apache/http/impl/conn/AbstractPoolEntry.java   |    12 +-
 .../http/impl/conn/AbstractPooledConnAdapter.java  |     2 +-
 .../impl/conn/BasicClientConnectionManager.java    |    10 +-
 .../impl/conn/DefaultClientConnectionOperator.java |     2 +-
 .../http/impl/conn/LoggingSessionInputBuffer.java  |     2 +-
 .../http/impl/conn/LoggingSessionOutputBuffer.java |     2 +-
 .../http/impl/conn/ProxySelectorRoutePlanner.java  |    27 +-
 .../http/impl/conn/SingleClientConnManager.java    |     2 +-
 .../http/impl/conn/tsccm/AbstractConnPool.java     |    18 +-
 .../http/impl/conn/tsccm/BasicPoolEntry.java       |     2 +-
 .../http/impl/conn/tsccm/BasicPoolEntryRef.java    |     4 +-
 .../http/impl/conn/tsccm/ConnPoolByRoute.java      |    18 +-
 .../http/impl/conn/tsccm/PoolEntryRequest.java     |     4 +-
 .../http/impl/conn/tsccm/RouteSpecificPool.java    |    18 +-
 .../conn/tsccm/ThreadSafeClientConnManager.java    |     4 +-
 .../apache/http/impl/conn/tsccm/WaitingThread.java |    32 +-
 .../apache/http/impl/cookie/BestMatchSpec.java}    |    30 +-
 .../http/impl/cookie/BestMatchSpecFactory.java     |    19 +-
 .../apache/http/impl/cookie/BrowserCompatSpec.java |    91 +-
 .../http/impl/cookie/BrowserCompatSpecFactory.java |    17 +-
 .../BrowserCompatVersionAttributeHandler.java      |    14 +-
 .../org/apache/http/impl/cookie/DateUtils.java     |     8 +-
 .../apache/http/impl/cookie/IgnoreSpecFactory.java |     6 +-
 .../http/impl/cookie/NetscapeDraftSpecFactory.java |    17 +-
 .../http/impl/cookie/PublicSuffixFilter.java       |    57 +-
 .../http/impl/cookie/PublicSuffixListParser.java}  |    51 +-
 .../http/impl/cookie/RFC2109SpecFactory.java       |    19 +-
 .../http/impl/cookie/RFC2965SpecFactory.java       |    19 +-
 .../main/java/org/apache/http/auth/AuthScheme.java |     8 +-
 .../org/apache/http/auth/AuthSchemeRegistry.java   |     2 +
 .../main/java/org/apache/http/auth/AuthScope.java  |   140 +-
 .../main/java/org/apache/http/auth/AuthState.java  |     4 +-
 .../apache/http/auth/AuthenticationException.java  |     6 +-
 .../org/apache/http/auth/BasicUserPrincipal.java   |     1 +
 .../http/auth/InvalidCredentialsException.java     |     6 +-
 .../KerberosCredentials.java}                      |    44 +-
 .../http/auth/MalformedChallengeException.java     |     6 +-
 .../java/org/apache/http/auth/NTCredentials.java   |     6 +-
 .../java/org/apache/http/auth/NTUserPrincipal.java |     5 +-
 .../http/auth/UsernamePasswordCredentials.java     |     2 +
 .../apache/http/client/AuthenticationStrategy.java |     4 +-
 .../http/client/CircularRedirectException.java     |     6 +-
 .../http/client/ConnectionBackoffStrategy.java     |    12 +-
 .../java/org/apache/http/client/HttpClient.java    |    28 +-
 .../http/client/HttpRequestRetryHandler.java       |     2 +-
 .../http/client/NonRepeatableRequestException.java |     2 +-
 .../org/apache/http/client/RedirectException.java  |     6 +-
 .../org/apache/http/client/RedirectStrategy.java   |     2 +-
 .../client/ServiceUnavailableRetryStrategy.java    |     2 +-
 .../org/apache/http/client/UserTokenHandler.java   |     9 +-
 .../org/apache/http/client/config/AuthSchemes.java |    21 +-
 .../org/apache/http/client/config/CookieSpecs.java |    22 +-
 .../apache/http/client/config/RequestConfig.java   |   149 +-
 .../http/client/entity/DecompressingEntity.java    |    37 +-
 .../client/entity/DeflateDecompressingEntity.java  |    50 +-
 .../apache/http/client/entity/EntityBuilder.java   |     9 +-
 .../client/entity/GzipDecompressingEntity.java     |    31 +-
 .../entity/InputStreamFactory.java}                |    15 +-
 .../entity/LazyDecompressingInputStream.java       |    13 +-
 .../methods/AbstractExecutionAwareRequest.java     |     7 +
 .../methods/HttpEntityEnclosingRequestBase.java    |     3 +
 .../org/apache/http/client/methods/HttpGet.java    |     2 +-
 .../org/apache/http/client/methods/HttpHead.java   |     2 +-
 .../apache/http/client/methods/HttpOptions.java    |     2 +-
 .../org/apache/http/client/methods/HttpPatch.java  |     8 +-
 .../org/apache/http/client/methods/HttpPost.java   |     2 +-
 .../org/apache/http/client/methods/HttpPut.java    |     2 +-
 .../http/client/methods/HttpRequestBase.java       |    13 +-
 .../http/client/methods/HttpRequestWrapper.java    |    57 +-
 .../org/apache/http/client/methods/HttpTrace.java  |     2 +-
 .../apache/http/client/methods/HttpUriRequest.java |    13 +-
 .../apache/http/client/methods/RequestBuilder.java |   232 +-
 .../apache/http/client/params/AllClientPNames.java |     3 +-
 .../apache/http/client/params/ClientPNames.java    |     2 +-
 .../client/protocol/RequestAcceptEncoding.java     |    27 +-
 .../http/client/protocol/RequestAddCookies.java    |    39 +-
 .../http/client/protocol/RequestAuthCache.java     |     1 +
 .../client/protocol/RequestClientConnControl.java  |     7 +-
 .../client/protocol/RequestDefaultHeaders.java     |     1 +
 .../client/protocol/RequestExpectContinue.java     |     6 +-
 .../client/protocol/ResponseContentEncoding.java   |    94 +-
 .../client/protocol/ResponseProcessCookies.java    |     9 +-
 .../org/apache/http/client/utils/CloneUtils.java   |     2 +-
 .../org/apache/http/client/utils/DateUtils.java    |    12 +-
 .../org/apache/http/client/utils/URIBuilder.java   |    48 +-
 .../org/apache/http/client/utils/URIUtils.java     |    59 +-
 .../apache/http/client/utils/URLEncodedUtils.java  |   158 +-
 .../apache/http/conn/ClientConnectionManager.java  |     6 +-
 .../apache/http/conn/ClientConnectionRequest.java  |     4 +-
 .../apache/http/conn/ConnectTimeoutException.java  |     2 +-
 .../http/conn/ConnectionKeepAliveStrategy.java     |     2 +-
 .../http/conn/ConnectionPoolTimeoutException.java  |     2 +-
 .../org/apache/http/conn/ConnectionRequest.java    |     4 +-
 .../org/apache/http/conn/EofSensorInputStream.java |    15 +-
 .../org/apache/http/conn/EofSensorWatcher.java     |    21 +-
 .../http/conn/HttpClientConnectionManager.java     |    28 +-
 .../HttpClientConnectionOperator.java}             |    45 +-
 .../apache/http/conn/HttpHostConnectException.java |     2 +-
 .../org/apache/http/conn/HttpRoutedConnection.java |    11 +-
 .../apache/http/conn/ManagedClientConnection.java  |    35 +-
 .../http/conn/ManagedHttpClientConnection.java     |     2 +-
 .../http/conn/routing/BasicRouteDirector.java      |     3 +-
 .../org/apache/http/conn/routing/HttpRoute.java    |    84 +-
 .../http/conn/routing/HttpRouteDirector.java       |     2 +-
 .../apache/http/conn/routing/HttpRoutePlanner.java |     7 +-
 .../org/apache/http/conn/routing/RouteInfo.java    |    19 +-
 .../org/apache/http/conn/routing/RouteTracker.java |    40 +-
 .../conn/scheme/LayeredSocketFactoryAdaptor.java   |     1 +
 .../java/org/apache/http/conn/scheme/Scheme.java   |    11 +-
 .../scheme/SchemeLayeredSocketFactoryAdaptor.java  |     1 +
 .../scheme/SchemeLayeredSocketFactoryAdaptor2.java |     4 +
 .../apache/http/conn/scheme/SchemeRegistry.java    |    14 +-
 .../http/conn/scheme/SchemeSocketFactory.java      |    15 +-
 .../conn/scheme/SchemeSocketFactoryAdaptor.java    |     3 +
 .../org/apache/http/conn/scheme/SocketFactory.java |    15 +-
 .../http/conn/scheme/SocketFactoryAdaptor.java     |     3 +
 .../http/conn/socket/ConnectionSocketFactory.java  |     6 +-
 .../conn/socket/PlainConnectionSocketFactory.java  |     2 +
 .../org/apache/http/conn/ssl/AbstractVerifier.java |   315 +-
 .../http/conn/ssl/AllowAllHostnameVerifier.java    |     6 +
 .../conn/ssl/BrowserCompatHostnameVerifier.java    |    18 +-
 .../http/conn/ssl/DefaultHostnameVerifier.java     |   297 +
 ...nameVerifier.java => NoopHostnameVerifier.java} |    22 +-
 .../http/conn/ssl/SSLConnectionSocketFactory.java  |   253 +-
 .../http/conn/ssl/StrictHostnameVerifier.java      |    18 +-
 .../http/conn/ssl/TrustSelfSignedStrategy.java     |     3 +
 .../org/apache/http/conn/ssl/TrustStrategy.java    |    21 +-
 .../apache/http/conn/ssl/X509HostnameVerifier.java |     3 +
 .../apache/http/conn/util/InetAddressUtils.java    |     3 +-
 .../util/PublicSuffixList.java}                    |    39 +-
 .../util}/PublicSuffixListParser.java              |    53 +-
 .../apache/http/conn/util/PublicSuffixMatcher.java |   121 +
 .../http/conn/util/PublicSuffixMatcherLoader.java  |   104 +
 .../java/org/apache/http/cookie/ClientCookie.java  |    19 +-
 .../CommonCookieAttributeHandler.java}             |    14 +-
 .../main/java/org/apache/http/cookie/Cookie.java   |    31 +-
 .../apache/http/cookie/CookieAttributeHandler.java |     2 +-
 .../http/cookie/CookieIdentityComparator.java      |     1 +
 .../java/org/apache/http/cookie/CookieOrigin.java  |     5 +-
 .../apache/http/cookie/CookiePathComparator.java   |     5 +-
 ...mparator.java => CookiePriorityComparator.java} |    59 +-
 .../CookieRestrictionViolationException.java       |     2 +-
 .../java/org/apache/http/cookie/CookieSpec.java    |    23 +-
 .../org/apache/http/cookie/CookieSpecRegistry.java |     2 +
 .../http/cookie/MalformedCookieException.java      |     6 +-
 .../java/org/apache/http/cookie/SetCookie.java     |    11 +-
 .../java/org/apache/http/cookie/SetCookie2.java    |    12 +-
 .../http/cookie/params/CookieSpecPNames.java       |    10 +-
 .../org/apache/http/impl/auth/AuthSchemeBase.java  |    10 +-
 .../org/apache/http/impl/auth/BasicScheme.java     |    31 +-
 .../apache/http/impl/auth/BasicSchemeFactory.java  |     2 +
 .../org/apache/http/impl/auth/DigestScheme.java    |    28 +-
 .../apache/http/impl/auth/DigestSchemeFactory.java |     2 +
 .../org/apache/http/impl/auth/GGSSchemeBase.java   |    92 +-
 .../apache/http/impl/auth/HttpAuthenticator.java   |     4 +-
 .../org/apache/http/impl/auth/KerberosScheme.java  |    34 +-
 .../http/impl/auth/KerberosSchemeFactory.java      |    23 +-
 .../java/org/apache/http/impl/auth/NTLMEngine.java |     4 +-
 .../apache/http/impl/auth/NTLMEngineException.java |     4 +-
 .../org/apache/http/impl/auth/NTLMEngineImpl.java  |   185 +-
 .../java/org/apache/http/impl/auth/NTLMScheme.java |     8 +-
 .../apache/http/impl/auth/NTLMSchemeFactory.java   |     2 +
 .../org/apache/http/impl/auth/RFC2617Scheme.java   |    42 +-
 .../org/apache/http/impl/auth/SPNegoScheme.java    |    34 +-
 .../apache/http/impl/auth/SPNegoSchemeFactory.java |    23 +-
 .../auth/UnsupportedDigestAlgorithmException.java  |     6 +-
 .../http/impl/client/AIMDBackoffManager.java       |    10 +-
 ...seHandler.java => AbstractResponseHandler.java} |    30 +-
 .../impl/client/AuthenticationStrategyImpl.java    |    21 +-
 .../apache/http/impl/client/BasicAuthCache.java    |    78 +-
 .../apache/http/impl/client/BasicCookieStore.java  |     4 +
 .../http/impl/client/BasicCredentialsProvider.java |     3 +
 .../http/impl/client/BasicResponseHandler.java     |    39 +-
 .../http/impl/client/CloseableHttpClient.java      |    48 +-
 .../http/impl/client/DefaultBackoffStrategy.java   |     2 +
 .../client/DefaultConnectionKeepAliveStrategy.java |     1 +
 .../client/DefaultHttpRequestRetryHandler.java     |     9 +-
 .../http/impl/client/DefaultRedirectStrategy.java  |    11 +-
 .../DefaultServiceUnavailableRetryStrategy.java    |     4 +-
 .../http/impl/client/DefaultUserTokenHandler.java  |     3 +-
 .../impl/client/EntityEnclosingRequestWrapper.java |     6 +-
 .../impl/client/FutureRequestExecutionService.java |     3 +-
 .../apache/http/impl/client/HttpClientBuilder.java |   548 +-
 .../http/impl/client/HttpRequestTaskCallable.java  |     1 +
 .../http/impl/client/IdleConnectionEvictor.java    |   123 +
 .../http/impl/client/InternalHttpClient.java       |    19 +-
 .../apache/http/impl/client/MinimalHttpClient.java |     9 +
 .../http/impl/client/NoopUserTokenHandler.java     |     3 +-
 .../http/impl/client/NullBackoffStrategy.java      |     2 +
 .../apache/http/impl/client/RedirectLocations.java |    26 +-
 .../apache/http/impl/client/RequestWrapper.java    |    14 +-
 .../client/StandardHttpRequestRetryHandler.java    |     5 +-
 .../org/apache/http/impl/client/SystemClock.java   |     1 +
 .../client/SystemDefaultCredentialsProvider.java   |    18 +-
 .../org/apache/http/impl/client/package-info.java  |     3 +-
 .../conn/BasicHttpClientConnectionManager.java     |    41 +-
 .../main/java/org/apache/http/impl/conn/CPool.java |     5 +
 .../java/org/apache/http/impl/conn/CPoolProxy.java |    24 +
 .../impl/conn/ConnectionShutdownException.java     |     2 +-
 ...va => DefaultHttpClientConnectionOperator.java} |    24 +-
 .../http/impl/conn/DefaultHttpResponseParser.java  |     8 +-
 .../conn/DefaultHttpResponseParserFactory.java     |     1 +
 .../conn/DefaultManagedHttpClientConnection.java   |     5 +
 .../apache/http/impl/conn/DefaultRoutePlanner.java |     6 +
 .../http/impl/conn/DefaultSchemePortResolver.java  |     1 +
 .../apache/http/impl/conn/InMemoryDnsResolver.java |     1 +
 .../conn/ManagedHttpClientConnectionFactory.java   |    31 +-
 .../conn/PoolingHttpClientConnectionManager.java   |   100 +-
 .../http/impl/conn/SystemDefaultDnsResolver.java   |     1 +
 .../cookie/AbstractCookieAttributeHandler.java     |     2 +
 .../http/impl/cookie/AbstractCookieSpec.java       |    48 +-
 .../apache/http/impl/cookie/BasicClientCookie.java |    68 +-
 .../http/impl/cookie/BasicClientCookie2.java       |     3 +
 .../http/impl/cookie/BasicCommentHandler.java      |    10 +-
 .../http/impl/cookie/BasicDomainHandler.java       |    85 +-
 .../http/impl/cookie/BasicExpiresHandler.java      |    14 +-
 .../http/impl/cookie/BasicMaxAgeHandler.java       |    16 +-
 .../apache/http/impl/cookie/BasicPathHandler.java  |    53 +-
 .../http/impl/cookie/BasicSecureHandler.java       |    10 +-
 .../apache/http/impl/cookie/CookieSpecBase.java    |    31 +-
 .../{BestMatchSpec.java => DefaultCookieSpec.java} |   120 +-
 .../impl/cookie/DefaultCookieSpecProvider.java     |   134 +
 .../org/apache/http/impl/cookie/IgnoreSpec.java    |     8 +-
 ...oreSpecFactory.java => IgnoreSpecProvider.java} |    27 +-
 .../apache/http/impl/cookie/LaxExpiresHandler.java |   220 +
 ...sicMaxAgeHandler.java => LaxMaxAgeHandler.java} |    48 +-
 .../http/impl/cookie/NetscapeDomainHandler.java    |    25 +-
 .../impl/cookie/NetscapeDraftHeaderParser.java     |    78 +-
 .../apache/http/impl/cookie/NetscapeDraftSpec.java |    51 +-
 ...Factory.java => NetscapeDraftSpecProvider.java} |    50 +-
 .../http/impl/cookie/PublicSuffixDomainFilter.java |   104 +
 .../http/impl/cookie/RFC2109DomainHandler.java     |    17 +-
 .../org/apache/http/impl/cookie/RFC2109Spec.java   |    57 +-
 ...65SpecFactory.java => RFC2109SpecProvider.java} |    69 +-
 .../http/impl/cookie/RFC2109VersionHandler.java    |    12 +-
 .../cookie/RFC2965CommentUrlAttributeHandler.java  |    17 +-
 .../cookie/RFC2965DiscardAttributeHandler.java     |    17 +-
 .../impl/cookie/RFC2965DomainAttributeHandler.java |    31 +-
 .../impl/cookie/RFC2965PortAttributeHandler.java   |    22 +-
 .../org/apache/http/impl/cookie/RFC2965Spec.java   |    41 +-
 .../http/impl/cookie/RFC2965SpecProvider.java      |    92 +
 .../cookie/RFC2965VersionAttributeHandler.java     |    14 +-
 .../http/impl/cookie/RFC6265CookieSpecBase.java    |   276 +
 .../impl/cookie/RFC6265CookieSpecProvider.java     |   122 +
 ...BasicSecureHandler.java => RFC6265LaxSpec.java} |    39 +-
 .../apache/http/impl/cookie/RFC6265StrictSpec.java |    58 +-
 .../http/impl/execchain/BackoffStrategyExec.java   |     1 +
 .../http/impl/execchain/ClientExecChain.java       |     3 +-
 .../http/impl/execchain/ConnectionHolder.java      |     4 +
 .../http/impl/execchain/HttpResponseProxy.java     |    28 +
 .../apache/http/impl/execchain/MainClientExec.java |    25 +-
 .../http/impl/execchain/MinimalClientExec.java     |     1 +
 .../apache/http/impl/execchain/ProtocolExec.java   |    35 +-
 .../apache/http/impl/execchain/RedirectExec.java   |     4 +-
 .../http/impl/execchain/RequestEntityProxy.java    |     9 +
 .../http/impl/execchain/ResponseEntityProxy.java   |     3 +
 .../org/apache/http/impl/execchain/RetryExec.java  |     4 +-
 .../execchain/ServiceUnavailableRetryExec.java     |     4 +-
 .../main/resources/mozilla/public-suffix-list.txt  | 10309 +++++++++++++++++++
 .../java/org/apache/http/auth/TestAuthScope.java   |   185 +
 .../http/client/config/TestRequestConfig.java      |    11 +-
 .../client/entity/TestDecompressingEntity.java     |    18 +-
 .../http/client/entity/TestEntityBuilder.java      |     1 +
 .../http/client/methods/TestRequestBuilder.java    |    43 +
 .../client/protocol/TestRequestAddCookies.java     |    74 +-
 .../http/client/protocol/TestRequestAuthCache.java |     4 +-
 .../protocol/TestResponseContentEncoding.java      |    30 +-
 .../protocol/TestResponseProcessCookies.java       |     4 +-
 .../apache/http/client/utils/TestDateUtils.java    |     6 -
 .../http/client/utils/TestHttpClientUtils.java     |     2 +-
 .../http/client/utils/TestRequestBuilder.java      |    74 +
 .../apache/http/client/utils/TestRfc3492Idn.java   |    79 -
 .../apache/http/client/utils/TestURIBuilder.java   |    62 +-
 .../org/apache/http/client/utils/TestURIUtils.java |    31 +
 .../http/client/utils/TestURLEncodedUtils.java     |     2 +-
 .../java/org/apache/http/conn/TestExceptions.java  |     2 +-
 .../apache/http/conn/routing/TestHttpRoute.java    |    58 +-
 .../http/conn/routing/TestRouteDirector.java       |     4 +-
 .../apache/http/conn/routing/TestRouteTracker.java |    18 +-
 .../http/conn/ssl/CertificatesToPlayWith.java      |     3 +-
 .../http/conn/ssl/TestDefaultHostnameVerifier.java |   300 +
 .../apache/http/conn/ssl/TestHostnameVerifier.java |    70 +-
 .../http/conn/ssl/TestSSLContextBuilder.java       |   100 -
 .../apache/http/conn/ssl/TestSSLSocketFactory.java |   340 +-
 .../http/conn/util/TestInetAddressUtils.java       |     3 +
 .../http/conn/util/TestPublicSuffixListParser.java |    72 +-
 .../http/conn/util/TestPublicSuffixMatcher.java    |    92 +
 .../org/apache/http/cookie/TestCookieOrigin.java   |     4 +
 .../http/cookie/TestCookiePriorityComparator.java  |   113 +
 .../org/apache/http/impl/auth/TestBasicScheme.java |    32 +-
 .../apache/http/impl/auth/TestDigestScheme.java    |    27 +
 .../http/impl/auth/TestHttpAuthenticator.java      |    56 +-
 .../apache/http/impl/auth/TestNTLMEngineImpl.java  |     3 +-
 .../apache/http/impl/auth/TestRFC2617Scheme.java   |    51 +-
 .../org/apache/http/impl/client/MockClock.java     |     1 +
 .../http/impl/client/MockConnPoolControl.java      |     8 +
 .../http/impl/client/TestAIMDBackoffManager.java   |     2 +-
 ...ndler.java => TestAbstractResponseHandler.java} |    18 +-
 .../impl/client/TestAuthenticationStrategy.java    |     2 +-
 .../http/impl/client/TestBasicAuthCache.java       |    31 +-
 .../impl/client/TestBasicCredentialsProvider.java  |    41 +-
 .../http/impl/client/TestBasicResponseHandler.java |     2 +-
 .../http/impl/client/TestCloseableHttpClient.java  |     5 +-
 .../client/TestFutureRequestExecutionService.java  |    25 +-
 .../impl/client/TestIdleConnectionEvictor.java     |    80 +
 .../http/impl/client/TestInternalHttpClient.java   |     8 +-
 .../client/integration/IntegrationTestBase.java    |    44 -
 .../impl/client/integration/TestAbortHandling.java |    90 +-
 .../integration/TestBasicConnectionManager.java    |    38 +-
 .../integration/TestClientAuthentication.java      |   316 +-
 .../TestClientAuthenticationFakeNTLM.java          |    76 +-
 .../TestClientAuthenticationFallBack.java          |    31 +-
 .../integration/TestClientReauthentication.java    |    29 +-
 .../integration/TestClientRequestExecution.java    |    57 +-
 .../integration/TestConnectionAutoRelease.java     |    92 +-
 .../integration/TestConnectionManagement.java      |   257 +-
 .../client/integration/TestConnectionReuse.java    |   131 +-
 .../client/integration/TestContentCodings.java     |   113 +-
 .../client/integration/TestCookie2Support.java     |   237 -
 .../client/integration/TestCookieVirtualHost.java  |    54 +-
 .../integration/TestIdleConnectionEviction.java    |    62 +-
 .../integration/TestMalformedServerResponse.java   |   132 +
 .../TestMinimalClientRequestExecution.java         |    18 +-
 .../impl/client/integration/TestRedirects.java     |   141 +-
 .../impl/client/integration/TestSPNegoScheme.java  |    25 +-
 .../integration/TestStatefulConnManagement.java    |    52 +-
 .../http/impl/conn/SessionInputBufferMock.java     |     5 +-
 .../conn/TestBasicHttpClientConnectionManager.java |    24 +-
 .../conn/TestHttpClientConnectionOperator.java     |    36 +-
 .../TestPoolingHttpClientConnectionManager.java    |    32 +-
 .../impl/conn/TestSystemDefaultRoutePlanner.java   |     5 +-
 .../http/impl/cookie/TestAbstractCookieSpec.java   |   134 -
 .../http/impl/cookie/TestBasicClientCookie.java    |     1 +
 .../http/impl/cookie/TestBasicClientCookie2.java   |     1 +
 .../impl/cookie/TestBasicCookieAttribHandlers.java |    43 +-
 .../http/impl/cookie/TestBrowserCompatSpec.java    |  1072 --
 .../http/impl/cookie/TestCookieNetscapeDraft.java  |    19 +
 .../http/impl/cookie/TestCookieRFC2109Spec.java    |     5 +-
 .../http/impl/cookie/TestCookieRFC2965Spec.java    |    50 +-
 ...stMatchSpec.java => TestDefaultCookieSpec.java} |    40 +-
 .../impl/cookie/TestLaxCookieAttribHandlers.java   |   317 +
 .../impl/cookie/TestPublicSuffixListParser.java    |    42 +-
 .../impl/cookie/TestRFC6265CookieSpecBase.java     |   337 +
 .../http/impl/execchain/TestConnectionHolder.java  |     1 +
 .../http/impl/execchain/TestMainClientExec.java    |    42 +-
 .../http/impl/execchain/TestMinimalClientExec.java |     7 +-
 .../http/impl/execchain/TestProtocolExec.java      |     6 +-
 .../http/impl/execchain/TestRedirectExec.java      |     4 +-
 .../impl/execchain/TestResponseEntityWrapper.java  |     2 +-
 .../apache/http/impl/execchain/TestRetryExec.java  |     8 +-
 .../org/apache/http/localserver/EchoHandler.java   |     3 +-
 .../http/localserver/LocalServerTestBase.java      |    89 +-
 .../apache/http/localserver/LocalTestServer.java   |   423 -
 .../org/apache/http/localserver/RandomHandler.java |    38 +-
 .../apache/http/localserver/RequestBasicAuth.java  |     1 +
 .../localserver/ResponseBasicUnauthorized.java     |     5 +-
 ...{RequestBasicAuth.java => SSLTestContexts.java} |    30 +-
 httpclient/src/test/resources/hc-test-1.truststore |   Bin 870 -> 0 bytes
 httpclient/src/test/resources/hc-test-2.truststore |   Bin 868 -> 0 bytes
 httpclient/src/test/resources/hc-test.keystore     |   Bin 2529 -> 0 bytes
 .../src/test/resources/test-keypasswd.keystore     |   Bin 1378 -> 0 bytes
 httpclient/src/test/resources/test.keystore        |   Bin 0 -> 1344 bytes
 httpmime/pom.xml                                   |    12 +-
 .../org/apache/http/entity/mime/HttpMultipart.java |    17 +-
 .../http/entity/mime/AbstractMultipartForm.java    |    37 +-
 .../org/apache/http/entity/mime/FormBodyPart.java  |    26 +-
 .../http/entity/mime/FormBodyPartBuilder.java      |   141 +
 .../java/org/apache/http/entity/mime/Header.java   |    11 +-
 .../mime/HttpBrowserCompatibleMultipart.java       |     3 +-
 .../http/entity/mime/HttpRFC6532Multipart.java     |     3 +-
 .../http/entity/mime/HttpStrictMultipart.java      |     3 +-
 .../http/entity/mime/MultipartEntityBuilder.java   |    80 +-
 .../http/entity/mime/MultipartFormEntity.java      |    14 +-
 .../entity/mime/content/AbstractContentBody.java   |     4 +
 .../http/entity/mime/content/ByteArrayBody.java    |     4 +
 .../entity/mime/content/ContentDescriptor.java     |    12 +-
 .../apache/http/entity/mime/content/FileBody.java  |     6 +-
 .../http/entity/mime/content/InputStreamBody.java  |     4 +
 .../http/entity/mime/content/StringBody.java       |    13 +-
 .../http/entity/mime/TestFormBodyPartBuilder.java  |   175 +
 .../http/entity/mime/TestMultipartContentBody.java |     7 +-
 .../entity/mime/TestMultipartEntityBuilder.java    |    59 +-
 .../apache/http/entity/mime/TestMultipartForm.java |    97 +-
 pom.xml                                            |   117 +-
 src/docbkx/connmgmt.xml                            |    76 +-
 src/docbkx/fundamentals.xml                        |   125 +-
 src/docbkx/preface.xml                             |     2 +-
 src/docbkx/statemgmt.xml                           |   166 +-
 550 files changed, 23712 insertions(+), 7735 deletions(-)

diff --git a/BUILDING.txt b/BUILDING.txt
index 9da4179..0539ea4 100644
--- a/BUILDING.txt
+++ b/BUILDING.txt
@@ -3,7 +3,7 @@ Building HttpComponents Client
 
 (1) Requisites
 --------------
-JDK 1.5+ is required in order to compile and run HttpClient.
+JDK 1.6+ is required in order to compile and run HttpClient.
 
 HttpClient utilizes Maven as a distribution management and packaging tool.
 Version 3.0.3 or later is required. 
@@ -16,9 +16,7 @@ http://maven.apache.org/run-maven/index.html
 
 Execute the following command in order to compile and test the components
 
-mvn package test
-
-Note that "mvn test" does not work in multi-module tests unless "mvn install" has been run.
+mvn test
 
 (3) Building packages 
 
@@ -33,11 +31,22 @@ httpclient/target/httpclient-<VERSION>.jar
 httpmime/target/httpmime-<VERSION>.jar
 httpclient-cache/target/httpclient-cache-<VERSION>.jar
 fluent-hc/target/fluent-hc-<VERSION>.jar
+httpclient-win/target/httpclient-win-<VERSION>.jar
 httpclient-osgi/target/org.apache.httpcomponents.httpclient_<VERSION>.jar
 
 where <VERSION> is the release version
 
-(4) Building documentation 
+(4) Validating packages
+
+Check for binary compatibility with the previous version with:
+
+mvn clirr:check
+
+Check for proper license headers with:
+
+mvn apache-rat:check
+
+(5) Building documentation 
 
 Execute the following command in order to generate javadoc:
 
diff --git a/LICENSE.txt b/LICENSE.txt
index d9a10c0..32f01ed 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -174,3 +174,385 @@
       of your accepting any such warranty or additional liability.
 
    END OF TERMS AND CONDITIONS
+
+=========================================================================
+
+This project includes Public Suffix List copied from
+<https://publicsuffix.org/list/effective_tld_names.dat>
+licensed under the terms of the Mozilla Public License, v. 2.0
+
+Full license text: <http://mozilla.org/MPL/2.0/>
+
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
diff --git a/NOTICE.txt b/NOTICE.txt
index 6ce1939..6a8629b 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,5 +1,5 @@
 Apache HttpComponents Client
-Copyright 1999-2014 The Apache Software Foundation
+Copyright 1999-2015 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.txt b/README.txt
index b4b201c..eb7212a 100644
--- a/README.txt
+++ b/README.txt
@@ -11,7 +11,7 @@ For building from source instructions please refer to BUILDING.txt.
 Dependencies
 ------------
 
-HttpClient main module requires Java 5.0 compatible runtime and
+HttpClient main module requires Java 6 compatible runtime and
 depends on the following external libraries:
 
 * Apache HttpComponents HttpCore
@@ -20,7 +20,7 @@ depends on the following external libraries:
 
 (for detailed information on external dependencies please see pom.xml)
 
-HttpMime module is optional and requires Java 5.0 compatible runtime
+HttpMime module is optional and requires Java 6 compatible runtime
 and depends on the following external libraries:
 
 * Apache HttpComponents HttpCore
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 7a30a72..493870e 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -1,18 +1,223 @@
-Release 4.3.5
+Release 4.4.1
 -------------------
 
-HttpClient 4.3.5 (GA) is a bug fix release that addresses several of issues reported since 
-release 4.3.4.
+HttpClient 4.4.1 (GA) is a maintenance release that fixes a number of defects in new functionality
+introduced in version 4.4.
+
+Users of HttpClient 4.4 are encouraged to upgrade.
+
+Please note that as of 4.4 HttpClient requires Java 1.6 or newer.
+
+Changelog:
+-------------------
+
+* Marked RFC 2109, RFC 2965, Netscape draft cookie specs as obsolete
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1633] RFC6265CookieSpecProvider compatibility level setting has no effect.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1628]: Auth cache can fail when domain name contains uppercase characters.
+  Contributed by Dennis Ju <dejuknow at gmail.com>
+
+* [HTTPCLIENT-1609] Stale connection check in PoolingHttpClientConnectionManager has no effect.
+  Internal connection pool does not correctly implement connection validation.
+  Contributed by Charles Lip <rene1 at singnet.com.sg>
+
+
+
+Release 4.4 Final
+-------------------
+
+This is the first stable (GA) release of HttpClient 4.4. Notable features and enhancements included
+in 4.4 series are:
+
+* Support for the latest HTTP state management specification (RFC 6265). Please note that the old 
+cookie policy is still used by default for compatibility reasons. RFC 6265 compliant cookie 
+policies need to be explicitly configured by the user. Please also note that as of next feature 
+release support for Netscape draft, RFC 2109 and RFC 2965 cookie policies will be deprecated 
+and disabled by default. It is recommended to use RFC 6265 compliant policies for new applications 
+unless compatibility with RFC 2109 and RFC 2965 is required and to migrate existing applications 
+to the default cookie policy.
+
+* Enhanced, redesigned and rewritten default SSL hostname verifier with improved RFC 2818
+compliance
+
+* Default SSL hostname verifier and default cookie policy now validate certificate identity 
+and cookie domain of origin against the public suffix list maintained by Mozilla.org
+<https://publicsuffix.org/list>
+
+* More efficient stale connection checking: indiscriminate connection checking which results
+in approximately 20 to 50 ms overhead per request has been deprecated in favor of conditional
+connection state validation (persistent connections are to be re-validated only if a specified
+period inactivity has elapsed)
+
+* Authentication cache thread-safety: authentication cache used by HttpClient is now thread-safe
+and can be shared by multiple threads in order to re-use authentication state for subsequent
+requests
+
+* Native Windows Negotiate and NTLM via SSPI through JNA: when running on Windows OS HttpClient
+configured to use native NTLM or SPNEGO authentication schemes can make use of platform specific
+functionality via JNA and current user credentials. This functionality is still considered
+experimental, known to have compatibility issues and subject to change without prior notice.
+Use at your discretion.
+
+This release also includes all fixes from the stable 4.3.x release branch.
+
+Please note that as of 4.4 HttpClient requires Java 1.6 or newer.
 
-Users of all HttpClient versions are advised to upgrade.
 
 Changelog:
 -------------------
 
-* Improved SSL cert subject parsing
+* Support for the latest HTTP state management specification (RFC 6265).
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1515] Caching of responses to HEAD requests
+  Contributed by Tyrone Cutajar <tj.cutajar at gmail.com> and 
+  Francois-Xavier Bonnet <fx at apache.org> 
+
+* [HTTPCLIENT-1560] Native Windows auth improvements
+  Contributed by Michael Osipov <michaelo at apache.org>
+
+* Update Apache Commons Logging version from 1.1.3 to 1.2. 
+  Contributed by Gary Gregory <ggregory at apache.org>
+
+* Update Apache Commons Codec version from 1.6 to 1.9. 
+  Contributed by Gary Gregory <ggregory at apache.org>
+
+* Update Ehcache version from 2.2.0 to 2.6.9. 
+  Contributed by Gary Gregory <ggregory at apache.org>
+
+* Update Ehcache version from 2.2.0 to 2.6.9. 
+  Contributed by Gary Gregory <ggregory at apache.org>
+
+* Update Spymemcached version from 2.6 to 2.11.4. 
+  Contributed by Gary Gregory <ggregory at apache.org>
+
+* Update SLF4J version from 1.5.11 to 1.7.7. 
+  Contributed by Gary Gregory <ggregory at apache.org>
+
+
+
+
+
+Release 4.4 BETA1
+-------------------
+
+This is the first BETA release of HttpClient 4.4. Notable features and enhancements included
+in 4.4 series are:
 
-* [HTTPCLIENT-1524] RFC 2617 auth schemes (basic and digest) cannot handle auth parameters with 
-  mixed or upper case
+* Enhanced redesigned and rewritten default SSL hostname verifier with improved RFC 2818
+compliance
+
+* Default SSL hostname verifier and default cookie policy now validate certificate identity 
+and cookie domain of origin against the public suffix list maintained by Mozilla.org
+<https://publicsuffix.org/list>
+
+* Native windows Negotiate/NTLM via JNA: when running on Windows OS HttpClient configured to use
+native NTLM or SPNEGO authentication schemes can make use of platform specific functionality
+via JNA and current user system credentials
+
+* More efficient stale connection checking: indiscriminate connection checking which results
+in approximately 20 to 50 ms overhead per request has been deprecated in favor of conditional
+connection state validation (persistent connections are to be re-validated only if a specified
+period inactivity has elapsed)
+
+* Authentication cache thread-safety: authentication caches used by HttpClient is now thread-safe
+and can be shared by multiple threads in order to re-use authentication state for subsequent
+requests
+
+This release also includes all fixes from the stable 4.3.x release branch.
+
+Please note that as of 4.4 HttpClient requires Java 1.6 or newer.
+
+
+Changelog:
+-------------------
+
+* [HTTPCLIENT-1547] HttpClient OSGi bundle doesn't import the package "javax.naming".
+  Contributed by Willem Jiang <ningjiang at apache.org>
+
+* [HTTPCLIENT-1541] Use correct (HTTP/hostname) service principle name for Windows native
+  Negotiate/NTLM auth schemes.
+  Contributed by Ka-Lok Fung <ka-lok.fung at sap.com>
+
+* Improved compliance with RFC 2818: default hostname verifier to ignore the common name of the
+  certificate subject if alternative subject names (dNSName or iPAddress) are present.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1540] Support delegated credentials (ISC_REQ_DELEGATE) by Native windows
+  native Negotiate/NTLM auth schemes.
+  Contributed by Ka-Lok Fung <ka-lok.fung at sap.com>
+
+
+
+Release 4.4 ALPHA1
+-------------------
+
+This is the first ALPHA release of HttpClient 4.4. Notable features and enhancements included
+in the 4.4 branch are:
+
+* More efficient stale connection checking: indiscriminate connection checking which results
+in approximately 20 to 50 ms overhead per request has been deprecated in favor of conditional
+connection state validation (persistent connections are to be re-validated only if a specified
+period inactivity has elapsed)
+
+* Native windows Negotiate/NTLM via JNA: when running on Windows OS HttpClient configured to use
+native NTLM or SPNEGO authentication schemes can make use of platform specific functionality
+via JNA and current user system credentials
+
+* Authentication cache thread-safety: authentication caches used by HttpClient is now thread-safe
+and can be shared by multiple threads in order to re-use authentication state for subsequent
+requests
+
+This release also includes all fixes from the stable 4.3.x release branch.
+
+Please note that as of 4.4 HttpClient requires Java 1.6 or newer.
+
+Please note that new features included in this release are still considered experimental and
+their API may change in the future 4.4 alpha and beta releases.
+
+
+Changelog:
+-------------------
+
+* [HTTPCLIENT-1493] Indiscriminate connection checking has been deprecated in favor of conditional
+  connection state validation. Persistent connections are to be re-validated only after a defined
+  period inactivity prior to being leased to the consumer.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1519] Use the original HttpHost instance passed as a parameter to
+  HttpClient#execute when generating 'Host' request header.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1491] Enable provision of Service Principal Name in Windows native
+  auth scheme.
+  Contributed by Malcolm Smith <malcolmfsmith at gmail.com>
+
+* [HTTPCLIENT-1403] Pluggable content decoders.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1466] FileBodyPart#generateContentType() ignores custom ContentType values.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1461] fixed performance degradation in gzip encoded content processing
+  introduced by HTTPCLIENT-1432.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1457] Incorrect handling of Windows (NT) credentials by
+  SystemDefaultCredentialsProvider.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1456] Request retrial after status 503 causes ClientProtocolException.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* [HTTPCLIENT-1454] Make connection operator APIs public.
+  Contributed by Tamas Cservenak <tamas at cservenak.net>
+
+* Update JUnit to version 4.11 from 4.9  
+  Contributed by Gary Gregory <ggregory at apache.org>
 
 
 
@@ -42,6 +247,8 @@ Changelog:
   throws NPE if config is null
 
 
+
+
 Release 4.3.3
 -------------------
 
@@ -72,7 +279,6 @@ Changelog:
   Contributed by Oleg Kalnichevski <olegk at apache.org>
 
 
-
 Release 4.3.2
 -------------------
 
diff --git a/fluent-hc/pom.xml b/fluent-hc/pom.xml
index 91be697..c2b875a 100644
--- a/fluent-hc/pom.xml
+++ b/fluent-hc/pom.xml
@@ -28,13 +28,13 @@
   <parent>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpcomponents-client</artifactId>
-    <version>4.3.5</version>
+    <version>4.4.1</version>
   </parent>
   <artifactId>fluent-hc</artifactId>
-  <name>Fluent API for Apache HttpClient</name>
+  <name>Apache HttpClient Fluent API</name>
   <inceptionYear>2011</inceptionYear>
   <description>
-   HttpComponents Client fluent API
+   Apache HttpComponents Client fluent API
   </description>
   <url>http://hc.apache.org/httpcomponents-client</url>
   <packaging>jar</packaging>
@@ -94,7 +94,7 @@
           <quiet>true</quiet>
           <source>${maven.compiler.source}</source>
           <links>
-            <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
+            <link>http://docs.oracle.com/javase/6/docs/api/</link>
             <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
             <link>http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/</link>
           </links>
diff --git a/fluent-hc/src/examples/org/apache/http/client/fluent/FluentAsync.java b/fluent-hc/src/examples/org/apache/http/client/fluent/FluentAsync.java
index 36b33b0..4cc97dc 100644
--- a/fluent-hc/src/examples/org/apache/http/client/fluent/FluentAsync.java
+++ b/fluent-hc/src/examples/org/apache/http/client/fluent/FluentAsync.java
@@ -59,14 +59,17 @@ public class FluentAsync {
         for (final Request request: requests) {
             Future<Content> future = async.execute(request, new FutureCallback<Content>() {
 
+                @Override
                 public void failed(final Exception ex) {
                     System.out.println(ex.getMessage() + ": " + request);
                 }
 
+                @Override
                 public void completed(final Content content) {
                     System.out.println("Request completed: " + request);
                 }
 
+                @Override
                 public void cancelled() {
                 }
 
diff --git a/fluent-hc/src/examples/org/apache/http/client/fluent/FluentResponseHandling.java b/fluent-hc/src/examples/org/apache/http/client/fluent/FluentResponseHandling.java
index 602fb87..8632e09 100644
--- a/fluent-hc/src/examples/org/apache/http/client/fluent/FluentResponseHandling.java
+++ b/fluent-hc/src/examples/org/apache/http/client/fluent/FluentResponseHandling.java
@@ -54,6 +54,7 @@ public class FluentResponseHandling {
         Document result = Request.Get("http://somehost/content")
                 .execute().handleResponse(new ResponseHandler<Document>() {
 
+            @Override
             public Document handleResponse(final HttpResponse response) throws IOException {
                 StatusLine statusLine = response.getStatusLine();
                 HttpEntity entity = response.getEntity();
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/Async.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/Async.java
index 99a721e..20e8af9 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/Async.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/Async.java
@@ -74,6 +74,7 @@ public class Async {
             this.handler = handler;
         }
 
+        @Override
         public void run() {
             try {
                 final Response response = this.executor.execute(this.request);
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/Content.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/Content.java
index d69b181..2be4c3f 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/Content.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/Content.java
@@ -28,12 +28,15 @@ package org.apache.http.client.fluent;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 
 import org.apache.http.Consts;
 import org.apache.http.entity.ContentType;
 
+/**
+ * This class represents arbitrary content of a specfic type that can be consumed
+ * multiple times and requires no explicit deallocation.
+ */
 public class Content {
 
     public static final Content NO_CONTENT = new Content(new byte[] {}, ContentType.DEFAULT_BINARY);
@@ -60,11 +63,14 @@ public class Content {
         if (charset == null) {
             charset = Consts.ISO_8859_1;
         }
-        try {
-            return new String(this.raw, charset.name());
-        } catch (final UnsupportedEncodingException ex) {
-            return new String(this.raw);
-        }
+        return asString(charset);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public String asString(final Charset charset) {
+        return new String(this.raw, charset);
     }
 
     public InputStream asStream() {
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/ContentResponseHandler.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/ContentResponseHandler.java
index da1b563..ebcbccc 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/ContentResponseHandler.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/ContentResponseHandler.java
@@ -29,30 +29,26 @@ package org.apache.http.client.fluent;
 import java.io.IOException;
 
 import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpResponseException;
-import org.apache.http.client.ResponseHandler;
 import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.AbstractResponseHandler;
 import org.apache.http.util.EntityUtils;
 
-class ContentResponseHandler implements ResponseHandler<Content> {
+/**
+ * {@link org.apache.http.client.ResponseHandler} implementation that converts
+ * {@link org.apache.http.HttpResponse} messages to {@link org.apache.http.client.fluent.Content}
+ * instances.
+ *
+ * @see org.apache.http.client.fluent.Content
+ *
+ * @since 4.4
+ */
+public class ContentResponseHandler extends AbstractResponseHandler<Content> {
 
-    public Content handleResponse(
-            final HttpResponse response) throws ClientProtocolException, IOException {
-        final StatusLine statusLine = response.getStatusLine();
-        final HttpEntity entity = response.getEntity();
-        if (statusLine.getStatusCode() >= 300) {
-            throw new HttpResponseException(statusLine.getStatusCode(),
-                    statusLine.getReasonPhrase());
-        }
-        if (entity != null) {
-            return new Content(
-                    EntityUtils.toByteArray(entity),
-                    ContentType.getOrDefault(entity));
-        }
-        return Content.NO_CONTENT;
+    @Override
+    public Content handleEntity(final HttpEntity entity) throws IOException {
+        return entity != null ?
+                new Content(EntityUtils.toByteArray(entity), ContentType.getOrDefault(entity)) :
+                Content.NO_CONTENT;
     }
 
 }
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java
index 6ce9927..e8b4387 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java
@@ -29,6 +29,7 @@ package org.apache.http.client.fluent;
 import java.io.IOException;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.SSLContext;
 
@@ -60,10 +61,11 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.message.BasicHeader;
 
 /**
- * An Executor for fluent requests
- * <p/>
+ * An Executor for fluent requests.
+ * <p>
  * A {@link PoolingHttpClientConnectionManager} with maximum 100 connections per route and
  * a total maximum of 200 connections is used internally.
+ * </p>
  */
 public class Executor {
 
@@ -129,6 +131,13 @@ public class Executor {
         return auth(authScope, creds);
     }
 
+    /**
+     * @since 4.4
+     */
+    public Executor auth(final String host, final Credentials creds) {
+        return auth(HttpHost.create(host), creds);
+    }
+
     public Executor authPreemptive(final HttpHost host) {
         final BasicScheme basicScheme = new BasicScheme();
         try {
@@ -139,16 +148,30 @@ public class Executor {
         return this;
     }
 
-    public Executor authPreemptiveProxy(final HttpHost host) {
+    /**
+     * @since 4.4
+     */
+    public Executor authPreemptive(final String host) {
+        return authPreemptive(HttpHost.create(host));
+    }
+
+    public Executor authPreemptiveProxy(final HttpHost proxy) {
         final BasicScheme basicScheme = new BasicScheme();
         try {
             basicScheme.processChallenge(new BasicHeader(AUTH.PROXY_AUTH, "BASIC "));
         } catch (final MalformedChallengeException ignore) {
         }
-        this.authCache.put(host, basicScheme);
+        this.authCache.put(proxy, basicScheme);
         return this;
     }
 
+    /**
+     * @since 4.4
+     */
+    public Executor authPreemptiveProxy(final String proxy) {
+        return authPreemptiveProxy(HttpHost.create(proxy));
+    }
+
     public Executor auth(final Credentials cred) {
         return auth(AuthScope.ANY, cred);
     }
@@ -220,4 +243,12 @@ public class Executor {
     public static void unregisterScheme(final String name) {
     }
 
+    /**
+     * Closes all idle persistent connections used by the internal pool.
+     * @since 4.4
+     */
+    public static void closeIdleConnections() {
+        CONNMGR.closeIdleConnections(0, TimeUnit.MICROSECONDS);
+    }
+
 }
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalByteArrayEntity.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalByteArrayEntity.java
index 7fb270a..b2702d1 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalByteArrayEntity.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalByteArrayEntity.java
@@ -75,24 +75,29 @@ class InternalByteArrayEntity extends AbstractHttpEntity implements Cloneable {
         this(b, off, len, null);
     }
 
+    @Override
     public boolean isRepeatable() {
         return true;
     }
 
+    @Override
     public long getContentLength() {
         return this.len;
     }
 
+    @Override
     public InputStream getContent() {
         return new ByteArrayInputStream(this.b, this.off, this.len);
     }
 
+    @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         Args.notNull(outstream, "Output stream");
         outstream.write(this.b, this.off, this.len);
         outstream.flush();
     }
 
+    @Override
     public boolean isStreaming() {
         return false;
     }
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalEntityEnclosingHttpRequest.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalEntityEnclosingHttpRequest.java
index d4b642c..6e0b4d6 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalEntityEnclosingHttpRequest.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalEntityEnclosingHttpRequest.java
@@ -44,14 +44,17 @@ class InternalEntityEnclosingHttpRequest extends InternalHttpRequest implements
         super(method, requestURI);
     }
 
+    @Override
     public HttpEntity getEntity() {
         return this.entity;
     }
 
+    @Override
     public void setEntity(final HttpEntity entity) {
         this.entity = entity;
     }
 
+    @Override
     public boolean expectContinue() {
         final Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
         return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalFileEntity.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalFileEntity.java
index 4ebaa6c..39c2b44 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalFileEntity.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalFileEntity.java
@@ -49,18 +49,22 @@ class InternalFileEntity extends AbstractHttpEntity implements Cloneable {
         }
     }
 
+    @Override
     public boolean isRepeatable() {
         return true;
     }
 
+    @Override
     public long getContentLength() {
         return this.file.length();
     }
 
+    @Override
     public InputStream getContent() throws IOException {
         return new FileInputStream(this.file);
     }
 
+    @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         Args.notNull(outstream, "Output stream");
         final InputStream instream = new FileInputStream(this.file);
@@ -76,6 +80,7 @@ class InternalFileEntity extends AbstractHttpEntity implements Cloneable {
         }
     }
 
+    @Override
     public boolean isStreaming() {
         return false;
     }
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalHttpRequest.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalHttpRequest.java
index 5bfc9fe..8d45954 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalHttpRequest.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalHttpRequest.java
@@ -69,18 +69,22 @@ class InternalHttpRequest extends AbstractHttpMessage
         this.version = version;
     }
 
+    @Override
     public ProtocolVersion getProtocolVersion() {
         return version != null ? version : HttpVersion.HTTP_1_1;
     }
 
+    @Override
     public String getMethod() {
         return this.method;
     }
 
+    @Override
     public URI getURI() {
         return this.uri;
     }
 
+    @Override
     public void abort() throws UnsupportedOperationException {
         if (this.aborted.compareAndSet(false, true)) {
             final Cancellable cancellable = this.cancellableRef.getAndSet(null);
@@ -90,30 +94,33 @@ class InternalHttpRequest extends AbstractHttpMessage
         }
     }
 
+    @Override
     public boolean isAborted() {
         return this.aborted.get();
     }
 
+    @Override
     public void setCancellable(final Cancellable cancellable) {
         if (!this.aborted.get()) {
             this.cancellableRef.set(cancellable);
         }
     }
 
+    @Override
     public RequestLine getRequestLine() {
-        final String method = getMethod();
         final ProtocolVersion ver = getProtocolVersion();
-        final URI uri = getURI();
+        final URI uriCopy = getURI();
         String uritext = null;
-        if (uri != null) {
-            uritext = uri.toASCIIString();
+        if (uriCopy != null) {
+            uritext = uriCopy.toASCIIString();
         }
-        if (uritext == null || uritext.length() == 0) {
+        if (uritext == null || uritext.isEmpty()) {
             uritext = "/";
         }
-        return new BasicRequestLine(method, uritext, ver);
+        return new BasicRequestLine(getMethod(), uritext, ver);
     }
 
+    @Override
     public RequestConfig getConfig() {
         return config;
     }
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalInputStreamEntity.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalInputStreamEntity.java
index 7d7da2b..3a47041 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalInputStreamEntity.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/InternalInputStreamEntity.java
@@ -49,18 +49,22 @@ class InternalInputStreamEntity extends AbstractHttpEntity {
         }
     }
 
+    @Override
     public boolean isRepeatable() {
         return false;
     }
 
+    @Override
     public long getContentLength() {
         return this.length;
     }
 
+    @Override
     public InputStream getContent() throws IOException {
         return this.content;
     }
 
+    @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         Args.notNull(outstream, "Output stream");
         final InputStream instream = this.content;
@@ -89,6 +93,7 @@ class InternalInputStreamEntity extends AbstractHttpEntity {
         }
     }
 
+    @Override
     public boolean isStreaming() {
         return true;
     }
diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/Request.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/Request.java
index 8ca0585..a89be34 100644
--- a/fluent-hc/src/main/java/org/apache/http/client/fluent/Request.java
+++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/Request.java
@@ -29,7 +29,6 @@ package org.apache.http.client.fluent;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.nio.charset.Charset;
 import java.text.SimpleDateFormat;
@@ -53,6 +52,7 @@ import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpHead;
 import org.apache.http.client.methods.HttpOptions;
+import org.apache.http.client.methods.HttpPatch;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpTrace;
@@ -95,6 +95,14 @@ public class Request {
         return new Request(new InternalEntityEnclosingHttpRequest(HttpPost.METHOD_NAME, URI.create(uri)));
     }
 
+    public static Request Patch(final URI uri) {
+        return new Request(new InternalEntityEnclosingHttpRequest(HttpPatch.METHOD_NAME, uri));
+    }
+
+    public static Request Patch(final String uri) {
+        return new Request(new InternalEntityEnclosingHttpRequest(HttpPatch.METHOD_NAME, URI.create(uri)));
+    }
+
     public static Request Put(final URI uri) {
         return new Request(new InternalEntityEnclosingHttpRequest(HttpPut.METHOD_NAME, uri));
     }
@@ -247,8 +255,10 @@ public class Request {
 
     /**
      * This parameter can no longer be used at the request level.
-     * <p/>
+     * <p>
      * This method has no effect. Do not use.
+     * </p>
+     *
      * @deprecated (4.3)
      */
     @Deprecated
@@ -278,6 +288,11 @@ public class Request {
         return this;
     }
 
+    /**
+     * @deprecated (4.4) Use {@link
+     *   org.apache.http.impl.conn.PoolingHttpClientConnectionManager#setValidateAfterInactivity(int)}
+     */
+    @Deprecated
     public Request staleConnectionCheck(final boolean b) {
         this.configBuilder.setStaleConnectionCheckEnabled(b);
         return this;
@@ -290,6 +305,14 @@ public class Request {
         return this;
     }
 
+    /**
+     * @since 4.4
+     */
+    public Request viaProxy(final String proxy) {
+        this.configBuilder.setProxy(HttpHost.create(proxy));
+        return this;
+    }
+
     //// HTTP entity operations
 
     public Request body(final HttpEntity entity) {
@@ -322,12 +345,7 @@ public class Request {
 
     public Request bodyString(final String s, final ContentType contentType) {
         final Charset charset = contentType != null ? contentType.getCharset() : null;
-        byte[] raw;
-        try {
-            raw = charset != null ? s.getBytes(charset.name()) : s.getBytes();
-        } catch (UnsupportedEncodingException ex) {
-            raw = s.getBytes();
-        }
+        final byte[] raw = charset != null ? s.getBytes(charset) : s.getBytes();
         return body(new InternalByteArrayEntity(raw, contentType));
     }
 
@@ -339,10 +357,24 @@ public class Request {
         return body(new InternalByteArrayEntity(b));
     }
 
+    /**
+     * @since 4.4
+     */
+    public Request bodyByteArray(final byte[] b, final ContentType contentType) {
+        return body(new InternalByteArrayEntity(b, contentType));
+    }
+
     public Request bodyByteArray(final byte[] b, final int off, final int len) {
         return body(new InternalByteArrayEntity(b, off, len));
     }
 
+    /**
+     * @since 4.4
+     */
+    public Request bodyByteArray(final byte[] b, final int off, final int len, final ContentType contentType) {
+        return body(new InternalByteArrayEntity(b, off, len, contentType));
+    }
+
     public Request bodyStream(final InputStream instream) {
         return body(new InternalInputStreamEntity(instream, -1, null));
     }
diff --git a/fluent-hc/src/test/java/org/apache/http/client/fluent/TestFluent.java b/fluent-hc/src/test/java/org/apache/http/client/fluent/TestFluent.java
index e42675b..1a1d86d 100644
--- a/fluent-hc/src/test/java/org/apache/http/client/fluent/TestFluent.java
+++ b/fluent-hc/src/test/java/org/apache/http/client/fluent/TestFluent.java
@@ -28,11 +28,12 @@ package org.apache.http.client.fluent;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.InetSocketAddress;
+import java.nio.charset.Charset;
 
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.ClientProtocolException;
@@ -40,22 +41,22 @@ import org.apache.http.client.ResponseHandler;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.localserver.LocalServerTestBase;
-import org.apache.http.localserver.LocalTestServer;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import junit.framework.Assert;
-
 public class TestFluent extends LocalServerTestBase {
 
-    @Before
+    @Before @Override
     public void setUp() throws Exception {
-        this.localServer = new LocalTestServer(null, null);
-        localServer.register("/", new HttpRequestHandler() {
+        super.setUp();
+        this.serverBootstrap.registerHandler("/", new HttpRequestHandler() {
 
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -64,8 +65,9 @@ public class TestFluent extends LocalServerTestBase {
             }
 
         });
-        localServer.register("/echo", new HttpRequestHandler() {
+        this.serverBootstrap.registerHandler("/echo", new HttpRequestHandler() {
 
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -88,48 +90,65 @@ public class TestFluent extends LocalServerTestBase {
             }
 
         });
-        startServer();
+    }
+
+    @After @Override
+    public void shutDown() throws Exception {
+        Executor.closeIdleConnections();
+        super.shutDown();
     }
 
     @Test
     public void testGetRequest() throws Exception {
-        final InetSocketAddress serviceAddress = this.localServer.getServiceAddress();
-        final String baseURL = "http://localhost:" + serviceAddress.getPort();
+        final HttpHost target = start();
+        final String baseURL = "http://localhost:" + target.getPort();
         final String message = Request.Get(baseURL + "/").execute().returnContent().asString();
         Assert.assertEquals("All is well", message);
     }
 
     @Test(expected = ClientProtocolException.class)
     public void testGetRequestFailure() throws Exception {
-        final InetSocketAddress serviceAddress = this.localServer.getServiceAddress();
-        final String baseURL = "http://localhost:" + serviceAddress.getPort();
+        final HttpHost target = start();
+        final String baseURL = "http://localhost:" + target.getPort();
         Request.Get(baseURL + "/boom").execute().returnContent().asString();
     }
 
     @Test
     public void testPostRequest() throws Exception {
-        final InetSocketAddress serviceAddress = this.localServer.getServiceAddress();
-        final String baseURL = "http://localhost:" + serviceAddress.getPort();
+        final HttpHost target = start();
+        final String baseURL = "http://localhost:" + target.getPort();
         final String message1 = Request.Post(baseURL + "/echo")
                 .bodyString("what is up?", ContentType.TEXT_PLAIN)
                 .execute().returnContent().asString();
         Assert.assertEquals("what is up?", message1);
         final String message2 = Request.Post(baseURL + "/echo")
-                .bodyByteArray(new byte[]{'a', 'b', 'c'})
+                .bodyByteArray(new byte[]{1, 2, 3}, ContentType.APPLICATION_OCTET_STREAM)
                 .execute().returnContent().asString();
-        Assert.assertEquals("abc", message2);
+        Assert.assertEquals("echo", message2);
+    }
+
+    @Test
+    public void testContentAsStringWithCharset() throws Exception {
+        final HttpHost target = start();
+        final String baseURL = "http://localhost:" + target.getPort();
+        final Content content = Request.Post(baseURL + "/echo").bodyByteArray("Ü".getBytes("utf-8")).execute()
+                .returnContent();
+        Assert.assertEquals((byte)-61, content.asBytes()[0]);
+        Assert.assertEquals((byte)-100, content.asBytes()[1]);
+        Assert.assertEquals("Ü", content.asString(Charset.forName("utf-8")));
     }
 
     @Test
     public void testConnectionRelease() throws Exception {
-        final InetSocketAddress serviceAddress = this.localServer.getServiceAddress();
-        final String baseURL = "http://localhost:" + serviceAddress.getPort();
+        final HttpHost target = start();
+        final String baseURL = "http://localhost:" + target.getPort();
         for (int i = 0; i < 20; i++) {
             Request.Get(baseURL + "/").execute().returnContent();
             Request.Get(baseURL + "/").execute().returnResponse();
             Request.Get(baseURL + "/").execute().discardContent();
             Request.Get(baseURL + "/").execute().handleResponse(new ResponseHandler<Object>() {
 
+                @Override
                 public Object handleResponse(
                         final HttpResponse response) throws IOException {
                     return null;
diff --git a/httpclient-cache/pom.xml b/httpclient-cache/pom.xml
index a288806..851577c 100644
--- a/httpclient-cache/pom.xml
+++ b/httpclient-cache/pom.xml
@@ -28,13 +28,13 @@
   <parent>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpcomponents-client</artifactId>
-    <version>4.3.5</version>
+    <version>4.4.1</version>
   </parent>
   <artifactId>httpclient-cache</artifactId>
   <name>Apache HttpClient Cache</name>
   <inceptionYear>2010</inceptionYear>
   <description>
-   HttpComponents HttpClient - Cache
+   Apache HttpComponents HttpClient - Cache
   </description>
   <url>http://hc.apache.org/httpcomponents-client</url>
   <packaging>jar</packaging>
@@ -64,7 +64,7 @@
       <optional>true</optional>
     </dependency>
     <dependency>
-      <groupId>spy</groupId>
+      <groupId>net.spy</groupId>
       <artifactId>spymemcached</artifactId>
       <scope>compile</scope>
       <optional>true</optional>
@@ -75,6 +75,11 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymock</artifactId>
       <scope>test</scope>
@@ -124,16 +129,16 @@
         </executions>
       </plugin>
       <plugin>
-       <groupId>org.apache.maven.plugins</groupId>
-       <artifactId>maven-jar-plugin</artifactId>
-       <executions>
-         <execution>
-           <goals>
-             <goal>test-jar</goal>
-           </goals>
-         </execution>
-       </executions>
-     </plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 
@@ -142,13 +147,13 @@
 
       <plugin>
         <artifactId>maven-javadoc-plugin</artifactId>
-         <version>${hc.javadoc.version}</version>
+        <version>${hc.javadoc.version}</version>
         <configuration>
           <!-- reduce console output. Can override with -Dquiet=false -->
           <quiet>true</quiet>
           <source>${maven.compiler.source}</source>
           <links>
-            <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
+            <link>http://docs.oracle.com/javase/6/docs/api/</link>
             <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
             <link>http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/</link>
           </links>
diff --git a/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java b/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java
index 57953ff..a54ff19 100644
--- a/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java
+++ b/httpclient-cache/src/main/java-deprecated/org/apache/http/impl/client/cache/CachingHttpClient.java
@@ -81,7 +81,8 @@ import org.apache.http.util.Args;
 import org.apache.http.util.VersionInfo;
 
 /**
- * <p>The {@link CachingHttpClient} is meant to be a drop-in replacement for
+ * <p>
+ * The {@link CachingHttpClient} is meant to be a drop-in replacement for
  * a {@link DefaultHttpClient} that transparently adds client-side caching.
  * The current implementation is conditionally compliant with HTTP/1.1
  * (meaning all the MUST and MUST NOTs are obeyed), although quite a lot,
@@ -93,9 +94,11 @@ import org.apache.http.util.VersionInfo;
  * passing in a {@link CacheConfig}. Note that all of the usual client
  * related configuration you want to do vis-a-vis timeouts and connection
  * pools should be done on this backend client before constructing a {@code
- * CachingHttpClient} from it.</p>
+ * CachingHttpClient} from it.
+ * </p>
  *
- * <p>Generally speaking, the {@code CachingHttpClient} is implemented as a
+ * <p>
+ * Generally speaking, the {@code CachingHttpClient} is implemented as a
  * <a href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</a>
  * of the backend client; for any incoming request it attempts to satisfy
  * it from the cache, but if it can't, or if it needs to revalidate a stale
@@ -106,15 +109,17 @@ import org.apache.http.util.VersionInfo;
  * or the cache may make a conditional request on your behalf to the origin).
  * This notion of "semantic transparency" means you should be able to drop
  * a {@link CachingHttpClient} into an existing application without breaking
- * anything.</p>
+ * anything.
+ * </p>
  *
- * <p>Folks that would like to experiment with alternative storage backends
+ * <p>
+ * Folks that would like to experiment with alternative storage backends
  * should look at the {@link HttpCacheStorage} interface and the related
  * package documentation there. You may also be interested in the provided
  * {@link org.apache.http.impl.client.cache.ehcache.EhcacheHttpCacheStorage
  * EhCache} and {@link
  * org.apache.http.impl.client.cache.memcached.MemcachedHttpCacheStorage
- * memcached} storage backends.</p>
+ * memcached} storage backends.
  * </p>
  * @since 4.1
  *
@@ -590,7 +595,7 @@ public class CachingHttpClient implements HttpClient {
                 || request.containsHeader(HeaderConstants.IF_MODIFIED_SINCE)) {
             cachedResponse = responseGenerator.generateNotModifiedResponse(entry);
         } else {
-            cachedResponse = responseGenerator.generateResponse(entry);
+            cachedResponse = responseGenerator.generateResponse(request, entry);
         }
         setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
         if (validityPolicy.getStalenessSecs(entry, now) > 0L) {
@@ -604,7 +609,7 @@ public class CachingHttpClient implements HttpClient {
         if (staleResponseNotAllowed(request, entry, now)) {
             return generateGatewayTimeout(context);
         } else {
-            return unvalidatedCacheHit(context, entry);
+            return unvalidatedCacheHit(request, context, entry);
         }
     }
 
@@ -614,9 +619,11 @@ public class CachingHttpClient implements HttpClient {
                 HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
     }
 
-    private HttpResponse unvalidatedCacheHit(final HttpContext context,
+    private HttpResponse unvalidatedCacheHit(
+            final HttpRequestWrapper request,
+            final HttpContext context,
             final HttpCacheEntry entry) {
-        final HttpResponse cachedResponse = responseGenerator.generateResponse(entry);
+        final HttpResponse cachedResponse = responseGenerator.generateResponse(request, entry);
         setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
         cachedResponse.addHeader(HeaderConstants.WARNING, "111 localhost \"Revalidation failed\"");
         return cachedResponse;
@@ -814,7 +821,7 @@ public class CachingHttpClient implements HttpClient {
                 conditionalRequest, requestDate, responseDate, backendResponse,
                 matchingVariant, matchedEntry);
 
-        final HttpResponse resp = responseGenerator.generateResponse(responseEntry);
+        final HttpResponse resp = responseGenerator.generateResponse(request, responseEntry);
         tryToUpdateVariantMap(target, request, matchingVariant);
 
         if (shouldSendNotModifiedResponse(request, responseEntry)) {
@@ -896,13 +903,13 @@ public class CachingHttpClient implements HttpClient {
                     && suitabilityChecker.allConditionalsMatch(request, updatedEntry, new Date())) {
                 return responseGenerator.generateNotModifiedResponse(updatedEntry);
             }
-            return responseGenerator.generateResponse(updatedEntry);
+            return responseGenerator.generateResponse(request, updatedEntry);
         }
 
         if (staleIfErrorAppliesTo(statusCode)
             && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
             && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
-            final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry);
+            final HttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry);
             cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
             final HttpEntity errorBody = backendResponse.getEntity();
             if (errorBody != null) {
@@ -1108,12 +1115,12 @@ public class CachingHttpClient implements HttpClient {
         /**
          * Used internally by {@link AsynchronousValidator} to schedule a
          * revalidation.
-         * @param parent
          * @param cachingClient
          * @param target
          * @param request
          * @param context
          * @param cacheEntry
+         * @param bookKeeping
          * @param identifier
          */
         AsynchronousValidationRequest(final AsynchronousValidator parent,
diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/CacheResponseStatus.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/CacheResponseStatus.java
index aa94bdb..75998e7 100644
--- a/httpclient-cache/src/main/java/org/apache/http/client/cache/CacheResponseStatus.java
+++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/CacheResponseStatus.java
@@ -50,6 +50,6 @@ public enum CacheResponseStatus {
     /** The response was generated from the cache after validating the
      * entry with the origin server.
      */
-    VALIDATED;
+    VALIDATED
 
 }
diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java
index 38ef49f..d8bf81b 100644
--- a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java
+++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheEntry.java
@@ -33,6 +33,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
 import org.apache.http.ProtocolVersion;
 import org.apache.http.StatusLine;
 import org.apache.http.annotation.Immutable;
@@ -54,6 +55,7 @@ import org.apache.http.util.Args;
 public class HttpCacheEntry implements Serializable {
 
     private static final long serialVersionUID = -6300496422359477413L;
+    private static final String REQUEST_METHOD_HEADER_NAME = "Hc-Request-Method";
 
     private final Date requestDate;
     private final Date responseDate;
@@ -80,6 +82,7 @@ public class HttpCacheEntry implements Serializable {
      *   of this parent entry; this maps a "variant key" (derived
      *   from the varying request headers) to a "cache key" (where
      *   in the cache storage the particular variant is located)
+     * @param requestMethod HTTP method used when the request was made
      */
     public HttpCacheEntry(
             final Date requestDate,
@@ -87,7 +90,8 @@ public class HttpCacheEntry implements Serializable {
             final StatusLine statusLine,
             final Header[] responseHeaders,
             final Resource resource,
-            final Map<String,String> variantMap) {
+            final Map<String,String> variantMap,
+            final String requestMethod) {
         super();
         Args.notNull(requestDate, "Request date");
         Args.notNull(responseDate, "Response date");
@@ -106,6 +110,35 @@ public class HttpCacheEntry implements Serializable {
     }
 
     /**
+     * Create a new {@link HttpCacheEntry} with variants.
+     * @param requestDate
+     *          Date/time when the request was made (Used for age
+     *            calculations)
+     * @param responseDate
+     *          Date/time that the response came back (Used for age
+     *            calculations)
+     * @param statusLine
+     *          HTTP status line from origin response
+     * @param responseHeaders
+     *          Header[] from original HTTP Response
+     * @param resource representing origin response body
+     * @param variantMap describing cache entries that are variants
+     *   of this parent entry; this maps a "variant key" (derived
+     *   from the varying request headers) to a "cache key" (where
+     *   in the cache storage the particular variant is located)
+     */
+    public HttpCacheEntry(
+            final Date requestDate,
+            final Date responseDate,
+            final StatusLine statusLine,
+            final Header[] responseHeaders,
+            final Resource resource,
+            final Map<String,String> variantMap) {
+        this(requestDate, responseDate, statusLine, responseHeaders, resource,
+                variantMap, null);
+    }
+
+    /**
      * Create a new {@link HttpCacheEntry}.
      *
      * @param requestDate
@@ -127,6 +160,28 @@ public class HttpCacheEntry implements Serializable {
     }
 
     /**
+     * Create a new {@link HttpCacheEntry}.
+     *
+     * @param requestDate
+     *          Date/time when the request was made (Used for age
+     *            calculations)
+     * @param responseDate
+     *          Date/time that the response came back (Used for age
+     *            calculations)
+     * @param statusLine
+     *          HTTP status line from origin response
+     * @param responseHeaders
+     *          Header[] from original HTTP Response
+     * @param resource representing origin response body
+     * @param requestMethod HTTP method used when the request was made
+     */
+    public HttpCacheEntry(final Date requestDate, final Date responseDate, final StatusLine statusLine,
+            final Header[] responseHeaders, final Resource resource, final String requestMethod) {
+        this(requestDate, responseDate, statusLine, responseHeaders, resource,
+                new HashMap<String,String>(),requestMethod);
+    }
+
+    /**
      * Find the "Date" response header and parse it into a java.util.Date
      * @return the Date value of the header or null if the header is not present
      */
@@ -191,7 +246,15 @@ public class HttpCacheEntry implements Serializable {
      * Returns all the headers that were on the origin response.
      */
     public Header[] getAllHeaders() {
-        return responseHeaders.getAllHeaders();
+        final HeaderGroup filteredHeaders = new HeaderGroup();
+        for (final HeaderIterator iterator = responseHeaders.iterator(); iterator
+                .hasNext();) {
+            final Header header = (Header) iterator.next();
+            if (!REQUEST_METHOD_HEADER_NAME.equals(header.getName())) {
+                filteredHeaders.addHeader(header);
+            }
+        }
+        return filteredHeaders.getAllHeaders();
     }
 
     /**
@@ -199,6 +262,9 @@ public class HttpCacheEntry implements Serializable {
      * name.
      */
     public Header getFirstHeader(final String name) {
+        if (REQUEST_METHOD_HEADER_NAME.equalsIgnoreCase(name)) {
+            return null;
+        }
         return responseHeaders.getFirstHeader(name);
     }
 
@@ -207,6 +273,9 @@ public class HttpCacheEntry implements Serializable {
      * response.
      */
     public Header[] getHeaders(final String name) {
+        if (REQUEST_METHOD_HEADER_NAME.equalsIgnoreCase(name)) {
+            return new Header[0];
+        }
         return responseHeaders.getHeaders(name);
     }
 
@@ -251,6 +320,21 @@ public class HttpCacheEntry implements Serializable {
     }
 
     /**
+     * Returns the HTTP request method that was used to create the cached
+     * response entry.
+     *
+     * @since 4.4
+     */
+    public String getRequestMethod() {
+        final Header requestMethodHeader = responseHeaders
+                .getFirstHeader(REQUEST_METHOD_HEADER_NAME);
+        if (requestMethodHeader != null) {
+            return requestMethodHeader.getValue();
+        }
+        return HeaderConstants.GET_METHOD;
+    }
+
+    /**
      * Provides a string representation of this instance suitable for
      * human consumption.
      */
diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateCallback.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateCallback.java
index 8c560b7..6cab4b4 100644
--- a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateCallback.java
+++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateCallback.java
@@ -41,9 +41,9 @@ public interface HttpCacheUpdateCallback {
      *
      * @param existing
      *            the cache entry currently in-place in the cache, possibly
-     *            <code>null</code> if nonexistent
+     *            {@code null} if nonexistent
      * @return the cache entry that should replace it, again,
-     *         possibly <code>null</code> if the entry should be deleted
+     *         possibly {@code null} if the entry should be deleted
      *
      * @since 4.1
      */
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java
index 797bb9f..6bc4dd3 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidationRequest.java
@@ -45,7 +45,7 @@ import org.apache.http.conn.routing.HttpRoute;
  * Class used to represent an asynchronous revalidation event, such as with
  * "stale-while-revalidate"
  */
-class AsynchronousValidationRequest implements Runnable {
+public class AsynchronousValidationRequest implements Runnable {
     private final AsynchronousValidator parent;
     private final CachingExec cachingExec;
     private final HttpRoute route;
@@ -88,6 +88,7 @@ class AsynchronousValidationRequest implements Runnable {
         this.consecutiveFailedAttempts = consecutiveFailedAttempts;
     }
 
+    @Override
     public void run() {
         try {
             if (revalidateCacheEntry()) {
@@ -104,10 +105,10 @@ class AsynchronousValidationRequest implements Runnable {
      * Revalidate the cache entry and return if the operation was successful.
      * Success means a connection to the server was established and replay did
      * not indicate a server error.
-     * @return <code>true</code> if the cache entry was successfully validated;
-     * otherwise <code>false</code>
+     * @return {@code true} if the cache entry was successfully validated;
+     * otherwise {@code false}
      */
-    protected boolean revalidateCacheEntry() {
+    private boolean revalidateCacheEntry() {
         try {
             final CloseableHttpResponse httpResponse = cachingExec.revalidateCacheEntry(route, request, context, execAware, cacheEntry);
             try {
@@ -163,7 +164,7 @@ class AsynchronousValidationRequest implements Runnable {
         return true;
     }
 
-    String getIdentifier() {
+    public String getIdentifier() {
         return identifier;
     }
 
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java
index 72d3a72..03a4d48 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/AsynchronousValidator.java
@@ -81,6 +81,7 @@ class AsynchronousValidator implements Closeable {
         this.failureCache = new DefaultFailureCache();
     }
 
+    @Override
     public void close() throws IOException {
         schedulingStrategy.close();
     }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java
index 865add8..2a03f60 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java
@@ -51,6 +51,7 @@ import org.apache.http.client.cache.HttpCacheUpdateException;
 import org.apache.http.client.cache.Resource;
 import org.apache.http.client.cache.ResourceFactory;
 import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.protocol.HTTP;
@@ -110,6 +111,7 @@ class BasicHttpCache implements HttpCache {
         this(CacheConfig.DEFAULT);
     }
 
+    @Override
     public void flushCacheEntriesFor(final HttpHost host, final HttpRequest request)
             throws IOException {
         if (!safeRequestMethods.contains(request.getRequestLine().getMethod())) {
@@ -118,6 +120,7 @@ class BasicHttpCache implements HttpCache {
         }
     }
 
+    @Override
     public void flushInvalidatedCacheEntriesFor(final HttpHost host, final HttpRequest request, final HttpResponse response) {
         if (!safeRequestMethods.contains(request.getRequestLine().getMethod())) {
             cacheInvalidator.flushInvalidatedCacheEntries(host, request, response);
@@ -149,6 +152,7 @@ class BasicHttpCache implements HttpCache {
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
 
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry existing) throws IOException {
                 return doGetUpdatedParentEntry(
                         req.getRequestLine().getUri(), existing, entry,
@@ -165,6 +169,7 @@ class BasicHttpCache implements HttpCache {
         }
     }
 
+    @Override
     public void reuseVariantEntryFor(final HttpHost target, final HttpRequest req,
             final Variant variant) throws IOException {
         final String parentCacheKey = uriExtractor.getURI(target, req);
@@ -173,6 +178,7 @@ class BasicHttpCache implements HttpCache {
         final String variantCacheKey = variant.getCacheKey();
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry existing)
                     throws IOException {
                 return doGetUpdatedParentEntry(req.getRequestLine().getUri(),
@@ -203,12 +209,15 @@ class BasicHttpCache implements HttpCache {
         } catch (final NumberFormatException nfe) {
             return false;
         }
+        if (resource == null) {
+            return false;
+        }
         return (resource.length() < contentLength);
     }
 
     CloseableHttpResponse generateIncompleteResponseError(
             final HttpResponse response, final Resource resource) {
-        final int contentLength = Integer.parseInt(response.getFirstHeader(HTTP.CONTENT_LEN).getValue());
+        final Integer contentLength = Integer.valueOf(response.getFirstHeader(HTTP.CONTENT_LEN).getValue());
         final HttpResponse error =
             new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_GATEWAY, "Bad Gateway");
         error.setHeader("Content-Type","text/plain;charset=UTF-8");
@@ -244,9 +253,11 @@ class BasicHttpCache implements HttpCache {
                 src.getStatusLine(),
                 src.getAllHeaders(),
                 resource,
-                variantMap);
+                variantMap,
+                src.getRequestMethod());
     }
 
+    @Override
     public HttpCacheEntry updateCacheEntry(final HttpHost target, final HttpRequest request,
             final HttpCacheEntry stale, final HttpResponse originResponse,
             final Date requestSent, final Date responseReceived) throws IOException {
@@ -260,6 +271,7 @@ class BasicHttpCache implements HttpCache {
         return updatedEntry;
     }
 
+    @Override
     public HttpCacheEntry updateVariantCacheEntry(final HttpHost target, final HttpRequest request,
             final HttpCacheEntry stale, final HttpResponse originResponse,
             final Date requestSent, final Date responseReceived, final String cacheKey) throws IOException {
@@ -273,6 +285,7 @@ class BasicHttpCache implements HttpCache {
         return updatedEntry;
     }
 
+    @Override
     public HttpResponse cacheAndReturnResponse(final HttpHost host, final HttpRequest request,
             final HttpResponse originResponse, final Date requestSent, final Date responseReceived)
             throws IOException {
@@ -281,6 +294,7 @@ class BasicHttpCache implements HttpCache {
                 responseReceived);
     }
 
+    @Override
     public CloseableHttpResponse cacheAndReturnResponse(
             final HttpHost host,
             final HttpRequest request,
@@ -308,9 +322,10 @@ class BasicHttpCache implements HttpCache {
                     responseReceived,
                     originResponse.getStatusLine(),
                     originResponse.getAllHeaders(),
-                    resource);
+                    resource,
+                    request.getRequestLine().getMethod());
             storeInCache(host, request, entry);
-            return responseGenerator.generateResponse(entry);
+            return responseGenerator.generateResponse(HttpRequestWrapper.wrap(request, host), entry);
         } finally {
             if (closeOriginResponse) {
                 originResponse.close();
@@ -324,6 +339,7 @@ class BasicHttpCache implements HttpCache {
                 resourceFactory, maxObjectSizeBytes, request, backEndResponse);
     }
 
+    @Override
     public HttpCacheEntry getCacheEntry(final HttpHost host, final HttpRequest request) throws IOException {
         final HttpCacheEntry root = storage.getEntry(uriExtractor.getURI(host, request));
         if (root == null) {
@@ -339,11 +355,13 @@ class BasicHttpCache implements HttpCache {
         return storage.getEntry(variantCacheKey);
     }
 
+    @Override
     public void flushInvalidatedCacheEntriesFor(final HttpHost host,
             final HttpRequest request) throws IOException {
         cacheInvalidator.flushInvalidatedCacheEntries(host, request);
     }
 
+    @Override
     public Map<String, Variant> getVariantCacheEntriesWithEtags(final HttpHost host, final HttpRequest request)
             throws IOException {
         final Map<String,Variant> variants = new HashMap<String,Variant>();
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCacheStorage.java
index 259e23b..76a525c 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCacheStorage.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCacheStorage.java
@@ -61,6 +61,7 @@ public class BasicHttpCacheStorage implements HttpCacheStorage {
      * @param entry
      *            HttpCacheEntry to place in the cache
      */
+    @Override
     public synchronized void putEntry(final String url, final HttpCacheEntry entry) throws IOException {
         entries.put(url, entry);
     }
@@ -72,6 +73,7 @@ public class BasicHttpCacheStorage implements HttpCacheStorage {
      *            Url that is the cache key
      * @return HttpCacheEntry if one exists, or null for cache miss
      */
+    @Override
     public synchronized HttpCacheEntry getEntry(final String url) throws IOException {
         return entries.get(url);
     }
@@ -82,10 +84,12 @@ public class BasicHttpCacheStorage implements HttpCacheStorage {
      * @param url
      *            Url that is the cache key
      */
+    @Override
     public synchronized void removeEntry(final String url) throws IOException {
         entries.remove(url);
     }
 
+    @Override
     public synchronized void updateEntry(
             final String url,
             final HttpCacheUpdateCallback callback) throws IOException {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicIdGenerator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicIdGenerator.java
index 9d4e508..04236ab 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicIdGenerator.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicIdGenerator.java
@@ -71,7 +71,7 @@ class BasicIdGenerator {
         buffer.append(System.currentTimeMillis());
         buffer.append('.');
         final Formatter formatter = new Formatter(buffer, Locale.US);
-        formatter.format("%1$016x-%2$08x", this.count, rndnum);
+        formatter.format("%1$016x-%2$08x", Long.valueOf(this.count), Integer.valueOf(rndnum));
         formatter.close();
         buffer.append('.');
         buffer.append(this.hostname);
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java
index 5ecdd66..3c4a55e 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java
@@ -98,7 +98,7 @@ import org.apache.http.util.Args;
  * CacheConfig#getAsynchronousWorkerIdleLifetimeSecs() maximum time they
  * can be idle before being reclaimed}. You can also control the {@link
  * CacheConfig#getRevalidationQueueSize() size of the queue} used for
- * revalidations when there aren't enough workers to keep up with demand.</b>
+ * revalidations when there aren't enough workers to keep up with demand.</p>
  */
 public class CacheConfig implements Cloneable {
 
@@ -460,7 +460,7 @@ public class CacheConfig implements Cloneable {
      * Sets the minimum number of threads to keep alive for background
      * revalidations due to the {@code stale-while-revalidate} directive.
      * @param min should be greater than zero and less than or equal
-     *   to <code>getAsynchronousWorkersMax()</code>
+     *   to {@code getAsynchronousWorkersMax()}
      *
      * @deprecated (4.3) use {@link Builder}.
      */
@@ -680,7 +680,7 @@ public class CacheConfig implements Cloneable {
          * Sets the minimum number of threads to keep alive for background
          * revalidations due to the {@code stale-while-revalidate} directive.
          * @param asynchronousWorkersCore should be greater than zero and less than or equal
-         *   to <code>getAsynchronousWorkersMax()</code>
+         *   to {@code getAsynchronousWorkersMax()}
          */
         public Builder setAsynchronousWorkersCore(final int asynchronousWorkersCore) {
             this.asynchronousWorkersCore = asynchronousWorkersCore;
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java
index 85a4211..66e4af7 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntity.java
@@ -50,30 +50,37 @@ class CacheEntity implements HttpEntity, Serializable {
         this.cacheEntry = cacheEntry;
     }
 
+    @Override
     public Header getContentType() {
         return this.cacheEntry.getFirstHeader(HTTP.CONTENT_TYPE);
     }
 
+    @Override
     public Header getContentEncoding() {
         return this.cacheEntry.getFirstHeader(HTTP.CONTENT_ENCODING);
     }
 
+    @Override
     public boolean isChunked() {
         return false;
     }
 
+    @Override
     public boolean isRepeatable() {
         return true;
     }
 
+    @Override
     public long getContentLength() {
         return this.cacheEntry.getResource().length();
     }
 
+    @Override
     public InputStream getContent() throws IOException {
         return this.cacheEntry.getResource().getInputStream();
     }
 
+    @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         Args.notNull(outstream, "Output stream");
         final InputStream instream = this.cacheEntry.getResource().getInputStream();
@@ -84,10 +91,12 @@ class CacheEntity implements HttpEntity, Serializable {
         }
     }
 
+    @Override
     public boolean isStreaming() {
         return false;
     }
 
+    @Override
     public void consumeContent() throws IOException {
     }
 
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java
index ffc528b..4801b9d 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java
@@ -96,7 +96,8 @@ class CacheEntryUpdater {
                 responseDate,
                 entry.getStatusLine(),
                 mergedHeaders,
-                resource);
+                resource,
+                entry.getRequestMethod());
     }
 
     protected Header[] mergeHeaders(final HttpCacheEntry entry, final HttpResponse response) {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
index 64b2c75..57c2d91 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
@@ -80,16 +80,13 @@ class CacheInvalidator implements HttpCacheInvalidator {
      * @param host The backend host we are talking to
      * @param req The HttpRequest to that host
      */
+    @Override
     public void flushInvalidatedCacheEntries(final HttpHost host, final HttpRequest req)  {
-        if (requestShouldNotBeCached(req)) {
-            log.debug("Request should not be cached");
-
-            final String theUri = cacheKeyGenerator.getURI(host, req);
-
-            final HttpCacheEntry parent = getEntry(theUri);
-
-            log.debug("parent entry: " + parent);
+        final String theUri = cacheKeyGenerator.getURI(host, req);
+        final HttpCacheEntry parent = getEntry(theUri);
 
+        if (requestShouldNotBeCached(req) || shouldInvalidateHeadCacheEntry(req, parent)) {
+            log.debug("Invalidating parent cache entry: " + parent);
             if (parent != null) {
                 for (final String variantURI : parent.getVariantMap().values()) {
                     flushEntry(variantURI);
@@ -115,6 +112,18 @@ class CacheInvalidator implements HttpCacheInvalidator {
         }
     }
 
+    private boolean shouldInvalidateHeadCacheEntry(final HttpRequest req, final HttpCacheEntry parentCacheEntry) {
+        return requestIsGet(req) && isAHeadCacheEntry(parentCacheEntry);
+    }
+
+    private boolean requestIsGet(final HttpRequest req) {
+        return req.getRequestLine().getMethod().equals((HeaderConstants.GET_METHOD));
+    }
+
+    private boolean isAHeadCacheEntry(final HttpCacheEntry parentCacheEntry) {
+        return parentCacheEntry != null && parentCacheEntry.getRequestMethod().equals(HeaderConstants.HEAD_METHOD);
+    }
+
     private void flushEntry(final String uri) {
         try {
             storage.removeEntry(uri);
@@ -193,6 +202,7 @@ class CacheInvalidator implements HttpCacheInvalidator {
     /** Flushes entries that were invalidated by the given response
      * received for the given host/request pair.
      */
+    @Override
     public void flushInvalidatedCacheEntries(final HttpHost host,
             final HttpRequest request, final HttpResponse response) {
         final int status = response.getStatusLine().getStatusCode();
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheKeyGenerator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheKeyGenerator.java
index 68a7bcc..3d006d5 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheKeyGenerator.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheKeyGenerator.java
@@ -143,7 +143,7 @@ class CacheKeyGenerator {
      * variant key.
      * @param req originating request
      * @param entry cache entry in question that has variants
-     * @return a <code>String</code> variant key
+     * @return a {@code String} variant key
      */
     public String getVariantKey(final HttpRequest req, final HttpCacheEntry entry) {
         final List<String> variantHeaderNames = new ArrayList<String>();
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java
index ec7390f..7690e8a 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheValidityPolicy.java
@@ -174,7 +174,7 @@ class CacheValidityPolicy {
     /**
      * @deprecated (4.3) use {@link HttpCacheEntry#getDate()}.
      * @param entry
-     * @return the Date of the entry
+     * @return
      */
     @Deprecated
     protected Date getDateValue(final HttpCacheEntry entry) {
@@ -214,7 +214,8 @@ class CacheValidityPolicy {
      * @return boolean indicating whether actual length matches Content-Length
      */
     protected boolean contentLengthHeaderMatchesActualLength(final HttpCacheEntry entry) {
-        return !hasContentLengthHeader(entry) || getContentLengthValue(entry) == entry.getResource().length();
+        return !hasContentLengthHeader(entry) ||
+                (entry.getResource() != null && getContentLengthValue(entry) == entry.getResource().length());
     }
 
     protected long getApparentAgeSecs(final HttpCacheEntry entry) {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java
index f10ff3a..d787703 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheableRequestPolicy.java
@@ -62,8 +62,9 @@ class CacheableRequestPolicy {
             return false;
         }
 
-        if (!method.equals(HeaderConstants.GET_METHOD)) {
-            log.trace("non-GET request was not serveable from cache");
+        if (!(method.equals(HeaderConstants.GET_METHOD) || method
+                .equals(HeaderConstants.HEAD_METHOD))) {
+            log.trace("non-GET or non-HEAD request was not serveable from cache");
             return false;
         }
 
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java
index 523c28f..f74a2e4 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedHttpResponseGenerator.java
@@ -37,6 +37,7 @@ import org.apache.http.annotation.Immutable;
 import org.apache.http.client.cache.HeaderConstants;
 import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.utils.DateUtils;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicHttpResponse;
@@ -64,19 +65,18 @@ class CachedHttpResponseGenerator {
     /**
      * If I was able to use a {@link CacheEntity} to response to the {@link org.apache.http.HttpRequest} then
      * generate an {@link HttpResponse} based on the cache entry.
-     * @param entry
-     *            {@link CacheEntity} to transform into an {@link HttpResponse}
+     * @param request {@link HttpRequestWrapper} to generate the response for
+     * @param entry {@link CacheEntity} to transform into an {@link HttpResponse}
      * @return {@link HttpResponse} that was constructed
      */
-    CloseableHttpResponse generateResponse(final HttpCacheEntry entry) {
-
+    CloseableHttpResponse generateResponse(final HttpRequestWrapper request, final HttpCacheEntry entry) {
         final Date now = new Date();
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, entry
                 .getStatusCode(), entry.getReasonPhrase());
 
         response.setHeaders(entry.getAllHeaders());
 
-        if (entry.getResource() != null) {
+        if (responseShouldContainEntity(request, entry)) {
             final HttpEntity entity = new CacheEntity(entry);
             addMissingContentLengthHeader(response, entity);
             response.setEntity(entity);
@@ -163,4 +163,10 @@ class CachedHttpResponseGenerator {
         final Header hdr = response.getFirstHeader(HTTP.TRANSFER_ENCODING);
         return hdr != null;
     }
+
+    private boolean responseShouldContainEntity(final HttpRequestWrapper request, final HttpCacheEntry cacheEntry) {
+        return request.getRequestLine().getMethod().equals(HeaderConstants.GET_METHOD) &&
+               cacheEntry.getResource() != null;
+    }
+
 }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java
index 7391a72..e7c940c 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachedResponseSuitabilityChecker.java
@@ -143,13 +143,12 @@ class CachedResponseSuitabilityChecker {
      * @return boolean yes/no answer
      */
     public boolean canCachedResponseBeUsed(final HttpHost host, final HttpRequest request, final HttpCacheEntry entry, final Date now) {
-
         if (!isFreshEnough(entry, request, now)) {
             log.trace("Cache entry was not fresh enough");
             return false;
         }
 
-        if (!validityStrategy.contentLengthHeaderMatchesActualLength(entry)) {
+        if (isGet(request) && !validityStrategy.contentLengthHeaderMatchesActualLength(entry)) {
             log.debug("Cache entry Content-Length and header information do not match");
             return false;
         }
@@ -160,13 +159,19 @@ class CachedResponseSuitabilityChecker {
         }
 
         if (!isConditional(request) && entry.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
-        return false;
+            return false;
         }
 
         if (isConditional(request) && !allConditionalsMatch(request, entry, now)) {
             return false;
         }
 
+        if (hasUnsupportedCacheEntryForGet(request, entry)) {
+            log.debug("HEAD response caching enabled but the cache entry does not contain a " +
+                      "request method, entity or a 204 response");
+            return false;
+        }
+
         for (final Header ccHdr : request.getHeaders(HeaderConstants.CACHE_CONTROL)) {
             for (final HeaderElement elt : ccHdr.getElements()) {
                 if (HeaderConstants.CACHE_CONTROL_NO_CACHE.equals(elt.getName())) {
@@ -233,6 +238,22 @@ class CachedResponseSuitabilityChecker {
         return true;
     }
 
+    private boolean isGet(final HttpRequest request) {
+        return request.getRequestLine().getMethod().equals(HeaderConstants.GET_METHOD);
+    }
+
+    private boolean entryIsNotA204Response(final HttpCacheEntry entry) {
+        return entry.getStatusCode() != HttpStatus.SC_NO_CONTENT;
+    }
+
+    private boolean cacheEntryDoesNotContainMethodAndEntity(final HttpCacheEntry entry) {
+        return entry.getRequestMethod() == null && entry.getResource() == null;
+    }
+
+    private boolean hasUnsupportedCacheEntryForGet(final HttpRequest request, final HttpCacheEntry entry) {
+        return isGet(request) && cacheEntryDoesNotContainMethodAndEntity(entry) && entryIsNotA204Response(entry);
+    }
+
     /**
      * Is this request the type of conditional request we support?
      * @param request The current httpRequest being made
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java
index f088157..d9c63dd 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java
@@ -27,6 +27,8 @@
 package org.apache.http.impl.client.cache;
 
 import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -44,6 +46,7 @@ import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolException;
 import org.apache.http.ProtocolVersion;
 import org.apache.http.RequestLine;
 import org.apache.http.annotation.ThreadSafe;
@@ -58,21 +61,28 @@ import org.apache.http.client.methods.HttpExecutionAware;
 import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.client.utils.DateUtils;
+import org.apache.http.client.utils.URIUtils;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.impl.execchain.ClientExecChain;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.protocol.HTTP;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.util.Args;
 import org.apache.http.util.VersionInfo;
 
 /**
+ * <p>
  * Request executor in the request execution chain that is responsible for
- * transparent client-side caching. The current implementation is conditionally
+ * transparent client-side caching.
+ * </p>
+ * <p>
+ * The current implementation is conditionally
  * compliant with HTTP/1.1 (meaning all the MUST and MUST NOTs are obeyed),
  * although quite a lot, though not all, of the SHOULDs and SHOULD NOTs
  * are obeyed too.
- * <p/>
+ * </p>
+ * <p>
  * Folks that would like to experiment with alternative storage backends
  * should look at the {@link HttpCacheStorage} interface and the related
  * package documentation there. You may also be interested in the provided
@@ -80,10 +90,12 @@ import org.apache.http.util.VersionInfo;
  * EhCache} and {@link
  * org.apache.http.impl.client.cache.memcached.MemcachedHttpCacheStorage
  * memcached} storage backends.
- * <p/>
+ * </p>
+ * <p>
  * Further responsibilities such as communication with the opposite
  * endpoint is delegated to the next executor in the request execution
  * chain.
+ * </p>
  *
  * @since 4.3
  */
@@ -224,6 +236,7 @@ public class CachingExec implements ClientExecChain {
         return execute(route, request, context, null);
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
@@ -290,10 +303,10 @@ public class CachingExec implements ClientExecChain {
             return callBackend(route, request, context, execAware);
         }
         context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
-        context.setAttribute(HttpClientContext.HTTP_TARGET_HOST, target);
-        context.setAttribute(HttpClientContext.HTTP_REQUEST, request);
-        context.setAttribute(HttpClientContext.HTTP_RESPONSE, out);
-        context.setAttribute(HttpClientContext.HTTP_REQ_SENT, Boolean.TRUE);
+        context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
+        context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
+        context.setAttribute(HttpCoreContext.HTTP_RESPONSE, out);
+        context.setAttribute(HttpCoreContext.HTTP_REQ_SENT, Boolean.TRUE);
         return out;
     }
 
@@ -335,7 +348,7 @@ public class CachingExec implements ClientExecChain {
         }
 
         final Map<String, Variant> variants = getExistingCacheVariants(target, request);
-        if (variants != null && variants.size() > 0) {
+        if (variants != null && !variants.isEmpty()) {
             return negotiateResponseFromVariants(route, request, context,
                     execAware, variants);
         }
@@ -417,7 +430,7 @@ public class CachingExec implements ClientExecChain {
                 || request.containsHeader(HeaderConstants.IF_MODIFIED_SINCE)) {
             cachedResponse = responseGenerator.generateNotModifiedResponse(entry);
         } else {
-            cachedResponse = responseGenerator.generateResponse(entry);
+            cachedResponse = responseGenerator.generateResponse(request, entry);
         }
         setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
         if (validityPolicy.getStalenessSecs(entry, now) > 0L) {
@@ -434,7 +447,7 @@ public class CachingExec implements ClientExecChain {
         if (staleResponseNotAllowed(request, entry, now)) {
             return generateGatewayTimeout(context);
         } else {
-            return unvalidatedCacheHit(context, entry);
+            return unvalidatedCacheHit(request, context, entry);
         }
     }
 
@@ -447,8 +460,10 @@ public class CachingExec implements ClientExecChain {
     }
 
     private CloseableHttpResponse unvalidatedCacheHit(
-            final HttpContext context, final HttpCacheEntry entry) {
-        final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(entry);
+            final HttpRequestWrapper request,
+            final HttpContext context,
+            final HttpCacheEntry entry) {
+        final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(request, entry);
         setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
         cachedResponse.addHeader(HeaderConstants.WARNING, "111 localhost \"Revalidation failed\"");
         return cachedResponse;
@@ -513,12 +528,14 @@ public class CachingExec implements ClientExecChain {
         final String release = (vi != null) ? vi.getRelease() : VersionInfo.UNAVAILABLE;
 
         String value;
+        final int major = pv.getMajor();
+        final int minor = pv.getMinor();
         if ("http".equalsIgnoreCase(pv.getProtocol())) {
-            value = String.format("%d.%d localhost (Apache-HttpClient/%s (cache))", pv.getMajor(), pv.getMinor(),
+            value = String.format("%d.%d localhost (Apache-HttpClient/%s (cache))", major, minor,
                     release);
         } else {
-            value = String.format("%s/%d.%d localhost (Apache-HttpClient/%s (cache))", pv.getProtocol(), pv.getMajor(),
-                    pv.getMinor(), release);
+            value = String.format("%s/%d.%d localhost (Apache-HttpClient/%s (cache))", pv.getProtocol(), major,
+                    minor, release);
         }
         viaHeaders.put(pv, value);
 
@@ -575,8 +592,8 @@ public class CachingExec implements ClientExecChain {
         final CloseableHttpResponse backendResponse = backend.execute(route, request, context, execAware);
         try {
             backendResponse.addHeader("Via", generateViaHeader(backendResponse));
-            return handleBackendResponse(route, request, context, execAware,
-                    requestDate, getCurrentDate(), backendResponse);
+            return handleBackendResponse(request, context, requestDate, getCurrentDate(),
+                    backendResponse);
         } catch (final IOException ex) {
             backendResponse.close();
             throw ex;
@@ -625,9 +642,8 @@ public class CachingExec implements ClientExecChain {
             backendResponse.addHeader("Via", generateViaHeader(backendResponse));
 
             if (backendResponse.getStatusLine().getStatusCode() != HttpStatus.SC_NOT_MODIFIED) {
-                return handleBackendResponse(
-                        route, request, context, execAware,
-                        requestDate, responseDate, backendResponse);
+                return handleBackendResponse(request, context, requestDate, responseDate,
+                        backendResponse);
             }
 
             final Header resultEtagHeader = backendResponse.getFirstHeader(HeaderConstants.ETAG);
@@ -662,7 +678,7 @@ public class CachingExec implements ClientExecChain {
                     backendResponse, matchingVariant, matchedEntry);
             backendResponse.close();
 
-            final CloseableHttpResponse resp = responseGenerator.generateResponse(responseEntry);
+            final CloseableHttpResponse resp = responseGenerator.generateResponse(request, responseEntry);
             tryToUpdateVariantMap(context.getTargetHost(), request, matchingVariant);
 
             if (shouldSendNotModifiedResponse(request, responseEntry)) {
@@ -735,6 +751,14 @@ public class CachingExec implements ClientExecChain {
             final HttpCacheEntry cacheEntry) throws IOException, HttpException {
 
         final HttpRequestWrapper conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(request, cacheEntry);
+        final URI uri = conditionalRequest.getURI();
+        if (uri != null) {
+            try {
+                conditionalRequest.setURI(URIUtils.rewriteURIForRoute(uri, route));
+            } catch (final URISyntaxException ex) {
+                throw new ProtocolException("Invalid URI: " + uri, ex);
+            }
+        }
 
         Date requestDate = getCurrentDate();
         CloseableHttpResponse backendResponse = backend.execute(
@@ -766,23 +790,22 @@ public class CachingExec implements ClientExecChain {
                 return responseGenerator
                         .generateNotModifiedResponse(updatedEntry);
             }
-            return responseGenerator.generateResponse(updatedEntry);
+            return responseGenerator.generateResponse(request, updatedEntry);
         }
 
         if (staleIfErrorAppliesTo(statusCode)
             && !staleResponseNotAllowed(request, cacheEntry, getCurrentDate())
             && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
             try {
-                final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry);
+                final CloseableHttpResponse cachedResponse = responseGenerator.generateResponse(request, cacheEntry);
                 cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
                 return cachedResponse;
             } finally {
                 backendResponse.close();
             }
         }
-        return handleBackendResponse(
-                route, conditionalRequest, context, execAware,
-                requestDate, responseDate, backendResponse);
+        return handleBackendResponse(conditionalRequest, context, requestDate, responseDate,
+                backendResponse);
     }
 
     private boolean staleIfErrorAppliesTo(final int statusCode) {
@@ -793,10 +816,8 @@ public class CachingExec implements ClientExecChain {
     }
 
     CloseableHttpResponse handleBackendResponse(
-            final HttpRoute route,
             final HttpRequestWrapper request,
             final HttpClientContext context,
-            final HttpExecutionAware execAware,
             final Date requestDate,
             final Date responseDate,
             final CloseableHttpResponse backendResponse) throws IOException {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java
index 04377de..e5b66b7 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClientBuilder.java
@@ -26,7 +26,9 @@
  */
 package org.apache.http.impl.client.cache;
 
+import java.io.Closeable;
 import java.io.File;
+import java.io.IOException;
 
 import org.apache.http.client.cache.HttpCacheInvalidator;
 import org.apache.http.client.cache.HttpCacheStorage;
@@ -48,6 +50,7 @@ public class CachingHttpClientBuilder extends HttpClientBuilder {
     private CacheConfig cacheConfig;
     private SchedulingStrategy schedulingStrategy;
     private HttpCacheInvalidator httpCacheInvalidator;
+    private boolean deleteCache;
 
     public static CachingHttpClientBuilder create() {
         return new CachingHttpClientBuilder();
@@ -55,6 +58,7 @@ public class CachingHttpClientBuilder extends HttpClientBuilder {
 
     protected CachingHttpClientBuilder() {
         super();
+        this.deleteCache = true;
     }
 
     public final CachingHttpClientBuilder setResourceFactory(
@@ -93,25 +97,42 @@ public class CachingHttpClientBuilder extends HttpClientBuilder {
         return this;
     }
 
+    public CachingHttpClientBuilder setDeleteCache(final boolean deleteCache) {
+        this.deleteCache = deleteCache;
+        return this;
+    }
+
     @Override
     protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
         final CacheConfig config = this.cacheConfig != null ? this.cacheConfig : CacheConfig.DEFAULT;
-        ResourceFactory resourceFactory = this.resourceFactory;
-        if (resourceFactory == null) {
+        // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
+        ResourceFactory resourceFactoryCopy = this.resourceFactory;
+        if (resourceFactoryCopy == null) {
             if (this.cacheDir == null) {
-                resourceFactory = new HeapResourceFactory();
+                resourceFactoryCopy = new HeapResourceFactory();
             } else {
-                resourceFactory = new FileResourceFactory(cacheDir);
+                resourceFactoryCopy = new FileResourceFactory(cacheDir);
             }
         }
-        HttpCacheStorage storage = this.storage;
-        if (storage == null) {
+        HttpCacheStorage storageCopy = this.storage;
+        if (storageCopy == null) {
             if (this.cacheDir == null) {
-                storage = new BasicHttpCacheStorage(config);
+                storageCopy = new BasicHttpCacheStorage(config);
             } else {
                 final ManagedHttpCacheStorage managedStorage = new ManagedHttpCacheStorage(config);
-                addCloseable(managedStorage);
-                storage = managedStorage;
+                if (this.deleteCache) {
+                    addCloseable(new Closeable() {
+
+                        @Override
+                        public void close() throws IOException {
+                            managedStorage.shutdown();
+                        }
+
+                    });
+                } else {
+                    addCloseable(managedStorage);
+                }
+                storageCopy = managedStorage;
             }
         }
         final AsynchronousValidator revalidator = createAsynchronousRevalidator(config);
@@ -119,13 +140,13 @@ public class CachingHttpClientBuilder extends HttpClientBuilder {
 
         HttpCacheInvalidator cacheInvalidator = this.httpCacheInvalidator;
         if (cacheInvalidator == null) {
-            cacheInvalidator = new CacheInvalidator(uriExtractor, storage);
+            cacheInvalidator = new CacheInvalidator(uriExtractor, storageCopy);
         }
 
         return new CachingExec(mainExec,
                 new BasicHttpCache(
-                        resourceFactory,
-                        storage, config,
+                        resourceFactoryCopy,
+                        storageCopy, config,
                         uriExtractor,
                         cacheInvalidator), config, revalidator);
     }
@@ -141,7 +162,6 @@ public class CachingHttpClientBuilder extends HttpClientBuilder {
         return null;
     }
 
-    @SuppressWarnings("resource")
     private SchedulingStrategy createSchedulingStrategy(final CacheConfig config) {
         return schedulingStrategy != null ? schedulingStrategy : new ImmediateSchedulingStrategy(config);
     }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedEntity.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedEntity.java
index 8ce4afb..a4cd65c 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedEntity.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedEntity.java
@@ -50,22 +50,27 @@ class CombinedEntity extends AbstractHttpEntity {
                 new ResourceStream(resource.getInputStream()), instream);
     }
 
+    @Override
     public long getContentLength() {
         return -1;
     }
 
+    @Override
     public boolean isRepeatable() {
         return false;
     }
 
+    @Override
     public boolean isStreaming() {
         return true;
     }
 
+    @Override
     public InputStream getContent() throws IOException, IllegalStateException {
         return this.combinedStream;
     }
 
+    @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         Args.notNull(outstream, "Output stream");
         final InputStream instream = getContent();
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java
index 2a0d1a9..c0626fa 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java
@@ -64,6 +64,7 @@ public class DefaultFailureCache implements FailureCache {
         this.storage = new ConcurrentHashMap<String, FailureCacheValue>();
     }
 
+    @Override
     public int getErrorCount(final String identifier) {
         if (identifier == null) {
             throw new IllegalArgumentException("identifier may not be null");
@@ -72,6 +73,7 @@ public class DefaultFailureCache implements FailureCache {
         return storedErrorCode != null ? storedErrorCode.getErrorCount() : 0;
     }
 
+    @Override
     public void resetErrorCount(final String identifier) {
         if (identifier == null) {
             throw new IllegalArgumentException("identifier may not be null");
@@ -79,6 +81,7 @@ public class DefaultFailureCache implements FailureCache {
         storage.remove(identifier);
     }
 
+    @Override
     public void increaseErrorCount(final String identifier) {
         if (identifier == null) {
             throw new IllegalArgumentException("identifier may not be null");
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java
index ea7f087..f84501b 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultHttpCacheEntrySerializer.java
@@ -48,6 +48,7 @@ import org.apache.http.client.cache.HttpCacheEntrySerializer;
 @Immutable
 public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer {
 
+    @Override
     public void writeTo(final HttpCacheEntry cacheEntry, final OutputStream os) throws IOException {
         final ObjectOutputStream oos = new ObjectOutputStream(os);
         try {
@@ -57,6 +58,7 @@ public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer
         }
     }
 
+    @Override
     public HttpCacheEntry readFrom(final InputStream is) throws IOException {
         final ObjectInputStream ois = new ObjectInputStream(is);
         try {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ExponentialBackOffSchedulingStrategy.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ExponentialBackOffSchedulingStrategy.java
index ee7e41a..21b644f 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ExponentialBackOffSchedulingStrategy.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ExponentialBackOffSchedulingStrategy.java
@@ -27,6 +27,7 @@
 package org.apache.http.impl.client.cache;
 
 import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.util.Args;
 
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -48,7 +49,8 @@ import java.util.concurrent.TimeUnit;
  *
  * The following equation is used to calculate the delay for a specific revalidation request:
  * <pre>
- *     delay = {@link #getInitialExpiryInMillis()} * Math.pow({@link #getBackOffRate()}, {@link AsynchronousValidationRequest#getConsecutiveFailedAttempts()} - 1))
+ *     delay = {@link #getInitialExpiryInMillis()} * Math.pow({@link #getBackOffRate()},
+ *     {@link AsynchronousValidationRequest#getConsecutiveFailedAttempts()} - 1))
  * </pre>
  * The resulting delay won't exceed {@link #getMaxExpiryInMillis()}.
  *
@@ -69,7 +71,7 @@ public class ExponentialBackOffSchedulingStrategy implements SchedulingStrategy
 
     /**
      * Create a new scheduling strategy using a fixed pool of worker threads.
-     * @param cacheConfig the thread pool configuration to be used; not <code>null</code>
+     * @param cacheConfig the thread pool configuration to be used; not {@code null}
      * @see org.apache.http.impl.client.cache.CacheConfig#getAsynchronousWorkersMax()
      * @see #DEFAULT_BACK_OFF_RATE
      * @see #DEFAULT_INITIAL_EXPIRY_IN_MILLIS
@@ -86,7 +88,7 @@ public class ExponentialBackOffSchedulingStrategy implements SchedulingStrategy
      * Create a new scheduling strategy by using a fixed pool of worker threads and the
      * given parameters to calculated the delay.
      *
-     * @param cacheConfig the thread pool configuration to be used; not <code>null</code>
+     * @param cacheConfig the thread pool configuration to be used; not {@code null}
      * @param backOffRate the back off rate to be used; not negative
      * @param initialExpiryInMillis the initial expiry in milli seconds; not negative
      * @param maxExpiryInMillis the upper limit of the delay in milli seconds; not negative
@@ -117,20 +119,22 @@ public class ExponentialBackOffSchedulingStrategy implements SchedulingStrategy
             final long backOffRate,
             final long initialExpiryInMillis,
             final long maxExpiryInMillis) {
-        this.executor = checkNotNull("executor", executor);
-        this.backOffRate = checkNotNegative("backOffRate", backOffRate);
-        this.initialExpiryInMillis = checkNotNegative("initialExpiryInMillis", initialExpiryInMillis);
-        this.maxExpiryInMillis = checkNotNegative("maxExpiryInMillis", maxExpiryInMillis);
+        this.executor = Args.notNull(executor, "Executor");
+        this.backOffRate = Args.notNegative(backOffRate, "BackOffRate");
+        this.initialExpiryInMillis = Args.notNegative(initialExpiryInMillis, "InitialExpiryInMillis");
+        this.maxExpiryInMillis = Args.notNegative(maxExpiryInMillis, "MaxExpiryInMillis");
     }
 
+    @Override
     public void schedule(
             final AsynchronousValidationRequest revalidationRequest) {
-        checkNotNull("revalidationRequest", revalidationRequest);
+        Args.notNull(revalidationRequest, "RevalidationRequest");
         final int consecutiveFailedAttempts = revalidationRequest.getConsecutiveFailedAttempts();
         final long delayInMillis = calculateDelayInMillis(consecutiveFailedAttempts);
         executor.schedule(revalidationRequest, delayInMillis, TimeUnit.MILLISECONDS);
     }
 
+    @Override
     public void close() {
         executor.shutdown();
     }
@@ -158,6 +162,10 @@ public class ExponentialBackOffSchedulingStrategy implements SchedulingStrategy
         }
     }
 
+    /**
+     * @deprecated Use {@link org.apache.http.util.Args#notNull(Object, String)}
+     */
+    @Deprecated
     protected static <T> T checkNotNull(final String parameterName, final T value) {
         if (value == null) {
             throw new IllegalArgumentException(parameterName + " may not be null");
@@ -165,6 +173,10 @@ public class ExponentialBackOffSchedulingStrategy implements SchedulingStrategy
         return value;
     }
 
+    /**
+     * @deprecated Use {@link org.apache.http.util.Args#notNegative(long, String)}
+     */
+    @Deprecated
     protected static long checkNotNegative(final String parameterName, final long value) {
         if (value < 0) {
             throw new IllegalArgumentException(parameterName + " may not be negative");
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java
index 03e2d5f..eef9c9a 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java
@@ -58,14 +58,17 @@ public class FileResource implements Resource {
         return this.file;
     }
 
+    @Override
     public synchronized InputStream getInputStream() throws IOException {
         return new FileInputStream(this.file);
     }
 
+    @Override
     public synchronized long length() {
         return this.file.length();
     }
 
+    @Override
     public synchronized void dispose() {
         if (this.disposed) {
             return;
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java
index 0f33154..f2c717c 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java
@@ -69,6 +69,7 @@ public class FileResourceFactory implements ResourceFactory {
         return new File(this.cacheDir, buffer.toString());
     }
 
+    @Override
     public Resource generate(
             final String requestId,
             final InputStream instream,
@@ -93,6 +94,7 @@ public class FileResourceFactory implements ResourceFactory {
         return new FileResource(file);
     }
 
+    @Override
     public Resource copy(
             final String requestId,
             final Resource resource) throws IOException {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResource.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResource.java
index 181d1ce..edf6b0f 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResource.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResource.java
@@ -53,14 +53,17 @@ public class HeapResource implements Resource {
         return this.b;
     }
 
+    @Override
     public InputStream getInputStream() {
         return new ByteArrayInputStream(this.b);
     }
 
+    @Override
     public long length() {
         return this.b.length;
     }
 
+    @Override
     public void dispose() {
     }
 
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java
index 8b0ce52..87a1b2a 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java
@@ -43,6 +43,7 @@ import org.apache.http.client.cache.ResourceFactory;
 @Immutable
 public class HeapResourceFactory implements ResourceFactory {
 
+    @Override
     public Resource generate(
             final String requestId,
             final InputStream instream,
@@ -62,6 +63,7 @@ public class HeapResourceFactory implements ResourceFactory {
         return createResource(outstream.toByteArray());
     }
 
+    @Override
     public Resource copy(
             final String requestId,
             final Resource resource) throws IOException {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java
index e1011b5..2689786 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java
@@ -83,7 +83,7 @@ interface HttpCache {
      * {@link Map} is returned
      * @param host
      * @param request
-     * @return a <code>Map</code> mapping Etags to variant cache entries
+     * @return a {@code Map} mapping Etags to variant cache entries
      * @throws IOException
      */
     Map<String,Variant> getVariantCacheEntriesWithEtags(HttpHost host, HttpRequest request)
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ImmediateSchedulingStrategy.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ImmediateSchedulingStrategy.java
index 9349ade..263c6b3 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ImmediateSchedulingStrategy.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ImmediateSchedulingStrategy.java
@@ -27,6 +27,7 @@
 package org.apache.http.impl.client.cache;
 
 import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.util.Args;
 
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ExecutorService;
@@ -67,14 +68,13 @@ public class ImmediateSchedulingStrategy implements SchedulingStrategy {
         this.executor = executor;
     }
 
+    @Override
     public void schedule(final AsynchronousValidationRequest revalidationRequest) {
-        if (revalidationRequest == null) {
-            throw new IllegalArgumentException("AsynchronousValidationRequest may not be null");
-        }
-
+        Args.notNull(revalidationRequest, "AsynchronousValidationRequest");
         executor.execute(revalidationRequest);
     }
 
+    @Override
     public void close() {
         executor.shutdown();
     }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCacheStorage.java
index 44e333f..0a02658 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCacheStorage.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ManagedHttpCacheStorage.java
@@ -41,17 +41,32 @@ import org.apache.http.client.cache.Resource;
 import org.apache.http.util.Args;
 
 /**
+ * <p>
  * {@link HttpCacheStorage} implementation capable of deallocating resources associated with
- * the cache entries. This cache keeps track of cache entries using
+ * the cache entries.
+ * <p>
+ * This cache keeps track of cache entries using
  * {@link java.lang.ref.PhantomReference} and maintains a collection of all resources that
  * are no longer in use. The cache, however, does not automatically deallocates associated
  * resources by invoking {@link Resource#dispose()} method. The consumer MUST periodically
  * call {@link #cleanResources()} method to trigger resource deallocation. The cache can be
  * permanently shut down using {@link #shutdown()} method. All resources associated with
  * the entries used by the cache will be deallocated.
- *
+ * </p>
+ * <p>
  * This {@link HttpCacheStorage} implementation is intended for use with {@link FileResource}
  * and similar.
+ * </p>
+ * <p>
+ * Compatibility note. Prior to version 4.4 this storage implementation used to dispose of
+ * all resource entries upon {@link #close()}. As of version 4.4 the {@link #close()} method
+ * disposes only of those resources that have been explicitly removed from the cache with
+ * {@link #removeEntry(String)} method.
+ * </p>
+ * <p>
+ * The {@link #shutdown()} ()} method can still be used to shut down the storage and dispose of
+ * all resources currently managed by it.
+ * </p>
  *
  * @since 4.1
  */
@@ -86,6 +101,7 @@ public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {
         }
     }
 
+    @Override
     public void putEntry(final String url, final HttpCacheEntry entry) throws IOException {
         Args.notNull(url, "URL");
         Args.notNull(entry, "Cache entry");
@@ -96,6 +112,7 @@ public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {
         }
     }
 
+    @Override
     public HttpCacheEntry getEntry(final String url) throws IOException {
         Args.notNull(url, "URL");
         ensureValidState();
@@ -104,6 +121,7 @@ public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {
         }
     }
 
+    @Override
     public void removeEntry(final String url) throws IOException {
         Args.notNull(url, "URL");
         ensureValidState();
@@ -114,6 +132,7 @@ public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {
         }
     }
 
+    @Override
     public void updateEntry(
             final String url,
             final HttpCacheUpdateCallback callback) throws IOException {
@@ -156,8 +175,17 @@ public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {
         }
     }
 
+    @Override
     public void close() {
-        shutdown();
+        if (this.active.compareAndSet(true, false)) {
+            synchronized (this) {
+                ResourceReference ref;
+                while ((ref = (ResourceReference) this.morque.poll()) != null) {
+                    this.resources.remove(ref);
+                    ref.getResource().dispose();
+                }
+            }
+        }
     }
 
 }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/OptionsHttp11Response.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/OptionsHttp11Response.java
index 704feca..2245360 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/OptionsHttp11Response.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/OptionsHttp11Response.java
@@ -53,46 +53,57 @@ final class OptionsHttp11Response extends AbstractHttpMessage implements HttpRes
             HttpStatus.SC_NOT_IMPLEMENTED, "");
     private final ProtocolVersion version = HttpVersion.HTTP_1_1;
 
+    @Override
     public StatusLine getStatusLine() {
         return statusLine;
     }
 
+    @Override
     public void setStatusLine(final StatusLine statusline) {
         // No-op on purpose, this class is not going to be doing any work.
     }
 
+    @Override
     public void setStatusLine(final ProtocolVersion ver, final int code) {
         // No-op on purpose, this class is not going to be doing any work.
     }
 
+    @Override
     public void setStatusLine(final ProtocolVersion ver, final int code, final String reason) {
         // No-op on purpose, this class is not going to be doing any work.
     }
 
+    @Override
     public void setStatusCode(final int code) throws IllegalStateException {
         // No-op on purpose, this class is not going to be doing any work.
     }
 
+    @Override
     public void setReasonPhrase(final String reason) throws IllegalStateException {
         // No-op on purpose, this class is not going to be doing any work.
     }
 
+    @Override
     public HttpEntity getEntity() {
         return null;
     }
 
+    @Override
     public void setEntity(final HttpEntity entity) {
         // No-op on purpose, this class is not going to be doing any work.
     }
 
+    @Override
     public Locale getLocale() {
         return null;
     }
 
+    @Override
     public void setLocale(final Locale loc) {
         // No-op on purpose, this class is not going to be doing any work.
     }
 
+    @Override
     public ProtocolVersion getProtocolVersion() {
         return version;
     }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java
index aed3f63..ae7a08b 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java
@@ -67,6 +67,7 @@ class ResponseCachingPolicy {
                 HttpStatus.SC_MOVED_PERMANENTLY,
                 HttpStatus.SC_GONE));
     private final Set<Integer> uncacheableStatuses;
+
     /**
      * Define a cache policy that limits the size of things that should be stored
      * in the cache to a maximum of {@link HttpResponse} bytes in size.
@@ -99,12 +100,13 @@ class ResponseCachingPolicy {
      *
      * @param httpMethod What type of request was this, a GET, PUT, other?
      * @param response The origin response
-     * @return <code>true</code> if response is cacheable
+     * @return {@code true} if response is cacheable
      */
     public boolean isResponseCacheable(final String httpMethod, final HttpResponse response) {
         boolean cacheable = false;
 
-        if (!HeaderConstants.GET_METHOD.equals(httpMethod)) {
+        if (!(HeaderConstants.GET_METHOD.equals(httpMethod) ||
+                HeaderConstants.HEAD_METHOD.equals(httpMethod))) {
             log.debug("Response was not cacheable.");
             return false;
         }
@@ -232,7 +234,7 @@ class ResponseCachingPolicy {
      *
      * @param request the {@link HttpRequest} that generated an origin hit
      * @param response the {@link HttpResponse} from the origin
-     * @return <code>true</code> if response is cacheable
+     * @return {@code true} if response is cacheable
      */
     public boolean isResponseCacheable(final HttpRequest request, final HttpResponse response) {
         if (requestProtocolGreaterThanAccepted(request)) {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java
index 9130d9b..26f3c9d 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProxyHandler.java
@@ -66,6 +66,7 @@ class ResponseProxyHandler implements InvocationHandler {
         IOUtils.consume(original.getEntity());
     }
 
+    @Override
     public Object invoke(
             final Object proxy, final Method method, final Object[] args) throws Throwable {
         if (method.equals(CLOSE_METHOD)) {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SchedulingStrategy.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SchedulingStrategy.java
index 4d2ba6c..c9e4fab 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SchedulingStrategy.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SchedulingStrategy.java
@@ -38,7 +38,7 @@ public interface SchedulingStrategy extends Closeable
     /**
      * Schedule an {@link AsynchronousValidationRequest} to be executed.
      *
-     * @param revalidationRequest the request to be executed; not <code>null</code>
+     * @param revalidationRequest the request to be executed; not {@code null}
      * @throws java.util.concurrent.RejectedExecutionException if the request could not be scheduled for execution
      */
     void schedule(AsynchronousValidationRequest revalidationRequest);
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/WarningValue.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/WarningValue.java
index 865e5b6..c9db1c6 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/WarningValue.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/WarningValue.java
@@ -66,7 +66,7 @@ class WarningValue {
      * skipped, in keeping with the philosophy of "ignore what you
      * cannot understand."
      * @param h Warning {@link Header} to parse
-     * @return array of <code>WarnValue</code> objects
+     * @return array of {@code WarnValue} objects
      */
     public static WarningValue[] getWarningValues(final Header h) {
         final List<WarningValue> out = new ArrayList<WarningValue>();
@@ -317,7 +317,7 @@ class WarningValue {
     }
 
     /** Returns the 3-digit code associated with this warning.
-     * @return <code>int</code>
+     * @return {@code int}
      */
     public int getWarnCode() { return warnCode; }
 
@@ -335,20 +335,20 @@ class WarningValue {
      * <pre>
      *   Warning: 110 fred "Response is stale"
      * </pre>
-     * then this method will return <code>"\"Response is stale\""</code>
+     * then this method will return {@code "\"Response is stale\""}
      * (surrounding quotes included).
      * @return {@link String}
      */
     public String getWarnText() { return warnText; }
 
     /** Returns the date and time when this warning was added, or
-     * <code>null</code> if a warning date was not supplied in the
+     * {@code null} if a warning date was not supplied in the
      * header.
      * @return {@link Date}
      */
     public Date getWarnDate() { return warnDate; }
 
-    /** Formats a <code>WarningValue</code> as a {@link String}
+    /** Formats a {@code WarningValue} as a {@link String}
      * suitable for including in a header. For example, you can:
      * <pre>
      *   WarningValue wv = ...;
@@ -360,10 +360,10 @@ class WarningValue {
     @Override
     public String toString() {
         if (warnDate != null) {
-            return String.format("%d %s %s \"%s\"", warnCode,
+            return String.format("%d %s %s \"%s\"", Integer.valueOf(warnCode),
                     warnAgent, warnText, DateUtils.formatDate(warnDate));
         } else {
-            return String.format("%d %s %s", warnCode, warnAgent, warnText);
+            return String.format("%d %s %s", Integer.valueOf(warnCode), warnAgent, warnText);
         }
     }
 
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java
index 56c0ced..d921027 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java
@@ -101,12 +101,14 @@ public class EhcacheHttpCacheStorage implements HttpCacheStorage {
         this.serializer = serializer;
     }
 
+    @Override
     public synchronized void putEntry(final String key, final HttpCacheEntry entry) throws IOException {
         final ByteArrayOutputStream bos = new ByteArrayOutputStream();
         serializer.writeTo(entry, bos);
         cache.put(new Element(key, bos.toByteArray()));
     }
 
+    @Override
     public synchronized HttpCacheEntry getEntry(final String key) throws IOException {
         final Element e = cache.get(key);
         if(e == null){
@@ -117,10 +119,12 @@ public class EhcacheHttpCacheStorage implements HttpCacheStorage {
         return serializer.readFrom(new ByteArrayInputStream(data));
     }
 
+    @Override
     public synchronized void removeEntry(final String key) {
         cache.remove(key);
     }
 
+    @Override
     public synchronized void updateEntry(final String key, final HttpCacheUpdateCallback callback)
             throws IOException, HttpCacheUpdateException {
         int numRetries = 0;
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntry.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntry.java
index 05739fd..80b346b 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntry.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntry.java
@@ -44,14 +44,14 @@ public interface MemcachedCacheEntry {
 
     /**
      * Returns the storage key associated with this entry. May return
-     * <code>null</code> if this is an "unset" instance waiting to be
+     * {@code null} if this is an "unset" instance waiting to be
      * {@link #set(byte[])} with a serialized representation.
      */
     String getStorageKey();
 
     /**
      * Returns the {@link HttpCacheEntry} associated with this entry.
-     * May return <code>null</code> if this is an "unset" instance
+     * May return {@code null} if this is an "unset" instance
      * waiting to be {@link #set(byte[])} with a serialized
      * representation.
      */
@@ -64,9 +64,10 @@ public interface MemcachedCacheEntry {
      * object should return updated (as appropriate) values for
      * {@link #getStorageKey()} and {@link #getHttpCacheEntry()}. This
      * should be viewed as an atomic operation on the
-     * <code>MemcachedCacheEntry</code>.
+     * {@code MemcachedCacheEntry}.
+     *
      * @param bytes serialized representation
-     * @throws {@link MemcachedSerializationException} if deserialization
+     * @throws MemcachedSerializationException if deserialization
      *   fails. In this case, the prior values for {{@link #getStorageKey()}
      *   and {@link #getHttpCacheEntry()} should remain unchanged.
      */
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactory.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactory.java
index 2cf7d1e..9bb1c2a 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactory.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactory.java
@@ -41,7 +41,7 @@ public interface MemcachedCacheEntryFactory {
      * we are hashing storage keys into cache keys to accommodate
      * limitations in memcached's key space, it is possible to have
      * cache collisions. Therefore, we store the storage key along
-     * with the <code>HttpCacheEntry</code> so it can be compared
+     * with the {@code HttpCacheEntry} so it can be compared
      * on retrieval and thus detect collisions.
      * @param storageKey storage key under which the entry will
      *   be logically stored
@@ -55,7 +55,7 @@ public interface MemcachedCacheEntryFactory {
      * Creates an "unset" {@link MemcachedCacheEntry} ready to accept
      * a serialized representation via {@link MemcachedCacheEntry#set(byte[])}
      * and deserialize it into a storage key and a {@link HttpCacheEntry}.
-     * @return <code>MemcachedCacheEntry</code>
+     * @return {@code MemcachedCacheEntry}
      */
     MemcachedCacheEntry getUnsetCacheEntry();
 
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactoryImpl.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactoryImpl.java
index dddcb92..c1d7595 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactoryImpl.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryFactoryImpl.java
@@ -33,10 +33,12 @@ import org.apache.http.client.cache.HttpCacheEntry;
  */
 public class MemcachedCacheEntryFactoryImpl implements MemcachedCacheEntryFactory {
 
+    @Override
     public MemcachedCacheEntry getMemcachedCacheEntry(final String key, final HttpCacheEntry entry) {
         return new MemcachedCacheEntryImpl(key, entry);
     }
 
+    @Override
     public MemcachedCacheEntry getUnsetCacheEntry() {
         return new MemcachedCacheEntryImpl(null, null);
     }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryImpl.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryImpl.java
index ec4b5c9..e1c4e37 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryImpl.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedCacheEntryImpl.java
@@ -55,6 +55,7 @@ public class MemcachedCacheEntryImpl implements MemcachedCacheEntry {
     /* (non-Javadoc)
      * @see org.apache.http.impl.client.cache.memcached.MemcachedCacheEntry#toByteArray()
      */
+    @Override
     synchronized public byte[] toByteArray() {
         final ByteArrayOutputStream bos = new ByteArrayOutputStream();
         ObjectOutputStream oos;
@@ -72,6 +73,7 @@ public class MemcachedCacheEntryImpl implements MemcachedCacheEntry {
     /* (non-Javadoc)
      * @see org.apache.http.impl.client.cache.memcached.MemcachedCacheEntry#getKey()
      */
+    @Override
     public synchronized String getStorageKey() {
         return key;
     }
@@ -79,6 +81,7 @@ public class MemcachedCacheEntryImpl implements MemcachedCacheEntry {
     /* (non-Javadoc)
      * @see org.apache.http.impl.client.cache.memcached.MemcachedCacheEntry#getHttpCacheEntry()
      */
+    @Override
     public synchronized HttpCacheEntry getHttpCacheEntry() {
         return httpCacheEntry;
     }
@@ -86,6 +89,7 @@ public class MemcachedCacheEntryImpl implements MemcachedCacheEntry {
     /* (non-Javadoc)
      * @see org.apache.http.impl.client.cache.memcached.MemcachedCacheEntry#set(byte[])
      */
+    @Override
     synchronized public void set(final byte[] bytes) {
         final ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
         ObjectInputStream ois;
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java
index 58820ab..39f703d 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java
@@ -45,41 +45,49 @@ import org.apache.http.client.cache.HttpCacheUpdateException;
 import org.apache.http.impl.client.cache.CacheConfig;
 
 /**
- * <p>This class is a storage backend that uses an external <i>memcached</i>
+ * <p>
+ * This class is a storage backend that uses an external <i>memcached</i>
  * for storing cached origin responses. This storage option provides a
  * couple of interesting advantages over the default in-memory storage
  * backend:
+ * </p>
  * <ol>
  * <li>in-memory cached objects can survive an application restart since
  * they are held in a separate process</li>
  * <li>it becomes possible for several cooperating applications to share
  * a large <i>memcached</i> farm together</li>
  * </ol>
+ * <p>
  * Note that in a shared memcached pool setting you may wish to make use
  * of the Ketama consistent hashing algorithm to reduce the number of
  * cache misses that might result if one of the memcached cluster members
  * fails (see the <a href="http://dustin.github.com/java-memcached-client/apidocs/net/spy/memcached/KetamaConnectionFactory.html">
  * KetamaConnectionFactory</a>).
  * </p>
- *
- * <p>Because memcached places limits on the size of its keys, we need to
+ * <p>
+ * Because memcached places limits on the size of its keys, we need to
  * introduce a key hashing scheme to map the annotated URLs the higher-level
  * caching HTTP client wants to use as keys onto ones that are suitable
  * for use with memcached. Please see {@link KeyHashingScheme} if you would
- * like to use something other than the provided {@link SHA256KeyHashingScheme}.</p>
+ * like to use something other than the provided {@link SHA256KeyHashingScheme}.
+ * </p>
  *
- * <p>Because this hashing scheme can potentially result in key collisions (though
+ * <p>
+ * Because this hashing scheme can potentially result in key collisions (though
  * highly unlikely), we need to store the higher-level logical storage key along
  * with the {@link HttpCacheEntry} so that we can re-check it on retrieval. There
  * is a default serialization scheme provided for this, although you can provide
  * your own implementations of {@link MemcachedCacheEntry} and
- * {@link MemcachedCacheEntryFactory} to customize this serialization.</p>
+ * {@link MemcachedCacheEntryFactory} to customize this serialization.
+ * </p>
  *
- * <p>Please refer to the <a href="http://code.google.com/p/memcached/wiki/NewStart">
+ * <p>
+ * Please refer to the <a href="http://code.google.com/p/memcached/wiki/NewStart">
  * memcached documentation</a> and in particular to the documentation for
  * the <a href="http://code.google.com/p/spymemcached/">spymemcached
  * documentation</a> for details about how to set up and configure memcached
- * and the Java client used here, respectively.</p>
+ * and the Java client used here, respectively.
+ * </p>
  *
  * @since 4.1
  */
@@ -158,6 +166,7 @@ public class MemcachedHttpCacheStorage implements HttpCacheStorage {
         this.keyHashingScheme = keyHashingScheme;
     }
 
+    @Override
     public void putEntry(final String url, final HttpCacheEntry entry) throws IOException  {
         final byte[] bytes = serializeEntry(url, entry);
         final String key = getCacheKey(url);
@@ -215,6 +224,7 @@ public class MemcachedHttpCacheStorage implements HttpCacheStorage {
         return mce;
     }
 
+    @Override
     public HttpCacheEntry getEntry(final String url) throws IOException {
         final String key = getCacheKey(url);
         if (key == null) {
@@ -231,6 +241,7 @@ public class MemcachedHttpCacheStorage implements HttpCacheStorage {
         }
     }
 
+    @Override
     public void removeEntry(final String url) throws IOException {
         final String key = getCacheKey(url);
         if (key == null) {
@@ -243,6 +254,7 @@ public class MemcachedHttpCacheStorage implements HttpCacheStorage {
         }
     }
 
+    @Override
     public void updateEntry(final String url, final HttpCacheUpdateCallback callback)
             throws HttpCacheUpdateException, IOException {
         int numRetries = 0;
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/PrefixKeyHashingScheme.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/PrefixKeyHashingScheme.java
index 62f4b01..58641d5 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/PrefixKeyHashingScheme.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/PrefixKeyHashingScheme.java
@@ -29,7 +29,7 @@ package org.apache.http.impl.client.cache.memcached;
 
 /**
  * This is a {@link KeyHashingScheme} decorator that simply adds
- * a known prefix to the results of another <code>KeyHashingScheme</code>.
+ * a known prefix to the results of another {@code KeyHashingScheme}.
  * Primarily useful for namespacing a shared memcached cluster, for
  * example.
  */
@@ -52,6 +52,7 @@ public class PrefixKeyHashingScheme implements KeyHashingScheme {
         this.backingScheme = backingScheme;
     }
 
+    @Override
     public String hash(final String storageKey) {
         return prefix + backingScheme.hash(storageKey);
     }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/SHA256KeyHashingScheme.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/SHA256KeyHashingScheme.java
index c07b123..a9a3964 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/SHA256KeyHashingScheme.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/SHA256KeyHashingScheme.java
@@ -44,6 +44,7 @@ public class SHA256KeyHashingScheme implements KeyHashingScheme {
 
     private static final Log log = LogFactory.getLog(SHA256KeyHashingScheme.class);
 
+    @Override
     public String hash(final String key) {
         final MessageDigest md = getDigest();
         md.update(key.getBytes());
diff --git a/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java b/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java
index b639737..6719a30 100644
--- a/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java
+++ b/httpclient-cache/src/test/java/org/apache/http/client/cache/TestHttpCacheEntry.java
@@ -26,7 +26,6 @@
  */
 package org.apache.http.client.cache;
 
-import static org.easymock.classextension.EasyMock.createNiceMock;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -34,6 +33,7 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 
 import java.util.Date;
 import java.util.HashMap;
@@ -65,12 +65,12 @@ public class TestHttpCacheEntry {
         nineSecondsAgo = new Date(now.getTime() - 9 * 1000L);
         statusLine = new BasicStatusLine(HttpVersion.HTTP_1_1,
                 HttpStatus.SC_OK, "OK");
-        mockResource = createNiceMock(Resource.class);
+        mockResource = mock(Resource.class);
     }
 
     private HttpCacheEntry makeEntry(final Header[] headers) {
         return new HttpCacheEntry(elevenSecondsAgo, nineSecondsAgo,
-                statusLine, headers, mockResource);
+                statusLine, headers, mockResource, HeaderConstants.GET_METHOD);
     }
 
     @Test
@@ -143,41 +143,45 @@ public class TestHttpCacheEntry {
         assertTrue(entry.hasVariants());
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void mustProvideRequestDate() {
         try {
             new HttpCacheEntry(null, new Date(), statusLine,
-                    new Header[]{}, mockResource);
+                    new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
             fail("Should have thrown exception");
         } catch (final IllegalArgumentException expected) {
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void mustProvideResponseDate() {
         try {
             new HttpCacheEntry(new Date(), null, statusLine,
-                    new Header[]{}, mockResource);
+                    new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
             fail("Should have thrown exception");
         } catch (final IllegalArgumentException expected) {
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void mustProvideStatusLine() {
         try {
             new HttpCacheEntry(new Date(), new Date(), null,
-                    new Header[]{}, mockResource);
+                    new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
             fail("Should have thrown exception");
         } catch (final IllegalArgumentException expected) {
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void mustProvideResponseHeaders() {
         try {
             new HttpCacheEntry(new Date(), new Date(), statusLine,
-                    null, mockResource);
+                    null, mockResource, HeaderConstants.GET_METHOD);
             fail("Should have thrown exception");
         } catch (final IllegalArgumentException expected) {
         }
@@ -186,14 +190,14 @@ public class TestHttpCacheEntry {
     @Test
     public void canRetrieveOriginalStatusLine() {
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertSame(statusLine, entry.getStatusLine());
     }
 
     @Test
     public void protocolVersionComesFromOriginalStatusLine() {
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertSame(statusLine.getProtocolVersion(),
                 entry.getProtocolVersion());
     }
@@ -201,14 +205,14 @@ public class TestHttpCacheEntry {
     @Test
     public void reasonPhraseComesFromOriginalStatusLine() {
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertSame(statusLine.getReasonPhrase(), entry.getReasonPhrase());
     }
 
     @Test
     public void statusCodeComesFromOriginalStatusLine() {
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertEquals(statusLine.getStatusCode(), entry.getStatusCode());
     }
 
@@ -216,7 +220,7 @@ public class TestHttpCacheEntry {
     public void canGetOriginalRequestDate() {
         final Date requestDate = new Date();
         entry = new HttpCacheEntry(requestDate, new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertSame(requestDate, entry.getRequestDate());
     }
 
@@ -224,14 +228,14 @@ public class TestHttpCacheEntry {
     public void canGetOriginalResponseDate() {
         final Date responseDate = new Date();
         entry = new HttpCacheEntry(new Date(), responseDate, statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertSame(responseDate, entry.getResponseDate());
     }
 
     @Test
     public void canGetOriginalResource() {
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertSame(mockResource, entry.getResource());
     }
 
@@ -242,7 +246,7 @@ public class TestHttpCacheEntry {
                 new BasicHeader("Date", DateUtils.formatDate(now))
         };
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                headers, mockResource);
+                headers, mockResource, HeaderConstants.GET_METHOD);
         final Header[] result = entry.getAllHeaders();
         assertEquals(headers.length, result.length);
         for(int i=0; i<headers.length; i++) {
@@ -250,17 +254,19 @@ public class TestHttpCacheEntry {
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void canConstructWithoutVariants() {
         new HttpCacheEntry(new Date(), new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void canProvideVariantMap() {
         new HttpCacheEntry(new Date(), new Date(), statusLine,
                 new Header[]{}, mockResource,
-                new HashMap<String,String>());
+                new HashMap<String,String>(), HeaderConstants.GET_METHOD);
     }
 
     @Test
@@ -270,7 +276,7 @@ public class TestHttpCacheEntry {
         variantMap.put("C","D");
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
                 new Header[]{}, mockResource,
-                variantMap);
+                variantMap, HeaderConstants.GET_METHOD);
         final Map<String,String> result = entry.getVariantMap();
         assertEquals(2, result.size());
         assertEquals("B", result.get("A"));
@@ -284,7 +290,7 @@ public class TestHttpCacheEntry {
         variantMap.put("C","D");
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
                 new Header[]{}, mockResource,
-                variantMap);
+                variantMap, HeaderConstants.GET_METHOD);
         final Map<String,String> result = entry.getVariantMap();
         try {
             result.remove("A");
@@ -301,7 +307,7 @@ public class TestHttpCacheEntry {
     @Test
     public void canConvertToString() {
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                new Header[]{}, mockResource);
+                new Header[]{}, mockResource, HeaderConstants.GET_METHOD);
         assertNotNull(entry.toString());
         assertFalse("".equals(entry.toString()));
     }
@@ -310,7 +316,7 @@ public class TestHttpCacheEntry {
     public void testMissingDateHeaderIsIgnored() {
         final Header[] headers = new Header[] {};
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                                   headers, mockResource);
+                                   headers, mockResource, HeaderConstants.GET_METHOD);
         assertNull(entry.getDate());
     }
 
@@ -318,21 +324,30 @@ public class TestHttpCacheEntry {
     public void testMalformedDateHeaderIsIgnored() {
         final Header[] headers = new Header[] { new BasicHeader("Date", "asdf") };
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                                   headers, mockResource);
+                                   headers, mockResource, HeaderConstants.GET_METHOD);
         assertNull(entry.getDate());
     }
 
     @Test
     public void testValidDateHeaderIsParsed() {
-        final long now = System.currentTimeMillis();
+        final long nowMs = System.currentTimeMillis();
         // round down to nearest second to make comparison easier
-        final Date date = new Date(now - (now % 1000L));
+        final Date date = new Date(nowMs - (nowMs % 1000L));
         final Header[] headers = new Header[] { new BasicHeader("Date", DateUtils.formatDate(date)) };
         entry = new HttpCacheEntry(new Date(), new Date(), statusLine,
-                                   headers, mockResource);
+                                   headers, mockResource, HeaderConstants.GET_METHOD);
         final Date dateHeaderValue = entry.getDate();
         assertNotNull(dateHeaderValue);
         assertEquals(date.getTime(), dateHeaderValue.getTime());
     }
 
+    @Test
+    public void testGetMethodReturnsCorrectRequestMethod() {
+        final Header[] headers = { new BasicHeader("foo", "fooValue"),
+                new BasicHeader("bar", "barValue1"),
+                new BasicHeader("bar", "barValue2")
+        };
+        entry = makeEntry(headers);
+        assertEquals(HeaderConstants.GET_METHOD, entry.getRequestMethod());
+    }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
index 3609324..9f85fcd 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java
@@ -42,7 +42,7 @@ import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.impl.execchain.ClientExecChain;
 import org.apache.http.message.BasicHttpRequest;
 import org.easymock.IExpectationSetters;
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
 import org.junit.Before;
 
 public abstract class AbstractProtocolTest {
@@ -79,7 +79,7 @@ public abstract class AbstractProtocolTest {
 
     @Before
     public void setUp() {
-        host = new HttpHost("foo.example.com");
+        host = new HttpHost("foo.example.com", 80);
 
         route = new HttpRoute(host);
 
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java
index c3108b7..9ea22b1 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/DummyBackend.java
@@ -55,6 +55,7 @@ public class DummyBackend implements ClientExecChain {
         return request;
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java
index da16d79..d1df505 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/HttpTestUtils.java
@@ -28,6 +28,7 @@ package org.apache.http.impl.client.cache;
 
 import java.io.InputStream;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Random;
 
@@ -41,6 +42,7 @@ import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
 import org.apache.http.RequestLine;
 import org.apache.http.StatusLine;
+import org.apache.http.client.cache.HeaderConstants;
 import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.utils.DateUtils;
 import org.apache.http.entity.ByteArrayEntity;
@@ -215,8 +217,8 @@ public class HttpTestUtils {
     }
 
     /*
-     * Assert.asserts that message <code>r2</code> represents exactly the same
-     * message as <code>r1</code>, except for hop-by-hop headers. "When a cache
+     * Assert.asserts that message {@code r2} represents exactly the same
+     * message as {@code r1}, except for hop-by-hop headers. "When a cache
      * is semantically transparent, the client receives exactly the same
      * response (except for hop-by-hop headers) that it would have received had
      * its request been handled directly by the origin server."
@@ -299,8 +301,7 @@ public class HttpTestUtils {
     public static HttpCacheEntry makeCacheEntry(final Date requestDate,
             final Date responseDate, final Header[] headers, final byte[] bytes,
             final Map<String,String> variantMap) {
-        final StatusLine statusLine = new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
-        return new HttpCacheEntry(requestDate, responseDate, statusLine, headers, new HeapResource(bytes), variantMap);
+        return new HttpCacheEntry(requestDate, responseDate, makeStatusLine(), headers, new HeapResource(bytes), variantMap, HeaderConstants.GET_METHOD);
     }
 
     public static HttpCacheEntry makeCacheEntry(final Header[] headers, final byte[] bytes) {
@@ -321,6 +322,39 @@ public class HttpTestUtils {
         return makeCacheEntry(now, now);
     }
 
+    public static HttpCacheEntry makeCacheEntryWithNoRequestMethodOrEntity(final Header[] headers) {
+        final Date now = new Date();
+        return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, null);
+    }
+
+    public static HttpCacheEntry makeCacheEntryWithNoRequestMethod(final Header[] headers) {
+        final Date now = new Date();
+        return new HttpCacheEntry(now, now, makeStatusLine(), headers, new HeapResource(getRandomBytes(128)), null, null);
+    }
+
+    public static HttpCacheEntry make204CacheEntryWithNoRequestMethod(final Header[] headers) {
+        final Date now = new Date();
+        return new HttpCacheEntry(now, now, make204StatusLine(), headers, null, null, HeaderConstants.HEAD_METHOD);
+    }
+
+    public static HttpCacheEntry makeHeadCacheEntry(final Header[] headers) {
+        final Date now = new Date();
+        return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, HeaderConstants.HEAD_METHOD);
+    }
+
+    public static HttpCacheEntry makeHeadCacheEntryWithNoRequestMethod(final Header[] headers) {
+        final Date now = new Date();
+        return new HttpCacheEntry(now, now, makeStatusLine(), headers, null, null, null);
+    }
+
+    public static StatusLine makeStatusLine() {
+        return new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
+    }
+
+    public static StatusLine make204StatusLine() {
+        return new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "OK");
+    }
+
     public static HttpResponse make200Response() {
         final HttpResponse out = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
         out.setHeader("Date", DateUtils.formatDate(new Date()));
@@ -356,8 +390,19 @@ public class HttpTestUtils {
         return new BasicHttpRequest("GET","/",HttpVersion.HTTP_1_1);
     }
 
+    public static HttpRequest makeDefaultHEADRequest() {
+        return new BasicHttpRequest("HEAD","/",HttpVersion.HTTP_1_1);
+    }
+
     public static HttpResponse make500Response() {
         return new BasicHttpResponse(HttpVersion.HTTP_1_1,
                 HttpStatus.SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
     }
+
+    public static Map<String, String> makeDefaultVariantMap(final String key, final String value) {
+        final Map<String, String> variants = new HashMap<String, String>();
+        variants.put(key, value);
+
+        return variants;
+    }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/RequestEquivalent.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/RequestEquivalent.java
index 45324b7..0ac2ef0 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/RequestEquivalent.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/RequestEquivalent.java
@@ -37,6 +37,7 @@ public class RequestEquivalent implements IArgumentMatcher {
         this.expected = expected;
     }
 
+    @Override
     public boolean matches(final Object actual) {
         if (!(actual instanceof HttpRequest)) {
             return false;
@@ -45,6 +46,7 @@ public class RequestEquivalent implements IArgumentMatcher {
         return HttpTestUtils.equivalent(expected, other);
     }
 
+    @Override
     public void appendTo(final StringBuffer buf) {
         buf.append("eqRequest(");
         buf.append(expected);
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ResponseEquivalent.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ResponseEquivalent.java
index b57126b..843db43 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ResponseEquivalent.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ResponseEquivalent.java
@@ -37,6 +37,7 @@ public class ResponseEquivalent implements IArgumentMatcher {
         this.expected = expected;
     }
 
+    @Override
     public boolean matches(final Object actual) {
         if (!(actual instanceof HttpResponse)) {
             return false;
@@ -45,6 +46,7 @@ public class ResponseEquivalent implements IArgumentMatcher {
         return HttpTestUtils.equivalent(expected, other);
     }
 
+    @Override
     public void appendTo(final StringBuffer buf) {
         buf.append("eqRequest(");
         buf.append(expected);
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/SimpleHttpCacheStorage.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/SimpleHttpCacheStorage.java
index 184b89b..6986f11 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/SimpleHttpCacheStorage.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/SimpleHttpCacheStorage.java
@@ -42,18 +42,22 @@ class SimpleHttpCacheStorage implements HttpCacheStorage {
         map = new HashMap<String,HttpCacheEntry>();
     }
 
+    @Override
     public void putEntry(final String key, final HttpCacheEntry entry) throws IOException {
         map.put(key, entry);
     }
 
+    @Override
     public HttpCacheEntry getEntry(final String key) throws IOException {
         return map.get(key);
     }
 
+    @Override
     public void removeEntry(final String key) throws IOException {
         map.remove(key);
     }
 
+    @Override
     public void updateEntry(final String key, final HttpCacheUpdateCallback callback)
             throws IOException {
         final HttpCacheEntry v1 = map.get(key);
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidationRequest.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidationRequest.java
index 6df2a62..c970f51 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidationRequest.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidationRequest.java
@@ -26,6 +26,10 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import java.io.IOException;
 
 import org.apache.http.Header;
@@ -41,7 +45,6 @@ import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.message.BasicHeader;
-import org.easymock.classextension.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -60,15 +63,15 @@ public class TestAsynchronousValidationRequest {
 
     @Before
     public void setUp() {
-        mockParent = EasyMock.createNiceMock(AsynchronousValidator.class);
-        mockClient = EasyMock.createNiceMock(CachingExec.class);
-        route = new HttpRoute(new HttpHost("foo.example.com"));
+        mockParent = mock(AsynchronousValidator.class);
+        mockClient = mock(CachingExec.class);
+        route = new HttpRoute(new HttpHost("foo.example.com", 80));
         request = HttpRequestWrapper.wrap(new HttpGet("/"));
         context = HttpClientContext.create();
-        mockExecAware = EasyMock.createNiceMock(HttpExecutionAware.class);
-        mockCacheEntry = EasyMock.createNiceMock(HttpCacheEntry.class);
-        mockResponse = EasyMock.createNiceMock(CloseableHttpResponse.class);
-        mockStatusLine = EasyMock.createNiceMock(StatusLine.class);
+        mockExecAware = mock(HttpExecutionAware.class);
+        mockCacheEntry = mock(HttpCacheEntry.class);
+        mockResponse = mock(CloseableHttpResponse.class);
+        mockStatusLine = mock(StatusLine.class);
     }
 
     @Test
@@ -79,17 +82,19 @@ public class TestAsynchronousValidationRequest {
                 mockParent, mockClient, route, request, context, mockExecAware, mockCacheEntry,
                 identifier, 0);
 
-        EasyMock.expect(
+        when(
                 mockClient.revalidateCacheEntry(
-                        route, request, context, mockExecAware, mockCacheEntry)).andReturn(mockResponse);
-        EasyMock.expect(mockResponse.getStatusLine()).andReturn(mockStatusLine);
-        EasyMock.expect(mockStatusLine.getStatusCode()).andReturn(200);
-        mockParent.markComplete(identifier);
-        mockParent.jobSuccessful(identifier);
+                        route, request, context, mockExecAware, mockCacheEntry)).thenReturn(mockResponse);
+        when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
+        when(mockStatusLine.getStatusCode()).thenReturn(200);
 
-        replayMocks();
         impl.run();
-        verifyMocks();
+
+        verify(mockClient).revalidateCacheEntry(
+                route, request, context, mockExecAware, mockCacheEntry);
+        verify(mockResponse).getStatusLine();
+        verify(mockParent).markComplete(identifier);
+        verify(mockParent).jobSuccessful(identifier);
     }
 
     @Test
@@ -100,17 +105,20 @@ public class TestAsynchronousValidationRequest {
                 mockParent, mockClient, route, request, context, mockExecAware, mockCacheEntry,
                 identifier, 0);
 
-        EasyMock.expect(
+        when(
                 mockClient.revalidateCacheEntry(
-                        route, request, context, mockExecAware, mockCacheEntry)).andReturn(mockResponse);
-        EasyMock.expect(mockResponse.getStatusLine()).andReturn(mockStatusLine);
-        EasyMock.expect(mockStatusLine.getStatusCode()).andReturn(200);
-        mockParent.markComplete(identifier);
-        mockParent.jobSuccessful(identifier);
+                        route, request, context, mockExecAware, mockCacheEntry)).thenReturn(mockResponse);
+        when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
+        when(mockStatusLine.getStatusCode()).thenReturn(200);
 
-        replayMocks();
         impl.run();
-        verifyMocks();
+
+        verify(mockClient).revalidateCacheEntry(
+                route, request, context, mockExecAware, mockCacheEntry);
+        verify(mockResponse).getStatusLine();
+        verify(mockStatusLine).getStatusCode();
+        verify(mockParent).markComplete(identifier);
+        verify(mockParent).jobSuccessful(identifier);
     }
 
     @Test
@@ -122,18 +130,22 @@ public class TestAsynchronousValidationRequest {
                 mockParent, mockClient, route, request, context, mockExecAware, mockCacheEntry,
                 identifier, 0);
 
-        EasyMock.expect(
+        when(
                 mockClient.revalidateCacheEntry(
-                        route, request, context, mockExecAware, mockCacheEntry)).andReturn(mockResponse);
-        EasyMock.expect(mockResponse.getStatusLine()).andReturn(mockStatusLine);
-        EasyMock.expect(mockStatusLine.getStatusCode()).andReturn(200);
-        EasyMock.expect(mockResponse.getHeaders(HeaderConstants.WARNING)).andReturn(warning);
-        mockParent.markComplete(identifier);
-        mockParent.jobFailed(identifier);
-
-        replayMocks();
+                        route, request, context, mockExecAware, mockCacheEntry)).thenReturn(mockResponse);
+        when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
+        when(mockStatusLine.getStatusCode()).thenReturn(200);
+        when(mockResponse.getHeaders(HeaderConstants.WARNING)).thenReturn(warning);
+
         impl.run();
-        verifyMocks();
+
+        verify(mockClient).revalidateCacheEntry(
+                route, request, context, mockExecAware, mockCacheEntry);
+        verify(mockResponse).getStatusLine();
+        verify(mockStatusLine).getStatusCode();
+        verify(mockResponse).getHeaders(HeaderConstants.WARNING);
+        verify(mockParent).markComplete(identifier);
+        verify(mockParent).jobFailed(identifier);
     }
 
     @Test
@@ -144,16 +156,17 @@ public class TestAsynchronousValidationRequest {
                 mockParent, mockClient, route, request, context, mockExecAware, mockCacheEntry,
                 identifier, 0);
 
-        EasyMock.expect(
+        when(
                 mockClient.revalidateCacheEntry(
-                        route, request, context, mockExecAware, mockCacheEntry)).andThrow(
+                        route, request, context, mockExecAware, mockCacheEntry)).thenThrow(
                 new ProtocolException());
-        mockParent.markComplete(identifier);
-        mockParent.jobFailed(identifier);
 
-        replayMocks();
         impl.run();
-        verifyMocks();
+
+        verify(mockClient).revalidateCacheEntry(
+                route, request, context, mockExecAware, mockCacheEntry);
+        verify(mockParent).markComplete(identifier);
+        verify(mockParent).jobFailed(identifier);
     }
 
     @Test
@@ -164,16 +177,17 @@ public class TestAsynchronousValidationRequest {
                 mockParent, mockClient, route, request, context, mockExecAware, mockCacheEntry,
                 identifier, 0);
 
-        EasyMock.expect(
+        when(
                 mockClient.revalidateCacheEntry(
-                        route, request, context, mockExecAware, mockCacheEntry)).andThrow(
+                        route, request, context, mockExecAware, mockCacheEntry)).thenThrow(
                                 new IOException());
-        mockParent.markComplete(identifier);
-        mockParent.jobFailed(identifier);
 
-        replayMocks();
         impl.run();
-        verifyMocks();
+
+        verify(mockClient).revalidateCacheEntry(
+                route, request, context, mockExecAware, mockCacheEntry);
+        verify(mockParent).markComplete(identifier);
+        verify(mockParent).jobFailed(identifier);
     }
 
     @Test
@@ -184,33 +198,16 @@ public class TestAsynchronousValidationRequest {
                 mockParent, mockClient, route, request, context, mockExecAware, mockCacheEntry,
                 identifier, 0);
 
-        EasyMock.expect(
+        when(
                 mockClient.revalidateCacheEntry(
-                        route, request, context, mockExecAware, mockCacheEntry)).andThrow(
+                        route, request, context, mockExecAware, mockCacheEntry)).thenThrow(
                                 new RuntimeException());
-        mockParent.markComplete(identifier);
-        mockParent.jobFailed(identifier);
 
-        replayMocks();
         impl.run();
-        verifyMocks();
-    }
-
-    public void replayMocks() {
-        EasyMock.replay(mockClient);
-        EasyMock.replay(mockExecAware);
-        EasyMock.replay(mockCacheEntry);
-        EasyMock.replay(mockResponse);
-        EasyMock.replay(mockStatusLine);
-        EasyMock.replay(mockParent);
-    }
 
-    public void verifyMocks() {
-        EasyMock.verify(mockClient);
-        EasyMock.verify(mockExecAware);
-        EasyMock.verify(mockCacheEntry);
-        EasyMock.verify(mockResponse);
-        EasyMock.verify(mockStatusLine);
-        EasyMock.verify(mockParent);
+        verify(mockClient).revalidateCacheEntry(
+                route, request, context, mockExecAware, mockCacheEntry);
+        verify(mockParent).markComplete(identifier);
+        verify(mockParent).jobFailed(identifier);
     }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidator.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidator.java
index 890c36f..58ecef1 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidator.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestAsynchronousValidator.java
@@ -26,6 +26,13 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import java.io.IOException;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -41,11 +48,10 @@ import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.message.BasicHeader;
-import org.easymock.Capture;
-import org.easymock.classextension.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
 @SuppressWarnings({"boxing","static-access"}) // test code
 public class TestAsynchronousValidator {
@@ -63,26 +69,26 @@ public class TestAsynchronousValidator {
 
     @Before
     public void setUp() {
-        mockClient = EasyMock.createNiceMock(CachingExec.class);
-        route = new HttpRoute(new HttpHost("foo.example.com"));
+        mockClient = mock(CachingExec.class);
+        route = new HttpRoute(new HttpHost("foo.example.com", 80));
         request = HttpRequestWrapper.wrap(new HttpGet("/"));
         context = HttpClientContext.create();
         context.setTargetHost(new HttpHost("foo.example.com"));
-        mockExecAware = EasyMock.createNiceMock(HttpExecutionAware.class);
-        mockCacheEntry = EasyMock.createNiceMock(HttpCacheEntry.class);
-        mockSchedulingStrategy = EasyMock.createNiceMock(SchedulingStrategy.class);
+        mockExecAware = mock(HttpExecutionAware.class);
+        mockCacheEntry = mock(HttpCacheEntry.class);
+        mockSchedulingStrategy = mock(SchedulingStrategy.class);
     }
 
     @Test
     public void testRevalidateCacheEntrySchedulesExecutionAndPopulatesIdentifier() {
         impl = new AsynchronousValidator(mockSchedulingStrategy);
 
-        EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(false);
-        mockSchedulingStrategy.schedule(EasyMock.isA(AsynchronousValidationRequest.class));
+        when(mockCacheEntry.hasVariants()).thenReturn(false);
 
-        replayMocks();
         impl.revalidateCacheEntry(mockClient, route, request, context, mockExecAware, mockCacheEntry);
-        verifyMocks();
+
+        verify(mockCacheEntry).hasVariants();
+        verify(mockSchedulingStrategy).schedule(isA(AsynchronousValidationRequest.class));
 
         Assert.assertEquals(1, impl.getScheduledIdentifiers().size());
     }
@@ -91,13 +97,13 @@ public class TestAsynchronousValidator {
     public void testMarkCompleteRemovesIdentifier() {
         impl = new AsynchronousValidator(mockSchedulingStrategy);
 
-        EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(false);
-        final Capture<AsynchronousValidationRequest> cap = new Capture<AsynchronousValidationRequest>();
-        mockSchedulingStrategy.schedule(EasyMock.capture(cap));
+        when(mockCacheEntry.hasVariants()).thenReturn(false);
 
-        replayMocks();
         impl.revalidateCacheEntry(mockClient, route, request, context, mockExecAware, mockCacheEntry);
-        verifyMocks();
+
+        final ArgumentCaptor<AsynchronousValidationRequest> cap = ArgumentCaptor.forClass(AsynchronousValidationRequest.class);
+        verify(mockCacheEntry).hasVariants();
+        verify(mockSchedulingStrategy).schedule(cap.capture());
 
         Assert.assertEquals(1, impl.getScheduledIdentifiers().size());
 
@@ -110,30 +116,28 @@ public class TestAsynchronousValidator {
     public void testRevalidateCacheEntryDoesNotPopulateIdentifierOnRejectedExecutionException() {
         impl = new AsynchronousValidator(mockSchedulingStrategy);
 
-        EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(false);
-        mockSchedulingStrategy.schedule(EasyMock.isA(AsynchronousValidationRequest.class));
-        EasyMock.expectLastCall().andThrow(new RejectedExecutionException());
+        when(mockCacheEntry.hasVariants()).thenReturn(false);
+        doThrow(new RejectedExecutionException()).when(mockSchedulingStrategy).schedule(isA(AsynchronousValidationRequest.class));
 
-        replayMocks();
         impl.revalidateCacheEntry(mockClient, route, request, context, mockExecAware, mockCacheEntry);
-        verifyMocks();
+
+        verify(mockCacheEntry).hasVariants();
 
         Assert.assertEquals(0, impl.getScheduledIdentifiers().size());
+        verify(mockSchedulingStrategy).schedule(isA(AsynchronousValidationRequest.class));
     }
 
     @Test
     public void testRevalidateCacheEntryProperlyCollapsesRequest() {
         impl = new AsynchronousValidator(mockSchedulingStrategy);
 
-        EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(false);
-        mockSchedulingStrategy.schedule(EasyMock.isA(AsynchronousValidationRequest.class));
-
-        EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(false);
+        when(mockCacheEntry.hasVariants()).thenReturn(false);
 
-        replayMocks();
         impl.revalidateCacheEntry(mockClient, route, request, context, mockExecAware, mockCacheEntry);
         impl.revalidateCacheEntry(mockClient, route, request, context, mockExecAware, mockCacheEntry);
-        verifyMocks();
+
+        verify(mockCacheEntry, times(2)).hasVariants();
+        verify(mockSchedulingStrategy).schedule(isA(AsynchronousValidationRequest.class));
 
         Assert.assertEquals(1, impl.getScheduledIdentifiers().size());
     }
@@ -152,18 +156,18 @@ public class TestAsynchronousValidator {
                 new BasicHeader(HeaderConstants.VARY, "Accept-Encoding")
         };
 
-        EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(true).times(2);
-        EasyMock.expect(mockCacheEntry.getHeaders(HeaderConstants.VARY)).andReturn(variantHeaders).times(2);
-        mockSchedulingStrategy.schedule(EasyMock.isA(AsynchronousValidationRequest.class));
-        EasyMock.expectLastCall().times(2);
+        when(mockCacheEntry.hasVariants()).thenReturn(true);
+        when(mockCacheEntry.getHeaders(HeaderConstants.VARY)).thenReturn(variantHeaders);
+        mockSchedulingStrategy.schedule(isA(AsynchronousValidationRequest.class));
 
-        replayMocks();
         impl.revalidateCacheEntry(mockClient, route, HttpRequestWrapper.wrap(req1), context, mockExecAware, mockCacheEntry);
         impl.revalidateCacheEntry(mockClient, route, HttpRequestWrapper.wrap(req2), context, mockExecAware, mockCacheEntry);
-        verifyMocks();
 
-        Assert.assertEquals(2, impl.getScheduledIdentifiers().size());
+        verify(mockCacheEntry, times(2)).hasVariants();
+        verify(mockCacheEntry, times(2)).getHeaders(HeaderConstants.VARY);
+        verify(mockSchedulingStrategy, times(2)).schedule(isA(AsynchronousValidationRequest.class));
 
+        Assert.assertEquals(2, impl.getScheduledIdentifiers().size());
     }
 
     @Test
@@ -175,11 +179,10 @@ public class TestAsynchronousValidator {
         final ImmediateSchedulingStrategy schedulingStrategy = new ImmediateSchedulingStrategy(config);
         impl = new AsynchronousValidator(schedulingStrategy);
 
-        EasyMock.expect(mockCacheEntry.hasVariants()).andReturn(false);
-        EasyMock.expect(mockClient.revalidateCacheEntry(
-                route, request, context, mockExecAware, mockCacheEntry)).andReturn(null);
+        when(mockCacheEntry.hasVariants()).thenReturn(false);
+        when(mockClient.revalidateCacheEntry(
+                route, request, context, mockExecAware, mockCacheEntry)).thenReturn(null);
 
-        replayMocks();
         impl.revalidateCacheEntry(mockClient, route, request, context, mockExecAware, mockCacheEntry);
 
         try {
@@ -189,7 +192,8 @@ public class TestAsynchronousValidator {
         } catch (final InterruptedException ie) {
 
         } finally {
-            verifyMocks();
+            verify(mockCacheEntry).hasVariants();
+            verify(mockClient).revalidateCacheEntry(route, request, context, mockExecAware, mockCacheEntry);
 
             Assert.assertEquals(0, impl.getScheduledIdentifiers().size());
         }
@@ -199,24 +203,8 @@ public class TestAsynchronousValidator {
     public void testSchedulingStrategyShutdownOnClose() throws IOException {
         impl = new AsynchronousValidator(mockSchedulingStrategy);
 
-        mockSchedulingStrategy.close();
-
-        replayMocks();
         impl.close();
-        verifyMocks();
-    }
-
-    public void replayMocks() {
-        EasyMock.replay(mockSchedulingStrategy);
-        EasyMock.replay(mockClient);
-        EasyMock.replay(mockExecAware);
-        EasyMock.replay(mockCacheEntry);
-    }
 
-    public void verifyMocks() {
-        EasyMock.verify(mockSchedulingStrategy);
-        EasyMock.verify(mockClient);
-        EasyMock.verify(mockExecAware);
-        EasyMock.verify(mockCacheEntry);
+        verify(mockSchedulingStrategy).close();
     }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java
index f457671..8549ab1 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java
@@ -263,6 +263,15 @@ public class TestBasicHttpCache {
     }
 
     @Test
+    public void testNullResourcesAreComplete()
+        throws Exception {
+        final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
+        resp.setHeader("Content-Length","256");
+
+        assertFalse(impl.isIncompleteResponse(resp, null));
+    }
+
+    @Test
     public void testIncompleteResponseErrorProvidesPlainTextErrorMessage()
         throws Exception {
         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
@@ -529,6 +538,7 @@ public class TestBasicHttpCache {
             return this.b;
         }
 
+        @Override
         public InputStream getInputStream() throws IOException {
             if (dispoased) {
                 throw new IOException("Already dispoased");
@@ -536,10 +546,12 @@ public class TestBasicHttpCache {
             return new ByteArrayInputStream(this.b);
         }
 
+        @Override
         public long length() {
             return this.b.length;
         }
 
+        @Override
         public void dispose() {
             this.dispoased = true;
         }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java
index f8408b7..5799339 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java
@@ -26,10 +26,10 @@
  */
 package org.apache.http.impl.client.cache;
 
-import static org.easymock.EasyMock.expect;
-import static org.easymock.classextension.EasyMock.createNiceMock;
-import static org.easymock.classextension.EasyMock.replay;
-import static org.easymock.classextension.EasyMock.verify;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.util.Date;
@@ -51,9 +51,6 @@ import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.message.BasicHttpResponse;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -78,25 +75,15 @@ public class TestCacheInvalidator {
         tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
 
         host = new HttpHost("foo.example.com");
-        mockStorage = createNiceMock(HttpCacheStorage.class);
+        mockStorage = mock(HttpCacheStorage.class);
         cacheKeyGenerator = new CacheKeyGenerator();
-        mockEntry = createNiceMock(HttpCacheEntry.class);
+        mockEntry = mock(HttpCacheEntry.class);
         request = HttpTestUtils.makeDefaultRequest();
         response = HttpTestUtils.make200Response();
 
         impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
     }
 
-    private void replayMocks() {
-        replay(mockStorage);
-        replay(mockEntry);
-    }
-
-    private void verifyMocks() {
-        verify(mockStorage);
-        verify(mockEntry);
-    }
-
     // Tests
     @Test
     public void testInvalidatesRequestsThatArentGETorHEAD() throws Exception {
@@ -106,137 +93,222 @@ public class TestCacheInvalidator {
         cacheEntryHasVariantMap(variantMap);
 
         cacheReturnsEntryForUri(theUri);
-        entryIsRemoved(theUri);
-        replayMocks();
 
         impl.flushInvalidatedCacheEntries(host, request);
 
-        verifyMocks();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
     }
 
     @Test
     public void testInvalidatesUrisInContentLocationHeadersOnPUTs() throws Exception {
-        final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
-        request.setEntity(HttpTestUtils.makeBody(128));
-        request.setHeader("Content-Length","128");
+        final HttpEntityEnclosingRequest putRequest = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
 
         final String contentLocation = "http://foo.example.com/content";
-        request.setHeader("Content-Location", contentLocation);
+        putRequest.setHeader("Content-Location", contentLocation);
 
         final String theUri = "http://foo.example.com:80/";
         cacheEntryHasVariantMap(new HashMap<String,String>());
 
         cacheReturnsEntryForUri(theUri);
-        entryIsRemoved(theUri);
-        entryIsRemoved("http://foo.example.com:80/content");
-
-        replayMocks();
 
-        impl.flushInvalidatedCacheEntries(host, request);
+        impl.flushInvalidatedCacheEntries(host, putRequest);
 
-        verifyMocks();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+        verify(mockStorage).removeEntry("http://foo.example.com:80/content");
     }
 
     @Test
     public void testInvalidatesUrisInLocationHeadersOnPUTs() throws Exception {
-        final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
-        request.setEntity(HttpTestUtils.makeBody(128));
-        request.setHeader("Content-Length","128");
+        final HttpEntityEnclosingRequest putRequest = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
 
         final String contentLocation = "http://foo.example.com/content";
-        request.setHeader("Location",contentLocation);
+        putRequest.setHeader("Location",contentLocation);
 
         final String theUri = "http://foo.example.com:80/";
         cacheEntryHasVariantMap(new HashMap<String,String>());
 
         cacheReturnsEntryForUri(theUri);
-        entryIsRemoved(theUri);
-        entryIsRemoved(cacheKeyGenerator.canonicalizeUri(contentLocation));
 
-        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, putRequest);
 
-        impl.flushInvalidatedCacheEntries(host, request);
-
-        verifyMocks();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+        verify(mockStorage).removeEntry(cacheKeyGenerator.canonicalizeUri(contentLocation));
     }
 
     @Test
     public void testInvalidatesRelativeUrisInContentLocationHeadersOnPUTs() throws Exception {
-        final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
-        request.setEntity(HttpTestUtils.makeBody(128));
-        request.setHeader("Content-Length","128");
+        final HttpEntityEnclosingRequest putRequest = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
 
         final String relativePath = "/content";
-        request.setHeader("Content-Location",relativePath);
+        putRequest.setHeader("Content-Location",relativePath);
 
         final String theUri = "http://foo.example.com:80/";
         cacheEntryHasVariantMap(new HashMap<String,String>());
 
         cacheReturnsEntryForUri(theUri);
-        entryIsRemoved(theUri);
-        entryIsRemoved("http://foo.example.com:80/content");
-
-        replayMocks();
 
-        impl.flushInvalidatedCacheEntries(host, request);
+        impl.flushInvalidatedCacheEntries(host, putRequest);
 
-        verifyMocks();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
+        verify(mockStorage).removeEntry("http://foo.example.com:80/content");
     }
 
     @Test
     public void testDoesNotInvalidateUrisInContentLocationHeadersOnPUTsToDifferentHosts() throws Exception {
-        final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
-        request.setEntity(HttpTestUtils.makeBody(128));
-        request.setHeader("Content-Length","128");
+        final HttpEntityEnclosingRequest putRequest = new BasicHttpEntityEnclosingRequest("PUT","/",HTTP_1_1);
+        putRequest.setEntity(HttpTestUtils.makeBody(128));
+        putRequest.setHeader("Content-Length","128");
 
         final String contentLocation = "http://bar.example.com/content";
-        request.setHeader("Content-Location",contentLocation);
+        putRequest.setHeader("Content-Location",contentLocation);
 
         final String theUri = "http://foo.example.com:80/";
         cacheEntryHasVariantMap(new HashMap<String,String>());
 
         cacheReturnsEntryForUri(theUri);
-        entryIsRemoved(theUri);
-
-        replayMocks();
 
-        impl.flushInvalidatedCacheEntries(host, request);
+        impl.flushInvalidatedCacheEntries(host, putRequest);
 
-        verifyMocks();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theUri);
+        verify(mockStorage).removeEntry(theUri);
     }
 
     @Test
     public void testDoesNotInvalidateGETRequest() throws Exception {
         request = new BasicHttpRequest("GET","/",HTTP_1_1);
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request);
-        verifyMocks();
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
     public void testDoesNotInvalidateHEADRequest() throws Exception {
         request = new BasicHttpRequest("HEAD","/",HTTP_1_1);
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request);
-        verifyMocks();
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testInvalidatesHEADCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicHttpRequest("GET", theURI,HTTP_1_1);
+
+        cacheEntryisForMethod("HEAD");
+        cacheEntryHasVariantMap(new HashMap<String, String>());
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockEntry).getRequestMethod();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+    }
+
+    @Test
+    public void testInvalidatesVariantHEADCacheEntriesIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicHttpRequest("GET", theURI,HTTP_1_1);
+        final String theVariantKey = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}";
+        final String theVariantURI = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}http://foo.example.com:80/";
+        final Map<String, String> variants = HttpTestUtils.makeDefaultVariantMap(theVariantKey, theVariantURI);
+
+        cacheEntryisForMethod("HEAD");
+        cacheEntryHasVariantMap(variants);
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockEntry).getRequestMethod();
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verify(mockStorage).removeEntry(theVariantURI);
+    }
+
+    @Test
+    public void testDoesNotInvalidateHEADCacheEntry() throws Exception {
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicHttpRequest("HEAD", theURI,HTTP_1_1);
+
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testDoesNotInvalidateHEADCacheEntryIfSubsequentHEADRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicHttpRequest("HEAD", theURI,HTTP_1_1);
+
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
+    }
+
+    @Test
+    public void testDoesNotInvalidateGETCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
+        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
+        final String theURI = "http://foo.example.com:80/";
+        request = new BasicHttpRequest("GET", theURI,HTTP_1_1);
+
+        cacheEntryisForMethod("GET");
+        cacheReturnsEntryForUri(theURI);
+
+        impl.flushInvalidatedCacheEntries(host, request);
+
+        verify(mockEntry).getRequestMethod();
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
     public void testDoesNotInvalidateRequestsWithClientCacheControlHeaders() throws Exception {
         request = new BasicHttpRequest("GET","/",HTTP_1_1);
         request.setHeader("Cache-Control","no-cache");
-        replayMocks();
+
         impl.flushInvalidatedCacheEntries(host, request);
-        verifyMocks();
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
     public void testDoesNotInvalidateRequestsWithClientPragmaHeaders() throws Exception {
         request = new BasicHttpRequest("GET","/",HTTP_1_1);
         request.setHeader("Pragma","no-cache");
-        replayMocks();
+
         impl.flushInvalidatedCacheEntries(host, request);
-        verifyMocks();
+
+        verify(mockStorage).getEntry("http://foo.example.com:80/");
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -244,19 +316,17 @@ public class TestCacheInvalidator {
         request = new BasicHttpRequest("POST","/",HTTP_1_1);
         final String theUri = "http://foo.example.com:80/";
         final String variantUri = "theVariantURI";
-
-        final Map<String,String> mapOfURIs = new HashMap<String,String>();
-        mapOfURIs.put(variantUri,variantUri);
+        final Map<String,String> mapOfURIs = HttpTestUtils.makeDefaultVariantMap(variantUri, variantUri);
 
         cacheReturnsEntryForUri(theUri);
         cacheEntryHasVariantMap(mapOfURIs);
 
-        entryIsRemoved(variantUri);
-        entryIsRemoved(theUri);
-
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theUri);
+        verify(mockEntry).getVariantMap();
+        verify(mockStorage).removeEntry(variantUri);
+        verify(mockStorage).removeEntry(theUri);
     }
 
     @Test
@@ -266,17 +336,18 @@ public class TestCacheInvalidator {
 
         cacheReturnsExceptionForUri(theURI);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
     public void doesNotFlushForResponsesWithoutContentLocation()
             throws Exception {
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -292,12 +363,12 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
     }
 
     @Test
@@ -314,12 +385,12 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
     }
 
     @Test
@@ -331,23 +402,9 @@ public class TestCacheInvalidator {
         final String theURI = "http://foo.example.com:80/bar";
         response.setHeader("Content-Location", theURI);
 
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
-           new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
-           new BasicHeader("ETag", "\"old-etag\"")
-        });
-
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
-        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
-            public Void answer() {
-                Assert.fail();
-                return null;
-              }
-          }).anyTimes();
-
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -363,12 +420,12 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(cacheKey)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(cacheKey);
+        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(cacheKey);
+        verify(mockStorage).removeEntry(cacheKey);
     }
 
     @Test
@@ -384,12 +441,12 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(cacheKey)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(cacheKey);
+        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(cacheKey);
+        verify(mockStorage).removeEntry(cacheKey);
     }
 
     @Test
@@ -405,18 +462,12 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(cacheKey)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(cacheKey);
-        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
-            public Void answer() {
-                Assert.fail();
-                return null;
-              }
-          }).anyTimes();
+        when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(cacheKey);
+        verifyNoMoreInteractions(mockStorage);
     }
 
 
@@ -434,18 +485,11 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"same-etag\"")
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
-        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
-            public Void answer() {
-                Assert.fail();
-                return null;
-              }
-          }).anyTimes();
-
-        replayMocks();
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -461,18 +505,12 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
-        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
-            public Void answer() {
-                Assert.fail();
-                return null;
-              }
-          }).anyTimes();
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -483,18 +521,12 @@ public class TestCacheInvalidator {
         final String theURI = "http://foo.example.com:80/bar";
         response.setHeader("Content-Location", theURI);
 
-        expect(mockStorage.getEntry(theURI)).andReturn(null).anyTimes();
-        mockStorage.removeEntry(theURI);
-        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
-            public Void answer() {
-                Assert.fail();
-                return null;
-              }
-          }).anyTimes();
+        when(mockStorage.getEntry(theURI)).thenReturn(null);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -510,18 +542,12 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
-        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
-            public Void answer() {
-                Assert.fail();
-                return null;
-              }
-          }).anyTimes();
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -536,11 +562,12 @@ public class TestCacheInvalidator {
            new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -556,12 +583,13 @@ public class TestCacheInvalidator {
                 new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -576,12 +604,13 @@ public class TestCacheInvalidator {
            new BasicHeader("ETag", "\"old-etag\"")
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -597,12 +626,13 @@ public class TestCacheInvalidator {
                 new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo))
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
     @Test
@@ -618,31 +648,31 @@ public class TestCacheInvalidator {
                 new BasicHeader("Date", "foo")
         });
 
-        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
-        mockStorage.removeEntry(theURI);
+        when(mockStorage.getEntry(theURI)).thenReturn(entry);
 
-        replayMocks();
         impl.flushInvalidatedCacheEntries(host, request, response);
-        verifyMocks();
+
+        verify(mockStorage).getEntry(theURI);
+        verify(mockStorage).removeEntry(theURI);
+        verifyNoMoreInteractions(mockStorage);
     }
 
 
     // Expectations
     private void cacheEntryHasVariantMap(final Map<String,String> variantMap) {
-        expect(mockEntry.getVariantMap()).andReturn(variantMap);
+        when(mockEntry.getVariantMap()).thenReturn(variantMap);
     }
 
     private void cacheReturnsEntryForUri(final String theUri) throws IOException {
-        expect(mockStorage.getEntry(theUri)).andReturn(mockEntry);
+        when(mockStorage.getEntry(theUri)).thenReturn(mockEntry);
     }
 
     private void cacheReturnsExceptionForUri(final String theUri) throws IOException {
-        expect(mockStorage.getEntry(theUri)).andThrow(
+        when(mockStorage.getEntry(theUri)).thenThrow(
                 new IOException("TOTAL FAIL"));
     }
 
-    private void entryIsRemoved(final String theUri) throws IOException {
-        mockStorage.removeEntry(theUri);
+    private void cacheEntryisForMethod(final String httpMethod) {
+        when(mockEntry.getRequestMethod()).thenReturn(httpMethod);
     }
-
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheKeyGenerator.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheKeyGenerator.java
index 7d714ab..4d217a9 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheKeyGenerator.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheKeyGenerator.java
@@ -26,6 +26,10 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import org.apache.http.Header;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
@@ -34,12 +38,11 @@ import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicHttpRequest;
-import org.easymock.classextension.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
- at SuppressWarnings({"boxing","static-access"}) // test code
+ at SuppressWarnings({"boxing","static-access"}) // this is test code
 public class TestCacheKeyGenerator {
 
     private static final BasicHttpRequest REQUEST_FULL_EPISODES = new BasicHttpRequest("GET",
@@ -47,28 +50,18 @@ public class TestCacheKeyGenerator {
     private static final BasicHttpRequest REQUEST_ROOT = new BasicHttpRequest("GET", "/");
 
     CacheKeyGenerator extractor;
-    private HttpHost host;
+    private HttpHost defaultHost;
     private HttpCacheEntry mockEntry;
     private HttpRequest mockRequest;
 
     @Before
     public void setUp() throws Exception {
-        host = new HttpHost("foo.example.com");
-        mockEntry = EasyMock.createNiceMock(HttpCacheEntry.class);
-        mockRequest = EasyMock.createNiceMock(HttpRequest.class);
+        defaultHost = new HttpHost("foo.example.com");
+        mockEntry = mock(HttpCacheEntry.class);
+        mockRequest = mock(HttpRequest.class);
         extractor = new CacheKeyGenerator();
     }
 
-    private void replayMocks() {
-        EasyMock.replay(mockEntry);
-        EasyMock.replay(mockRequest);
-    }
-
-    private void verifyMocks() {
-        EasyMock.verify(mockEntry);
-        EasyMock.verify(mockRequest);
-    }
-
     @Test
     public void testExtractsUriFromAbsoluteUriInRequest() {
         final HttpHost host = new HttpHost("bar.example.com");
@@ -124,19 +117,18 @@ public class TestCacheKeyGenerator {
     @Test
     public void testGetVariantURIWithNoVaryHeaderReturnsNormalURI() {
         final String theURI = "theURI";
-        org.easymock.EasyMock.expect(mockEntry.hasVariants()).andReturn(false);
+        when(mockEntry.hasVariants()).thenReturn(false);
         extractor = new CacheKeyGenerator() {
             @Override
             public String getURI(final HttpHost h, final HttpRequest req) {
-                Assert.assertSame(host, h);
+                Assert.assertSame(defaultHost, h);
                 Assert.assertSame(mockRequest, req);
                 return theURI;
             }
         };
 
-        replayMocks();
-        final String result = extractor.getVariantURI(host, mockRequest, mockEntry);
-        verifyMocks();
+        final String result = extractor.getVariantURI(defaultHost, mockRequest, mockEntry);
+        verify(mockEntry).hasVariants();
         Assert.assertSame(theURI, result);
     }
 
@@ -149,20 +141,21 @@ public class TestCacheKeyGenerator {
         extractor = new CacheKeyGenerator() {
             @Override
             public String getURI(final HttpHost h, final HttpRequest req) {
-                Assert.assertSame(host, h);
+                Assert.assertSame(defaultHost, h);
                 Assert.assertSame(mockRequest, req);
                 return theURI;
             }
         };
-        EasyMock.expect(mockEntry.hasVariants()).andReturn(true).anyTimes();
-        EasyMock.expect(mockEntry.getHeaders("Vary")).andReturn(varyHeaders);
-        EasyMock.expect(mockRequest.getHeaders("Accept-Encoding")).andReturn(
+        when(mockEntry.hasVariants()).thenReturn(true);
+        when(mockEntry.getHeaders("Vary")).thenReturn(varyHeaders);
+        when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(
                 encHeaders);
-        replayMocks();
 
-        final String result = extractor.getVariantURI(host, mockRequest, mockEntry);
+        final String result = extractor.getVariantURI(defaultHost, mockRequest, mockEntry);
 
-        verifyMocks();
+        verify(mockEntry).hasVariants();
+        verify(mockEntry).getHeaders("Vary");
+        verify(mockRequest).getHeaders("Accept-Encoding");
         Assert.assertEquals("{Accept-Encoding=gzip}" + theURI, result);
     }
 
@@ -174,20 +167,21 @@ public class TestCacheKeyGenerator {
         extractor = new CacheKeyGenerator() {
             @Override
             public String getURI(final HttpHost h, final HttpRequest req) {
-                Assert.assertSame(host, h);
+                Assert.assertSame(defaultHost, h);
                 Assert.assertSame(mockRequest, req);
                 return theURI;
             }
         };
-        EasyMock.expect(mockEntry.hasVariants()).andReturn(true).anyTimes();
-        EasyMock.expect(mockEntry.getHeaders("Vary")).andReturn(varyHeaders);
-        EasyMock.expect(mockRequest.getHeaders("Accept-Encoding"))
-                .andReturn(noHeaders);
-        replayMocks();
+        when(mockEntry.hasVariants()).thenReturn(true);
+        when(mockEntry.getHeaders("Vary")).thenReturn(varyHeaders);
+        when(mockRequest.getHeaders("Accept-Encoding"))
+                .thenReturn(noHeaders);
 
-        final String result = extractor.getVariantURI(host, mockRequest, mockEntry);
+        final String result = extractor.getVariantURI(defaultHost, mockRequest, mockEntry);
 
-        verifyMocks();
+        verify(mockEntry).hasVariants();
+        verify(mockEntry).getHeaders("Vary");
+        verify(mockRequest).getHeaders("Accept-Encoding");
         Assert.assertEquals("{Accept-Encoding=}" + theURI, result);
     }
 
@@ -200,21 +194,23 @@ public class TestCacheKeyGenerator {
         extractor = new CacheKeyGenerator() {
             @Override
             public String getURI(final HttpHost h, final HttpRequest req) {
-                Assert.assertSame(host, h);
+                Assert.assertSame(defaultHost, h);
                 Assert.assertSame(mockRequest, req);
                 return theURI;
             }
         };
-        EasyMock.expect(mockEntry.hasVariants()).andReturn(true).anyTimes();
-        EasyMock.expect(mockEntry.getHeaders("Vary")).andReturn(varyHeaders);
-        EasyMock.expect(mockRequest.getHeaders("Accept-Encoding")).andReturn(
+        when(mockEntry.hasVariants()).thenReturn(true);
+        when(mockEntry.getHeaders("Vary")).thenReturn(varyHeaders);
+        when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(
                 encHeaders);
-        EasyMock.expect(mockRequest.getHeaders("User-Agent")).andReturn(uaHeaders);
-        replayMocks();
+        when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
 
-        final String result = extractor.getVariantURI(host, mockRequest, mockEntry);
+        final String result = extractor.getVariantURI(defaultHost, mockRequest, mockEntry);
 
-        verifyMocks();
+        verify(mockEntry).hasVariants();
+        verify(mockEntry).getHeaders("Vary");
+        verify(mockRequest).getHeaders("Accept-Encoding");
+        verify(mockRequest).getHeaders("User-Agent");
         Assert.assertEquals("{Accept-Encoding=gzip&User-Agent=browser}" + theURI, result);
     }
 
@@ -228,20 +224,22 @@ public class TestCacheKeyGenerator {
         extractor = new CacheKeyGenerator() {
             @Override
             public String getURI(final HttpHost h, final HttpRequest req) {
-                Assert.assertSame(host, h);
+                Assert.assertSame(defaultHost, h);
                 Assert.assertSame(mockRequest, req);
                 return theURI;
             }
         };
-        EasyMock.expect(mockEntry.hasVariants()).andReturn(true).anyTimes();
-        EasyMock.expect(mockEntry.getHeaders("Vary")).andReturn(varyHeaders);
-        EasyMock.expect(mockRequest.getHeaders("Accept-Encoding")).andReturn(encHeaders);
-        EasyMock.expect(mockRequest.getHeaders("User-Agent")).andReturn(uaHeaders);
-        replayMocks();
+        when(mockEntry.hasVariants()).thenReturn(true);
+        when(mockEntry.getHeaders("Vary")).thenReturn(varyHeaders);
+        when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
+        when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
 
-        final String result = extractor.getVariantURI(host, mockRequest, mockEntry);
+        final String result = extractor.getVariantURI(defaultHost, mockRequest, mockEntry);
 
-        verifyMocks();
+        verify(mockEntry).hasVariants();
+        verify(mockEntry).getHeaders("Vary");
+        verify(mockRequest).getHeaders("Accept-Encoding");
+        verify(mockRequest).getHeaders("User-Agent");
         Assert.assertEquals("{Accept-Encoding=gzip&User-Agent=browser}" + theURI, result);
     }
 
@@ -255,20 +253,22 @@ public class TestCacheKeyGenerator {
         extractor = new CacheKeyGenerator() {
             @Override
             public String getURI(final HttpHost h, final HttpRequest req) {
-                Assert.assertSame(host, h);
+                Assert.assertSame(defaultHost, h);
                 Assert.assertSame(mockRequest, req);
                 return theURI;
             }
         };
-        EasyMock.expect(mockEntry.hasVariants()).andReturn(true).anyTimes();
-        EasyMock.expect(mockEntry.getHeaders("Vary")).andReturn(varyHeaders);
-        EasyMock.expect(mockRequest.getHeaders("Accept-Encoding")).andReturn(encHeaders);
-        EasyMock.expect(mockRequest.getHeaders("User-Agent")).andReturn(uaHeaders);
-        replayMocks();
+        when(mockEntry.hasVariants()).thenReturn(true);
+        when(mockEntry.getHeaders("Vary")).thenReturn(varyHeaders);
+        when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
+        when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
 
-        final String result = extractor.getVariantURI(host, mockRequest, mockEntry);
+        final String result = extractor.getVariantURI(defaultHost, mockRequest, mockEntry);
 
-        verifyMocks();
+        verify(mockEntry).hasVariants();
+        verify(mockEntry).getHeaders("Vary");
+        verify(mockRequest).getHeaders("Accept-Encoding");
+        verify(mockRequest).getHeaders("User-Agent");
         Assert
                 .assertEquals("{Accept-Encoding=gzip%2C+deflate&User-Agent=browser}" + theURI,
                         result);
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java
index 6cf49e8..5e8e5e1 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheValidityPolicy.java
@@ -96,7 +96,7 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getApparentAgeSecs(final HttpCacheEntry entry) {
+            protected long getApparentAgeSecs(final HttpCacheEntry ent) {
                 return 6;
             }
         };
@@ -109,7 +109,7 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getApparentAgeSecs(final HttpCacheEntry entry) {
+            protected long getApparentAgeSecs(final HttpCacheEntry ent) {
                 return 10;
             }
         };
@@ -127,12 +127,12 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getCorrectedReceivedAgeSecs(final HttpCacheEntry entry) {
+            protected long getCorrectedReceivedAgeSecs(final HttpCacheEntry ent) {
                 return 7;
             }
 
             @Override
-            protected long getResponseDelaySecs(final HttpCacheEntry entry) {
+            protected long getResponseDelaySecs(final HttpCacheEntry ent) {
                 return 13;
             }
         };
@@ -142,7 +142,6 @@ public class TestCacheValidityPolicy {
     @Test
     public void testResidentTimeSecondsIsTimeSinceResponseTime() {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, sixSecondsAgo);
-        impl = new CacheValidityPolicy();
         assertEquals(6, impl.getResidentTimeSecs(entry, now));
     }
 
@@ -151,11 +150,11 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getCorrectedInitialAgeSecs(final HttpCacheEntry entry) {
+            protected long getCorrectedInitialAgeSecs(final HttpCacheEntry ent) {
                 return 11;
             }
             @Override
-            protected long getResidentTimeSecs(final HttpCacheEntry entry, final Date d) {
+            protected long getResidentTimeSecs(final HttpCacheEntry ent, final Date d) {
                 return 17;
             }
         };
@@ -356,6 +355,14 @@ public class TestCacheValidityPolicy {
     }
 
     @Test
+    public void testNullResourceInvalidatesEntry() {
+        final int contentLength = 128;
+        final Header[] headers = {new BasicHeader(HTTP.CONTENT_LEN, Integer.toString(contentLength))};
+        final HttpCacheEntry entry = HttpTestUtils.makeHeadCacheEntry(headers);
+        assertFalse(impl.contentLengthHeaderMatchesActualLength(entry));
+    }
+
+    @Test
     public void testMalformedContentLengthReturnsNegativeOne() {
         final Header[] headers = new Header[] { new BasicHeader("Content-Length", "asdf") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
@@ -466,34 +473,25 @@ public class TestCacheValidityPolicy {
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsFalseWhenDirectiveIsAbsent() {
-        final Date now = new Date();
-
         final Header[] headers = new Header[] { new BasicHeader("Cache-control", "public") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
 
-        final CacheValidityPolicy impl = new CacheValidityPolicy();
-
         assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
     }
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsTrueWhenWithinStaleness() {
-        final Date now = new Date();
-        final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
         final Header[] headers = new Header[] {
                 new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
                 new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=15")
         };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
 
-        final CacheValidityPolicy impl = new CacheValidityPolicy();
-
         assertTrue(impl.mayReturnStaleWhileRevalidating(entry, now));
     }
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsFalseWhenPastStaleness() {
-        final Date now = new Date();
         final Date twentyFiveSecondsAgo = new Date(now.getTime() - 25 * 1000L);
         final Header[] headers = new Header[] {
                 new BasicHeader("Date", DateUtils.formatDate(twentyFiveSecondsAgo)),
@@ -501,23 +499,17 @@ public class TestCacheValidityPolicy {
         };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
 
-        final CacheValidityPolicy impl = new CacheValidityPolicy();
-
         assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
     }
 
     @Test
     public void testMayReturnStaleWhileRevalidatingIsFalseWhenDirectiveEmpty() {
-        final Date now = new Date();
-        final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
         final Header[] headers = new Header[] {
                 new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
                 new BasicHeader("Cache-Control", "max-age=5, stale-while-revalidate=")
         };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, now, headers);
 
-        final CacheValidityPolicy impl = new CacheValidityPolicy();
-
         assertFalse(impl.mayReturnStaleWhileRevalidating(entry, now));
     }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java
index 927a7cd..8b06ca2 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheableRequestPolicy.java
@@ -45,7 +45,6 @@ public class TestCacheableRequestPolicy {
         final BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
 
         Assert.assertTrue(policy.isServableFromCache(request));
-
     }
 
     @Test
@@ -83,9 +82,55 @@ public class TestCacheableRequestPolicy {
     }
 
     @Test
-    public void testIsArbitraryMethodServableFromCache() {
+    public void testIsHeadServableFromCache() {
+        BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+
+        Assert.assertTrue(policy.isServableFromCache(request));
+
+        request = new BasicHttpRequest("HEAD", "someUri");
+        request.addHeader("Cache-Control", "public");
+        request.addHeader("Cache-Control", "max-age=20");
+
+        Assert.assertTrue(policy.isServableFromCache(request));
+    }
 
+    @Test
+    public void testIsHeadWithCacheControlServableFromCache() {
         BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+        request.addHeader("Cache-Control", "no-cache");
+
+        Assert.assertFalse(policy.isServableFromCache(request));
+
+        request = new BasicHttpRequest("HEAD", "someUri");
+        request.addHeader("Cache-Control", "no-store");
+        request.addHeader("Cache-Control", "max-age=20");
+
+        Assert.assertFalse(policy.isServableFromCache(request));
+
+        request = new BasicHttpRequest("HEAD", "someUri");
+        request.addHeader("Cache-Control", "public");
+        request.addHeader("Cache-Control", "no-store, max-age=20");
+
+        Assert.assertFalse(policy.isServableFromCache(request));
+    }
+
+    @Test
+    public void testIsHeadWithPragmaServableFromCache() {
+        BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+        request.addHeader("Pragma", "no-cache");
+
+        Assert.assertFalse(policy.isServableFromCache(request));
+
+        request = new BasicHttpRequest("HEAD", "someUri");
+        request.addHeader("Pragma", "value1");
+        request.addHeader("Pragma", "value2");
+
+        Assert.assertFalse(policy.isServableFromCache(request));
+    }
+
+    @Test
+    public void testIsArbitraryMethodServableFromCache() {
+        BasicHttpRequest request = new BasicHttpRequest("TRACE", "someUri");
 
         Assert.assertFalse(policy.isServableFromCache(request));
 
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java
index f62b7a3..3fc12f6 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedHttpResponseGenerator.java
@@ -26,51 +26,46 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.mockito.Matchers.isA;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import java.util.Date;
+import java.util.HashMap;
 
 import org.apache.http.Header;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.cache.HttpCacheEntry;
-import org.apache.http.client.utils.DateUtils;
+import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.message.BasicHeader;
-import org.easymock.classextension.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+ at SuppressWarnings({"boxing","static-access"}) // test code
 public class TestCachedHttpResponseGenerator {
 
     private HttpCacheEntry entry;
+    private HttpRequestWrapper request;
     private CacheValidityPolicy mockValidityPolicy;
     private CachedHttpResponseGenerator impl;
-    private Date now;
 
     @Before
     public void setUp() {
-        now = new Date();
-        final Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
-        final Date eightSecondsAgo = new Date(now.getTime() - 8 * 1000L);
-        final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
-        final Date tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
-        final Header[] hdrs = { new BasicHeader("Date", DateUtils.formatDate(eightSecondsAgo)),
-                new BasicHeader("Expires", DateUtils.formatDate(tenSecondsFromNow)),
-                new BasicHeader("Content-Length", "150") };
-
-        entry = HttpTestUtils.makeCacheEntry(tenSecondsAgo, sixSecondsAgo, hdrs);
-        mockValidityPolicy = EasyMock.createNiceMock(CacheValidityPolicy.class);
+        entry = HttpTestUtils.makeCacheEntry(new HashMap<String, String>());
+        request = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultRequest());
+        mockValidityPolicy = mock(CacheValidityPolicy.class);
         impl = new CachedHttpResponseGenerator(mockValidityPolicy);
     }
 
-    public void replayMocks() {
-        EasyMock.replay(mockValidityPolicy);
-    }
-
     @Test
     public void testResponseHasContentLength() {
         final byte[] buf = new byte[] { 1, 2, 3, 4, 5 };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(buf);
+        final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry(buf);
 
-        final HttpResponse response = impl.generateResponse(entry);
+        final HttpResponse response = impl.generateResponse(request, entry1);
 
         final Header length = response.getFirstHeader("Content-Length");
         Assert.assertNotNull("Content-Length Header is missing", length);
@@ -84,9 +79,9 @@ public class TestCachedHttpResponseGenerator {
 
         final Header[] hdrs = new Header[] { new BasicHeader("Transfer-Encoding", "chunked") };
         final byte[] buf = new byte[] { 1, 2, 3, 4, 5 };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(hdrs, buf);
+        final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry(hdrs, buf);
 
-        final HttpResponse response = impl.generateResponse(entry);
+        final HttpResponse response = impl.generateResponse(request, entry1);
 
         final Header length = response.getFirstHeader("Content-Length");
 
@@ -95,7 +90,7 @@ public class TestCachedHttpResponseGenerator {
 
     @Test
     public void testResponseMatchesCacheEntry() {
-        final HttpResponse response = impl.generateResponse(entry);
+        final HttpResponse response = impl.generateResponse(request, entry);
 
         Assert.assertTrue(response.containsHeader("Content-Length"));
 
@@ -106,7 +101,7 @@ public class TestCachedHttpResponseGenerator {
 
     @Test
     public void testResponseStatusCodeMatchesCacheEntry() {
-        final HttpResponse response = impl.generateResponse(entry);
+        final HttpResponse response = impl.generateResponse(request, entry);
 
         Assert.assertEquals(entry.getStatusCode(), response.getStatusLine().getStatusCode());
     }
@@ -114,9 +109,10 @@ public class TestCachedHttpResponseGenerator {
     @Test
     public void testAgeHeaderIsPopulatedWithCurrentAgeOfCacheEntryIfNonZero() {
         currentAge(10L);
-        replayMocks();
 
-        final HttpResponse response = impl.generateResponse(entry);
+        final HttpResponse response = impl.generateResponse(request, entry);
+
+        verify(mockValidityPolicy).getCurrentAgeSecs(same(entry), isA(Date.class));
 
         final Header ageHdr = response.getFirstHeader("Age");
         Assert.assertNotNull(ageHdr);
@@ -126,9 +122,10 @@ public class TestCachedHttpResponseGenerator {
     @Test
     public void testAgeHeaderIsNotPopulatedIfCurrentAgeOfCacheEntryIsZero() {
         currentAge(0L);
-        replayMocks();
 
-        final HttpResponse response = impl.generateResponse(entry);
+        final HttpResponse response = impl.generateResponse(request, entry);
+
+        verify(mockValidityPolicy).getCurrentAgeSecs(same(entry), isA(Date.class));
 
         final Header ageHdr = response.getFirstHeader("Age");
         Assert.assertNull(ageHdr);
@@ -137,9 +134,10 @@ public class TestCachedHttpResponseGenerator {
     @Test
     public void testAgeHeaderIsPopulatedWithMaxAgeIfCurrentAgeTooBig() {
         currentAge(CacheValidityPolicy.MAX_AGE + 1L);
-        replayMocks();
 
-        final HttpResponse response = impl.generateResponse(entry);
+        final HttpResponse response = impl.generateResponse(request, entry);
+
+        verify(mockValidityPolicy).getCurrentAgeSecs(same(entry), isA(Date.class));
 
         final Header ageHdr = response.getFirstHeader("Age");
         Assert.assertNotNull(ageHdr);
@@ -147,9 +145,24 @@ public class TestCachedHttpResponseGenerator {
     }
 
     private void currentAge(final long sec) {
-        EasyMock.expect(
-                mockValidityPolicy.getCurrentAgeSecs(EasyMock.same(entry),
-                        EasyMock.isA(Date.class))).andReturn(sec);
+        when(
+                mockValidityPolicy.getCurrentAgeSecs(same(entry),
+                        isA(Date.class))).thenReturn(sec);
+    }
+
+    @Test
+    public void testResponseContainsEntityToServeGETRequestIfEntryContainsResource() throws Exception {
+        final HttpResponse response = impl.generateResponse(request, entry);
+
+        Assert.assertNotNull(response.getEntity());
+    }
+
+    @Test
+    public void testResponseDoesNotContainEntityToServeHEADRequestIfEntryContainsResource() throws Exception {
+        final HttpRequestWrapper headRequest = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultHEADRequest());
+        final HttpResponse response = impl.generateResponse(headRequest, entry);
+
+        Assert.assertNull(response.getEntity());
     }
 
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedResponseSuitabilityChecker.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedResponseSuitabilityChecker.java
index 0735026..a5cfffa 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedResponseSuitabilityChecker.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachedResponseSuitabilityChecker.java
@@ -36,7 +36,6 @@ import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.utils.DateUtils;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicHttpRequest;
-import org.easymock.classextension.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -51,7 +50,6 @@ public class TestCachedResponseSuitabilityChecker {
     private HttpHost host;
     private HttpRequest request;
     private HttpCacheEntry entry;
-    private CacheValidityPolicy mockValidityPolicy;
     private CachedResponseSuitabilityChecker impl;
 
     @Before
@@ -63,7 +61,6 @@ public class TestCachedResponseSuitabilityChecker {
 
         host = new HttpHost("foo.example.com");
         request = new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1);
-        mockValidityPolicy = EasyMock.createNiceMock(CacheValidityPolicy.class);
         entry = HttpTestUtils.makeCacheEntry();
 
         impl = new CachedResponseSuitabilityChecker(CacheConfig.DEFAULT);
@@ -73,14 +70,6 @@ public class TestCachedResponseSuitabilityChecker {
         return HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, headers);
     }
 
-    public void replayMocks() {
-        EasyMock.replay(mockValidityPolicy);
-    }
-
-    public void verifyMocks() {
-        EasyMock.verify(mockValidityPolicy);
-    }
-
     @Test
     public void testNotSuitableIfContentLengthHeaderIsWrong() {
         final Header[] headers = {
@@ -261,4 +250,81 @@ public class TestCachedResponseSuitabilityChecker {
 
         Assert.assertTrue(impl.canCachedResponseBeUsed(host, request, entry, now));
     }
+
+    @Test
+    public void testSuitableIfRequestMethodisHEAD() {
+        final HttpRequest headRequest = new BasicHttpRequest("HEAD", "/foo", HttpVersion.HTTP_1_1);
+        final Header[] headers = {
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+                new BasicHeader("Cache-Control", "max-age=3600"),
+                new BasicHeader("Content-Length","128")
+        };
+        entry = getEntry(headers);
+
+        Assert.assertTrue(impl.canCachedResponseBeUsed(host, headRequest, entry, now));
+    }
+
+    @Test
+    public void testNotSuitableIfRequestMethodIsGETAndEntryResourceIsNull() {
+        final Header[] headers = {
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+                new BasicHeader("Cache-Control", "max-age=3600"),
+                new BasicHeader("Content-Length","128")
+        };
+        entry = HttpTestUtils.makeHeadCacheEntry(headers);
+
+        Assert.assertFalse(impl.canCachedResponseBeUsed(host, request, entry, now));
+    }
+
+    @Test
+    public void testNotSuitableForGETIfEntryDoesNotSpecifyARequestMethodOrEntity() {
+        impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
+        final Header[] headers = {
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+                new BasicHeader("Cache-Control", "max-age=3600"),
+                new BasicHeader("Content-Length","128")
+        };
+        entry = HttpTestUtils.makeCacheEntryWithNoRequestMethodOrEntity(headers);
+
+        Assert.assertFalse(impl.canCachedResponseBeUsed(host, request, entry, now));
+    }
+
+    @Test
+    public void testSuitableForGETIfEntryDoesNotSpecifyARequestMethodButContainsEntity() {
+        impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
+        final Header[] headers = {
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+                new BasicHeader("Cache-Control", "max-age=3600"),
+                new BasicHeader("Content-Length","128")
+        };
+        entry = HttpTestUtils.makeCacheEntryWithNoRequestMethod(headers);
+
+        Assert.assertTrue(impl.canCachedResponseBeUsed(host, request, entry, now));
+    }
+
+    @Test
+    public void testSuitableForGETIfHeadResponseCachingEnabledAndEntryDoesNotSpecifyARequestMethodButContains204Response() {
+        impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
+        final Header[] headers = {
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+                new BasicHeader("Cache-Control", "max-age=3600")
+        };
+        entry = HttpTestUtils.make204CacheEntryWithNoRequestMethod(headers);
+
+        Assert.assertTrue(impl.canCachedResponseBeUsed(host, request, entry, now));
+    }
+
+    @Test
+    public void testSuitableForHEADIfHeadResponseCachingEnabledAndEntryDoesNotSpecifyARequestMethod() {
+        final HttpRequest headRequest = new BasicHttpRequest("HEAD", "/foo", HttpVersion.HTTP_1_1);
+        impl = new CachedResponseSuitabilityChecker(CacheConfig.custom().build());
+        final Header[] headers = {
+                new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+                new BasicHeader("Cache-Control", "max-age=3600"),
+                new BasicHeader("Content-Length","128")
+        };
+        entry = HttpTestUtils.makeHeadCacheEntryWithNoRequestMethod(headers);
+
+        Assert.assertTrue(impl.canCachedResponseBeUsed(host, headRequest, entry, now));
+    }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExec.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExec.java
index 2683c93..abda62a 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExec.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExec.java
@@ -53,6 +53,7 @@ import org.apache.http.HttpVersion;
 import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpExecutionAware;
+import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.client.utils.DateUtils;
@@ -64,11 +65,12 @@ import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.message.BasicStatusLine;
 import org.apache.http.protocol.HTTP;
 import org.easymock.IExpectationSetters;
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+ at SuppressWarnings("boxing") // test code
 public class TestCachingExec extends TestCachingExecChain {
 
     private static final String GET_CURRENT_DATE = "getCurrentDate";
@@ -261,10 +263,8 @@ public class TestCachingExec extends TestCachingExecChain {
         backendExpectsRequestAndReturn(validate, originResponse);
         getCurrentDateReturns(responseDate);
         expect(impl.handleBackendResponse(
-                eq(route),
                 same(validate),
                 same(context),
-                (HttpExecutionAware) isNull(),
                 eq(requestDate),
                 eq(responseDate),
                 same(originResponse))).andReturn(finalResponse);
@@ -310,6 +310,36 @@ public class TestCachingExec extends TestCachingExecChain {
     }
 
     @Test
+    public void testRevalidationRewritesAbsoluteUri() throws Exception {
+
+        mockImplMethods(GET_CURRENT_DATE);
+
+        // Fail on an unexpected request, rather than causing a later NPE
+        EasyMock.resetToStrict(mockBackend);
+
+        final HttpRequestWrapper validate = HttpRequestWrapper.wrap(
+                new HttpGet("http://foo.example.com/resource"));
+        final HttpRequestWrapper relativeValidate = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/resource", HttpVersion.HTTP_1_1));
+        final CloseableHttpResponse originResponse = Proxies.enhanceResponse(
+            new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "Okay"));
+
+        conditionalRequestBuilderReturns(validate);
+        getCurrentDateReturns(requestDate);
+
+        final CloseableHttpResponse resp = mockBackend.execute(EasyMock.isA(HttpRoute.class),
+                eqRequest(relativeValidate), EasyMock.isA(HttpClientContext.class),
+                EasyMock.<HttpExecutionAware> isNull());
+        expect(resp).andReturn(originResponse);
+
+        getCurrentDateReturns(responseDate);
+
+        replayMocks();
+        impl.revalidateCacheEntry(route, request, context, null, entry);
+        verifyMocks();
+    }
+
+    @Test
     public void testEndlessResponsesArePassedThrough() throws Exception {
         impl = createCachingExecChain(mockBackend, new BasicHttpCache(), CacheConfig.DEFAULT);
 
@@ -403,10 +433,8 @@ public class TestCachingExec extends TestCachingExecChain {
             throws IOException {
         expect(
                 impl.handleBackendResponse(
-                        isA(HttpRoute.class),
                         same(request),
                         isA(HttpClientContext.class),
-                        (HttpExecutionAware) isNull(),
                         isA(Date.class),
                         isA(Date.class),
                         isA(CloseableHttpResponse.class))).andReturn(
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExecChain.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExecChain.java
index 7dfbd50..852c1ca 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExecChain.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingExecChain.java
@@ -80,12 +80,12 @@ import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.util.EntityUtils;
 import org.easymock.Capture;
 import org.easymock.IExpectationSetters;
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
- at SuppressWarnings({"boxing","static-access"}) // test code
+ at SuppressWarnings("boxing") // test code
 public abstract class TestCachingExecChain {
 
     private ClientExecChain impl;
@@ -139,7 +139,7 @@ public abstract class TestCachingExecChain {
         config = CacheConfig.DEFAULT;
         asyncValidator = new AsynchronousValidator(config);
 
-        host = new HttpHost("foo.example.com");
+        host = new HttpHost("foo.example.com", 80);
         route = new HttpRoute(host);
         request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/stuff",
             HttpVersion.HTTP_1_1));
@@ -328,9 +328,9 @@ public abstract class TestCachingExecChain {
 
     @Test
     public void testNonCacheableResponseIsNotCachedAndIsReturnedAsIs() throws Exception {
-        final CacheConfig config = CacheConfig.DEFAULT;
+        final CacheConfig configDefault = CacheConfig.DEFAULT;
         impl = createCachingExecChain(mockBackend, new BasicHttpCache(new HeapResourceFactory(),
-            mockStorage, config), config);
+            mockStorage, configDefault), configDefault);
 
         final HttpRequestWrapper req1 = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultRequest());
         final HttpResponse resp1 = HttpTestUtils.make200Response();
@@ -1781,8 +1781,9 @@ public abstract class TestCachingExecChain {
     }
 
     protected void responseIsGeneratedFromCache() {
-        expect(mockResponseGenerator.generateResponse((HttpCacheEntry) anyObject())).andReturn(
-            mockCachedResponse);
+        expect(
+            mockResponseGenerator.generateResponse((HttpRequestWrapper) anyObject(), (HttpCacheEntry) anyObject()))
+            .andReturn(mockCachedResponse);
     }
 
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedEntity.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedEntity.java
index 43775cb..2e728bd 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedEntity.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedEntity.java
@@ -26,11 +26,14 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import java.io.ByteArrayInputStream;
 
 import org.apache.http.client.cache.Resource;
 import org.apache.http.util.EntityUtils;
-import org.easymock.classextension.EasyMock;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -38,11 +41,9 @@ public class TestCombinedEntity {
 
     @Test
     public void testCombinedEntityBasics() throws Exception {
-        final Resource resource = EasyMock.createNiceMock(Resource.class);
-        EasyMock.expect(resource.getInputStream()).andReturn(
+        final Resource resource = mock(Resource.class);
+        when(resource.getInputStream()).thenReturn(
                 new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5 }));
-        resource.dispose();
-        EasyMock.replay(resource);
 
         final ByteArrayInputStream instream = new ByteArrayInputStream(new byte[] { 6, 7, 8, 9, 10 });
         final CombinedEntity entity = new CombinedEntity(resource, instream);
@@ -53,7 +54,8 @@ public class TestCombinedEntity {
         final byte[] result = EntityUtils.toByteArray(entity);
         Assert.assertArrayEquals(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, result);
 
-        EasyMock.verify(resource);
+        verify(resource).getInputStream();
+        verify(resource).dispose();
     }
 
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestConditionalRequestBuilder.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestConditionalRequestBuilder.java
index 22d50f9..aab1885 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestConditionalRequestBuilder.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestConditionalRequestBuilder.java
@@ -65,9 +65,9 @@ public class TestConditionalRequestBuilder {
         final String theUri = "/theuri";
         final String lastModified = "this is my last modified date";
 
-        final HttpRequest request = new BasicHttpRequest(theMethod, theUri);
-        request.addHeader("Accept-Encoding", "gzip");
-        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(request);
+        final HttpRequest basicRequest = new BasicHttpRequest(theMethod, theUri);
+        basicRequest.addHeader("Accept-Encoding", "gzip");
+        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(basicRequest);
 
         final Header[] headers = new Header[] {
                 new BasicHeader("Date", DateUtils.formatDate(new Date())),
@@ -76,11 +76,11 @@ public class TestConditionalRequestBuilder {
         final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
         final HttpRequestWrapper newRequest = impl.buildConditionalRequest(requestWrapper, cacheEntry);
 
-        Assert.assertNotSame(request, newRequest);
+        Assert.assertNotSame(basicRequest, newRequest);
 
         Assert.assertEquals(theMethod, newRequest.getRequestLine().getMethod());
         Assert.assertEquals(theUri, newRequest.getRequestLine().getUri());
-        Assert.assertEquals(request.getRequestLine().getProtocolVersion(), newRequest
+        Assert.assertEquals(basicRequest.getRequestLine().getProtocolVersion(), newRequest
                 .getRequestLine().getProtocolVersion());
         Assert.assertEquals(2, newRequest.getAllHeaders().length);
 
@@ -104,10 +104,10 @@ public class TestConditionalRequestBuilder {
             new BasicHeader("Last-Modified", lmDate),
             new BasicHeader("ETag", etag)
         };
-        final HttpRequest request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
-        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(request);
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        final HttpRequest result = impl.buildConditionalRequest(requestWrapper, entry);
+        final HttpRequest basicRequest = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
+        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(basicRequest);
+        final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
+        final HttpRequest result = impl.buildConditionalRequest(requestWrapper, cacheEntry);
         Assert.assertEquals(lmDate,
                 result.getFirstHeader("If-Modified-Since").getValue());
         Assert.assertEquals(etag,
@@ -120,9 +120,9 @@ public class TestConditionalRequestBuilder {
         final String theUri = "/theuri";
         final String theETag = "this is my eTag";
 
-        final HttpRequest request = new BasicHttpRequest(theMethod, theUri);
-        request.addHeader("Accept-Encoding", "gzip");
-        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(request);
+        final HttpRequest basicRequest = new BasicHttpRequest(theMethod, theUri);
+        basicRequest.addHeader("Accept-Encoding", "gzip");
+        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(basicRequest);
 
         final Header[] headers = new Header[] {
                 new BasicHeader("Date", DateUtils.formatDate(new Date())),
@@ -133,11 +133,11 @@ public class TestConditionalRequestBuilder {
 
         final HttpRequest newRequest = impl.buildConditionalRequest(requestWrapper, cacheEntry);
 
-        Assert.assertNotSame(request, newRequest);
+        Assert.assertNotSame(basicRequest, newRequest);
 
         Assert.assertEquals(theMethod, newRequest.getRequestLine().getMethod());
         Assert.assertEquals(theUri, newRequest.getRequestLine().getUri());
-        Assert.assertEquals(request.getRequestLine().getProtocolVersion(), newRequest
+        Assert.assertEquals(basicRequest.getRequestLine().getProtocolVersion(), newRequest
                 .getRequestLine().getProtocolVersion());
 
         Assert.assertEquals(3, newRequest.getAllHeaders().length);
@@ -151,8 +151,8 @@ public class TestConditionalRequestBuilder {
 
     @Test
     public void testCacheEntryWithMustRevalidateDoesEndToEndRevalidation() throws Exception {
-        final HttpRequest request = new BasicHttpRequest("GET","/",HttpVersion.HTTP_1_1);
-        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(request);
+        final HttpRequest basicRequest = new BasicHttpRequest("GET","/",HttpVersion.HTTP_1_1);
+        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(basicRequest);
         final Date now = new Date();
         final Date elevenSecondsAgo = new Date(now.getTime() - 11 * 1000L);
         final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
@@ -180,8 +180,8 @@ public class TestConditionalRequestBuilder {
 
     @Test
     public void testCacheEntryWithProxyRevalidateDoesEndToEndRevalidation() throws Exception {
-        final HttpRequest request = new BasicHttpRequest("GET","/",HttpVersion.HTTP_1_1);
-        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(request);
+        final HttpRequest basicRequest = new BasicHttpRequest("GET","/",HttpVersion.HTTP_1_1);
+        final HttpRequestWrapper requestWrapper = HttpRequestWrapper.wrap(basicRequest);
         final Date now = new Date();
         final Date elevenSecondsAgo = new Date(now.getTime() - 11 * 1000L);
         final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestExponentialBackingOffSchedulingStrategy.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestExponentialBackingOffSchedulingStrategy.java
index 7d5c366..40559af 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestExponentialBackingOffSchedulingStrategy.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestExponentialBackingOffSchedulingStrategy.java
@@ -26,13 +26,16 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import org.apache.http.HttpHost;
 import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.impl.execchain.ClientExecChain;
 import org.apache.http.message.BasicHttpRequest;
-import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -46,7 +49,7 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
     @Before
     public void setUp() {
-        mockExecutor = EasyMock.createMock(ScheduledExecutorService.class);
+        mockExecutor = mock(ScheduledExecutorService.class);
 
         impl = new ExponentialBackOffSchedulingStrategy(
                 mockExecutor,
@@ -62,9 +65,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithoutDelay(request);
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 0, TimeUnit.MILLISECONDS);
     }
 
     @Test
@@ -73,9 +76,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithDelay(request, TimeUnit.SECONDS.toMillis(6));
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 6000, TimeUnit.MILLISECONDS);
     }
 
     @Test
@@ -84,9 +87,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithDelay(request, TimeUnit.SECONDS.toMillis(60));
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 60000, TimeUnit.MILLISECONDS);
     }
 
     @Test
@@ -95,9 +98,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithDelay(request, TimeUnit.SECONDS.toMillis(600));
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 600000, TimeUnit.MILLISECONDS);
     }
 
     @Test
@@ -106,9 +109,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithDelay(request, TimeUnit.SECONDS.toMillis(6000));
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 6000000, TimeUnit.MILLISECONDS);
     }
 
     @Test
@@ -117,9 +120,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithDelay(request, TimeUnit.SECONDS.toMillis(60000));
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 60000000, TimeUnit.MILLISECONDS);
     }
 
     @Test
@@ -128,9 +131,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithDelay(request, TimeUnit.SECONDS.toMillis(86400));
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 86400000, TimeUnit.MILLISECONDS);
     }
 
     @Test
@@ -139,9 +142,9 @@ public class TestExponentialBackingOffSchedulingStrategy {
 
         expectRequestScheduledWithDelay(request, TimeUnit.SECONDS.toMillis(86400));
 
-        replayMocks();
         impl.schedule(request);
-        verifyMocks();
+
+        verify(mockExecutor).schedule(request, 86400000, TimeUnit.MILLISECONDS);
     }
 
     private void expectRequestScheduledWithoutDelay(final AsynchronousValidationRequest request) {
@@ -149,22 +152,14 @@ public class TestExponentialBackingOffSchedulingStrategy {
     }
 
     private void expectRequestScheduledWithDelay(final AsynchronousValidationRequest request, final long delayInMillis) {
-        EasyMock.expect(mockExecutor.schedule(request, delayInMillis, TimeUnit.MILLISECONDS)).andReturn(null);
-    }
-
-    private void replayMocks() {
-        EasyMock.replay(mockExecutor);
-    }
-
-    private void verifyMocks() {
-        EasyMock.verify(mockExecutor);
+        when(mockExecutor.schedule(request, delayInMillis, TimeUnit.MILLISECONDS)).thenReturn(null);
     }
 
     private AsynchronousValidationRequest createAsynchronousValidationRequest(final int errorCount) {
-        final ClientExecChain clientExecChain = EasyMock.createNiceMock(ClientExecChain.class);
+        final ClientExecChain clientExecChain = mock(ClientExecChain.class);
         final CachingExec cachingHttpClient = new CachingExec(clientExecChain);
         final AsynchronousValidator mockValidator = new AsynchronousValidator(impl);
-        final HttpRoute httpRoute = new HttpRoute(new HttpHost("foo.example.com"));
+        final HttpRoute httpRoute = new HttpRoute(new HttpHost("foo.example.com", 80));
         final HttpRequestWrapper httpRequestWrapper = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/"));
         final HttpClientContext httpClientContext = new HttpClientContext();
         return new AsynchronousValidationRequest(mockValidator, cachingHttpClient, httpRoute, httpRequestWrapper,
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java
index 628b0e1..188f08c 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java
@@ -32,7 +32,6 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.Date;
@@ -43,6 +42,7 @@ import org.apache.commons.codec.binary.Base64;
 import org.apache.http.Header;
 import org.apache.http.ProtocolVersion;
 import org.apache.http.StatusLine;
+import org.apache.http.client.cache.HeaderConstants;
 import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.cache.HttpCacheEntrySerializer;
 import org.apache.http.client.cache.Resource;
@@ -80,7 +80,7 @@ public class TestHttpCacheEntrySerializers {
         assertTrue(areEqual(readEntry, writeEntry));
     }
 
-    private HttpCacheEntry makeCacheEntryWithVariantMap() throws UnsupportedEncodingException {
+    private HttpCacheEntry makeCacheEntryWithVariantMap() {
         final Header[] headers = new Header[5];
         for (int i = 0; i < headers.length; i++) {
             headers[i] = new BasicHeader("header" + i, "value" + i);
@@ -94,7 +94,7 @@ public class TestHttpCacheEntrySerializers {
         variantMap.put("test variant 2","true");
         final HttpCacheEntry cacheEntry = new HttpCacheEntry(new Date(), new Date(),
                 slObj, headers, new HeapResource(Base64.decodeBase64(body
-                        .getBytes(UTF8.name()))), variantMap);
+                        .getBytes(UTF8))), variantMap, HeaderConstants.GET_METHOD);
 
         return cacheEntry;
     }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheJiraNumber1147.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheJiraNumber1147.java
index 99b78b8..ceb8f71 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheJiraNumber1147.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheJiraNumber1147.java
@@ -26,6 +26,13 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import java.io.File;
 import java.util.Date;
 
@@ -42,11 +49,11 @@ import org.apache.http.client.utils.DateUtils;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.impl.execchain.ClientExecChain;
 import org.apache.http.message.BasicHttpResponse;
-import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Matchers;
 
 public class TestHttpCacheJiraNumber1147 {
 
@@ -87,12 +94,14 @@ public class TestHttpCacheJiraNumber1147 {
         final ResourceFactory resourceFactory = new FileResourceFactory(cacheDir);
         final HttpCacheStorage httpCacheStorage = new ManagedHttpCacheStorage(cacheConfig);
 
-        final ClientExecChain backend = EasyMock.createNiceMock(ClientExecChain.class);
+        final ClientExecChain backend = mock(ClientExecChain.class);
         final HttpRequestWrapper get = HttpRequestWrapper.wrap(new HttpGet("http://somehost/"));
         final HttpClientContext context = HttpClientContext.create();
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
+        context.setTargetHost(target);
+
         final Date now = new Date();
         final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
 
@@ -103,12 +112,11 @@ public class TestHttpCacheJiraNumber1147 {
         response.setHeader("Cache-Control", "public, max-age=3600");
         response.setHeader("Last-Modified", DateUtils.formatDate(tenSecondsAgo));
 
-        EasyMock.expect(backend.execute(
-                EasyMock.eq(route),
-                EasyMock.isA(HttpRequestWrapper.class),
-                EasyMock.same(context),
-                EasyMock.<HttpExecutionAware>isNull())).andReturn(Proxies.enhanceResponse(response));
-        EasyMock.replay(backend);
+        when(backend.execute(
+                eq(route),
+                isA(HttpRequestWrapper.class),
+                isA(HttpClientContext.class),
+                (HttpExecutionAware) Matchers.isNull())).thenReturn(Proxies.enhanceResponse(response));
 
         final BasicHttpCache cache = new BasicHttpCache(resourceFactory, httpCacheStorage, cacheConfig);
         final ClientExecChain t = createCachingExecChain(backend, cache, cacheConfig);
@@ -117,23 +125,30 @@ public class TestHttpCacheJiraNumber1147 {
         Assert.assertEquals(200, response1.getStatusLine().getStatusCode());
         IOUtils.consume(response1.getEntity());
 
-        EasyMock.verify(backend);
+        verify(backend).execute(
+                eq(route),
+                isA(HttpRequestWrapper.class),
+                isA(HttpClientContext.class),
+                (HttpExecutionAware) Matchers.isNull());
 
         removeCache();
 
-        EasyMock.reset(backend);
-        EasyMock.expect(backend.execute(
-                EasyMock.eq(route),
-                EasyMock.isA(HttpRequestWrapper.class),
-                EasyMock.same(context),
-                EasyMock.<HttpExecutionAware>isNull())).andReturn(Proxies.enhanceResponse(response));
-        EasyMock.replay(backend);
+        reset(backend);
+        when(backend.execute(
+                eq(route),
+                isA(HttpRequestWrapper.class),
+                isA(HttpClientContext.class),
+                (HttpExecutionAware) Matchers.isNull())).thenReturn(Proxies.enhanceResponse(response));
 
         final HttpResponse response2 = t.execute(route, get, context, null);
         Assert.assertEquals(200, response2.getStatusLine().getStatusCode());
         IOUtils.consume(response2.getEntity());
 
-        EasyMock.verify(backend);
+        verify(backend).execute(
+                eq(route),
+                isA(HttpRequestWrapper.class),
+                isA(HttpClientContext.class),
+                (HttpExecutionAware) Matchers.isNull());
     }
 
     protected ClientExecChain createCachingExecChain(final ClientExecChain backend,
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestImmediateSchedulingStrategy.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestImmediateSchedulingStrategy.java
index 5d20b2c..fdb4805 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestImmediateSchedulingStrategy.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestImmediateSchedulingStrategy.java
@@ -26,7 +26,8 @@
  */
 package org.apache.http.impl.client.cache;
 
-import org.easymock.classextension.EasyMock;
+import static org.mockito.Mockito.mock;
+
 import org.junit.Before;
 import org.junit.Test;
 
@@ -40,8 +41,8 @@ public class TestImmediateSchedulingStrategy {
 
     @Before
     public void setUp() {
-        mockExecutor = EasyMock.createMock(ExecutorService.class);
-        mockRevalidationRequest = EasyMock.createNiceMock(AsynchronousValidationRequest.class);
+        mockExecutor = mock(ExecutorService.class);
+        mockRevalidationRequest = mock(AsynchronousValidationRequest.class);
         schedulingStrategy = new ImmediateSchedulingStrategy(mockExecutor);
     }
 
@@ -49,10 +50,6 @@ public class TestImmediateSchedulingStrategy {
     public void testRequestScheduledImmediately() {
         mockExecutor.execute(mockRevalidationRequest);
 
-        EasyMock.replay(mockExecutor);
-        EasyMock.replay(mockRevalidationRequest);
         schedulingStrategy.schedule(mockRevalidationRequest);
-        EasyMock.verify(mockExecutor);
-        EasyMock.verify(mockRevalidationRequest);
     }
-}
\ No newline at end of file
+}
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java
index da9bbb1..53d0d66 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolDeviations.java
@@ -50,7 +50,7 @@ import org.apache.http.message.BasicHttpEntityEnclosingRequest;
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.message.BasicHttpResponse;
 import org.easymock.Capture;
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -70,7 +70,7 @@ import org.junit.Test;
  * and are expected to be a drop-in replacement. The test cases captured here
  * document the places where we differ from the HTTP RFC.
  */
- at SuppressWarnings({"boxing","static-access"}) // test code
+ at SuppressWarnings("boxing") // test code
 public class TestProtocolDeviations {
 
     private static ProtocolVersion HTTP_1_1 = new ProtocolVersion("HTTP", 1, 1);
@@ -93,7 +93,7 @@ public class TestProtocolDeviations {
 
     @Before
     public void setUp() {
-        host = new HttpHost("foo.example.com");
+        host = new HttpHost("foo.example.com", 80);
 
         route = new HttpRoute(host);
 
@@ -221,7 +221,7 @@ public class TestProtocolDeviations {
         final byte[] bytes = new byte[128];
         new Random().nextBytes(bytes);
 
-        final HttpEntity mockBody = EasyMock.createMockBuilder(ByteArrayEntity.class).withConstructor(
+        final HttpEntity mockBody = org.easymock.classextension.EasyMock.createMockBuilder(ByteArrayEntity.class).withConstructor(
                 new Object[] { bytes }).addMockedMethods("getContentLength").createNiceMock();
         org.easymock.EasyMock.expect(mockBody.getContentLength()).andReturn(-1L).anyTimes();
         post.setEntity(mockBody);
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
index ca1881b..3378083 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
@@ -59,7 +59,7 @@ import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.protocol.HTTP;
 import org.easymock.Capture;
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -73,7 +73,6 @@ import org.junit.Test;
  * pass downstream to the backend HttpClient are are conditionally compliant
  * with the rules for an HTTP/1.1 client.
  */
- at SuppressWarnings({"static-access"}) // test code
 public class TestProtocolRequirements extends AbstractProtocolTest {
 
     @Test
@@ -4807,7 +4806,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
     protected void testUnsafeMethodDoesNotInvalidateCacheForHeaderUri(
             final HttpRequestWrapper unsafeReq) throws Exception, IOException {
 
-        final HttpHost otherHost = new HttpHost("bar.example.com");
+        final HttpHost otherHost = new HttpHost("bar.example.com", 80);
         final HttpRoute otherRoute = new HttpRoute(otherHost);
         final HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
                 new BasicHttpRequest("GET", "/content", HttpVersion.HTTP_1_1));
@@ -4843,12 +4842,12 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
     }
 
     protected HttpRequestWrapper makeRequestWithBody(final String method, final String requestUri) {
-        final HttpEntityEnclosingRequest request =
+        final HttpEntityEnclosingRequest req =
             new BasicHttpEntityEnclosingRequest(method, requestUri, HttpVersion.HTTP_1_1);
         final int nbytes = 128;
-        request.setEntity(HttpTestUtils.makeBody(nbytes));
-        request.setHeader("Content-Length",""+nbytes);
-        return HttpRequestWrapper.wrap(request);
+        req.setEntity(HttpTestUtils.makeBody(nbytes));
+        req.setHeader("Content-Length",""+nbytes);
+        return HttpRequestWrapper.wrap(req);
     }
 
     @Test
@@ -6050,7 +6049,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
         // received-by
         if (!Pattern.matches(tokenRegexp, parts[1])) {
             // host : port
-            new HttpHost(parts[1]);
+            new HttpHost(parts[1]); // TODO - unused - is this a test bug? else use Assert.assertNotNull
         }
 
         // comment
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java
index 0458f48..c69e6bf 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRFC5861Compliance.java
@@ -101,8 +101,8 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
 
         final HttpRequestWrapper req2 = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultRequest());
         final HttpResponse resp2 = HttpTestUtils.make500Response();
-        final byte[] body = HttpTestUtils.getRandomBytes(101);
-        final ByteArrayInputStream buf = new ByteArrayInputStream(body);
+        final byte[] body101 = HttpTestUtils.getRandomBytes(101);
+        final ByteArrayInputStream buf = new ByteArrayInputStream(body101);
         final ConsumableInputStream cis = new ConsumableInputStream(buf);
         final HttpEntity entity = new InputStreamEntity(cis, 101);
         resp2.setEntity(entity);
@@ -167,9 +167,9 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
     @Test
     public void testStaleIfErrorInResponseNeedNotYieldToProxyRevalidateForPrivateCache()
             throws Exception{
-        final CacheConfig config = CacheConfig.custom()
+        final CacheConfig configUnshared = CacheConfig.custom()
                 .setSharedCache(false).build();
-        impl = new CachingExec(mockBackend, new BasicHttpCache(config), config);
+        impl = new CachingExec(mockBackend, new BasicHttpCache(configUnshared), configUnshared);
 
         final Date tenSecondsAgo = new Date(new Date().getTime() - 10 * 1000L);
         final HttpRequestWrapper req1 = HttpRequestWrapper.wrap(HttpTestUtils.makeDefaultRequest());
@@ -367,6 +367,11 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
     }
 
     @Test
+    public void testHTTPCLIENT1470() {
+        impl = new CachingExec(mockBackend, cache, null, new AsynchronousValidator(config));
+    }
+
+    @Test
     public void testStaleWhileRevalidateReturnsStaleNonRevalidatableEntryWithWarning()
         throws Exception {
         config = CacheConfig.custom().setMaxCacheEntries(MAX_ENTRIES).setMaxObjectSize(MAX_BYTES)
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
index a07f180..e2ace06 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
@@ -91,10 +91,10 @@ public class TestRequestProtocolCompliance {
 
     @Test
     public void removesEntityFromTRACERequest() throws Exception {
-        final HttpEntityEnclosingRequest req =
+        final HttpEntityEnclosingRequest reqst =
             new BasicHttpEntityEnclosingRequest("TRACE", "/", HttpVersion.HTTP_1_1);
-        req.setEntity(HttpTestUtils.makeBody(50));
-        final HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(req);
+        reqst.setEntity(HttpTestUtils.makeBody(50));
+        final HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(reqst);
         impl.makeRequestCompliant(wrapper);
         if (wrapper instanceof HttpEntityEnclosingRequest) {
             assertNull(((HttpEntityEnclosingRequest) wrapper).getEntity());
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java
index 5734053..8bab0a5 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java
@@ -76,6 +76,12 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadCacheable() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testResponsesToRequestsWithAuthorizationHeadersAreNotCacheableBySharedCache() {
         request = new BasicHttpRequest("GET","/",HTTP_1_1);
         request.setHeader("Authorization","Basic dXNlcjpwYXNzd2Q=");
@@ -268,6 +274,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithNoCacheCacheable() {
+        response.addHeader("Cache-Control", "no-cache");
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsGetWithNoStoreCacheable() {
         response.addHeader("Cache-Control", "no-store");
 
@@ -275,6 +288,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithNoStoreCacheable() {
+        response.addHeader("Cache-Control", "no-store");
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsGetWithNoStoreEmbeddedInListCacheable() {
         response.addHeader("Cache-Control", "public, no-store");
 
@@ -282,6 +302,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithNoStoreEmbeddedInListCacheable() {
+        response.addHeader("Cache-Control", "public, no-store");
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsGetWithNoCacheEmbeddedInListCacheable() {
         response.addHeader("Cache-Control", "public, no-cache");
 
@@ -289,6 +316,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithNoCacheEmbeddedInListCacheable() {
+        response.addHeader("Cache-Control", "public, no-cache");
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsGetWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
         response.addHeader("Cache-Control", "max-age=20");
         response.addHeader("Cache-Control", "public, no-cache");
@@ -297,6 +331,14 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
+        response.addHeader("Cache-Control", "max-age=20");
+        response.addHeader("Cache-Control", "public, no-cache");
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsGetWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
         response.addHeader("Cache-Control", "max-age=20");
         response.addHeader("Cache-Control", "public, no-store");
@@ -305,6 +347,14 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
+        response.addHeader("Cache-Control", "max-age=20");
+        response.addHeader("Cache-Control", "public, no-store");
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsGetWithAnyCacheControlCacheable() {
         response.addHeader("Cache-Control", "max=10");
 
@@ -320,6 +370,22 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithAnyCacheControlCacheable() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        response.addHeader("Cache-Control", "max=10");
+
+        Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
+
+        response = new BasicHttpResponse(
+                new BasicStatusLine(HTTP_1_1, HttpStatus.SC_OK, ""));
+        response.setHeader("Date", DateUtils.formatDate(new Date()));
+        response.addHeader("Cache-Control", "no-transform");
+        response.setHeader("Content-Length", "0");
+
+        Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsGetWithout200Cacheable() {
         HttpResponse response404 = new BasicHttpResponse(new BasicStatusLine(HTTP_1_1,
                 HttpStatus.SC_NOT_FOUND, ""));
@@ -333,6 +399,19 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithout200Cacheable() {
+        HttpResponse response404 = new BasicHttpResponse(new BasicStatusLine(HTTP_1_1,
+                HttpStatus.SC_NOT_FOUND, ""));
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response404));
+
+        response404 = new BasicHttpResponse(new BasicStatusLine(HTTP_1_1,
+                HttpStatus.SC_GATEWAY_TIMEOUT, ""));
+
+        Assert.assertFalse(policy.isResponseCacheable("HEAD", response404));
+    }
+
+    @Test
     public void testVaryStarIsNotCacheable() {
         response.setHeader("Vary", "*");
         Assert.assertFalse(policy.isResponseCacheable("GET", response));
@@ -355,6 +434,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testIsHeadWithVaryHeaderCacheable() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        response.addHeader("Vary", "Accept-Encoding");
+        Assert.assertTrue(policy.isResponseCacheable("HEAD", response));
+    }
+
+    @Test
     public void testIsArbitraryMethodCacheable() {
 
         Assert.assertFalse(policy.isResponseCacheable("PUT", response));
@@ -486,6 +572,12 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheable() {
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
         policy = new ResponseCachingPolicy(0, true, true, false);
         request = new BasicHttpRequest("GET", "/foo?s=bar");
@@ -493,6 +585,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
+        policy = new ResponseCachingPolicy(0, true, true, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheable() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response.setHeader("Date", DateUtils.formatDate(now));
@@ -501,6 +600,15 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheable() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        Assert.assertTrue(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
         policy = new ResponseCachingPolicy(0, true, true, false);
         request = new BasicHttpRequest("GET", "/foo?s=bar");
@@ -510,6 +618,15 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
+        policy = new ResponseCachingPolicy(0, true, true, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        Assert.assertTrue(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
@@ -517,6 +634,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
         policy = new ResponseCachingPolicy(0, true, true, false);
         request = new BasicHttpRequest("GET", "/foo?s=bar");
@@ -525,6 +649,14 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
+        policy = new ResponseCachingPolicy(0, true, true, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
@@ -534,6 +666,16 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        Assert.assertTrue(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
         policy = new ResponseCachingPolicy(0, true, true, false);
         request = new BasicHttpRequest("GET", "/foo?s=bar");
@@ -544,6 +686,16 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
+        policy = new ResponseCachingPolicy(0, true, true, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response.setHeader("Via", "1.0 someproxy");
@@ -551,6 +703,13 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response.setHeader("Via", "1.0 someproxy");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response.setHeader("Date", DateUtils.formatDate(now));
@@ -560,6 +719,16 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        response.setHeader("Via", "1.0 someproxy");
+        Assert.assertTrue(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
         policy = new ResponseCachingPolicy(0, true, true, true);
         request = new BasicHttpRequest("GET", "/foo?s=bar");
@@ -570,6 +739,16 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
+        policy = new ResponseCachingPolicy(0, true, true, true);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        response.setHeader("Via", "1.0 someproxy");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response.setHeader("Date", DateUtils.formatDate(now));
@@ -579,6 +758,16 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        response.setHeader("Via", "HTTP/1.0 someproxy");
+        Assert.assertTrue(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
         policy = new ResponseCachingPolicy(0, true, true, true);
         request = new BasicHttpRequest("GET", "/foo?s=bar");
@@ -589,6 +778,16 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
+        policy = new ResponseCachingPolicy(0, true, true, true);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        response.setHeader("Via", "HTTP/1.0 someproxy");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void getsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
         response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
@@ -599,6 +798,17 @@ public class TestResponseCachingPolicy {
     }
 
     @Test
+    public void headsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
+        policy = new ResponseCachingPolicy(0, true, false, false);
+        request = new BasicHttpRequest("HEAD", "/foo?s=bar");
+        response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        response.setHeader("Date", DateUtils.formatDate(now));
+        response.setHeader("Expires", DateUtils.formatDate(tenSecondsFromNow));
+        response.setHeader("Via", "1.1 someproxy");
+        Assert.assertTrue(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
     public void notCacheableIfExpiresEqualsDateAndNoCacheControl() {
         response.setHeader("Date", DateUtils.formatDate(now));
         response.setHeader("Expires", DateUtils.formatDate(now));
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseProtocolCompliance.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseProtocolCompliance.java
index 24ca14f..6460e85 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseProtocolCompliance.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseProtocolCompliance.java
@@ -26,8 +26,8 @@
  */
 package org.apache.http.impl.client.cache;
 
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.util.Date;
@@ -151,4 +151,5 @@ public class TestResponseProtocolCompliance {
         }
         assertTrue(closed.set || bais.read() == -1);
     }
+
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestStaleWhileRevalidationReleasesConnection.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestStaleWhileRevalidationReleasesConnection.java
index 88f962b..b91feb4 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestStaleWhileRevalidationReleasesConnection.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestStaleWhileRevalidationReleasesConnection.java
@@ -26,6 +26,13 @@
  */
 package org.apache.http.impl.client.cache;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpException;
@@ -38,10 +45,12 @@ import org.apache.http.client.cache.CacheResponseStatus;
 import org.apache.http.client.cache.HttpCacheContext;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpGet;
+import org.apache.http.config.SocketConfig;
 import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.impl.bootstrap.HttpServer;
+import org.apache.http.impl.bootstrap.ServerBootstrap;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.localserver.LocalTestServer;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
@@ -49,13 +58,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Locale;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
 /**
  * Test that after background validation that a subsequent request for non cached
  * conent can be made.  This verifies that the connection has been release back to
@@ -65,7 +67,7 @@ public class TestStaleWhileRevalidationReleasesConnection {
 
     private static final EchoViaHeaderHandler cacheHandler = new EchoViaHeaderHandler();
 
-    protected LocalTestServer localServer;
+    protected HttpServer localServer;
     private int port;
     private CloseableHttpClient client;
     private final String url = "/static/dom";
@@ -74,12 +76,15 @@ public class TestStaleWhileRevalidationReleasesConnection {
 
     @Before
     public void start() throws Exception  {
-        this.localServer = new LocalTestServer(null, null);
-        this.localServer.register(url +"*", new EchoViaHeaderHandler());
-        localServer.setTimeout(5000);
+        this.localServer = ServerBootstrap.bootstrap()
+                .setSocketConfig(SocketConfig.custom()
+                        .setSoTimeout(5000)
+                        .build())
+                .registerHandler(url + "*", new EchoViaHeaderHandler())
+                .create();
         this.localServer.start();
 
-        port = this.localServer.getServiceAddress().getPort();
+        port = this.localServer.getLocalPort();
 
         final CacheConfig cacheConfig = CacheConfig.custom()
                 .setMaxCacheEntries(100)
@@ -235,7 +240,6 @@ public class TestStaleWhileRevalidationReleasesConnection {
 
         /**
          * Return the header the user can set the content that will be returned by the server
-         * @return
          */
         public String getUserContentHeader() {
             return DEFAULT_CLIENT_CONTROLLED_CONTENT_HEADER;
@@ -252,12 +256,13 @@ public class TestStaleWhileRevalidationReleasesConnection {
          * @throws org.apache.http.HttpException    in case of a problem
          * @throws java.io.IOException      in case of an IO problem
          */
+        @Override
         public void handle(final HttpRequest request,
                            final HttpResponse response,
                            final HttpContext context)
                 throws HttpException, IOException {
 
-            final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
+            final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
             if (!"GET".equals(method) &&
                     !"POST".equals(method) &&
                     !"PUT".equals(method)
@@ -280,11 +285,7 @@ public class TestStaleWhileRevalidationReleasesConnection {
         public byte[] getHeaderContent(final HttpRequest request) {
             final Header contentHeader = request.getFirstHeader(DEFAULT_CLIENT_CONTROLLED_CONTENT_HEADER);
             if(contentHeader!=null) {
-                try {
-                    return contentHeader.getValue().getBytes("UTF-8");
-                } catch(final UnsupportedEncodingException e) {
-                    return contentHeader.getValue().getBytes();
-                }
+                return contentHeader.getValue().getBytes(Consts.UTF_8);
             } else {
                 return DEFAULT_CONTENT;
             }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java
index 4072fa4..ee91cec 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java
@@ -26,6 +26,13 @@
  */
 package org.apache.http.impl.client.cache.ehcache;
 
+import static org.mockito.Matchers.isA;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -40,10 +47,9 @@ import org.apache.http.client.cache.HttpCacheUpdateCallback;
 import org.apache.http.client.cache.HttpCacheUpdateException;
 import org.apache.http.impl.client.cache.CacheConfig;
 import org.apache.http.impl.client.cache.HttpTestUtils;
-import org.easymock.EasyMock;
 import org.junit.Test;
 
- at SuppressWarnings({"boxing"}) // test code
+ at SuppressWarnings("boxing") // test code
 public class TestEhcacheHttpCacheStorage extends TestCase {
 
     private Ehcache mockCache;
@@ -52,22 +58,12 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
 
     @Override
     public void setUp() {
-        mockCache = EasyMock.createNiceMock(Ehcache.class);
+        mockCache = mock(Ehcache.class);
         final CacheConfig config = CacheConfig.custom().setMaxUpdateRetries(1).build();
-        mockSerializer = EasyMock.createNiceMock(HttpCacheEntrySerializer.class);
+        mockSerializer = mock(HttpCacheEntrySerializer.class);
         impl = new EhcacheHttpCacheStorage(mockCache, config, mockSerializer);
     }
 
-    private void replayMocks(){
-        EasyMock.replay(mockCache);
-        EasyMock.replay(mockSerializer);
-    }
-
-    private void verifyMocks(){
-        EasyMock.verify(mockCache);
-        EasyMock.verify(mockSerializer);
-    }
-
     @Test
     public void testCachePut() throws IOException {
         final String key = "foo";
@@ -75,23 +71,21 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
 
         final Element e = new Element(key, new byte[]{});
 
-        mockSerializer.writeTo(EasyMock.same(value), EasyMock.isA(OutputStream.class));
-        mockCache.put(e);
-
-        replayMocks();
         impl.putEntry(key, value);
-        verifyMocks();
+
+        verify(mockSerializer).writeTo(same(value), isA(OutputStream.class));
+        verify(mockCache).put(e);;
     }
 
     @Test
     public void testCacheGetNullEntry() throws IOException {
         final String key = "foo";
 
-        EasyMock.expect(mockCache.get(key)).andReturn(null);
+        when(mockCache.get(key)).thenReturn(null);
 
-        replayMocks();
         final HttpCacheEntry resultingEntry = impl.getEntry(key);
-        verifyMocks();
+
+        verify(mockCache).get(key);
 
         assertNull(resultingEntry);
     }
@@ -103,14 +97,15 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
 
         final Element element = new Element(key, new byte[]{});
 
-        EasyMock.expect(mockCache.get(key))
-                .andReturn(element);
-        EasyMock.expect(mockSerializer.readFrom(EasyMock.isA(InputStream.class)))
-                .andReturn(cachedValue);
+        when(mockCache.get(key))
+                .thenReturn(element);
+        when(mockSerializer.readFrom(isA(InputStream.class)))
+                .thenReturn(cachedValue);
 
-        replayMocks();
         final HttpCacheEntry resultingEntry = impl.getEntry(key);
-        verifyMocks();
+
+        verify(mockCache).get(key);
+        verify(mockSerializer).readFrom(isA(InputStream.class));
 
         assertSame(cachedValue, resultingEntry);
     }
@@ -119,11 +114,10 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
     public void testCacheRemove() {
         final String key = "foo";
 
-        EasyMock.expect(mockCache.remove(key)).andReturn(true);
+        when(mockCache.remove(key)).thenReturn(true);
 
-        replayMocks();
         impl.removeEntry(key);
-        verifyMocks();
+        verify(mockCache).remove(key);
     }
 
     @Test
@@ -134,6 +128,7 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         final Element element = new Element(key, new byte[]{});
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old){
                 assertNull(old);
                 return updatedValue;
@@ -141,15 +136,16 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         };
 
         // get empty old entry
-        EasyMock.expect(mockCache.get(key)).andReturn(null);
+        when(mockCache.get(key)).thenReturn(null);
 
         // put new entry
-        mockSerializer.writeTo(EasyMock.same(updatedValue), EasyMock.isA(OutputStream.class));
-        mockCache.put(element);
+        mockSerializer.writeTo(same(updatedValue), isA(OutputStream.class));
 
-        replayMocks();
         impl.updateEntry(key, callback);
-        verifyMocks();
+
+        verify(mockCache).get(key);
+        verify(mockSerializer).writeTo(same(updatedValue), isA(OutputStream.class));
+        verify(mockCache).put(element);
     }
 
     @Test
@@ -161,6 +157,7 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         final Element existingElement = new Element(key, new byte[]{});
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old){
                 assertEquals(existingValue, old);
                 return updatedValue;
@@ -168,16 +165,19 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         };
 
         // get existing old entry
-        EasyMock.expect(mockCache.get(key)).andReturn(existingElement);
-        EasyMock.expect(mockSerializer.readFrom(EasyMock.isA(InputStream.class))).andReturn(existingValue);
+        when(mockCache.get(key)).thenReturn(existingElement);
+        when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
 
         // update
-        mockSerializer.writeTo(EasyMock.same(updatedValue), EasyMock.isA(OutputStream.class));
-        EasyMock.expect(mockCache.replace(EasyMock.same(existingElement), EasyMock.isA(Element.class))).andReturn(true);
+        mockSerializer.writeTo(same(updatedValue), isA(OutputStream.class));
+        when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(true);
 
-        replayMocks();
         impl.updateEntry(key, callback);
-        verifyMocks();
+
+        verify(mockCache).get(key);
+        verify(mockSerializer).readFrom(isA(InputStream.class));
+        verify(mockSerializer).writeTo(same(updatedValue), isA(OutputStream.class));
+        verify(mockCache).replace(same(existingElement), isA(Element.class));
     }
 
     @Test
@@ -189,6 +189,7 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         final Element existingElement = new Element(key, new byte[]{});
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old){
                 assertEquals(existingValue, old);
                 return updatedValue;
@@ -196,20 +197,18 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         };
 
         // get existing old entry, will happen twice
-        EasyMock.expect(mockCache.get(key)).andReturn(existingElement).times(2);
-        EasyMock.expect(mockSerializer.readFrom(EasyMock.isA(InputStream.class))).andReturn(existingValue).times(2);
+        when(mockCache.get(key)).thenReturn(existingElement);
+        when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
 
-        // update but fail
-        mockSerializer.writeTo(EasyMock.same(updatedValue), EasyMock.isA(OutputStream.class));
-        EasyMock.expectLastCall().times(2);
-        EasyMock.expect(mockCache.replace(EasyMock.same(existingElement), EasyMock.isA(Element.class))).andReturn(false);
+        // Fail first and then succeed
+        when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(false).thenReturn(true);
 
-        // update again and succeed
-        EasyMock.expect(mockCache.replace(EasyMock.same(existingElement), EasyMock.isA(Element.class))).andReturn(true);
-
-        replayMocks();
         impl.updateEntry(key, callback);
-        verifyMocks();
+
+        verify(mockCache, times(2)).get(key);
+        verify(mockSerializer, times(2)).readFrom(isA(InputStream.class));
+        verify(mockSerializer, times(2)).writeTo(same(updatedValue), isA(OutputStream.class));
+        verify(mockCache, times(2)).replace(same(existingElement), isA(Element.class));
     }
 
     @Test
@@ -221,6 +220,7 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         final Element existingElement = new Element(key, new byte[]{});
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old){
                 assertEquals(existingValue, old);
                 return updatedValue;
@@ -228,19 +228,20 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
         };
 
         // get existing old entry
-        EasyMock.expect(mockCache.get(key)).andReturn(existingElement).times(2);
-        EasyMock.expect(mockSerializer.readFrom(EasyMock.isA(InputStream.class))).andReturn(existingValue).times(2);
+        when(mockCache.get(key)).thenReturn(existingElement);
+        when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
 
         // update but fail
-        mockSerializer.writeTo(EasyMock.same(updatedValue), EasyMock.isA(OutputStream.class));
-        EasyMock.expectLastCall().times(2);
-        EasyMock.expect(mockCache.replace(EasyMock.same(existingElement), EasyMock.isA(Element.class))).andReturn(false).times(2);
+        when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(false);
 
-        replayMocks();
         try{
             impl.updateEntry(key, callback);
             fail("Expected HttpCacheUpdateException");
         } catch (final HttpCacheUpdateException e) { }
-        verifyMocks();
+
+        verify(mockCache, times(2)).get(key);
+        verify(mockSerializer, times(2)).readFrom(isA(InputStream.class));
+        verify(mockSerializer, times(2)).writeTo(same(updatedValue), isA(OutputStream.class));
+        verify(mockCache, times(2)).replace(same(existingElement), isA(Element.class));
     }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtocolRequirements.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtocolRequirements.java
index d51d8d0..ddda48e 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtocolRequirements.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheProtocolRequirements.java
@@ -37,7 +37,7 @@ import org.apache.http.impl.client.cache.CachingExec;
 import org.apache.http.impl.client.cache.HeapResourceFactory;
 import org.apache.http.impl.client.cache.TestProtocolRequirements;
 import org.apache.http.impl.execchain.ClientExecChain;
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedCacheEntryImpl.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedCacheEntryImpl.java
index 2fa8947..84defa2 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedCacheEntryImpl.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedCacheEntryImpl.java
@@ -79,13 +79,13 @@ public class TestMemcachedCacheEntryImpl {
     @Test
     public void canBeReconstitutedFromByteArray() throws Exception {
         final String key = impl.getStorageKey();
-        final HttpCacheEntry entry = impl.getHttpCacheEntry();
+        final HttpCacheEntry entry1 = impl.getHttpCacheEntry();
         final byte[] bytes = impl.toByteArray();
         impl = new MemcachedCacheEntryImpl();
         impl.set(bytes);
 
         assertEquals(key, impl.getStorageKey());
-        assertEquivalent(entry, impl.getHttpCacheEntry());
+        assertEquivalent(entry1, impl.getHttpCacheEntry());
     }
 
     @Test(expected=MemcachedSerializationException.class)
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedHttpCacheStorage.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedHttpCacheStorage.java
index d4b18a4..a5ac52e 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedHttpCacheStorage.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestMemcachedHttpCacheStorage.java
@@ -26,6 +26,13 @@
  */
 package org.apache.http.impl.client.cache.memcached;
 
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
@@ -40,7 +47,6 @@ import org.apache.http.client.cache.HttpCacheUpdateCallback;
 import org.apache.http.client.cache.HttpCacheUpdateException;
 import org.apache.http.impl.client.cache.CacheConfig;
 import org.apache.http.impl.client.cache.HttpTestUtils;
-import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -57,38 +63,18 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
     @Override
     @Before
     public void setUp() throws Exception {
-        mockMemcachedClient = EasyMock.createNiceMock(MemcachedClientIF.class);
-        mockKeyHashingScheme = EasyMock.createNiceMock(KeyHashingScheme.class);
-        mockMemcachedCacheEntryFactory = EasyMock.createNiceMock(MemcachedCacheEntryFactory.class);
-        mockMemcachedCacheEntry = EasyMock.createNiceMock(MemcachedCacheEntry.class);
-        mockMemcachedCacheEntry2 = EasyMock.createNiceMock(MemcachedCacheEntry.class);
-        mockMemcachedCacheEntry3 = EasyMock.createNiceMock(MemcachedCacheEntry.class);
-        mockMemcachedCacheEntry4 = EasyMock.createNiceMock(MemcachedCacheEntry.class);
+        mockMemcachedClient = mock(MemcachedClientIF.class);
+        mockKeyHashingScheme = mock(KeyHashingScheme.class);
+        mockMemcachedCacheEntryFactory = mock(MemcachedCacheEntryFactory.class);
+        mockMemcachedCacheEntry = mock(MemcachedCacheEntry.class);
+        mockMemcachedCacheEntry2 = mock(MemcachedCacheEntry.class);
+        mockMemcachedCacheEntry3 = mock(MemcachedCacheEntry.class);
+        mockMemcachedCacheEntry4 = mock(MemcachedCacheEntry.class);
         final CacheConfig config = CacheConfig.custom().setMaxUpdateRetries(1).build();
         impl = new MemcachedHttpCacheStorage(mockMemcachedClient, config,
                 mockMemcachedCacheEntryFactory, mockKeyHashingScheme);
     }
 
-    private void replayMocks() {
-        EasyMock.replay(mockMemcachedClient);
-        EasyMock.replay(mockKeyHashingScheme);
-        EasyMock.replay(mockMemcachedCacheEntry);
-        EasyMock.replay(mockMemcachedCacheEntry2);
-        EasyMock.replay(mockMemcachedCacheEntry3);
-        EasyMock.replay(mockMemcachedCacheEntry4);
-        EasyMock.replay(mockMemcachedCacheEntryFactory);
-    }
-
-    private void verifyMocks() {
-        EasyMock.verify(mockMemcachedClient);
-        EasyMock.verify(mockKeyHashingScheme);
-        EasyMock.verify(mockMemcachedCacheEntry);
-        EasyMock.verify(mockMemcachedCacheEntry2);
-        EasyMock.verify(mockMemcachedCacheEntry3);
-        EasyMock.verify(mockMemcachedCacheEntry4);
-        EasyMock.verify(mockMemcachedCacheEntryFactory);
-    }
-
     @Test
     public void testSuccessfulCachePut() throws IOException {
         final String url = "foo";
@@ -96,18 +82,20 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
         final byte[] serialized = HttpTestUtils.getRandomBytes(128);
 
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
-            .andReturn(mockMemcachedCacheEntry);
-        EasyMock.expect(mockMemcachedCacheEntry.toByteArray())
-            .andReturn(serialized);
-        EasyMock.expect(mockKeyHashingScheme.hash(url))
-            .andReturn(key);
-        EasyMock.expect(mockMemcachedClient.set(key, 0, serialized))
-            .andReturn(null);
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.toByteArray())
+            .thenReturn(serialized);
+        when(mockKeyHashingScheme.hash(url))
+            .thenReturn(key);
+        when(mockMemcachedClient.set(key, 0, serialized))
+            .thenReturn(null);
 
-        replayMocks();
         impl.putEntry(url, value);
-        verifyMocks();
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
+        verify(mockMemcachedCacheEntry).toByteArray();
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).set(key, 0, serialized);
     }
 
     @Test
@@ -116,16 +104,18 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
         final byte[] serialized = HttpTestUtils.getRandomBytes(128);
 
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
-            .andReturn(mockMemcachedCacheEntry).times(0,1);
-        EasyMock.expect(mockMemcachedCacheEntry.toByteArray())
-            .andReturn(serialized).times(0,1);
-        EasyMock.expect(mockKeyHashingScheme.hash(url))
-            .andThrow(new MemcachedKeyHashingException(new Exception()));
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.toByteArray())
+            .thenReturn(serialized);
+        when(mockKeyHashingScheme.hash(url))
+            .thenThrow(new MemcachedKeyHashingException(new Exception()));
 
-        replayMocks();
         impl.putEntry(url, value);
-        verifyMocks();
+
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
+        verify(mockMemcachedCacheEntry).toByteArray();
+        verify(mockKeyHashingScheme).hash(url);
     }
 
     public void testThrowsIOExceptionWhenMemcachedPutTimesOut() {
@@ -134,22 +124,25 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
         final byte[] serialized = HttpTestUtils.getRandomBytes(128);
 
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
-            .andReturn(mockMemcachedCacheEntry);
-        EasyMock.expect(mockMemcachedCacheEntry.toByteArray())
-            .andReturn(serialized);
-        EasyMock.expect(mockKeyHashingScheme.hash(url))
-            .andReturn(key);
-        EasyMock.expect(mockMemcachedClient.set(key, 0, serialized))
-            .andThrow(new OperationTimeoutException("timed out"));
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.toByteArray())
+            .thenReturn(serialized);
+        when(mockKeyHashingScheme.hash(url))
+            .thenReturn(key);
+        when(mockMemcachedClient.set(key, 0, serialized))
+            .thenThrow(new OperationTimeoutException("timed out"));
 
-        replayMocks();
         try {
             impl.putEntry(url, value);
             fail("should have thrown exception");
         } catch (final IOException expected) {
         }
-        verifyMocks();
+
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
+        verify(mockMemcachedCacheEntry).toByteArray();
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).set(key, 0, serialized);
     }
 
     @Test
@@ -158,21 +151,20 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final String key = "key";
         final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
 
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
-            .andReturn(mockMemcachedCacheEntry);
-        EasyMock.expect(mockMemcachedCacheEntry.toByteArray())
-            .andThrow(new MemcachedSerializationException(new Exception()));
-        EasyMock.expect(mockKeyHashingScheme.hash(url))
-            .andReturn(key).times(0,1);
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.toByteArray())
+            .thenThrow(new MemcachedSerializationException(new Exception()));
 
-        replayMocks();
         try {
             impl.putEntry(url, value);
             fail("should have thrown exception");
         } catch (final IOException expected) {
 
         }
-        verifyMocks();
+
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
+        verify(mockMemcachedCacheEntry).toByteArray();
     }
 
     @Test
@@ -183,17 +175,22 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final byte[] serialized = HttpTestUtils.getRandomBytes(128);
         final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry();
 
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key);
-        EasyMock.expect(mockMemcachedClient.get(key)).andReturn(serialized);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
-            .andReturn(mockMemcachedCacheEntry);
-        mockMemcachedCacheEntry.set(serialized);
-        EasyMock.expect(mockMemcachedCacheEntry.getStorageKey()).andReturn(url);
-        EasyMock.expect(mockMemcachedCacheEntry.getHttpCacheEntry()).andReturn(cacheEntry);
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.get(key)).thenReturn(serialized);
+        when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.getStorageKey()).thenReturn(url);
+        when(mockMemcachedCacheEntry.getHttpCacheEntry()).thenReturn(cacheEntry);
 
-        replayMocks();
         final HttpCacheEntry resultingEntry = impl.getEntry(url);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).get(key);
+        verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
+        verify(mockMemcachedCacheEntry).set(serialized);
+        verify(mockMemcachedCacheEntry).getStorageKey();
+        verify(mockMemcachedCacheEntry).getHttpCacheEntry();
+
         assertSame(cacheEntry, resultingEntry);
     }
 
@@ -203,12 +200,14 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final String url = "foo";
         final String key = "key";
 
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key);
-        EasyMock.expect(mockMemcachedClient.get(key)).andReturn(new Object());
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.get(key)).thenReturn(new Object());
 
-        replayMocks();
         final HttpCacheEntry resultingEntry = impl.getEntry(url);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).get(key);
+
         assertNull(resultingEntry);
     }
 
@@ -218,12 +217,14 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final String url = "foo";
         final String key = "key";
 
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key);
-        EasyMock.expect(mockMemcachedClient.get(key)).andReturn(null);
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.get(key)).thenReturn(null);
 
-        replayMocks();
         final HttpCacheEntry resultingEntry = impl.getEntry(url);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).get(key);
+
         assertNull(resultingEntry);
     }
 
@@ -234,16 +235,18 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final String key = "key";
         final byte[] serialized = HttpTestUtils.getRandomBytes(128);
 
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key);
-        EasyMock.expect(mockMemcachedClient.get(key)).andReturn(serialized);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
-            .andReturn(mockMemcachedCacheEntry);
-        mockMemcachedCacheEntry.set(serialized);
-        EasyMock.expectLastCall().andThrow(new MemcachedSerializationException(new Exception()));
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.get(key)).thenReturn(serialized);
+        when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
+            .thenReturn(mockMemcachedCacheEntry);
+        doThrow(new MemcachedSerializationException(new Exception())).when(mockMemcachedCacheEntry).set(serialized);
 
-        replayMocks();
         assertNull(impl.getEntry(url));
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).get(key);
+        verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
+        verify(mockMemcachedCacheEntry).set(serialized);
     }
 
     @Test
@@ -251,65 +254,66 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
             IOException {
         final String url = "foo";
 
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andThrow(new MemcachedKeyHashingException(new Exception()));
+        when(mockKeyHashingScheme.hash(url)).thenThrow(new MemcachedKeyHashingException(new Exception()));
 
-        replayMocks();
         assertNull(impl.getEntry(url));
-        verifyMocks();
+        verify(mockKeyHashingScheme).hash(url);
     }
 
     @Test
     public void testThrowsIOExceptionIfMemcachedTimesOutOnGet() {
         final String url = "foo";
         final String key = "key";
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key);
-        EasyMock.expect(mockMemcachedClient.get(key))
-            .andThrow(new OperationTimeoutException(""));
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.get(key))
+            .thenThrow(new OperationTimeoutException(""));
 
-        replayMocks();
         try {
             impl.getEntry(url);
             fail("should have thrown exception");
         } catch (final IOException expected) {
         }
-        verifyMocks();
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).get(key);
     }
 
     @Test
     public void testCacheRemove() throws IOException {
         final String url = "foo";
         final String key = "key";
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key);
-        EasyMock.expect(mockMemcachedClient.delete(key)).andReturn(null);
-        replayMocks();
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.delete(key)).thenReturn(null);
+
         impl.removeEntry(url);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).delete(key);
     }
 
     @Test
     public void testCacheRemoveHandlesKeyHashingFailure() throws IOException {
         final String url = "foo";
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(null);
-        replayMocks();
+        when(mockKeyHashingScheme.hash(url)).thenReturn(null);
         impl.removeEntry(url);
-        verifyMocks();
+        verify(mockKeyHashingScheme).hash(url);
     }
 
     @Test
     public void testCacheRemoveThrowsIOExceptionOnMemcachedTimeout() {
         final String url = "foo";
         final String key = "key";
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key);
-        EasyMock.expect(mockMemcachedClient.delete(key))
-            .andThrow(new OperationTimeoutException(""));
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.delete(key))
+            .thenThrow(new OperationTimeoutException(""));
 
-        replayMocks();
         try {
             impl.removeEntry(url);
             fail("should have thrown exception");
         } catch (final IOException expected) {
         }
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).delete(key);
     }
 
     @Test
@@ -321,6 +325,7 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final byte[] serialized = HttpTestUtils.getRandomBytes(128);
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old) {
                 assertNull(old);
                 return updatedValue;
@@ -328,18 +333,22 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         };
 
         // get empty old entry
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key).anyTimes();
-        EasyMock.expect(mockMemcachedClient.gets(key)).andReturn(null);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
-            .andReturn(mockMemcachedCacheEntry);
-        EasyMock.expect(mockMemcachedCacheEntry.toByteArray()).andReturn(serialized);
-        EasyMock.expect(
-                mockMemcachedClient.set(EasyMock.eq(key), EasyMock.eq(0),
-                        EasyMock.aryEq(serialized))).andReturn(null);
-
-        replayMocks();
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.gets(key)).thenReturn(null);
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.toByteArray()).thenReturn(serialized);
+        when(
+                mockMemcachedClient.set(key, 0,
+                        serialized)).thenReturn(null);
+
         impl.updateEntry(url, callback);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme, times(2)).hash(url);
+        verify(mockMemcachedClient).gets(key);
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
+        verify(mockMemcachedCacheEntry).toByteArray();
+        verify(mockMemcachedClient).set(key,  0, serialized);
     }
 
     @Test
@@ -353,6 +362,7 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final byte[] newBytes = HttpTestUtils.getRandomBytes(128);
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old) {
                 assertNull(old);
                 return updatedValue;
@@ -360,23 +370,28 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         };
 
         // get empty old entry
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key).anyTimes();
-        EasyMock.expect(mockMemcachedClient.gets(key)).andReturn(casValue);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
-            .andReturn(mockMemcachedCacheEntry);
-        mockMemcachedCacheEntry.set(oldBytes);
-        EasyMock.expect(mockMemcachedCacheEntry.getStorageKey()).andReturn("not" + url).anyTimes();
-
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
-            .andReturn(mockMemcachedCacheEntry2);
-        EasyMock.expect(mockMemcachedCacheEntry2.toByteArray()).andReturn(newBytes);
-        EasyMock.expect(
-                mockMemcachedClient.set(EasyMock.eq(key), EasyMock.eq(0),
-                        EasyMock.aryEq(newBytes))).andReturn(null);
-
-        replayMocks();
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.gets(key)).thenReturn(casValue);
+        when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.getStorageKey()).thenReturn("not" + url);
+
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
+            .thenReturn(mockMemcachedCacheEntry2);
+        when(mockMemcachedCacheEntry2.toByteArray()).thenReturn(newBytes);
+        when(
+                mockMemcachedClient.set(key, 0,
+                        newBytes)).thenReturn(null);
+
         impl.updateEntry(url, callback);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme, times(2)).hash(url);
+        verify(mockMemcachedClient).gets(key);
+        verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
+        verify(mockMemcachedCacheEntry).getStorageKey();
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
+        verify(mockMemcachedCacheEntry2).toByteArray();
+        verify(mockMemcachedClient).set(key,  0, newBytes);
     }
 
     @Test
@@ -392,6 +407,7 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
 
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old) {
                 assertSame(existingValue, old);
                 return updatedValue;
@@ -399,25 +415,31 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         };
 
         // get empty old entry
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key).anyTimes();
-        EasyMock.expect(mockMemcachedClient.gets(key)).andReturn(casValue);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
-            .andReturn(mockMemcachedCacheEntry);
-        mockMemcachedCacheEntry.set(oldBytes);
-        EasyMock.expect(mockMemcachedCacheEntry.getStorageKey()).andReturn(url);
-        EasyMock.expect(mockMemcachedCacheEntry.getHttpCacheEntry()).andReturn(existingValue);
-
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
-            .andReturn(mockMemcachedCacheEntry2);
-        EasyMock.expect(mockMemcachedCacheEntry2.toByteArray()).andReturn(newBytes);
-
-        EasyMock.expect(
-                mockMemcachedClient.cas(EasyMock.eq(key), EasyMock.eq(casValue.getCas()),
-                        EasyMock.aryEq(newBytes))).andReturn(CASResponse.OK);
-
-        replayMocks();
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.gets(key)).thenReturn(casValue);
+        when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.getStorageKey()).thenReturn(url);
+        when(mockMemcachedCacheEntry.getHttpCacheEntry()).thenReturn(existingValue);
+
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
+            .thenReturn(mockMemcachedCacheEntry2);
+        when(mockMemcachedCacheEntry2.toByteArray()).thenReturn(newBytes);
+
+        when(
+                mockMemcachedClient.cas(key, casValue.getCas(),
+                        newBytes)).thenReturn(CASResponse.OK);
+
         impl.updateEntry(url, callback);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).gets(key);
+        verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
+        verify(mockMemcachedCacheEntry).getStorageKey();
+        verify(mockMemcachedCacheEntry).getHttpCacheEntry();
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
+        verify(mockMemcachedCacheEntry2).toByteArray();
+        verify(mockMemcachedClient).cas(key, casValue.getCas(), newBytes);
     }
 
     @Test
@@ -435,6 +457,7 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
                 mockMemcachedCacheEntryFactory, mockKeyHashingScheme);
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old) {
                 assertSame(existingValue, old);
                 return updatedValue;
@@ -442,29 +465,35 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         };
 
         // get empty old entry
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key).anyTimes();
-        EasyMock.expect(mockMemcachedClient.gets(key)).andReturn(casValue);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
-            .andReturn(mockMemcachedCacheEntry);
-        mockMemcachedCacheEntry.set(oldBytes);
-        EasyMock.expect(mockMemcachedCacheEntry.getStorageKey()).andReturn(url);
-        EasyMock.expect(mockMemcachedCacheEntry.getHttpCacheEntry()).andReturn(existingValue);
-
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
-            .andReturn(mockMemcachedCacheEntry2);
-        EasyMock.expect(mockMemcachedCacheEntry2.toByteArray()).andReturn(newBytes);
-
-        EasyMock.expect(
-                mockMemcachedClient.cas(EasyMock.eq(key), EasyMock.eq(casValue.getCas()),
-                        EasyMock.aryEq(newBytes))).andReturn(CASResponse.EXISTS);
-
-        replayMocks();
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.gets(key)).thenReturn(casValue);
+        when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
+            .thenReturn(mockMemcachedCacheEntry);
+        when(mockMemcachedCacheEntry.getStorageKey()).thenReturn(url);
+        when(mockMemcachedCacheEntry.getHttpCacheEntry()).thenReturn(existingValue);
+
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
+            .thenReturn(mockMemcachedCacheEntry2);
+        when(mockMemcachedCacheEntry2.toByteArray()).thenReturn(newBytes);
+
+        when(
+                mockMemcachedClient.cas(key, casValue.getCas(),
+                        newBytes)).thenReturn(CASResponse.EXISTS);
+
         try {
             impl.updateEntry(url, callback);
             fail("should have thrown exception");
         } catch (final HttpCacheUpdateException expected) {
         }
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).gets(key);
+        verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
+        verify(mockMemcachedCacheEntry).getStorageKey();
+        verify(mockMemcachedCacheEntry).getHttpCacheEntry();
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
+        verify(mockMemcachedCacheEntry2).toByteArray();
+        verify(mockMemcachedClient).cas(key, casValue.getCas(), newBytes);
     }
 
 
@@ -477,14 +506,12 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final HttpCacheEntry existingValue2 = HttpTestUtils.makeCacheEntry();
         final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
         final HttpCacheEntry updatedValue2 = HttpTestUtils.makeCacheEntry();
-        final byte[] oldBytes = HttpTestUtils.getRandomBytes(128);
         final byte[] oldBytes2 = HttpTestUtils.getRandomBytes(128);
-        final CASValue<Object> casValue = new CASValue<Object>(1, oldBytes);
         final CASValue<Object> casValue2 = new CASValue<Object>(2, oldBytes2);
-        final byte[] newBytes = HttpTestUtils.getRandomBytes(128);
         final byte[] newBytes2 = HttpTestUtils.getRandomBytes(128);
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old) {
                 if (old == existingValue) {
                     return updatedValue;
@@ -494,41 +521,43 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
             }
         };
 
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key).anyTimes();
-        EasyMock.expect(mockMemcachedClient.gets(key)).andReturn(casValue);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
-            .andReturn(mockMemcachedCacheEntry);
-        mockMemcachedCacheEntry.set(oldBytes);
-        EasyMock.expect(mockMemcachedCacheEntry.getStorageKey()).andReturn(url);
-        EasyMock.expect(mockMemcachedCacheEntry.getHttpCacheEntry()).andReturn(existingValue);
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
 
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
-            .andReturn(mockMemcachedCacheEntry2);
-        EasyMock.expect(mockMemcachedCacheEntry2.toByteArray()).andReturn(newBytes);
+        // take two
+        when(mockMemcachedClient.gets(key)).thenReturn(casValue2);
+        when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
+            .thenReturn(mockMemcachedCacheEntry3);
+        when(mockMemcachedCacheEntry3.getStorageKey()).thenReturn(url);
+        when(mockMemcachedCacheEntry3.getHttpCacheEntry()).thenReturn(existingValue2);
 
-        EasyMock.expect(
-                mockMemcachedClient.cas(EasyMock.eq(key), EasyMock.eq(casValue.getCas()),
-                        EasyMock.aryEq(newBytes))).andReturn(CASResponse.EXISTS);
+        when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue2))
+            .thenReturn(mockMemcachedCacheEntry4);
+        when(mockMemcachedCacheEntry4.toByteArray()).thenReturn(newBytes2);
+
+        when(
+                mockMemcachedClient.cas(key, casValue2.getCas(),
+                        newBytes2)).thenReturn(CASResponse.OK);
 
-        // take two
-        EasyMock.expect(mockMemcachedClient.gets(key)).andReturn(casValue2);
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
-            .andReturn(mockMemcachedCacheEntry3);
-        mockMemcachedCacheEntry3.set(oldBytes2);
-        EasyMock.expect(mockMemcachedCacheEntry3.getStorageKey()).andReturn(url);
-        EasyMock.expect(mockMemcachedCacheEntry3.getHttpCacheEntry()).andReturn(existingValue2);
-
-        EasyMock.expect(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue2))
-            .andReturn(mockMemcachedCacheEntry4);
-        EasyMock.expect(mockMemcachedCacheEntry4.toByteArray()).andReturn(newBytes2);
-
-        EasyMock.expect(
-                mockMemcachedClient.cas(EasyMock.eq(key), EasyMock.eq(casValue2.getCas()),
-                        EasyMock.aryEq(newBytes2))).andReturn(CASResponse.OK);
-
-        replayMocks();
         impl.updateEntry(url, callback);
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).gets(key);
+        verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
+
+        verify(mockMemcachedCacheEntry3).set(oldBytes2);
+        verify(mockMemcachedCacheEntry3).getStorageKey();
+        verify(mockMemcachedCacheEntry3).getHttpCacheEntry();
+        verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue2);
+        verify(mockMemcachedCacheEntry4).toByteArray();
+        verify(mockMemcachedClient).cas(key, casValue2.getCas(), newBytes2);
+
+        verifyNoMoreInteractions(mockMemcachedClient);
+        verifyNoMoreInteractions(mockKeyHashingScheme);
+        verifyNoMoreInteractions(mockMemcachedCacheEntry);
+        verifyNoMoreInteractions(mockMemcachedCacheEntry2);
+        verifyNoMoreInteractions(mockMemcachedCacheEntry3);
+        verifyNoMoreInteractions(mockMemcachedCacheEntry4);
+        verifyNoMoreInteractions(mockMemcachedCacheEntryFactory);
     }
 
 
@@ -539,6 +568,7 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
 
         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
+            @Override
             public HttpCacheEntry update(final HttpCacheEntry old) {
                 assertNull(old);
                 return updatedValue;
@@ -546,17 +576,18 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
         };
 
         // get empty old entry
-        EasyMock.expect(mockKeyHashingScheme.hash(url)).andReturn(key).anyTimes();
-        EasyMock.expect(mockMemcachedClient.gets(key))
-            .andThrow(new OperationTimeoutException(""));
+        when(mockKeyHashingScheme.hash(url)).thenReturn(key);
+        when(mockMemcachedClient.gets(key))
+            .thenThrow(new OperationTimeoutException(""));
 
-        replayMocks();
         try {
             impl.updateEntry(url, callback);
             fail("should have thrown exception");
         } catch (final IOException expected) {
         }
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
+        verify(mockMemcachedClient).gets(key);
     }
 
 
@@ -564,15 +595,15 @@ public class TestMemcachedHttpCacheStorage extends TestCase {
     public void testThrowsExceptionOnUpdateIfCannotHashStorageKey() throws Exception {
         final String url = "foo";
 
-        EasyMock.expect(mockKeyHashingScheme.hash(url))
-            .andThrow(new MemcachedKeyHashingException(new Exception()));
+        when(mockKeyHashingScheme.hash(url))
+            .thenThrow(new MemcachedKeyHashingException(new Exception()));
 
-        replayMocks();
         try {
             impl.updateEntry(url, null);
             fail("should have thrown exception");
         } catch (final HttpCacheUpdateException expected) {
         }
-        verifyMocks();
+
+        verify(mockKeyHashingScheme).hash(url);
     }
 }
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestPrefixKeyHashingScheme.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestPrefixKeyHashingScheme.java
index bef09c5..e91acc6 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestPrefixKeyHashingScheme.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestPrefixKeyHashingScheme.java
@@ -42,6 +42,7 @@ public class TestPrefixKeyHashingScheme {
     @Before
     public void setUp() {
         scheme = new KeyHashingScheme() {
+            @Override
             public String hash(final String storageKey) {
                 assertEquals(KEY, storageKey);
                 return "hash";
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestSHA256HashingScheme.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestSHA256HashingScheme.java
index 28f7b49..ea75c9b 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestSHA256HashingScheme.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/memcached/TestSHA256HashingScheme.java
@@ -37,7 +37,7 @@ public class TestSHA256HashingScheme {
     public void canHash() {
         final SHA256KeyHashingScheme impl = new SHA256KeyHashingScheme();
         final String result = impl.hash("hello, hashing world");
-        assertTrue(result != null && result.length() > 0);
+        assertTrue(result != null && !result.isEmpty());
     }
 
 }
diff --git a/httpclient-osgi/pom.xml b/httpclient-osgi/pom.xml
index 1c8a80f..8f9d78d 100644
--- a/httpclient-osgi/pom.xml
+++ b/httpclient-osgi/pom.xml
@@ -28,20 +28,20 @@
   <parent>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpcomponents-client</artifactId>
-    <version>4.3.5</version>
+    <version>4.4.1</version>
   </parent>
   <artifactId>httpclient-osgi</artifactId>
   <name>Apache HttpClient OSGi bundle</name>
   <inceptionYear>1999</inceptionYear>
   <description>
-   HttpComponents Client (OSGi bundle)
+   Apache HttpComponents Client (OSGi bundle)
   </description>
   <url>http://hc.apache.org/httpcomponents-client</url>
   <packaging>bundle</packaging>
 
   <properties>
-    <httpcore.osgi.import.version>"[4.3.0, 4.4.0)"</httpcore.osgi.import.version>
-    <commons-logging.osgi.import.version>"[1.1.0, 1.2.0)"</commons-logging.osgi.import.version>
+    <httpcore.osgi.import.version>"[4.4.0, 4.5.0)"</httpcore.osgi.import.version>
+    <commons-logging.osgi.import.version>"[1.1.0, 1.3.0)"</commons-logging.osgi.import.version>
   </properties>
 
   <dependencies>
@@ -54,7 +54,7 @@
     <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpcore</artifactId>
-      <scope>compile</scope>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>commons-codec</groupId>
@@ -132,6 +132,9 @@
             <Import-Package>
             javax.crypto,
             javax.crypto.spec,
+            javax.naming,
+            javax.naming.directory,
+            javax.naming.ldap,
             javax.net,
             javax.net.ssl,
             javax.security.auth.x500,
@@ -148,6 +151,7 @@
             org.apache.http.params;version=${httpcore.osgi.import.version},
             org.apache.http.pool;version=${httpcore.osgi.import.version},
             org.apache.http.protocol;version=${httpcore.osgi.import.version},
+            org.apache.http.ssl;version=${httpcore.osgi.import.version},
             org.apache.http.util;version=${httpcore.osgi.import.version},
             org.apache.http.impl;version=${httpcore.osgi.import.version},
             org.apache.http.impl.entity;version=${httpcore.osgi.import.version},
diff --git a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/HttpProxyConfigurationActivator.java b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/HttpProxyConfigurationActivator.java
index b641dd4..6586601 100644
--- a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/HttpProxyConfigurationActivator.java
+++ b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/HttpProxyConfigurationActivator.java
@@ -67,6 +67,7 @@ public final class HttpProxyConfigurationActivator implements BundleActivator, M
     /**
      * {@inheritDoc}
      */
+    @Override
     public void start(final BundleContext context) throws Exception {
         this.context = context;
 
@@ -85,6 +86,7 @@ public final class HttpProxyConfigurationActivator implements BundleActivator, M
     /**
      * {@inheritDoc}
      */
+    @Override
     public void stop(final BundleContext context) throws Exception {
         // unregister services
         for (final ServiceRegistration registeredConfiguration : registeredConfigurations.values()) {
@@ -116,6 +118,7 @@ public final class HttpProxyConfigurationActivator implements BundleActivator, M
     /**
      * {@inheritDoc}
      */
+    @Override
     public String getName() {
         return SERVICE_PID;
     }
@@ -123,6 +126,7 @@ public final class HttpProxyConfigurationActivator implements BundleActivator, M
     /**
      * {@inheritDoc}
      */
+    @Override
     public void updated(final String pid, @SuppressWarnings("rawtypes") final Dictionary config) throws ConfigurationException {
         final ServiceRegistration registration = registeredConfigurations.get(pid);
         OSGiProxyConfiguration proxyConfiguration;
@@ -146,6 +150,7 @@ public final class HttpProxyConfigurationActivator implements BundleActivator, M
     /**
      * {@inheritDoc}
      */
+    @Override
     public void deleted(final String pid) {
         final ServiceRegistration registeredConfiguration = registeredConfigurations.get(pid);
         if (null != registeredConfiguration) {
diff --git a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiClientBuilderFactory.java b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiClientBuilderFactory.java
index cbd5626..a8d1ed5 100644
--- a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiClientBuilderFactory.java
+++ b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiClientBuilderFactory.java
@@ -55,6 +55,7 @@ public final class OSGiClientBuilderFactory implements HttpClientBuilderFactory
         this.trackedHttpClients = trackedHttpClients;
     }
 
+    @Override
     public HttpClientBuilder newBuilder() {
         return new OSGiHttpClientBuilder(bundleContext, registeredConfigurations, trackedHttpClients);
     }
diff --git a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiCredentialsProvider.java b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiCredentialsProvider.java
index d4f6027..f2af640 100644
--- a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiCredentialsProvider.java
+++ b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiCredentialsProvider.java
@@ -55,6 +55,7 @@ final class OSGiCredentialsProvider implements CredentialsProvider {
     /**
      * {@inheritDoc}
      */
+    @Override
     public void setCredentials(final AuthScope authscope, final Credentials credentials) {
         // do nothing, not used in this version
     }
@@ -62,6 +63,7 @@ final class OSGiCredentialsProvider implements CredentialsProvider {
     /**
      * {@inheritDoc}
      */
+    @Override
     public Credentials getCredentials(final AuthScope authscope) {
         // iterate over all active proxy configurations at the moment of getting the credential
         for (final ServiceRegistration registration : registeredConfigurations.values()) {
@@ -85,6 +87,7 @@ final class OSGiCredentialsProvider implements CredentialsProvider {
     /**
      * {@inheritDoc}
      */
+    @Override
     public void clear() {
         // do nothing, not used in this version
     }
diff --git a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiHttpRoutePlanner.java b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiHttpRoutePlanner.java
index 01c2202..2f0fe5f 100644
--- a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiHttpRoutePlanner.java
+++ b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiHttpRoutePlanner.java
@@ -120,6 +120,7 @@ final class OSGiHttpRoutePlanner extends DefaultRoutePlanner {
             this.hostName = hostName;
         }
 
+        @Override
         public boolean matches(final String host) {
             return hostName.equalsIgnoreCase(host);
         }
@@ -130,11 +131,12 @@ final class OSGiHttpRoutePlanner extends DefaultRoutePlanner {
         private final String domainName;
 
         DomainNameMatcher(final String domainName) {
-            this.domainName = domainName.toLowerCase(Locale.ENGLISH);
+            this.domainName = domainName.toLowerCase(Locale.ROOT);
         }
 
+        @Override
         public boolean matches(final String host) {
-            return host.toLowerCase(Locale.ENGLISH).endsWith(domainName);
+            return host.toLowerCase(Locale.ROOT).endsWith(domainName);
         }
     }
 
@@ -146,6 +148,7 @@ final class OSGiHttpRoutePlanner extends DefaultRoutePlanner {
             this.address = address;
         }
 
+        @Override
         public boolean matches(final String host) {
             final NetworkAddress hostAddress = NetworkAddress.parse(host);
             return hostAddress != null && address.address == (hostAddress.address & address.mask);
@@ -185,7 +188,7 @@ final class OSGiHttpRoutePlanner extends DefaultRoutePlanner {
         }
 
         private static int toInt(final String value, final int max) {
-            if (value == null || value.length() == 0) {
+            if (value == null || value.isEmpty()) {
                 return max;
             }
 
diff --git a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiProxyConfiguration.java b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiProxyConfiguration.java
index df6dbc9..3a05160 100644
--- a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiProxyConfiguration.java
+++ b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/OSGiProxyConfiguration.java
@@ -43,7 +43,7 @@ public final class OSGiProxyConfiguration implements ProxyConfiguration {
      */
     private static final String PROPERTYNAME_PROXY_ENABLED = "proxy.enabled";
 
-    private static final boolean PROPERTYDEFAULT_PROXY_ENABLED = true;
+    private static final Boolean PROPERTYDEFAULT_PROXY_ENABLED = Boolean.TRUE;
 
     /**
      * Property representing the hostname of the proxy. Defaults to empty.
@@ -57,7 +57,7 @@ public final class OSGiProxyConfiguration implements ProxyConfiguration {
      */
     private static final String PROPERTYNAME_PROXY_PORT = "proxy.port";
 
-    private static final int PROPERTYDEFAULT_PROXY_PORT = 0;
+    private static final Integer PROPERTYDEFAULT_PROXY_PORT = Integer.valueOf(0);
 
     /**
      * Property representing the username to authenticate with towards the proxy. Defaults to empty.
@@ -81,11 +81,11 @@ public final class OSGiProxyConfiguration implements ProxyConfiguration {
 
     private static final String[] PROPERTYDEFAULT_PROXY_EXCEPTIONS = new String[]{"localhost", "127.0.0.1"};
 
-    private boolean enabled;
+    private Boolean enabled = Boolean.FALSE; // fewer boxing conversions needed when stored as an object
 
     private String hostname;
 
-    private int port;
+    private Integer port = Integer.valueOf(0); // fewer boxing conversions needed when stored as an object
 
     private String username;
 
@@ -93,26 +93,32 @@ public final class OSGiProxyConfiguration implements ProxyConfiguration {
 
     private String[] proxyExceptions;
 
+    @Override
     public boolean isEnabled() {
-        return enabled;
+        return enabled.booleanValue();
     }
 
+    @Override
     public String getHostname() {
         return hostname;
     }
 
+    @Override
     public int getPort() {
-        return port;
+        return port.intValue();
     }
 
+    @Override
     public String getUsername() {
         return username;
     }
 
+    @Override
     public String getPassword() {
         return password;
     }
 
+    @Override
     public String[] getProxyExceptions() {
         return proxyExceptions;
     }
diff --git a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/PropertiesUtils.java b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/PropertiesUtils.java
index c7690b1..f0ad493 100644
--- a/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/PropertiesUtils.java
+++ b/httpclient-osgi/src/main/java/org/apache/http/osgi/impl/PropertiesUtils.java
@@ -83,10 +83,10 @@ final class PropertiesUtils {
 
     /**
      * Returns the parameter as a single value. If the
-     * parameter is neither an array nor a <code>java.util.Collection</code> the
+     * parameter is neither an array nor a {@code java.util.Collection} the
      * parameter is returned unmodified. If the parameter is a non-empty array,
      * the first array element is returned. If the property is a non-empty
-     * <code>java.util.Collection</code>, the first collection element is returned.
+     * {@code java.util.Collection}, the first collection element is returned.
      *
      * @param propValue the parameter to convert.
      */
@@ -119,6 +119,7 @@ final class PropertiesUtils {
 
     private static class BooleanPropertyConverter implements PropertyConverter<Boolean> {
 
+        @Override
         public Boolean to(final Object propValue) {
             return Boolean.valueOf(String.valueOf(propValue));
         }
@@ -127,6 +128,7 @@ final class PropertiesUtils {
 
     private static class StringPropertyConverter implements PropertyConverter<String> {
 
+        @Override
         public String to(final Object propValue) {
             return String.valueOf(propValue);
         }
@@ -135,6 +137,7 @@ final class PropertiesUtils {
 
     private static class StringArrayPropertyConverter implements PropertyConverter<String[]> {
 
+        @Override
         public String[] to(final Object propValue) {
             if (propValue instanceof String) {
                 // single string
@@ -174,6 +177,7 @@ final class PropertiesUtils {
 
     private static class IntegerPropertyConverter implements PropertyConverter<Integer> {
 
+        @Override
         public Integer to(final Object propValue) {
             return Integer.valueOf(String.valueOf(propValue));
         }
@@ -182,6 +186,7 @@ final class PropertiesUtils {
 
     private static class LongPropertyConverter implements PropertyConverter<Long> {
 
+        @Override
         public Long to(final Object propValue) {
             return Long.valueOf(String.valueOf(propValue));
         }
@@ -190,6 +195,7 @@ final class PropertiesUtils {
 
     private static class DoublePropertyConverter implements PropertyConverter<Double> {
 
+        @Override
         public Double to(final Object propValue) {
             return Double.valueOf(String.valueOf(propValue));
         }
diff --git a/httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.xml b/httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.xml
index 2bddab4..ab59f1b 100644
--- a/httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.xml
+++ b/httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.xml
@@ -44,7 +44,7 @@
 
     <AD id="proxy.port"
       type="Integer"
-      default=""
+      default="8080"
       name="%proxy.port.name"
       description="%proxy.port.description" />
 
diff --git a/httpclient-osgi/src/test/java/org/apache/http/osgi/impl/TestPropertiesUtils.java b/httpclient-osgi/src/test/java/org/apache/http/osgi/impl/TestPropertiesUtils.java
index c0cc07a..60f0b56 100644
--- a/httpclient-osgi/src/test/java/org/apache/http/osgi/impl/TestPropertiesUtils.java
+++ b/httpclient-osgi/src/test/java/org/apache/http/osgi/impl/TestPropertiesUtils.java
@@ -35,20 +35,20 @@ import org.junit.Test;
 /**
  * @since 4.3
  */
+ at SuppressWarnings("boxing") // test code
 public final class TestPropertiesUtils {
 
     @Test
     public void toBoolean() {
         assertConverted(true, null, boolean.class, true);
-        assertConverted(true, null, Boolean.class, true); // TODO should these be Boolean.TRUE?
+        assertConverted(true, null, Boolean.class, true);
         assertConverted(false, "false", boolean.class, null);
-        assertConverted(false, "false", Boolean.class, null); // TODO should these be Boolean.FALSE?
+        assertConverted(false, "false", Boolean.class, null);
         // whatever value is interpreted as `false` by Boolean.valueOf
         assertConverted(false, "not a boolean", boolean.class, true);
-        assertConverted(false, "not a boolean", Boolean.class, true); // TODO should these be Boolean.FALSE/TRUE?
+        assertConverted(false, "not a boolean", Boolean.class, true);
     }
 
-    @SuppressWarnings("boxing")
     @Test
     public void toSingleString() {
         assertConverted("fallback to default value", null, String.class, "fallback to default value");
@@ -60,7 +60,6 @@ public final class TestPropertiesUtils {
         assertConverted("456789", 456789, String.class, null);
     }
 
-    @SuppressWarnings("boxing")
     @Test
     public void toStringArray() {
         assertConvertedArray(new String[]{"fallback to default value"},
@@ -88,7 +87,6 @@ public final class TestPropertiesUtils {
                              new String[]{"fallback to default value"});
     }
 
-    @SuppressWarnings("boxing")
     @Test
     public void toInt() {
         assertConverted(123, null, int.class, 123);
@@ -99,7 +97,6 @@ public final class TestPropertiesUtils {
         assertConverted(789, "not an integer", Integer.class, 789);
     }
 
-    @SuppressWarnings("boxing")
     @Test
     public void toLong() {
         assertConverted(123l, null, long.class, 123l);
@@ -110,7 +107,6 @@ public final class TestPropertiesUtils {
         assertConverted(789l, "not a long", Long.class, 789l);
     }
 
-    @SuppressWarnings("boxing")
     @Test
     public void toDouble() {
         assertConverted(123d, null, double.class, 123d);
diff --git a/httpclient-win/pom.xml b/httpclient-win/pom.xml
index b89719a..a7dcce1 100644
--- a/httpclient-win/pom.xml
+++ b/httpclient-win/pom.xml
@@ -23,19 +23,17 @@
    individuals on behalf of the Apache Software Foundation.  For more
    information on the Apache Software Foundation, please see
    <http://www.apache.org />.
- -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpcomponents-client</artifactId>
-    <version>4.3-beta3-SNAPSHOT</version>
+    <version>4.4.1</version>
   </parent>
-  <artifactId>winauth-jni</artifactId>
-  <name>Windows Integrated Auth</name>
+  <artifactId>httpclient-win</artifactId>
+  <name>Apache HttpClient Windows features</name>
   <description>
-   Windows Integrated Authentication for Apache HttpClient via JNI
+   Apache HttpClient Windows specific functionality
   </description>
   <url>http://hc.apache.org/httpcomponents-client</url>
   <packaging>jar</packaging>
@@ -48,6 +46,13 @@
       <scope>compile</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+      <classifier>tests</classifier>
+    </dependency>
+    <dependency>
       <groupId>net.java.dev.jna</groupId>
       <artifactId>jna</artifactId>
       <scope>compile</scope>
@@ -69,13 +74,13 @@
 
       <plugin>
         <artifactId>maven-javadoc-plugin</artifactId>
-         <version>${hc.javadoc.version}</version>
+        <version>${hc.javadoc.version}</version>
         <configuration>
           <!-- reduce console output. Can override with -Dquiet=false -->
           <quiet>true</quiet>
           <source>${maven.compiler.source}</source>
           <links>
-            <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
+            <link>http://docs.oracle.com/javase/6/docs/api/</link>
             <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
           </links>
         </configuration>
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java b/httpclient-win/src/examples/org/apache/http/examples/client/win/ClientWinAuth.java
similarity index 50%
copy from httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java
copy to httpclient-win/src/examples/org/apache/http/examples/client/win/ClientWinAuth.java
index fd581b0..97e3db7 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java
+++ b/httpclient-win/src/examples/org/apache/http/examples/client/win/ClientWinAuth.java
@@ -24,68 +24,40 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.examples.client;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.security.KeyStore;
+package org.apache.http.examples.client.win;
 
-import javax.net.ssl.SSLContext;
-
-import org.apache.http.HttpEntity;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.ssl.SSLContexts;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
 import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.client.WinHttpClients;
 import org.apache.http.util.EntityUtils;
 
 /**
- * This example demonstrates how to create secure connections with a custom SSL
- * context.
+ * This example demonstrates how to create HttpClient pre-configured
+ * with support for integrated Windows authentication.
  */
-public class ClientCustomSSL {
+public class ClientWinAuth {
 
     public final static void main(String[] args) throws Exception {
-        KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
-        FileInputStream instream = new FileInputStream(new File("my.keystore"));
-        try {
-            trustStore.load(instream, "nopassword".toCharArray());
-        } finally {
-            instream.close();
+
+        if (!WinHttpClients.isWinAuthAvailable()) {
+            System.out.println("Integrated Win auth is not supported!!!");
         }
 
-        // Trust own CA and all self-signed certs
-        SSLContext sslcontext = SSLContexts.custom()
-                .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
-                .build();
-        // Allow TLSv1 protocol only
-        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
-                sslcontext,
-                new String[] { "TLSv1" },
-                null,
-                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
-        CloseableHttpClient httpclient = HttpClients.custom()
-                .setSSLSocketFactory(sslsf)
-                .build();
+        CloseableHttpClient httpclient = WinHttpClients.createDefault();
+        // There is no need to provide user credentials
+        // HttpClient will attempt to access current user security context through
+        // Windows platform specific methods via JNI.
         try {
+            HttpGet httpget = new HttpGet("http://winhost/");
 
-            HttpGet httpget = new HttpGet("https://localhost/");
-
-            System.out.println("executing request" + httpget.getRequestLine());
-
+            System.out.println("Executing request " + httpget.getRequestLine());
             CloseableHttpResponse response = httpclient.execute(httpget);
             try {
-                HttpEntity entity = response.getEntity();
-
                 System.out.println("----------------------------------------");
                 System.out.println(response.getStatusLine());
-                if (entity != null) {
-                    System.out.println("Response content length: " + entity.getContentLength());
-                }
-                EntityUtils.consume(entity);
+                EntityUtils.consume(response.getEntity());
             } finally {
                 response.close();
             }
@@ -95,3 +67,4 @@ public class ClientCustomSSL {
     }
 
 }
+
diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java
index d4e2346..8174992 100644
--- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java
+++ b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java
@@ -33,21 +33,24 @@ import java.security.Principal;
 import org.apache.http.annotation.Immutable;
 import org.apache.http.auth.Credentials;
 
-import com.sun.jna.platform.win32.Secur32Util;
 import com.sun.jna.platform.win32.Secur32.EXTENDED_NAME_FORMAT;
+import com.sun.jna.platform.win32.Secur32Util;
 
 /**
  * Returns the current Windows user credentials
- * <p/>
+ * <p>
  * EXPERIMENTAL
+ * </p>
  *
- * @since 4.3
+ * @since 4.4
  */
 @Immutable
-public class CurrentWindowsCredentials implements Credentials, Serializable, Principal {
+public final class CurrentWindowsCredentials implements Credentials, Serializable, Principal {
 
     private static final long serialVersionUID = 4361166468529298169L;
 
+    public static final CurrentWindowsCredentials INSTANCE = new CurrentWindowsCredentials();
+
     /**
      * Get the SAM-compatible username of the currently logged-on user.
      *
@@ -60,30 +63,25 @@ public class CurrentWindowsCredentials implements Credentials, Serializable, Pri
     private CurrentWindowsCredentials() {
     }
 
-    private static class LazyHolder {
-        private static final CurrentWindowsCredentials INSTANCE = new CurrentWindowsCredentials();
-    }
-
-    public static CurrentWindowsCredentials get() {
-        return LazyHolder.INSTANCE;
-    }
-
+    @Override
     public Principal getUserPrincipal() {
         return this;
     }
 
     @Override
     public int hashCode() {
-        return 245678; // always the same?
+        return getClass().hashCode();
     }
 
     @Override
     public boolean equals(final Object o) {
-        if (this == o) return true;
-        if (o instanceof CurrentWindowsCredentials) {
+        if (this == o) {
             return true;
         }
-        return false;
+        if (o == null) {
+            return false;
+        }
+        return getClass().equals(o.getClass());
     }
 
     @Override
@@ -94,10 +92,12 @@ public class CurrentWindowsCredentials implements Credentials, Serializable, Pri
     /**
      * Returns an empty password
      */
+    @Override
     public String getPassword() {
         return "";
     }
 
+    @Override
     public String getName() {
         return getCurrentUsername();
     }
diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsCredentialsProvider.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsCredentialsProvider.java
new file mode 100644
index 0000000..aae9e22
--- /dev/null
+++ b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsCredentialsProvider.java
@@ -0,0 +1,76 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.auth.win;
+
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.AuthSchemes;
+import org.apache.http.util.Args;
+
+/**
+ * {@link org.apache.http.client.CredentialsProvider} implementation that always returns
+ * {@link org.apache.http.impl.auth.win.CurrentWindowsCredentials} instance to NTLM
+ * and SPNego authentication challenges.
+ * <p>
+ * EXPERIMENTAL
+ * </p>
+ *
+ * @since 4.4
+ */
+ at ThreadSafe
+public class WindowsCredentialsProvider implements CredentialsProvider {
+
+    private final CredentialsProvider provider;
+
+    public WindowsCredentialsProvider(final CredentialsProvider provider) {
+        this.provider = Args.notNull(provider, "Credentials provider");
+    }
+
+    @Override
+    public Credentials getCredentials(final AuthScope authscope) {
+        final String scheme = authscope.getScheme();
+        if (AuthSchemes.NTLM.equalsIgnoreCase(scheme) || AuthSchemes.SPNEGO.equalsIgnoreCase(scheme)) {
+            return CurrentWindowsCredentials.INSTANCE;
+        } else {
+            return provider.getCredentials(authscope);
+        }
+    }
+
+    @Override
+    public void setCredentials(final AuthScope authscope, final Credentials credentials) {
+        provider.setCredentials(authscope, credentials);
+    }
+
+    @Override
+    public void clear() {
+        provider.clear();
+    }
+}
+
+
diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNTLMSchemeFactory.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNTLMSchemeFactory.java
index 0f38e0b..94f715a 100644
--- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNTLMSchemeFactory.java
+++ b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNTLMSchemeFactory.java
@@ -36,16 +36,25 @@ import org.apache.http.protocol.HttpContext;
 /**
  * {@link AuthSchemeProvider} implementation that creates and initializes
  * {@link WindowsNegotiateScheme} using JNA to implement NTLM
- * <p/>
+ * <p>
  * EXPERIMENTAL
+ * </p>
  *
- * @since 4.3
+ * @since 4.4
  */
 @Immutable
 public class WindowsNTLMSchemeFactory implements AuthSchemeProvider {
 
+    private String servicePrincipalName;
+
+    public WindowsNTLMSchemeFactory(final String servicePrincipalName) {
+        super();
+        this.servicePrincipalName = servicePrincipalName;
+    }
+
+    @Override
     public AuthScheme create(final HttpContext context) {
-        return new WindowsNegotiateScheme(AuthSchemes.NTLM);
+        return new WindowsNegotiateScheme(AuthSchemes.NTLM, servicePrincipalName);
     }
 
 }
diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java
index bc93a34..29a6b42 100644
--- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java
+++ b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java
@@ -26,10 +26,11 @@
  */
 package org.apache.http.impl.auth.win;
 
-import java.util.Locale;
-
 import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.http.Header;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.annotation.NotThreadSafe;
 import org.apache.http.auth.AUTH;
@@ -38,6 +39,8 @@ import org.apache.http.auth.Credentials;
 import org.apache.http.auth.InvalidCredentialsException;
 import org.apache.http.auth.MalformedChallengeException;
 import org.apache.http.client.config.AuthSchemes;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.RouteInfo;
 import org.apache.http.impl.auth.AuthSchemeBase;
 import org.apache.http.message.BufferedHeader;
 import org.apache.http.protocol.HttpContext;
@@ -54,44 +57,41 @@ import com.sun.jna.platform.win32.WinError;
 import com.sun.jna.ptr.IntByReference;
 
 /**
- * Auth scheme that makes use of JNA to implement Negotiate & NTLM on Windows Platforms.
- * <p/>
+ * Auth scheme that makes use of JNA to implement Negotiate and NTLM on Windows Platforms.
+ * <p>
  * This will delegate negotiation to the windows machine.
- * <p/>
+ * </p>
+ * <p>
  * EXPERIMENTAL
+ * </p>
  *
- * @since 4.3
+ * @since 4.4
  */
 @NotThreadSafe
 public class WindowsNegotiateScheme extends AuthSchemeBase {
 
-    public static boolean isAvaliable() {
-        String os = System.getProperty("os.name");
-        os = os != null ? os.toLowerCase(Locale.ENGLISH) : null;
-        if (os != null && os.contains("windows")) {
-            try {
-                return Sspi.MAX_TOKEN_SIZE > 0;
-            } catch (Exception ignore) { // Likely ClassNotFound
-                return false;
-            }
-        }
-        return false;
-    }
+    private final Log log = LogFactory.getLog(getClass());
 
     // NTLM or Negotiate
     private final String scheme;
+    private final String servicePrincipalName;
 
     private CredHandle clientCred;
-    private CtxtHandle sppicontext;
+    private CtxtHandle sspiContext;
     private boolean continueNeeded;
     private String challenge;
 
-    public WindowsNegotiateScheme(final String scheme) {
+    public WindowsNegotiateScheme(final String scheme, final String servicePrincipalName) {
         super();
 
         this.scheme = (scheme == null) ? AuthSchemes.SPNEGO : scheme;
         this.challenge = null;
         this.continueNeeded = true;
+        this.servicePrincipalName = servicePrincipalName;
+
+        if (this.log.isDebugEnabled()) {
+            this.log.debug("Created WindowsNegotiateScheme using " + this.scheme);
+        }
     }
 
     public void dispose() {
@@ -101,15 +101,15 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
                 throw new Win32Exception(rc);
             }
         }
-        if (sppicontext != null && !sppicontext.isNull()) {
-            final int rc = Secur32.INSTANCE.DeleteSecurityContext(sppicontext);
+        if (sspiContext != null && !sspiContext.isNull()) {
+            final int rc = Secur32.INSTANCE.DeleteSecurityContext(sspiContext);
             if (WinError.SEC_E_OK != rc) {
                 throw new Win32Exception(rc);
             }
         }
         continueNeeded = true; // waiting
         clientCred = null;
-        sppicontext = null;
+        sspiContext = null;
     }
 
     @Override
@@ -118,25 +118,28 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
         super.finalize();
     }
 
+    @Override
     public String getSchemeName() {
         return scheme;
     }
 
     // String parameters not supported
+    @Override
     public String getParameter(final String name) {
         return null;
     }
 
     // NTLM/Negotiate do not support authentication realms
+    @Override
     public String getRealm() {
         return null;
     }
 
+    @Override
     public boolean isConnectionBased() {
         return true;
     }
 
-
     @Override
     protected void parseChallenge(
             final CharArrayBuffer buffer,
@@ -144,12 +147,12 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
             final int endIndex) throws MalformedChallengeException {
         this.challenge = buffer.substringTrimmed(beginIndex, endIndex);
 
-        if (this.challenge.length() == 0) {
+        if (this.challenge.isEmpty()) {
             if (clientCred != null) {
+                dispose(); // run cleanup first before throwing an exception otherwise can leak OS resources
                 if (continueNeeded) {
                     throw new RuntimeException("Unexpected token");
                 }
-                dispose();
             }
         }
     }
@@ -183,23 +186,33 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
                     throw new Win32Exception(rc);
                 }
 
-                response = getToken(null, null, username);
-            } catch (Throwable t) {
-                dispose();
-                throw new AuthenticationException("Authentication Failed", t);
+                final String targetName = getServicePrincipalName(context);
+                response = getToken(null, null, targetName);
+            } catch (RuntimeException ex) {
+                failAuthCleanup();
+                if (ex instanceof Win32Exception) {
+                    throw new AuthenticationException("Authentication Failed", ex);
+                } else {
+                    throw ex;
+                }
             }
-        } else if (this.challenge == null || this.challenge.length() == 0) {
-            dispose();
+        } else if (this.challenge == null || this.challenge.isEmpty()) {
+            failAuthCleanup();
             throw new AuthenticationException("Authentication Failed");
         } else {
             try {
                 final byte[] continueTokenBytes = Base64.decodeBase64(this.challenge);
                 final SecBufferDesc continueTokenBuffer = new SecBufferDesc(
                         Sspi.SECBUFFER_TOKEN, continueTokenBytes);
-                response = getToken(this.sppicontext, continueTokenBuffer, "localhost");
-            } catch (Throwable t) {
-                dispose();
-                throw new AuthenticationException("Authentication Failed", t);
+                final String targetName = getServicePrincipalName(context);
+                response = getToken(this.sspiContext, continueTokenBuffer, targetName);
+            } catch (RuntimeException ex) {
+                failAuthCleanup();
+                if (ex instanceof Win32Exception) {
+                    throw new AuthenticationException("Authentication Failed", ex);
+                } else {
+                    throw ex;
+                }
             }
         }
 
@@ -216,10 +229,43 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
         return new BufferedHeader(buffer);
     }
 
-    /**
-     * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375506(v=vs.85).aspx
-     */
-    private String getToken(
+    private void failAuthCleanup() {
+        dispose();
+        this.continueNeeded = false;
+    }
+
+    // Per RFC4559, the Service Principal Name should HTTP/<hostname>. However, <hostname>
+    // can just be the host or the fully qualified name (e.g., see "Kerberos SPN generation"
+    // at http://www.chromium.org/developers/design-documents/http-authentication). Here,
+    // I've chosen to use the host that has been provided in HttpHost so that I don't incur
+    // any additional DNS lookup cost.
+    private String getServicePrincipalName(final HttpContext context) {
+        final String spn;
+        if (this.servicePrincipalName != null) {
+            spn = this.servicePrincipalName;
+        } else {
+            final HttpClientContext clientContext = HttpClientContext.adapt(context);
+            final HttpHost target = clientContext.getTargetHost();
+            if (target != null) {
+                spn = "HTTP/" + target.getHostName();
+            } else {
+                final RouteInfo route = clientContext.getHttpRoute();
+                if (route != null) {
+                    spn = "HTTP/" + route.getTargetHost().getHostName();
+                } else {
+                    // Should not happen
+                    spn = null;
+                }
+            }
+        }
+        if (this.log.isDebugEnabled()) {
+            this.log.debug("Using SPN: " + spn);
+        }
+        return spn;
+    }
+
+    // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa375506(v=vs.85).aspx
+    String getToken(
             final CtxtHandle continueCtx,
             final SecBufferDesc continueToken,
             final String targetName) {
@@ -227,10 +273,10 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
         final SecBufferDesc token = new SecBufferDesc(
                 Sspi.SECBUFFER_TOKEN, Sspi.MAX_TOKEN_SIZE);
 
-        sppicontext = new CtxtHandle();
+        sspiContext = new CtxtHandle();
         final int rc = Secur32.INSTANCE.InitializeSecurityContext(clientCred,
-                continueCtx, targetName, Sspi.ISC_REQ_CONNECTION, 0,
-                Sspi.SECURITY_NATIVE_DREP, continueToken, 0, sppicontext, token,
+                continueCtx, targetName, Sspi.ISC_REQ_DELEGATE | Sspi.ISC_REQ_MUTUAL_AUTH, 0,
+                Sspi.SECURITY_NATIVE_DREP, continueToken, 0, sspiContext, token,
                 attr, null);
         switch (rc) {
             case WinError.SEC_I_CONTINUE_NEEDED:
@@ -247,10 +293,12 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
         return Base64.encodeBase64String(token.getBytes());
     }
 
+    @Override
     public boolean isComplete() {
         return !continueNeeded;
     }
 
+    @Override
     @Deprecated
     public Header authenticate(
             final Credentials credentials,
@@ -259,5 +307,3 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
     }
 
 }
-
-
diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateSchemeFactory.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateSchemeFactory.java
index 82f59c3..b1e3e57 100644
--- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateSchemeFactory.java
+++ b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateSchemeFactory.java
@@ -36,16 +36,25 @@ import org.apache.http.protocol.HttpContext;
 /**
  * {@link AuthSchemeProvider} implementation that creates and initializes
  * {@link WindowsNegotiateScheme} using JNA to Negotiate credentials
- * <p/>
+ * <p>
  * EXPERIMENTAL
+ * </p>
  *
- *  @since 4.3
+ *  @since 4.4
  */
 @Immutable
 public class WindowsNegotiateSchemeFactory implements AuthSchemeProvider {
 
+    private String servicePrincipalName;
+
+    public WindowsNegotiateSchemeFactory(final String servicePrincipalName) {
+        super();
+        this.servicePrincipalName = servicePrincipalName;
+    }
+
+    @Override
     public AuthScheme create(final HttpContext context) {
-        return new WindowsNegotiateScheme(AuthSchemes.SPNEGO);
+        return new WindowsNegotiateScheme(AuthSchemes.SPNEGO, servicePrincipalName);
     }
 
 }
diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/package-info.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/package-info.java
index 8439e1d..a16090a 100644
--- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/package-info.java
+++ b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/package-info.java
@@ -26,9 +26,10 @@
  */
 
 /**
- * Auth scheme that makes use of JNA to implement Negotiate & NTLM on Windows Platforms.
- * <p/>
+ * Auth scheme that makes use of JNA to implement Negotiate and NTLM on Windows Platforms.
+ * <p>
  * Please note this class is considered experimental and may be discontinued or removed
  * in the future.
+ * </p>
  */
 package org.apache.http.impl.auth.win;
diff --git a/httpclient-win/src/main/java/org/apache/http/impl/client/WinHttpClients.java b/httpclient-win/src/main/java/org/apache/http/impl/client/WinHttpClients.java
new file mode 100644
index 0000000..8b81fc5
--- /dev/null
+++ b/httpclient-win/src/main/java/org/apache/http/impl/client/WinHttpClients.java
@@ -0,0 +1,111 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.client;
+
+import java.util.Locale;
+
+import org.apache.http.auth.AuthSchemeProvider;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.AuthSchemes;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.impl.auth.BasicSchemeFactory;
+import org.apache.http.impl.auth.DigestSchemeFactory;
+import org.apache.http.impl.auth.win.WindowsCredentialsProvider;
+import org.apache.http.impl.auth.win.WindowsNTLMSchemeFactory;
+import org.apache.http.impl.auth.win.WindowsNegotiateSchemeFactory;
+
+import com.sun.jna.platform.win32.Sspi;
+
+/**
+ * Factory methods for {@link CloseableHttpClient} instances configured to use integrated
+ * Windows authentication by default.
+ *
+ * @since 4.4
+ */
+public class WinHttpClients {
+
+    private WinHttpClients() {
+        super();
+    }
+
+    public static boolean isWinAuthAvailable() {
+        String os = System.getProperty("os.name");
+        os = os != null ? os.toLowerCase(Locale.ROOT) : null;
+        if (os != null && os.contains("windows")) {
+            try {
+                return Sspi.MAX_TOKEN_SIZE > 0;
+            } catch (Exception ignore) { // Likely ClassNotFound
+                return false;
+            }
+        }
+        return false;
+    }
+
+    private static HttpClientBuilder createBuilder() {
+        if (isWinAuthAvailable()) {
+            final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
+                    .register(AuthSchemes.BASIC, new BasicSchemeFactory())
+                    .register(AuthSchemes.DIGEST, new DigestSchemeFactory())
+                    .register(AuthSchemes.NTLM, new WindowsNTLMSchemeFactory(null))
+                    .register(AuthSchemes.SPNEGO, new WindowsNegotiateSchemeFactory(null))
+                    .build();
+            final CredentialsProvider credsProvider = new WindowsCredentialsProvider(new SystemDefaultCredentialsProvider());
+            return HttpClientBuilder.create()
+                    .setDefaultCredentialsProvider(credsProvider)
+                    .setDefaultAuthSchemeRegistry(authSchemeRegistry);
+        } else {
+            return HttpClientBuilder.create();
+        }
+    }
+
+    /**
+     * Creates builder object for construction of custom
+     * {@link CloseableHttpClient} instances.
+     */
+    public static HttpClientBuilder custom() {
+        return createBuilder();
+    }
+
+    /**
+     * Creates {@link CloseableHttpClient} instance with default
+     * configuration.
+     */
+    public static CloseableHttpClient createDefault() {
+        return createBuilder().build();
+    }
+
+    /**
+     * Creates {@link CloseableHttpClient} instance with default
+     * configuration based on system properties.
+     */
+    public static CloseableHttpClient createSystem() {
+        return createBuilder().useSystemProperties().build();
+    }
+
+
+}
diff --git a/httpclient-win/src/test/java/org/apache/http/impl/auth/win/TestWindowsNegotiateScheme.java b/httpclient-win/src/test/java/org/apache/http/impl/auth/win/TestWindowsNegotiateScheme.java
new file mode 100644
index 0000000..6ff2d74
--- /dev/null
+++ b/httpclient-win/src/test/java/org/apache/http/impl/auth/win/TestWindowsNegotiateScheme.java
@@ -0,0 +1,140 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.auth.win;
+
+import java.io.IOException;
+
+import com.sun.jna.platform.win32.Sspi.CtxtHandle;
+import com.sun.jna.platform.win32.Sspi.SecBufferDesc;
+import com.sun.jna.platform.win32.Win32Exception;
+import com.sun.jna.platform.win32.WinError;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AUTH;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthSchemeProvider;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.AuthSchemes;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
+import org.apache.http.impl.client.WinHttpClients;
+import org.apache.http.localserver.LocalServerTestBase;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.util.EntityUtils;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for Windows negotiate authentication.
+ */
+public class TestWindowsNegotiateScheme extends LocalServerTestBase {
+
+    @Before @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        this.serverBootstrap.registerHandler("/", new HttpRequestHandler() {
+
+            @Override
+            public void handle(
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
+                response.addHeader(AUTH.WWW_AUTH, AuthSchemes.SPNEGO);
+                response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
+            }
+
+        });
+    }
+
+    @After @Override
+    public void shutDown() throws Exception {
+        super.shutDown();
+    }
+
+    @Test(timeout=30000) // this timeout (in ms) needs to be extended if you're actively debugging the code
+    public void testNoInfiniteLoopOnSPNOutsideDomain() throws Exception {
+        Assume.assumeTrue("Test can only be run on Windows", WinHttpClients.isWinAuthAvailable());
+
+        // HTTPCLIENT-1545
+        // If a service principle name (SPN) from outside your Windows domain tree (e.g., HTTP/example.com) is used,
+        // InitializeSecurityContext will return SEC_E_DOWNGRADE_DETECTED (decimal: -2146892976, hex: 0x80090350).
+        // Because WindowsNegotiateScheme wasn't setting the completed state correctly when authentication fails,
+        // HttpClient goes into an infinite loop, constantly retrying the negotiate authentication to kingdom
+        // come. This error message, "The system detected a possible attempt to compromise security. Please ensure that
+        // you can contact the server that authenticated you." is associated with SEC_E_DOWNGRADE_DETECTED.
+
+        final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
+            .register(AuthSchemes.SPNEGO, new AuthSchemeProvider() {
+                public AuthScheme create(final HttpContext context) {
+                    return new WindowsNegotiateSchemeGetTokenFail(AuthSchemes.SPNEGO, "HTTP/example.com");
+                }
+            }).build();
+        final CredentialsProvider credsProvider =
+                new WindowsCredentialsProvider(new SystemDefaultCredentialsProvider());
+        final CloseableHttpClient customClient = HttpClientBuilder.create()
+                .setDefaultCredentialsProvider(credsProvider)
+                .setDefaultAuthSchemeRegistry(authSchemeRegistry).build();
+
+        final HttpHost target = start();
+        final HttpGet httpGet = new HttpGet("/");
+        final CloseableHttpResponse response = customClient.execute(target, httpGet);
+        try {
+            EntityUtils.consume(response.getEntity());
+        } finally {
+            response.close();
+        }
+    }
+
+    private final class WindowsNegotiateSchemeGetTokenFail extends WindowsNegotiateScheme {
+
+        public WindowsNegotiateSchemeGetTokenFail(final String scheme, final String servicePrincipalName) {
+            super(scheme, servicePrincipalName);
+        }
+
+        @Override
+        String getToken(final CtxtHandle continueCtx, final SecBufferDesc continueToken, final String targetName) {
+            dispose();
+            /* We will rather throw SEC_E_TARGET_UNKNOWN because SEC_E_DOWNGRADE_DETECTED is not
+             * available on Windows XP and this unit test always fails.
+             */
+            throw new Win32Exception(WinError.SEC_E_TARGET_UNKNOWN);
+        }
+
+    }
+
+}
diff --git a/httpclient/pom.xml b/httpclient/pom.xml
index a436643..1cd8213 100644
--- a/httpclient/pom.xml
+++ b/httpclient/pom.xml
@@ -28,12 +28,12 @@
   <parent>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpcomponents-client</artifactId>
-    <version>4.3.5</version>
+    <version>4.4.1</version>
   </parent>
   <artifactId>httpclient</artifactId>
   <name>Apache HttpClient</name>
   <description>
-   HttpComponents Client
+   Apache HttpComponents Client
   </description>
   <url>http://hc.apache.org/httpcomponents-client</url>
   <packaging>jar</packaging>
@@ -97,6 +97,25 @@
         </executions>
       </plugin>
       <plugin>
+        <groupId>com.googlecode.maven-download-plugin</groupId>
+        <artifactId>download-maven-plugin</artifactId>
+        <version>1.2.0</version>
+        <executions>
+          <execution>
+            <id>download-public-suffix-list</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>wget</goal>
+            </goals>
+            <configuration>
+              <url>https://publicsuffix.org/list/effective_tld_names.dat</url>
+              <outputDirectory>${project.build.outputDirectory}/mozilla</outputDirectory>
+              <outputFileName>public-suffix-list.txt</outputFileName>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <artifactId>maven-jar-plugin</artifactId>
         <executions>
           <execution>
@@ -114,13 +133,13 @@
 
       <plugin>
         <artifactId>maven-javadoc-plugin</artifactId>
-         <version>${hc.javadoc.version}</version>
+        <version>${hc.javadoc.version}</version>
         <configuration>
           <!-- reduce console output. Can override with -Dquiet=false -->
           <quiet>true</quiet>
           <source>${maven.compiler.source}</source>
           <links>
-            <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
+            <link>http://docs.oracle.com/javase/6/docs/api/</link>
             <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
           </links>
         </configuration>
@@ -161,4 +180,22 @@
     </plugins>
   </reporting>
 
+  <profiles>
+    <profile>
+      <id>release</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>com.googlecode.maven-download-plugin</groupId>
+            <artifactId>download-maven-plugin</artifactId>
+            <configuration>
+              <overwrite>true</overwrite>
+              <skipCache>true</skipCache>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
 </project>
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientConfiguration.java b/httpclient/src/examples/org/apache/http/examples/client/ClientConfiguration.java
index d6c38e9..ac6aa39 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientConfiguration.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientConfiguration.java
@@ -60,18 +60,15 @@ import org.apache.http.conn.ManagedHttpClientConnection;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLContexts;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
 import org.apache.http.impl.DefaultHttpResponseFactory;
 import org.apache.http.impl.client.BasicCookieStore;
 import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
 import org.apache.http.impl.conn.DefaultHttpResponseParser;
 import org.apache.http.impl.conn.DefaultHttpResponseParserFactory;
+import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.impl.conn.SystemDefaultDnsResolver;
 import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
@@ -82,6 +79,7 @@ import org.apache.http.io.SessionInputBuffer;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicLineParser;
 import org.apache.http.message.LineParser;
+import org.apache.http.ssl.SSLContexts;
 import org.apache.http.util.CharArrayBuffer;
 
 /**
@@ -141,14 +139,12 @@ public class ClientConfiguration {
         // SSL context for secure connections can be created either based on
         // system or application specific properties.
         SSLContext sslcontext = SSLContexts.createSystemDefault();
-        // Use custom hostname verifier to customize SSL hostname verification.
-        X509HostnameVerifier hostnameVerifier = new BrowserCompatHostnameVerifier();
 
         // Create a registry of custom connection socket factories for supported
         // protocol schemes.
         Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
             .register("http", PlainConnectionSocketFactory.INSTANCE)
-            .register("https", new SSLConnectionSocketFactory(sslcontext, hostnameVerifier))
+            .register("https", new SSLConnectionSocketFactory(sslcontext))
             .build();
 
         // Use custom DNS resolver to override the system DNS resolution.
@@ -177,6 +173,8 @@ public class ClientConfiguration {
         // by default or for a specific host.
         connManager.setDefaultSocketConfig(socketConfig);
         connManager.setSocketConfig(new HttpHost("somehost", 80), socketConfig);
+        // Validate connections after 1 sec of inactivity
+        connManager.setValidateAfterInactivity(1000);
 
         // Create message constraints
         MessageConstraints messageConstraints = MessageConstraints.custom()
@@ -207,9 +205,8 @@ public class ClientConfiguration {
         CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
         // Create global request configuration
         RequestConfig defaultRequestConfig = RequestConfig.custom()
-            .setCookieSpec(CookieSpecs.BEST_MATCH)
+            .setCookieSpec(CookieSpecs.DEFAULT)
             .setExpectContinueEnabled(true)
-            .setStaleConnectionCheckEnabled(true)
             .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
             .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
             .build();
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java b/httpclient/src/examples/org/apache/http/examples/client/ClientCustomPublicSuffixList.java
similarity index 55%
copy from httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java
copy to httpclient/src/examples/org/apache/http/examples/client/ClientCustomPublicSuffixList.java
index fd581b0..0246caf 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientCustomPublicSuffixList.java
@@ -26,55 +26,56 @@
  */
 package org.apache.http.examples.client;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.security.KeyStore;
-
-import javax.net.ssl.SSLContext;
+import java.net.URL;
 
 import org.apache.http.HttpEntity;
+import org.apache.http.client.config.CookieSpecs;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.ssl.SSLContexts;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
+import org.apache.http.config.Lookup;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.apache.http.conn.util.PublicSuffixMatcherLoader;
+import org.apache.http.cookie.CookieSpecProvider;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
 import org.apache.http.util.EntityUtils;
 
 /**
- * This example demonstrates how to create secure connections with a custom SSL
- * context.
+ * This example demonstrates how to use a custom public suffix list.
  */
-public class ClientCustomSSL {
+public class ClientCustomPublicSuffixList {
 
     public final static void main(String[] args) throws Exception {
-        KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
-        FileInputStream instream = new FileInputStream(new File("my.keystore"));
-        try {
-            trustStore.load(instream, "nopassword".toCharArray());
-        } finally {
-            instream.close();
-        }
 
-        // Trust own CA and all self-signed certs
-        SSLContext sslcontext = SSLContexts.custom()
-                .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
+        // Use PublicSuffixMatcherLoader to load public suffix list from a file,
+        // resource or from an arbitrary URL
+        PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.load(
+                new URL("https://publicsuffix.org/list/effective_tld_names.dat"));
+
+        // Please use the publicsuffix.org URL to download the list no more than once per day !!!
+        // Please consider making a local copy !!!
+
+        DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
+
+        RFC6265CookieSpecProvider cookieSpecProvider = new RFC6265CookieSpecProvider(publicSuffixMatcher);
+        Lookup<CookieSpecProvider> cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
+                .register(CookieSpecs.DEFAULT, cookieSpecProvider)
+                .register(CookieSpecs.STANDARD, cookieSpecProvider)
+                .register(CookieSpecs.STANDARD_STRICT, cookieSpecProvider)
                 .build();
-        // Allow TLSv1 protocol only
-        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
-                sslcontext,
-                new String[] { "TLSv1" },
-                null,
-                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+
         CloseableHttpClient httpclient = HttpClients.custom()
-                .setSSLSocketFactory(sslsf)
+                .setSSLHostnameVerifier(hostnameVerifier)
+                .setDefaultCookieSpecRegistry(cookieSpecRegistry)
                 .build();
         try {
 
-            HttpGet httpget = new HttpGet("https://localhost/");
+            HttpGet httpget = new HttpGet("https://remotehost/");
 
-            System.out.println("executing request" + httpget.getRequestLine());
+            System.out.println("executing request " + httpget.getRequestLine());
 
             CloseableHttpResponse response = httpclient.execute(httpget);
             try {
@@ -82,9 +83,6 @@ public class ClientCustomSSL {
 
                 System.out.println("----------------------------------------");
                 System.out.println(response.getStatusLine());
-                if (entity != null) {
-                    System.out.println("Response content length: " + entity.getContentLength());
-                }
                 EntityUtils.consume(entity);
             } finally {
                 response.close();
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java b/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java
index fd581b0..eb16287 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.java
@@ -27,19 +27,17 @@
 package org.apache.http.examples.client;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.security.KeyStore;
 
 import javax.net.ssl.SSLContext;
 
 import org.apache.http.HttpEntity;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.ssl.SSLContexts;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContexts;
 import org.apache.http.util.EntityUtils;
 
 /**
@@ -49,24 +47,17 @@ import org.apache.http.util.EntityUtils;
 public class ClientCustomSSL {
 
     public final static void main(String[] args) throws Exception {
-        KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
-        FileInputStream instream = new FileInputStream(new File("my.keystore"));
-        try {
-            trustStore.load(instream, "nopassword".toCharArray());
-        } finally {
-            instream.close();
-        }
-
         // Trust own CA and all self-signed certs
         SSLContext sslcontext = SSLContexts.custom()
-                .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
+                .loadTrustMaterial(new File("my.keystore"), "nopassword".toCharArray(),
+                        new TrustSelfSignedStrategy())
                 .build();
         // Allow TLSv1 protocol only
         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                 sslcontext,
                 new String[] { "TLSv1" },
                 null,
-                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
         CloseableHttpClient httpclient = HttpClients.custom()
                 .setSSLSocketFactory(sslsf)
                 .build();
@@ -74,7 +65,7 @@ public class ClientCustomSSL {
 
             HttpGet httpget = new HttpGet("https://localhost/");
 
-            System.out.println("executing request" + httpget.getRequestLine());
+            System.out.println("executing request " + httpget.getRequestLine());
 
             CloseableHttpResponse response = httpclient.execute(httpget);
             try {
@@ -82,9 +73,6 @@ public class ClientCustomSSL {
 
                 System.out.println("----------------------------------------");
                 System.out.println(response.getStatusLine());
-                if (entity != null) {
-                    System.out.println("Response content length: " + entity.getContentLength());
-                }
                 EntityUtils.consume(entity);
             } finally {
                 response.close();
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java b/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java
index 3c734d1..b349709 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientEvictExpiredConnections.java
@@ -30,10 +30,10 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.HttpClientConnectionManager;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.pool.PoolStats;
 import org.apache.http.util.EntityUtils;
 
 /**
@@ -47,6 +47,8 @@ public class ClientEvictExpiredConnections {
         cm.setMaxTotal(100);
         CloseableHttpClient httpclient = HttpClients.custom()
                 .setConnectionManager(cm)
+                .evictExpiredConnections()
+                .evictIdleConnections(5L, TimeUnit.SECONDS)
                 .build();
         try {
             // create an array of URIs to perform GETs on
@@ -56,9 +58,6 @@ public class ClientEvictExpiredConnections {
                 "http://hc.apache.org/httpcomponents-client-ga/",
             };
 
-            IdleConnectionEvictor connEvictor = new IdleConnectionEvictor(cm);
-            connEvictor.start();
-
             for (int i = 0; i < urisToGet.length; i++) {
                 String requestURI = urisToGet[i];
                 HttpGet request = new HttpGet(requestURI);
@@ -75,54 +74,18 @@ public class ClientEvictExpiredConnections {
                 }
             }
 
+            PoolStats stats1 = cm.getTotalStats();
+            System.out.println("Connections kept alive: " + stats1.getAvailable());
+
             // Sleep 10 sec and let the connection evictor do its job
-            Thread.sleep(20000);
+            Thread.sleep(10000);
 
-            // Shut down the evictor thread
-            connEvictor.shutdown();
-            connEvictor.join();
+            PoolStats stats2 = cm.getTotalStats();
+            System.out.println("Connections kept alive: " + stats2.getAvailable());
 
         } finally {
             httpclient.close();
         }
     }
 
-    public static class IdleConnectionEvictor extends Thread {
-
-        private final HttpClientConnectionManager connMgr;
-
-        private volatile boolean shutdown;
-
-        public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {
-            super();
-            this.connMgr = connMgr;
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!shutdown) {
-                    synchronized (this) {
-                        wait(5000);
-                        // Close expired connections
-                        connMgr.closeExpiredConnections();
-                        // Optionally, close connections
-                        // that have been idle longer than 5 sec
-                        connMgr.closeIdleConnections(5, TimeUnit.SECONDS);
-                    }
-                }
-            } catch (InterruptedException ex) {
-                // terminate
-            }
-        }
-
-        public void shutdown() {
-            shutdown = true;
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-
-    }
-
 }
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteSOCKS.java b/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteSOCKS.java
index ef9b644..3cf62d7 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteSOCKS.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteSOCKS.java
@@ -71,7 +71,7 @@ public class ClientExecuteSOCKS {
             HttpGet request = new HttpGet("/");
 
             System.out.println("Executing request " + request + " to " + target + " via SOCKS proxy " + socksaddr);
-            CloseableHttpResponse response = httpclient.execute(target, request);
+            CloseableHttpResponse response = httpclient.execute(target, request, context);
             try {
                 System.out.println("----------------------------------------");
                 System.out.println(response.getStatusLine());
@@ -86,12 +86,14 @@ public class ClientExecuteSOCKS {
 
     static class MyConnectionSocketFactory implements ConnectionSocketFactory {
 
+        @Override
         public Socket createSocket(final HttpContext context) throws IOException {
             InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
             Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
             return new Socket(proxy);
         }
 
+        @Override
         public Socket connectSocket(
                 final int connectTimeout,
                 final Socket socket,
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
index 2eaa66a..b0986cd 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
@@ -44,7 +44,7 @@ import org.apache.http.util.EntityUtils;
 /**
  * An example of HttpClient can be customized to authenticate
  * preemptively using BASIC scheme.
- * <b/>
+ * <b>
  * Generally, preemptive authentication can be considered less
  * secure than a response to an authentication challenge
  * and therefore discouraged.
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java
index 22e56e1..fd2e118 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java
@@ -44,10 +44,11 @@ import org.apache.http.util.EntityUtils;
 /**
  * An example of HttpClient can be customized to authenticate
  * preemptively using DIGEST scheme.
- * <p/>
+ * <p>
  * Generally, preemptive authentication can be considered less
  * secure than a response to an authentication challenge
  * and therefore discouraged.
+ * </p>
  */
 public class ClientPreemptiveDigestAuthentication {
 
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientWithRequestFuture.java b/httpclient/src/examples/org/apache/http/examples/client/ClientWithRequestFuture.java
index fc245c0..e9f9740 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientWithRequestFuture.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientWithRequestFuture.java
@@ -56,6 +56,7 @@ public class ClientWithRequestFuture {
         try {
             // Because things are asynchronous, you must provide a ResponseHandler
             ResponseHandler<Boolean> handler = new ResponseHandler<Boolean>() {
+                @Override
                 public Boolean handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
                     // simply return true if the status was OK
                     return response.getStatusLine().getStatusCode() == 200;
@@ -89,14 +90,17 @@ public class ClientWithRequestFuture {
             System.out.println("It was ok? "  + wasItOk3);
 
             FutureCallback<Boolean> callback = new FutureCallback<Boolean>() {
+                @Override
                 public void completed(Boolean result) {
                     System.out.println("completed with " + result);
                 }
 
+                @Override
                 public void failed(Exception ex) {
                     System.out.println("failed with " + ex.getMessage());
                 }
 
+                @Override
                 public void cancelled() {
                     System.out.println("cancelled");
                 }
diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java b/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java
index 4d8bc62..401fdc9 100644
--- a/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java
+++ b/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java
@@ -54,6 +54,7 @@ public class ClientWithResponseHandler {
             // Create a custom response handler
             ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
 
+                @Override
                 public String handleResponse(
                         final HttpResponse response) throws ClientProtocolException, IOException {
                     int status = response.getStatusLine().getStatusCode();
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/client/AuthenticationHandler.java b/httpclient/src/main/java-deprecated/org/apache/http/client/AuthenticationHandler.java
index 60065bd..5a64fc3 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/client/AuthenticationHandler.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/AuthenticationHandler.java
@@ -59,8 +59,8 @@ public interface AuthenticationHandler {
      * of authentication failure
      * @param response HTTP response.
      * @param context HTTP context.
-     * @return <code>true</code> if user authentication is required,
-     *   <code>false</code> otherwise.
+     * @return {@code true} if user authentication is required,
+     *   {@code false} otherwise.
      */
     boolean isAuthenticationRequested(
             HttpResponse response,
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/client/RedirectHandler.java b/httpclient/src/main/java-deprecated/org/apache/http/client/RedirectHandler.java
index 7bd4bd4..01e9d75 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/client/RedirectHandler.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/RedirectHandler.java
@@ -56,7 +56,7 @@ public interface RedirectHandler {
      * @param response the response received from the target server
      * @param context the context for the request execution
      *
-     * @return <code>true</code> if the request should be redirected, <code>false</code>
+     * @return {@code true} if the request should be redirected, {@code false}
      * otherwise
      */
     boolean isRedirectRequested(HttpResponse response, HttpContext context);
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/client/RequestDirector.java b/httpclient/src/main/java-deprecated/org/apache/http/client/RequestDirector.java
index 195c1e6..a0da0ca 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/client/RequestDirector.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/RequestDirector.java
@@ -52,13 +52,14 @@ public interface RequestDirector {
 
     /**
      * Executes a request.
-     * <br/><b>Note:</b>
-     * For the time being, a new director is instantiated for each request.
-     * This is the same behavior as for <code>HttpMethodDirector</code>
+     * <p>
+     * <b>Note:</b> For the time being, a new director is instantiated for each request.
+     * This is the same behavior as for {@code HttpMethodDirector}
      * in HttpClient 3.
+     * </p>
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/client/params/AuthPolicy.java b/httpclient/src/main/java-deprecated/org/apache/http/client/params/AuthPolicy.java
index c04a6c1..768ddf9 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/client/params/AuthPolicy.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/params/AuthPolicy.java
@@ -67,7 +67,7 @@ public final class AuthPolicy {
      *
      * @since 4.1
      */
-    public static final String SPNEGO = "negotiate";
+    public static final String SPNEGO = "Negotiate";
 
     /**
      * Kerberos Authentication scheme.
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/RequestAuthenticationBase.java b/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/RequestAuthenticationBase.java
index 0a90fba..bec0069 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/RequestAuthenticationBase.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/RequestAuthenticationBase.java
@@ -58,7 +58,7 @@ abstract class RequestAuthenticationBase implements HttpRequestInterceptor {
             final HttpContext context) {
         AuthScheme authScheme = authState.getAuthScheme();
         Credentials creds = authState.getCredentials();
-        switch (authState.getState()) {
+        switch (authState.getState()) { // TODO add UNCHALLENGED and HANDSHAKE cases
         case FAILURE:
             return;
         case SUCCESS:
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/ResponseAuthCache.java b/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/ResponseAuthCache.java
index 71b1a60..a08f182 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/ResponseAuthCache.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/protocol/ResponseAuthCache.java
@@ -91,7 +91,7 @@ public class ResponseAuthCache implements HttpResponseInterceptor {
                     authCache = new BasicAuthCache();
                     context.setAttribute(ClientContext.AUTH_CACHE, authCache);
                 }
-                switch (targetState.getState()) {
+                switch (targetState.getState()) {  // TODO add SUCCESS, UNCHALLENGED and HANDSHAKE cases
                 case CHALLENGED:
                     cache(authCache, target, targetState.getAuthScheme());
                     break;
@@ -112,7 +112,7 @@ public class ResponseAuthCache implements HttpResponseInterceptor {
                     authCache = new BasicAuthCache();
                     context.setAttribute(ClientContext.AUTH_CACHE, authCache);
                 }
-                switch (proxyState.getState()) {
+                switch (proxyState.getState()) {  // TODO add SUCCESS, UNCHALLENGED and HANDSHAKE cases
                 case CHALLENGED:
                     cache(authCache, proxy, proxyState.getAuthScheme());
                     break;
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/Idn.java b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/Idn.java
similarity index 95%
rename from httpclient/src/main/java/org/apache/http/client/utils/Idn.java
rename to httpclient/src/main/java-deprecated/org/apache/http/client/utils/Idn.java
index 41c0e2b..072c7e8 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/Idn.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/Idn.java
@@ -29,8 +29,11 @@ package org.apache.http.client.utils;
 /**
  * Abstraction of international domain name (IDN) conversion.
  *
+ * @deprecated (4.4) use standard {@link java.net.IDN}.
+ *
  * @since 4.0
  */
+ at Deprecated
 public interface Idn {
     /**
      * Converts a name from its punycode representation to Unicode.
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/JdkIdn.java b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/JdkIdn.java
similarity index 96%
rename from httpclient/src/main/java/org/apache/http/client/utils/JdkIdn.java
rename to httpclient/src/main/java-deprecated/org/apache/http/client/utils/JdkIdn.java
index 2f0b086..99898b8 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/JdkIdn.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/JdkIdn.java
@@ -34,9 +34,12 @@ import org.apache.http.annotation.Immutable;
 /**
  * Uses the java.net.IDN class through reflection.
  *
+ * @deprecated (4.4) use standard {@link java.net.IDN}.
+ *
  * @since 4.0
  */
 @Immutable
+ at Deprecated
 public class JdkIdn implements Idn {
     private final Method toUnicode;
 
@@ -57,6 +60,7 @@ public class JdkIdn implements Idn {
         }
     }
 
+    @Override
     public String toUnicode(final String punycode) {
         try {
             return (String) toUnicode.invoke(null, punycode);
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/Punycode.java b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/Punycode.java
similarity index 96%
rename from httpclient/src/main/java/org/apache/http/client/utils/Punycode.java
rename to httpclient/src/main/java-deprecated/org/apache/http/client/utils/Punycode.java
index 750f503..2d17f34 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/Punycode.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/Punycode.java
@@ -32,9 +32,12 @@ import org.apache.http.annotation.Immutable;
  * Facade that provides conversion between Unicode and Punycode domain names.
  * It will use an appropriate implementation.
  *
+ * @deprecated (4.4) use standard {@link java.net.IDN}.
+ *
  * @since 4.0
  */
 @Immutable
+ at Deprecated
 public class Punycode {
     private static final Idn impl;
     static {
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/Rfc3492Idn.java b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/Rfc3492Idn.java
similarity index 96%
rename from httpclient/src/main/java/org/apache/http/client/utils/Rfc3492Idn.java
rename to httpclient/src/main/java-deprecated/org/apache/http/client/utils/Rfc3492Idn.java
index 293d9b0..29dabc4 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/Rfc3492Idn.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/client/utils/Rfc3492Idn.java
@@ -33,9 +33,12 @@ import org.apache.http.annotation.Immutable;
 /**
  * Implementation from pseudo code in RFC 3492.
  *
+ * @deprecated (4.4) use standard {@link java.net.IDN}.
+ *
  * @since 4.0
  */
 @Immutable
+ at Deprecated
 public class Rfc3492Idn implements Idn {
     private static final int base = 36;
     private static final int tmin = 1;
@@ -76,6 +79,7 @@ public class Rfc3492Idn implements Idn {
         throw new IllegalArgumentException("illegal digit: "+ c);
     }
 
+    @Override
     public String toUnicode(final String punycode) {
         final StringBuilder unicode = new StringBuilder(punycode.length());
         final StringTokenizer tok = new StringTokenizer(punycode, ".");
@@ -104,11 +108,11 @@ public class Rfc3492Idn implements Idn {
             input = input.substring(lastdelim + 1);
         }
 
-        while (input.length() > 0) {
+        while (!input.isEmpty()) {
             final int oldi = i;
             int w = 1;
             for (int k = base;; k += base) {
-                if (input.length() == 0) {
+                if (input.isEmpty()) {
                     break;
                 }
                 final char c = input.charAt(0);
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/conn/ClientConnectionOperator.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/ClientConnectionOperator.java
index 03d859d..adc46af 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/conn/ClientConnectionOperator.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/ClientConnectionOperator.java
@@ -69,7 +69,7 @@ public interface ClientConnectionOperator {
      * @param conn      the connection to open
      * @param target    the target host to connect to
      * @param local     the local address to route from, or
-     *                  <code>null</code> for the default
+     *                  {@code null} for the default
      * @param context   the context for the connection
      * @param params    the parameters for the connection
      *
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/conn/MultihomePlainSocketFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/MultihomePlainSocketFactory.java
index 2f1c10f..01e465d 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/conn/MultihomePlainSocketFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/MultihomePlainSocketFactory.java
@@ -155,7 +155,7 @@ public final class MultihomePlainSocketFactory implements SocketFactory {
      *
      * @param sock      the connected socket
      *
-     * @return  <code>false</code>
+     * @return  {@code false}
      *
      * @throws IllegalArgumentException if the argument is invalid
      */
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/conn/OperatedClientConnection.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/OperatedClientConnection.java
index 0fa35e3..21755ea 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/conn/OperatedClientConnection.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/OperatedClientConnection.java
@@ -52,10 +52,11 @@ public interface OperatedClientConnection extends HttpClientConnection, HttpInet
      * If the connection is to a proxy but not tunnelled, this is
      * the proxy. If the connection is tunnelled through a proxy,
      * this is the target of the tunnel.
-     * <br/>
+     * <p>
      * The return value is well-defined only while the connection is open.
      * It may change even while the connection is open,
      * because of an {@link #update update}.
+     * </p>
      *
      * @return  the host to which this connection is opened
      */
@@ -67,8 +68,8 @@ public interface OperatedClientConnection extends HttpClientConnection, HttpInet
      * It may change even while the connection is open,
      * because of an {@link #update update}.
      *
-     * @return  <code>true</code> if this connection is secure,
-     *          <code>false</code> otherwise
+     * @return  {@code true} if this connection is secure,
+     *          {@code false} otherwise
      */
     boolean isSecure();
 
@@ -117,9 +118,9 @@ public interface OperatedClientConnection extends HttpClientConnection, HttpInet
      * An attempt to call this method on an open connection will cause
      * an exception.
      *
-     * @param secure    <code>true</code> if this connection is secure, for
-     *                  example if an <code>SSLSocket</code> is used, or
-     *                  <code>false</code> if it is not secure
+     * @param secure    {@code true} if this connection is secure, for
+     *                  example if an {@code SSLSocket} is used, or
+     *                  {@code false} if it is not secure
      * @param params    parameters for this connection. The parameters will
      *                  be used when creating dependent objects, for example
      *                  to determine buffer sizes.
@@ -133,19 +134,20 @@ public interface OperatedClientConnection extends HttpClientConnection, HttpInet
      * Updates are used for example when a tunnel has been established,
      * or when a TLS/SSL connection has been layered on top of a plain
      * socket connection.
-     * <br/>
+     * <p>
      * <b>Note:</b> Updating the connection will <i>not</i> close the
      * previously used socket. It is the caller's responsibility to close
      * that socket if it is no longer required.
+     * </p>
      *
      * @param sock      the new socket for communicating with the target host,
-     *                  or <code>null</code> to continue using the old socket.
-     *                  If <code>null</code> is passed, helper objects that
+     *                  or {@code null} to continue using the old socket.
+     *                  If {@code null} is passed, helper objects that
      *                  depend on the socket should be re-used. In that case,
      *                  some changes in the parameters will not take effect.
      * @param target    the new target host of this connection
-     * @param secure    <code>true</code> if this connection is now secure,
-     *                  <code>false</code> if it is not secure
+     * @param secure    {@code true} if this connection is now secure,
+     *                  {@code false} if it is not secure
      * @param params    new parameters for this connection
      */
     void update(Socket sock, HttpHost target,
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnPerRouteBean.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnPerRouteBean.java
index 6645ad7..6700c5b 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnPerRouteBean.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnPerRouteBean.java
@@ -76,7 +76,7 @@ public final class ConnPerRouteBean implements ConnPerRoute {
     }
 
     public void setDefaultMaxPerRoute(final int max) {
-        Args.positive(max, "Defautl max per route");
+        Args.positive(max, "Default max per route");
         this.defaultMax = max;
     }
 
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnRouteParams.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnRouteParams.java
index bf75bce..c4a9bc1 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnRouteParams.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/params/ConnRouteParams.java
@@ -68,13 +68,13 @@ public class ConnRouteParams implements ConnRoutePNames {
     /**
      * Obtains the {@link ConnRoutePNames#DEFAULT_PROXY DEFAULT_PROXY}
      * parameter value.
-     * {@link #NO_HOST} will be mapped to <code>null</code>,
+     * {@link #NO_HOST} will be mapped to {@code null},
      * to allow unsetting in a hierarchy.
      *
      * @param params    the parameters in which to look up
      *
      * @return  the default proxy set in the argument parameters, or
-     *          <code>null</code> if not set
+     *          {@code null} if not set
      */
     public static HttpHost getDefaultProxy(final HttpParams params) {
         Args.notNull(params, "Parameters");
@@ -92,9 +92,9 @@ public class ConnRouteParams implements ConnRoutePNames {
      * parameter value.
      *
      * @param params    the parameters in which to set the value
-     * @param proxy     the value to set, may be <code>null</code>.
+     * @param proxy     the value to set, may be {@code null}.
      *                  Note that {@link #NO_HOST} will be mapped to
-     *                  <code>null</code> by {@link #getDefaultProxy},
+     *                  {@code null} by {@link #getDefaultProxy},
      *                  to allow for explicit unsetting in hierarchies.
      */
     public static void setDefaultProxy(final HttpParams params,
@@ -106,13 +106,13 @@ public class ConnRouteParams implements ConnRoutePNames {
     /**
      * Obtains the {@link ConnRoutePNames#FORCED_ROUTE FORCED_ROUTE}
      * parameter value.
-     * {@link #NO_ROUTE} will be mapped to <code>null</code>,
+     * {@link #NO_ROUTE} will be mapped to {@code null},
      * to allow unsetting in a hierarchy.
      *
      * @param params    the parameters in which to look up
      *
      * @return  the forced route set in the argument parameters, or
-     *          <code>null</code> if not set
+     *          {@code null} if not set
      */
     public static HttpRoute getForcedRoute(final HttpParams params) {
         Args.notNull(params, "Parameters");
@@ -130,9 +130,9 @@ public class ConnRouteParams implements ConnRoutePNames {
      * parameter value.
      *
      * @param params    the parameters in which to set the value
-     * @param route     the value to set, may be <code>null</code>.
+     * @param route     the value to set, may be {@code null}.
      *                  Note that {@link #NO_ROUTE} will be mapped to
-     *                  <code>null</code> by {@link #getForcedRoute},
+     *                  {@code null} by {@link #getForcedRoute},
      *                  to allow for explicit unsetting in hierarchies.
      */
     public static void setForcedRoute(final HttpParams params,
@@ -145,13 +145,13 @@ public class ConnRouteParams implements ConnRoutePNames {
      * Obtains the {@link ConnRoutePNames#LOCAL_ADDRESS LOCAL_ADDRESS}
      * parameter value.
      * There is no special value that would automatically be mapped to
-     * <code>null</code>. You can use the wildcard address (0.0.0.0 for IPv4,
+     * {@code null}. You can use the wildcard address (0.0.0.0 for IPv4,
      * :: for IPv6) to override a specific local address in a hierarchy.
      *
      * @param params    the parameters in which to look up
      *
      * @return  the local address set in the argument parameters, or
-     *          <code>null</code> if not set
+     *          {@code null} if not set
      */
     public static InetAddress getLocalAddress(final HttpParams params) {
         Args.notNull(params, "Parameters");
@@ -166,7 +166,7 @@ public class ConnRouteParams implements ConnRoutePNames {
      * parameter value.
      *
      * @param params    the parameters in which to set the value
-     * @param local     the value to set, may be <code>null</code>
+     * @param local     the value to set, may be {@code null}
      */
     public static void setLocalAddress(final HttpParams params,
                                              final InetAddress local) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/conn/scheme/PlainSocketFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/scheme/PlainSocketFactory.java
index 2d0d44a..7a59cea 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/conn/scheme/PlainSocketFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/scheme/PlainSocketFactory.java
@@ -128,7 +128,7 @@ public class PlainSocketFactory implements SocketFactory, SchemeSocketFactory {
      *
      * @param sock      the connected socket
      *
-     * @return  <code>false</code>
+     * @return  {@code false}
      */
     public final boolean isSecure(final Socket sock) {
         return false;
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/PrivateKeyDetails.java
similarity index 95%
rename from httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java
rename to httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/PrivateKeyDetails.java
index 1abb449..ff94d4d 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/PrivateKeyDetails.java
@@ -35,7 +35,10 @@ import java.util.Arrays;
  * Private key details.
  *
  * @since 4.3
+ *
+ * @deprecated (4.4) use {@link org.apache.http.ssl.PrivateKeyDetails}.
  */
+ at Deprecated
 public final class PrivateKeyDetails {
 
     private final String type;
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/PrivateKeyStrategy.java
similarity index 94%
rename from httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
rename to httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/PrivateKeyStrategy.java
index 4238e28..119869b 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/PrivateKeyStrategy.java
@@ -33,7 +33,10 @@ import java.util.Map;
  * A strategy allowing for a choice of an alias during SSL authentication.
  *
  * @since 4.3
+ *
+ * @deprecated (4.4) use {@link org.apache.http.ssl.PrivateKeyStrategy}.
  */
+ at Deprecated
 public interface PrivateKeyStrategy {
 
     /**
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLContextBuilder.java
similarity index 95%
rename from httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java
rename to httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLContextBuilder.java
index 5d81fda..44aa397 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLContextBuilder.java
@@ -39,7 +39,7 @@ import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 
@@ -57,8 +57,11 @@ import org.apache.http.annotation.NotThreadSafe;
  * Builder for {@link SSLContext} instances.
  *
  * @since 4.3
+ *
+ * @deprecated (4.4) use {@link org.apache.http.ssl.SSLContextBuilder}.
  */
 @NotThreadSafe
+ at Deprecated
 public class SSLContextBuilder {
 
     static final String TLS   = "TLS";
@@ -71,8 +74,8 @@ public class SSLContextBuilder {
 
     public SSLContextBuilder() {
         super();
-        this.keymanagers = new HashSet<KeyManager>();
-        this.trustmanagers = new HashSet<TrustManager>();
+        this.keymanagers = new LinkedHashSet<KeyManager>();
+        this.trustmanagers = new LinkedHashSet<TrustManager>();
     }
 
     public SSLContextBuilder useTLS() {
@@ -179,11 +182,13 @@ public class SSLContextBuilder {
             this.trustStrategy = trustStrategy;
         }
 
+        @Override
         public void checkClientTrusted(
                 final X509Certificate[] chain, final String authType) throws CertificateException {
             this.trustManager.checkClientTrusted(chain, authType);
         }
 
+        @Override
         public void checkServerTrusted(
                 final X509Certificate[] chain, final String authType) throws CertificateException {
             if (!this.trustStrategy.isTrusted(chain, authType)) {
@@ -191,6 +196,7 @@ public class SSLContextBuilder {
             }
         }
 
+        @Override
         public X509Certificate[] getAcceptedIssuers() {
             return this.trustManager.getAcceptedIssuers();
         }
@@ -208,11 +214,13 @@ public class SSLContextBuilder {
             this.aliasStrategy = aliasStrategy;
         }
 
+        @Override
         public String[] getClientAliases(
                 final String keyType, final Principal[] issuers) {
             return this.keyManager.getClientAliases(keyType, issuers);
         }
 
+        @Override
         public String chooseClientAlias(
                 final String[] keyTypes, final Principal[] issuers, final Socket socket) {
             final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
@@ -228,11 +236,13 @@ public class SSLContextBuilder {
             return this.aliasStrategy.chooseAlias(validAliases, socket);
         }
 
+        @Override
         public String[] getServerAliases(
                 final String keyType, final Principal[] issuers) {
             return this.keyManager.getServerAliases(keyType, issuers);
         }
 
+        @Override
         public String chooseServerAlias(
                 final String keyType, final Principal[] issuers, final Socket socket) {
             final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
@@ -246,10 +256,12 @@ public class SSLContextBuilder {
             return this.aliasStrategy.chooseAlias(validAliases, socket);
         }
 
+        @Override
         public X509Certificate[] getCertificateChain(final String alias) {
             return this.keyManager.getCertificateChain(alias);
         }
 
+        @Override
         public PrivateKey getPrivateKey(final String alias) {
             return this.keyManager.getPrivateKey(alias);
         }
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContexts.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLContexts.java
similarity index 87%
rename from httpclient/src/main/java/org/apache/http/conn/ssl/SSLContexts.java
rename to httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLContexts.java
index 87a17a7..26ab3e5 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContexts.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLContexts.java
@@ -38,13 +38,16 @@ import org.apache.http.annotation.Immutable;
  * {@link SSLContext} factory methods.
  *
  * @since 4.3
+ *
+ * @deprecated (4.4) use {@link org.apache.http.ssl.SSLContexts}.
  */
 @Immutable
+ at Deprecated
 public class SSLContexts {
 
     /**
      * Creates default factory based on the standard JSSE trust material
-     * (<code>cacerts</code> file in the security properties directory). System properties
+     * ({@code cacerts} file in the security properties directory). System properties
      * are not taken into consideration.
      *
      * @return the default SSL socket factory
@@ -63,16 +66,16 @@ public class SSLContexts {
 
     /**
      * Creates default SSL context based on system properties. This method obtains
-     * default SSL context by calling <code>SSLContext.getInstance("Default")</code>.
-     * Please note that <code>Default</code> algorithm is supported as of Java 6.
+     * default SSL context by calling {@code SSLContext.getInstance("Default")}.
+     * Please note that {@code Default} algorithm is supported as of Java 6.
      * This method will fall back onto {@link #createDefault()} when
-     * <code>Default</code> algorithm is not available.
+     * {@code Default} algorithm is not available.
      *
      * @return default system SSL context
      */
     public static SSLContext createSystemDefault() throws SSLInitializationException {
         try {
-            return SSLContext.getInstance("Default");
+            return SSLContext.getDefault();
         } catch (final NoSuchAlgorithmException ex) {
             return createDefault();
         }
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLSocketFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLSocketFactory.java
index 44d63e7..3c90577 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLSocketFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/conn/ssl/SSLSocketFactory.java
@@ -63,20 +63,23 @@ import org.apache.http.util.TextUtils;
  * <p>
  * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of
  * trusted certificates and to authenticate to the HTTPS server using a private key.
+ * </p>
  * <p>
  * SSLSocketFactory will enable server authentication when supplied with
  * a {@link KeyStore trust-store} file containing one or several trusted certificates. The client
  * secure socket will reject the connection during the SSL session handshake if the target HTTPS
  * server attempts to authenticate itself with a non-trusted certificate.
+ * </p>
  * <p>
  * Use JDK keytool utility to import a trusted certificate and generate a trust-store file:
- *    <pre>
- *     keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
- *    </pre>
+ * </p>
+ * <pre>keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
+ * </pre>
  * <p>
  * In special cases the standard trust verification process can be bypassed by using a custom
  * {@link TrustStrategy}. This interface is primarily intended for allowing self-signed
  * certificates to be accepted as trusted without having to add them to the trust-store file.
+ * </p>
  * <p>
  * SSLSocketFactory will enable client authentication when supplied with
  * a {@link KeyStore key-store} file containing a private key/public certificate
@@ -85,6 +88,7 @@ import org.apache.http.util.TextUtils;
  * requested to do so by the server.
  * The target HTTPS server will in its turn verify the certificate presented
  * by the client in order to establish client's authenticity.
+ * </p>
  * <p>
  * Use the following sequence of actions to generate a key-store file
  * </p>
@@ -92,15 +96,17 @@ import org.apache.http.util.TextUtils;
  *     <li>
  *      <p>
  *      Use JDK keytool utility to generate a new key
+ *      </p>
  *      <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ *      <p>
  *      For simplicity use the same password for the key as that of the key-store
  *      </p>
  *     </li>
  *     <li>
  *      <p>
  *      Issue a certificate signing request (CSR)
- *      <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
  *     </p>
+ *     <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
  *     </li>
  *     <li>
  *      <p>
@@ -112,20 +118,20 @@ import org.apache.http.util.TextUtils;
  *     <li>
  *      <p>
  *       Import the trusted CA root certificate
- *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
  *      </p>
+ *      <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
  *     </li>
  *     <li>
  *      <p>
  *       Import the PKCS#7 file containg the complete certificate chain
- *       <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
  *      </p>
+ *      <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
  *     </li>
  *     <li>
  *      <p>
  *       Verify the content the resultant keystore file
- *       <pre>keytool -list -v -keystore my.keystore</pre>
  *      </p>
+ *      <pre>keytool -list -v -keystore my.keystore</pre>
  *     </li>
  *   </ul>
  *
@@ -153,7 +159,7 @@ public class SSLSocketFactory implements LayeredConnectionSocketFactory, SchemeL
 
     /**
      * Obtains default SSL socket factory with an SSL context based on the standard JSSE
-     * trust material (<code>cacerts</code> file in the security properties directory).
+     * trust material ({@code cacerts} file in the security properties directory).
      * System properties are not taken into consideration.
      *
      * @return default SSL socket factory
@@ -407,13 +413,14 @@ public class SSLSocketFactory implements LayeredConnectionSocketFactory, SchemeL
      * Checks whether a socket connection is secure.
      * This factory creates TLS/SSL socket connections
      * which, by default, are considered secure.
-     * <br/>
+     * <p>
      * Derived classes may override this method to perform
      * runtime checks, for example based on the cypher suite.
+     * </p>
      *
      * @param sock      the connected socket
      *
-     * @return  <code>true</code>
+     * @return  {@code true}
      *
      * @throws IllegalArgumentException if the argument is invalid
      */
@@ -485,6 +492,7 @@ public class SSLSocketFactory implements LayeredConnectionSocketFactory, SchemeL
      *
      * The default implementation is a no-op, but could be overridden to, e.g.,
      * call {@link SSLSocket#setEnabledCipherSuites(java.lang.String[])}.
+     * @throws IOException (only if overridden)
      *
      * @since 4.2
      */
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/auth/NegotiateScheme.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/auth/NegotiateScheme.java
index 6711c8a..d39a019 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/auth/NegotiateScheme.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/auth/NegotiateScheme.java
@@ -77,7 +77,7 @@ public class NegotiateScheme extends GGSSchemeBase {
     /**
      * Returns textual designation of the Negotiate authentication scheme.
      *
-     * @return <code>Negotiate</code>
+     * @return {@code Negotiate}
      */
     public String getSchemeName() {
         return "Negotiate";
@@ -113,6 +113,11 @@ public class NegotiateScheme extends GGSSchemeBase {
 
     @Override
     protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
+        return super.generateToken(input, authServer);
+    }
+
+    @Override
+    protected byte[] generateToken(final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
         /* Using the SPNEGO OID is the correct method.
          * Kerberos v5 works for IIS but not JBoss. Unwrapping
          * the initial token when using SPNEGO OID looks like what is
@@ -133,7 +138,7 @@ public class NegotiateScheme extends GGSSchemeBase {
         byte[] token = input;
         boolean tryKerberos = false;
         try {
-            token = generateGSSToken(token, negotiationOid, authServer);
+            token = generateGSSToken(token, negotiationOid, authServer, credentials);
         } catch (final GSSException ex){
             // BAD MECH means we are likely to be using 1.5, fall back to Kerberos MECH.
             // Rethrow any other exception.
@@ -149,7 +154,7 @@ public class NegotiateScheme extends GGSSchemeBase {
             /* Kerberos v5 GSS-API mechanism defined in RFC 1964.*/
             log.debug("Using Kerberos MECH " + KERBEROS_OID);
             negotiationOid  = new Oid(KERBEROS_OID);
-            token = generateGSSToken(token, negotiationOid, authServer);
+            token = generateGSSToken(token, negotiationOid, authServer, credentials);
 
             /*
              * IIS accepts Kerberos and SPNEGO tokens. Some other servers Jboss, Glassfish?
@@ -170,7 +175,7 @@ public class NegotiateScheme extends GGSSchemeBase {
      * Returns the authentication parameter with the given name, if available.
      *
      * <p>There are no valid parameters for Negotiate authentication so this
-     * method always returns <tt>null</tt>.</p>
+     * method always returns {@code null}.</p>
      *
      * @param name The name of the parameter to be returned
      *
@@ -183,19 +188,19 @@ public class NegotiateScheme extends GGSSchemeBase {
 
     /**
      * The concept of an authentication realm is not supported by the Negotiate
-     * authentication scheme. Always returns <code>null</code>.
+     * authentication scheme. Always returns {@code null}.
      *
-     * @return <code>null</code>
+     * @return {@code null}
      */
     public String getRealm() {
         return null;
     }
 
     /**
-     * Returns <tt>true</tt>.
+     * Returns {@code true}.
      * Negotiate authentication scheme is connection based.
      *
-     * @return <tt>true</tt>.
+     * @return {@code true}.
      */
     public boolean isConnectionBased() {
         return true;
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractAuthenticationHandler.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractAuthenticationHandler.java
index 3b73322..9f211a4 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractAuthenticationHandler.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractAuthenticationHandler.java
@@ -106,7 +106,7 @@ public abstract class AbstractAuthenticationHandler implements AuthenticationHan
             }
             final int endIndex = pos;
             final String s = buffer.substring(beginIndex, endIndex);
-            map.put(s.toLowerCase(Locale.ENGLISH), header);
+            map.put(s.toLowerCase(Locale.ROOT), header);
         }
         return map;
     }
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractHttpClient.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractHttpClient.java
index 40dc0d3..a1f7345 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractHttpClient.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AbstractHttpClient.java
@@ -53,6 +53,7 @@ import org.apache.http.client.RedirectHandler;
 import org.apache.http.client.RedirectStrategy;
 import org.apache.http.client.RequestDirector;
 import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.config.CookieSpecs;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.params.AuthPolicy;
@@ -102,62 +103,77 @@ import org.apache.http.util.Args;
  * of those aspects with custom, application specific ones. This class
  * also provides factory methods to instantiate those objects:
  * <ul>
- *   <li>{@link HttpRequestExecutor}</li> object used to transmit messages
+ *   <li>{@link HttpRequestExecutor} object used to transmit messages
  *    over HTTP connections. The {@link #createRequestExecutor()} must be
  *    implemented by concrete super classes to instantiate this object.
- *   <li>{@link BasicHttpProcessor}</li> object to manage a list of protocol
+ *    </li>
+ *   <li>{@link BasicHttpProcessor} object to manage a list of protocol
  *    interceptors and apply cross-cutting protocol logic to all incoming
  *    and outgoing HTTP messages. The {@link #createHttpProcessor()} must be
  *    implemented by concrete super classes to instantiate this object.
- *   <li>{@link HttpRequestRetryHandler}</li> object used to decide whether
+ *    </li>
+ *   <li>{@link HttpRequestRetryHandler} object used to decide whether
  *    or not a failed HTTP request is safe to retry automatically.
  *    The {@link #createHttpRequestRetryHandler()} must be
  *    implemented by concrete super classes to instantiate this object.
- *   <li>{@link ClientConnectionManager}</li> object used to manage
+ *    </li>
+ *   <li>{@link ClientConnectionManager} object used to manage
  *    persistent HTTP connections.
- *   <li>{@link ConnectionReuseStrategy}</li> object used to decide whether
+ *    </li>
+ *   <li>{@link ConnectionReuseStrategy} object used to decide whether
  *    or not a HTTP connection can be kept alive and re-used for subsequent
  *    HTTP requests. The {@link #createConnectionReuseStrategy()} must be
  *    implemented by concrete super classes to instantiate this object.
- *   <li>{@link ConnectionKeepAliveStrategy}</li> object used to decide how
+ *    </li>
+ *   <li>{@link ConnectionKeepAliveStrategy} object used to decide how
  *    long a persistent HTTP connection can be kept alive.
  *    The {@link #createConnectionKeepAliveStrategy()} must be
  *    implemented by concrete super classes to instantiate this object.
- *   <li>{@link CookieSpecRegistry}</li> object used to maintain a list of
+ *    </li>
+ *   <li>{@link CookieSpecRegistry} object used to maintain a list of
  *    supported cookie specifications.
  *    The {@link #createCookieSpecRegistry()} must be implemented by concrete
  *    super classes to instantiate this object.
- *   <li>{@link CookieStore}</li> object used to maintain a collection of
+ *    </li>
+ *   <li>{@link CookieStore} object used to maintain a collection of
  *    cookies. The {@link #createCookieStore()} must be implemented by
  *    concrete super classes to instantiate this object.
- *   <li>{@link AuthSchemeRegistry}</li> object used to maintain a list of
+ *    </li>
+ *   <li>{@link AuthSchemeRegistry} object used to maintain a list of
  *    supported authentication schemes.
  *    The {@link #createAuthSchemeRegistry()} must be implemented by concrete
  *    super classes to instantiate this object.
- *   <li>{@link CredentialsProvider}</li> object used to maintain
+ *    </li>
+ *   <li>{@link CredentialsProvider} object used to maintain
  *    a collection user credentials. The {@link #createCredentialsProvider()}
  *    must be implemented by concrete super classes to instantiate
  *    this object.
- *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
+ *    </li>
+ *   <li>{@link AuthenticationStrategy} object used to authenticate
  *    against the target host.
  *    The {@link #createTargetAuthenticationStrategy()} must be implemented
  *    by concrete super classes to instantiate this object.
- *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
+ *    </li>
+ *   <li>{@link AuthenticationStrategy} object used to authenticate
  *    against the proxy host.
  *    The {@link #createProxyAuthenticationStrategy()} must be implemented
  *    by concrete super classes to instantiate this object.
- *   <li>{@link HttpRoutePlanner}</li> object used to calculate a route
+ *    </li>
+ *   <li>{@link HttpRoutePlanner} object used to calculate a route
  *    for establishing a connection to the target host. The route
  *    may involve multiple intermediate hops.
  *    The {@link #createHttpRoutePlanner()} must be implemented
  *    by concrete super classes to instantiate this object.
- *   <li>{@link RedirectStrategy}</li> object used to determine if an HTTP
+ *    </li>
+ *   <li>{@link RedirectStrategy} object used to determine if an HTTP
  *    request should be redirected to a new location in response to an HTTP
  *    response received from the target server.
- *   <li>{@link UserTokenHandler}</li> object used to determine if the
+ *    </li>
+ *   <li>{@link UserTokenHandler} object used to determine if the
  *    execution context is user identity specific.
  *    The {@link #createUserTokenHandler()} must be implemented by
  *    concrete super classes to instantiate this object.
+ *    </li>
  * </ul>
  * <p>
  *   This class also maintains a list of protocol interceptors intended
@@ -357,6 +373,9 @@ public abstract class AbstractHttpClient extends CloseableHttpClient {
     protected CookieSpecRegistry createCookieSpecRegistry() {
         final CookieSpecRegistry registry = new CookieSpecRegistry();
         registry.register(
+                CookieSpecs.DEFAULT,
+                new BestMatchSpecFactory());
+        registry.register(
                 CookiePolicy.BEST_MATCH,
                 new BestMatchSpecFactory());
         registry.register(
@@ -971,11 +990,12 @@ public abstract class AbstractHttpClient extends CloseableHttpClient {
      * The default implementation in this class creates a new
      * {@link ClientParamsStack} from the request parameters
      * and the client parameters.
-     * <br/>
+     * <p>
      * This method is called by the default implementation of
      * {@link #execute(HttpHost,HttpRequest,HttpContext)}
      * to obtain the parameters for the
      * {@link DefaultRequestDirector}.
+     * </p>
      *
      * @param req    the request that will be executed
      *
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AuthenticationStrategyAdaptor.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AuthenticationStrategyAdaptor.java
index 2b67d5f..3f5106f 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AuthenticationStrategyAdaptor.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/AuthenticationStrategyAdaptor.java
@@ -111,7 +111,7 @@ class AuthenticationStrategyAdaptor implements AuthenticationStrategy {
             return options;
         }
         final String id = authScheme.getSchemeName();
-        final Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
+        final Header challenge = challenges.get(id.toLowerCase(Locale.ROOT));
         authScheme.processChallenge(challenge);
 
         final AuthScope authScope = new AuthScope(
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/ClientParamsStack.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/ClientParamsStack.java
index 883c1d3..a7da9b8 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/ClientParamsStack.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/ClientParamsStack.java
@@ -60,7 +60,7 @@ import org.apache.http.util.Args;
  *     on a per-request basis.
  *     </li>
  * </ol>
- * Each stack entry may be <code>null</code>. That is preferable over
+ * Each stack entry may be {@code null}. That is preferable over
  * an empty params collection, since it avoids searching the empty collection
  * when looking up parameters.
  *
@@ -73,16 +73,16 @@ import org.apache.http.util.Args;
 @Deprecated
 public class ClientParamsStack extends AbstractHttpParams {
 
-    /** The application parameter collection, or <code>null</code>. */
+    /** The application parameter collection, or {@code null}. */
     protected final HttpParams applicationParams;
 
-    /** The client parameter collection, or <code>null</code>. */
+    /** The client parameter collection, or {@code null}. */
     protected final HttpParams clientParams;
 
-    /** The request parameter collection, or <code>null</code>. */
+    /** The request parameter collection, or {@code null}. */
     protected final HttpParams requestParams;
 
-    /** The override parameter collection, or <code>null</code>. */
+    /** The override parameter collection, or {@code null}. */
     protected final HttpParams overrideParams;
 
 
@@ -91,10 +91,10 @@ public class ClientParamsStack extends AbstractHttpParams {
      * The arguments will be stored as-is, there is no copying to
      * prevent modification.
      *
-     * @param aparams   application parameters, or <code>null</code>
-     * @param cparams   client parameters, or <code>null</code>
-     * @param rparams   request parameters, or <code>null</code>
-     * @param oparams   override parameters, or <code>null</code>
+     * @param aparams   application parameters, or {@code null}
+     * @param cparams   client parameters, or {@code null}
+     * @param rparams   request parameters, or {@code null}
+     * @param oparams   override parameters, or {@code null}
      */
     public ClientParamsStack(final HttpParams aparams, final HttpParams cparams,
                              final HttpParams rparams, final HttpParams oparams) {
@@ -123,15 +123,15 @@ public class ClientParamsStack extends AbstractHttpParams {
     /**
      * Creates a modified copy of a parameter stack.
      * The new stack will contain the explicitly passed elements.
-     * For elements where the explicit argument is <code>null</code>,
+     * For elements where the explicit argument is {@code null},
      * the corresponding element from the argument stack is used.
      * There is no copying of parameters.
      *
      * @param stack     the stack to modify
-     * @param aparams   application parameters, or <code>null</code>
-     * @param cparams   client parameters, or <code>null</code>
-     * @param rparams   request parameters, or <code>null</code>
-     * @param oparams   override parameters, or <code>null</code>
+     * @param aparams   application parameters, or {@code null}
+     * @param cparams   client parameters, or {@code null}
+     * @param rparams   request parameters, or {@code null}
+     * @param oparams   override parameters, or {@code null}
      */
     public ClientParamsStack(final ClientParamsStack stack,
                              final HttpParams aparams, final HttpParams cparams,
@@ -146,7 +146,7 @@ public class ClientParamsStack extends AbstractHttpParams {
     /**
      * Obtains the application parameters of this stack.
      *
-     * @return  the application parameters, or <code>null</code>
+     * @return  the application parameters, or {@code null}
      */
     public final HttpParams getApplicationParams() {
         return applicationParams;
@@ -155,7 +155,7 @@ public class ClientParamsStack extends AbstractHttpParams {
     /**
      * Obtains the client parameters of this stack.
      *
-     * @return  the client parameters, or <code>null</code>
+     * @return  the client parameters, or {@code null}
      */
     public final HttpParams getClientParams() {
         return clientParams;
@@ -164,7 +164,7 @@ public class ClientParamsStack extends AbstractHttpParams {
     /**
      * Obtains the request parameters of this stack.
      *
-     * @return  the request parameters, or <code>null</code>
+     * @return  the request parameters, or {@code null}
      */
     public final HttpParams getRequestParams() {
         return requestParams;
@@ -173,7 +173,7 @@ public class ClientParamsStack extends AbstractHttpParams {
     /**
      * Obtains the override parameters of this stack.
      *
-     * @return  the override parameters, or <code>null</code>
+     * @return  the override parameters, or {@code null}
      */
     public final HttpParams getOverrideParams() {
         return overrideParams;
@@ -187,7 +187,7 @@ public class ClientParamsStack extends AbstractHttpParams {
      * @param name      the name of the parameter to obtain
      *
      * @return  the highest-priority value for that parameter, or
-     *          <code>null</code> if it is not set anywhere in this stack
+     *          {@code null} if it is not set anywhere in this stack
      */
     public Object getParameter(final String name) {
         Args.notNull(name, "Parameter name");
@@ -256,10 +256,11 @@ public class ClientParamsStack extends AbstractHttpParams {
      * accidental modification of parameters passed by the application to
      * a framework object is therefore pointless and disabled.
      * Create a new stack if you really need a copy.
-     * <br/>
+     * <p>
      * Derived classes may change this behavior.
+     * </p>
      *
-     * @return <code>this</code> parameter stack
+     * @return {@code this} parameter stack
      */
     public HttpParams copy() {
         return this;
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/CloseableHttpResponseProxy.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/CloseableHttpResponseProxy.java
similarity index 75%
rename from httpclient/src/main/java/org/apache/http/impl/client/CloseableHttpResponseProxy.java
rename to httpclient/src/main/java-deprecated/org/apache/http/impl/client/CloseableHttpResponseProxy.java
index 5b575f6..bd41fc6 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/CloseableHttpResponseProxy.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/CloseableHttpResponseProxy.java
@@ -28,6 +28,7 @@
 package org.apache.http.impl.client;
 
 import java.io.IOException;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -42,9 +43,21 @@ import org.apache.http.util.EntityUtils;
 /**
  * @since 4.3
  */
+ at Deprecated
 @NotThreadSafe
 class CloseableHttpResponseProxy implements InvocationHandler {
 
+    private final static Constructor<?> CONSTRUCTOR;
+
+    static {
+        try {
+            CONSTRUCTOR = Proxy.getProxyClass(CloseableHttpResponseProxy.class.getClassLoader(),
+                    new Class<?>[] { CloseableHttpResponse.class }).getConstructor(new Class[] { InvocationHandler.class });
+        } catch (NoSuchMethodException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
     private final HttpResponse original;
 
     CloseableHttpResponseProxy(final HttpResponse original) {
@@ -57,6 +70,7 @@ class CloseableHttpResponseProxy implements InvocationHandler {
         EntityUtils.consume(entity);
     }
 
+    @Override
     public Object invoke(
             final Object proxy, final Method method, final Object[] args) throws Throwable {
         final String mname = method.getName();
@@ -78,10 +92,15 @@ class CloseableHttpResponseProxy implements InvocationHandler {
     }
 
     public static CloseableHttpResponse newProxy(final HttpResponse original) {
-        return (CloseableHttpResponse) Proxy.newProxyInstance(
-                CloseableHttpResponseProxy.class.getClassLoader(),
-                new Class<?>[] { CloseableHttpResponse.class },
-                new CloseableHttpResponseProxy(original));
+        try {
+            return (CloseableHttpResponse) CONSTRUCTOR.newInstance(new CloseableHttpResponseProxy(original));
+        } catch (InstantiationException ex) {
+            throw new IllegalStateException(ex);
+        } catch (InvocationTargetException ex) {
+            throw new IllegalStateException(ex);
+        } catch (IllegalAccessException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
 }
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DecompressingHttpClient.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DecompressingHttpClient.java
index f806bd1..db2255e 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DecompressingHttpClient.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DecompressingHttpClient.java
@@ -52,22 +52,22 @@ import org.apache.http.util.EntityUtils;
 
 /**
  * <p>Decorator adding support for compressed responses. This class sets
- * the <code>Accept-Encoding</code> header on requests to indicate
- * support for the <code>gzip</code> and <code>deflate</code>
- * compression schemes; it then checks the <code>Content-Encoding</code>
+ * the {@code Accept-Encoding} header on requests to indicate
+ * support for the {@code gzip} and {@code deflate}
+ * compression schemes; it then checks the {@code Content-Encoding}
  * header on the response to uncompress any compressed response bodies.
  * The {@link java.io.InputStream} of the entity will contain the uncompressed
  * content.</p>
  *
  * <p><b>N.B.</b> Any upstream clients of this class need to be aware that
  * this effectively obscures visibility into the length of a server
- * response body, since the <code>Content-Length</code> header will
+ * response body, since the {@code Content-Length} header will
  * correspond to the compressed entity length received from the server,
  * but the content length experienced by reading the response body may
  * be different (hopefully higher!).</p>
  *
  * <p>That said, this decorator is compatible with the
- * <code>CachingHttpClient</code> in that the two decorators can be added
+ * {@code CachingHttpClient} in that the two decorators can be added
  * in either order and still have cacheable responses be cached.</p>
  *
  * @since 4.2
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultHttpClient.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultHttpClient.java
index d41b760..e64b008 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultHttpClient.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultHttpClient.java
@@ -47,6 +47,7 @@ import org.apache.http.protocol.RequestContent;
 import org.apache.http.protocol.RequestExpectContinue;
 import org.apache.http.protocol.RequestTargetHost;
 import org.apache.http.protocol.RequestUserAgent;
+import org.apache.http.util.VersionInfo;
 
 /**
  * Default implementation of {@link org.apache.http.client.HttpClient} pre-configured
@@ -109,7 +110,7 @@ import org.apache.http.protocol.RequestUserAgent;
  *
  * @since 4.0
  *
- * @deprecated (4.3) use {@link HttpClientBuilder}.
+ * @deprecated (4.3) use {@link HttpClientBuilder} see also {@link CloseableHttpClient}.
  */
 @ThreadSafe
 @Deprecated
@@ -172,7 +173,7 @@ public class DefaultHttpClient extends AbstractHttpClient {
      * <li>{@link org.apache.http.params.CoreConnectionPNames#SOCKET_BUFFER_SIZE}:
      *   8192</li>
      * <li>{@link org.apache.http.params.CoreProtocolPNames#USER_AGENT}:
-     *   Apache-HttpClient/<release> (java 1.5)</li>
+     *   Apache-HttpClient (Java 1.5)</li>
      * </ul>
      */
     public static void setDefaultHttpParams(final HttpParams params) {
@@ -180,7 +181,8 @@ public class DefaultHttpClient extends AbstractHttpClient {
         HttpProtocolParams.setContentCharset(params, HTTP.DEF_CONTENT_CHARSET.name());
         HttpConnectionParams.setTcpNoDelay(params, true);
         HttpConnectionParams.setSocketBufferSize(params, 8192);
-        HttpProtocolParams.setUserAgent(params, HttpClientBuilder.DEFAULT_USER_AGENT);
+        HttpProtocolParams.setUserAgent(params, VersionInfo.getUserAgent("Apache-HttpClient",
+                "org.apache.http.client", DefaultHttpClient.class));
     }
 
     /**
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultRequestDirector.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultRequestDirector.java
index eaf784b..1ee69a5 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultRequestDirector.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/DefaultRequestDirector.java
@@ -744,12 +744,12 @@ public class DefaultRequestDirector implements RequestDirector {
      * to determine the route for either the original or a followup request.
      *
      * @param targetHost  the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
      * @param context   the context to use for the execution,
-     *                  never <code>null</code>
+     *                  never {@code null}
      *
      * @return  the route the request should take
      *
@@ -841,9 +841,9 @@ public class DefaultRequestDirector implements RequestDirector {
      * @param route     the route to establish
      * @param context   the context for request execution
      *
-     * @return  <code>true</code> if the tunnelled route is secure,
-     *          <code>false</code> otherwise.
-     *          The implementation here always returns <code>false</code>,
+     * @return  {@code true} if the tunnelled route is secure,
+     *          {@code false} otherwise.
+     *          The implementation here always returns {@code false},
      *          but derived classes may override.
      *
      * @throws HttpException    in case of a problem
@@ -942,12 +942,12 @@ public class DefaultRequestDirector implements RequestDirector {
      *
      * @param route     the route to establish
      * @param hop       the hop in the route to establish now.
-     *                  <code>route.getHopTarget(hop)</code>
+     *                  {@code route.getHopTarget(hop)}
      *                  will return the proxy to tunnel to.
      * @param context   the context for request execution
      *
-     * @return  <code>true</code> if the partially tunnelled connection
-     *          is secure, <code>false</code> otherwise.
+     * @return  {@code true} if the partially tunnelled connection
+     *          is secure, {@code false} otherwise.
      *
      * @throws HttpException    in case of a problem
      * @throws IOException      in case of an IO problem
@@ -1017,7 +1017,7 @@ public class DefaultRequestDirector implements RequestDirector {
      * @param context   the context used for the current request execution
      *
      * @return  the followup request and route if there is a followup, or
-     *          <code>null</code> if the response should be returned as is
+     *          {@code null} if the response should be returned as is
      *
      * @throws HttpException    in case of a problem
      * @throws IOException      in case of an IO problem
@@ -1121,7 +1121,7 @@ public class DefaultRequestDirector implements RequestDirector {
 
     /**
      * Shuts down the connection.
-     * This method is called from a <code>catch</code> block in
+     * This method is called from a {@code catch} block in
      * {@link #execute execute} during exception handling.
      */
     private void abortConnection() {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/SystemDefaultHttpClient.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/SystemDefaultHttpClient.java
index 095beab..0d3c581 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/client/SystemDefaultHttpClient.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/client/SystemDefaultHttpClient.java
@@ -66,6 +66,7 @@ import org.apache.http.params.HttpParams;
  * <p>
  * The following parameters can be used to customize the behavior of this
  * class:
+ * </p>
  * <ul>
  *  <li>{@link org.apache.http.params.CoreProtocolPNames#PROTOCOL_VERSION}</li>
  *  <li>{@link org.apache.http.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li>
@@ -98,7 +99,6 @@ import org.apache.http.params.HttpParams;
  *  <li>{@link org.apache.http.client.params.ClientPNames#DEFAULT_HEADERS}</li>
  *  <li>{@link org.apache.http.client.params.ClientPNames#CONN_MANAGER_TIMEOUT}</li>
  * </ul>
- * </p>
  *
  * @since 4.2
  *
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractClientConnAdapter.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractClientConnAdapter.java
index 9c12678..52d8875 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractClientConnAdapter.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractClientConnAdapter.java
@@ -95,8 +95,8 @@ public abstract class AbstractClientConnAdapter implements ManagedClientConnecti
      * The adapter is initially <i>not</i>
      * {@link #isMarkedReusable marked} as reusable.
      *
-     * @param mgr       the connection manager, or <code>null</code>
-     * @param conn      the connection to wrap, or <code>null</code>
+     * @param mgr       the connection manager, or {@code null}
+     * @param conn      the connection to wrap, or {@code null}
      */
     protected AbstractClientConnAdapter(final ClientConnectionManager mgr,
                                         final OperatedClientConnection conn) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPoolEntry.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPoolEntry.java
index bc1b37f..3182ebb 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPoolEntry.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPoolEntry.java
@@ -75,7 +75,7 @@ public abstract class AbstractPoolEntry {
     /** Connection state object */
     protected volatile Object state;
 
-    /** The tracked route, or <code>null</code> before tracking starts. */
+    /** The tracked route, or {@code null} before tracking starts. */
     protected volatile RouteTracker tracker;
 
 
@@ -84,7 +84,7 @@ public abstract class AbstractPoolEntry {
      *
      * @param connOperator     the Connection Operator for this entry
      * @param route   the planned route for the connection,
-     *                or <code>null</code>
+     *                or {@code null}
      */
     protected AbstractPoolEntry(final ClientConnectionOperator connOperator,
                                 final HttpRoute route) {
@@ -168,8 +168,8 @@ public abstract class AbstractPoolEntry {
      * The tunnel has to be established outside by sending a CONNECT
      * request to the (last) proxy.
      *
-     * @param secure    <code>true</code> if the tunnel should be
-     *                  considered secure, <code>false</code> otherwise
+     * @param secure    {@code true} if the tunnel should be
+     *                  considered secure, {@code false} otherwise
      * @param params    the parameters for tunnelling the connection
      *
      * @throws IOException  in case of a problem
@@ -196,8 +196,8 @@ public abstract class AbstractPoolEntry {
      *  See {@link org.apache.http.conn.ManagedClientConnection#tunnelProxy
      *                                  ManagedClientConnection.tunnelProxy}
      *                  for details.
-     * @param secure    <code>true</code> if the tunnel should be
-     *                  considered secure, <code>false</code> otherwise
+     * @param secure    {@code true} if the tunnel should be
+     *                  considered secure, {@code false} otherwise
      * @param params    the parameters for tunnelling the connection
      *
      * @throws IOException  in case of a problem
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPooledConnAdapter.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPooledConnAdapter.java
index d2a6da5..79bc619 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPooledConnAdapter.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/AbstractPooledConnAdapter.java
@@ -74,7 +74,7 @@ public abstract class AbstractPooledConnAdapter extends AbstractClientConnAdapte
     /**
      * Obtains the pool entry.
      *
-     * @return  the pool entry, or <code>null</code> if detached
+     * @return  the pool entry, or {@code null} if detached
      *
      * @deprecated (4.0.1)
      */
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/BasicClientConnectionManager.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/BasicClientConnectionManager.java
index a8c608b..7a2baed 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/BasicClientConnectionManager.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/BasicClientConnectionManager.java
@@ -50,15 +50,17 @@ import org.apache.http.util.Asserts;
  * A connection manager for a single connection. This connection manager maintains only one active
  * connection. Even though this class is fully thread-safe it ought to be used by one execution
  * thread only, as only one thread a time can lease the connection at a time.
- * <p/>
+ * <p>
  * This connection manager will make an effort to reuse the connection for subsequent requests
  * with the same {@link HttpRoute route}. It will, however, close the existing connection and
  * open it for the given route, if the route of the persistent connection does not match that
  * of the connection request. If the connection has been already been allocated
  * {@link IllegalStateException} is thrown.
- * <p/>
+ * </p>
+ * <p>
  * This connection manager implementation should be used inside an EJB container instead of
  * {@link PoolingClientConnectionManager}.
+ * </p>
  *
  * @since 4.2
  *
@@ -164,8 +166,8 @@ public class BasicClientConnectionManager implements ClientConnectionManager {
             }
             if (this.poolEntry == null) {
                 final String id = Long.toString(COUNTER.getAndIncrement());
-                final OperatedClientConnection conn = this.connOperator.createConnection();
-                this.poolEntry = new HttpPoolEntry(this.log, id, route, conn, 0, TimeUnit.MILLISECONDS);
+                final OperatedClientConnection opconn = this.connOperator.createConnection();
+                this.poolEntry = new HttpPoolEntry(this.log, id, route, opconn, 0, TimeUnit.MILLISECONDS);
             }
             final long now = System.currentTimeMillis();
             if (this.poolEntry.isExpired(now)) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/DefaultClientConnectionOperator.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
index 2491604..fb1a719 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
@@ -63,7 +63,7 @@ import org.apache.http.util.Asserts;
  * addresses fail to respond. Please note the same
  * {@link org.apache.http.params.CoreConnectionPNames#CONNECTION_TIMEOUT} value will be used
  * for each connection attempt, so in the worst case the total elapsed time before timeout
- * can be <code>CONNECTION_TIMEOUT * n</code> where <code>n</code> is the number of IP addresses
+ * can be {@code CONNECTION_TIMEOUT * n} where {@code n} is the number of IP addresses
  * of the given host. One can disable multihome support by overriding
  * the {@link #resolveHostname(String)} method and returning only one IP address for the given
  * host name.
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionInputBuffer.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionInputBuffer.java
index 26a2c44..349e6f7 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionInputBuffer.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionInputBuffer.java
@@ -60,7 +60,7 @@ public class LoggingSessionInputBuffer implements SessionInputBuffer, EofSensor
      * Create an instance that wraps the specified session input buffer.
      * @param in The session input buffer.
      * @param wire The wire log to use.
-     * @param charset protocol charset, <code>ASCII</code> if <code>null</code>
+     * @param charset protocol charset, {@code ASCII} if {@code null}
      */
     public LoggingSessionInputBuffer(
             final SessionInputBuffer in, final Wire wire, final String charset) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java
index 6549dee..8d8fc8a 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/LoggingSessionOutputBuffer.java
@@ -55,7 +55,7 @@ public class LoggingSessionOutputBuffer implements SessionOutputBuffer {
      * Create an instance that wraps the specified session output buffer.
      * @param out The session output buffer.
      * @param wire The Wire log to use.
-     * @param charset protocol charset, <code>ASCII</code> if <code>null</code>
+     * @param charset protocol charset, {@code ASCII} if {@code null}
      */
     public LoggingSessionOutputBuffer(
             final SessionOutputBuffer out, final Wire wire, final String charset) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
index cba3f67..69d714b 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
@@ -78,7 +78,7 @@ public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
     /** The scheme registry. */
     protected final SchemeRegistry schemeRegistry; // @ThreadSafe
 
-    /** The proxy selector to use, or <code>null</code> for system default. */
+    /** The proxy selector to use, or {@code null} for system default. */
     protected ProxySelector proxySelector;
 
     /**
@@ -86,7 +86,7 @@ public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
      *
      * @param schreg    the scheme registry
      * @param prosel    the proxy selector, or
-     *                  <code>null</code> for the system default
+     *                  {@code null} for the system default
      */
     public ProxySelectorRoutePlanner(final SchemeRegistry schreg,
                                      final ProxySelector prosel) {
@@ -98,7 +98,7 @@ public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
     /**
      * Obtains the proxy selector to use.
      *
-     * @return the proxy selector, or <code>null</code> for the system default
+     * @return the proxy selector, or {@code null} for the system default
      */
     public ProxySelector getProxySelector() {
         return this.proxySelector;
@@ -108,7 +108,7 @@ public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
      * Sets the proxy selector to use.
      *
      * @param prosel    the proxy selector, or
-     *                  <code>null</code> to use the system default
+     *                  {@code null} to use the system default
      */
     public void setProxySelector(final ProxySelector prosel) {
         this.proxySelector = prosel;
@@ -154,11 +154,11 @@ public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
     /**
      * Determines a proxy for the given target.
      *
-     * @param target    the planned target, never <code>null</code>
-     * @param request   the request to be sent, never <code>null</code>
-     * @param context   the context, or <code>null</code>
+     * @param target    the planned target, never {@code null}
+     * @param request   the request to be sent, never {@code null}
+     * @param context   the context, or {@code null}
      *
-     * @return  the proxy to use, or <code>null</code> for a direct route
+     * @return  the proxy to use, or {@code null} for a direct route
      *
      * @throws HttpException
      *         in case of system proxy settings that cannot be handled
@@ -210,8 +210,9 @@ public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
      *
      * @return  a host string, either as a symbolic name or
      *          as a literal IP address string
-     * <br/>
+     * <p>
      * (TODO: determine format for IPv6 addresses, with or without [brackets])
+     * </p>
      */
     protected String getHost(final InetSocketAddress isa) {
 
@@ -232,10 +233,10 @@ public class ProxySelectorRoutePlanner implements HttpRoutePlanner {
      * such as proxy rotation if there are multiple options.
      *
      * @param proxies   the list of proxies to choose from,
-     *                  never <code>null</code> or empty
-     * @param target    the planned target, never <code>null</code>
-     * @param request   the request to be sent, never <code>null</code>
-     * @param context   the context, or <code>null</code>
+     *                  never {@code null} or empty
+     * @param target    the planned target, never {@code null}
+     * @param request   the request to be sent, never {@code null}
+     * @param context   the context, or {@code null}
      *
      * @return  a proxy type
      */
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/SingleClientConnManager.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/SingleClientConnManager.java
index 9ef80ab..d3bfc9b 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/SingleClientConnManager.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/SingleClientConnManager.java
@@ -157,7 +157,7 @@ public class SingleClientConnManager implements ClientConnectionManager {
      * The default implementation here instantiates
      * {@link DefaultClientConnectionOperator DefaultClientConnectionOperator}.
      *
-     * @param schreg    the scheme registry to use, or <code>null</code>
+     * @param schreg    the scheme registry to use, or {@code null}
      *
      * @return  the connection operator to use
      */
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/AbstractConnPool.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/AbstractConnPool.java
index 32cdca6..c7e6243 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/AbstractConnPool.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/AbstractConnPool.java
@@ -50,7 +50,7 @@ import org.apache.http.util.Args;
  * It is used by the {@link ThreadSafeClientConnManager}.
  * The abstract pool includes a {@link #poolLock}, which is used to
  * synchronize access to the internal pool datastructures.
- * Don't use <code>synchronized</code> for that purpose!
+ * Don't use {@code synchronized} for that purpose!
  *
  * @since 4.0
  *
@@ -102,9 +102,10 @@ public abstract class AbstractConnPool {
      * Obtains a pool entry with a connection within the given timeout.
      *
      * @param route     the route for which to get the connection
+     * @param state     the state
      * @param timeout   the timeout, 0 or negative for no timeout
-     * @param tunit     the unit for the <code>timeout</code>,
-     *                  may be <code>null</code> only if there is no timeout
+     * @param tunit     the unit for the {@code timeout},
+     *                  may be {@code null} only if there is no timeout
      *
      * @return  pool entry holding a connection for the route
      *
@@ -126,6 +127,9 @@ public abstract class AbstractConnPool {
     /**
      * Returns a new {@link PoolEntryRequest}, from which a {@link BasicPoolEntry}
      * can be obtained, or the request can be aborted.
+     * @param route the route
+     * @param state the state
+     * @return the entry request
      */
     public abstract PoolEntryRequest requestPoolEntry(HttpRoute route, Object state);
 
@@ -137,8 +141,8 @@ public abstract class AbstractConnPool {
      * attempt to determine whether it can be re-used or not.
      *
      * @param entry     the entry for the connection to release
-     * @param reusable  <code>true</code> if the entry is deemed
-     *                  reusable, <code>false</code> otherwise.
+     * @param reusable  {@code true} if the entry is deemed
+     *                  reusable, {@code false} otherwise.
      * @param validDuration The duration that the entry should remain free and reusable.
      * @param timeUnit The unit of time the duration is measured in.
      */
@@ -155,7 +159,7 @@ public abstract class AbstractConnPool {
      *
      * @param idletime  the time the connections should have been idle
      *                  in order to be closed now
-     * @param tunit     the unit for the <code>idletime</code>
+     * @param tunit     the unit for the {@code idletime}
      */
     public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
 
@@ -218,7 +222,7 @@ public abstract class AbstractConnPool {
     /**
      * Closes a connection from this pool.
      *
-     * @param conn      the connection to close, or <code>null</code>
+     * @param conn      the connection to close, or {@code null}
      */
     protected void closeConnection(final OperatedClientConnection conn) {
         if (conn != null) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java
index 19566bb..f79128f 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntry.java
@@ -77,7 +77,7 @@ public class BasicPoolEntry extends AbstractPoolEntry {
      *
      * @param op        the connection operator
      * @param route     the planned route for the connection
-     * @param connTTL   maximum lifetime of this entry, <=0 implies "infinity"
+     * @param connTTL   maximum lifetime of this entry, <=0 implies "infinity"
      * @param timeunit  TimeUnit of connTTL
      *
      * @since 4.1
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java
index b34a0ce..2220380 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.java
@@ -51,8 +51,8 @@ public class BasicPoolEntryRef extends WeakReference<BasicPoolEntry> {
     /**
      * Creates a new reference to a pool entry.
      *
-     * @param entry   the pool entry, must not be <code>null</code>
-     * @param queue   the reference queue, or <code>null</code>
+     * @param entry   the pool entry, must not be {@code null}
+     * @param queue   the reference queue, or {@code null}
      */
     public BasicPoolEntryRef(final BasicPoolEntry entry,
                              final ReferenceQueue<Object> queue) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java
index ab9f643..7c1bace 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.java
@@ -52,7 +52,7 @@ import org.apache.http.util.Asserts;
 
 /**
  * A connection pool that maintains connections by route.
- * This class is derived from <code>MultiThreadedHttpConnectionManager</code>
+ * This class is derived from {@code MultiThreadedHttpConnectionManager}
  * in HttpClient 3.x, see there for original authors. It implements the same
  * algorithm for connection re-use and connection-per-host enforcement:
  * <ul>
@@ -61,7 +61,7 @@ import org.apache.http.util.Asserts;
  * </ul>
  * Note that access to the pool data structures is synchronized via the
  * {@link AbstractConnPool#poolLock poolLock} in the base class,
- * not via <code>synchronized</code> methods.
+ * not via {@code synchronized} methods.
  *
  * @since 4.0
  *
@@ -203,7 +203,7 @@ public class ConnPoolByRoute extends AbstractConnPool {
      * Called by {@link #getRoutePool} when necessary.
      *
      * @param cond      the condition to wait for
-     * @param rospl     the route specific pool, or <code>null</code>
+     * @param rospl     the route specific pool, or {@code null}
      *
      * @return  a waiting thread representation
      */
@@ -230,7 +230,7 @@ public class ConnPoolByRoute extends AbstractConnPool {
      * @param create    whether to create the pool if it doesn't exist
      *
      * @return  the pool for the argument route,
-     *     never <code>null</code> if <code>create</code> is <code>true</code>
+     *     never {@code null} if {@code create} is {@code true}
      */
     protected RouteSpecificPool getRoutePool(final HttpRoute route,
                                              final boolean create) {
@@ -308,8 +308,8 @@ public class ConnPoolByRoute extends AbstractConnPool {
      *
      * @param route     the route for which to get the connection
      * @param timeout   the timeout, 0 or negative for no timeout
-     * @param tunit     the unit for the <code>timeout</code>,
-     *                  may be <code>null</code> only if there is no timeout
+     * @param tunit     the unit for the {@code timeout},
+     *                  may be {@code null} only if there is no timeout
      * @param aborter   an object which can abort a {@link WaitingThread}.
      *
      * @return  pool entry holding a connection for the route
@@ -477,7 +477,7 @@ public class ConnPoolByRoute extends AbstractConnPool {
      * @param rospl       the route-specific pool from which to get an entry
      *
      * @return  an available pool entry for the given route, or
-     *          <code>null</code> if none is available
+     *          {@code null} if none is available
      */
     protected BasicPoolEntry getFreeEntry(final RouteSpecificPool rospl, final Object state) {
 
@@ -647,7 +647,7 @@ public class ConnPoolByRoute extends AbstractConnPool {
      * if there is one.
      * Otherwise, a thread in the connection pool will be notified.
      *
-     * @param rospl     the pool in which to notify, or <code>null</code>
+     * @param rospl     the pool in which to notify, or {@code null}
      */
     protected void notifyWaitingThread(final RouteSpecificPool rospl) {
 
@@ -708,7 +708,7 @@ public class ConnPoolByRoute extends AbstractConnPool {
      *
      * @param idletime  the time the connections should have been idle
      *                  in order to be closed now
-     * @param tunit     the unit for the <code>idletime</code>
+     * @param tunit     the unit for the {@code idletime}
      */
     @Override
     public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java
index 25835d9..52b3564 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/PoolEntryRequest.java
@@ -46,8 +46,8 @@ public interface PoolEntryRequest {
      * an {@link InterruptedException} is thrown.
      *
      * @param timeout   the timeout, 0 or negative for no timeout
-     * @param tunit     the unit for the <code>timeout</code>,
-     *                  may be <code>null</code> only if there is no timeout
+     * @param tunit     the unit for the {@code timeout},
+     *                  may be {@code null} only if there is no timeout
      *
      * @return  pool entry holding a connection for the route
      *
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java
index 79cf866..875802f 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/RouteSpecificPool.java
@@ -84,7 +84,7 @@ public class RouteSpecificPool {
         this.route = route;
         this.maxEntries = maxEntries;
         this.connPerRoute = new ConnPerRoute() {
-            public int getMaxForRoute(final HttpRoute route) {
+            public int getMaxForRoute(final HttpRoute unused) {
                 return RouteSpecificPool.this.maxEntries;
             }
         };
@@ -135,8 +135,8 @@ public class RouteSpecificPool {
      * A pool is unused if there is neither an entry nor a waiting thread.
      * All entries count, not only the free but also the allocated ones.
      *
-     * @return  <code>true</code> if this pool is unused,
-     *          <code>false</code> otherwise
+     * @return  {@code true} if this pool is unused,
+     *          {@code false} otherwise
      */
     public boolean isUnused() {
         return (numEntries < 1) && waitingThreads.isEmpty();
@@ -168,7 +168,7 @@ public class RouteSpecificPool {
     /**
      * Obtains a free entry from this pool, if one is available.
      *
-     * @return an available pool entry, or <code>null</code> if there is none
+     * @return an available pool entry, or {@code null} if there is none
      */
     public BasicPoolEntry allocEntry(final Object state) {
         if (!freeEntries.isEmpty()) {
@@ -236,8 +236,8 @@ public class RouteSpecificPool {
      *
      * @param entry     the entry to delete from this pool
      *
-     * @return  <code>true</code> if the entry was found and deleted, or
-     *          <code>false</code> if the entry was not found
+     * @return  {@code true} if the entry was found and deleted, or
+     *          {@code false} if the entry was not found
      */
     public boolean deleteEntry(final BasicPoolEntry entry) {
 
@@ -278,8 +278,8 @@ public class RouteSpecificPool {
     /**
      * Checks whether there is a waiting thread in this pool.
      *
-     * @return  <code>true</code> if there is a waiting thread,
-     *          <code>false</code> otherwise
+     * @return  {@code true} if there is a waiting thread,
+     *          {@code false} otherwise
      */
     public boolean hasThread() {
         return !this.waitingThreads.isEmpty();
@@ -289,7 +289,7 @@ public class RouteSpecificPool {
     /**
      * Returns the next thread in the queue.
      *
-     * @return  a waiting thread, or <code>null</code> if there is none
+     * @return  a waiting thread, or {@code null} if there is none
      */
     public WaitingThread nextThread() {
         return this.waitingThreads.peek();
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
index 2e1baf5..2a3538e 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
@@ -105,7 +105,7 @@ public class ThreadSafeClientConnManager implements ClientConnectionManager {
      * Creates a new thread safe connection manager.
      *
      * @param schreg    the scheme registry.
-     * @param connTTL   max connection lifetime, <=0 implies "infinity"
+     * @param connTTL   max connection lifetime, <=0 implies "infinity"
      * @param connTTLTimeUnit   TimeUnit of connTTL
      *
      * @since 4.1
@@ -119,7 +119,7 @@ public class ThreadSafeClientConnManager implements ClientConnectionManager {
      * Creates a new thread safe connection manager.
      *
      * @param schreg    the scheme registry.
-     * @param connTTL   max connection lifetime, <=0 implies "infinity"
+     * @param connTTL   max connection lifetime, <=0 implies "infinity"
      * @param connTTLTimeUnit   TimeUnit of connTTL
      * @param connPerRoute    mapping of maximum connections per route,
      *   provided as a dependency so it can be managed externally, e.g.
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/WaitingThread.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/WaitingThread.java
index 1a93495..30e47a5 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/WaitingThread.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/conn/tsccm/WaitingThread.java
@@ -34,18 +34,20 @@ import org.apache.http.util.Args;
 
 /**
  * Represents a thread waiting for a connection.
- * This class implements throwaway objects. It is instantiated whenever
+ * <p>
+ * This class implements throw away objects. It is instantiated whenever
  * a thread needs to wait. Instances are not re-used, except if the
- * waiting thread experiences a spurious wakeup and continues to wait.
- * <br/>
+ * waiting thread experiences a spurious wake up and continues to wait.
+ * </p>
+ * <p>
  * All methods assume external synchronization on the condition
  * passed to the constructor.
  * Instances of this class do <i>not</i> synchronize access!
- *
+ * </p>
  *
  * @since 4.0
  *
- * @deprecated (4.2)  do not use
+ * @deprecated (4.2) do not use
  */
 @Deprecated
 public class WaitingThread {
@@ -69,7 +71,7 @@ public class WaitingThread {
      *
      * @param cond      the condition for which to wait
      * @param pool      the pool on which the thread will be waiting,
-     *                  or <code>null</code>
+     *                  or {@code null}
      */
     public WaitingThread(final Condition cond, final RouteSpecificPool pool) {
 
@@ -83,7 +85,7 @@ public class WaitingThread {
     /**
      * Obtains the condition.
      *
-     * @return  the condition on which to wait, never <code>null</code>
+     * @return  the condition on which to wait, never {@code null}
      */
     public final Condition getCondition() {
         // not synchronized
@@ -95,7 +97,7 @@ public class WaitingThread {
      * Obtains the pool, if there is one.
      *
      * @return  the pool on which a thread is or was waiting,
-     *          or <code>null</code>
+     *          or {@code null}
      */
     public final RouteSpecificPool getPool() {
         // not synchronized
@@ -106,7 +108,7 @@ public class WaitingThread {
     /**
      * Obtains the thread, if there is one.
      *
-     * @return  the thread which is waiting, or <code>null</code>
+     * @return  the thread which is waiting, or {@code null}
      */
     public final Thread getThread() {
         // not synchronized
@@ -118,13 +120,14 @@ public class WaitingThread {
      * Blocks the calling thread.
      * This method returns when the thread is notified or interrupted,
      * if a timeout occurrs, or if there is a spurious wakeup.
-     * <br/>
+     * <p>
      * This method assumes external synchronization.
+     * </p>
      *
-     * @param deadline  when to time out, or <code>null</code> for no timeout
+     * @param deadline  when to time out, or {@code null} for no timeout
      *
-     * @return  <code>true</code> if the condition was satisfied,
-     *          <code>false</code> in case of a timeout.
+     * @return  {@code true} if the condition was satisfied,
+     *          {@code false} in case of a timeout.
      *          Typically, a call to {@link #wakeup} is used to indicate
      *          that the condition was satisfied. Since the condition is
      *          accessible outside, this cannot be guaranteed though.
@@ -172,8 +175,9 @@ public class WaitingThread {
 
     /**
      * Wakes up the waiting thread.
-     * <br/>
+     * <p>
      * This method assumes external synchronization.
+     * </p>
      */
     public void wakeup() {
 
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BestMatchSpec.java
similarity index 68%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java
copy to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BestMatchSpec.java
index 6270da1..a21da60 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BestMatchSpec.java
@@ -24,28 +24,34 @@
  * <http://www.apache.org/>.
  *
  */
+
 package org.apache.http.impl.cookie;
 
-import org.apache.http.annotation.Immutable;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.cookie.SetCookie;
-import org.apache.http.util.Args;
+import org.apache.http.annotation.ThreadSafe;
 
 /**
+ * 'Meta' cookie specification that picks up a cookie policy based on
+ * the format of cookies sent with the HTTP response.
+ *
+ * @deprecated (4.4) use {@link org.apache.http.impl.cookie.DefaultCookieSpec}.
  *
  * @since 4.0
  */
- at Immutable
-public class BasicCommentHandler extends AbstractCookieAttributeHandler {
+ at ThreadSafe
+ at Deprecated
+public class BestMatchSpec extends DefaultCookieSpec {
+
+    public BestMatchSpec(final String[] datepatterns, final boolean oneHeader) {
+        super(datepatterns, oneHeader);
+    }
 
-    public BasicCommentHandler() {
-        super();
+    public BestMatchSpec() {
+        this(null, false);
     }
 
-    public void parse(final SetCookie cookie, final String value)
-            throws MalformedCookieException {
-        Args.notNull(cookie, "Cookie");
-        cookie.setComment(value);
+    @Override
+    public String toString() {
+        return "best-match";
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BestMatchSpecFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BestMatchSpecFactory.java
similarity index 84%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/BestMatchSpecFactory.java
rename to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BestMatchSpecFactory.java
index 5703d2b..7ad7f63 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BestMatchSpecFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BestMatchSpecFactory.java
@@ -38,28 +38,30 @@ import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that creates and initializes
- * {@link BestMatchSpec} instances.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link org.apache.http.impl.cookie.BestMatchSpec}. The instance returned by this factory can
+ * be shared by multiple threads.
+ *
+ * @deprecated (4.4) use {@link org.apache.http.impl.cookie.DefaultCookieSpecProvider}.
  *
  * @since 4.0
  */
 @Immutable
- at SuppressWarnings("deprecation")
+ at Deprecated
 public class BestMatchSpecFactory implements CookieSpecFactory, CookieSpecProvider {
 
-    private final String[] datepatterns;
-    private final boolean oneHeader;
+    private final CookieSpec cookieSpec;
 
     public BestMatchSpecFactory(final String[] datepatterns, final boolean oneHeader) {
         super();
-        this.datepatterns = datepatterns;
-        this.oneHeader = oneHeader;
+        this.cookieSpec = new BestMatchSpec(datepatterns, oneHeader);;
     }
 
     public BestMatchSpecFactory() {
         this(null, false);
     }
 
+    @Override
     public CookieSpec newInstance(final HttpParams params) {
         if (params != null) {
 
@@ -79,8 +81,9 @@ public class BestMatchSpecFactory implements CookieSpecFactory, CookieSpecProvid
         }
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
-        return new BestMatchSpec(this.datepatterns, this.oneHeader);
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpec.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatSpec.java
similarity index 72%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpec.java
rename to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatSpec.java
index ce5e283..7b20123 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpec.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatSpec.java
@@ -28,15 +28,18 @@
 package org.apache.http.impl.cookie;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 
 import org.apache.http.FormattedHeader;
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.NameValuePair;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.client.utils.DateUtils;
-import org.apache.http.cookie.ClientCookie;
 import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SM;
@@ -53,10 +56,11 @@ import org.apache.http.util.CharArrayBuffer;
  * common web browser applications such as Microsoft Internet Explorer
  * and Mozilla FireFox.
  *
+ * @deprecated (4.4) use {@link org.apache.http.impl.cookie.DefaultCookieSpec}.
  *
  * @since 4.0
  */
- at NotThreadSafe // superclass is @NotThreadSafe
+ at ThreadSafe
 public class BrowserCompatSpec extends CookieSpecBase {
 
 
@@ -77,40 +81,21 @@ public class BrowserCompatSpec extends CookieSpecBase {
         "EEE, dd-MM-yyyy HH:mm:ss z",
     };
 
-    private final String[] datepatterns;
-
     /** Default constructor */
     public BrowserCompatSpec(final String[] datepatterns, final BrowserCompatSpecFactory.SecurityLevel securityLevel) {
-        super();
-        if (datepatterns != null) {
-            this.datepatterns = datepatterns.clone();
-        } else {
-            this.datepatterns = DEFAULT_DATE_PATTERNS;
-        }
-        switch (securityLevel) {
-            case SECURITYLEVEL_DEFAULT:
-                registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
-                break;
-            case SECURITYLEVEL_IE_MEDIUM:
-                registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler() {
-                        @Override
-                        public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
-                            // No validation
-                        }
-                    }
-                );
-                break;
-            default:
-                throw new RuntimeException("Unknown security level");
-        }
-
-        registerAttribHandler(ClientCookie.DOMAIN_ATTR, new BasicDomainHandler());
-        registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
-        registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
-        registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
-        registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
-                this.datepatterns));
-        registerAttribHandler(ClientCookie.VERSION_ATTR, new BrowserCompatVersionAttributeHandler());
+        super(new BrowserCompatVersionAttributeHandler(),
+                new BasicDomainHandler(),
+                securityLevel == BrowserCompatSpecFactory.SecurityLevel.SECURITYLEVEL_IE_MEDIUM ?
+                        new BasicPathHandler() {
+                            @Override
+                            public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
+                                // No validation
+                            }
+                        } : new BasicPathHandler(),
+                new BasicMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new BasicCommentHandler(),
+                new BasicExpiresHandler(datepatterns != null ? datepatterns.clone() : DEFAULT_DATE_PATTERNS));
     }
 
     /** Default constructor */
@@ -123,6 +108,7 @@ public class BrowserCompatSpec extends CookieSpecBase {
         this(null, BrowserCompatSpecFactory.SecurityLevel.SECURITYLEVEL_DEFAULT);
     }
 
+    @Override
     public List<Cookie> parse(final Header header, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(header, "Header");
@@ -132,7 +118,7 @@ public class BrowserCompatSpec extends CookieSpecBase {
             throw new MalformedCookieException("Unrecognized cookie header '"
                     + header.toString() + "'");
         }
-        HeaderElement[] helems = header.getElements();
+        final HeaderElement[] helems = header.getElements();
         boolean versioned = false;
         boolean netscape = false;
         for (final HeaderElement helem: helems) {
@@ -163,15 +149,42 @@ public class BrowserCompatSpec extends CookieSpecBase {
                 buffer.append(s);
                 cursor = new ParserCursor(0, buffer.length());
             }
-            helems = new HeaderElement[] { parser.parseHeader(buffer, cursor) };
+            final HeaderElement elem = parser.parseHeader(buffer, cursor);
+            final String name = elem.getName();
+            final String value = elem.getValue();
+            if (name == null || name.isEmpty()) {
+                throw new MalformedCookieException("Cookie name may not be empty");
+            }
+            final BasicClientCookie cookie = new BasicClientCookie(name, value);
+            cookie.setPath(getDefaultPath(origin));
+            cookie.setDomain(getDefaultDomain(origin));
+
+            // cycle through the parameters
+            final NameValuePair[] attribs = elem.getParameters();
+            for (int j = attribs.length - 1; j >= 0; j--) {
+                final NameValuePair attrib = attribs[j];
+                final String s = attrib.getName().toLowerCase(Locale.ROOT);
+                cookie.setAttribute(s, attrib.getValue());
+                final CookieAttributeHandler handler = findAttribHandler(s);
+                if (handler != null) {
+                    handler.parse(cookie, attrib.getValue());
+                }
+            }
+            // Override version for Netscape style cookies
+            if (netscape) {
+                cookie.setVersion(0);
+            }
+            return Collections.<Cookie>singletonList(cookie);
+        } else {
+            return parse(helems, origin);
         }
-        return parse(helems, origin);
     }
 
     private static boolean isQuoteEnclosed(final String s) {
         return s != null && s.startsWith("\"") && s.endsWith("\"");
     }
 
+    @Override
     public List<Header> formatCookies(final List<Cookie> cookies) {
         Args.notEmpty(cookies, "List of cookies");
         final CharArrayBuffer buffer = new CharArrayBuffer(20 * cookies.size());
@@ -203,10 +216,12 @@ public class BrowserCompatSpec extends CookieSpecBase {
         return headers;
     }
 
+    @Override
     public int getVersion() {
         return 0;
     }
 
+    @Override
     public Header getVersionHeader() {
         return null;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java
similarity index 84%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java
rename to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java
index f0d771b..a89908f 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatSpecFactory.java
@@ -38,13 +38,16 @@ import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that creates and initializes
- * {@link BrowserCompatSpec} instances.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link org.apache.http.impl.cookie.BrowserCompatSpec}. The instance returned by this factory
+ * can be shared by multiple threads.
+ *
+ * @deprecated (4.4) use {@link org.apache.http.impl.cookie.DefaultCookieSpecProvider}.
  *
  * @since 4.0
  */
 @Immutable
- at SuppressWarnings("deprecation")
+ at Deprecated
 public class BrowserCompatSpecFactory implements CookieSpecFactory, CookieSpecProvider {
 
     public enum SecurityLevel {
@@ -52,13 +55,13 @@ public class BrowserCompatSpecFactory implements CookieSpecFactory, CookieSpecPr
         SECURITYLEVEL_IE_MEDIUM
     }
 
-    private final String[] datepatterns;
     private final SecurityLevel securityLevel;
+    private final CookieSpec cookieSpec;
 
     public BrowserCompatSpecFactory(final String[] datepatterns, final SecurityLevel securityLevel) {
         super();
-        this.datepatterns = datepatterns;
         this.securityLevel = securityLevel;
+        this.cookieSpec = new BrowserCompatSpec(datepatterns, securityLevel);
     }
 
     public BrowserCompatSpecFactory(final String[] datepatterns) {
@@ -69,6 +72,7 @@ public class BrowserCompatSpecFactory implements CookieSpecFactory, CookieSpecPr
         this(null, SecurityLevel.SECURITYLEVEL_DEFAULT);
     }
 
+    @Override
     public CookieSpec newInstance(final HttpParams params) {
         if (params != null) {
 
@@ -85,8 +89,9 @@ public class BrowserCompatSpecFactory implements CookieSpecFactory, CookieSpecPr
         }
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
-        return new BrowserCompatSpec(this.datepatterns);
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java
similarity index 83%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java
copy to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java
index 633a535..c4c389f 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java
@@ -28,18 +28,22 @@
 package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
 
 /**
- * <tt>"Version"</tt> cookie attribute handler for BrowserCompat cookie spec.
+ * {@code "Version"} cookie attribute handler for BrowserCompat cookie spec.
+ *
+ *  @deprecated (4.4) no longer used.
  *
  * @since 4.3
  */
 @Immutable
 public class BrowserCompatVersionAttributeHandler extends
-        AbstractCookieAttributeHandler {
+        AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
     public BrowserCompatVersionAttributeHandler() {
         super();
@@ -48,6 +52,7 @@ public class BrowserCompatVersionAttributeHandler extends
     /**
      * Parse cookie version attribute.
      */
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -63,4 +68,9 @@ public class BrowserCompatVersionAttributeHandler extends
         cookie.setVersion(version);
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.VERSION_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/DateUtils.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/DateUtils.java
index ad64ec1..57e0bd1 100644
--- a/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/DateUtils.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/DateUtils.java
@@ -58,7 +58,7 @@ public final class DateUtils {
 
     /**
      * Date format pattern used to parse HTTP date headers in ANSI C
-     * <code>asctime()</code> format.
+     * {@code asctime()} format.
      */
     public static final String PATTERN_ASCTIME = org.apache.http.client.utils.DateUtils.PATTERN_ASCTIME;
 
@@ -100,9 +100,9 @@ public final class DateUtils {
      * @param dateValue the date value to parse
      * @param dateFormats the date formats to use
      * @param startDate During parsing, two digit years will be placed in the range
-     * <code>startDate</code> to <code>startDate + 100 years</code>. This value may
-     * be <code>null</code>. When <code>null</code> is given as a parameter, year
-     * <code>2000</code> will be used.
+     * {@code startDate} to {@code startDate + 100 years}. This value may
+     * be {@code null}. When {@code null} is given as a parameter, year
+     * {@code 2000} will be used.
      *
      * @return the parsed date
      *
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/IgnoreSpecFactory.java
similarity index 94%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecFactory.java
copy to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/IgnoreSpecFactory.java
index 51c7951..91052c1 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/IgnoreSpecFactory.java
@@ -37,20 +37,24 @@ import org.apache.http.protocol.HttpContext;
 /**
  * {@link CookieSpecProvider} implementation that ignores all cookies.
  *
+ * @deprecated (4.4) Use {@link org.apache.http.impl.cookie.IgnoreSpecProvider}.
+ *
  * @since 4.1
  */
 @Immutable
- at SuppressWarnings("deprecation")
+ at Deprecated
 public class IgnoreSpecFactory implements CookieSpecFactory, CookieSpecProvider {
 
     public IgnoreSpecFactory() {
         super();
     }
 
+    @Override
     public CookieSpec newInstance(final HttpParams params) {
         return new IgnoreSpec();
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
         return new IgnoreSpec();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
similarity index 83%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
copy to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
index 0d91d7e..e5e72d8 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
@@ -38,26 +38,30 @@ import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that creates and initializes
- * {@link NetscapeDraftSpec} instances.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link org.apache.http.impl.cookie.NetscapeDraftSpec}. The instance returned by this factory
+ * can be shared by multiple threads.
+ *
+ * @deprecated (4.4) Use {@link org.apache.http.impl.cookie.NetscapeDraftSpecProvider}.
  *
  * @since 4.0
  */
 @Immutable
- at SuppressWarnings("deprecation")
+ at Deprecated
 public class NetscapeDraftSpecFactory implements CookieSpecFactory, CookieSpecProvider {
 
-    private final String[] datepatterns;
+    private final CookieSpec cookieSpec;
 
     public NetscapeDraftSpecFactory(final String[] datepatterns) {
         super();
-        this.datepatterns = datepatterns;
+        this.cookieSpec = new NetscapeDraftSpec(datepatterns);
     }
 
     public NetscapeDraftSpecFactory() {
         this(null);
     }
 
+    @Override
     public CookieSpec newInstance(final HttpParams params) {
         if (params != null) {
 
@@ -74,8 +78,9 @@ public class NetscapeDraftSpecFactory implements CookieSpecFactory, CookieSpecPr
         }
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
-        return new NetscapeDraftSpec(this.datepatterns);
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixFilter.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/PublicSuffixFilter.java
similarity index 72%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixFilter.java
rename to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/PublicSuffixFilter.java
index 1b8cb50..c1b9323 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixFilter.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/PublicSuffixFilter.java
@@ -27,10 +27,8 @@
 package org.apache.http.impl.cookie;
 
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
 
-import org.apache.http.client.utils.Punycode;
+import org.apache.http.conn.util.PublicSuffixMatcher;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
@@ -45,12 +43,16 @@ import org.apache.http.cookie.SetCookie;
  * An uptodate list of suffixes can be obtained from
  * <a href="http://publicsuffix.org/">publicsuffix.org</a>
  *
+ * @deprecated (4.4) use {@link org.apache.http.impl.cookie.PublicSuffixDomainFilter}
+ *
  * @since 4.0
  */
+ at Deprecated
 public class PublicSuffixFilter implements CookieAttributeHandler {
     private final CookieAttributeHandler wrapped;
-    private Set<String> exceptions;
-    private Set<String> suffixes;
+    private Collection<String> exceptions;
+    private Collection<String> suffixes;
+    private PublicSuffixMatcher matcher;
 
     public PublicSuffixFilter(final CookieAttributeHandler wrapped) {
         this.wrapped = wrapped;
@@ -63,7 +65,8 @@ public class PublicSuffixFilter implements CookieAttributeHandler {
      * @param suffixes
      */
     public void setPublicSuffixes(final Collection<String> suffixes) {
-        this.suffixes = new HashSet<String>(suffixes);
+        this.suffixes = suffixes;
+        this.matcher = null;
     }
 
     /**
@@ -72,12 +75,14 @@ public class PublicSuffixFilter implements CookieAttributeHandler {
      * @param exceptions
      */
     public void setExceptions(final Collection<String> exceptions) {
-        this.exceptions = new HashSet<String>(exceptions);
+        this.exceptions = exceptions;
+        this.matcher = null;
     }
 
     /**
      * Never matches if the cookie's domain is from the blacklist.
      */
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         if (isForPublicSuffix(cookie)) {
             return false;
@@ -85,48 +90,20 @@ public class PublicSuffixFilter implements CookieAttributeHandler {
         return wrapped.match(cookie, origin);
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
         wrapped.parse(cookie, value);
     }
 
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
         wrapped.validate(cookie, origin);
     }
 
     private boolean isForPublicSuffix(final Cookie cookie) {
-        String domain = cookie.getDomain();
-        if (domain.startsWith(".")) {
-            domain = domain.substring(1);
-        }
-        domain = Punycode.toUnicode(domain);
-
-        // An exception rule takes priority over any other matching rule.
-        if (this.exceptions != null) {
-            if (this.exceptions.contains(domain)) {
-                return false;
-            }
+        if (matcher == null) {
+            matcher = new PublicSuffixMatcher(this.suffixes, this.exceptions);
         }
-
-
-        if (this.suffixes == null) {
-            return false;
-        }
-
-        do {
-            if (this.suffixes.contains(domain)) {
-                return true;
-            }
-            // patterns
-            if (domain.startsWith("*.")) {
-                domain = domain.substring(2);
-            }
-            final int nextdot = domain.indexOf('.');
-            if (nextdot == -1) {
-                break;
-            }
-            domain = "*" + domain.substring(nextdot);
-        } while (domain.length() > 0);
-
-        return false;
+        return matcher.matches(cookie.getDomain());
     }
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/PublicSuffixListParser.java
similarity index 51%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java
rename to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/PublicSuffixListParser.java
index 633a535..210956c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BrowserCompatVersionAttributeHandler.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/PublicSuffixListParser.java
@@ -24,43 +24,46 @@
  * <http://www.apache.org/>.
  *
  */
-
 package org.apache.http.impl.cookie;
 
+import java.io.IOException;
+import java.io.Reader;
+
 import org.apache.http.annotation.Immutable;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.cookie.SetCookie;
-import org.apache.http.util.Args;
+import org.apache.http.conn.util.PublicSuffixList;
 
 /**
- * <tt>"Version"</tt> cookie attribute handler for BrowserCompat cookie spec.
+ * Parses the list from <a href="http://publicsuffix.org/">publicsuffix.org</a>
+ * and configures a PublicSuffixFilter.
  *
- * @since 4.3
+ * @deprecated (4.4) use {@link org.apache.http.conn.util.PublicSuffixListParser}.
+ *
+ * @since 4.0
  */
 @Immutable
-public class BrowserCompatVersionAttributeHandler extends
-        AbstractCookieAttributeHandler {
+ at Deprecated
+public class PublicSuffixListParser {
+
+    private final PublicSuffixFilter filter;
+    private final org.apache.http.conn.util.PublicSuffixListParser parser;
 
-    public BrowserCompatVersionAttributeHandler() {
-        super();
+    PublicSuffixListParser(final PublicSuffixFilter filter) {
+        this.filter = filter;
+        this.parser = new org.apache.http.conn.util.PublicSuffixListParser();
     }
 
     /**
-     * Parse cookie version attribute.
+     * Parses the public suffix list format.
+     * When creating the reader from the file, make sure to
+     * use the correct encoding (the original list is in UTF-8).
+     *
+     * @param reader the suffix list. The caller is responsible for closing the reader.
+     * @throws IOException on error while reading from list
      */
-    public void parse(final SetCookie cookie, final String value)
-            throws MalformedCookieException {
-        Args.notNull(cookie, "Cookie");
-        if (value == null) {
-            throw new MalformedCookieException("Missing value for version attribute");
-        }
-        int version = 0;
-        try {
-            version = Integer.parseInt(value);
-        } catch (final NumberFormatException e) {
-            // Just ignore invalid versions
-        }
-        cookie.setVersion(version);
+    public void parse(final Reader reader) throws IOException {
+        final PublicSuffixList suffixList = parser.parse(reader);
+        filter.setPublicSuffixes(suffixList.getRules());
+        filter.setExceptions(suffixList.getExceptions());
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109SpecFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/RFC2109SpecFactory.java
similarity index 84%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109SpecFactory.java
rename to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/RFC2109SpecFactory.java
index bb5ef68..278e240 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109SpecFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/RFC2109SpecFactory.java
@@ -38,28 +38,30 @@ import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that creates and initializes
- * {@link RFC2109Spec} instances.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link org.apache.http.impl.cookie.RFC2109Spec}. The instance returned by this factory
+ * can be shared by multiple threads.
+ *
+ * @deprecated (4.4) Use {@link org.apache.http.impl.cookie.RFC2109SpecProvider}.
  *
  * @since 4.0
  */
 @Immutable
- at SuppressWarnings("deprecation")
+ at Deprecated
 public class RFC2109SpecFactory implements CookieSpecFactory, CookieSpecProvider {
 
-    private final String[] datepatterns;
-    private final boolean oneHeader;
+    private final CookieSpec cookieSpec;
 
     public RFC2109SpecFactory(final String[] datepatterns, final boolean oneHeader) {
         super();
-        this.datepatterns = datepatterns;
-        this.oneHeader = oneHeader;
+        this.cookieSpec = new RFC2109Spec(datepatterns, oneHeader);
     }
 
     public RFC2109SpecFactory() {
         this(null, false);
     }
 
+    @Override
     public CookieSpec newInstance(final HttpParams params) {
         if (params != null) {
 
@@ -79,8 +81,9 @@ public class RFC2109SpecFactory implements CookieSpecFactory, CookieSpecProvider
         }
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
-        return new RFC2109Spec(this.datepatterns, this.oneHeader);
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/RFC2965SpecFactory.java
similarity index 84%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java
copy to httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/RFC2965SpecFactory.java
index 70e42d9..95ba801 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java
+++ b/httpclient/src/main/java-deprecated/org/apache/http/impl/cookie/RFC2965SpecFactory.java
@@ -38,28 +38,30 @@ import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that creates and initializes
- * {@link RFC2965Spec} instances.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link org.apache.http.impl.cookie.RFC2965Spec}. The instance returned by this factory can
+ * be shared by multiple threads.
+ *
+ * @deprecated (4.4) Use {@link org.apache.http.impl.cookie.RFC2965SpecProvider}.
  *
  * @since 4.0
  */
 @Immutable
- at SuppressWarnings("deprecation")
+ at Deprecated
 public class RFC2965SpecFactory implements CookieSpecFactory, CookieSpecProvider {
 
-    private final String[] datepatterns;
-    private final boolean oneHeader;
+    private final CookieSpec cookieSpec;
 
     public RFC2965SpecFactory(final String[] datepatterns, final boolean oneHeader) {
         super();
-        this.datepatterns = datepatterns;
-        this.oneHeader = oneHeader;
+        this.cookieSpec = new RFC2965Spec(datepatterns, oneHeader);
     }
 
     public RFC2965SpecFactory() {
         this(null, false);
     }
 
+    @Override
     public CookieSpec newInstance(final HttpParams params) {
         if (params != null) {
 
@@ -79,8 +81,9 @@ public class RFC2965SpecFactory implements CookieSpecFactory, CookieSpecProvider
         }
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
-        return new RFC2965Spec(this.datepatterns, this.oneHeader);
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java b/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java
index e9d4ae2..49bd65f 100644
--- a/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java
+++ b/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java
@@ -85,7 +85,7 @@ public interface AuthScheme {
     /**
      * Returns authentication realm. If the concept of an authentication
      * realm is not applicable to the given authentication scheme, returns
-     * <code>null</code>.
+     * {@code null}.
      *
      * @return the authentication realm
      */
@@ -95,7 +95,7 @@ public interface AuthScheme {
      * Tests if the authentication scheme is provides authorization on a per
      * connection basis instead of usual per request basis
      *
-     * @return <tt>true</tt> if the scheme is connection based, <tt>false</tt>
+     * @return {@code true} if the scheme is connection based, {@code false}
      * if the scheme is request based.
      */
     boolean isConnectionBased();
@@ -106,8 +106,8 @@ public interface AuthScheme {
      * successfully or unsuccessfully, that is, all the required authorization
      * challenges have been processed in their entirety.
      *
-     * @return <tt>true</tt> if the authentication process has been completed,
-     * <tt>false</tt> otherwise.
+     * @return {@code true} if the authentication process has been completed,
+     * {@code false} otherwise.
      */
     boolean isComplete();
 
diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthSchemeRegistry.java b/httpclient/src/main/java/org/apache/http/auth/AuthSchemeRegistry.java
index 74e3665..d3dcddc 100644
--- a/httpclient/src/main/java/org/apache/http/auth/AuthSchemeRegistry.java
+++ b/httpclient/src/main/java/org/apache/http/auth/AuthSchemeRegistry.java
@@ -140,9 +140,11 @@ public final class AuthSchemeRegistry implements Lookup<AuthSchemeProvider> {
         registeredSchemes.putAll(map);
     }
 
+    @Override
     public AuthSchemeProvider lookup(final String name) {
         return new AuthSchemeProvider() {
 
+            @Override
             public AuthScheme create(final HttpContext context) {
                 final HttpRequest request = (HttpRequest) context.getAttribute(
                         ExecutionContext.HTTP_REQUEST);
diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthScope.java b/httpclient/src/main/java/org/apache/http/auth/AuthScope.java
index 1a0fd84..5488540 100644
--- a/httpclient/src/main/java/org/apache/http/auth/AuthScope.java
+++ b/httpclient/src/main/java/org/apache/http/auth/AuthScope.java
@@ -34,34 +34,35 @@ import org.apache.http.util.Args;
 import org.apache.http.util.LangUtils;
 
 /**
- * The class represents an authentication scope consisting of a host name,
- * a port number, a realm name and an authentication scheme name which
- * {@link Credentials Credentials} apply to.
- *
- *
+ * {@code AuthScope} represents an authentication scope consisting of a host name,
+ * a port number, a realm name and an authentication scheme name.
+ * <p>
+ * This class can also optionally contain a host of origin, if created in response
+ * to authentication challenge from a specific host.
+ * </p>
  * @since 4.0
  */
 @Immutable
 public class AuthScope {
 
     /**
-     * The <tt>null</tt> value represents any host. In the future versions of
+     * The {@code null} value represents any host. In the future versions of
      * HttpClient the use of this parameter will be discontinued.
      */
     public static final String ANY_HOST = null;
 
     /**
-     * The <tt>-1</tt> value represents any port.
+     * The {@code -1} value represents any port.
      */
     public static final int ANY_PORT = -1;
 
     /**
-     * The <tt>null</tt> value represents any realm.
+     * The {@code null} value represents any realm.
      */
     public static final String ANY_REALM = null;
 
     /**
-     * The <tt>null</tt> value represents any authentication scheme.
+     * The {@code null} value represents any authentication scheme.
      */
     public static final String ANY_SCHEME = null;
 
@@ -84,74 +85,89 @@ public class AuthScope {
     /** The port the credentials apply to. */
     private final int port;
 
-    /** Creates a new credentials scope for the given
-     * <tt>host</tt>, <tt>port</tt>, <tt>realm</tt>, and
-     * <tt>authentication scheme</tt>.
+    /** The original host, if known */
+    private final HttpHost origin;
+
+    /**
+     * Defines auth scope with the given {@code host}, {@code port}, {@code realm}, and
+     * {@code schemeName}.
      *
-     * @param host the host the credentials apply to. May be set
-     *   to <tt>null</tt> if credentials are applicable to
-     *   any host.
-     * @param port the port the credentials apply to. May be set
-     *   to negative value if credentials are applicable to
-     *   any port.
-     * @param realm the realm the credentials apply to. May be set
-     *   to <tt>null</tt> if credentials are applicable to
-     *   any realm.
-     * @param scheme the authentication scheme the credentials apply to.
-     *   May be set to <tt>null</tt> if credentials are applicable to
-     *   any authentication scheme.
+     * @param host authentication host. May be {@link #ANY_HOST} if applies
+     *   to any host.
+     * @param port authentication port. May be {@link #ANY_PORT} if applies
+     *   to any port of the host.
+     * @param realm authentication realm. May be {@link #ANY_REALM} if applies
+     *   to any realm on the host.
+     * @param schemeName authentication scheme. May be {@link #ANY_SCHEME} if applies
+     *   to any scheme supported by the host.
      */
-    public AuthScope(final String host, final int port,
-        final String realm, final String scheme)
-    {
-        this.host =   (host == null)   ? ANY_HOST: host.toLowerCase(Locale.ENGLISH);
-        this.port =   (port < 0)       ? ANY_PORT: port;
-        this.realm =  (realm == null)  ? ANY_REALM: realm;
-        this.scheme = (scheme == null) ? ANY_SCHEME: scheme.toUpperCase(Locale.ENGLISH);
+    public AuthScope(
+            final String host,
+            final int port,
+            final String realm,
+            final String schemeName) {
+        this.host = host == null ? ANY_HOST: host.toLowerCase(Locale.ROOT);
+        this.port = port < 0 ? ANY_PORT : port;
+        this.realm = realm == null ? ANY_REALM : realm;
+        this.scheme = schemeName == null ? ANY_SCHEME : schemeName.toUpperCase(Locale.ROOT);
+        this.origin = null;
     }
 
     /**
+     * Defines auth scope for a specific host of origin.
+     *
+     * @param origin host of origin
+     * @param realm authentication realm. May be {@link #ANY_REALM} if applies
+     *   to any realm on the host.
+     * @param schemeName authentication scheme. May be {@link #ANY_SCHEME} if applies
+     *   to any scheme supported by the host.
+     *
      * @since 4.2
      */
-    public AuthScope(final HttpHost host, final String realm, final String schemeName) {
-        this(host.getHostName(), host.getPort(), realm, schemeName);
+    public AuthScope(
+            final HttpHost origin,
+            final String realm,
+            final String schemeName) {
+        Args.notNull(origin, "Host");
+        this.host = origin.getHostName().toLowerCase(Locale.ROOT);
+        this.port = origin.getPort() < 0 ? ANY_PORT : origin.getPort();
+        this.realm = realm == null ? ANY_REALM : realm;
+        this.scheme = schemeName == null ? ANY_SCHEME : schemeName.toUpperCase(Locale.ROOT);
+        this.origin = origin;
     }
 
     /**
+     * Defines auth scope for a specific host of origin.
+     *
+     * @param origin host of origin
+     *
      * @since 4.2
      */
-    public AuthScope(final HttpHost host) {
-        this(host, ANY_REALM, ANY_SCHEME);
+    public AuthScope(final HttpHost origin) {
+        this(origin, ANY_REALM, ANY_SCHEME);
     }
 
-    /** Creates a new credentials scope for the given
-     * <tt>host</tt>, <tt>port</tt>, <tt>realm</tt>, and any
-     * authentication scheme.
+    /**
+     * Defines auth scope with the given {@code host}, {@code port} and {@code realm}.
      *
-     * @param host the host the credentials apply to. May be set
-     *   to <tt>null</tt> if credentials are applicable to
-     *   any host.
-     * @param port the port the credentials apply to. May be set
-     *   to negative value if credentials are applicable to
-     *   any port.
-     * @param realm the realm the credentials apply to. May be set
-     *   to <tt>null</tt> if credentials are applicable to
-     *   any realm.
+     * @param host authentication host. May be {@link #ANY_HOST} if applies
+     *   to any host.
+     * @param port authentication port. May be {@link #ANY_PORT} if applies
+     *   to any port of the host.
+     * @param realm authentication realm. May be {@link #ANY_REALM} if applies
+     *   to any realm on the host.
      */
     public AuthScope(final String host, final int port, final String realm) {
         this(host, port, realm, ANY_SCHEME);
     }
 
-    /** Creates a new credentials scope for the given
-     * <tt>host</tt>, <tt>port</tt>, any realm name, and any
-     * authentication scheme.
+    /**
+     * Defines auth scope with the given {@code host} and {@code port}.
      *
-     * @param host the host the credentials apply to. May be set
-     *   to <tt>null</tt> if credentials are applicable to
-     *   any host.
-     * @param port the port the credentials apply to. May be set
-     *   to negative value if credentials are applicable to
-     *   any port.
+     * @param host authentication host. May be {@link #ANY_HOST} if applies
+     *   to any host.
+     * @param port authentication port. May be {@link #ANY_PORT} if applies
+     *   to any port of the host.
      */
     public AuthScope(final String host, final int port) {
         this(host, port, ANY_REALM, ANY_SCHEME);
@@ -167,6 +183,16 @@ public class AuthScope {
         this.port = authscope.getPort();
         this.realm = authscope.getRealm();
         this.scheme = authscope.getScheme();
+        this.origin = authscope.getOrigin();
+    }
+
+    /**
+     * @return host of origin. If unknown returns @null,
+     *
+     * @since 4.4
+     */
+    public HttpHost getOrigin() {
+        return this.origin;
     }
 
     /**
@@ -266,7 +292,7 @@ public class AuthScope {
     public String toString() {
         final StringBuilder buffer = new StringBuilder();
         if (this.scheme != null) {
-            buffer.append(this.scheme.toUpperCase(Locale.ENGLISH));
+            buffer.append(this.scheme.toUpperCase(Locale.ROOT));
             buffer.append(' ');
         }
         if (this.realm != null) {
diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthState.java b/httpclient/src/main/java/org/apache/http/auth/AuthState.java
index 28bf7ba..9b932e7 100644
--- a/httpclient/src/main/java/org/apache/http/auth/AuthState.java
+++ b/httpclient/src/main/java/org/apache/http/auth/AuthState.java
@@ -126,7 +126,7 @@ public class AuthState {
     }
 
     /**
-     * Returns <code>true</code> if {@link AuthOption}s are available, <code>false</code>
+     * Returns {@code true} if {@link AuthOption}s are available, {@code false}
      * otherwise.
      *
      * @since 4.2
@@ -198,7 +198,7 @@ public class AuthState {
     /**
      * Returns actual {@link AuthScope} if available
      *
-     * @return actual authentication scope if available, <code>null</code otherwise
+     * @return actual authentication scope if available, {@code null} otherwise
      *
      * @deprecated (4.2)  do not use.
      */
diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthenticationException.java b/httpclient/src/main/java/org/apache/http/auth/AuthenticationException.java
index cd59d9e..8d8e34c 100644
--- a/httpclient/src/main/java/org/apache/http/auth/AuthenticationException.java
+++ b/httpclient/src/main/java/org/apache/http/auth/AuthenticationException.java
@@ -41,7 +41,7 @@ public class AuthenticationException extends ProtocolException {
     private static final long serialVersionUID = -6794031905674764776L;
 
     /**
-     * Creates a new AuthenticationException with a <tt>null</tt> detail message.
+     * Creates a new AuthenticationException with a {@code null} detail message.
      */
     public AuthenticationException() {
         super();
@@ -60,8 +60,8 @@ public class AuthenticationException extends ProtocolException {
      * Creates a new AuthenticationException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public AuthenticationException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/auth/BasicUserPrincipal.java b/httpclient/src/main/java/org/apache/http/auth/BasicUserPrincipal.java
index 4659b0b..92bf4e6 100644
--- a/httpclient/src/main/java/org/apache/http/auth/BasicUserPrincipal.java
+++ b/httpclient/src/main/java/org/apache/http/auth/BasicUserPrincipal.java
@@ -51,6 +51,7 @@ public final class BasicUserPrincipal implements Principal, Serializable {
         this.username = username;
     }
 
+    @Override
     public String getName() {
         return this.username;
     }
diff --git a/httpclient/src/main/java/org/apache/http/auth/InvalidCredentialsException.java b/httpclient/src/main/java/org/apache/http/auth/InvalidCredentialsException.java
index a110a18..e357241 100644
--- a/httpclient/src/main/java/org/apache/http/auth/InvalidCredentialsException.java
+++ b/httpclient/src/main/java/org/apache/http/auth/InvalidCredentialsException.java
@@ -41,7 +41,7 @@ public class InvalidCredentialsException extends AuthenticationException {
     private static final long serialVersionUID = -4834003835215460648L;
 
     /**
-     * Creates a new InvalidCredentialsException with a <tt>null</tt> detail message.
+     * Creates a new InvalidCredentialsException with a {@code null} detail message.
      */
     public InvalidCredentialsException() {
         super();
@@ -60,8 +60,8 @@ public class InvalidCredentialsException extends AuthenticationException {
      * Creates a new InvalidCredentialsException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public InvalidCredentialsException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieRestrictionViolationException.java b/httpclient/src/main/java/org/apache/http/auth/KerberosCredentials.java
similarity index 60%
copy from httpclient/src/main/java/org/apache/http/cookie/CookieRestrictionViolationException.java
copy to httpclient/src/main/java/org/apache/http/auth/KerberosCredentials.java
index ab9b346..05cb433 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieRestrictionViolationException.java
+++ b/httpclient/src/main/java/org/apache/http/auth/KerberosCredentials.java
@@ -24,38 +24,46 @@
  * <http://www.apache.org/>.
  *
  */
+package org.apache.http.auth;
 
-package org.apache.http.cookie;
+import java.io.Serializable;
+import java.security.Principal;
 
 import org.apache.http.annotation.Immutable;
+import org.ietf.jgss.GSSCredential;
 
 /**
- * Signals that a cookie violates a restriction imposed by the cookie
- * specification.
+ * {@link Credentials} implementation based on GSSCredential for Kerberos Authentication.
  *
- * @since 4.1
+ * @since 4.4
  */
 @Immutable
-public class CookieRestrictionViolationException extends MalformedCookieException {
+public class KerberosCredentials implements Credentials, Serializable {
 
-    private static final long serialVersionUID = 7371235577078589013L;
+    private static final long serialVersionUID = 487421613855550713L;
 
-    /**
-     * Creates a new CookeFormatViolationException with a <tt>null</tt> detail
-     * message.
-     */
-    public CookieRestrictionViolationException() {
-        super();
-    }
+    /** GSSCredential  */
+    private final GSSCredential gssCredential;
 
     /**
-     * Creates a new CookeRestrictionViolationException with a specified
-     * message string.
+     * Constructor with GSSCredential argument
      *
-     * @param message The exception detail message
+     * @param gssCredential
      */
-    public CookieRestrictionViolationException(final String message) {
-        super(message);
+    public KerberosCredentials(final GSSCredential gssCredential) {
+        this.gssCredential = gssCredential;
+    }
+
+    public GSSCredential getGSSCredential() {
+        return gssCredential;
+    }
+
+    public Principal getUserPrincipal() {
+        return null;
+    }
+
+    public String getPassword() {
+        return null;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/auth/MalformedChallengeException.java b/httpclient/src/main/java/org/apache/http/auth/MalformedChallengeException.java
index 1fa5383..172ba0c 100644
--- a/httpclient/src/main/java/org/apache/http/auth/MalformedChallengeException.java
+++ b/httpclient/src/main/java/org/apache/http/auth/MalformedChallengeException.java
@@ -42,7 +42,7 @@ public class MalformedChallengeException extends ProtocolException {
     private static final long serialVersionUID = 814586927989932284L;
 
     /**
-     * Creates a new MalformedChallengeException with a <tt>null</tt> detail message.
+     * Creates a new MalformedChallengeException with a {@code null} detail message.
      */
     public MalformedChallengeException() {
         super();
@@ -61,8 +61,8 @@ public class MalformedChallengeException extends ProtocolException {
      * Creates a new MalformedChallengeException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public MalformedChallengeException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/auth/NTCredentials.java b/httpclient/src/main/java/org/apache/http/auth/NTCredentials.java
index fabb9c5..b0a0c4e 100644
--- a/httpclient/src/main/java/org/apache/http/auth/NTCredentials.java
+++ b/httpclient/src/main/java/org/apache/http/auth/NTCredentials.java
@@ -75,7 +75,7 @@ public class NTCredentials implements Credentials, Serializable {
         final int atSlash = username.indexOf('/');
         if (atSlash >= 0) {
             this.principal = new NTUserPrincipal(
-                    username.substring(0, atSlash).toUpperCase(Locale.ENGLISH),
+                    username.substring(0, atSlash).toUpperCase(Locale.ROOT),
                     username.substring(atSlash + 1));
         } else {
             this.principal = new NTUserPrincipal(
@@ -104,12 +104,13 @@ public class NTCredentials implements Credentials, Serializable {
         this.principal = new NTUserPrincipal(domain, userName);
         this.password = password;
         if (workstation != null) {
-            this.workstation = workstation.toUpperCase(Locale.ENGLISH);
+            this.workstation = workstation.toUpperCase(Locale.ROOT);
         } else {
             this.workstation = null;
         }
     }
 
+    @Override
     public Principal getUserPrincipal() {
         return this.principal;
     }
@@ -118,6 +119,7 @@ public class NTCredentials implements Credentials, Serializable {
         return this.principal.getUsername();
     }
 
+    @Override
     public String getPassword() {
         return this.password;
     }
diff --git a/httpclient/src/main/java/org/apache/http/auth/NTUserPrincipal.java b/httpclient/src/main/java/org/apache/http/auth/NTUserPrincipal.java
index 642a686..8299939 100644
--- a/httpclient/src/main/java/org/apache/http/auth/NTUserPrincipal.java
+++ b/httpclient/src/main/java/org/apache/http/auth/NTUserPrincipal.java
@@ -55,11 +55,11 @@ public class NTUserPrincipal implements Principal, Serializable {
         Args.notNull(username, "User name");
         this.username = username;
         if (domain != null) {
-            this.domain = domain.toUpperCase(Locale.ENGLISH);
+            this.domain = domain.toUpperCase(Locale.ROOT);
         } else {
             this.domain = null;
         }
-        if (this.domain != null && this.domain.length() > 0) {
+        if (this.domain != null && !this.domain.isEmpty()) {
             final StringBuilder buffer = new StringBuilder();
             buffer.append(this.domain);
             buffer.append('\\');
@@ -70,6 +70,7 @@ public class NTUserPrincipal implements Principal, Serializable {
         }
     }
 
+    @Override
     public String getName() {
         return this.ntname;
     }
diff --git a/httpclient/src/main/java/org/apache/http/auth/UsernamePasswordCredentials.java b/httpclient/src/main/java/org/apache/http/auth/UsernamePasswordCredentials.java
index 8e500a0..e2f45c0 100644
--- a/httpclient/src/main/java/org/apache/http/auth/UsernamePasswordCredentials.java
+++ b/httpclient/src/main/java/org/apache/http/auth/UsernamePasswordCredentials.java
@@ -80,6 +80,7 @@ public class UsernamePasswordCredentials implements Credentials, Serializable {
         this.password = password;
     }
 
+    @Override
     public Principal getUserPrincipal() {
         return this.principal;
     }
@@ -88,6 +89,7 @@ public class UsernamePasswordCredentials implements Credentials, Serializable {
         return this.principal.getName();
     }
 
+    @Override
     public String getPassword() {
         return password;
     }
diff --git a/httpclient/src/main/java/org/apache/http/client/AuthenticationStrategy.java b/httpclient/src/main/java/org/apache/http/client/AuthenticationStrategy.java
index 4f4ef96..501959b 100644
--- a/httpclient/src/main/java/org/apache/http/client/AuthenticationStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/client/AuthenticationStrategy.java
@@ -58,8 +58,8 @@ public interface AuthenticationStrategy {
      * @param authhost authentication host.
      * @param response HTTP response.
      * @param context HTTP context.
-     * @return <code>true</code> if user authentication is required,
-     *   <code>false</code> otherwise.
+     * @return {@code true} if user authentication is required,
+     *   {@code false} otherwise.
      */
     boolean isAuthenticationRequested(
             HttpHost authhost,
diff --git a/httpclient/src/main/java/org/apache/http/client/CircularRedirectException.java b/httpclient/src/main/java/org/apache/http/client/CircularRedirectException.java
index c88e10c..489aa72 100644
--- a/httpclient/src/main/java/org/apache/http/client/CircularRedirectException.java
+++ b/httpclient/src/main/java/org/apache/http/client/CircularRedirectException.java
@@ -40,7 +40,7 @@ public class CircularRedirectException extends RedirectException {
     private static final long serialVersionUID = 6830063487001091803L;
 
     /**
-     * Creates a new CircularRedirectException with a <tt>null</tt> detail message.
+     * Creates a new CircularRedirectException with a {@code null} detail message.
      */
     public CircularRedirectException() {
         super();
@@ -59,8 +59,8 @@ public class CircularRedirectException extends RedirectException {
      * Creates a new CircularRedirectException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public CircularRedirectException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/client/ConnectionBackoffStrategy.java b/httpclient/src/main/java/org/apache/http/client/ConnectionBackoffStrategy.java
index b71068b..5a7a6d9 100644
--- a/httpclient/src/main/java/org/apache/http/client/ConnectionBackoffStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/client/ConnectionBackoffStrategy.java
@@ -32,7 +32,7 @@ import org.apache.http.HttpResponse;
  * When managing a dynamic number of connections for a given route, this
  * strategy assesses whether a given request execution outcome should
  * result in a backoff signal or not, based on either examining the
- * <code>Throwable</code> that resulted or by examining the resulting
+ * {@code Throwable} that resulted or by examining the resulting
  * response (e.g. for its status code).
  *
  * @since 4.2
@@ -41,11 +41,11 @@ import org.apache.http.HttpResponse;
 public interface ConnectionBackoffStrategy {
 
     /**
-     * Determines whether seeing the given <code>Throwable</code> as
+     * Determines whether seeing the given {@code Throwable} as
      * a result of request execution should result in a backoff
      * signal.
-     * @param t the <code>Throwable</code> that happened
-     * @return <code>true</code> if a backoff signal should be
+     * @param t the {@code Throwable} that happened
+     * @return {@code true} if a backoff signal should be
      *   given
      */
     boolean shouldBackoff(Throwable t);
@@ -56,8 +56,8 @@ public interface ConnectionBackoffStrategy {
      * signal. Implementations MUST restrict themselves to examining
      * the response header and MUST NOT consume any of the response
      * body, if any.
-     * @param resp the <code>HttpResponse</code> that was received
-     * @return <code>true</code> if a backoff signal should be
+     * @param resp the {@code HttpResponse} that was received
+     * @return {@code true} if a backoff signal should be
      *   given
      */
     boolean shouldBackoff(HttpResponse resp);
diff --git a/httpclient/src/main/java/org/apache/http/client/HttpClient.java b/httpclient/src/main/java/org/apache/http/client/HttpClient.java
index 8cc2e62..c7c0b64 100644
--- a/httpclient/src/main/java/org/apache/http/client/HttpClient.java
+++ b/httpclient/src/main/java/org/apache/http/client/HttpClient.java
@@ -95,7 +95,7 @@ public interface HttpClient {
      *
      * @param request   the request to execute
      * @param context   the context to use for the execution, or
-     *                  <code>null</code> to use the default context
+     *                  {@code null} to use the default context
      *
      * @return  the response to the request. This is always a final response,
      *          never an intermediate response with an 1xx status code.
@@ -112,7 +112,7 @@ public interface HttpClient {
      * Executes HTTP request using the default context.
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
@@ -132,12 +132,12 @@ public interface HttpClient {
      * Executes HTTP request using the given context.
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
      * @param context   the context to use for the execution, or
-     *                  <code>null</code> to use the default context
+     *                  {@code null} to use the default context
      *
      * @return  the response to the request. This is always a final response,
      *          never an intermediate response with an 1xx status code.
@@ -154,12 +154,13 @@ public interface HttpClient {
     /**
      * Executes HTTP request using the default context and processes the
      * response using the given response handler.
-     * <p/>
+     * <p>
      * Implementing classes are required to ensure that the content entity
      * associated with the response is fully consumed and the underlying
      * connection is released back to the connection manager automatically
      * in all cases relieving individual {@link ResponseHandler}s from
      * having to manage resource deallocation internally.
+     * </p>
      *
      * @param request   the request to execute
      * @param responseHandler the response handler
@@ -176,17 +177,18 @@ public interface HttpClient {
     /**
      * Executes HTTP request using the given context and processes the
      * response using the given response handler.
-     * <p/>
+     * <p>
      * Implementing classes are required to ensure that the content entity
      * associated with the response is fully consumed and the underlying
      * connection is released back to the connection manager automatically
      * in all cases relieving individual {@link ResponseHandler}s from
      * having to manage resource deallocation internally.
+     * </p>
      *
      * @param request   the request to execute
      * @param responseHandler the response handler
      * @param context   the context to use for the execution, or
-     *                  <code>null</code> to use the default context
+     *                  {@code null} to use the default context
      *
      * @return  the response object as generated by the response handler.
      * @throws IOException in case of a problem or the connection was aborted
@@ -201,15 +203,16 @@ public interface HttpClient {
     /**
      * Executes HTTP request to the target using the default context and
      * processes the response using the given response handler.
-     * <p/>
+     * <p>
      * Implementing classes are required to ensure that the content entity
      * associated with the response is fully consumed and the underlying
      * connection is released back to the connection manager automatically
      * in all cases relieving individual {@link ResponseHandler}s from
      * having to manage resource deallocation internally.
+     * </p>
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
@@ -228,21 +231,22 @@ public interface HttpClient {
     /**
      * Executes HTTP request to the target using the given context and
      * processes the response using the given response handler.
-     * <p/>
+     * <p>
      * Implementing classes are required to ensure that the content entity
      * associated with the response is fully consumed and the underlying
      * connection is released back to the connection manager automatically
      * in all cases relieving individual {@link ResponseHandler}s from
      * having to manage resource deallocation internally.
+     * </p>
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
      * @param responseHandler the response handler
      * @param context   the context to use for the execution, or
-     *                  <code>null</code> to use the default context
+     *                  {@code null} to use the default context
      *
      * @return  the response object as generated by the response handler.
      * @throws IOException in case of a problem or the connection was aborted
diff --git a/httpclient/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java b/httpclient/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java
index f848859..bf0403e 100644
--- a/httpclient/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java
+++ b/httpclient/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java
@@ -52,7 +52,7 @@ public interface HttpRequestRetryHandler {
      * unsuccessfully executed
      * @param context the context for the request execution
      *
-     * @return <code>true</code> if the method should be retried, <code>false</code>
+     * @return {@code true} if the method should be retried, {@code false}
      * otherwise
      */
     boolean retryRequest(IOException exception, int executionCount, HttpContext context);
diff --git a/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java b/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java
index 342126f..4f4befb 100644
--- a/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java
+++ b/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java
@@ -42,7 +42,7 @@ public class NonRepeatableRequestException extends ProtocolException {
     private static final long serialVersionUID = 82685265288806048L;
 
     /**
-     * Creates a new NonRepeatableEntityException with a <tt>null</tt> detail message.
+     * Creates a new NonRepeatableEntityException with a {@code null} detail message.
      */
     public NonRepeatableRequestException() {
         super();
diff --git a/httpclient/src/main/java/org/apache/http/client/RedirectException.java b/httpclient/src/main/java/org/apache/http/client/RedirectException.java
index c2b3ba9..cf2abac 100644
--- a/httpclient/src/main/java/org/apache/http/client/RedirectException.java
+++ b/httpclient/src/main/java/org/apache/http/client/RedirectException.java
@@ -41,7 +41,7 @@ public class RedirectException extends ProtocolException {
     private static final long serialVersionUID = 4418824536372559326L;
 
     /**
-     * Creates a new RedirectException with a <tt>null</tt> detail message.
+     * Creates a new RedirectException with a {@code null} detail message.
      */
     public RedirectException() {
         super();
@@ -60,8 +60,8 @@ public class RedirectException extends ProtocolException {
      * Creates a new RedirectException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public RedirectException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/client/RedirectStrategy.java b/httpclient/src/main/java/org/apache/http/client/RedirectStrategy.java
index 9a82469..7f42b89 100644
--- a/httpclient/src/main/java/org/apache/http/client/RedirectStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/client/RedirectStrategy.java
@@ -54,7 +54,7 @@ public interface RedirectStrategy {
      * @param response the response received from the target server
      * @param context the context for the request execution
      *
-     * @return <code>true</code> if the request should be redirected, <code>false</code>
+     * @return {@code true} if the request should be redirected, {@code false}
      * otherwise
      */
     boolean isRedirected(
diff --git a/httpclient/src/main/java/org/apache/http/client/ServiceUnavailableRetryStrategy.java b/httpclient/src/main/java/org/apache/http/client/ServiceUnavailableRetryStrategy.java
index 69c449f..ba5c84a 100644
--- a/httpclient/src/main/java/org/apache/http/client/ServiceUnavailableRetryStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/client/ServiceUnavailableRetryStrategy.java
@@ -47,7 +47,7 @@ public interface ServiceUnavailableRetryStrategy {
      * unsuccessfully executed
      * @param context the context for the request execution
 
-     * @return <code>true</code> if the method should be retried, <code>false</code>
+     * @return {@code true} if the method should be retried, {@code false}
      * otherwise
      */
     boolean retryRequest(HttpResponse response, int executionCount, HttpContext context);
diff --git a/httpclient/src/main/java/org/apache/http/client/UserTokenHandler.java b/httpclient/src/main/java/org/apache/http/client/UserTokenHandler.java
index 5d8b1b8..fe29f03 100644
--- a/httpclient/src/main/java/org/apache/http/client/UserTokenHandler.java
+++ b/httpclient/src/main/java/org/apache/http/client/UserTokenHandler.java
@@ -33,11 +33,12 @@ import org.apache.http.protocol.HttpContext;
  * A handler for determining if the given execution context is user specific
  * or not. The token object returned by this handler is expected to uniquely
  * identify the current user if the context is user specific or to be
- * <code>null</code> if the context does not contain any resources or details
+ * {@code null} if the context does not contain any resources or details
  * specific to the current user.
- * <p/>
+ * <p>
  * The user token will be used to ensure that user specific resources will not
  * be shared with or reused by other users.
+ * </p>
  *
  * @since 4.0
  */
@@ -46,12 +47,12 @@ public interface UserTokenHandler {
     /**
      * The token object returned by this method is expected to uniquely
      * identify the current user if the context is user specific or to be
-     * <code>null</code> if it is not.
+     * {@code null} if it is not.
      *
      * @param context the execution context
      *
      * @return user token that uniquely identifies the user or
-     * <code>null</null> if the context is not user specific.
+     * {@code null} if the context is not user specific.
      */
     Object getUserToken(HttpContext context);
 
diff --git a/httpclient/src/main/java/org/apache/http/client/config/AuthSchemes.java b/httpclient/src/main/java/org/apache/http/client/config/AuthSchemes.java
index 3b6d803..58f5d61 100644
--- a/httpclient/src/main/java/org/apache/http/client/config/AuthSchemes.java
+++ b/httpclient/src/main/java/org/apache/http/client/config/AuthSchemes.java
@@ -38,30 +38,33 @@ import org.apache.http.annotation.Immutable;
 public final class AuthSchemes {
 
     /**
-     * Basic authentication scheme as defined in RFC2617 (considered inherently
-     * insecure, but most widely supported)
+     * Basic authentication scheme as defined in RFC 2617 (considered inherently
+     * insecure, but most widely supported).
      */
     public static final String BASIC = "Basic";
 
     /**
-     * Digest authentication scheme as defined in RFC2617.
+     * Digest authentication scheme as defined in RFC 2617.
      */
     public static final String DIGEST = "Digest";
 
     /**
-     * The NTLM scheme is a proprietary Microsoft Windows Authentication
-     * protocol (considered to be the most secure among currently supported
-     * authentication schemes).
+     * The NTLM authentication scheme is a proprietary Microsoft Windows
+     * authentication protocol as defined in [MS-NLMP].
      */
     public static final String NTLM = "NTLM";
 
     /**
-     * SPNEGO Authentication scheme.
+     * SPNEGO authentication scheme as defined in RFC 4559 and RFC 4178
+     * (considered to be the most secure among currently supported
+     * authentication schemes if Kerberos is selected).
      */
-    public static final String SPNEGO = "negotiate";
+    public static final String SPNEGO = "Negotiate";
 
     /**
-     * Kerberos Authentication scheme.
+     * Kerberos authentication scheme as defined in RFC 4120
+     * (considered to be the most secure among currently supported
+     * authentication schemes).
      */
     public static final String KERBEROS = "Kerberos";
 
diff --git a/httpclient/src/main/java/org/apache/http/client/config/CookieSpecs.java b/httpclient/src/main/java/org/apache/http/client/config/CookieSpecs.java
index 4ab3ddd..86477f2 100644
--- a/httpclient/src/main/java/org/apache/http/client/config/CookieSpecs.java
+++ b/httpclient/src/main/java/org/apache/http/client/config/CookieSpecs.java
@@ -40,7 +40,10 @@ public final class CookieSpecs {
     /**
      * The policy that provides high degree of compatibility
      * with common cookie management of popular HTTP agents.
+     *
+     * @deprecated (4.4) use {link #DEFAULT}.
      */
+    @Deprecated
     public static final String BROWSER_COMPATIBILITY = "compatibility";
 
     /**
@@ -49,16 +52,33 @@ public final class CookieSpecs {
     public static final String NETSCAPE = "netscape";
 
     /**
-     * The RFC 2965 compliant policy (standard).
+     * The RFC 6265 compliant policy (interoprability profile).
      */
     public static final String STANDARD = "standard";
 
     /**
+     * The RFC 6265 compliant policy (strict profile).
+     *
+     * @since 4.4
+     */
+    public static final String STANDARD_STRICT = "standard-strict";
+
+    /**
      * The default 'best match' policy.
+     *
+     * @deprecated (4.4) use {link #DEFAULT}.
      */
+    @Deprecated
     public static final String BEST_MATCH = "best-match";
 
     /**
+     * The default policy. This policy provides a higher degree of compatibility
+     * with common cookie management of popular HTTP agents for non-standard
+     * (Netscape style) cookies.
+     */
+    public static final String DEFAULT = "default";
+
+    /**
      * The policy that ignores cookies.
      */
     public static final String IGNORE_COOKIES = "ignoreCookies";
diff --git a/httpclient/src/main/java/org/apache/http/client/config/RequestConfig.java b/httpclient/src/main/java/org/apache/http/client/config/RequestConfig.java
index 9bb457d..303eaf7 100644
--- a/httpclient/src/main/java/org/apache/http/client/config/RequestConfig.java
+++ b/httpclient/src/main/java/org/apache/http/client/config/RequestConfig.java
@@ -31,7 +31,14 @@ import java.net.InetAddress;
 import java.util.Collection;
 
 import org.apache.http.HttpHost;
+import org.apache.http.annotation.Immutable;
 
+/**
+ *  Immutable class encapsulating request configuration items.
+ *  The default setting for stale connection checking changed
+ *  to false, and the feature was deprecated starting with version 4.4.
+ */
+ at Immutable
 public class RequestConfig implements Cloneable {
 
     public static final RequestConfig DEFAULT = new Builder().build();
@@ -51,6 +58,7 @@ public class RequestConfig implements Cloneable {
     private final int connectionRequestTimeout;
     private final int connectTimeout;
     private final int socketTimeout;
+    private final boolean decompressionEnabled;
 
     RequestConfig(
             final boolean expectContinueEnabled,
@@ -67,7 +75,8 @@ public class RequestConfig implements Cloneable {
             final Collection<String> proxyPreferredAuthSchemes,
             final int connectionRequestTimeout,
             final int connectTimeout,
-            final int socketTimeout) {
+            final int socketTimeout,
+            final boolean decompressionEnabled) {
         super();
         this.expectContinueEnabled = expectContinueEnabled;
         this.proxy = proxy;
@@ -84,6 +93,7 @@ public class RequestConfig implements Cloneable {
         this.connectionRequestTimeout = connectionRequestTimeout;
         this.connectTimeout = connectTimeout;
         this.socketTimeout = socketTimeout;
+        this.decompressionEnabled = decompressionEnabled;
     }
 
     /**
@@ -93,17 +103,20 @@ public class RequestConfig implements Cloneable {
      * a request body to determine if the origin server is willing to
      * accept the request (based on the request headers) before the client
      * sends the request body.
-     * <p/>
+     * <p>
      * The use of the 'Expect: 100-continue' handshake can result in
      * a noticeable performance improvement for entity enclosing requests
      * (such as POST and PUT) that require the target server's
      * authentication.
-     * <p/>
+     * </p>
+     * <p>
      * 'Expect: 100-continue' handshake should be used with caution, as it
      * may cause problems with HTTP servers and proxies that do not support
      * HTTP/1.1 protocol.
-     * <p/>
-     * Default: <code>false</code>
+     * </p>
+     * <p>
+     * Default: {@code false}
+     * </p>
      */
     public boolean isExpectContinueEnabled() {
         return expectContinueEnabled;
@@ -111,8 +124,9 @@ public class RequestConfig implements Cloneable {
 
     /**
      * Returns HTTP proxy to be used for request execution.
-     * <p/>
-     * Default: <code>null</code>
+     * <p>
+     * Default: {@code null}
+     * </p>
      */
     public HttpHost getProxy() {
         return proxy;
@@ -120,12 +134,14 @@ public class RequestConfig implements Cloneable {
 
     /**
      * Returns local address to be used for request execution.
-     * <p/>
+     * <p>
      * On machines with multiple network interfaces, this parameter
      * can be used to select the network interface from which the
      * connection originates.
-     * <p/>
-     * Default: <code>null</code>
+     * </p>
+     * <p>
+     * Default: {@code null}
+     * </p>
      */
     public InetAddress getLocalAddress() {
         return localAddress;
@@ -136,9 +152,14 @@ public class RequestConfig implements Cloneable {
      * connection check can cause up to 30 millisecond overhead per request and
      * should be used only when appropriate. For performance critical
      * operations this check should be disabled.
-     * <p/>
-     * Default: <code>true</code>
+     * <p>
+     * Default: {@code false} since 4.4
+     * </p>
+     *
+     * @deprecated (4.4) Use {@link
+     *   org.apache.http.impl.conn.PoolingHttpClientConnectionManager#getValidateAfterInactivity()}
      */
+    @Deprecated
     public boolean isStaleConnectionCheckEnabled() {
         return staleConnectionCheckEnabled;
     }
@@ -146,8 +167,9 @@ public class RequestConfig implements Cloneable {
     /**
      * Determines the name of the cookie specification to be used for HTTP state
      * management.
-     * <p/>
-     * Default: <code>null</code>
+     * <p>
+     * Default: {@code null}
+     * </p>
      */
     public String getCookieSpec() {
         return cookieSpec;
@@ -155,8 +177,9 @@ public class RequestConfig implements Cloneable {
 
     /**
      * Determines whether redirects should be handled automatically.
-     * <p/>
-     * Default: <code>true</code>
+     * <p>
+     * Default: {@code true}
+     * </p>
      */
     public boolean isRedirectsEnabled() {
         return redirectsEnabled;
@@ -165,8 +188,9 @@ public class RequestConfig implements Cloneable {
     /**
      * Determines whether relative redirects should be rejected. HTTP specification
      * requires the location value be an absolute URI.
-     * <p/>
-     * Default: <code>true</code>
+     * <p>
+     * Default: {@code true}
+     * </p>
      */
     public boolean isRelativeRedirectsAllowed() {
         return relativeRedirectsAllowed;
@@ -176,8 +200,9 @@ public class RequestConfig implements Cloneable {
      * Determines whether circular redirects (redirects to the same location) should
      * be allowed. The HTTP spec is not sufficiently clear whether circular redirects
      * are permitted, therefore optionally they can be enabled
-     * <p/>
-     * Default: <code>false</code>
+     * <p>
+     * Default: {@code false}
+     * </p>
      */
     public boolean isCircularRedirectsAllowed() {
         return circularRedirectsAllowed;
@@ -186,8 +211,9 @@ public class RequestConfig implements Cloneable {
     /**
      * Returns the maximum number of redirects to be followed. The limit on number
      * of redirects is intended to prevent infinite loops.
-     * <p/>
-     * Default: <code>50</code>
+     * <p>
+     * Default: {@code 50}
+     * </p>
      */
     public int getMaxRedirects() {
         return maxRedirects;
@@ -195,8 +221,9 @@ public class RequestConfig implements Cloneable {
 
     /**
      * Determines whether authentication should be handled automatically.
-     * <p/>
-     * Default: <code>true</code>
+     * <p>
+     * Default: {@code true}
+     * </p>
      */
     public boolean isAuthenticationEnabled() {
         return authenticationEnabled;
@@ -205,8 +232,9 @@ public class RequestConfig implements Cloneable {
     /**
      * Determines the order of preference for supported authentication schemes
      * when authenticating with the target host.
-     * <p/>
-     * Default: <code>null</code>
+     * <p>
+     * Default: {@code null}
+     * </p>
      */
     public Collection<String> getTargetPreferredAuthSchemes() {
         return targetPreferredAuthSchemes;
@@ -215,8 +243,9 @@ public class RequestConfig implements Cloneable {
     /**
      * Determines the order of preference for supported authentication schemes
      * when authenticating with the proxy host.
-     * <p/>
-     * Default: <code>null</code>
+     * <p>
+     * Default: {@code null}
+     * </p>
      */
     public Collection<String> getProxyPreferredAuthSchemes() {
         return proxyPreferredAuthSchemes;
@@ -226,11 +255,13 @@ public class RequestConfig implements Cloneable {
      * Returns the timeout in milliseconds used when requesting a connection
      * from the connection manager. A timeout value of zero is interpreted
      * as an infinite timeout.
-     * <p/>
+     * <p>
      * A timeout value of zero is interpreted as an infinite timeout.
      * A negative value is interpreted as undefined (system default).
-     * <p/>
-     * Default: <code>-1</code>
+     * </p>
+     * <p>
+     * Default: {@code -1}
+     * </p>
      */
     public int getConnectionRequestTimeout() {
         return connectionRequestTimeout;
@@ -239,30 +270,46 @@ public class RequestConfig implements Cloneable {
     /**
      * Determines the timeout in milliseconds until a connection is established.
      * A timeout value of zero is interpreted as an infinite timeout.
-     * <p/>
+     * <p>
      * A timeout value of zero is interpreted as an infinite timeout.
      * A negative value is interpreted as undefined (system default).
-     * <p/>
-     * Default: <code>-1</code>
+     * </p>
+     * <p>
+     * Default: {@code -1}
+     * </p>
      */
     public int getConnectTimeout() {
         return connectTimeout;
     }
 
     /**
-     * Defines the socket timeout (<code>SO_TIMEOUT</code>) in milliseconds,
+     * Defines the socket timeout ({@code SO_TIMEOUT}) in milliseconds,
      * which is the timeout for waiting for data  or, put differently,
      * a maximum period inactivity between two consecutive data packets).
-     * <p/>
+     * <p>
      * A timeout value of zero is interpreted as an infinite timeout.
      * A negative value is interpreted as undefined (system default).
-     * <p/>
-     * Default: <code>-1</code>
+     * </p>
+     * <p>
+     * Default: {@code -1}
+     * </p>
      */
     public int getSocketTimeout() {
         return socketTimeout;
     }
 
+    /**
+     * Determines whether compressed entities should be decompressed automatically.
+     * <p>
+     * Default: {@code true}
+     * </p>
+     *
+     * @since 4.4
+     */
+    public boolean isDecompressionEnabled() {
+        return decompressionEnabled;
+    }
+
     @Override
     protected RequestConfig clone() throws CloneNotSupportedException {
         return (RequestConfig) super.clone();
@@ -271,10 +318,10 @@ public class RequestConfig implements Cloneable {
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append(", expectContinueEnabled=").append(expectContinueEnabled);
+        builder.append("[");
+        builder.append("expectContinueEnabled=").append(expectContinueEnabled);
         builder.append(", proxy=").append(proxy);
         builder.append(", localAddress=").append(localAddress);
-        builder.append(", staleConnectionCheckEnabled=").append(staleConnectionCheckEnabled);
         builder.append(", cookieSpec=").append(cookieSpec);
         builder.append(", redirectsEnabled=").append(redirectsEnabled);
         builder.append(", relativeRedirectsAllowed=").append(relativeRedirectsAllowed);
@@ -286,6 +333,7 @@ public class RequestConfig implements Cloneable {
         builder.append(", connectionRequestTimeout=").append(connectionRequestTimeout);
         builder.append(", connectTimeout=").append(connectTimeout);
         builder.append(", socketTimeout=").append(socketTimeout);
+        builder.append(", decompressionEnabled=").append(decompressionEnabled);
         builder.append("]");
         return builder.toString();
     }
@@ -294,6 +342,7 @@ public class RequestConfig implements Cloneable {
         return new Builder();
     }
 
+    @SuppressWarnings("deprecation")
     public static RequestConfig.Builder copy(final RequestConfig config) {
         return new Builder()
             .setExpectContinueEnabled(config.isExpectContinueEnabled())
@@ -310,7 +359,8 @@ public class RequestConfig implements Cloneable {
             .setProxyPreferredAuthSchemes(config.getProxyPreferredAuthSchemes())
             .setConnectionRequestTimeout(config.getConnectionRequestTimeout())
             .setConnectTimeout(config.getConnectTimeout())
-            .setSocketTimeout(config.getSocketTimeout());
+            .setSocketTimeout(config.getSocketTimeout())
+            .setDecompressionEnabled(config.isDecompressionEnabled());
     }
 
     public static class Builder {
@@ -330,10 +380,11 @@ public class RequestConfig implements Cloneable {
         private int connectionRequestTimeout;
         private int connectTimeout;
         private int socketTimeout;
+        private boolean decompressionEnabled;
 
         Builder() {
             super();
-            this.staleConnectionCheckEnabled = true;
+            this.staleConnectionCheckEnabled = false;
             this.redirectsEnabled = true;
             this.maxRedirects = 50;
             this.relativeRedirectsAllowed = true;
@@ -341,6 +392,7 @@ public class RequestConfig implements Cloneable {
             this.connectionRequestTimeout = -1;
             this.connectTimeout = -1;
             this.socketTimeout = -1;
+            this.decompressionEnabled = true;
         }
 
         public Builder setExpectContinueEnabled(final boolean expectContinueEnabled) {
@@ -358,6 +410,11 @@ public class RequestConfig implements Cloneable {
             return this;
         }
 
+        /**
+         * @deprecated (4.4) Use {@link
+         *   org.apache.http.impl.conn.PoolingHttpClientConnectionManager#setValidateAfterInactivity(int)}
+         */
+        @Deprecated
         public Builder setStaleConnectionCheckEnabled(final boolean staleConnectionCheckEnabled) {
             this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;
             return this;
@@ -418,6 +475,11 @@ public class RequestConfig implements Cloneable {
             return this;
         }
 
+        public Builder setDecompressionEnabled(final boolean decompressionEnabled) {
+            this.decompressionEnabled = decompressionEnabled;
+            return this;
+        }
+
         public RequestConfig build() {
             return new RequestConfig(
                     expectContinueEnabled,
@@ -434,7 +496,8 @@ public class RequestConfig implements Cloneable {
                     proxyPreferredAuthSchemes,
                     connectionRequestTimeout,
                     connectTimeout,
-                    socketTimeout);
+                    socketTimeout,
+                    decompressionEnabled);
         }
 
     }
diff --git a/httpclient/src/main/java/org/apache/http/client/entity/DecompressingEntity.java b/httpclient/src/main/java/org/apache/http/client/entity/DecompressingEntity.java
index f0e16db..08d7c6d 100644
--- a/httpclient/src/main/java/org/apache/http/client/entity/DecompressingEntity.java
+++ b/httpclient/src/main/java/org/apache/http/client/entity/DecompressingEntity.java
@@ -30,6 +30,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.entity.HttpEntityWrapper;
 import org.apache.http.util.Args;
@@ -37,15 +38,16 @@ import org.apache.http.util.Args;
 /**
  * Common base class for decompressing {@link HttpEntity} implementations.
  *
- * @since 4.1
+ * @since 4.4
  */
-abstract class DecompressingEntity extends HttpEntityWrapper {
+public class DecompressingEntity extends HttpEntityWrapper {
 
     /**
      * Default buffer size.
      */
     private static final int BUFFER_SIZE = 1024 * 2;
 
+    private final InputStreamFactory inputStreamFactory;
     /**
      * {@link #getContent()} method must return the same {@link InputStream}
      * instance when DecompressingEntity is wrapping a streaming entity.
@@ -55,23 +57,21 @@ abstract class DecompressingEntity extends HttpEntityWrapper {
     /**
      * Creates a new {@link DecompressingEntity}.
      *
-     * @param wrapped
-     *            the non-null {@link HttpEntity} to be wrapped
+     * @param wrapped the non-null {@link HttpEntity} to be wrapped
+     * @param inputStreamFactory factory to create decompressing stream.
      */
-    public DecompressingEntity(final HttpEntity wrapped) {
+    public DecompressingEntity(
+            final HttpEntity wrapped,
+            final InputStreamFactory inputStreamFactory) {
         super(wrapped);
+        this.inputStreamFactory = inputStreamFactory;
     }
 
-    abstract InputStream decorate(final InputStream wrapped) throws IOException;
-
     private InputStream getDecompressingStream() throws IOException {
         final InputStream in = wrappedEntity.getContent();
-        return new LazyDecompressingInputStream(in, this);
+        return new LazyDecompressingInputStream(in, inputStreamFactory);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public InputStream getContent() throws IOException {
         if (wrappedEntity.isStreaming()) {
@@ -84,9 +84,6 @@ abstract class DecompressingEntity extends HttpEntityWrapper {
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         Args.notNull(outstream, "Output stream");
@@ -102,4 +99,16 @@ abstract class DecompressingEntity extends HttpEntityWrapper {
         }
     }
 
+    @Override
+    public Header getContentEncoding() {
+        /* Content encoding is now 'identity' */
+        return null;
+    }
+
+    @Override
+    public long getContentLength() {
+        /* length of decompressed content is not known */
+        return -1;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/client/entity/DeflateDecompressingEntity.java b/httpclient/src/main/java/org/apache/http/client/entity/DeflateDecompressingEntity.java
index 4089d00..1d3cd7f 100644
--- a/httpclient/src/main/java/org/apache/http/client/entity/DeflateDecompressingEntity.java
+++ b/httpclient/src/main/java/org/apache/http/client/entity/DeflateDecompressingEntity.java
@@ -29,20 +29,19 @@ package org.apache.http.client.entity;
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 
 /**
  * {@link org.apache.http.entity.HttpEntityWrapper} responsible for handling
- * deflate Content Coded responses. In RFC2616 terms, <code>deflate</code>
- * means a <code>zlib</code> stream as defined in RFC1950. Some server
+ * deflate Content Coded responses. In RFC2616 terms, {@code deflate}
+ * means a {@code zlib} stream as defined in RFC1950. Some server
  * implementations have misinterpreted RFC2616 to mean that a
- * <code>deflate</code> stream as defined in RFC1951 should be used
+ * {@code deflate} stream as defined in RFC1951 should be used
  * (or maybe they did that since that's how IE behaves?). It's confusing
- * that <code>deflate</code> in HTTP 1.1 means <code>zlib</code> streams
- * rather than <code>deflate</code> streams. We handle both types in here,
+ * that {@code deflate} in HTTP 1.1 means {@code zlib} streams
+ * rather than {@code deflate} streams. We handle both types in here,
  * since that's what is seen on the internet. Moral - prefer
- * <code>gzip</code>!
+ * {@code gzip}!
  *
  * @see GzipDecompressingEntity
  *
@@ -58,39 +57,14 @@ public class DeflateDecompressingEntity extends DecompressingEntity {
      *            a non-null {@link HttpEntity} to be wrapped
      */
     public DeflateDecompressingEntity(final HttpEntity entity) {
-        super(entity);
-    }
+        super(entity, new InputStreamFactory() {
 
-    /**
-     * Returns the non-null InputStream that should be returned to by all requests to
-     * {@link #getContent()}.
-     *
-     * @return a non-null InputStream
-     * @throws IOException if there was a problem
-     */
-    @Override
-    InputStream decorate(final InputStream wrapped) throws IOException {
-        return new DeflateInputStream(wrapped);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Header getContentEncoding() {
-
-        /* This HttpEntityWrapper has dealt with the Content-Encoding. */
-        return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public long getContentLength() {
+            @Override
+            public InputStream create(final InputStream instream) throws IOException {
+                return new DeflateInputStream(instream);
+            }
 
-        /* Length of inflated content is unknown. */
-        return -1;
+        });
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/client/entity/EntityBuilder.java b/httpclient/src/main/java/org/apache/http/client/entity/EntityBuilder.java
index 5e1b39e..ce3dfe2 100644
--- a/httpclient/src/main/java/org/apache/http/client/entity/EntityBuilder.java
+++ b/httpclient/src/main/java/org/apache/http/client/entity/EntityBuilder.java
@@ -47,9 +47,10 @@ import org.apache.http.entity.StringEntity;
 
 /**
  * Builder for {@link HttpEntity} instances.
- * <p/>
+ * <p>
  * Several setter methods of this builder are mutually exclusive. In case of multiple invocations
  * of the following methods only the last one will have effect:
+ * </p>
  * <ul>
  *   <li>{@link #setText(String)}</li>
  *   <li>{@link #setBinary(byte[])}</li>
@@ -273,7 +274,7 @@ public class EntityBuilder {
     }
 
     /**
-     * Returns <code>true</code> if entity is to be chunk coded, <code>false</code> otherwise.
+     * Returns {@code true} if entity is to be chunk coded, {@code false} otherwise.
      */
     public boolean isChunked() {
         return chunked;
@@ -288,7 +289,7 @@ public class EntityBuilder {
     }
 
     /**
-     * Returns <code>true</code> if entity is to be GZIP compressed, <code>false</code> otherwise.
+     * Returns {@code true} if entity is to be GZIP compressed, {@code false} otherwise.
      */
     public boolean isGzipCompress() {
         return gzipCompress;
@@ -316,7 +317,7 @@ public class EntityBuilder {
         } else if (this.binary != null) {
             e = new ByteArrayEntity(this.binary, getContentOrDefault(ContentType.DEFAULT_BINARY));
         } else if (this.stream != null) {
-            e = new InputStreamEntity(this.stream, 1, getContentOrDefault(ContentType.DEFAULT_BINARY));
+            e = new InputStreamEntity(this.stream, -1, getContentOrDefault(ContentType.DEFAULT_BINARY));
         } else if (this.parameters != null) {
             e = new UrlEncodedFormEntity(this.parameters,
                     this.contentType != null ? this.contentType.getCharset() : null);
diff --git a/httpclient/src/main/java/org/apache/http/client/entity/GzipDecompressingEntity.java b/httpclient/src/main/java/org/apache/http/client/entity/GzipDecompressingEntity.java
index a0198ef..ca45b59 100644
--- a/httpclient/src/main/java/org/apache/http/client/entity/GzipDecompressingEntity.java
+++ b/httpclient/src/main/java/org/apache/http/client/entity/GzipDecompressingEntity.java
@@ -30,7 +30,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.zip.GZIPInputStream;
 
-import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 
 /**
@@ -49,32 +48,14 @@ public class GzipDecompressingEntity extends DecompressingEntity {
      *            the non-null {@link HttpEntity} to be wrapped
      */
     public GzipDecompressingEntity(final HttpEntity entity) {
-        super(entity);
-    }
-
-    @Override
-    InputStream decorate(final InputStream wrapped) throws IOException {
-        return new GZIPInputStream(wrapped);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Header getContentEncoding() {
-
-        /* This HttpEntityWrapper has dealt with the Content-Encoding. */
-        return null;
-    }
+        super(entity, new InputStreamFactory() {
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public long getContentLength() {
+            @Override
+            public InputStream create(final InputStream instream) throws IOException {
+                return new GZIPInputStream(instream);
+            }
 
-        /* length of ungzipped content is not known */
-        return -1;
+        });
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java b/httpclient/src/main/java/org/apache/http/client/entity/InputStreamFactory.java
similarity index 81%
copy from httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java
copy to httpclient/src/main/java/org/apache/http/client/entity/InputStreamFactory.java
index cc62de3..4753cf6 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java
+++ b/httpclient/src/main/java/org/apache/http/client/entity/InputStreamFactory.java
@@ -24,17 +24,18 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.client;
+package org.apache.http.client.entity;
+
+import java.io.IOException;
+import java.io.InputStream;
 
 /**
- * The actual system clock.
+ * Factory for decorated {@link java.io.InputStream}s.
  *
- * @since 4.2
+ * @since 4.4
  */
-class SystemClock implements Clock {
+public interface InputStreamFactory {
 
-    public long getCurrentTime() {
-        return System.currentTimeMillis();
-    }
+    InputStream create(InputStream instream) throws IOException;
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/client/entity/LazyDecompressingInputStream.java b/httpclient/src/main/java/org/apache/http/client/entity/LazyDecompressingInputStream.java
index fb0e43b..db95ce8 100644
--- a/httpclient/src/main/java/org/apache/http/client/entity/LazyDecompressingInputStream.java
+++ b/httpclient/src/main/java/org/apache/http/client/entity/LazyDecompressingInputStream.java
@@ -26,11 +26,11 @@
  */
 package org.apache.http.client.entity;
 
-import org.apache.http.annotation.NotThreadSafe;
-
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.http.annotation.NotThreadSafe;
+
 /**
  * Lazy init InputStream wrapper.
  */
@@ -38,21 +38,20 @@ import java.io.InputStream;
 class LazyDecompressingInputStream extends InputStream {
 
     private final InputStream wrappedStream;
-
-    private final DecompressingEntity decompressingEntity;
+    private final InputStreamFactory inputStreamFactory;
 
     private InputStream wrapperStream;
 
     public LazyDecompressingInputStream(
             final InputStream wrappedStream,
-            final DecompressingEntity decompressingEntity) {
+            final InputStreamFactory inputStreamFactory) {
         this.wrappedStream = wrappedStream;
-        this.decompressingEntity = decompressingEntity;
+        this.inputStreamFactory = inputStreamFactory;
     }
 
     private void initWrapper() throws IOException {
         if (wrapperStream == null) {
-            wrapperStream = decompressingEntity.decorate(wrappedStream);
+            wrapperStream = inputStreamFactory.create(wrappedStream);
         }
     }
 
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/AbstractExecutionAwareRequest.java b/httpclient/src/main/java/org/apache/http/client/methods/AbstractExecutionAwareRequest.java
index 5be1f40..9d2facf 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/AbstractExecutionAwareRequest.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/AbstractExecutionAwareRequest.java
@@ -50,10 +50,12 @@ public abstract class AbstractExecutionAwareRequest extends AbstractHttpMessage
         this.cancellableRef = new AtomicReference<Cancellable>(null);
     }
 
+    @Override
     @Deprecated
     public void setConnectionRequest(final ClientConnectionRequest connRequest) {
         setCancellable(new Cancellable() {
 
+            @Override
             public boolean cancel() {
                 connRequest.abortRequest();
                 return true;
@@ -62,10 +64,12 @@ public abstract class AbstractExecutionAwareRequest extends AbstractHttpMessage
         });
     }
 
+    @Override
     @Deprecated
     public void setReleaseTrigger(final ConnectionReleaseTrigger releaseTrigger) {
         setCancellable(new Cancellable() {
 
+            @Override
             public boolean cancel() {
                 try {
                     releaseTrigger.abortConnection();
@@ -78,6 +82,7 @@ public abstract class AbstractExecutionAwareRequest extends AbstractHttpMessage
         });
     }
 
+    @Override
     public void abort() {
         if (this.aborted.compareAndSet(false, true)) {
             final Cancellable cancellable = this.cancellableRef.getAndSet(null);
@@ -87,6 +92,7 @@ public abstract class AbstractExecutionAwareRequest extends AbstractHttpMessage
         }
     }
 
+    @Override
     public boolean isAborted() {
         return this.aborted.get();
     }
@@ -94,6 +100,7 @@ public abstract class AbstractExecutionAwareRequest extends AbstractHttpMessage
     /**
      * @since 4.2
      */
+    @Override
     public void setCancellable(final Cancellable cancellable) {
         if (!this.aborted.get()) {
             this.cancellableRef.set(cancellable);
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java
index 4218733..5efb828 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.java
@@ -50,14 +50,17 @@ public abstract class HttpEntityEnclosingRequestBase
         super();
     }
 
+    @Override
     public HttpEntity getEntity() {
         return this.entity;
     }
 
+    @Override
     public void setEntity(final HttpEntity entity) {
         this.entity = entity;
     }
 
+    @Override
     public boolean expectContinue() {
         final Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
         return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpGet.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpGet.java
index 674b2ee..35de2d3 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpGet.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpGet.java
@@ -36,6 +36,7 @@ import org.apache.http.annotation.NotThreadSafe;
  * <p>
  * The HTTP GET method is defined in section 9.3 of
  * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * </p>
  * <blockquote>
  * The GET method means retrieve whatever information (in the form of an
  * entity) is identified by the Request-URI. If the Request-URI refers
@@ -43,7 +44,6 @@ import org.apache.http.annotation.NotThreadSafe;
  * returned as the entity in the response and not the source text of the
  * process, unless that text happens to be the output of the process.
  * </blockquote>
- * </p>
  *
  * @since 4.0
  */
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpHead.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpHead.java
index 6fb1edf..4e4bd96 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpHead.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpHead.java
@@ -36,6 +36,7 @@ import org.apache.http.annotation.NotThreadSafe;
  * <p>
  * The HTTP HEAD method is defined in section 9.4 of
  * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * </p>
  * <blockquote>
  * The HEAD method is identical to GET except that the server MUST NOT
  * return a message-body in the response. The metainformation contained
@@ -46,7 +47,6 @@ import org.apache.http.annotation.NotThreadSafe;
  * often used for testing hypertext links for validity, accessibility,
  * and recent modification.
  * </blockquote>
- * </p>
  *
  * @since 4.0
  */
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpOptions.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpOptions.java
index 614dddf..382edda 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpOptions.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpOptions.java
@@ -43,6 +43,7 @@ import org.apache.http.util.Args;
  * <p>
  * The HTTP OPTIONS method is defined in section 9.2 of
  * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * </p>
  * <blockquote>
  *  The OPTIONS method represents a request for information about the
  *  communication options available on the request/response chain
@@ -51,7 +52,6 @@ import org.apache.http.util.Args;
  *  or the capabilities of a server, without implying a resource action
  *  or initiating a resource retrieval.
  * </blockquote>
- * </p>
  *
  * @since 4.0
  */
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpPatch.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpPatch.java
index 3a6b126..43153e4 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpPatch.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpPatch.java
@@ -35,7 +35,9 @@ import org.apache.http.annotation.NotThreadSafe;
  * HTTP PATCH method.
  * <p>
  * The HTTP PATCH method is defined in <a
- * href="http://tools.ietf.org/html/rfc5789">RF5789</a>: <blockquote> The PATCH
+ * href="http://tools.ietf.org/html/rfc5789">RF5789</a>:
+ * </p>
+ * <blockquote> The PATCH
  * method requests that a set of changes described in the request entity be
  * applied to the resource identified by the Request- URI. Differs from the PUT
  * method in the way the server processes the enclosed entity to modify the
@@ -43,8 +45,8 @@ import org.apache.http.annotation.NotThreadSafe;
  * origin server, and the client is requesting that the stored version be
  * replaced. With PATCH, however, the enclosed entity contains a set of
  * instructions describing how a resource currently residing on the origin
- * server should be modified to produce a new version. </blockquote>
- * </p>
+ * server should be modified to produce a new version.
+ * </blockquote>
  *
  * @since 4.2
  */
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpPost.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpPost.java
index 099833d..410092e 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpPost.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpPost.java
@@ -36,6 +36,7 @@ import org.apache.http.annotation.NotThreadSafe;
  * <p>
  * The HTTP POST method is defined in section 9.5 of
  * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * </p>
  * <blockquote>
  * The POST method is used to request that the origin server accept the entity
  * enclosed in the request as a new subordinate of the resource identified by
@@ -50,7 +51,6 @@ import org.apache.http.annotation.NotThreadSafe;
  *   <li>Extending a database through an append operation</li>
  * </ul>
  * </blockquote>
- * </p>
  *
  * @since 4.0
  */
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpPut.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpPut.java
index aadd145..ac0515a 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpPut.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpPut.java
@@ -36,13 +36,13 @@ import org.apache.http.annotation.NotThreadSafe;
  * <p>
  * The HTTP PUT method is defined in section 9.6 of
  * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * </p>
  * <blockquote>
  * The PUT method requests that the enclosed entity be stored under the
  * supplied Request-URI. If the Request-URI refers to an already
  * existing resource, the enclosed entity SHOULD be considered as a
  * modified version of the one residing on the origin server.
  * </blockquote>
- * </p>
  *
  * @since 4.0
  */
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestBase.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestBase.java
index 65d6737..f997c3c 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestBase.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestBase.java
@@ -50,6 +50,7 @@ public abstract class HttpRequestBase extends AbstractExecutionAwareRequest
     private URI uri;
     private RequestConfig config;
 
+    @Override
     public abstract String getMethod();
 
     /**
@@ -59,6 +60,7 @@ public abstract class HttpRequestBase extends AbstractExecutionAwareRequest
         this.version = version;
     }
 
+    @Override
     public ProtocolVersion getProtocolVersion() {
         return version != null ? version : HttpProtocolParams.getVersion(getParams());
     }
@@ -69,25 +71,28 @@ public abstract class HttpRequestBase extends AbstractExecutionAwareRequest
      * Please note URI remains unchanged in the course of request execution and
      * is not updated if the request is redirected to another location.
      */
+    @Override
     public URI getURI() {
         return this.uri;
     }
 
+    @Override
     public RequestLine getRequestLine() {
         final String method = getMethod();
         final ProtocolVersion ver = getProtocolVersion();
-        final URI uri = getURI();
+        final URI uriCopy = getURI(); // avoids possible window where URI could be changed
         String uritext = null;
-        if (uri != null) {
-            uritext = uri.toASCIIString();
+        if (uriCopy != null) {
+            uritext = uriCopy.toASCIIString();
         }
-        if (uritext == null || uritext.length() == 0) {
+        if (uritext == null || uritext.isEmpty()) {
             uritext = "/";
         }
         return new BasicRequestLine(method, uritext, ver);
     }
 
 
+    @Override
     public RequestConfig getConfig() {
         return config;
     }
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestWrapper.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestWrapper.java
index 771185f..a593cec 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestWrapper.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpRequestWrapper.java
@@ -32,6 +32,7 @@ import java.net.URI;
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.ProtocolVersion;
 import org.apache.http.RequestLine;
@@ -40,6 +41,7 @@ import org.apache.http.message.AbstractHttpMessage;
 import org.apache.http.message.BasicRequestLine;
 import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HTTP;
+import org.apache.http.util.Args;
 
 /**
  * A wrapper class for {@link HttpRequest} that can be used to change properties of the current
@@ -52,13 +54,15 @@ import org.apache.http.protocol.HTTP;
 public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRequest {
 
     private final HttpRequest original;
+    private final HttpHost target;
     private final String method;
     private ProtocolVersion version;
     private URI uri;
 
-    private HttpRequestWrapper(final HttpRequest request) {
+    private HttpRequestWrapper(final HttpRequest request, final HttpHost target) {
         super();
-        this.original = request;
+        this.original = Args.notNull(request, "HTTP request");
+        this.target = target;
         this.version = this.original.getRequestLine().getProtocolVersion();
         this.method = this.original.getRequestLine().getMethod();
         if (request instanceof HttpUriRequest) {
@@ -69,6 +73,7 @@ public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRe
         setHeaders(request.getAllHeaders());
     }
 
+    @Override
     public ProtocolVersion getProtocolVersion() {
         return this.version != null ? this.version : this.original.getProtocolVersion();
     }
@@ -77,6 +82,7 @@ public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRe
         this.version = version;
     }
 
+    @Override
     public URI getURI() {
         return this.uri;
     }
@@ -85,18 +91,22 @@ public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRe
         this.uri = uri;
     }
 
+    @Override
     public String getMethod() {
         return method;
     }
 
+    @Override
     public void abort() throws UnsupportedOperationException {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public boolean isAborted() {
         return false;
     }
 
+    @Override
     public RequestLine getRequestLine() {
         String requestUri = null;
         if (this.uri != null) {
@@ -104,7 +114,7 @@ public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRe
         } else {
             requestUri = this.original.getRequestLine().getUri();
         }
-        if (requestUri == null || requestUri.length() == 0) {
+        if (requestUri == null || requestUri.isEmpty()) {
             requestUri = "/";
         }
         return new BasicRequestLine(this.method, requestUri, getProtocolVersion());
@@ -114,6 +124,13 @@ public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRe
         return this.original;
     }
 
+    /**
+     * @since 4.4
+     */
+    public HttpHost getTarget() {
+        return target;
+    }
+
     @Override
     public String toString() {
         return getRequestLine() + " " + this.headergroup;
@@ -124,19 +141,22 @@ public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRe
 
         private HttpEntity entity;
 
-        public HttpEntityEnclosingRequestWrapper(final HttpEntityEnclosingRequest request) {
-            super(request);
+        HttpEntityEnclosingRequestWrapper(final HttpEntityEnclosingRequest request, final HttpHost target) {
+            super(request, target);
             this.entity = request.getEntity();
         }
 
+        @Override
         public HttpEntity getEntity() {
             return this.entity;
         }
 
+        @Override
         public void setEntity(final HttpEntity entity) {
             this.entity = entity;
         }
 
+        @Override
         public boolean expectContinue() {
             final Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
             return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
@@ -144,14 +164,31 @@ public class HttpRequestWrapper extends AbstractHttpMessage implements HttpUriRe
 
     }
 
+    /**
+     * Creates a mutable wrapper of the original request.
+     *
+     * @param request original request
+     * @return mutable request wrappering the original one
+     */
     public static HttpRequestWrapper wrap(final HttpRequest request) {
-        if (request == null) {
-            return null;
-        }
+        return wrap(request, null);
+    }
+
+
+    /**
+     * Creates a mutable wrapper of the original request.
+     *
+     * @param request original request
+     * @param target original target, if explicitly specified
+     * @return mutable request wrappering the original one
+     * @since 4.4
+     */
+    public static HttpRequestWrapper wrap(final HttpRequest request, final HttpHost target) {
+        Args.notNull(request, "HTTP request");
         if (request instanceof HttpEntityEnclosingRequest) {
-            return new HttpEntityEnclosingRequestWrapper((HttpEntityEnclosingRequest) request);
+            return new HttpEntityEnclosingRequestWrapper((HttpEntityEnclosingRequest) request, target);
         } else {
-            return new HttpRequestWrapper(request);
+            return new HttpRequestWrapper(request, target);
         }
     }
 
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpTrace.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpTrace.java
index 6b16e0d..c0bcc86 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpTrace.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpTrace.java
@@ -36,6 +36,7 @@ import org.apache.http.annotation.NotThreadSafe;
  * <p>
  * The HTTP TRACE method is defined in section 9.6 of
  * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * </p>
  * <blockquote>
  *  The TRACE method is used to invoke a remote, application-layer loop-
  *  back of the request message. The final recipient of the request
@@ -45,7 +46,6 @@ import org.apache.http.annotation.NotThreadSafe;
  *  value of zero (0) in the request (see section 14.31). A TRACE request
  *  MUST NOT include an entity.
  * </blockquote>
- * </p>
  *
  * @since 4.0
  */
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/HttpUriRequest.java b/httpclient/src/main/java/org/apache/http/client/methods/HttpUriRequest.java
index 8d8510f..56de260 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/HttpUriRequest.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/HttpUriRequest.java
@@ -41,16 +41,17 @@ import org.apache.http.HttpRequest;
 public interface HttpUriRequest extends HttpRequest {
 
     /**
-     * Returns the HTTP method this request uses, such as <code>GET</code>,
-     * <code>PUT</code>, <code>POST</code>, or other.
+     * Returns the HTTP method this request uses, such as {@code GET},
+     * {@code PUT}, {@code POST}, or other.
      */
     String getMethod();
 
     /**
      * Returns the URI this request uses, such as
-     * <code>http://example.org/path/to/file</code>.
-     * <br/>
+     * {@code http://example.org/path/to/file}.
+     * <p>
      * Note that the URI may be absolute URI (as above) or may be a relative URI.
+     * </p>
      * <p>
      * Implementations are encouraged to return
      * the URI that was initially requested.
@@ -76,8 +77,8 @@ public interface HttpUriRequest extends HttpRequest {
     /**
      * Tests if the request execution has been aborted.
      *
-     * @return <code>true</code> if the request execution has been aborted,
-     *   <code>false</code> otherwise.
+     * @return {@code true} if the request execution has been aborted,
+     *   {@code false} otherwise.
      */
     boolean isAborted();
 
diff --git a/httpclient/src/main/java/org/apache/http/client/methods/RequestBuilder.java b/httpclient/src/main/java/org/apache/http/client/methods/RequestBuilder.java
index 7a457fe..763bcb5 100644
--- a/httpclient/src/main/java/org/apache/http/client/methods/RequestBuilder.java
+++ b/httpclient/src/main/java/org/apache/http/client/methods/RequestBuilder.java
@@ -27,12 +27,15 @@
 
 package org.apache.http.client.methods;
 
+import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.HeaderIterator;
 import org.apache.http.HttpEntity;
@@ -44,6 +47,8 @@ import org.apache.http.annotation.NotThreadSafe;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.entity.ContentType;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.message.HeaderGroup;
@@ -52,12 +57,13 @@ import org.apache.http.util.Args;
 
 /**
  * Builder for {@link HttpUriRequest} instances.
- * <p/>
+ * <p>
  * Please note that this class treats parameters differently depending on composition
  * of the request: if the request has a content entity explicitly set with
  * {@link #setEntity(org.apache.http.HttpEntity)} or it is not an entity enclosing method
  * (such as POST or PUT), parameters will be added to the query component of the request URI.
  * Otherwise, parameters will be added as a URL encoded {@link UrlEncodedFormEntity entity}.
+ * </p>
  *
  * @since 4.3
  */
@@ -65,18 +71,32 @@ import org.apache.http.util.Args;
 public class RequestBuilder {
 
     private String method;
+    private Charset charset;
     private ProtocolVersion version;
     private URI uri;
     private HeaderGroup headergroup;
     private HttpEntity entity;
-    private LinkedList<NameValuePair> parameters;
+    private List<NameValuePair> parameters;
     private RequestConfig config;
 
     RequestBuilder(final String method) {
         super();
+        this.charset = Consts.UTF_8;
         this.method = method;
     }
 
+    RequestBuilder(final String method, final URI uri) {
+        super();
+        this.method = method;
+        this.uri = uri;
+    }
+
+    RequestBuilder(final String method, final String uri) {
+        super();
+        this.method = method;
+        this.uri = uri != null ? URI.create(uri) : null;
+    }
+
     RequestBuilder() {
         this(null);
     }
@@ -90,30 +110,149 @@ public class RequestBuilder {
         return new RequestBuilder(HttpGet.METHOD_NAME);
     }
 
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder get(final URI uri) {
+        return new RequestBuilder(HttpGet.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder get(final String uri) {
+        return new RequestBuilder(HttpGet.METHOD_NAME, uri);
+    }
+
     public static RequestBuilder head() {
         return new RequestBuilder(HttpHead.METHOD_NAME);
     }
 
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder head(final URI uri) {
+        return new RequestBuilder(HttpHead.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder head(final String uri) {
+        return new RequestBuilder(HttpHead.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder patch() {
+        return new RequestBuilder(HttpPatch.METHOD_NAME);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder patch(final URI uri) {
+        return new RequestBuilder(HttpPatch.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder patch(final String uri) {
+        return new RequestBuilder(HttpPatch.METHOD_NAME, uri);
+    }
+
     public static RequestBuilder post() {
         return new RequestBuilder(HttpPost.METHOD_NAME);
     }
 
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder post(final URI uri) {
+        return new RequestBuilder(HttpPost.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder post(final String uri) {
+        return new RequestBuilder(HttpPost.METHOD_NAME, uri);
+    }
+
     public static RequestBuilder put() {
         return new RequestBuilder(HttpPut.METHOD_NAME);
     }
 
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder put(final URI uri) {
+        return new RequestBuilder(HttpPut.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder put(final String uri) {
+        return new RequestBuilder(HttpPut.METHOD_NAME, uri);
+    }
+
     public static RequestBuilder delete() {
         return new RequestBuilder(HttpDelete.METHOD_NAME);
     }
 
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder delete(final URI uri) {
+        return new RequestBuilder(HttpDelete.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder delete(final String uri) {
+        return new RequestBuilder(HttpDelete.METHOD_NAME, uri);
+    }
+
     public static RequestBuilder trace() {
         return new RequestBuilder(HttpTrace.METHOD_NAME);
     }
 
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder trace(final URI uri) {
+        return new RequestBuilder(HttpTrace.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder trace(final String uri) {
+        return new RequestBuilder(HttpTrace.METHOD_NAME, uri);
+    }
+
     public static RequestBuilder options() {
         return new RequestBuilder(HttpOptions.METHOD_NAME);
     }
 
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder options(final URI uri) {
+        return new RequestBuilder(HttpOptions.METHOD_NAME, uri);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public static RequestBuilder options(final String uri) {
+        return new RequestBuilder(HttpOptions.METHOD_NAME, uri);
+    }
+
     public static RequestBuilder copy(final HttpRequest request) {
         Args.notNull(request, "HTTP request");
         return new RequestBuilder().doCopy(request);
@@ -125,30 +264,80 @@ public class RequestBuilder {
         }
         method = request.getRequestLine().getMethod();
         version = request.getRequestLine().getProtocolVersion();
-        if (request instanceof HttpUriRequest) {
-            uri = ((HttpUriRequest) request).getURI();
-        } else {
-            uri = URI.create(request.getRequestLine().getUri());
-        }
+
         if (headergroup == null) {
             headergroup = new HeaderGroup();
         }
         headergroup.clear();
         headergroup.setHeaders(request.getAllHeaders());
+
+        parameters = null;
+        entity = null;
+
         if (request instanceof HttpEntityEnclosingRequest) {
-            entity = ((HttpEntityEnclosingRequest) request).getEntity();
+            final HttpEntity originalEntity = ((HttpEntityEnclosingRequest) request).getEntity();
+            final ContentType contentType = ContentType.get(originalEntity);
+            if (contentType != null &&
+                    contentType.getMimeType().equals(ContentType.APPLICATION_FORM_URLENCODED.getMimeType())) {
+                try {
+                    final List<NameValuePair> formParams = URLEncodedUtils.parse(originalEntity);
+                    if (!formParams.isEmpty()) {
+                        parameters = formParams;
+                    }
+                } catch (IOException ignore) {
+                }
+            } else {
+                entity = originalEntity;
+            }
+        }
+
+        final URI originalUri;
+        if (request instanceof HttpUriRequest) {
+            originalUri = ((HttpUriRequest) request).getURI();
         } else {
-            entity = null;
+            originalUri = URI.create(request.getRequestLine().getUri());
         }
+
+        final URIBuilder uriBuilder = new URIBuilder(originalUri);
+        if (parameters == null) {
+            final List<NameValuePair> queryParams = uriBuilder.getQueryParams();
+            if (!queryParams.isEmpty()) {
+                parameters = queryParams;
+                uriBuilder.clearParameters();
+            } else {
+                parameters = null;
+            }
+        }
+        try {
+            uri = uriBuilder.build();
+        } catch (URISyntaxException ex) {
+            // Should never happen
+            uri = originalUri;
+        }
+
         if (request instanceof Configurable) {
-            this.config = ((Configurable) request).getConfig();
+            config = ((Configurable) request).getConfig();
         } else {
-            this.config = null;
+            config = null;
         }
-        this.parameters = null;
         return this;
     }
 
+    /**
+     * @since 4.4
+     */
+    public RequestBuilder setCharset(final Charset charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    /**
+     * @since 4.4
+     */
+    public Charset getCharset() {
+        return charset;
+    }
+
     public String getMethod() {
         return method;
     }
@@ -286,29 +475,32 @@ public class RequestBuilder {
 
     public HttpUriRequest build() {
         final HttpRequestBase result;
-        URI uri = this.uri != null ? this.uri : URI.create("/");
-        HttpEntity entity = this.entity;
+        URI uriNotNull = this.uri != null ? this.uri : URI.create("/");
+        HttpEntity entityCopy = this.entity;
         if (parameters != null && !parameters.isEmpty()) {
-            if (entity == null && (HttpPost.METHOD_NAME.equalsIgnoreCase(method)
+            if (entityCopy == null && (HttpPost.METHOD_NAME.equalsIgnoreCase(method)
                     || HttpPut.METHOD_NAME.equalsIgnoreCase(method))) {
-                entity = new UrlEncodedFormEntity(parameters, HTTP.DEF_CONTENT_CHARSET);
+                entityCopy = new UrlEncodedFormEntity(parameters, HTTP.DEF_CONTENT_CHARSET);
             } else {
                 try {
-                    uri = new URIBuilder(uri).addParameters(parameters).build();
+                    uriNotNull = new URIBuilder(uriNotNull)
+                      .setCharset(this.charset)
+                      .addParameters(parameters)
+                      .build();
                 } catch (final URISyntaxException ex) {
                     // should never happen
                 }
             }
         }
-        if (entity == null) {
+        if (entityCopy == null) {
             result = new InternalRequest(method);
         } else {
             final InternalEntityEclosingRequest request = new InternalEntityEclosingRequest(method);
-            request.setEntity(entity);
+            request.setEntity(entityCopy);
             result = request;
         }
         result.setProtocolVersion(this.version);
-        result.setURI(uri);
+        result.setURI(uriNotNull);
         if (this.headergroup != null) {
             result.setHeaders(this.headergroup.getAllHeaders());
         }
diff --git a/httpclient/src/main/java/org/apache/http/client/params/AllClientPNames.java b/httpclient/src/main/java/org/apache/http/client/params/AllClientPNames.java
index d11fe09..bd45028 100644
--- a/httpclient/src/main/java/org/apache/http/client/params/AllClientPNames.java
+++ b/httpclient/src/main/java/org/apache/http/client/params/AllClientPNames.java
@@ -40,10 +40,11 @@ import org.apache.http.params.CoreProtocolPNames;
  * module and all dependency modules or informational units.
  * It does not define additional parameter names, but references
  * other interfaces defining parameter names.
- * <br/>
+ * <p>
  * This interface is meant as a navigation aid for developers.
  * When referring to parameter names, you should use the interfaces
  * in which the respective constants are actually defined.
+ * </p>
  *
  * @since 4.0
  *
diff --git a/httpclient/src/main/java/org/apache/http/client/params/ClientPNames.java b/httpclient/src/main/java/org/apache/http/client/params/ClientPNames.java
index 1249e2f..1d8b037 100644
--- a/httpclient/src/main/java/org/apache/http/client/params/ClientPNames.java
+++ b/httpclient/src/main/java/org/apache/http/client/params/ClientPNames.java
@@ -91,7 +91,7 @@ public interface ClientPNames {
     public static final String COOKIE_POLICY = "http.protocol.cookie-policy";
 
     /**
-     * Defines the virtual host to be used in the <code>Host</code>
+     * Defines the virtual host to be used in the {@code Host}
      * request header instead of the physical host.
      * <p>
      * This parameter expects a value of type {@link org.apache.http.HttpHost}.
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAcceptEncoding.java b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAcceptEncoding.java
index 610c745..9209ac8 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAcceptEncoding.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAcceptEncoding.java
@@ -27,6 +27,7 @@
 package org.apache.http.client.protocol;
 
 import java.io.IOException;
+import java.util.List;
 
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
@@ -46,16 +47,38 @@ import org.apache.http.protocol.HttpContext;
 @Immutable
 public class RequestAcceptEncoding implements HttpRequestInterceptor {
 
+    private final String acceptEncoding;
+
     /**
-     * Adds the header {@code "Accept-Encoding: gzip,deflate"} to the request.
+     * @since 4.4
      */
+    public RequestAcceptEncoding(final List<String> encodings) {
+        if (encodings != null && !encodings.isEmpty()) {
+            final StringBuilder buf = new StringBuilder();
+            for (int i = 0; i < encodings.size(); i++) {
+                if (i > 0) {
+                    buf.append(",");
+                }
+                buf.append(encodings.get(i));
+            }
+            this.acceptEncoding = buf.toString();
+        } else {
+            this.acceptEncoding = "gzip,deflate";
+        }
+    }
+
+    public RequestAcceptEncoding() {
+        this(null);
+    }
+
+    @Override
     public void process(
             final HttpRequest request,
             final HttpContext context) throws HttpException, IOException {
 
         /* Signal support for Accept-Encoding transfer encodings. */
         if (!request.containsHeader("Accept-Encoding")) {
-            request.addHeader("Accept-Encoding", "gzip,deflate");
+            request.addHeader("Accept-Encoding", acceptEncoding);
         }
     }
 
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java
index 710fd57..b548d04 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java
@@ -52,7 +52,6 @@ import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieSpec;
 import org.apache.http.cookie.CookieSpecProvider;
-import org.apache.http.cookie.SetCookie2;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.Args;
 import org.apache.http.util.TextUtils;
@@ -60,7 +59,7 @@ import org.apache.http.util.TextUtils;
 /**
  * Request interceptor that matches cookies available in the current
  * {@link CookieStore} to the request being executed and generates
- * corresponding <code>Cookie</code> request headers.
+ * corresponding {@code Cookie} request headers.
  *
  * @since 4.0
  */
@@ -73,6 +72,7 @@ public class RequestAddCookies implements HttpRequestInterceptor {
         super();
     }
 
+    @Override
     public void process(final HttpRequest request, final HttpContext context)
             throws HttpException, IOException {
         Args.notNull(request, "HTTP request");
@@ -116,7 +116,7 @@ public class RequestAddCookies implements HttpRequestInterceptor {
         final RequestConfig config = clientContext.getRequestConfig();
         String policy = config.getCookieSpec();
         if (policy == null) {
-            policy = CookieSpecs.BEST_MATCH;
+            policy = CookieSpecs.DEFAULT;
         }
         if (this.log.isDebugEnabled()) {
             this.log.debug("CookieSpec selected: " + policy);
@@ -147,14 +147,19 @@ public class RequestAddCookies implements HttpRequestInterceptor {
         // Get an instance of the selected cookie policy
         final CookieSpecProvider provider = registry.lookup(policy);
         if (provider == null) {
-            throw new HttpException("Unsupported cookie policy: " + policy);
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Unsupported cookie policy: " + policy);
+            }
+
+            return;
         }
         final CookieSpec cookieSpec = provider.create(clientContext);
         // Get all cookies available in the HTTP state
-        final List<Cookie> cookies = new ArrayList<Cookie>(cookieStore.getCookies());
+        final List<Cookie> cookies = cookieStore.getCookies();
         // Find cookies matching the given origin
         final List<Cookie> matchedCookies = new ArrayList<Cookie>();
         final Date now = new Date();
+        boolean expired = false;
         for (final Cookie cookie : cookies) {
             if (!cookie.isExpired(now)) {
                 if (cookieSpec.match(cookie, cookieOrigin)) {
@@ -167,8 +172,15 @@ public class RequestAddCookies implements HttpRequestInterceptor {
                 if (this.log.isDebugEnabled()) {
                     this.log.debug("Cookie " + cookie + " expired");
                 }
+                expired = true;
             }
         }
+        // Per RFC 6265, 5.3
+        // The user agent must evict all expired cookies if, at any time, an expired cookie
+        // exists in the cookie store
+        if (expired) {
+            cookieStore.clearExpired(now);
+        }
         // Generate Cookie request headers
         if (!matchedCookies.isEmpty()) {
             final List<Header> headers = cookieSpec.formatCookies(matchedCookies);
@@ -179,19 +191,10 @@ public class RequestAddCookies implements HttpRequestInterceptor {
 
         final int ver = cookieSpec.getVersion();
         if (ver > 0) {
-            boolean needVersionHeader = false;
-            for (final Cookie cookie : matchedCookies) {
-                if (ver != cookie.getVersion() || !(cookie instanceof SetCookie2)) {
-                    needVersionHeader = true;
-                }
-            }
-
-            if (needVersionHeader) {
-                final Header header = cookieSpec.getVersionHeader();
-                if (header != null) {
-                    // Advertise cookie version support
-                    request.addHeader(header);
-                }
+            final Header header = cookieSpec.getVersionHeader();
+            if (header != null) {
+                // Advertise cookie version support
+                request.addHeader(header);
             }
         }
 
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
index 2078ba8..fa6a362 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
@@ -63,6 +63,7 @@ public class RequestAuthCache implements HttpRequestInterceptor {
         super();
     }
 
+    @Override
     public void process(final HttpRequest request, final HttpContext context)
             throws HttpException, IOException {
         Args.notNull(request, "HTTP request");
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/RequestClientConnControl.java b/httpclient/src/main/java/org/apache/http/client/protocol/RequestClientConnControl.java
index 742955e..aba6602 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/RequestClientConnControl.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/RequestClientConnControl.java
@@ -41,9 +41,9 @@ import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.Args;
 
 /**
- * This protocol interceptor is responsible for adding <code>Connection</code>
- * or <code>Proxy-Connection</code> headers to the outgoing requests, which
- * is essential for managing persistence of <code>HTTP/1.0</code> connections.
+ * This protocol interceptor is responsible for adding {@code Connection}
+ * or {@code Proxy-Connection} headers to the outgoing requests, which
+ * is essential for managing persistence of {@code HTTP/1.0} connections.
  *
  * @since 4.0
  */
@@ -58,6 +58,7 @@ public class RequestClientConnControl implements HttpRequestInterceptor {
         super();
     }
 
+    @Override
     public void process(final HttpRequest request, final HttpContext context)
             throws HttpException, IOException {
         Args.notNull(request, "HTTP request");
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/RequestDefaultHeaders.java b/httpclient/src/main/java/org/apache/http/client/protocol/RequestDefaultHeaders.java
index f8d27ce..967270a 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/RequestDefaultHeaders.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/RequestDefaultHeaders.java
@@ -62,6 +62,7 @@ public class RequestDefaultHeaders implements HttpRequestInterceptor {
         this(null);
     }
 
+    @Override
     public void process(final HttpRequest request, final HttpContext context)
             throws HttpException, IOException {
         Args.notNull(request, "HTTP request");
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/RequestExpectContinue.java b/httpclient/src/main/java/org/apache/http/client/protocol/RequestExpectContinue.java
index 23817e6..27edc17 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/RequestExpectContinue.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/RequestExpectContinue.java
@@ -44,10 +44,11 @@ import org.apache.http.util.Args;
 
 /**
  * RequestExpectContinue is responsible for enabling the 'expect-continue'
- * handshake by adding <code>Expect</code> header.
- * <p/>
+ * handshake by adding {@code Expect} header.
+ * <p>
  * This interceptor takes into account {@link RequestConfig#isExpectContinueEnabled()}
  * setting.
+ * </p>
  *
  * @since 4.3
  */
@@ -58,6 +59,7 @@ public class RequestExpectContinue implements HttpRequestInterceptor {
         super();
     }
 
+    @Override
     public void process(final HttpRequest request, final HttpContext context)
             throws HttpException, IOException {
         Args.notNull(request, "HTTP request");
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java b/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java
index f55b5be..ef6c76e 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java
@@ -27,7 +27,9 @@
 package org.apache.http.client.protocol;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Locale;
+import java.util.zip.GZIPInputStream;
 
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
@@ -36,8 +38,12 @@ import org.apache.http.HttpException;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpResponseInterceptor;
 import org.apache.http.annotation.Immutable;
-import org.apache.http.client.entity.DeflateDecompressingEntity;
-import org.apache.http.client.entity.GzipDecompressingEntity;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.DecompressingEntity;
+import org.apache.http.client.entity.DeflateInputStream;
+import org.apache.http.client.entity.InputStreamFactory;
+import org.apache.http.config.Lookup;
+import org.apache.http.config.RegistryBuilder;
 import org.apache.http.protocol.HttpContext;
 
 /**
@@ -54,55 +60,77 @@ public class ResponseContentEncoding implements HttpResponseInterceptor {
 
     public static final String UNCOMPRESSED = "http.client.response.uncompressed";
 
+    private final static InputStreamFactory GZIP = new InputStreamFactory() {
+
+        @Override
+        public InputStream create(final InputStream instream) throws IOException {
+            return new GZIPInputStream(instream);
+        }
+    };
+
+    private final static InputStreamFactory DEFLATE = new InputStreamFactory() {
+
+        @Override
+        public InputStream create(final InputStream instream) throws IOException {
+            return new DeflateInputStream(instream);
+        }
+
+    };
+
+    private final Lookup<InputStreamFactory> decoderRegistry;
+
     /**
-     * Handles the following {@code Content-Encoding}s by
-     * using the appropriate decompressor to wrap the response Entity:
+     * @since 4.4
+     */
+    public ResponseContentEncoding(final Lookup<InputStreamFactory> decoderRegistry) {
+        this.decoderRegistry = decoderRegistry != null ? decoderRegistry :
+            RegistryBuilder.<InputStreamFactory>create()
+                    .register("gzip", GZIP)
+                    .register("x-gzip", GZIP)
+                    .register("deflate", DEFLATE)
+                    .build();
+    }
+
+    /**
+     * Handles {@code gzip} and {@code deflate} compressed entities by using the following
+     * decoders:
      * <ul>
-     * <li>gzip - see {@link GzipDecompressingEntity}</li>
-     * <li>deflate - see {@link DeflateDecompressingEntity}</li>
-     * <li>identity - no action needed</li>
+     * <li>gzip - see {@link GZIPInputStream}</li>
+     * <li>deflate - see {@link DeflateInputStream}</li>
      * </ul>
-     *
-     * @param response the response which contains the entity
-     * @param  context not currently used
-     *
-     * @throws HttpException if the {@code Content-Encoding} is none of the above
      */
+    public ResponseContentEncoding() {
+        this(null);
+    }
+
+    @Override
     public void process(
             final HttpResponse response,
             final HttpContext context) throws HttpException, IOException {
         final HttpEntity entity = response.getEntity();
 
+        final HttpClientContext clientContext = HttpClientContext.adapt(context);
+        final RequestConfig requestConfig = clientContext.getRequestConfig();
         // entity can be null in case of 304 Not Modified, 204 No Content or similar
         // check for zero length entity.
-        if (entity != null && entity.getContentLength() != 0) {
+        if (requestConfig.isDecompressionEnabled() && entity != null && entity.getContentLength() != 0) {
             final Header ceheader = entity.getContentEncoding();
             if (ceheader != null) {
                 final HeaderElement[] codecs = ceheader.getElements();
-                boolean uncompressed = false;
                 for (final HeaderElement codec : codecs) {
-                    final String codecname = codec.getName().toLowerCase(Locale.ENGLISH);
-                    if ("gzip".equals(codecname) || "x-gzip".equals(codecname)) {
-                        response.setEntity(new GzipDecompressingEntity(response.getEntity()));
-                        uncompressed = true;
-                        break;
-                    } else if ("deflate".equals(codecname)) {
-                        response.setEntity(new DeflateDecompressingEntity(response.getEntity()));
-                        uncompressed = true;
-                        break;
-                    } else if ("identity".equals(codecname)) {
-
-                        /* Don't need to transform the content - no-op */
-                        return;
+                    final String codecname = codec.getName().toLowerCase(Locale.ROOT);
+                    final InputStreamFactory decoderFactory = decoderRegistry.lookup(codecname);
+                    if (decoderFactory != null) {
+                        response.setEntity(new DecompressingEntity(response.getEntity(), decoderFactory));
+                        response.removeHeaders("Content-Length");
+                        response.removeHeaders("Content-Encoding");
+                        response.removeHeaders("Content-MD5");
                     } else {
-                        throw new HttpException("Unsupported Content-Coding: " + codec.getName());
+                        if (!"identity".equals(codecname)) {
+                            throw new HttpException("Unsupported Content-Coding: " + codec.getName());
+                        }
                     }
                 }
-                if (uncompressed) {
-                    response.removeHeaders("Content-Length");
-                    response.removeHeaders("Content-Encoding");
-                    response.removeHeaders("Content-MD5");
-                }
             }
         }
     }
diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/ResponseProcessCookies.java b/httpclient/src/main/java/org/apache/http/client/protocol/ResponseProcessCookies.java
index 1192e60..5f3cfab 100644
--- a/httpclient/src/main/java/org/apache/http/client/protocol/ResponseProcessCookies.java
+++ b/httpclient/src/main/java/org/apache/http/client/protocol/ResponseProcessCookies.java
@@ -62,6 +62,7 @@ public class ResponseProcessCookies implements HttpResponseInterceptor {
         super();
     }
 
+    @Override
     public void process(final HttpResponse response, final HttpContext context)
             throws HttpException, IOException {
         Args.notNull(response, "HTTP request");
@@ -137,10 +138,12 @@ public class ResponseProcessCookies implements HttpResponseInterceptor {
         buf.append(cookie.getName());
         buf.append("=\"");
         String v = cookie.getValue();
-        if (v.length() > 100) {
-            v = v.substring(0, 100) + "...";
+        if (v != null) {
+            if (v.length() > 100) {
+                v = v.substring(0, 100) + "...";
+            }
+            buf.append(v);
         }
-        buf.append(v);
         buf.append("\"");
         buf.append(", version:");
         buf.append(Integer.toString(cookie.getVersion()));
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/CloneUtils.java b/httpclient/src/main/java/org/apache/http/client/utils/CloneUtils.java
index 39a1d34..597dc26 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/CloneUtils.java
+++ b/httpclient/src/main/java/org/apache/http/client/utils/CloneUtils.java
@@ -50,7 +50,7 @@ public class CloneUtils {
             final Class<?> clazz = obj.getClass ();
             final Method m;
             try {
-                m = clazz.getMethod("clone", (Class[]) null);
+                m = clazz.getMethod("clone", (Class<?>[]) null);
             } catch (final NoSuchMethodException ex) {
                 throw new NoSuchMethodError(ex.getMessage());
             }
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/DateUtils.java b/httpclient/src/main/java/org/apache/http/client/utils/DateUtils.java
index 86f3c7e..326230a 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/DateUtils.java
+++ b/httpclient/src/main/java/org/apache/http/client/utils/DateUtils.java
@@ -62,7 +62,7 @@ public final class DateUtils {
 
     /**
      * Date format pattern used to parse HTTP date headers in ANSI C
-     * <code>asctime()</code> format.
+     * {@code asctime()} format.
      */
     public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
 
@@ -114,9 +114,9 @@ public final class DateUtils {
      * @param dateValue the date value to parse
      * @param dateFormats the date formats to use
      * @param startDate During parsing, two digit years will be placed in the range
-     * <code>startDate</code> to <code>startDate + 100 years</code>. This value may
-     * be <code>null</code>. When <code>null</code> is given as a parameter, year
-     * <code>2000</code> will be used.
+     * {@code startDate} to {@code startDate + 100 years}. This value may
+     * be {@code null}. When {@code null} is given as a parameter, year
+     * {@code 2000} will be used.
      *
      * @return the parsed date or null if input could not be parsed
      */
@@ -214,9 +214,9 @@ public final class DateUtils {
          * creates a {@link SimpleDateFormat} for the requested format string.
          *
          * @param pattern
-         *            a non-<code>null</code> format String according to
+         *            a non-{@code null} format String according to
          *            {@link SimpleDateFormat}. The format is not checked against
-         *            <code>null</code> since all paths go through
+         *            {@code null} since all paths go through
          *            {@link DateUtils}.
          * @return the requested format. This simple dateformat should not be used
          *         to {@link SimpleDateFormat#applyPattern(String) apply} to a
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/URIBuilder.java b/httpclient/src/main/java/org/apache/http/client/utils/URIBuilder.java
index 1694657..227e494 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/URIBuilder.java
+++ b/httpclient/src/main/java/org/apache/http/client/utils/URIBuilder.java
@@ -59,6 +59,7 @@ public class URIBuilder {
     private String encodedQuery;
     private List<NameValuePair> queryParams;
     private String query;
+    private Charset charset;
     private String fragment;
     private String encodedFragment;
 
@@ -90,8 +91,23 @@ public class URIBuilder {
         digestURI(uri);
     }
 
+    /**
+     * @since 4.4
+     */
+    public URIBuilder setCharset(final Charset charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    /**
+     * @since 4.4
+     */
+    public Charset getCharset() {
+        return charset;
+    }
+
     private List <NameValuePair> parseQuery(final String query, final Charset charset) {
-        if (query != null && query.length() > 0) {
+        if (query != null && !query.isEmpty()) {
             return URLEncodedUtils.parse(query, charset);
         }
         return null;
@@ -162,25 +178,25 @@ public class URIBuilder {
         this.encodedPath = uri.getRawPath();
         this.path = uri.getPath();
         this.encodedQuery = uri.getRawQuery();
-        this.queryParams = parseQuery(uri.getRawQuery(), Consts.UTF_8);
+        this.queryParams = parseQuery(uri.getRawQuery(), this.charset != null ? this.charset : Consts.UTF_8);
         this.encodedFragment = uri.getRawFragment();
         this.fragment = uri.getFragment();
     }
 
     private String encodeUserInfo(final String userInfo) {
-        return URLEncodedUtils.encUserInfo(userInfo, Consts.UTF_8);
+        return URLEncodedUtils.encUserInfo(userInfo, this.charset != null ? this.charset : Consts.UTF_8);
     }
 
     private String encodePath(final String path) {
-        return URLEncodedUtils.encPath(path, Consts.UTF_8);
+        return URLEncodedUtils.encPath(path, this.charset != null ? this.charset : Consts.UTF_8);
     }
 
     private String encodeUrlForm(final List<NameValuePair> params) {
-        return URLEncodedUtils.format(params, Consts.UTF_8);
+        return URLEncodedUtils.format(params, this.charset != null ? this.charset : Consts.UTF_8);
     }
 
     private String encodeUric(final String fragment) {
-        return URLEncodedUtils.encUric(fragment, Consts.UTF_8);
+        return URLEncodedUtils.encUric(fragment, this.charset != null ? this.charset : Consts.UTF_8);
     }
 
     /**
@@ -263,7 +279,7 @@ public class URIBuilder {
      */
     @Deprecated
     public URIBuilder setQuery(final String query) {
-        this.queryParams = parseQuery(query, Consts.UTF_8);
+        this.queryParams = parseQuery(query, this.charset != null ? this.charset : Consts.UTF_8);
         this.query = null;
         this.encodedQuery = null;
         this.encodedSchemeSpecificPart = null;
@@ -273,9 +289,10 @@ public class URIBuilder {
     /**
      * Sets URI query parameters. The parameter name / values are expected to be unescaped
      * and may contain non ASCII characters.
-     * <p/>
+     * <p>
      * Please note query parameters and custom query component are mutually exclusive. This method
      * will remove custom query if present.
+     * </p>
      *
      * @since 4.3
      */
@@ -295,9 +312,10 @@ public class URIBuilder {
     /**
      * Adds URI query parameters. The parameter name / values are expected to be unescaped
      * and may contain non ASCII characters.
-     * <p/>
+     * <p>
      * Please note query parameters and custom query component are mutually exclusive. This method
      * will remove custom query if present.
+     * </p>
      *
      * @since 4.3
      */
@@ -315,9 +333,10 @@ public class URIBuilder {
     /**
      * Sets URI query parameters. The parameter name / values are expected to be unescaped
      * and may contain non ASCII characters.
-     * <p/>
+     * <p>
      * Please note query parameters and custom query component are mutually exclusive. This method
      * will remove custom query if present.
+     * </p>
      *
      * @since 4.3
      */
@@ -339,9 +358,10 @@ public class URIBuilder {
     /**
      * Adds parameter to URI query. The parameter name and value are expected to be unescaped
      * and may contain non ASCII characters.
-     * <p/>
+     * <p>
      * Please note query parameters and custom query component are mutually exclusive. This method
      * will remove custom query if present.
+     * </p>
      */
     public URIBuilder addParameter(final String param, final String value) {
         if (this.queryParams == null) {
@@ -357,9 +377,10 @@ public class URIBuilder {
     /**
      * Sets parameter of URI query overriding existing value if set. The parameter name and value
      * are expected to be unescaped and may contain non ASCII characters.
-     * <p/>
+     * <p>
      * Please note query parameters and custom query component are mutually exclusive. This method
      * will remove custom query if present.
+     * </p>
      */
     public URIBuilder setParameter(final String param, final String value) {
         if (this.queryParams == null) {
@@ -395,9 +416,10 @@ public class URIBuilder {
     /**
      * Sets custom URI query. The value is expected to be unescaped and may contain non ASCII
      * characters.
-     * <p/>
+     * <p>
      * Please note query parameters and custom query component are mutually exclusive. This method
      * will remove query parameters if present.
+     * </p>
      *
      * @since 4.3
      */
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java b/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java
index 99d8267..c44d824 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java
+++ b/httpclient/src/main/java/org/apache/http/client/utils/URIUtils.java
@@ -34,6 +34,7 @@ import java.util.Stack;
 
 import org.apache.http.HttpHost;
 import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.routing.RouteInfo;
 import org.apache.http.util.Args;
 import org.apache.http.util.TextUtils;
 
@@ -189,15 +190,48 @@ public class URIUtils {
             uribuilder.setPath("/");
         }
         if (uribuilder.getHost() != null) {
-            uribuilder.setHost(uribuilder.getHost().toLowerCase(Locale.ENGLISH));
+            uribuilder.setHost(uribuilder.getHost().toLowerCase(Locale.ROOT));
         }
         uribuilder.setFragment(null);
         return uribuilder.build();
     }
 
     /**
+     * A convenience method that optionally converts the original {@link java.net.URI} either
+     * to a relative or an absolute form as required by the specified route.
+     *
+     * @param uri
+     *            original URI.
+     * @throws URISyntaxException
+     *             If the resulting URI is invalid.
+     *
+     * @since 4.4
+     */
+    public static URI rewriteURIForRoute(final URI uri, final RouteInfo route) throws URISyntaxException {
+        if (uri == null) {
+            return null;
+        }
+        if (route.getProxyHost() != null && !route.isTunnelled()) {
+            // Make sure the request URI is absolute
+            if (!uri.isAbsolute()) {
+                final HttpHost target = route.getTargetHost();
+                return rewriteURI(uri, target, true);
+            } else {
+                return rewriteURI(uri);
+            }
+        } else {
+            // Make sure the request URI is relative
+            if (uri.isAbsolute()) {
+                return rewriteURI(uri, null, true);
+            } else {
+                return rewriteURI(uri);
+            }
+        }
+    }
+
+    /**
      * Resolves a URI reference against a base URI. Work-around for bug in
-     * java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
+     * java.net.URI (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535)
      *
      * @param baseURI the base URI
      * @param reference the URI reference
@@ -209,7 +243,7 @@ public class URIUtils {
 
     /**
      * Resolves a URI reference against a base URI. Work-around for bugs in
-     * java.net.URI (e.g. <http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
+     * java.net.URI (e.g. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535)
      *
      * @param baseURI the base URI
      * @param reference the URI reference
@@ -223,7 +257,7 @@ public class URIUtils {
         if (s.startsWith("?")) {
             return resolveReferenceStartingWithQueryString(baseURI, ref);
         }
-        final boolean emptyReference = s.length() == 0;
+        final boolean emptyReference = s.isEmpty();
         if (emptyReference) {
             ref = URI.create("#");
         }
@@ -268,7 +302,7 @@ public class URIUtils {
         final String[] inputSegments = path.split("/");
         final Stack<String> outputSegments = new Stack<String>();
         for (final String inputSegment : inputSegments) {
-            if ((inputSegment.length() == 0)
+            if ((inputSegment.isEmpty())
                 || (".".equals(inputSegment))) {
                 // Do nothing
             } else if ("..".equals(inputSegment)) {
@@ -288,8 +322,8 @@ public class URIUtils {
             outputBuffer.append('/');
         }
         try {
-            final String scheme = uri.getScheme().toLowerCase(Locale.ENGLISH);
-            final String auth = uri.getAuthority().toLowerCase(Locale.ENGLISH);
+            final String scheme = uri.getScheme().toLowerCase(Locale.ROOT);
+            final String auth = uri.getAuthority().toLowerCase(Locale.ROOT);
             final URI ref = new URI(scheme, auth, outputBuffer.toString(),
                     null, null);
             if (uri.getQuery() == null && uri.getFragment() == null) {
@@ -315,7 +349,7 @@ public class URIUtils {
      * Extracts target host from the given {@link URI}.
      *
      * @param uri
-     * @return the target host if the URI is absolute or <code>null</null> if the URI is
+     * @return the target host if the URI is absolute or {@code null} if the URI is
      * relative or does not contain a valid host name.
      *
      * @since 4.1
@@ -367,7 +401,10 @@ public class URIUtils {
             }
             final String scheme = uri.getScheme();
             if (!TextUtils.isBlank(host)) {
-                target = new HttpHost(host, port, scheme);
+                try {
+                    target = new HttpHost(host, port, scheme);
+                } catch (IllegalArgumentException ignore) {
+                }
             }
         }
         return target;
@@ -383,10 +420,10 @@ public class URIUtils {
      *            original request before any redirects
      * @param target
      *            if the last URI is relative, it is resolved against this target,
-     *            or <code>null</code> if not available.
+     *            or {@code null} if not available.
      * @param redirects
      *            collection of redirect locations since the original request
-     *            or <code>null</code> if not available.
+     *            or {@code null} if not available.
      * @return interpreted (absolute) URI
      */
     public static URI resolve(
diff --git a/httpclient/src/main/java/org/apache/http/client/utils/URLEncodedUtils.java b/httpclient/src/main/java/org/apache/http/client/utils/URLEncodedUtils.java
index 08ed445..958a98a 100644
--- a/httpclient/src/main/java/org/apache/http/client/utils/URLEncodedUtils.java
+++ b/httpclient/src/main/java/org/apache/http/client/utils/URLEncodedUtils.java
@@ -28,6 +28,9 @@
 package org.apache.http.client.utils;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
@@ -45,12 +48,12 @@ import org.apache.http.HttpEntity;
 import org.apache.http.NameValuePair;
 import org.apache.http.annotation.Immutable;
 import org.apache.http.entity.ContentType;
-import org.apache.http.message.BasicHeaderValueParser;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.message.ParserCursor;
+import org.apache.http.message.TokenParser;
 import org.apache.http.protocol.HTTP;
+import org.apache.http.util.Args;
 import org.apache.http.util.CharArrayBuffer;
-import org.apache.http.util.EntityUtils;
 
 /**
  * A collection of utilities for encoding URLs.
@@ -71,33 +74,30 @@ public class URLEncodedUtils {
 
     /**
      * Returns a list of {@link NameValuePair NameValuePairs} as built from the URI's query portion. For example, a URI
-     * of http://example.org/path/to/file?a=1&b=2&c=3 would return a list of three NameValuePairs, one for a=1, one for
-     * b=2, and one for c=3. By convention, {@code '&'} and {@code ';'} are accepted as parameter separators.
+     * of {@code http://example.org/path/to/file?a=1&b=2&c=3} would return a list of three NameValuePairs, one for a=1,
+     * one for b=2, and one for c=3. By convention, {@code '&'} and {@code ';'} are accepted as parameter separators.
      * <p>
      * This is typically useful while parsing an HTTP PUT.
      *
      * This API is currently only used for testing.
      *
      * @param uri
-     *            URI to parse
+     *        URI to parse
      * @param charset
-     *            Charset name to use while parsing the query
+     *        Charset name to use while parsing the query
      * @return a list of {@link NameValuePair} as built from the URI's query portion.
      */
     public static List <NameValuePair> parse(final URI uri, final String charset) {
         final String query = uri.getRawQuery();
-        if (query != null && query.length() > 0) {
-            final List<NameValuePair> result = new ArrayList<NameValuePair>();
-            final Scanner scanner = new Scanner(query);
-            parse(result, scanner, QP_SEP_PATTERN, charset);
-            return result;
+        if (query != null && !query.isEmpty()) {
+            return parse(query, Charset.forName(charset));
         }
         return Collections.emptyList();
     }
 
     /**
-     * Returns a list of {@link NameValuePair NameValuePairs} as parsed from an {@link HttpEntity}. The encoding is
-     * taken from the entity's Content-Encoding header.
+     * Returns a list of {@link NameValuePair NameValuePairs} as parsed from an {@link HttpEntity}.
+     * The encoding is taken from the entity's Content-Encoding header.
      * <p>
      * This is typically used while parsing an HTTP POST.
      *
@@ -110,22 +110,38 @@ public class URLEncodedUtils {
     public static List <NameValuePair> parse(
             final HttpEntity entity) throws IOException {
         final ContentType contentType = ContentType.get(entity);
-        if (contentType != null && contentType.getMimeType().equalsIgnoreCase(CONTENT_TYPE)) {
-            final String content = EntityUtils.toString(entity, Consts.ASCII);
-            if (content != null && content.length() > 0) {
-                Charset charset = contentType.getCharset();
-                if (charset == null) {
-                    charset = HTTP.DEF_CONTENT_CHARSET;
-                }
-                return parse(content, charset, QP_SEPS);
+        if (contentType == null || !contentType.getMimeType().equalsIgnoreCase(CONTENT_TYPE)) {
+            return Collections.emptyList();
+        }
+        final long len = entity.getContentLength();
+        Args.check(len <= Integer.MAX_VALUE, "HTTP entity is too large");
+        final Charset charset = contentType.getCharset() != null ? contentType.getCharset() : HTTP.DEF_CONTENT_CHARSET;
+        final InputStream instream = entity.getContent();
+        if (instream == null) {
+            return Collections.emptyList();
+        }
+        final CharArrayBuffer buf;
+        try {
+            buf = new CharArrayBuffer(len > 0 ? (int) len : 1024);
+            final Reader reader = new InputStreamReader(instream, charset);
+            final char[] tmp = new char[1024];
+            int l;
+            while((l = reader.read(tmp)) != -1) {
+                buf.append(tmp, 0, l);
             }
+
+        } finally {
+            instream.close();
         }
-        return Collections.emptyList();
+        if (buf.length() == 0) {
+            return Collections.emptyList();
+        }
+        return parse(buf, charset, QP_SEP_A);
     }
 
     /**
      * Returns true if the entity's Content-Type header is
-     * <code>application/x-www-form-urlencoded</code>.
+     * {@code application/x-www-form-urlencoded}.
      */
     public static boolean isEncoded(final HttpEntity entity) {
         final Header h = entity.getContentType();
@@ -140,8 +156,8 @@ public class URLEncodedUtils {
     }
 
     /**
-     * Adds all parameters within the Scanner to the list of <code>parameters</code>, as encoded by
-     * <code>encoding</code>. For example, a scanner containing the string <code>a=1&b=2&c=3</code> would add the
+     * Adds all parameters within the Scanner to the list of {@code parameters}, as encoded by
+     * {@code encoding}. For example, a scanner containing the string {@code a=1&b=2&c=3} would add the
      * {@link NameValuePair NameValuePairs} a=1, b=2, and c=3 to the list of parameters. By convention, {@code '&'} and
      * {@code ';'} are accepted as parameter separators.
      *
@@ -151,18 +167,21 @@ public class URLEncodedUtils {
      *            Input that contains the parameters to parse.
      * @param charset
      *            Encoding to use when decoding the parameters.
+     *
+     * @deprecated (4.4) use {@link #parse(String, java.nio.charset.Charset)}
      */
+    @Deprecated
     public static void parse(
-            final List <NameValuePair> parameters,
+            final List<NameValuePair> parameters,
             final Scanner scanner,
             final String charset) {
-        parse(parameters, scanner, QP_SEP_PATTERN, charset);
+        parse(parameters, scanner, "[" + QP_SEP_A + QP_SEP_S + "]", charset);
     }
 
     /**
      * Adds all parameters within the Scanner to the list of
-     * <code>parameters</code>, as encoded by <code>encoding</code>. For
-     * example, a scanner containing the string <code>a=1&b=2&c=3</code> would
+     * {@code parameters}, as encoded by {@code encoding}. For
+     * example, a scanner containing the string {@code a=1&b=2&c=3} would
      * add the {@link NameValuePair NameValuePairs} a=1, b=2, and c=3 to the
      * list of parameters.
      *
@@ -174,7 +193,10 @@ public class URLEncodedUtils {
      *            The Pattern string for parameter separators, by convention {@code "[&;]"}
      * @param charset
      *            Encoding to use when decoding the parameters.
+     *
+     * @deprecated (4.4) use {@link #parse(org.apache.http.util.CharArrayBuffer, java.nio.charset.Charset, char...)}
      */
+    @Deprecated
     public static void parse(
             final List <NameValuePair> parameters,
             final Scanner scanner,
@@ -182,8 +204,8 @@ public class URLEncodedUtils {
             final String charset) {
         scanner.useDelimiter(parameterSepartorPattern);
         while (scanner.hasNext()) {
-            String name = null;
-            String value = null;
+            final String name;
+            final String value;
             final String token = scanner.next();
             final int i = token.indexOf(NAME_VALUE_SEPARATOR);
             if (i != -1) {
@@ -191,22 +213,13 @@ public class URLEncodedUtils {
                 value = decodeFormFields(token.substring(i + 1).trim(), charset);
             } else {
                 name = decodeFormFields(token.trim(), charset);
+                value = null;
             }
             parameters.add(new BasicNameValuePair(name, value));
         }
     }
 
     /**
-     * Query parameter separators.
-     */
-    private static final char[] QP_SEPS = new char[] { QP_SEP_A, QP_SEP_S };
-
-    /**
-     * Query parameter separator pattern.
-     */
-    private static final String QP_SEP_PATTERN = "[" + new String(QP_SEPS) + "]";
-
-    /**
      * Returns a list of {@link NameValuePair NameValuePairs} as parsed from the given string using the given character
      * encoding. By convention, {@code '&'} and {@code ';'} are accepted as parameter separators.
      *
@@ -219,7 +232,9 @@ public class URLEncodedUtils {
      * @since 4.2
      */
     public static List<NameValuePair> parse(final String s, final Charset charset) {
-        return parse(s, charset, QP_SEPS);
+        final CharArrayBuffer buffer = new CharArrayBuffer(s.length());
+        buffer.append(s);
+        return parse(buffer, charset, QP_SEP_A, QP_SEP_S);
     }
 
     /**
@@ -230,27 +245,64 @@ public class URLEncodedUtils {
      *            text to parse.
      * @param charset
      *            Encoding to use when decoding the parameters.
-     * @param parameterSeparator
-     *            The characters used to separate parameters, by convention, {@code '&'} and {@code ';'}.
+     * @param separators
+     *            element separators.
      * @return a list of {@link NameValuePair} as built from the URI's query portion.
      *
      * @since 4.3
      */
-    public static List<NameValuePair> parse(final String s, final Charset charset, final char... parameterSeparator) {
+    public static List<NameValuePair> parse(final String s, final Charset charset, final char... separators) {
         if (s == null) {
             return Collections.emptyList();
         }
-        final BasicHeaderValueParser parser = BasicHeaderValueParser.INSTANCE;
         final CharArrayBuffer buffer = new CharArrayBuffer(s.length());
         buffer.append(s);
-        final ParserCursor cursor = new ParserCursor(0, buffer.length());
+        return parse(buffer, charset, separators);
+    }
+
+    /**
+     * Returns a list of {@link NameValuePair NameValuePairs} as parsed from the given string using
+     * the given character encoding.
+     *
+     * @param buf
+     *            text to parse.
+     * @param charset
+     *            Encoding to use when decoding the parameters.
+     * @param separators
+     *            element separators.
+     * @return a list of {@link NameValuePair} as built from the URI's query portion.
+     *
+     * @since 4.4
+     */
+    public static List<NameValuePair> parse(
+            final CharArrayBuffer buf, final Charset charset, final char... separators) {
+        Args.notNull(buf, "Char array buffer");
+        final TokenParser tokenParser = TokenParser.INSTANCE;
+        final BitSet delimSet = new BitSet();
+        for (char separator: separators) {
+            delimSet.set(separator);
+        }
+        final ParserCursor cursor = new ParserCursor(0, buf.length());
         final List<NameValuePair> list = new ArrayList<NameValuePair>();
         while (!cursor.atEnd()) {
-            final NameValuePair nvp = parser.parseNameValuePair(buffer, cursor, parameterSeparator);
-            if (nvp.getName().length() > 0) {
+            delimSet.set('=');
+            final String name = tokenParser.parseToken(buf, cursor, delimSet);
+            String value = null;
+            if (!cursor.atEnd()) {
+                final int delim = buf.charAt(cursor.getPos());
+                cursor.updatePos(cursor.getPos() + 1);
+                if (delim == '=') {
+                    delimSet.clear('=');
+                    value = tokenParser.parseValue(buf, cursor, delimSet);
+                    if (!cursor.atEnd()) {
+                        cursor.updatePos(cursor.getPos() + 1);
+                    }
+                }
+            }
+            if (!name.isEmpty()) {
                 list.add(new BasicNameValuePair(
-                        decodeFormFields(nvp.getName(), charset),
-                        decodeFormFields(nvp.getValue(), charset)));
+                        decodeFormFields(name, charset),
+                        decodeFormFields(value, charset)));
             }
         }
         return list;
@@ -554,7 +606,7 @@ public class URLEncodedUtils {
      * Encode/escape www-url-form-encoded content.
      * <p>
      * Uses the {@link #URLENCODER} set of characters, rather than
-     * the {@link #UNRSERVED} set; this is for compatibilty with previous
+     * the {@link #UNRESERVED} set; this is for compatibilty with previous
      * releases, URLEncoder.encode() and most browsers.
      *
      * @param content the content to encode, will convert space to '+'
@@ -572,7 +624,7 @@ public class URLEncodedUtils {
      * Encode/escape www-url-form-encoded content.
      * <p>
      * Uses the {@link #URLENCODER} set of characters, rather than
-     * the {@link #UNRSERVED} set; this is for compatibilty with previous
+     * the {@link #UNRESERVED} set; this is for compatibilty with previous
      * releases, URLEncoder.encode() and most browsers.
      *
      * @param content the content to encode, will convert space to '+'
diff --git a/httpclient/src/main/java/org/apache/http/conn/ClientConnectionManager.java b/httpclient/src/main/java/org/apache/http/conn/ClientConnectionManager.java
index 1f55a03..8b30e68 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ClientConnectionManager.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ClientConnectionManager.java
@@ -53,7 +53,7 @@ public interface ClientConnectionManager {
     /**
      * Obtains the scheme registry used by this manager.
      *
-     * @return  the scheme registry, never <code>null</code>
+     * @return  the scheme registry, never {@code null}
      */
     SchemeRegistry getSchemeRegistry();
 
@@ -67,7 +67,7 @@ public interface ClientConnectionManager {
     /**
      * Releases a connection for use by others.
      * You may optionally specify how long the connection is valid
-     * to be reused.  Values <= 0 are considered to be valid forever.
+     * to be reused.  Values <= 0 are considered to be valid forever.
      * If the connection is not marked as reusable, the connection will
      * not be reused regardless of the valid duration.
      *
@@ -92,7 +92,7 @@ public interface ClientConnectionManager {
      * All expired connections will also be closed.
      *
      * @param idletime  the idle time of connections to be closed
-     * @param tunit     the unit for the <code>idletime</code>
+     * @param tunit     the unit for the {@code idletime}
      *
      * @see #closeExpiredConnections()
      */
diff --git a/httpclient/src/main/java/org/apache/http/conn/ClientConnectionRequest.java b/httpclient/src/main/java/org/apache/http/conn/ClientConnectionRequest.java
index 0e7946c..cd8d5c4 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ClientConnectionRequest.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ClientConnectionRequest.java
@@ -51,8 +51,8 @@ public interface ClientConnectionRequest {
      * be thrown.
      *
      * @param timeout   the timeout, 0 or negative for no timeout
-     * @param tunit     the unit for the <code>timeout</code>,
-     *                  may be <code>null</code> only if there is no timeout
+     * @param tunit     the unit for the {@code timeout},
+     *                  may be {@code null} only if there is no timeout
      *
      * @return  a connection that can be used to communicate
      *          along the given route
diff --git a/httpclient/src/main/java/org/apache/http/conn/ConnectTimeoutException.java b/httpclient/src/main/java/org/apache/http/conn/ConnectTimeoutException.java
index 52e7a29..a76bcda 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ConnectTimeoutException.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ConnectTimeoutException.java
@@ -50,7 +50,7 @@ public class ConnectTimeoutException extends InterruptedIOException {
     private final HttpHost host;
 
     /**
-     * Creates a ConnectTimeoutException with a <tt>null</tt> detail message.
+     * Creates a ConnectTimeoutException with a {@code null} detail message.
      */
     public ConnectTimeoutException() {
         super();
diff --git a/httpclient/src/main/java/org/apache/http/conn/ConnectionKeepAliveStrategy.java b/httpclient/src/main/java/org/apache/http/conn/ConnectionKeepAliveStrategy.java
index cbdb4a0..7d54eba 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ConnectionKeepAliveStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ConnectionKeepAliveStrategy.java
@@ -59,7 +59,7 @@ public interface ConnectionKeepAliveStrategy {
      *            the context in which the connection is being used.
      *
      * @return the duration in ms for which it is safe to keep the connection
-     *         idle, or <=0 if no suggested duration.
+     *         idle, or <=0 if no suggested duration.
      */
     long getKeepAliveDuration(HttpResponse response, HttpContext context);
 
diff --git a/httpclient/src/main/java/org/apache/http/conn/ConnectionPoolTimeoutException.java b/httpclient/src/main/java/org/apache/http/conn/ConnectionPoolTimeoutException.java
index 9cdd189..3328cc4 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ConnectionPoolTimeoutException.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ConnectionPoolTimeoutException.java
@@ -42,7 +42,7 @@ public class ConnectionPoolTimeoutException extends ConnectTimeoutException {
     private static final long serialVersionUID = -7898874842020245128L;
 
     /**
-     * Creates a ConnectTimeoutException with a <tt>null</tt> detail message.
+     * Creates a ConnectTimeoutException with a {@code null} detail message.
      */
     public ConnectionPoolTimeoutException() {
         super();
diff --git a/httpclient/src/main/java/org/apache/http/conn/ConnectionRequest.java b/httpclient/src/main/java/org/apache/http/conn/ConnectionRequest.java
index a6c6af9..3520a52 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ConnectionRequest.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ConnectionRequest.java
@@ -52,8 +52,8 @@ public interface ConnectionRequest extends Cancellable {
      * be thrown.
      *
      * @param timeout   the timeout, 0 or negative for no timeout
-     * @param tunit     the unit for the <code>timeout</code>,
-     *                  may be <code>null</code> only if there is no timeout
+     * @param tunit     the unit for the {@code timeout},
+     *                  may be {@code null} only if there is no timeout
      *
      * @return  a connection that can be used to communicate
      *          along the given route
diff --git a/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java b/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java
index c5a1a0b..3b81bd0 100644
--- a/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java
+++ b/httpclient/src/main/java/org/apache/http/conn/EofSensorInputStream.java
@@ -48,7 +48,7 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
 
     /**
      * The wrapped input stream, while accessible.
-     * The value changes to <code>null</code> when the wrapped stream
+     * The value changes to {@code null} when the wrapped stream
      * becomes inaccessible.
      */
     protected InputStream wrappedStream;
@@ -56,7 +56,7 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
     /**
      * Indicates whether this stream itself is closed.
      * If it isn't, but {@link #wrappedStream wrappedStream}
-     * is <code>null</code>, we're running in EOF mode.
+     * is {@code null}, we're running in EOF mode.
      * All read operations will indicate EOF without accessing
      * the underlying stream. After closing this stream, read
      * operations will trigger an {@link IOException IOException}.
@@ -76,7 +76,7 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
      * should be closed before detaching from it.
      *
      * @param in        the wrapped stream
-     * @param watcher   the watcher for events, or <code>null</code> for
+     * @param watcher   the watcher for events, or {@code null} for
      *                  auto-close behavior without notification
      */
     public EofSensorInputStream(final InputStream in,
@@ -98,8 +98,8 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
     /**
      * Checks whether the underlying stream can be read from.
      *
-     * @return  <code>true</code> if the underlying stream is accessible,
-     *          <code>false</code> if this stream is in EOF mode and
+     * @return  {@code true} if the underlying stream is accessible,
+     *          {@code false} if this stream is in EOF mode and
      *          detached from the underlying stream
      *
      * @throws IOException      if this stream is already closed
@@ -179,10 +179,11 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
      * This method should only be called while the underlying stream is
      * still accessible. Use {@link #isReadAllowed isReadAllowed} to
      * check that condition.
-     * <br/>
+     * <p>
      * If EOF is detected, the watcher will be notified and this stream
      * is detached from the underlying stream. This prevents multiple
      * notifications from this stream.
+     * </p>
      *
      * @param eof       the result of the calling read operation.
      *                  A negative value indicates that EOF is reached.
@@ -268,6 +269,7 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
     /**
      * Same as {@link #close close()}.
      */
+    @Override
     public void releaseConnection() throws IOException {
         close();
     }
@@ -279,6 +281,7 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
      * indicates that there should be no attempt to read until the end of
      * the stream.
      */
+    @Override
     public void abortConnection() throws IOException {
         // tolerate multiple calls
         selfClosed = true;
diff --git a/httpclient/src/main/java/org/apache/http/conn/EofSensorWatcher.java b/httpclient/src/main/java/org/apache/http/conn/EofSensorWatcher.java
index 58e6b42..772a80a 100644
--- a/httpclient/src/main/java/org/apache/http/conn/EofSensorWatcher.java
+++ b/httpclient/src/main/java/org/apache/http/conn/EofSensorWatcher.java
@@ -42,13 +42,13 @@ public interface EofSensorWatcher {
      *
      * @param wrapped   the underlying stream which has reached EOF
      *
-     * @return  <code>true</code> if <code>wrapped</code> should be closed,
-     *          <code>false</code> if it should be left alone
+     * @return  {@code true} if {@code wrapped} should be closed,
+     *          {@code false} if it should be left alone
      *
      * @throws IOException
      *         in case of an IO problem, for example if the watcher itself
      *         closes the underlying stream. The caller will leave the
-     *         wrapped stream alone, as if <code>false</code> was returned.
+     *         wrapped stream alone, as if {@code false} was returned.
      */
     boolean eofDetected(InputStream wrapped)
         throws IOException;
@@ -60,13 +60,13 @@ public interface EofSensorWatcher {
      *
      * @param wrapped   the underlying stream which has not reached EOF
      *
-     * @return  <code>true</code> if <code>wrapped</code> should be closed,
-     *          <code>false</code> if it should be left alone
+     * @return  {@code true} if {@code wrapped} should be closed,
+     *          {@code false} if it should be left alone
      *
      * @throws IOException
      *         in case of an IO problem, for example if the watcher itself
      *         closes the underlying stream. The caller will leave the
-     *         wrapped stream alone, as if <code>false</code> was returned.
+     *         wrapped stream alone, as if {@code false} was returned.
      */
     boolean streamClosed(InputStream wrapped)
         throws IOException;
@@ -75,19 +75,20 @@ public interface EofSensorWatcher {
      * Indicates that the {@link EofSensorInputStream stream} is aborted.
      * This method will be called only if EOF was <i>not</i> detected
      * before aborting. Otherwise, {@link #eofDetected eofDetected} is called.
-     * <p/>
+     * <p>
      * This method will also be invoked when an input operation causes an
      * IOException to be thrown to make sure the input stream gets shut down.
+     * </p>
      *
      * @param wrapped   the underlying stream which has not reached EOF
      *
-     * @return  <code>true</code> if <code>wrapped</code> should be closed,
-     *          <code>false</code> if it should be left alone
+     * @return  {@code true} if {@code wrapped} should be closed,
+     *          {@code false} if it should be left alone
      *
      * @throws IOException
      *         in case of an IO problem, for example if the watcher itself
      *         closes the underlying stream. The caller will leave the
-     *         wrapped stream alone, as if <code>false</code> was returned.
+     *         wrapped stream alone, as if {@code false} was returned.
      */
     boolean streamAbort(InputStream wrapped)
         throws IOException;
diff --git a/httpclient/src/main/java/org/apache/http/conn/HttpClientConnectionManager.java b/httpclient/src/main/java/org/apache/http/conn/HttpClientConnectionManager.java
index bbac0b3..70c2908 100644
--- a/httpclient/src/main/java/org/apache/http/conn/HttpClientConnectionManager.java
+++ b/httpclient/src/main/java/org/apache/http/conn/HttpClientConnectionManager.java
@@ -35,15 +35,17 @@ import org.apache.http.protocol.HttpContext;
 
 /**
  * Represents a manager of persistent client connections.
- * <p/>
+ * <p>
  * The purpose of an HTTP connection manager is to serve as a factory for new
  * HTTP connections, manage persistent connections and synchronize access to
  * persistent connections making sure that only one thread of execution can
  * have access to a connection at a time.
- * <p/>
+ * </p>
+ * <p>
  * Implementations of this interface must be thread-safe. Access to shared
  * data must be synchronized as methods of this interface may be executed
  * from multiple threads.
+ * </p>
  *
  * @since 4.3
  */
@@ -53,7 +55,7 @@ public interface HttpClientConnectionManager {
      * Returns a new {@link ConnectionRequest}, from which a
      * {@link HttpClientConnection} can be obtained or the request can be
      * aborted.
-     * <p/>
+     * <p>
      * Please note that newly allocated connections can be returned
      * in the closed state. The consumer of that connection is responsible
      * for fully establishing the route the to the connection target
@@ -64,15 +66,16 @@ public interface HttpClientConnectionManager {
      * {@link #upgrade(org.apache.http.HttpClientConnection,
      *   org.apache.http.conn.routing.HttpRoute,
      *   org.apache.http.protocol.HttpContext) upgrade} method to upgrade
-     * the connection after having executed <code>CONNECT</code> method to
+     * the connection after having executed {@code CONNECT} method to
      * all intermediate proxy hops and and finally calling {@link #routeComplete(
      *  org.apache.http.HttpClientConnection,
      *  org.apache.http.conn.routing.HttpRoute,
      *  org.apache.http.protocol.HttpContext) routeComplete} to mark the route
      *  as fully completed.
+     * </p>
      *
      * @param route HTTP route of the requested connection.
-     * @param state expected state of the connection or <code>null</code>
+     * @param state expected state of the connection or {@code null}
      *              if the connection is not expected to carry any state.
      */
     ConnectionRequest requestConnection(HttpRoute route, Object state);
@@ -81,7 +84,7 @@ public interface HttpClientConnectionManager {
      * Releases the connection back to the manager making it potentially
      * re-usable by other consumers. Optionally, the maximum period
      * of how long the manager should keep the connection alive can be
-     * defined using <code>validDuration</code> and <code>timeUnit</code>
+     * defined using {@code validDuration} and {@code timeUnit}
      * parameters.
      *
      * @param conn      the managed connection to release.
@@ -112,7 +115,7 @@ public interface HttpClientConnectionManager {
 
     /**
      * Upgrades the underlying connection socket to TLS/SSL (or another layering
-     * protocol) after having executed <code>CONNECT</code> method to all
+     * protocol) after having executed {@code CONNECT} method to all
      * intermediate proxy hops
      *
      * @param conn the managed connection.
@@ -141,16 +144,18 @@ public interface HttpClientConnectionManager {
 
     /**
      * Closes idle connections in the pool.
-     * <p/>
+     * <p>
      * Open connections in the pool that have not been used for the
      * timespan given by the argument will be closed.
      * Currently allocated connections are not subject to this method.
      * Times will be checked with milliseconds precision
-     *
+     * </p>
+     * <p>
      * All expired connections will also be closed.
+     * </p>
      *
      * @param idletime  the idle time of connections to be closed
-     * @param tunit     the unit for the <code>idletime</code>
+     * @param tunit     the unit for the {@code idletime}
      *
      * @see #closeExpiredConnections()
      */
@@ -158,11 +163,12 @@ public interface HttpClientConnectionManager {
 
     /**
      * Closes all expired connections in the pool.
-     * <p/>
+     * <p>
      * Open connections in the pool that have not been used for
      * the timespan defined when the connection was released will be closed.
      * Currently allocated connections are not subject to this method.
      * Times will be checked with milliseconds precision.
+     * </p>
      */
     void closeExpiredConnections();
 
diff --git a/httpclient/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java b/httpclient/src/main/java/org/apache/http/conn/HttpClientConnectionOperator.java
similarity index 54%
copy from httpclient/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java
copy to httpclient/src/main/java/org/apache/http/conn/HttpClientConnectionOperator.java
index f848859..25255d6 100644
--- a/httpclient/src/main/java/org/apache/http/client/HttpRequestRetryHandler.java
+++ b/httpclient/src/main/java/org/apache/http/conn/HttpClientConnectionOperator.java
@@ -25,36 +25,37 @@
  *
  */
 
-package org.apache.http.client;
+package org.apache.http.conn;
 
 import java.io.IOException;
+import java.net.InetSocketAddress;
 
+import org.apache.http.HttpHost;
+import org.apache.http.config.SocketConfig;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * A handler for determining if an HttpRequest should be retried after a
- * recoverable exception during execution.
- * <p>
- * Implementations of this interface must be thread-safe. Access to shared
- * data must be synchronized as methods of this interface may be executed
- * from multiple threads.
+ * Connection operator that performs connection connect and upgrade operations. Usually, components
+ * participating in these operations are registry of {@link org.apache.http.conn.socket.ConnectionSocketFactory},
+ * {@link SchemePortResolver} and {@link DnsResolver}. In general, HTTP client user should not
+ * provide implementations of this interface, as HttpClient will use the default one that covers
+ * most of the cases needed for majority of users.
  *
- * @since 4.0
+ * @since 4.4
  */
-public interface HttpRequestRetryHandler {
+public interface HttpClientConnectionOperator {
 
-    /**
-     * Determines if a method should be retried after an IOException
-     * occurs during execution.
-     *
-     * @param exception the exception that occurred
-     * @param executionCount the number of times this method has been
-     * unsuccessfully executed
-     * @param context the context for the request execution
-     *
-     * @return <code>true</code> if the method should be retried, <code>false</code>
-     * otherwise
-     */
-    boolean retryRequest(IOException exception, int executionCount, HttpContext context);
+    void connect(
+            ManagedHttpClientConnection conn,
+            HttpHost host,
+            InetSocketAddress localAddress,
+            int connectTimeout,
+            SocketConfig socketConfig,
+            HttpContext context) throws IOException;
+
+    void upgrade(
+            ManagedHttpClientConnection conn,
+            HttpHost host,
+            HttpContext context) throws IOException;
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/conn/HttpHostConnectException.java b/httpclient/src/main/java/org/apache/http/conn/HttpHostConnectException.java
index 56c1d19..fa88a45 100644
--- a/httpclient/src/main/java/org/apache/http/conn/HttpHostConnectException.java
+++ b/httpclient/src/main/java/org/apache/http/conn/HttpHostConnectException.java
@@ -53,7 +53,7 @@ public class HttpHostConnectException extends ConnectException {
      */
     @Deprecated
     public HttpHostConnectException(final HttpHost host, final ConnectException cause) {
-        this(cause, host, null);
+        this(cause, host, (InetAddress[]) null);
     }
 
     /**
diff --git a/httpclient/src/main/java/org/apache/http/conn/HttpRoutedConnection.java b/httpclient/src/main/java/org/apache/http/conn/HttpRoutedConnection.java
index 416f357..f332725 100644
--- a/httpclient/src/main/java/org/apache/http/conn/HttpRoutedConnection.java
+++ b/httpclient/src/main/java/org/apache/http/conn/HttpRoutedConnection.java
@@ -47,8 +47,8 @@ public interface HttpRoutedConnection extends HttpInetConnection {
      * The return value is well-defined only while the connection is open.
      * It may change even while the connection is open.
      *
-     * @return  <code>true</code> if this connection is secure,
-     *          <code>false</code> otherwise
+     * @return  {@code true} if this connection is secure,
+     *          {@code false} otherwise
      */
     boolean isSecure();
 
@@ -56,7 +56,7 @@ public interface HttpRoutedConnection extends HttpInetConnection {
      * Obtains the current route of this connection.
      *
      * @return  the route established so far, or
-     *          <code>null</code> if not connected
+     *          {@code null} if not connected
      */
     HttpRoute getRoute();
 
@@ -65,16 +65,17 @@ public interface HttpRoutedConnection extends HttpInetConnection {
      * If this connection is open, and the underlying socket is an
      * {@link javax.net.ssl.SSLSocket SSLSocket}, the SSL session of
      * that socket is obtained. This is a potentially blocking operation.
-     * <br/>
+     * <p>
      * <b>Note:</b> Whether the underlying socket is an SSL socket
      * can not necessarily be determined via {@link #isSecure}.
      * Plain sockets may be considered secure, for example if they are
      * connected to a known host in the same network segment.
      * On the other hand, SSL sockets may be considered insecure,
      * for example depending on the chosen cipher suite.
+     * </p>
      *
      * @return  the underlying SSL session if available,
-     *          <code>null</code> otherwise
+     *          {@code null} otherwise
      */
     SSLSession getSSLSession();
 
diff --git a/httpclient/src/main/java/org/apache/http/conn/ManagedClientConnection.java b/httpclient/src/main/java/org/apache/http/conn/ManagedClientConnection.java
index 0751bd9..8a06797 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ManagedClientConnection.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ManagedClientConnection.java
@@ -55,17 +55,19 @@ public interface ManagedClientConnection extends
      * The return value is well-defined only while the connection is open.
      * It may change even while the connection is open.
      *
-     * @return  <code>true</code> if this connection is secure,
-     *          <code>false</code> otherwise
+     * @return  {@code true} if this connection is secure,
+     *          {@code false} otherwise
      */
+    @Override
     boolean isSecure();
 
     /**
      * Obtains the current route of this connection.
      *
      * @return  the route established so far, or
-     *          <code>null</code> if not connected
+     *          {@code null} if not connected
      */
+    @Override
     HttpRoute getRoute();
 
     /**
@@ -73,17 +75,19 @@ public interface ManagedClientConnection extends
      * If this connection is open, and the underlying socket is an
      * {@link javax.net.ssl.SSLSocket SSLSocket}, the SSL session of
      * that socket is obtained. This is a potentially blocking operation.
-     * <br/>
+     * <p>
      * <b>Note:</b> Whether the underlying socket is an SSL socket
      * can not necessarily be determined via {@link #isSecure}.
      * Plain sockets may be considered secure, for example if they are
      * connected to a known host in the same network segment.
      * On the other hand, SSL sockets may be considered insecure,
      * for example depending on the chosen cipher suite.
+     * </p>
      *
      * @return  the underlying SSL session if available,
-     *          <code>null</code> otherwise
+     *          {@code null} otherwise
      */
+    @Override
     SSLSession getSSLSession();
 
     /**
@@ -104,14 +108,15 @@ public interface ManagedClientConnection extends
      * The route is the one previously passed to {@link #open open}.
      * Subsequently, {@link #layerProtocol layerProtocol} can be called
      * to layer the TLS/SSL protocol on top of the tunnelled connection.
-     * <br/>
+     * <p>
      * <b>Note:</b> In HttpClient 3, a call to the corresponding method
      * would automatically trigger the layering of the TLS/SSL protocol.
      * This is not the case anymore, you can establish a tunnel without
      * layering a new protocol over the connection.
+     * </p>
      *
-     * @param secure    <code>true</code> if the tunnel should be considered
-     *                  secure, <code>false</code> otherwise
+     * @param secure    {@code true} if the tunnel should be considered
+     *                  secure, {@code false} otherwise
      * @param params    the parameters for tunnelling this connection
      *
      * @throws IOException  in case of a problem
@@ -133,8 +138,8 @@ public interface ManagedClientConnection extends
      *                  of the tunnel. The tunnel does <i>not</i> yet
      *                  reach to the target, use {@link #tunnelTarget}
      *                  to indicate an end-to-end tunnel.
-     * @param secure    <code>true</code> if the connection should be
-     *                  considered secure, <code>false</code> otherwise
+     * @param secure    {@code true} if the connection should be
+     *                  considered secure, {@code false} otherwise
      * @param params    the parameters for tunnelling this connection
      *
      * @throws IOException  in case of a problem
@@ -166,11 +171,12 @@ public interface ManagedClientConnection extends
      * The connection will automatically clear the checkpoint when
      * used for communication. A call to this method indicates that
      * the next checkpoint has been reached.
-     * <br/>
+     * <p>
      * A reusable communication state is necessary but not sufficient
      * for the connection to be reused.
      * A {@link #getRoute route} mismatch, the connection being closed,
      * or other circumstances might prevent reuse.
+     * </p>
      */
     void markReusable();
 
@@ -180,12 +186,13 @@ public interface ManagedClientConnection extends
      * to prevent its reuse. Reasons for preventing reuse include
      * error conditions and the evaluation of a
      * {@link org.apache.http.ConnectionReuseStrategy reuse strategy}.
-     * <br/>
+     * <p>
      * <b>Note:</b>
      * It is <i>not</i> necessary to call here before writing to
      * or reading from this connection. Communication attempts will
      * automatically unmark the state as non-reusable. It can then
      * be switched back using {@link #markReusable markReusable}.
+     * </p>
      */
     void unmarkReusable();
 
@@ -194,9 +201,9 @@ public interface ManagedClientConnection extends
      * See {@link #markReusable markReusable} and
      * {@link #unmarkReusable unmarkReusable} for details.
      *
-     * @return  <code>true</code> if this connection is marked as being in
+     * @return  {@code true} if this connection is marked as being in
      *          a reusable communication state,
-     *          <code>false</code> otherwise
+     *          {@code false} otherwise
      */
     boolean isMarkedReusable();
 
diff --git a/httpclient/src/main/java/org/apache/http/conn/ManagedHttpClientConnection.java b/httpclient/src/main/java/org/apache/http/conn/ManagedHttpClientConnection.java
index 7a98420..44cd60f 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ManagedHttpClientConnection.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ManagedHttpClientConnection.java
@@ -73,7 +73,7 @@ public interface ManagedHttpClientConnection extends HttpClientConnection, HttpI
      * that socket is obtained. This is a potentially blocking operation.
      *
      * @return  the underlying SSL session if available,
-     *          <code>null</code> otherwise
+     *          {@code null} otherwise
      */
     SSLSession getSSLSession();
 
diff --git a/httpclient/src/main/java/org/apache/http/conn/routing/BasicRouteDirector.java b/httpclient/src/main/java/org/apache/http/conn/routing/BasicRouteDirector.java
index 2963019..eff3f04 100644
--- a/httpclient/src/main/java/org/apache/http/conn/routing/BasicRouteDirector.java
+++ b/httpclient/src/main/java/org/apache/http/conn/routing/BasicRouteDirector.java
@@ -43,12 +43,13 @@ public class BasicRouteDirector implements HttpRouteDirector {
      *
      * @param plan      the planned route
      * @param fact      the currently established route, or
-     *                  <code>null</code> if nothing is established
+     *                  {@code null} if nothing is established
      *
      * @return  one of the constants defined in this class, indicating
      *          either the next step to perform, or success, or failure.
      *          0 is for success, a negative value for failure.
      */
+    @Override
     public int nextStep(final RouteInfo plan, final RouteInfo fact) {
         Args.notNull(plan, "Planned route");
 
diff --git a/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java b/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java
index b841243..847fa7e 100644
--- a/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java
+++ b/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java
@@ -52,7 +52,7 @@ public final class HttpRoute implements RouteInfo, Cloneable {
 
     /**
      * The local address to connect from.
-     * <code>null</code> indicates that the default should be used.
+     * {@code null} indicates that the default should be used.
      */
     private final InetAddress localAddress;
 
@@ -71,7 +71,7 @@ public final class HttpRoute implements RouteInfo, Cloneable {
     private HttpRoute(final HttpHost target, final InetAddress local, final List<HttpHost> proxies,
                      final boolean secure, final TunnelType tunnelled, final LayerType layered) {
         Args.notNull(target, "Target host");
-        this.targetHost   = target;
+        this.targetHost = normalize(target);
         this.localAddress = local;
         if (proxies != null && !proxies.isEmpty()) {
             this.proxyChain = new ArrayList<HttpHost>(proxies);
@@ -86,16 +86,44 @@ public final class HttpRoute implements RouteInfo, Cloneable {
         this.layered      = layered != null ? layered : LayerType.PLAIN;
     }
 
+    //TODO: to be removed in 5.0
+    private static int getDefaultPort(final String schemeName) {
+        if ("http".equalsIgnoreCase(schemeName)) {
+            return 80;
+        } else if ("https".equalsIgnoreCase(schemeName)) {
+            return 443;
+        } else {
+            return -1;
+        }
+
+    }
+
+    //TODO: to be removed in 5.0
+    private static HttpHost normalize(final HttpHost target) {
+        if (target.getPort() >= 0 ) {
+            return target;
+        } else {
+            final InetAddress address = target.getAddress();
+            final String schemeName = target.getSchemeName();
+            if (address != null) {
+                return new HttpHost(address, getDefaultPort(schemeName), schemeName);
+            } else {
+                final String hostName = target.getHostName();
+                return new HttpHost(hostName, getDefaultPort(schemeName), schemeName);
+            }
+        }
+    }
+
     /**
      * Creates a new route with all attributes specified explicitly.
      *
      * @param target    the host to which to route
      * @param local     the local address to route from, or
-     *                  <code>null</code> for the default
+     *                  {@code null} for the default
      * @param proxies   the proxy chain to use, or
-     *                  <code>null</code> for a direct route
-     * @param secure    <code>true</code> if the route is (to be) secure,
-     *                  <code>false</code> otherwise
+     *                  {@code null} for a direct route
+     * @param secure    {@code true} if the route is (to be) secure,
+     *                  {@code false} otherwise
      * @param tunnelled the tunnel type of this route
      * @param layered   the layering type of this route
      */
@@ -110,17 +138,17 @@ public final class HttpRoute implements RouteInfo, Cloneable {
      *
      * @param target    the host to which to route
      * @param local     the local address to route from, or
-     *                  <code>null</code> for the default
+     *                  {@code null} for the default
      * @param proxy     the proxy to use, or
-     *                  <code>null</code> for a direct route
-     * @param secure    <code>true</code> if the route is (to be) secure,
-     *                  <code>false</code> otherwise
-     * @param tunnelled <code>true</code> if the route is (to be) tunnelled
+     *                  {@code null} for a direct route
+     * @param secure    {@code true} if the route is (to be) secure,
+     *                  {@code false} otherwise
+     * @param tunnelled {@code true} if the route is (to be) tunnelled
      *                  via the proxy,
-     *                  <code>false</code> otherwise
-     * @param layered   <code>true</code> if the route includes a
+     *                  {@code false} otherwise
+     * @param layered   {@code true} if the route includes a
      *                  layered protocol,
-     *                  <code>false</code> otherwise
+     *                  {@code false} otherwise
      */
     public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
                      final boolean secure, final TunnelType tunnelled, final LayerType layered) {
@@ -134,9 +162,9 @@ public final class HttpRoute implements RouteInfo, Cloneable {
      *
      * @param target    the host to which to route
      * @param local     the local address to route from, or
-     *                  <code>null</code> for the default
-     * @param secure    <code>true</code> if the route is (to be) secure,
-     *                  <code>false</code> otherwise
+     *                  {@code null} for the default
+     * @param secure    {@code true} if the route is (to be) secure,
+     *                  {@code false} otherwise
      */
     public HttpRoute(final HttpHost target, final InetAddress local, final boolean secure) {
         this(target, local, Collections.<HttpHost>emptyList(), secure,
@@ -155,16 +183,16 @@ public final class HttpRoute implements RouteInfo, Cloneable {
 
     /**
      * Creates a new route through a proxy.
-     * When using this constructor, the <code>proxy</code> MUST be given.
+     * When using this constructor, the {@code proxy} MUST be given.
      * For convenience, it is assumed that a secure connection will be
      * layered over a tunnel through the proxy.
      *
      * @param target    the host to which to route
      * @param local     the local address to route from, or
-     *                  <code>null</code> for the default
+     *                  {@code null} for the default
      * @param proxy     the proxy to use
-     * @param secure    <code>true</code> if the route is (to be) secure,
-     *                  <code>false</code> otherwise
+     * @param secure    {@code true} if the route is (to be) secure,
+     *                  {@code false} otherwise
      */
     public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
                      final boolean secure) {
@@ -185,10 +213,12 @@ public final class HttpRoute implements RouteInfo, Cloneable {
         this(target, null, proxy, false);
     }
 
+    @Override
     public final HttpHost getTargetHost() {
         return this.targetHost;
     }
 
+    @Override
     public final InetAddress getLocalAddress() {
         return this.localAddress;
     }
@@ -197,10 +227,12 @@ public final class HttpRoute implements RouteInfo, Cloneable {
         return this.localAddress != null ? new InetSocketAddress(this.localAddress, 0) : null;
     }
 
+    @Override
     public final int getHopCount() {
         return proxyChain != null ? proxyChain.size() + 1 : 1;
     }
 
+    @Override
     public final HttpHost getHopTarget(final int hop) {
         Args.notNegative(hop, "Hop index");
         final int hopcount = getHopCount();
@@ -212,26 +244,32 @@ public final class HttpRoute implements RouteInfo, Cloneable {
         }
     }
 
+    @Override
     public final HttpHost getProxyHost() {
         return proxyChain != null && !this.proxyChain.isEmpty() ? this.proxyChain.get(0) : null;
     }
 
+    @Override
     public final TunnelType getTunnelType() {
         return this.tunnelled;
     }
 
+    @Override
     public final boolean isTunnelled() {
         return (this.tunnelled == TunnelType.TUNNELLED);
     }
 
+    @Override
     public final LayerType getLayerType() {
         return this.layered;
     }
 
+    @Override
     public final boolean isLayered() {
         return (this.layered == LayerType.LAYERED);
     }
 
+    @Override
     public final boolean isSecure() {
         return this.secure;
     }
@@ -241,8 +279,8 @@ public final class HttpRoute implements RouteInfo, Cloneable {
      *
      * @param obj         the object to compare with
      *
-     * @return  <code>true</code> if the argument is the same route,
-     *          <code>false</code>
+     * @return  {@code true} if the argument is the same route,
+     *          {@code false}
      */
     @Override
     public final boolean equals(final Object obj) {
diff --git a/httpclient/src/main/java/org/apache/http/conn/routing/HttpRouteDirector.java b/httpclient/src/main/java/org/apache/http/conn/routing/HttpRouteDirector.java
index 410dcf7..d6e9d25 100644
--- a/httpclient/src/main/java/org/apache/http/conn/routing/HttpRouteDirector.java
+++ b/httpclient/src/main/java/org/apache/http/conn/routing/HttpRouteDirector.java
@@ -63,7 +63,7 @@ public interface HttpRouteDirector {
      *
      * @param plan      the planned route
      * @param fact      the currently established route, or
-     *                  <code>null</code> if nothing is established
+     *                  {@code null} if nothing is established
      *
      * @return  one of the constants defined in this interface, indicating
      *          either the next step to perform, or success, or failure.
diff --git a/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoutePlanner.java b/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoutePlanner.java
index 254f1ed..76297d4 100644
--- a/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoutePlanner.java
+++ b/httpclient/src/main/java/org/apache/http/conn/routing/HttpRoutePlanner.java
@@ -36,10 +36,11 @@ import org.apache.http.protocol.HttpContext;
  * Encapsulates logic to compute a {@link HttpRoute} to a target host.
  * Implementations may for example be based on parameters, or on the
  * standard Java system properties.
- * <p/>
+ * <p>
  * Implementations of this interface must be thread-safe. Access to shared
  * data must be synchronized as methods of this interface may be executed
  * from multiple threads.
+ * </p>
  *
  * @since 4.0
  */
@@ -49,12 +50,12 @@ public interface HttpRoutePlanner {
      * Determines the route for a request.
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
      * @param context   the context to use for the subsequent execution.
-     *                  Implementations may accept <code>null</code>.
+     *                  Implementations may accept {@code null}.
      *
      * @return  the route that the request should take
      *
diff --git a/httpclient/src/main/java/org/apache/http/conn/routing/RouteInfo.java b/httpclient/src/main/java/org/apache/http/conn/routing/RouteInfo.java
index 9ea6b1b..59c37a2 100644
--- a/httpclient/src/main/java/org/apache/http/conn/routing/RouteInfo.java
+++ b/httpclient/src/main/java/org/apache/http/conn/routing/RouteInfo.java
@@ -55,11 +55,12 @@ public interface RouteInfo {
      * over an existing connection.
      * Protocols can only be layered over a tunnel to the target, or
      * or over a direct connection without proxies.
-     * <br/>
+     * <p>
      * Layering a protocol
      * over a direct connection makes little sense, since the connection
      * could be established with the new protocol in the first place.
      * But we don't want to exclude that use case.
+     * </p>
      */
     public enum LayerType  { PLAIN, LAYERED }
 
@@ -74,7 +75,7 @@ public interface RouteInfo {
      * Obtains the local address to connect from.
      *
      * @return  the local address,
-     *          or <code>null</code>
+     *          or {@code null}
      */
     InetAddress getLocalAddress();
 
@@ -109,7 +110,7 @@ public interface RouteInfo {
      * Obtains the first proxy host.
      *
      * @return the first proxy in the proxy chain, or
-     *         <code>null</code> if this route is direct
+     *         {@code null} if this route is direct
      */
     HttpHost getProxyHost();
 
@@ -125,9 +126,9 @@ public interface RouteInfo {
      * Checks whether this route is tunnelled through a proxy.
      * If there is a proxy chain, only end-to-end tunnels are considered.
      *
-     * @return  <code>true</code> if tunnelled end-to-end through at least
+     * @return  {@code true} if tunnelled end-to-end through at least
      *          one proxy,
-     *          <code>false</code> otherwise
+     *          {@code false} otherwise
      */
     boolean isTunnelled();
 
@@ -145,16 +146,16 @@ public interface RouteInfo {
      * In the presence of proxies, only layering over an end-to-end tunnel
      * is considered.
      *
-     * @return  <code>true</code> if layered,
-     *          <code>false</code> otherwise
+     * @return  {@code true} if layered,
+     *          {@code false} otherwise
      */
     boolean isLayered();
 
     /**
      * Checks whether this route is secure.
      *
-     * @return  <code>true</code> if secure,
-     *          <code>false</code> otherwise
+     * @return  {@code true} if secure,
+     *          {@code false} otherwise
      */
     boolean isSecure();
 
diff --git a/httpclient/src/main/java/org/apache/http/conn/routing/RouteTracker.java b/httpclient/src/main/java/org/apache/http/conn/routing/RouteTracker.java
index f1d808d..e550799 100644
--- a/httpclient/src/main/java/org/apache/http/conn/routing/RouteTracker.java
+++ b/httpclient/src/main/java/org/apache/http/conn/routing/RouteTracker.java
@@ -48,7 +48,7 @@ public final class RouteTracker implements RouteInfo, Cloneable {
 
     /**
      * The local address to connect from.
-     * <code>null</code> indicates that the default should be used.
+     * {@code null} indicates that the default should be used.
      */
     private final InetAddress localAddress;
 
@@ -76,7 +76,7 @@ public final class RouteTracker implements RouteInfo, Cloneable {
      *
      * @param target    the host to which to route
      * @param local     the local address to route from, or
-     *                  <code>null</code> for the default
+     *                  {@code null} for the default
      */
     public RouteTracker(final HttpHost target, final InetAddress local) {
         Args.notNull(target, "Target host");
@@ -111,8 +111,8 @@ public final class RouteTracker implements RouteInfo, Cloneable {
     /**
      * Tracks connecting to the target.
      *
-     * @param secure    <code>true</code> if the route is secure,
-     *                  <code>false</code> otherwise
+     * @param secure    {@code true} if the route is secure,
+     *                  {@code false} otherwise
      */
     public final void connectTarget(final boolean secure) {
         Asserts.check(!this.connected, "Already connected");
@@ -124,8 +124,8 @@ public final class RouteTracker implements RouteInfo, Cloneable {
      * Tracks connecting to the first proxy.
      *
      * @param proxy     the proxy connected to
-     * @param secure    <code>true</code> if the route is secure,
-     *                  <code>false</code> otherwise
+     * @param secure    {@code true} if the route is secure,
+     *                  {@code false} otherwise
      */
     public final void connectProxy(final HttpHost proxy, final boolean secure) {
         Args.notNull(proxy, "Proxy host");
@@ -138,8 +138,8 @@ public final class RouteTracker implements RouteInfo, Cloneable {
     /**
      * Tracks tunnelling to the target.
      *
-     * @param secure    <code>true</code> if the route is secure,
-     *                  <code>false</code> otherwise
+     * @param secure    {@code true} if the route is secure,
+     *                  {@code false} otherwise
      */
     public final void tunnelTarget(final boolean secure) {
         Asserts.check(this.connected, "No tunnel unless connected");
@@ -154,8 +154,8 @@ public final class RouteTracker implements RouteInfo, Cloneable {
      * the route as tunnelled. Only end-to-end tunnels are considered there.
      *
      * @param proxy     the proxy tunnelled to
-     * @param secure    <code>true</code> if the route is secure,
-     *                  <code>false</code> otherwise
+     * @param secure    {@code true} if the route is secure,
+     *                  {@code false} otherwise
      */
     public final void tunnelProxy(final HttpHost proxy, final boolean secure) {
         Args.notNull(proxy, "Proxy host");
@@ -174,8 +174,8 @@ public final class RouteTracker implements RouteInfo, Cloneable {
     /**
      * Tracks layering a protocol.
      *
-     * @param secure    <code>true</code> if the route is secure,
-     *                  <code>false</code> otherwise
+     * @param secure    {@code true} if the route is secure,
+     *                  {@code false} otherwise
      */
     public final void layerProtocol(final boolean secure) {
         // it is possible to layer a protocol over a direct connection,
@@ -185,14 +185,17 @@ public final class RouteTracker implements RouteInfo, Cloneable {
         this.secure  = secure;
     }
 
+    @Override
     public final HttpHost getTargetHost() {
         return this.targetHost;
     }
 
+    @Override
     public final InetAddress getLocalAddress() {
         return this.localAddress;
     }
 
+    @Override
     public final int getHopCount() {
         int hops = 0;
         if (this.connected) {
@@ -205,6 +208,7 @@ public final class RouteTracker implements RouteInfo, Cloneable {
         return hops;
     }
 
+    @Override
     public final HttpHost getHopTarget(final int hop) {
         Args.notNegative(hop, "Hop index");
         final int hopcount = getHopCount();
@@ -219,6 +223,7 @@ public final class RouteTracker implements RouteInfo, Cloneable {
         return result;
     }
 
+    @Override
     public final HttpHost getProxyHost() {
         return (this.proxyChain == null) ? null : this.proxyChain[0];
     }
@@ -227,22 +232,27 @@ public final class RouteTracker implements RouteInfo, Cloneable {
         return this.connected;
     }
 
+    @Override
     public final TunnelType getTunnelType() {
         return this.tunnelled;
     }
 
+    @Override
     public final boolean isTunnelled() {
         return (this.tunnelled == TunnelType.TUNNELLED);
     }
 
+    @Override
     public final LayerType getLayerType() {
         return this.layered;
     }
 
+    @Override
     public final boolean isLayered() {
         return (this.layered == LayerType.LAYERED);
     }
 
+    @Override
     public final boolean isSecure() {
         return this.secure;
     }
@@ -253,7 +263,7 @@ public final class RouteTracker implements RouteInfo, Cloneable {
      * If not connected, nothing has been tracked so far.
      *
      * @return  the tracked route, or
-     *          <code>null</code> if nothing has been tracked so far
+     *          {@code null} if nothing has been tracked so far
      */
     public final HttpRoute toRoute() {
         return !this.connected ?
@@ -267,8 +277,8 @@ public final class RouteTracker implements RouteInfo, Cloneable {
      *
      * @param o         the object to compare with
      *
-     * @return  <code>true</code> if the argument is the same tracked route,
-     *          <code>false</code>
+     * @return  {@code true} if the argument is the same tracked route,
+     *          {@code false}
      */
     @Override
     public final boolean equals(final Object o) {
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/LayeredSocketFactoryAdaptor.java b/httpclient/src/main/java/org/apache/http/conn/scheme/LayeredSocketFactoryAdaptor.java
index c836931..017d968 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/LayeredSocketFactoryAdaptor.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/LayeredSocketFactoryAdaptor.java
@@ -44,6 +44,7 @@ class LayeredSocketFactoryAdaptor extends SocketFactoryAdaptor implements Layere
         this.factory = factory;
     }
 
+    @Override
     public Socket createSocket(
             final Socket socket,
             final String host, final int port, final boolean autoClose) throws IOException, UnknownHostException {
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/Scheme.java b/httpclient/src/main/java/org/apache/http/conn/scheme/Scheme.java
index 4a66773..68d7aa9 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/Scheme.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/Scheme.java
@@ -36,8 +36,9 @@ import org.apache.http.util.LangUtils;
  * Encapsulates specifics of a protocol scheme such as "http" or "https". Schemes are identified
  * by lowercase names. Supported schemes are typically collected in a {@link SchemeRegistry
  * SchemeRegistry}.
- * <p/>
+ * <p>
  * For example, to configure support for "https://" URLs, you could write code like the following:
+ * </p>
  * <pre>
  * Scheme https = new Scheme("https", 443, new MySecureSocketFactory());
  * SchemeRegistry registry = new SchemeRegistry();
@@ -76,7 +77,7 @@ public final class Scheme {
     /**
      * Creates a new scheme.
      * Whether the created scheme allows for layered connections
-     * depends on the class of <code>factory</code>.
+     * depends on the class of {@code factory}.
      *
      * @param name      the scheme name, for example "http".
      *                  The name will be converted to lowercase.
@@ -107,7 +108,7 @@ public final class Scheme {
     /**
      * Creates a new scheme.
      * Whether the created scheme allows for layered connections
-     * depends on the class of <code>factory</code>.
+     * depends on the class of {@code factory}.
      *
      * @param name      the scheme name, for example "http".
      *                  The name will be converted to lowercase.
@@ -196,8 +197,8 @@ public final class Scheme {
     /**
      * Indicates whether this scheme allows for layered connections.
      *
-     * @return <code>true</code> if layered connections are possible,
-     *         <code>false</code> otherwise
+     * @return {@code true} if layered connections are possible,
+     *         {@code false} otherwise
      */
     public final boolean isLayered() {
         return layered;
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor.java b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor.java
index c4d5618..24204c6 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor.java
@@ -47,6 +47,7 @@ class SchemeLayeredSocketFactoryAdaptor extends SchemeSocketFactoryAdaptor
         this.factory = factory;
     }
 
+    @Override
     public Socket createLayeredSocket(
             final Socket socket,
             final String target, final int port,
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor2.java b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor2.java
index 4d10630..2b23641 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor2.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeLayeredSocketFactoryAdaptor2.java
@@ -48,10 +48,12 @@ class SchemeLayeredSocketFactoryAdaptor2 implements SchemeLayeredSocketFactory {
         this.factory = factory;
     }
 
+    @Override
     public Socket createSocket(final HttpParams params) throws IOException {
         return this.factory.createSocket(params);
     }
 
+    @Override
     public Socket connectSocket(
             final Socket sock,
             final InetSocketAddress remoteAddress,
@@ -60,10 +62,12 @@ class SchemeLayeredSocketFactoryAdaptor2 implements SchemeLayeredSocketFactory {
         return this.factory.connectSocket(sock, remoteAddress, localAddress, params);
     }
 
+    @Override
     public boolean isSecure(final Socket sock) throws IllegalArgumentException {
         return this.factory.isSecure(sock);
     }
 
+    @Override
     public Socket createLayeredSocket(
             final Socket socket,
             final String target, final int port,
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeRegistry.java b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeRegistry.java
index de5ac10..6928ce5 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeRegistry.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeRegistry.java
@@ -63,7 +63,7 @@ public final class SchemeRegistry {
      *
      * @param name      the name of the scheme to look up (in lowercase)
      *
-     * @return  the scheme, never <code>null</code>
+     * @return  the scheme, never {@code null}
      *
      * @throws IllegalStateException
      *          if the scheme with the given name is not registered
@@ -79,11 +79,11 @@ public final class SchemeRegistry {
 
     /**
      * Obtains the scheme for a host.
-     * Convenience method for <code>getScheme(host.getSchemeName())</pre>
+     * Convenience method for {@code getScheme(host.getSchemeName())}
      *
-     * @param host      the host for which to obtain the scheme
+     * @param host the host for which to obtain the scheme
      *
-     * @return  the scheme for the given host, never <code>null</code>
+     * @return the scheme for the given host, never {@code null}
      *
      * @throws IllegalStateException
      *          if a scheme with the respective name is not registered
@@ -99,7 +99,7 @@ public final class SchemeRegistry {
      * @param name      the name of the scheme to look up (in lowercase)
      *
      * @return  the scheme, or
-     *          <code>null</code> if there is none by this name
+     *          {@code null} if there is none by this name
      */
     public final Scheme get(final String name) {
         Args.notNull(name, "Scheme name");
@@ -117,7 +117,7 @@ public final class SchemeRegistry {
      * @param sch       the scheme to register
      *
      * @return  the scheme previously registered with that name, or
-     *          <code>null</code> if none was registered
+     *          {@code null} if none was registered
      */
     public final Scheme register(final Scheme sch) {
         Args.notNull(sch, "Scheme");
@@ -131,7 +131,7 @@ public final class SchemeRegistry {
      * @param name      the name of the scheme to unregister (in lowercase)
      *
      * @return  the unregistered scheme, or
-     *          <code>null</code> if there was none
+     *          {@code null} if there was none
      */
     public final Scheme unregister(final String name) {
         Args.notNull(name, "Scheme name");
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactory.java b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactory.java
index f2f1a75..2501c1c 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactory.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactory.java
@@ -66,32 +66,33 @@ public interface SchemeSocketFactory {
 
     /**
      * Connects a socket to the target host with the given remote address.
-     * <p/>
+     * <p>
      * Please note that {@link org.apache.http.conn.HttpInetSocketAddress} class should
      * be used in order to pass the target remote address along with the original
      * {@link org.apache.http.HttpHost} value used to resolve the address. The use of
      * {@link org.apache.http.conn.HttpInetSocketAddress} can also ensure that no reverse
      * DNS lookup will be performed if the target remote address was specified
      * as an IP address.
+     * </p>
      *
      * @param sock      the socket to connect, as obtained from
      *                  {@link #createSocket(HttpParams) createSocket}.
-     *                  <code>null</code> indicates that a new socket
+     *                  {@code null} indicates that a new socket
      *                  should be created and connected.
      * @param remoteAddress the remote address to connect to.
      * @param localAddress the local address to bind the socket to, or
-     *                  <code>null</code> for any
+     *                  {@code null} for any
      * @param params    additional {@link HttpParams parameters} for connecting
      *
      * @return  the connected socket. The returned object may be different
-     *          from the <code>sock</code> argument if this factory supports
+     *          from the {@code sock} argument if this factory supports
      *          a layered protocol.
      *
      * @throws IOException if an I/O error occurs
      * @throws UnknownHostException if the IP address of the target host
      *          can not be determined
      * @throws ConnectTimeoutException if the socket cannot be connected
-     *          within the time limit defined in the <code>params</code>
+     *          within the time limit defined in the {@code params}
      *
      * @see org.apache.http.conn.HttpInetSocketAddress
      */
@@ -113,9 +114,9 @@ public interface SchemeSocketFactory {
      *
      * @param sock      the connected socket to check
      *
-     * @return  <code>true</code> if the connection of the socket
+     * @return  {@code true} if the connection of the socket
      *          should be considered secure, or
-     *          <code>false</code> if it should not
+     *          {@code false} if it should not
      *
      * @throws IllegalArgumentException
      *  if the argument is invalid, for example because it is
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactoryAdaptor.java b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactoryAdaptor.java
index 70023a6..08de43e 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactoryAdaptor.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/SchemeSocketFactoryAdaptor.java
@@ -49,6 +49,7 @@ class SchemeSocketFactoryAdaptor implements SchemeSocketFactory {
         this.factory = factory;
     }
 
+    @Override
     public Socket connectSocket(
             final Socket sock,
             final InetSocketAddress remoteAddress,
@@ -65,10 +66,12 @@ class SchemeSocketFactoryAdaptor implements SchemeSocketFactory {
         return this.factory.connectSocket(sock, host, port, local, localPort, params);
     }
 
+    @Override
     public Socket createSocket(final HttpParams params) throws IOException {
         return this.factory.createSocket();
     }
 
+    @Override
     public boolean isSecure(final Socket sock) throws IllegalArgumentException {
         return this.factory.isSecure(sock);
     }
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactory.java b/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactory.java
index 99cbf50..7d1736d 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactory.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactory.java
@@ -63,25 +63,25 @@ public interface SocketFactory {
      *
      * @param sock      the socket to connect, as obtained from
      *                  {@link #createSocket createSocket}.
-     *                  <code>null</code> indicates that a new socket
+     *                  {@code null} indicates that a new socket
      *                  should be created and connected.
      * @param host      the host to connect to
      * @param port      the port to connect to on the host
      * @param localAddress the local address to bind the socket to, or
-     *                  <code>null</code> for any
+     *                  {@code null} for any
      * @param localPort the port on the local machine,
      *                  0 or a negative number for any
      * @param params    additional {@link HttpParams parameters} for connecting
      *
      * @return  the connected socket. The returned object may be different
-     *          from the <code>sock</code> argument if this factory supports
+     *          from the {@code sock} argument if this factory supports
      *          a layered protocol.
      *
      * @throws IOException if an I/O error occurs
      * @throws UnknownHostException if the IP address of the target host
      *          can not be determined
      * @throws ConnectTimeoutException if the socket cannot be connected
-     *          within the time limit defined in the <code>params</code>
+     *          within the time limit defined in the {@code params}
      */
     Socket connectSocket(
         Socket sock,
@@ -98,7 +98,7 @@ public interface SocketFactory {
      * by this factory.
      * The factory will <i>not</i> perform I/O operations
      * in this method.
-     * <br/>
+     * <p>
      * As a rule of thumb, plain sockets are not secure and
      * TLS/SSL sockets are secure. However, there may be
      * application specific deviations. For example, a plain
@@ -106,12 +106,13 @@ public interface SocketFactory {
      * could be considered secure. On the other hand, a
      * TLS/SSL socket could be considered insecure based on
      * the cipher suite chosen for the connection.
+     * </p>
      *
      * @param sock      the connected socket to check
      *
-     * @return  <code>true</code> if the connection of the socket
+     * @return  {@code true} if the connection of the socket
      *          should be considered secure, or
-     *          <code>false</code> if it should not
+     *          {@code false} if it should not
      *
      * @throws IllegalArgumentException
      *  if the argument is invalid, for example because it is
diff --git a/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactoryAdaptor.java b/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactoryAdaptor.java
index 8e4a5cc..3a9f9a0 100644
--- a/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactoryAdaptor.java
+++ b/httpclient/src/main/java/org/apache/http/conn/scheme/SocketFactoryAdaptor.java
@@ -47,11 +47,13 @@ class SocketFactoryAdaptor implements SocketFactory {
         this.factory = factory;
     }
 
+    @Override
     public Socket createSocket() throws IOException {
         final HttpParams params = new BasicHttpParams();
         return this.factory.createSocket(params);
     }
 
+    @Override
     public Socket connectSocket(
             final Socket socket,
             final String host, final int port,
@@ -66,6 +68,7 @@ class SocketFactoryAdaptor implements SocketFactory {
         return this.factory.connectSocket(socket, remote, local, params);
     }
 
+    @Override
     public boolean isSecure(final Socket socket) throws IllegalArgumentException {
         return this.factory.isSecure(socket);
     }
diff --git a/httpclient/src/main/java/org/apache/http/conn/socket/ConnectionSocketFactory.java b/httpclient/src/main/java/org/apache/http/conn/socket/ConnectionSocketFactory.java
index 29ee7b4..9c751b7 100644
--- a/httpclient/src/main/java/org/apache/http/conn/socket/ConnectionSocketFactory.java
+++ b/httpclient/src/main/java/org/apache/http/conn/socket/ConnectionSocketFactory.java
@@ -57,14 +57,14 @@ public interface ConnectionSocketFactory {
      *
      * @param connectTimeout connect timeout.
      * @param sock the socket to connect, as obtained from {@link #createSocket(HttpContext)}.
-     * <code>null</code> indicates that a new socket should be created and connected.
+     * {@code null} indicates that a new socket should be created and connected.
      * @param host target host as specified by the caller (end user).
      * @param remoteAddress the resolved remote address to connect to.
-     * @param localAddress the local address to bind the socket to, or <code>null</code> for any.
+     * @param localAddress the local address to bind the socket to, or {@code null} for any.
      * @param context the actual HTTP context.
      *
      * @return  the connected socket. The returned object may be different
-     *          from the <code>sock</code> argument if this factory supports
+     *          from the {@code sock} argument if this factory supports
      *          a layered protocol.
      *
      * @throws IOException if an I/O error occurs
diff --git a/httpclient/src/main/java/org/apache/http/conn/socket/PlainConnectionSocketFactory.java b/httpclient/src/main/java/org/apache/http/conn/socket/PlainConnectionSocketFactory.java
index 0d373f4..193e73d 100644
--- a/httpclient/src/main/java/org/apache/http/conn/socket/PlainConnectionSocketFactory.java
+++ b/httpclient/src/main/java/org/apache/http/conn/socket/PlainConnectionSocketFactory.java
@@ -53,10 +53,12 @@ public class PlainConnectionSocketFactory implements ConnectionSocketFactory {
         super();
     }
 
+    @Override
     public Socket createSocket(final HttpContext context) throws IOException {
         return new Socket();
     }
 
+    @Override
     public Socket connectSocket(
             final int connectTimeout,
             final Socket socket,
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java b/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java
index 3c3580f..81d4d7e 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java
@@ -29,75 +29,49 @@ package org.apache.http.conn.ssl;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
 import java.security.cert.Certificate;
-import java.security.cert.CertificateParsingException;
 import java.security.cert.X509Certificate;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
-import java.util.NoSuchElementException;
 
-import javax.naming.InvalidNameException;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
+import javax.security.auth.x500.X500Principal;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.http.annotation.Immutable;
 import org.apache.http.conn.util.InetAddressUtils;
+import org.apache.http.util.Args;
 
 /**
  * Abstract base class for all standard {@link X509HostnameVerifier}
  * implementations.
  *
  * @since 4.0
+ *
+ * @deprecated (4.4) use an implementation of {@link javax.net.ssl.HostnameVerifier} or
+ *  {@link DefaultHostnameVerifier}.
  */
- at Immutable
+ at Deprecated
 public abstract class AbstractVerifier implements X509HostnameVerifier {
 
-    /**
-     * This contains a list of 2nd-level domains that aren't allowed to
-     * have wildcards when combined with country-codes.
-     * For example: [*.co.uk].
-     * <p/>
-     * The [*.co.uk] problem is an interesting one.  Should we just hope
-     * that CA's would never foolishly allow such a certificate to happen?
-     * Looks like we're the only implementation guarding against this.
-     * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
-     */
-    private final static String[] BAD_COUNTRY_2LDS =
-          { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
-            "lg", "ne", "net", "or", "org" };
+    private final Log log = LogFactory.getLog(getClass());
+
+    final static String[] BAD_COUNTRY_2LDS =
+            { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
+                    "lg", "ne", "net", "or", "org" };
 
     static {
         // Just in case developer forgot to manually sort the array.  :-)
         Arrays.sort(BAD_COUNTRY_2LDS);
     }
 
-    private final Log log = LogFactory.getLog(getClass());
-
-    public AbstractVerifier() {
-        super();
-    }
-
+    @Override
     public final void verify(final String host, final SSLSocket ssl)
-          throws IOException {
-        if(host == null) {
-            throw new NullPointerException("host to verify is null");
-        }
-
+            throws IOException {
+        Args.notNull(host, "Host");
         SSLSession session = ssl.getSession();
         if(session == null) {
             // In our experience this only happens under IBM 1.4.x when
@@ -140,222 +114,140 @@ public abstract class AbstractVerifier implements X509HostnameVerifier {
         verify(host, x509);
     }
 
+    @Override
     public final boolean verify(final String host, final SSLSession session) {
         try {
             final Certificate[] certs = session.getPeerCertificates();
             final X509Certificate x509 = (X509Certificate) certs[0];
             verify(host, x509);
             return true;
-        }
-        catch(final SSLException e) {
+        } catch(final SSLException ex) {
+            if (log.isDebugEnabled()) {
+                log.debug(ex.getMessage(), ex);
+            }
             return false;
         }
     }
 
-    public final void verify(final String host, final X509Certificate cert)
-          throws SSLException {
-        final String[] cns = getCNs(cert);
-        final String[] subjectAlts = getSubjectAlts(cert, host);
-        verify(host, cns, subjectAlts);
+    public final void verify(
+            final String host, final X509Certificate cert) throws SSLException {
+        final boolean ipv4 = InetAddressUtils.isIPv4Address(host);
+        final boolean ipv6 = InetAddressUtils.isIPv6Address(host);
+        final int subjectType = ipv4 || ipv6 ? DefaultHostnameVerifier.IP_ADDRESS_TYPE : DefaultHostnameVerifier.DNS_NAME_TYPE;
+        final List<String> subjectAlts = DefaultHostnameVerifier.extractSubjectAlts(cert, subjectType);
+        final X500Principal subjectPrincipal = cert.getSubjectX500Principal();
+        final String cn = DefaultHostnameVerifier.extractCN(subjectPrincipal.getName(X500Principal.RFC2253));
+        verify(host,
+                cn != null ? new String[] {cn} : null,
+                subjectAlts != null && !subjectAlts.isEmpty() ? subjectAlts.toArray(new String[subjectAlts.size()]) : null);
     }
 
     public final void verify(final String host, final String[] cns,
                              final String[] subjectAlts,
                              final boolean strictWithSubDomains)
-          throws SSLException {
+            throws SSLException {
 
-        // Build the list of names we're going to check.  Our DEFAULT and
-        // STRICT implementations of the HostnameVerifier only use the
-        // first CN provided.  All other CNs are ignored.
-        // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
-        final LinkedList<String> names = new LinkedList<String>();
-        if(cns != null && cns.length > 0 && cns[0] != null) {
-            names.add(cns[0]);
-        }
-        if(subjectAlts != null) {
-            for (final String subjectAlt : subjectAlts) {
-                if (subjectAlt != null) {
-                    names.add(subjectAlt);
+        final String cn = cns != null && cns.length > 0 ? cns[0] : null;
+        final List<String> subjectAltList = subjectAlts != null && subjectAlts.length > 0 ? Arrays.asList(subjectAlts) : null;
+
+        final String normalizedHost = InetAddressUtils.isIPv6Address(host) ?
+                DefaultHostnameVerifier.normaliseAddress(host.toLowerCase(Locale.ROOT)) : host;
+
+        if (subjectAltList != null) {
+            for (String subjectAlt: subjectAltList) {
+                final String normalizedAltSubject = InetAddressUtils.isIPv6Address(subjectAlt) ?
+                        DefaultHostnameVerifier.normaliseAddress(subjectAlt) : subjectAlt;
+                if (matchIdentity(normalizedHost, normalizedAltSubject, strictWithSubDomains)) {
+                    return;
                 }
             }
+            throw new SSLException("Certificate for <" + host + "> doesn't match any " +
+                    "of the subject alternative names: " + subjectAltList);
+        } else if (cn != null) {
+            final String normalizedCN = InetAddressUtils.isIPv6Address(cn) ?
+                    DefaultHostnameVerifier.normaliseAddress(cn) : cn;
+            if (matchIdentity(normalizedHost, normalizedCN, strictWithSubDomains)) {
+                return;
+            }
+            throw new SSLException("Certificate for <" + host + "> doesn't match " +
+                    "common name of the certificate subject: " + cn);
+        } else {
+            throw new SSLException("Certificate subject for <" + host + "> doesn't contain " +
+                    "a common name and does not have alternative names");
         }
+    }
 
-        if(names.isEmpty()) {
-            final String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
-            throw new SSLException(msg);
+    private static boolean matchIdentity(final String host, final String identity, final boolean strict) {
+        if (host == null) {
+            return false;
         }
-
-        // StringBuilder for building the error message.
-        final StringBuilder buf = new StringBuilder();
-
-        // We're can be case-insensitive when comparing the host we used to
-        // establish the socket to the hostname in the certificate.
-        final String hostName = normaliseIPv6Address(host.trim().toLowerCase(Locale.ENGLISH));
-        boolean match = false;
-        for(final Iterator<String> it = names.iterator(); it.hasNext();) {
-            // Don't trim the CN, though!
-            String cn = it.next();
-            cn = cn.toLowerCase(Locale.ENGLISH);
-            // Store CN in StringBuilder in case we need to report an error.
-            buf.append(" <");
-            buf.append(cn);
-            buf.append('>');
-            if(it.hasNext()) {
-                buf.append(" OR");
-            }
-
-            // The CN better have at least two dots if it wants wildcard
-            // action.  It also can't be [*.co.uk] or [*.co.jp] or
-            // [*.org.uk], etc...
-            final String parts[] = cn.split("\\.");
-            final boolean doWildcard =
-                    parts.length >= 3 && parts[0].endsWith("*") &&
-                    validCountryWildcard(cn) && !isIPAddress(host);
-
-            if(doWildcard) {
-                final String firstpart = parts[0];
-                if (firstpart.length() > 1) { // e.g. server*
-                    final String prefix = firstpart.substring(0, firstpart.length() - 1); // e.g. server
-                    final String suffix = cn.substring(firstpart.length()); // skip wildcard part from cn
-                    final String hostSuffix = hostName.substring(prefix.length()); // skip wildcard part from host
-                    match = hostName.startsWith(prefix) && hostSuffix.endsWith(suffix);
-                } else {
-                    match = hostName.endsWith(cn.substring(1));
-                }
-                if(match && strictWithSubDomains) {
-                    // If we're in strict mode, then [*.foo.com] is not
-                    // allowed to match [a.b.foo.com]
-                    match = countDots(hostName) == countDots(cn);
-                }
+        final String normalizedHost = host.toLowerCase(Locale.ROOT);
+        final String normalizedIdentity = identity.toLowerCase(Locale.ROOT);
+        // The CN better have at least two dots if it wants wildcard
+        // action.  It also can't be [*.co.uk] or [*.co.jp] or
+        // [*.org.uk], etc...
+        final String parts[] = normalizedIdentity.split("\\.");
+        final boolean doWildcard = parts.length >= 3 && parts[0].endsWith("*") &&
+                (!strict || validCountryWildcard(parts));
+        if (doWildcard) {
+            boolean match;
+            final String firstpart = parts[0];
+            if (firstpart.length() > 1) { // e.g. server*
+                final String prefix = firstpart.substring(0, firstpart.length() - 1); // e.g. server
+                final String suffix = normalizedIdentity.substring(firstpart.length()); // skip wildcard part from cn
+                final String hostSuffix = normalizedHost.substring(prefix.length()); // skip wildcard part from normalizedHost
+                match = normalizedHost.startsWith(prefix) && hostSuffix.endsWith(suffix);
             } else {
-                match = hostName.equals(normaliseIPv6Address(cn));
+                match = normalizedHost.endsWith(normalizedIdentity.substring(1));
             }
-            if(match) {
-                break;
-            }
-        }
-        if(!match) {
-            throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
+            return match && (!strict || countDots(normalizedHost) == countDots(normalizedIdentity));
+        } else {
+            return normalizedHost.equals(normalizedIdentity);
         }
     }
 
-    /**
-     * @deprecated (4.3.1) should not be a part of public APIs.
-     */
-    @Deprecated
-    public static boolean acceptableCountryWildcard(final String cn) {
-        final String parts[] = cn.split("\\.");
+    private static boolean validCountryWildcard(final String parts[]) {
         if (parts.length != 3 || parts[2].length() != 2) {
             return true; // it's not an attempt to wildcard a 2TLD within a country code
         }
         return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0;
     }
 
-    boolean validCountryWildcard(final String cn) {
-        final String parts[] = cn.split("\\.");
-        if (parts.length != 3 || parts[2].length() != 2) {
-            return true; // it's not an attempt to wildcard a 2TLD within a country code
-        }
-        return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0;
+    public static boolean acceptableCountryWildcard(final String cn) {
+        return validCountryWildcard(cn.split("\\."));
     }
 
     public static String[] getCNs(final X509Certificate cert) {
         final String subjectPrincipal = cert.getSubjectX500Principal().toString();
         try {
-            return extractCNs(subjectPrincipal);
+            final String cn = DefaultHostnameVerifier.extractCN(subjectPrincipal);
+            return cn != null ? new String[] { cn } : null;
         } catch (SSLException ex) {
             return null;
         }
     }
 
-    static String[] extractCNs(final String subjectPrincipal) throws SSLException {
-        if (subjectPrincipal == null) {
-            return null;
-        }
-        final List<String> cns = new ArrayList<String>();
-        try {
-            final LdapName subjectDN = new LdapName(subjectPrincipal);
-            final List<Rdn> rdns = subjectDN.getRdns();
-            for (int i = rdns.size() - 1; i >= 0; i--) {
-                final Rdn rds = rdns.get(i);
-                final Attributes attributes = rds.toAttributes();
-                final Attribute cn = attributes.get("cn");
-                if (cn != null) {
-                    try {
-                        final Object value = cn.get();
-                        if (value != null) {
-                            cns.add(value.toString());
-                        }
-                    } catch (NoSuchElementException ignore) {
-                    } catch (NamingException ignore) {
-                    }
-                }
-            }
-        } catch (InvalidNameException e) {
-            throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
-        }
-        return cns.isEmpty() ? null : cns.toArray(new String[ cns.size() ]);
-    }
-
-    /**
-     * Extracts the array of SubjectAlt DNS or IP names from an X509Certificate.
-     * Returns null if there aren't any.
-     *
-     * @param cert X509Certificate
-     * @param hostname
-     * @return Array of SubjectALT DNS or IP names stored in the certificate.
-     */
-    private static String[] getSubjectAlts(
-            final X509Certificate cert, final String hostname) {
-        final int subjectType;
-        if (isIPAddress(hostname)) {
-            subjectType = 7;
-        } else {
-            subjectType = 2;
-        }
-
-        final LinkedList<String> subjectAltList = new LinkedList<String>();
-        Collection<List<?>> c = null;
-        try {
-            c = cert.getSubjectAlternativeNames();
-        }
-        catch(final CertificateParsingException cpe) {
-        }
-        if(c != null) {
-            for (final List<?> aC : c) {
-                final List<?> list = aC;
-                final int type = ((Integer) list.get(0)).intValue();
-                if (type == subjectType) {
-                    final String s = (String) list.get(1);
-                    subjectAltList.add(s);
-                }
-            }
-        }
-        if(!subjectAltList.isEmpty()) {
-            final String[] subjectAlts = new String[subjectAltList.size()];
-            subjectAltList.toArray(subjectAlts);
-            return subjectAlts;
-        } else {
-            return null;
-        }
-    }
-
     /**
      * Extracts the array of SubjectAlt DNS names from an X509Certificate.
      * Returns null if there aren't any.
-     * <p/>
+     * <p>
      * Note:  Java doesn't appear able to extract international characters
      * from the SubjectAlts.  It can only extract international characters
      * from the CN field.
-     * <p/>
+     * </p>
+     * <p>
      * (Or maybe the version of OpenSSL I'm using to test isn't storing the
      * international characters correctly in the SubjectAlts?).
+     * </p>
      *
      * @param cert X509Certificate
      * @return Array of SubjectALT DNS names stored in the certificate.
      */
     public static String[] getDNSSubjectAlts(final X509Certificate cert) {
-        return getSubjectAlts(cert, null);
+        final List<String> subjectAlts = DefaultHostnameVerifier.extractSubjectAlts(
+                cert, DefaultHostnameVerifier.DNS_NAME_TYPE);
+        return subjectAlts != null && !subjectAlts.isEmpty() ?
+                subjectAlts.toArray(new String[subjectAlts.size()]) : null;
     }
 
     /**
@@ -373,25 +265,4 @@ public abstract class AbstractVerifier implements X509HostnameVerifier {
         return count;
     }
 
-    private static boolean isIPAddress(final String hostname) {
-        return hostname != null &&
-            (InetAddressUtils.isIPv4Address(hostname) ||
-                    InetAddressUtils.isIPv6Address(hostname));
-    }
-
-    /*
-     * Check if hostname is IPv6, and if so, convert to standard format.
-     */
-    private String normaliseIPv6Address(final String hostname) {
-        if (hostname == null || !InetAddressUtils.isIPv6Address(hostname)) {
-            return hostname;
-        }
-        try {
-            final InetAddress inetAddress = InetAddress.getByName(hostname);
-            return inetAddress.getHostAddress();
-        } catch (final UnknownHostException uhe) { // Should not happen, because we check for IPv6 address above
-            log.error("Unexpected error converting "+hostname, uhe);
-            return hostname;
-        }
-    }
 }
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java b/httpclient/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
index 07f3de4..3dc856e 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
@@ -35,10 +35,16 @@ import org.apache.http.annotation.Immutable;
  *
  *
  * @since 4.0
+ *
+ * @deprecated (4.4) Use {@link org.apache.http.conn.ssl.NoopHostnameVerifier}
  */
+ at Deprecated
 @Immutable
 public class AllowAllHostnameVerifier extends AbstractVerifier {
 
+    public static final AllowAllHostnameVerifier INSTANCE = new AllowAllHostnameVerifier();
+
+    @Override
     public final void verify(
             final String host,
             final String[] cns,
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java b/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
index ef1ec1e..4c4aee9 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
@@ -33,20 +33,27 @@ import org.apache.http.annotation.Immutable;
 
 /**
  * The HostnameVerifier that works the same way as Curl and Firefox.
- * <p/>
+ * <p>
  * The hostname must match either the first CN, or any of the subject-alts.
  * A wildcard can occur in the CN, and in any of the subject-alts.
- * <p/>
+ * </p>
+ * <p>
  * The only difference between BROWSER_COMPATIBLE and STRICT is that a wildcard
  * (such as "*.foo.com") with BROWSER_COMPATIBLE matches all subdomains,
  * including "a.b.foo.com".
- *
+ * </p>
  *
  * @since 4.0
+ *
+ * @deprecated (4.4) Use {@link org.apache.http.conn.ssl.DefaultHostnameVerifier}
  */
 @Immutable
+ at Deprecated
 public class BrowserCompatHostnameVerifier extends AbstractVerifier {
 
+    public static final BrowserCompatHostnameVerifier INSTANCE = new BrowserCompatHostnameVerifier();
+
+    @Override
     public final void verify(
             final String host,
             final String[] cns,
@@ -55,11 +62,6 @@ public class BrowserCompatHostnameVerifier extends AbstractVerifier {
     }
 
     @Override
-    boolean validCountryWildcard(final String cn) {
-        return true;
-    }
-
-    @Override
     public final String toString() {
         return "BROWSER_COMPATIBLE";
     }
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java b/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java
new file mode 100644
index 0000000..03a1edb
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java
@@ -0,0 +1,297 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+
+import javax.naming.InvalidNameException;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.util.InetAddressUtils;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+
+/**
+ * Default {@link javax.net.ssl.HostnameVerifier} implementation.
+ *
+ * @since 4.4
+ */
+ at Immutable
+public final class DefaultHostnameVerifier implements HostnameVerifier {
+
+    final static int DNS_NAME_TYPE        = 2;
+    final static int IP_ADDRESS_TYPE      = 7;
+
+    private final Log log = LogFactory.getLog(getClass());
+
+    private final PublicSuffixMatcher publicSuffixMatcher;
+
+    public DefaultHostnameVerifier(final PublicSuffixMatcher publicSuffixMatcher) {
+        this.publicSuffixMatcher = publicSuffixMatcher;
+    }
+
+    public DefaultHostnameVerifier() {
+        this(null);
+    }
+
+    @Override
+    public final boolean verify(final String host, final SSLSession session) {
+        try {
+            final Certificate[] certs = session.getPeerCertificates();
+            final X509Certificate x509 = (X509Certificate) certs[0];
+            verify(host, x509);
+            return true;
+        } catch(final SSLException ex) {
+            if (log.isDebugEnabled()) {
+                log.debug(ex.getMessage(), ex);
+            }
+            return false;
+        }
+    }
+
+    public final void verify(
+            final String host, final X509Certificate cert) throws SSLException {
+        final boolean ipv4 = InetAddressUtils.isIPv4Address(host);
+        final boolean ipv6 = InetAddressUtils.isIPv6Address(host);
+        final int subjectType = ipv4 || ipv6 ? IP_ADDRESS_TYPE : DNS_NAME_TYPE;
+        final List<String> subjectAlts = extractSubjectAlts(cert, subjectType);
+        if (subjectAlts != null && !subjectAlts.isEmpty()) {
+            if (ipv4) {
+                matchIPAddress(host, subjectAlts);
+            } else if (ipv6) {
+                matchIPv6Address(host, subjectAlts);
+            } else {
+                matchDNSName(host, subjectAlts, this.publicSuffixMatcher);
+            }
+        } else {
+            // CN matching has been deprecated by rfc2818 and can be used
+            // as fallback only when no subjectAlts are available
+            final X500Principal subjectPrincipal = cert.getSubjectX500Principal();
+            final String cn = extractCN(subjectPrincipal.getName(X500Principal.RFC2253));
+            if (cn == null) {
+                throw new SSLException("Certificate subject for <" + host + "> doesn't contain " +
+                        "a common name and does not have alternative names");
+            }
+            matchCN(host, cn, this.publicSuffixMatcher);
+        }
+    }
+
+    static void matchIPAddress(final String host, final List<String> subjectAlts) throws SSLException {
+        for (int i = 0; i < subjectAlts.size(); i++) {
+            final String subjectAlt = subjectAlts.get(i);
+            if (host.equals(subjectAlt)) {
+                return;
+            }
+        }
+        throw new SSLException("Certificate for <" + host + "> doesn't match any " +
+                "of the subject alternative names: " + subjectAlts);
+    }
+
+    static void matchIPv6Address(final String host, final List<String> subjectAlts) throws SSLException {
+        final String normalisedHost = normaliseAddress(host);
+        for (int i = 0; i < subjectAlts.size(); i++) {
+            final String subjectAlt = subjectAlts.get(i);
+            final String normalizedSubjectAlt = normaliseAddress(subjectAlt);
+            if (normalisedHost.equals(normalizedSubjectAlt)) {
+                return;
+            }
+        }
+        throw new SSLException("Certificate for <" + host + "> doesn't match any " +
+                "of the subject alternative names: " + subjectAlts);
+    }
+
+    static void matchDNSName(final String host, final List<String> subjectAlts,
+                             final PublicSuffixMatcher publicSuffixMatcher) throws SSLException {
+        final String normalizedHost = host.toLowerCase(Locale.ROOT);
+        for (int i = 0; i < subjectAlts.size(); i++) {
+            final String subjectAlt = subjectAlts.get(i);
+            final String normalizedSubjectAlt = subjectAlt.toLowerCase(Locale.ROOT);
+            if (matchIdentityStrict(normalizedHost, normalizedSubjectAlt, publicSuffixMatcher)) {
+                return;
+            }
+        }
+        throw new SSLException("Certificate for <" + host + "> doesn't match any " +
+                "of the subject alternative names: " + subjectAlts);
+    }
+
+    static void matchCN(final String host, final String cn,
+                 final PublicSuffixMatcher publicSuffixMatcher) throws SSLException {
+        if (!matchIdentityStrict(host, cn, publicSuffixMatcher)) {
+            throw new SSLException("Certificate for <" + host + "> doesn't match " +
+                    "common name of the certificate subject: " + cn);
+        }
+    }
+
+    static boolean matchDomainRoot(final String host, final String domainRoot) {
+        if (domainRoot == null) {
+            return false;
+        }
+        return host.endsWith(domainRoot) && (host.length() == domainRoot.length()
+                || host.charAt(host.length() - domainRoot.length() - 1) == '.');
+    }
+
+    private static boolean matchIdentity(final String host, final String identity,
+                                         final PublicSuffixMatcher publicSuffixMatcher,
+                                         final boolean strict) {
+        if (publicSuffixMatcher != null && host.contains(".")) {
+            if (!matchDomainRoot(host, publicSuffixMatcher.getDomainRoot(identity))) {
+                return false;
+            }
+        }
+
+        // RFC 2818, 3.1. Server Identity
+        // "...Names may contain the wildcard
+        // character * which is considered to match any single domain name
+        // component or component fragment..."
+        // Based on this statement presuming only singular wildcard is legal
+        final int asteriskIdx = identity.indexOf('*');
+        if (asteriskIdx != -1) {
+            final String prefix = identity.substring(0, asteriskIdx);
+            final String suffix = identity.substring(asteriskIdx + 1);
+            if (!prefix.isEmpty() && !host.startsWith(prefix)) {
+                return false;
+            }
+            if (!suffix.isEmpty() && !host.endsWith(suffix)) {
+                return false;
+            }
+            // Additional sanity checks on content selected by wildcard can be done here
+            if (strict) {
+                final String remainder = host.substring(
+                        prefix.length(), host.length() - suffix.length());
+                if (remainder.contains(".")) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return host.equalsIgnoreCase(identity);
+    }
+
+    static boolean matchIdentity(final String host, final String identity,
+                                 final PublicSuffixMatcher publicSuffixMatcher) {
+        return matchIdentity(host, identity, publicSuffixMatcher, false);
+    }
+
+    static boolean matchIdentity(final String host, final String identity) {
+        return matchIdentity(host, identity, null, false);
+    }
+
+    static boolean matchIdentityStrict(final String host, final String identity,
+                                       final PublicSuffixMatcher publicSuffixMatcher) {
+        return matchIdentity(host, identity, publicSuffixMatcher, true);
+    }
+
+    static boolean matchIdentityStrict(final String host, final String identity) {
+        return matchIdentity(host, identity, null, true);
+    }
+
+    static String extractCN(final String subjectPrincipal) throws SSLException {
+        if (subjectPrincipal == null) {
+            return null;
+        }
+        try {
+            final LdapName subjectDN = new LdapName(subjectPrincipal);
+            final List<Rdn> rdns = subjectDN.getRdns();
+            for (int i = rdns.size() - 1; i >= 0; i--) {
+                final Rdn rds = rdns.get(i);
+                final Attributes attributes = rds.toAttributes();
+                final Attribute cn = attributes.get("cn");
+                if (cn != null) {
+                    try {
+                        final Object value = cn.get();
+                        if (value != null) {
+                            return value.toString();
+                        }
+                    } catch (NoSuchElementException ignore) {
+                    } catch (NamingException ignore) {
+                    }
+                }
+            }
+            return null;
+        } catch (InvalidNameException e) {
+            throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
+        }
+    }
+
+    static List<String> extractSubjectAlts(final X509Certificate cert, final int subjectType) {
+        Collection<List<?>> c = null;
+        try {
+            c = cert.getSubjectAlternativeNames();
+        } catch(final CertificateParsingException ignore) {
+        }
+        List<String> subjectAltList = null;
+        if (c != null) {
+            for (final List<?> aC : c) {
+                final List<?> list = aC;
+                final int type = ((Integer) list.get(0)).intValue();
+                if (type == subjectType) {
+                    final String s = (String) list.get(1);
+                    if (subjectAltList == null) {
+                        subjectAltList = new ArrayList<String>();
+                    }
+                    subjectAltList.add(s);
+                }
+            }
+        }
+        return subjectAltList;
+    }
+
+    /*
+     * Normalize IPv6 or DNS name.
+     */
+    static String normaliseAddress(final String hostname) {
+        if (hostname == null) {
+            return hostname;
+        }
+        try {
+            final InetAddress inetAddress = InetAddress.getByName(hostname);
+            return inetAddress.getHostAddress();
+        } catch (final UnknownHostException unexpected) { // Should not happen, because we check for IPv6 address above
+            return hostname;
+        }
+    }
+}
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java b/httpclient/src/main/java/org/apache/http/conn/ssl/NoopHostnameVerifier.java
similarity index 76%
copy from httpclient/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
copy to httpclient/src/main/java/org/apache/http/conn/ssl/NoopHostnameVerifier.java
index 07f3de4..1b5cdd9 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/NoopHostnameVerifier.java
@@ -27,28 +27,30 @@
 
 package org.apache.http.conn.ssl;
 
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSession;
+
 import org.apache.http.annotation.Immutable;
 
 /**
- * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
+ * The NO_OP HostnameVerifier essentially turns hostname verification
  * off. This implementation is a no-op, and never throws the SSLException.
  *
- *
- * @since 4.0
+ * @since 4.4
  */
 @Immutable
-public class AllowAllHostnameVerifier extends AbstractVerifier {
+public class NoopHostnameVerifier implements HostnameVerifier {
 
-    public final void verify(
-            final String host,
-            final String[] cns,
-            final String[] subjectAlts) {
-        // Allow everything - so never blowup.
+    public static final NoopHostnameVerifier INSTANCE = new NoopHostnameVerifier();
+
+    @Override
+    public boolean verify(final String s, final SSLSession sslSession) {
+        return true;
     }
 
     @Override
     public final String toString() {
-        return "ALLOW_ALL";
+        return "NO_OP";
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java b/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java
index c175fd2..15923e7 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java
@@ -27,20 +27,37 @@
 
 package org.apache.http.conn.ssl;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.http.HttpHost;
 import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
+import org.apache.http.conn.util.PublicSuffixMatcherLoader;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.ssl.SSLContexts;
 import org.apache.http.util.Args;
 import org.apache.http.util.TextUtils;
 
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-
 /**
  * Layered socket factory for TLS/SSL connections.
  * <p>
@@ -75,15 +92,17 @@ import java.net.Socket;
  *     <li>
  *      <p>
  *      Use JDK keytool utility to generate a new key
+ *      </p>
  *      <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ *      <p>
  *      For simplicity use the same password for the key as that of the key-store
  *      </p>
  *     </li>
  *     <li>
  *      <p>
  *      Issue a certificate signing request (CSR)
+ *      </p>
  *      <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
- *     </p>
  *     </li>
  *     <li>
  *      <p>
@@ -95,52 +114,62 @@ import java.net.Socket;
  *     <li>
  *      <p>
  *       Import the trusted CA root certificate
- *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
  *      </p>
+ *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
  *     </li>
  *     <li>
- *      <p>
- *       Import the PKCS#7 file containg the complete certificate chain
+ *       <p>
+ *       Import the PKCS#7 file containing the complete certificate chain
+ *       </p>
  *       <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
- *      </p>
  *     </li>
  *     <li>
- *      <p>
- *       Verify the content the resultant keystore file
+ *       <p>
+ *       Verify the content of the resultant keystore file
+ *       </p>
  *       <pre>keytool -list -v -keystore my.keystore</pre>
- *      </p>
  *     </li>
  *   </ul>
  *
- * @since 4.0
+ * @since 4.3
  */
- at ThreadSafe
+ at ThreadSafe @SuppressWarnings("deprecation")
 public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactory {
 
     public static final String TLS   = "TLS";
     public static final String SSL   = "SSL";
     public static final String SSLV2 = "SSLv2";
 
+    @Deprecated
     public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
-        = new AllowAllHostnameVerifier();
+        = AllowAllHostnameVerifier.INSTANCE;
 
+    @Deprecated
     public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
-        = new BrowserCompatHostnameVerifier();
+        = BrowserCompatHostnameVerifier.INSTANCE;
 
+    @Deprecated
     public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
-        = new StrictHostnameVerifier();
+        = StrictHostnameVerifier.INSTANCE;
+
+    private final Log log = LogFactory.getLog(getClass());
+
+    /**
+     * @since 4.4
+     */
+    public static HostnameVerifier getDefaultHostnameVerifier() {
+        return new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
+    }
 
     /**
      * Obtains default SSL socket factory with an SSL context based on the standard JSSE
-     * trust material (<code>cacerts</code> file in the security properties directory).
+     * trust material ({@code cacerts} file in the security properties directory).
      * System properties are not taken into consideration.
      *
      * @return default SSL socket factory
      */
     public static SSLConnectionSocketFactory getSocketFactory() throws SSLInitializationException {
-        return new SSLConnectionSocketFactory(
-            SSLContexts.createDefault(),
-            BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+        return new SSLConnectionSocketFactory(SSLContexts.createDefault(), getDefaultHostnameVerifier());
     }
 
     private static String[] split(final String s) {
@@ -153,9 +182,8 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
     /**
      * Obtains default SSL socket factory with an SSL context based on system properties
      * as described in
-     * <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html">
-     * "JavaTM Secure Socket Extension (JSSE) Reference Guide for the JavaTM 2 Platform
-     * Standard Edition 5</a>
+     * <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+     * Java&#x2122; Secure Socket Extension (JSSE) Reference Guide</a>.
      *
      * @return default system SSL socket factory
      */
@@ -164,24 +192,34 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
             (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
             split(System.getProperty("https.protocols")),
             split(System.getProperty("https.cipherSuites")),
-            BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+            getDefaultHostnameVerifier());
     }
 
     private final javax.net.ssl.SSLSocketFactory socketfactory;
-    private final X509HostnameVerifier hostnameVerifier;
+    private final HostnameVerifier hostnameVerifier;
     private final String[] supportedProtocols;
     private final String[] supportedCipherSuites;
 
     public SSLConnectionSocketFactory(final SSLContext sslContext) {
-        this(sslContext, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+        this(sslContext, getDefaultHostnameVerifier());
     }
 
+    /**
+     * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLContext,
+     *   javax.net.ssl.HostnameVerifier)}
+     */
+    @Deprecated
     public SSLConnectionSocketFactory(
             final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
         this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
                 null, null, hostnameVerifier);
     }
 
+    /**
+     * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLContext,
+     *   String[], String[], javax.net.ssl.HostnameVerifier)}
+     */
+    @Deprecated
     public SSLConnectionSocketFactory(
             final SSLContext sslContext,
             final String[] supportedProtocols,
@@ -191,21 +229,72 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
                 supportedProtocols, supportedCipherSuites, hostnameVerifier);
     }
 
+    /**
+     * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
+     *   javax.net.ssl.HostnameVerifier)}
+     */
+    @Deprecated
     public SSLConnectionSocketFactory(
             final javax.net.ssl.SSLSocketFactory socketfactory,
             final X509HostnameVerifier hostnameVerifier) {
         this(socketfactory, null, null, hostnameVerifier);
     }
 
+    /**
+     * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
+     *   String[], String[], javax.net.ssl.HostnameVerifier)}
+     */
+    @Deprecated
     public SSLConnectionSocketFactory(
             final javax.net.ssl.SSLSocketFactory socketfactory,
             final String[] supportedProtocols,
             final String[] supportedCipherSuites,
             final X509HostnameVerifier hostnameVerifier) {
+        this(socketfactory, supportedProtocols, supportedCipherSuites, (HostnameVerifier) hostnameVerifier);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public SSLConnectionSocketFactory(
+            final SSLContext sslContext, final HostnameVerifier hostnameVerifier) {
+        this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
+                null, null, hostnameVerifier);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public SSLConnectionSocketFactory(
+            final SSLContext sslContext,
+            final String[] supportedProtocols,
+            final String[] supportedCipherSuites,
+            final HostnameVerifier hostnameVerifier) {
+        this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
+                supportedProtocols, supportedCipherSuites, hostnameVerifier);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public SSLConnectionSocketFactory(
+            final javax.net.ssl.SSLSocketFactory socketfactory,
+            final HostnameVerifier hostnameVerifier) {
+        this(socketfactory, null, null, hostnameVerifier);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public SSLConnectionSocketFactory(
+            final javax.net.ssl.SSLSocketFactory socketfactory,
+            final String[] supportedProtocols,
+            final String[] supportedCipherSuites,
+            final HostnameVerifier hostnameVerifier) {
         this.socketfactory = Args.notNull(socketfactory, "SSL socket factory");
         this.supportedProtocols = supportedProtocols;
         this.supportedCipherSuites = supportedCipherSuites;
-        this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
+        this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : getDefaultHostnameVerifier();
     }
 
     /**
@@ -214,14 +303,17 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
      *
      * The default implementation is a no-op, but could be overridden to, e.g.,
      * call {@link javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[])}.
+     * @throws IOException may be thrown if overridden
      */
     protected void prepareSocket(final SSLSocket socket) throws IOException {
     }
 
+    @Override
     public Socket createSocket(final HttpContext context) throws IOException {
         return SocketFactory.getDefault().createSocket();
     }
 
+    @Override
     public Socket connectSocket(
             final int connectTimeout,
             final Socket socket,
@@ -236,6 +328,12 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
             sock.bind(localAddress);
         }
         try {
+            if (connectTimeout > 0 && sock.getSoTimeout() == 0) {
+                sock.setSoTimeout(connectTimeout);
+            }
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Connecting socket to " + remoteAddress + " with timeout " + connectTimeout);
+            }
             sock.connect(remoteAddress, connectTimeout);
         } catch (final IOException ex) {
             try {
@@ -247,6 +345,7 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
         // Setup SSL layering if necessary
         if (sock instanceof SSLSocket) {
             final SSLSocket sslsock = (SSLSocket) sock;
+            this.log.debug("Starting handshake");
             sslsock.startHandshake();
             verifyHostname(sslsock, host.getHostName());
             return sock;
@@ -255,6 +354,7 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
         }
     }
 
+    @Override
     public Socket createLayeredSocket(
             final Socket socket,
             final String target,
@@ -267,23 +367,104 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
                 true);
         if (supportedProtocols != null) {
             sslsock.setEnabledProtocols(supportedProtocols);
+        } else {
+            // If supported protocols are not explicitly set, remove all SSL protocol versions
+            final String[] allProtocols = sslsock.getEnabledProtocols();
+            final List<String> enabledProtocols = new ArrayList<String>(allProtocols.length);
+            for (String protocol: allProtocols) {
+                if (!protocol.startsWith("SSL")) {
+                    enabledProtocols.add(protocol);
+                }
+            }
+            if (!enabledProtocols.isEmpty()) {
+                sslsock.setEnabledProtocols(enabledProtocols.toArray(new String[enabledProtocols.size()]));
+            }
         }
         if (supportedCipherSuites != null) {
             sslsock.setEnabledCipherSuites(supportedCipherSuites);
         }
+
+        if (this.log.isDebugEnabled()) {
+            this.log.debug("Enabled protocols: " + Arrays.asList(sslsock.getEnabledProtocols()));
+            this.log.debug("Enabled cipher suites:" + Arrays.asList(sslsock.getEnabledCipherSuites()));
+        }
+
         prepareSocket(sslsock);
+        this.log.debug("Starting handshake");
         sslsock.startHandshake();
         verifyHostname(sslsock, target);
         return sslsock;
     }
 
-    X509HostnameVerifier getHostnameVerifier() {
-        return this.hostnameVerifier;
-    }
-
     private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {
         try {
-            this.hostnameVerifier.verify(hostname, sslsock);
+            SSLSession session = sslsock.getSession();
+            if (session == null) {
+                // In our experience this only happens under IBM 1.4.x when
+                // spurious (unrelated) certificates show up in the server'
+                // chain.  Hopefully this will unearth the real problem:
+                final InputStream in = sslsock.getInputStream();
+                in.available();
+                // If ssl.getInputStream().available() didn't cause an
+                // exception, maybe at least now the session is available?
+                session = sslsock.getSession();
+                if (session == null) {
+                    // If it's still null, probably a startHandshake() will
+                    // unearth the real problem.
+                    sslsock.startHandshake();
+                    session = sslsock.getSession();
+                }
+            }
+            if (session == null) {
+                throw new SSLHandshakeException("SSL session not available");
+            }
+
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Secure session established");
+                this.log.debug(" negotiated protocol: " + session.getProtocol());
+                this.log.debug(" negotiated cipher suite: " + session.getCipherSuite());
+
+                try {
+
+                    final Certificate[] certs = session.getPeerCertificates();
+                    final X509Certificate x509 = (X509Certificate) certs[0];
+                    final X500Principal peer = x509.getSubjectX500Principal();
+
+                    this.log.debug(" peer principal: " + peer.toString());
+                    final Collection<List<?>> altNames1 = x509.getSubjectAlternativeNames();
+                    if (altNames1 != null) {
+                        final List<String> altNames = new ArrayList<String>();
+                        for (final List<?> aC : altNames1) {
+                            if (!aC.isEmpty()) {
+                                altNames.add((String) aC.get(1));
+                            }
+                        }
+                        this.log.debug(" peer alternative names: " + altNames);
+                    }
+
+                    final X500Principal issuer = x509.getIssuerX500Principal();
+                    this.log.debug(" issuer principal: " + issuer.toString());
+                    final Collection<List<?>> altNames2 = x509.getIssuerAlternativeNames();
+                    if (altNames2 != null) {
+                        final List<String> altNames = new ArrayList<String>();
+                        for (final List<?> aC : altNames2) {
+                            if (!aC.isEmpty()) {
+                                altNames.add((String) aC.get(1));
+                            }
+                        }
+                        this.log.debug(" issuer alternative names: " + altNames);
+                    }
+                } catch (Exception ignore) {
+                }
+            }
+
+            if (!this.hostnameVerifier.verify(hostname, session)) {
+                final Certificate[] certs = session.getPeerCertificates();
+                final X509Certificate x509 = (X509Certificate) certs[0];
+                final X500Principal x500Principal = x509.getSubjectX500Principal();
+                throw new SSLPeerUnverifiedException("Host name '" + hostname + "' does not match " +
+                        "the certificate subject provided by the peer (" + x500Principal.toString() + ")");
+            }
             // verifyHostName() didn't blowup - good!
         } catch (final IOException iox) {
             // close the socket before re-throwing the exception
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java b/httpclient/src/main/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java
index 9be638d..362d6ab 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java
@@ -33,27 +33,33 @@ import org.apache.http.annotation.Immutable;
 
 /**
  * The Strict HostnameVerifier works the same way as Sun Java 1.4, Sun
- * Java 5, Sun Java 6-rc.  It's also pretty close to IE6.  This
- * implementation appears to be compliant with RFC 2818 for dealing with
- * wildcards.
- * <p/>
+ * Java 5, Sun Java 6.  It's also pretty close to IE6.  This implementation
+ * appears to be compliant with RFC 2818 for dealing with wildcards.
+ * <p>
  * The hostname must match either the first CN, or any of the subject-alts.
  * A wildcard can occur in the CN, and in any of the subject-alts.  The
  * one divergence from IE6 is how we only check the first CN.  IE6 allows
  * a match against any of the CNs present.  We decided to follow in
  * Sun Java 1.4's footsteps and only check the first CN.  (If you need
  * to check all the CN's, feel free to write your own implementation!).
- * <p/>
+ * </p>
+ * <p>
  * A wildcard such as "*.foo.com" matches only subdomains in the same
  * level, for example "a.foo.com".  It does not match deeper subdomains
  * such as "a.b.foo.com".
- *
+ * </p>
  *
  * @since 4.0
+ *
+ * @deprecated (4.4) Use {@link org.apache.http.conn.ssl.DefaultHostnameVerifier}
  */
 @Immutable
+ at Deprecated
 public class StrictHostnameVerifier extends AbstractVerifier {
 
+    public static final StrictHostnameVerifier INSTANCE = new StrictHostnameVerifier();
+
+    @Override
     public final void verify(
             final String host,
             final String[] cns,
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/TrustSelfSignedStrategy.java b/httpclient/src/main/java/org/apache/http/conn/ssl/TrustSelfSignedStrategy.java
index 038b1ed..e59b52e 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/TrustSelfSignedStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/TrustSelfSignedStrategy.java
@@ -37,6 +37,9 @@ import java.security.cert.X509Certificate;
  */
 public class TrustSelfSignedStrategy implements TrustStrategy {
 
+    public static final TrustSelfSignedStrategy INSTANCE = new TrustSelfSignedStrategy();
+
+    @Override
     public boolean isTrusted(
             final X509Certificate[] chain, final String authType) throws CertificateException {
         return chain.length == 1;
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/TrustStrategy.java b/httpclient/src/main/java/org/apache/http/conn/ssl/TrustStrategy.java
index 3af8777..53a8091 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/TrustStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/TrustStrategy.java
@@ -26,9 +26,6 @@
  */
 package org.apache.http.conn.ssl;
 
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
 /**
  * A strategy to establish trustworthiness of certificates without consulting the trust manager
  * configured in the actual SSL context. This interface can be used to override the standard
@@ -36,22 +33,6 @@ import java.security.cert.X509Certificate;
  *
  * @since 4.1
  */
-public interface TrustStrategy {
-
-    /**
-     * Determines whether the certificate chain can be trusted without consulting the trust manager
-     * configured in the actual SSL context. This method can be used to override the standard JSSE
-     * certificate verification process.
-     * <p>
-     * Please note that, if this method returns <code>false</code>, the trust manager configured
-     * in the actual SSL context can still clear the certificate as trusted.
-     *
-     * @param chain the peer certificate chain
-     * @param authType the authentication type based on the client certificate
-     * @return <code>true</code> if the certificate can be trusted without verification by
-     *   the trust manager, <code>false</code> otherwise.
-     * @throws CertificateException thrown if the certificate is not trusted or invalid.
-     */
-    boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException;
+public interface TrustStrategy extends org.apache.http.ssl.TrustStrategy {
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/X509HostnameVerifier.java b/httpclient/src/main/java/org/apache/http/conn/ssl/X509HostnameVerifier.java
index 55fa88b..8bca83a 100644
--- a/httpclient/src/main/java/org/apache/http/conn/ssl/X509HostnameVerifier.java
+++ b/httpclient/src/main/java/org/apache/http/conn/ssl/X509HostnameVerifier.java
@@ -41,7 +41,10 @@ import javax.net.ssl.SSLSocket;
  * methods added by X509HostnameVerifier.
  *
  * @since 4.0
+ *
+ * @deprecated (4.4) Use {@link javax.net.ssl.HostnameVerifier}.
  */
+ at Deprecated
 public interface X509HostnameVerifier extends HostnameVerifier {
 
     /**
diff --git a/httpclient/src/main/java/org/apache/http/conn/util/InetAddressUtils.java b/httpclient/src/main/java/org/apache/http/conn/util/InetAddressUtils.java
index df46788..acee8af 100644
--- a/httpclient/src/main/java/org/apache/http/conn/util/InetAddressUtils.java
+++ b/httpclient/src/main/java/org/apache/http/conn/util/InetAddressUtils.java
@@ -43,7 +43,8 @@ public class InetAddressUtils {
     }
 
     private static final String IPV4_BASIC_PATTERN_STRING =
-            "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + // initial 3 fields, 0-255 followed by .
+            "(([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){1}" + // initial first field, 1-255
+            "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){2}" + // following 2 fields, 0-255 followed by .
              "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; // final field, 0-255
 
     private static final Pattern IPV4_PATTERN =
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixList.java
similarity index 58%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java
copy to httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixList.java
index 2d9d024..ec15c9d 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java
+++ b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixList.java
@@ -24,37 +24,40 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.cookie;
+package org.apache.http.conn.util;
+
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.http.annotation.Immutable;
-import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieOrigin;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
 
 /**
+ * Public suffix is a set of DNS names or wildcards concatenated with dots. It represents
+ * the part of a domain name which is not under the control of the individual registrant
+ * <p>
+ * An up-to-date list of suffixes can be obtained from
+ * <a href="http://publicsuffix.org/">publicsuffix.org</a>
  *
- * @since 4.0
+ * @since 4.4
  */
 @Immutable
-public class BasicSecureHandler extends AbstractCookieAttributeHandler {
+public final class PublicSuffixList {
+
+    private final List<String> rules;
+    private final List<String> exceptions;
 
-    public BasicSecureHandler() {
-        super();
+    public PublicSuffixList(final List<String> rules, final List<String> exceptions) {
+        this.rules = Collections.unmodifiableList(Args.notNull(rules, "Domain suffix rules"));
+        this.exceptions = Collections.unmodifiableList(Args.notNull(exceptions, "Domain suffix exceptions"));
     }
 
-    public void parse(final SetCookie cookie, final String value)
-            throws MalformedCookieException {
-        Args.notNull(cookie, "Cookie");
-        cookie.setSecure(true);
+    public List<String> getRules() {
+        return rules;
     }
 
-    @Override
-    public boolean match(final Cookie cookie, final CookieOrigin origin) {
-        Args.notNull(cookie, "Cookie");
-        Args.notNull(origin, "Cookie origin");
-        return !cookie.isSecure() || origin.isSecure();
+    public List<String> getExceptions() {
+        return exceptions;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixListParser.java b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixListParser.java
similarity index 70%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixListParser.java
rename to httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixListParser.java
index b89f291..84bbd18 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixListParser.java
+++ b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixListParser.java
@@ -24,13 +24,13 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.cookie;
+package org.apache.http.conn.util;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.Reader;
 import java.util.ArrayList;
-import java.util.Collection;
+import java.util.List;
 
 import org.apache.http.annotation.Immutable;
 
@@ -38,43 +38,39 @@ import org.apache.http.annotation.Immutable;
  * Parses the list from <a href="http://publicsuffix.org/">publicsuffix.org</a>
  * and configures a PublicSuffixFilter.
  *
- * @since 4.0
+ * @since 4.4
  */
 @Immutable
-public class PublicSuffixListParser {
+public final class PublicSuffixListParser {
+
     private static final int MAX_LINE_LEN = 256;
-    private final PublicSuffixFilter filter;
 
-    PublicSuffixListParser(final PublicSuffixFilter filter) {
-        this.filter = filter;
+    public PublicSuffixListParser() {
     }
 
     /**
-     * Parses the public suffix list format.
-     * When creating the reader from the file, make sure to
+     * Parses the public suffix list format. When creating the reader from the file, make sure to
      * use the correct encoding (the original list is in UTF-8).
      *
-     * @param list the suffix list. The caller is responsible for closing the reader.
-     * @throws IOException on error while reading from list
+     * @param reader the data reader. The caller is responsible for closing the reader.
+     * @throws java.io.IOException on error while reading from list
      */
-    public void parse(final Reader list) throws IOException {
-        final Collection<String> rules = new ArrayList<String>();
-        final Collection<String> exceptions = new ArrayList<String>();
-        final BufferedReader r = new BufferedReader(list);
+    public PublicSuffixList parse(final Reader reader) throws IOException {
+        final List<String> rules = new ArrayList<String>();
+        final List<String> exceptions = new ArrayList<String>();
+        final BufferedReader r = new BufferedReader(reader);
         final StringBuilder sb = new StringBuilder(256);
         boolean more = true;
         while (more) {
             more = readLine(r, sb);
             String line = sb.toString();
-            if (line.length() == 0) {
+            if (line.isEmpty()) {
                 continue;
             }
-            if (line.startsWith("//"))
-             {
+            if (line.startsWith("//")) {
                 continue; //entire lines can also be commented using //
             }
-            if (line.startsWith("."))
-             {
+            if (line.startsWith(".")) {
                 line = line.substring(1); // A leading dot is optional
             }
             // An exclamation mark (!) at the start of a rule marks an exception to a previous wildcard rule
@@ -89,18 +85,9 @@ public class PublicSuffixListParser {
                 rules.add(line);
             }
         }
-
-        filter.setPublicSuffixes(rules);
-        filter.setExceptions(exceptions);
+        return new PublicSuffixList(rules, exceptions);
     }
 
-    /**
-     *
-     * @param r
-     * @param sb
-     * @return false when the end of the stream is reached
-     * @throws IOException
-     */
     private boolean readLine(final Reader r, final StringBuilder sb) throws IOException {
         sb.setLength(0);
         int b;
@@ -117,11 +104,11 @@ public class PublicSuffixListParser {
             if (!hitWhitespace) {
                 sb.append(c);
             }
-            if (sb.length() > MAX_LINE_LEN)
-             {
-                throw new IOException("Line too long"); // prevent excess memory usage
+            if (sb.length() > MAX_LINE_LEN) {
+                return false; // prevent excess memory usage
             }
         }
         return (b != -1);
     }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixMatcher.java b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixMatcher.java
new file mode 100644
index 0000000..02393ac
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixMatcher.java
@@ -0,0 +1,121 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.conn.util;
+
+import java.net.IDN;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.util.Args;
+
+/**
+ * Utility class that can test if DNS names match the content of the Public Suffix List.
+ * <p>
+ * An up-to-date list of suffixes can be obtained from
+ * <a href="http://publicsuffix.org/">publicsuffix.org</a>
+ *
+ * @see org.apache.http.conn.util.PublicSuffixList
+ *
+ * @since 4.4
+ */
+ at ThreadSafe
+public final class PublicSuffixMatcher {
+
+    private final Map<String, String> rules;
+    private final Map<String, String> exceptions;
+
+    public PublicSuffixMatcher(final Collection<String> rules, final Collection<String> exceptions) {
+        Args.notNull(rules,  "Domain suffix rules");
+        this.rules = new ConcurrentHashMap<String, String>(rules.size());
+        for (String rule: rules) {
+            this.rules.put(rule, rule);
+        }
+        if (exceptions != null) {
+            this.exceptions = new ConcurrentHashMap<String, String>(exceptions.size());
+            for (String exception: exceptions) {
+                this.exceptions.put(exception, exception);
+            }
+        } else {
+            this.exceptions = null;
+        }
+    }
+
+    /**
+     * Returns registrable part of the domain for the given domain name of {@code null}
+     * if given domain represents a public suffix.
+     *
+     * @param domain
+     * @return domain root
+     */
+    public String getDomainRoot(final String domain) {
+        if (domain == null) {
+            return null;
+        }
+        if (domain.startsWith(".")) {
+            return null;
+        }
+        String domainName = null;
+        String segment = domain.toLowerCase(Locale.ROOT);
+        while (segment != null) {
+
+            // An exception rule takes priority over any other matching rule.
+            if (this.exceptions != null && this.exceptions.containsKey(IDN.toUnicode(segment))) {
+                return segment;
+            }
+
+            if (this.rules.containsKey(IDN.toUnicode(segment))) {
+                break;
+            }
+
+            final int nextdot = segment.indexOf('.');
+            final String nextSegment = nextdot != -1 ? segment.substring(nextdot + 1) : null;
+
+            if (nextSegment != null) {
+                if (this.rules.containsKey("*." + IDN.toUnicode(nextSegment))) {
+                    break;
+                }
+            }
+            if (nextdot != -1) {
+                domainName = segment;
+            }
+            segment = nextSegment;
+        }
+        return domainName;
+    }
+
+    public boolean matches(final String domain) {
+        if (domain == null) {
+            return false;
+        }
+        final String domainRoot = getDomainRoot(domain.startsWith(".") ? domain.substring(1) : domain);
+        return domainRoot == null;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixMatcherLoader.java b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixMatcherLoader.java
new file mode 100644
index 0000000..9017406
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/conn/util/PublicSuffixMatcherLoader.java
@@ -0,0 +1,104 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.conn.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Arrays;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Consts;
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.util.Args;
+
+/**
+ * {@link org.apache.http.conn.util.PublicSuffixMatcher} loader.
+ *
+ * @since 4.4
+ */
+ at ThreadSafe
+public final class PublicSuffixMatcherLoader {
+
+    private static PublicSuffixMatcher load(final InputStream in) throws IOException {
+        final PublicSuffixList list = new PublicSuffixListParser().parse(
+                new InputStreamReader(in, Consts.UTF_8));
+        return new PublicSuffixMatcher(list.getRules(), list.getExceptions());
+    }
+
+    public static PublicSuffixMatcher load(final URL url) throws IOException {
+        Args.notNull(url, "URL");
+        final InputStream in = url.openStream();
+        try {
+            return load(in);
+        } finally {
+            in.close();
+        }
+    }
+
+    public static PublicSuffixMatcher load(final File file) throws IOException {
+        Args.notNull(file, "File");
+        final InputStream in = new FileInputStream(file);
+        try {
+            return load(in);
+        } finally {
+            in.close();
+        }
+    }
+
+    private static volatile PublicSuffixMatcher DEFAULT_INSTANCE;
+
+    public static PublicSuffixMatcher getDefault() {
+        if (DEFAULT_INSTANCE == null) {
+            synchronized (PublicSuffixMatcherLoader.class) {
+                if (DEFAULT_INSTANCE == null){
+                    final URL url = PublicSuffixMatcherLoader.class.getResource(
+                            "/mozilla/public-suffix-list.txt");
+                    if (url != null) {
+                        try {
+                            DEFAULT_INSTANCE = load(url);
+                        } catch (IOException ex) {
+                            // Should never happen
+                            final Log log = LogFactory.getLog(PublicSuffixMatcherLoader.class);
+                            if (log.isWarnEnabled()) {
+                                log.warn("Failure loading public suffix list from default resource", ex);
+                            }
+                        }
+                    } else {
+                        DEFAULT_INSTANCE = new PublicSuffixMatcher(Arrays.asList("com"), null);
+                    }
+                }
+            }
+        }
+        return DEFAULT_INSTANCE;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/cookie/ClientCookie.java b/httpclient/src/main/java/org/apache/http/cookie/ClientCookie.java
index 164d302..aa5fee8 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/ClientCookie.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/ClientCookie.java
@@ -27,32 +27,39 @@
 
 package org.apache.http.cookie;
 
+import org.apache.http.annotation.Obsolete;
+
 /**
  * ClientCookie extends the standard {@link Cookie} interface with
  * additional client specific functionality such ability to retrieve
  * original cookie attributes exactly as they were specified by the
- * origin server. This is important for generating the <tt>Cookie</tt>
+ * origin server. This is important for generating the {@code Cookie}
  * header because some cookie specifications require that the
- * <tt>Cookie</tt> header should include certain attributes only if
- * they were specified in the <tt>Set-Cookie</tt> header.
- *
+ * {@code Cookie} header should include certain attributes only if
+ * they were specified in the {@code Set-Cookie} header.
+ * <p>
+ * Please do not use attributes marked as @Obsolete. They have been rendered
+ * obsolete by RFC 6265.
  *
  * @since 4.0
  */
 public interface ClientCookie extends Cookie {
 
-    // RFC2109 attributes
+    @Obsolete
     public static final String VERSION_ATTR    = "version";
     public static final String PATH_ATTR       = "path";
     public static final String DOMAIN_ATTR     = "domain";
     public static final String MAX_AGE_ATTR    = "max-age";
     public static final String SECURE_ATTR     = "secure";
+    @Obsolete
     public static final String COMMENT_ATTR    = "comment";
     public static final String EXPIRES_ATTR    = "expires";
 
-    // RFC2965 attributes
+    @Obsolete
     public static final String PORT_ATTR       = "port";
+    @Obsolete
     public static final String COMMENTURL_ATTR = "commenturl";
+    @Obsolete
     public static final String DISCARD_ATTR    = "discard";
 
     String getAttribute(String name);
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java b/httpclient/src/main/java/org/apache/http/cookie/CommonCookieAttributeHandler.java
similarity index 77%
copy from httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java
copy to httpclient/src/main/java/org/apache/http/cookie/CommonCookieAttributeHandler.java
index cc62de3..d82f7af 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CommonCookieAttributeHandler.java
@@ -24,17 +24,17 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.client;
+package org.apache.http.cookie;
 
 /**
- * The actual system clock.
+ * Extension of {@link org.apache.http.cookie.CookieAttributeHandler} intended
+ * to handle one specific common attribute whose name is returned with
+ * {@link #getAttributeName()} method.
  *
- * @since 4.2
+ * @since 4.4
  */
-class SystemClock implements Clock {
+public interface CommonCookieAttributeHandler extends CookieAttributeHandler {
 
-    public long getCurrentTime() {
-        return System.currentTimeMillis();
-    }
+    String getAttributeName();
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/cookie/Cookie.java b/httpclient/src/main/java/org/apache/http/cookie/Cookie.java
index b1c18f3..e259281 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/Cookie.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/Cookie.java
@@ -29,11 +29,16 @@ package org.apache.http.cookie;
 
 import java.util.Date;
 
+import org.apache.http.annotation.Obsolete;
+
 /**
  * Cookie interface represents a token or short packet of state information
  * (also referred to as "magic-cookie") that the HTTP agent and the target
  * server can exchange to maintain a session. In its simples form an HTTP
  * cookie is merely a name / value pair.
+ * <p>
+ * Please do not use attributes marked as @Obsolete. They have been rendered
+ * obsolete by RFC 6265.
  *
  * @since 4.0
  */
@@ -55,34 +60,36 @@ public interface Cookie {
 
     /**
      * Returns the comment describing the purpose of this cookie, or
-     * <tt>null</tt> if no such comment has been defined.
+     * {@code null} if no such comment has been defined.
      *
      * @return comment
      */
+    @Obsolete
     String getComment();
 
     /**
      * If a user agent (web browser) presents this cookie to a user, the
      * cookie's purpose will be described by the information at this URL.
      */
+    @Obsolete
     String getCommentURL();
 
     /**
-     * Returns the expiration {@link Date} of the cookie, or <tt>null</tt>
+     * Returns the expiration {@link Date} of the cookie, or {@code null}
      * if none exists.
      * <p><strong>Note:</strong> the object returned by this method is
      * considered immutable. Changing it (e.g. using setTime()) could result
      * in undefined behaviour. Do so at your peril. </p>
-     * @return Expiration {@link Date}, or <tt>null</tt>.
+     * @return Expiration {@link Date}, or {@code null}.
      */
     Date getExpiryDate();
 
     /**
-     * Returns <tt>false</tt> if the cookie should be discarded at the end
-     * of the "session"; <tt>true</tt> otherwise.
+     * Returns {@code false} if the cookie should be discarded at the end
+     * of the "session"; {@code true} otherwise.
      *
-     * @return <tt>false</tt> if the cookie should be discarded at the end
-     *         of the "session"; <tt>true</tt> otherwise
+     * @return {@code false} if the cookie should be discarded at the end
+     *         of the "session"; {@code true} otherwise
      */
     boolean isPersistent();
 
@@ -107,13 +114,14 @@ public interface Cookie {
      * Get the Port attribute. It restricts the ports to which a cookie
      * may be returned in a Cookie request header.
      */
+    @Obsolete
     int[] getPorts();
 
     /**
      * Indicates whether this cookie requires a secure connection.
      *
-     * @return  <code>true</code> if this cookie should only be sent
-     *          over secure connections, <code>false</code> otherwise.
+     * @return  {@code true} if this cookie should only be sent
+     *          over secure connections, {@code false} otherwise.
      */
     boolean isSecure();
 
@@ -123,15 +131,18 @@ public interface Cookie {
      *
      * @return the version of the cookie.
      */
+    @Obsolete
     int getVersion();
 
     /**
      * Returns true if this cookie has expired.
      * @param date Current time
      *
-     * @return <tt>true</tt> if the cookie has expired.
+     * @return {@code true} if the cookie has expired.
      */
     boolean isExpired(final Date date);
 
+    //TODO: RFC 6265 requires cookies to track their creation time; add #getCreationDate()
+
 }
 
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java b/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java
index a6621a8..95e1c33 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java
@@ -66,7 +66,7 @@ public interface CookieAttributeHandler {
    *
    * @param cookie {@link org.apache.http.cookie.Cookie} to match
    * @param origin the cookie source to match against
-   * @return <tt>true</tt> if the match is successful; <tt>false</tt> otherwise
+   * @return {@code true} if the match is successful; {@code false} otherwise
    */
   boolean match(Cookie cookie, CookieOrigin origin);
 
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java b/httpclient/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java
index cade729..935a5a3 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java
@@ -45,6 +45,7 @@ public class CookieIdentityComparator implements Serializable, Comparator<Cookie
 
     private static final long serialVersionUID = 4466565437490631532L;
 
+    @Override
     public int compare(final Cookie c1, final Cookie c2) {
         int res = c1.getName().compareTo(c2.getName());
         if (res == 0) {
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java b/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java
index 8605149..b46f6bd 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java
@@ -30,6 +30,7 @@ import java.util.Locale;
 
 import org.apache.http.annotation.Immutable;
 import org.apache.http.util.Args;
+import org.apache.http.util.TextUtils;
 
 /**
  * CookieOrigin class encapsulates details of an origin server that
@@ -50,9 +51,9 @@ public final class CookieOrigin {
         Args.notBlank(host, "Host");
         Args.notNegative(port, "Port");
         Args.notNull(path, "Path");
-        this.host = host.toLowerCase(Locale.ENGLISH);
+        this.host = host.toLowerCase(Locale.ROOT);
         this.port = port;
-        if (path.trim().length() != 0) {
+        if (!TextUtils.isBlank(path)) {
             this.path = path;
         } else {
             this.path = "/";
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java b/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java
index 1432cb7..f9e3e76 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java
@@ -34,7 +34,7 @@ import org.apache.http.annotation.Immutable;
 
 /**
  * This cookie comparator ensures that multiple cookies satisfying
- * a common criteria are ordered in the <tt>Cookie</tt> header such
+ * a common criteria are ordered in the {@code Cookie} header such
  * that those with more specific Path attributes precede those with
  * less specific.
  *
@@ -50,6 +50,8 @@ import org.apache.http.annotation.Immutable;
 @Immutable
 public class CookiePathComparator implements Serializable, Comparator<Cookie> {
 
+    public static final CookiePathComparator INSTANCE = new CookiePathComparator();
+
     private static final long serialVersionUID = 7523645369616405818L;
 
     private String normalizePath(final Cookie cookie) {
@@ -63,6 +65,7 @@ public class CookiePathComparator implements Serializable, Comparator<Cookie> {
         return path;
     }
 
+    @Override
     public int compare(final Cookie c1, final Cookie c2) {
         final String path1 = normalizePath(c1);
         final String path2 = normalizePath(c2);
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java b/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java
similarity index 52%
copy from httpclient/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java
copy to httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java
index cade729..77e4e01 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieIdentityComparator.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java
@@ -27,54 +27,43 @@
 
 package org.apache.http.cookie;
 
-import java.io.Serializable;
 import java.util.Comparator;
+import java.util.Date;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.impl.cookie.BasicClientCookie;
 
 /**
- * This cookie comparator can be used to compare identity of cookies.
- * <p>
- *  Cookies are considered identical if their names are equal and
- *  their domain attributes match ignoring case.
+ * This cookie comparator ensures that cookies with longer paths take precedence over
+ * cookies with shorter path. Among cookies with equal path length cookies with ealier
+ * creation time take precedence over cookies with later creation time
  *
- * @since 4.0
+ * @since 4.4
  */
 @Immutable
-public class CookieIdentityComparator implements Serializable, Comparator<Cookie> {
+public class CookiePriorityComparator implements Comparator<Cookie> {
 
-    private static final long serialVersionUID = 4466565437490631532L;
+    public static final CookiePriorityComparator INSTANCE = new CookiePriorityComparator();
 
+    private int getPathLength(final Cookie cookie) {
+        final String path = cookie.getPath();
+        return path != null ? path.length() : 1;
+    }
+
+    @Override
     public int compare(final Cookie c1, final Cookie c2) {
-        int res = c1.getName().compareTo(c2.getName());
-        if (res == 0) {
-            // do not differentiate empty and null domains
-            String d1 = c1.getDomain();
-            if (d1 == null) {
-                d1 = "";
-            } else if (d1.indexOf('.') == -1) {
-                d1 = d1 + ".local";
-            }
-            String d2 = c2.getDomain();
-            if (d2 == null) {
-                d2 = "";
-            } else if (d2.indexOf('.') == -1) {
-                d2 = d2 + ".local";
-            }
-            res = d1.compareToIgnoreCase(d2);
-        }
-        if (res == 0) {
-            String p1 = c1.getPath();
-            if (p1 == null) {
-                p1 = "/";
-            }
-            String p2 = c2.getPath();
-            if (p2 == null) {
-                p2 = "/";
+        final int l1 = getPathLength(c1);
+        final int l2 = getPathLength(c2);
+        //TODO: update this class once Cookie interface has been expended with #getCreationTime method
+        final int result = l2 - l1;
+        if (result == 0 && c1 instanceof BasicClientCookie && c2 instanceof BasicClientCookie) {
+            final Date d1 = ((BasicClientCookie) c1).getCreationDate();
+            final Date d2 = ((BasicClientCookie) c2).getCreationDate();
+            if (d1 != null && d2 != null) {
+                return (int) (d1.getTime() - d2.getTime());
             }
-            res = p1.compareTo(p2);
         }
-        return res;
+        return result;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieRestrictionViolationException.java b/httpclient/src/main/java/org/apache/http/cookie/CookieRestrictionViolationException.java
index ab9b346..3b30a97 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieRestrictionViolationException.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookieRestrictionViolationException.java
@@ -41,7 +41,7 @@ public class CookieRestrictionViolationException extends MalformedCookieExceptio
     private static final long serialVersionUID = 7371235577078589013L;
 
     /**
-     * Creates a new CookeFormatViolationException with a <tt>null</tt> detail
+     * Creates a new CookeFormatViolationException with a {@code null} detail
      * message.
      */
     public CookieRestrictionViolationException() {
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieSpec.java b/httpclient/src/main/java/org/apache/http/cookie/CookieSpec.java
index 9c0caf9..c3aceff 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieSpec.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookieSpec.java
@@ -30,6 +30,7 @@ package org.apache.http.cookie;
 import java.util.List;
 
 import org.apache.http.Header;
+import org.apache.http.annotation.Obsolete;
 
 /**
  * Defines the cookie management specification.
@@ -40,7 +41,9 @@ import org.apache.http.Header;
  *   <li>  formatting of "Cookie" header
  * </ul>
  * for a given host, port and path of origin
- *
+ * <p>
+ * Please do not use methods marked as @Obsolete. They have been rendered
+ * obsolete by RFC 6265.
  *
  * @since 4.0
  */
@@ -52,19 +55,20 @@ public interface CookieSpec {
      *
      * @return version of the state management specification
      */
+    @Obsolete
     int getVersion();
 
     /**
-      * Parse the <tt>"Set-Cookie"</tt> Header into an array of Cookies.
+      * Parse the {@code "Set-Cookie"} Header into an array of Cookies.
       *
       * <p>This method will not perform the validation of the resultant
       * {@link Cookie}s</p>
       *
       * @see #validate
       *
-      * @param header the <tt>Set-Cookie</tt> received from the server
+      * @param header the {@code Set-Cookie} received from the server
       * @param origin details of the cookie origin
-      * @return an array of <tt>Cookie</tt>s parsed from the header
+      * @return an array of {@code Cookie}s parsed from the header
       * @throws MalformedCookieException if an exception occurs during parsing
       */
     List<Cookie> parse(Header header, CookieOrigin origin) throws MalformedCookieException;
@@ -85,13 +89,13 @@ public interface CookieSpec {
      * @param cookie the Cookie to be matched
      * @param origin the target to test against
      *
-     * @return <tt>true</tt> if the cookie should be submitted with a request
-     *  with given attributes, <tt>false</tt> otherwise.
+     * @return {@code true} if the cookie should be submitted with a request
+     *  with given attributes, {@code false} otherwise.
      */
     boolean match(Cookie cookie, CookieOrigin origin);
 
     /**
-     * Create <tt>"Cookie"</tt> headers for an array of Cookies.
+     * Create {@code "Cookie"} headers for an array of Cookies.
      *
      * @param cookies the Cookies format into a Cookie header
      * @return a Header for the given Cookies.
@@ -101,9 +105,10 @@ public interface CookieSpec {
 
     /**
      * Returns a request header identifying what version of the state management
-     * specification is understood. May be <code>null</code> if the cookie
-     * specification does not support <tt>Cookie2</tt> header.
+     * specification is understood. May be {@code null} if the cookie
+     * specification does not support {@code Cookie2} header.
      */
+    @Obsolete
     Header getVersionHeader();
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieSpecRegistry.java b/httpclient/src/main/java/org/apache/http/cookie/CookieSpecRegistry.java
index d66e3ad..43e6ffe 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/CookieSpecRegistry.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/CookieSpecRegistry.java
@@ -152,9 +152,11 @@ public final class CookieSpecRegistry implements Lookup<CookieSpecProvider> {
         registeredSpecs.putAll(map);
     }
 
+    @Override
     public CookieSpecProvider lookup(final String name) {
         return new CookieSpecProvider() {
 
+            @Override
             public CookieSpec create(final HttpContext context) {
                 final HttpRequest request = (HttpRequest) context.getAttribute(
                         ExecutionContext.HTTP_REQUEST);
diff --git a/httpclient/src/main/java/org/apache/http/cookie/MalformedCookieException.java b/httpclient/src/main/java/org/apache/http/cookie/MalformedCookieException.java
index 19d2ec0..da70979 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/MalformedCookieException.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/MalformedCookieException.java
@@ -43,7 +43,7 @@ public class MalformedCookieException extends ProtocolException {
     private static final long serialVersionUID = -6695462944287282185L;
 
     /**
-     * Creates a new MalformedCookieException with a <tt>null</tt> detail message.
+     * Creates a new MalformedCookieException with a {@code null} detail message.
      */
     public MalformedCookieException() {
         super();
@@ -62,8 +62,8 @@ public class MalformedCookieException extends ProtocolException {
      * Creates a new MalformedCookieException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public MalformedCookieException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/cookie/SetCookie.java b/httpclient/src/main/java/org/apache/http/cookie/SetCookie.java
index a3b9673..7008bf5 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/SetCookie.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/SetCookie.java
@@ -29,9 +29,14 @@ package org.apache.http.cookie;
 
 import java.util.Date;
 
+import org.apache.http.annotation.Obsolete;
+
 /**
- * This interface represents a <code>Set-Cookie</code> response header sent by the
+ * This interface represents a {@code Set-Cookie} response header sent by the
  * origin server to the HTTP agent in order to maintain a conversational state.
+ * <p>
+ * Please do not use methods marked as @Obsolete. They have been rendered
+ * obsolete by RFC 6265
  *
  * @since 4.0
  */
@@ -47,6 +52,7 @@ public interface SetCookie extends Cookie {
      *
      * @see #getComment()
      */
+    @Obsolete
     void setComment(String comment);
 
     /**
@@ -84,7 +90,7 @@ public interface SetCookie extends Cookie {
     /**
      * Sets the secure attribute of the cookie.
      * <p>
-     * When <tt>true</tt> the cookie should only be sent
+     * When {@code true} the cookie should only be sent
      * using a secure protocol (https).  This should only be set when
      * the cookie's originating server used a secure protocol to set the
      * cookie's value.
@@ -103,6 +109,7 @@ public interface SetCookie extends Cookie {
      *
      * @see Cookie#getVersion
      */
+    @Obsolete
     void setVersion(int version);
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/cookie/SetCookie2.java b/httpclient/src/main/java/org/apache/http/cookie/SetCookie2.java
index f92de76..2f07298 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/SetCookie2.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/SetCookie2.java
@@ -27,9 +27,14 @@
 
 package org.apache.http.cookie;
 
+import org.apache.http.annotation.Obsolete;
+
 /**
- * This interface represents a <code>Set-Cookie2</code> response header sent by the
+ * This interface represents a {@code Set-Cookie2} response header sent by the
  * origin server to the HTTP agent in order to maintain a conversational state.
+ * <p>
+ * Please do not use methods marked as @Obsolete. They have been rendered
+ * obsolete by RFC 6265
  *
  * @since 4.0
  */
@@ -39,21 +44,24 @@ public interface SetCookie2 extends SetCookie {
      * If a user agent (web browser) presents this cookie to a user, the
      * cookie's purpose will be described by the information at this URL.
      */
+    @Obsolete
     void setCommentURL(String commentURL);
 
     /**
      * Sets the Port attribute. It restricts the ports to which a cookie
      * may be returned in a Cookie request header.
      */
+    @Obsolete
     void setPorts(int[] ports);
 
     /**
      * Set the Discard attribute.
      *
-     * Note: <tt>Discard</tt> attribute overrides <tt>Max-age</tt>.
+     * Note: {@code Discard} attribute overrides {@code Max-age}.
      *
      * @see #isPersistent()
      */
+    @Obsolete
     void setDiscard(boolean discard);
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/cookie/params/CookieSpecPNames.java b/httpclient/src/main/java/org/apache/http/cookie/params/CookieSpecPNames.java
index 8d7d801..646b66d 100644
--- a/httpclient/src/main/java/org/apache/http/cookie/params/CookieSpecPNames.java
+++ b/httpclient/src/main/java/org/apache/http/cookie/params/CookieSpecPNames.java
@@ -40,10 +40,10 @@ public interface CookieSpecPNames {
 
     /**
      * Defines valid date patterns to be used for parsing non-standard
-     * <code>expires</code> attribute. Only required for compatibility
-     * with non-compliant servers that still use <code>expires</code>
+     * {@code expires} attribute. Only required for compatibility
+     * with non-compliant servers that still use {@code expires}
      * defined in the Netscape draft instead of the standard
-     * <code>max-age</code> attribute.
+     * {@code max-age} attribute.
      * <p>
      * This parameter expects a value of type {@link java.util.Collection}.
      * The collection elements must be of type {@link String} compatible
@@ -54,8 +54,8 @@ public interface CookieSpecPNames {
 
     /**
      * Defines whether cookies should be forced into a single
-     * <code>Cookie</code> request header. Otherwise, each cookie is formatted
-     * as a separate <code>Cookie</code> header.
+     * {@code Cookie} request header. Otherwise, each cookie is formatted
+     * as a separate {@code Cookie} header.
      * <p>
      * This parameter expects a value of type {@link Boolean}.
      * </p>
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/AuthSchemeBase.java b/httpclient/src/main/java/org/apache/http/impl/auth/AuthSchemeBase.java
index 3d850e8..2340831 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/AuthSchemeBase.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/AuthSchemeBase.java
@@ -59,7 +59,7 @@ public abstract class AuthSchemeBase implements ContextAwareAuthScheme {
     private ChallengeState challengeState;
 
     /**
-     * Creates an instance of <tt>AuthSchemeBase</tt> with the given challenge
+     * Creates an instance of {@code AuthSchemeBase} with the given challenge
      * state.
      *
      * @since 4.2
@@ -86,6 +86,7 @@ public abstract class AuthSchemeBase implements ContextAwareAuthScheme {
      * @throws MalformedChallengeException is thrown if the authentication challenge
      * is malformed
      */
+    @Override
     public void processChallenge(final Header header) throws MalformedChallengeException {
         Args.notNull(header, "Header");
         final String authheader = header.getName();
@@ -128,6 +129,7 @@ public abstract class AuthSchemeBase implements ContextAwareAuthScheme {
     }
 
 
+    @Override
     @SuppressWarnings("deprecation")
     public Header authenticate(
             final Credentials credentials,
@@ -140,7 +142,7 @@ public abstract class AuthSchemeBase implements ContextAwareAuthScheme {
             CharArrayBuffer buffer, int beginIndex, int endIndex) throws MalformedChallengeException;
 
     /**
-     * Returns <code>true</code> if authenticating against a proxy, <code>false</code>
+     * Returns {@code true} if authenticating against a proxy, {@code false}
      * otherwise.
      */
     public boolean isProxy() {
@@ -148,7 +150,7 @@ public abstract class AuthSchemeBase implements ContextAwareAuthScheme {
     }
 
     /**
-     * Returns {@link ChallengeState} value or <code>null</code> if unchallenged.
+     * Returns {@link ChallengeState} value or {@code null} if unchallenged.
      *
      * @since 4.2
      */
@@ -160,7 +162,7 @@ public abstract class AuthSchemeBase implements ContextAwareAuthScheme {
     public String toString() {
         final String name = getSchemeName();
         if (name != null) {
-            return name.toUpperCase(Locale.ENGLISH);
+            return name.toUpperCase(Locale.ROOT);
         } else {
             return super.toString();
         }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
index 92cd964..2f51de7 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
@@ -53,7 +53,8 @@ import org.apache.http.util.EncodingUtils;
 @NotThreadSafe
 public class BasicScheme extends RFC2617Scheme {
 
-    private final Base64 base64codec;
+    private static final long serialVersionUID = -1931571557597830536L;
+
     /** Whether the basic authentication process is complete */
     private boolean complete;
 
@@ -62,12 +63,11 @@ public class BasicScheme extends RFC2617Scheme {
      */
     public BasicScheme(final Charset credentialsCharset) {
         super(credentialsCharset);
-        this.base64codec = new Base64(0);
         this.complete = false;
     }
 
     /**
-     * Creates an instance of <tt>BasicScheme</tt> with the given challenge
+     * Creates an instance of {@code BasicScheme} with the given challenge
      * state.
      *
      * @since 4.2
@@ -77,7 +77,6 @@ public class BasicScheme extends RFC2617Scheme {
     @Deprecated
     public BasicScheme(final ChallengeState challengeState) {
         super(challengeState);
-        this.base64codec = new Base64(0);
     }
 
     public BasicScheme() {
@@ -87,8 +86,9 @@ public class BasicScheme extends RFC2617Scheme {
     /**
      * Returns textual designation of the basic authentication scheme.
      *
-     * @return <code>basic</code>
+     * @return {@code basic}
      */
+    @Override
     public String getSchemeName() {
         return "basic";
     }
@@ -111,18 +111,20 @@ public class BasicScheme extends RFC2617Scheme {
     /**
      * Tests if the Basic authentication process has been completed.
      *
-     * @return <tt>true</tt> if Basic authorization has been processed,
-     *   <tt>false</tt> otherwise.
+     * @return {@code true} if Basic authorization has been processed,
+     *   {@code false} otherwise.
      */
+    @Override
     public boolean isComplete() {
         return this.complete;
     }
 
     /**
-     * Returns <tt>false</tt>. Basic authentication scheme is request based.
+     * Returns {@code false}. Basic authentication scheme is request based.
      *
-     * @return <tt>false</tt>.
+     * @return {@code false}.
      */
+    @Override
     public boolean isConnectionBased() {
         return false;
     }
@@ -131,6 +133,7 @@ public class BasicScheme extends RFC2617Scheme {
      * @deprecated (4.2) Use {@link org.apache.http.auth.ContextAwareAuthScheme#authenticate(
      *   Credentials, HttpRequest, org.apache.http.protocol.HttpContext)}
      */
+    @Override
     @Deprecated
     public Header authenticate(
             final Credentials credentials, final HttpRequest request) throws AuthenticationException {
@@ -162,6 +165,7 @@ public class BasicScheme extends RFC2617Scheme {
         tmp.append(":");
         tmp.append((credentials.getPassword() == null) ? "null" : credentials.getPassword());
 
+        final Base64 base64codec = new Base64(0);
         final byte[] base64password = base64codec.encode(
                 EncodingUtils.getBytes(tmp.toString(), getCredentialsCharset(request)));
 
@@ -178,7 +182,7 @@ public class BasicScheme extends RFC2617Scheme {
     }
 
     /**
-     * Returns a basic <tt>Authorization</tt> header value for the given
+     * Returns a basic {@code Authorization} header value for the given
      * {@link Credentials} and charset.
      *
      * @param credentials The credentials to encode.
@@ -216,4 +220,11 @@ public class BasicScheme extends RFC2617Scheme {
         return new BufferedHeader(buffer);
     }
 
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("BASIC [complete=").append(complete)
+                .append("]");
+        return builder.toString();
+    }
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/BasicSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/BasicSchemeFactory.java
index c149fbe..5409a77 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/BasicSchemeFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/BasicSchemeFactory.java
@@ -60,10 +60,12 @@ public class BasicSchemeFactory implements AuthSchemeFactory, AuthSchemeProvider
         this(null);
     }
 
+    @Override
     public AuthScheme newInstance(final HttpParams params) {
         return new BasicScheme();
     }
 
+    @Override
     public AuthScheme create(final HttpContext context) {
         return new BasicScheme(this.charset);
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
index 35ee6c6..a7607e3 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
@@ -64,16 +64,19 @@ import org.apache.http.util.EncodingUtils;
  * Currently only qop=auth or no qop is supported. qop=auth-int
  * is unsupported. If auth and auth-int are provided, auth is
  * used.
- * <p/>
+ * <p>
  * Since the digest username is included as clear text in the generated
  * Authentication header, the charset of the username must be compatible
  * with the HTTP element charset used by the connection.
+ * </p>
  *
  * @since 4.0
  */
 @NotThreadSafe
 public class DigestScheme extends RFC2617Scheme {
 
+    private static final long serialVersionUID = 3883908186234566916L;
+
     /**
      * Hexa values used when creating 32 character long digest in HTTP DigestScheme
      * in case of authentication.
@@ -108,7 +111,7 @@ public class DigestScheme extends RFC2617Scheme {
     }
 
     /**
-     * Creates an instance of <tt>DigestScheme</tt> with the given challenge
+     * Creates an instance of {@code DigestScheme} with the given challenge
      * state.
      *
      * @since 4.2
@@ -137,14 +140,18 @@ public class DigestScheme extends RFC2617Scheme {
             final Header header) throws MalformedChallengeException {
         super.processChallenge(header);
         this.complete = true;
+        if (getParameters().isEmpty()) {
+            throw new MalformedChallengeException("Authentication challenge is empty");
+        }
     }
 
     /**
      * Tests if the Digest authentication process has been completed.
      *
-     * @return <tt>true</tt> if Digest authorization has been processed,
-     *   <tt>false</tt> otherwise.
+     * @return {@code true} if Digest authorization has been processed,
+     *   {@code false} otherwise.
      */
+    @Override
     public boolean isComplete() {
         final String s = getParameter("stale");
         if ("true".equalsIgnoreCase(s)) {
@@ -157,17 +164,19 @@ public class DigestScheme extends RFC2617Scheme {
     /**
      * Returns textual designation of the digest authentication scheme.
      *
-     * @return <code>digest</code>
+     * @return {@code digest}
      */
+    @Override
     public String getSchemeName() {
         return "digest";
     }
 
     /**
-     * Returns <tt>false</tt>. Digest authentication scheme is request based.
+     * Returns {@code false}. Digest authentication scheme is request based.
      *
-     * @return <tt>false</tt>.
+     * @return {@code false}.
      */
+    @Override
     public boolean isConnectionBased() {
         return false;
     }
@@ -180,6 +189,7 @@ public class DigestScheme extends RFC2617Scheme {
      * @deprecated (4.2) Use {@link org.apache.http.auth.ContextAwareAuthScheme#authenticate(
      *   Credentials, HttpRequest, org.apache.http.protocol.HttpContext)}
      */
+    @Override
     @Deprecated
     public Header authenticate(
             final Credentials credentials, final HttpRequest request) throws AuthenticationException {
@@ -263,7 +273,7 @@ public class DigestScheme extends RFC2617Scheme {
             final StringTokenizer tok = new StringTokenizer(qoplist, ",");
             while (tok.hasMoreTokens()) {
                 final String variant = tok.nextToken().trim();
-                qopset.add(variant.toLowerCase(Locale.ENGLISH));
+                qopset.add(variant.toLowerCase(Locale.ROOT));
             }
             if (request instanceof HttpEntityEnclosingRequest && qopset.contains("auth-int")) {
                 qop = QOP_AUTH_INT;
@@ -307,7 +317,7 @@ public class DigestScheme extends RFC2617Scheme {
         }
         final StringBuilder sb = new StringBuilder(256);
         final Formatter formatter = new Formatter(sb, Locale.US);
-        formatter.format("%08x", nounceCount);
+        formatter.format("%08x", Long.valueOf(nounceCount));
         formatter.close();
         final String nc = sb.toString();
 
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/DigestSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/DigestSchemeFactory.java
index 51aca1d..67a4e9e 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/DigestSchemeFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/DigestSchemeFactory.java
@@ -60,10 +60,12 @@ public class DigestSchemeFactory implements AuthSchemeFactory, AuthSchemeProvide
         this(null);
     }
 
+    @Override
     public AuthScheme newInstance(final HttpParams params) {
         return new DigestScheme();
     }
 
+    @Override
     public AuthScheme create(final HttpContext context) {
         return new DigestScheme(this.charset);
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java b/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java
index 4ce7aa8..eba45c2 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java
@@ -26,6 +26,9 @@
  */
 package org.apache.http.impl.auth;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -37,6 +40,7 @@ import org.apache.http.auth.AUTH;
 import org.apache.http.auth.AuthenticationException;
 import org.apache.http.auth.Credentials;
 import org.apache.http.auth.InvalidCredentialsException;
+import org.apache.http.auth.KerberosCredentials;
 import org.apache.http.auth.MalformedChallengeException;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.conn.routing.HttpRoute;
@@ -45,6 +49,7 @@ import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.Args;
 import org.apache.http.util.CharArrayBuffer;
 import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSManager;
 import org.ietf.jgss.GSSName;
@@ -67,6 +72,7 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
 
     private final Base64 base64codec;
     private final boolean stripPort;
+    private final boolean useCanonicalHostname;
 
     /** Authentication process state */
     private State state;
@@ -74,15 +80,20 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
     /** base64 decoded challenge **/
     private byte[] token;
 
-    GGSSchemeBase(final boolean stripPort) {
+    GGSSchemeBase(final boolean stripPort, final boolean useCanonicalHostname) {
         super();
         this.base64codec = new Base64(0);
         this.stripPort = stripPort;
+        this.useCanonicalHostname = useCanonicalHostname;
         this.state = State.UNINITIATED;
     }
 
+    GGSSchemeBase(final boolean stripPort) {
+        this(stripPort, true);
+    }
+
     GGSSchemeBase() {
-        this(false);
+        this(true,true);
     }
 
     protected GSSManager getManager() {
@@ -91,22 +102,55 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
 
     protected byte[] generateGSSToken(
             final byte[] input, final Oid oid, final String authServer) throws GSSException {
-        byte[] token = input;
-        if (token == null) {
-            token = new byte[0];
+        return generateGSSToken(input, oid, authServer, null);
+    }
+
+    /**
+     * @since 4.4
+     */
+    protected byte[] generateGSSToken(
+            final byte[] input, final Oid oid, final String authServer,
+            final Credentials credentials) throws GSSException {
+        byte[] inputBuff = input;
+        if (inputBuff == null) {
+            inputBuff = new byte[0];
         }
         final GSSManager manager = getManager();
         final GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
+
+        final GSSCredential gssCredential;
+        if (credentials instanceof KerberosCredentials) {
+            gssCredential = ((KerberosCredentials) credentials).getGSSCredential();
+        } else {
+            gssCredential = null;
+        }
+
         final GSSContext gssContext = manager.createContext(
-                serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
+                serverName.canonicalize(oid), oid, gssCredential, GSSContext.DEFAULT_LIFETIME);
         gssContext.requestMutualAuth(true);
         gssContext.requestCredDeleg(true);
-        return gssContext.initSecContext(token, 0, token.length);
+        return gssContext.initSecContext(inputBuff, 0, inputBuff.length);
+    }
+
+    /**
+     * @deprecated (4.4) Use {@link #generateToken(byte[], String, org.apache.http.auth.Credentials)}.
+     */
+    @Deprecated
+    protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
+        return null;
     }
 
-    protected abstract byte[] generateToken(
-            byte[] input, final String authServer) throws GSSException;
+    /**
+     * @since 4.4
+     */
+    //TODO: make this method abstract
+    @SuppressWarnings("deprecation")
+    protected byte[] generateToken(
+            final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
+        return generateToken(input, authServer);
+    }
 
+    @Override
     public boolean isComplete() {
         return this.state == State.TOKEN_GENERATED || this.state == State.FAILED;
     }
@@ -115,6 +159,7 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
      * @deprecated (4.2) Use {@link org.apache.http.auth.ContextAwareAuthScheme#authenticate(
      *   Credentials, HttpRequest, org.apache.http.protocol.HttpContext)}
      */
+    @Override
     @Deprecated
     public Header authenticate(
             final Credentials credentials,
@@ -149,16 +194,28 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
                     host = route.getTargetHost();
                 }
                 final String authServer;
-                if (!this.stripPort && host.getPort() > 0) {
-                    authServer = host.toHostString();
+                String hostname = host.getHostName();
+
+                if (this.useCanonicalHostname){
+                    try {
+                         //TODO: uncomment this statement and delete the resolveCanonicalHostname,
+                         //TODO: as soon canonical hostname resolving is implemented in the SystemDefaultDnsResolver
+                         //final DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;
+                         //hostname = dnsResolver.resolveCanonicalHostname(host.getHostName());
+                         hostname = resolveCanonicalHostname(hostname);
+                    } catch (UnknownHostException ignore){
+                    }
+                }
+                if (this.stripPort) { // || host.getPort()==80 || host.getPort()==443) {
+                    authServer = hostname;
                 } else {
-                    authServer = host.getHostName();
+                    authServer = hostname + ":" + host.getPort();
                 }
 
                 if (log.isDebugEnabled()) {
                     log.debug("init " + authServer);
                 }
-                token = generateToken(token, authServer);
+                token = generateToken(token, authServer, credentials);
                 state = State.TOKEN_GENERATED;
             } catch (final GSSException gsse) {
                 state = State.FAILED;
@@ -213,4 +270,13 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
         }
     }
 
+    private String resolveCanonicalHostname(final String host) throws UnknownHostException {
+        final InetAddress in = InetAddress.getByName(host);
+        final String canonicalServer = in.getCanonicalHostName();
+        if (in.getHostAddress().contentEquals(canonicalServer)) {
+            return host;
+        }
+        return canonicalServer;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java b/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java
index 97fcbf2..6bc2878 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java
@@ -131,7 +131,7 @@ public class HttpAuthenticator {
             case UNCHALLENGED:
                 if (authScheme != null) {
                     final String id = authScheme.getSchemeName();
-                    final Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
+                    final Header challenge = challenges.get(id.toLowerCase(Locale.ROOT));
                     if (challenge != null) {
                         this.log.debug("Authorization challenge processed");
                         authScheme.processChallenge(challenge);
@@ -177,7 +177,7 @@ public class HttpAuthenticator {
             final HttpContext context) throws HttpException, IOException {
         AuthScheme authScheme = authState.getAuthScheme();
         Credentials creds = authState.getCredentials();
-        switch (authState.getState()) {
+        switch (authState.getState()) { // TODO add UNCHALLENGED and HANDSHAKE cases
         case FAILURE:
             return;
         case SUCCESS:
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java
index 886f233..9b2ba62 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java
@@ -46,14 +46,22 @@ public class KerberosScheme extends GGSSchemeBase {
 
     private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
 
+    /**
+     * @since 4.4
+     */
+    public KerberosScheme(final boolean stripPort, final boolean useCanonicalHostname) {
+        super(stripPort, useCanonicalHostname);
+    }
+
     public KerberosScheme(final boolean stripPort) {
         super(stripPort);
     }
 
     public KerberosScheme() {
-        super(false);
+        super();
     }
 
+    @Override
     public String getSchemeName() {
         return "Kerberos";
     }
@@ -78,17 +86,23 @@ public class KerberosScheme extends GGSSchemeBase {
         return super.authenticate(credentials, request, context);
     }
 
-    @Override
+    @Override @SuppressWarnings("deprecation")
     protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
-        return generateGSSToken(input, new Oid(KERBEROS_OID), authServer);
+        return super.generateToken(input, authServer);
+    }
+
+    @Override
+    protected byte[] generateToken(final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
+        return generateGSSToken(input, new Oid(KERBEROS_OID), authServer, credentials);
     }
 
     /**
      * There are no valid parameters for KERBEROS authentication so this
-     * method always returns <code>null</code>.
+     * method always returns {@code null}.
      *
-     * @return <code>null</code>
+     * @return {@code null}
      */
+    @Override
     public String getParameter(final String name) {
         Args.notNull(name, "Parameter name");
         return null;
@@ -96,19 +110,21 @@ public class KerberosScheme extends GGSSchemeBase {
 
     /**
      * The concept of an authentication realm is not supported by the Negotiate
-     * authentication scheme. Always returns <code>null</code>.
+     * authentication scheme. Always returns {@code null}.
      *
-     * @return <code>null</code>
+     * @return {@code null}
      */
+    @Override
     public String getRealm() {
         return null;
     }
 
     /**
-     * Returns <tt>true</tt>. KERBEROS authentication scheme is connection based.
+     * Returns {@code true}. KERBEROS authentication scheme is connection based.
      *
-     * @return <tt>true</tt>.
+     * @return {@code true}.
      */
+    @Override
     public boolean isConnectionBased() {
         return true;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosSchemeFactory.java
index 6603345..431258e 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosSchemeFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosSchemeFactory.java
@@ -44,26 +44,43 @@ import org.apache.http.protocol.HttpContext;
 public class KerberosSchemeFactory implements AuthSchemeFactory, AuthSchemeProvider {
 
     private final boolean stripPort;
+    private final boolean useCanonicalHostname;
+
+    /**
+     * @since 4.4
+     */
+    public KerberosSchemeFactory(final boolean stripPort, final boolean useCanonicalHostname) {
+        super();
+        this.stripPort = stripPort;
+        this.useCanonicalHostname = useCanonicalHostname;
+    }
 
     public KerberosSchemeFactory(final boolean stripPort) {
         super();
         this.stripPort = stripPort;
+        this.useCanonicalHostname = true;
     }
 
     public KerberosSchemeFactory() {
-        this(false);
+        this(true, true);
     }
 
     public boolean isStripPort() {
         return stripPort;
     }
 
+    public boolean isUseCanonicalHostname() {
+        return useCanonicalHostname;
+    }
+
+    @Override
     public AuthScheme newInstance(final HttpParams params) {
-        return new KerberosScheme(this.stripPort);
+        return new KerberosScheme(this.stripPort, this.useCanonicalHostname);
     }
 
+    @Override
     public AuthScheme create(final HttpContext context) {
-        return new KerberosScheme(this.stripPort);
+        return new KerberosScheme(this.stripPort, this.useCanonicalHostname);
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngine.java b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngine.java
index d9b4a4f..05c6093 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngine.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngine.java
@@ -38,9 +38,9 @@ public interface NTLMEngine {
     /**
      * Generates a Type1 message given the domain and workstation.
      *
-     * @param domain Optional Windows domain name. Can be <code>null</code>.
+     * @param domain Optional Windows domain name. Can be {@code null}.
      * @param workstation Optional Windows workstation name. Can be
-     *  <code>null</code>.
+     *  {@code null}.
      * @return Type1 message
      * @throws NTLMEngineException
      */
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineException.java b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineException.java
index 58921c7..f902ae1 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineException.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineException.java
@@ -57,8 +57,8 @@ public class NTLMEngineException extends AuthenticationException {
      * Creates a new NTLMEngineException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public NTLMEngineException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java
index 7094d2f..0926e2c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java
@@ -27,6 +27,7 @@
 package org.apache.http.impl.auth;
 
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
 import java.security.Key;
 import java.security.MessageDigest;
 import java.util.Arrays;
@@ -36,7 +37,9 @@ import javax.crypto.Cipher;
 import javax.crypto.spec.SecretKeySpec;
 
 import org.apache.commons.codec.binary.Base64;
+import org.apache.http.Consts;
 import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.util.CharsetUtils;
 import org.apache.http.util.EncodingUtils;
 
 /**
@@ -48,6 +51,11 @@ import org.apache.http.util.EncodingUtils;
 @NotThreadSafe
 final class NTLMEngineImpl implements NTLMEngine {
 
+    /** Unicode encoding */
+    private static final Charset UNICODE_LITTLE_UNMARKED = CharsetUtils.lookup("UnicodeLittleUnmarked");
+    /** Character encoding */
+    private static final Charset DEFAULT_CHARSET = Consts.ASCII;
+
     // Flags we use; descriptions according to:
     // http://davenport.sourceforge.net/ntlm.html
     // and
@@ -80,22 +88,18 @@ final class NTLMEngineImpl implements NTLMEngine {
         RND_GEN = rnd;
     }
 
-    /** Character encoding */
-    static final String DEFAULT_CHARSET = "ASCII";
-
-    /** The character set to use for encoding the credentials */
-    private String credentialCharset = DEFAULT_CHARSET;
-
     /** The signature string as bytes in the default encoding */
     private static final byte[] SIGNATURE;
 
     static {
-        final byte[] bytesWithoutNull = EncodingUtils.getBytes("NTLMSSP", "ASCII");
+        final byte[] bytesWithoutNull = "NTLMSSP".getBytes(Consts.ASCII);
         SIGNATURE = new byte[bytesWithoutNull.length + 1];
         System.arraycopy(bytesWithoutNull, 0, SIGNATURE, 0, bytesWithoutNull.length);
         SIGNATURE[bytesWithoutNull.length] = (byte) 0x00;
     }
 
+    private static final Type1Message TYPE_1_MESSAGE = new Type1Message();
+
     /**
      * Returns the response for the given message.
      *
@@ -113,7 +117,7 @@ final class NTLMEngineImpl implements NTLMEngine {
      * @throws org.apache.http.HttpException
      *             If the messages cannot be retrieved.
      */
-    final String getResponseFor(final String message, final String username, final String password,
+    static String getResponseFor(final String message, final String username, final String password,
             final String host, final String domain) throws NTLMEngineException {
 
         final String response;
@@ -138,8 +142,10 @@ final class NTLMEngineImpl implements NTLMEngine {
      *            The domain to authenticate with.
      * @return String the message to add to the HTTP request header.
      */
-    String getType1Message(final String host, final String domain) throws NTLMEngineException {
-        return new Type1Message(domain, host).getResponse();
+    static String getType1Message(final String host, final String domain) throws NTLMEngineException {
+        // For compatibility reason do not include domain and host in type 1 message
+        //return new Type1Message(domain, host).getResponse();
+        return TYPE_1_MESSAGE.getResponse();
     }
 
     /**
@@ -160,30 +166,15 @@ final class NTLMEngineImpl implements NTLMEngine {
      *            the 8 byte array the server sent.
      * @return The type 3 message.
      * @throws NTLMEngineException
-     *             If {@link #RC4(byte[],byte[])} fails.
+     *             If {@encrypt(byte[],byte[])} fails.
      */
-    String getType3Message(final String user, final String password, final String host, final String domain,
+    static String getType3Message(final String user, final String password, final String host, final String domain,
             final byte[] nonce, final int type2Flags, final String target, final byte[] targetInformation)
             throws NTLMEngineException {
         return new Type3Message(domain, host, user, password, nonce, type2Flags, target,
                 targetInformation).getResponse();
     }
 
-    /**
-     * @return Returns the credentialCharset.
-     */
-    String getCredentialCharset() {
-        return credentialCharset;
-    }
-
-    /**
-     * @param credentialCharset
-     *            The credentialCharset to set.
-     */
-    void setCredentialCharset(final String credentialCharset) {
-        this.credentialCharset = credentialCharset;
-    }
-
     /** Strip dot suffix from a name */
     private static String stripDotSuffix(final String value) {
         if (value == null) {
@@ -448,10 +439,10 @@ final class NTLMEngineImpl implements NTLMEngine {
         public byte[] getLM2SessionResponse()
             throws NTLMEngineException {
             if (lm2SessionResponse == null) {
-                final byte[] clChallenge = getClientChallenge();
+                final byte[] clntChallenge = getClientChallenge();
                 lm2SessionResponse = new byte[24];
-                System.arraycopy(clChallenge, 0, lm2SessionResponse, 0, clChallenge.length);
-                Arrays.fill(lm2SessionResponse, clChallenge.length, lm2SessionResponse.length, (byte) 0x00);
+                System.arraycopy(clntChallenge, 0, lm2SessionResponse, 0, clntChallenge.length);
+                Arrays.fill(lm2SessionResponse, clntChallenge.length, lm2SessionResponse.length, (byte) 0x00);
             }
             return lm2SessionResponse;
         }
@@ -563,19 +554,6 @@ final class NTLMEngineImpl implements NTLMEngine {
     static byte[] ntlm2SessionResponse(final byte[] ntlmHash, final byte[] challenge,
             final byte[] clientChallenge) throws NTLMEngineException {
         try {
-            // Look up MD5 algorithm (was necessary on jdk 1.4.2)
-            // This used to be needed, but java 1.5.0_07 includes the MD5
-            // algorithm (finally)
-            // Class x = Class.forName("gnu.crypto.hash.MD5");
-            // Method updateMethod = x.getMethod("update",new
-            // Class[]{byte[].class});
-            // Method digestMethod = x.getMethod("digest",new Class[0]);
-            // Object mdInstance = x.newInstance();
-            // updateMethod.invoke(mdInstance,new Object[]{challenge});
-            // updateMethod.invoke(mdInstance,new Object[]{clientChallenge});
-            // byte[] digest = (byte[])digestMethod.invoke(mdInstance,new
-            // Object[0]);
-
             final MessageDigest md5 = MessageDigest.getInstance("MD5");
             md5.update(challenge);
             md5.update(clientChallenge);
@@ -603,13 +581,13 @@ final class NTLMEngineImpl implements NTLMEngine {
      */
     private static byte[] lmHash(final String password) throws NTLMEngineException {
         try {
-            final byte[] oemPassword = password.toUpperCase(Locale.ENGLISH).getBytes("US-ASCII");
+            final byte[] oemPassword = password.toUpperCase(Locale.ROOT).getBytes(Consts.ASCII);
             final int length = Math.min(oemPassword.length, 14);
             final byte[] keyBytes = new byte[14];
             System.arraycopy(oemPassword, 0, keyBytes, 0, length);
             final Key lowKey = createDESKey(keyBytes, 0);
             final Key highKey = createDESKey(keyBytes, 7);
-            final byte[] magicConstant = "KGS!@#$%".getBytes("US-ASCII");
+            final byte[] magicConstant = "KGS!@#$%".getBytes(Consts.ASCII);
             final Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
             des.init(Cipher.ENCRYPT_MODE, lowKey);
             final byte[] lowHash = des.doFinal(magicConstant);
@@ -634,14 +612,13 @@ final class NTLMEngineImpl implements NTLMEngine {
      *         the NTLM Response and the NTLMv2 and LMv2 Hashes.
      */
     private static byte[] ntlmHash(final String password) throws NTLMEngineException {
-        try {
-            final byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked");
-            final MD4 md4 = new MD4();
-            md4.update(unicodePassword);
-            return md4.getOutput();
-        } catch (final UnsupportedEncodingException e) {
-            throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e);
+        if (UNICODE_LITTLE_UNMARKED == null) {
+            throw new NTLMEngineException("Unicode not supported");
         }
+        final byte[] unicodePassword = password.getBytes(UNICODE_LITTLE_UNMARKED);
+        final MD4 md4 = new MD4();
+        md4.update(unicodePassword);
+        return md4.getOutput();
     }
 
     /**
@@ -652,17 +629,16 @@ final class NTLMEngineImpl implements NTLMEngine {
      */
     private static byte[] lmv2Hash(final String domain, final String user, final byte[] ntlmHash)
             throws NTLMEngineException {
-        try {
-            final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
-            // Upper case username, upper case domain!
-            hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked"));
-            if (domain != null) {
-                hmacMD5.update(domain.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked"));
-            }
-            return hmacMD5.getOutput();
-        } catch (final UnsupportedEncodingException e) {
-            throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e);
+        if (UNICODE_LITTLE_UNMARKED == null) {
+            throw new NTLMEngineException("Unicode not supported");
+        }
+        final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
+        // Upper case username, upper case domain!
+        hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
+        if (domain != null) {
+            hmacMD5.update(domain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
         }
+        return hmacMD5.getOutput();
     }
 
     /**
@@ -673,17 +649,16 @@ final class NTLMEngineImpl implements NTLMEngine {
      */
     private static byte[] ntlmv2Hash(final String domain, final String user, final byte[] ntlmHash)
             throws NTLMEngineException {
-        try {
-            final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
-            // Upper case username, mixed case target!!
-            hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked"));
-            if (domain != null) {
-                hmacMD5.update(domain.getBytes("UnicodeLittleUnmarked"));
-            }
-            return hmacMD5.getOutput();
-        } catch (final UnsupportedEncodingException e) {
-            throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e);
+        if (UNICODE_LITTLE_UNMARKED == null) {
+            throw new NTLMEngineException("Unicode not supported");
+        }
+        final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
+        // Upper case username, mixed case target!!
+        hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
+        if (domain != null) {
+            hmacMD5.update(domain.getBytes(UNICODE_LITTLE_UNMARKED));
         }
+        return hmacMD5.getOutput();
     }
 
     /**
@@ -843,8 +818,7 @@ final class NTLMEngineImpl implements NTLMEngine {
 
         /** Constructor to use when message contents are known */
         NTLMMessage(final String messageBody, final int expectedType) throws NTLMEngineException {
-            messageContents = Base64.decodeBase64(EncodingUtils.getBytes(messageBody,
-                    DEFAULT_CHARSET));
+            messageContents = Base64.decodeBase64(messageBody.getBytes(DEFAULT_CHARSET));
             // Look for NTLM message
             if (messageContents.length < SIGNATURE.length) {
                 throw new NTLMEngineException("NTLM message decoding error - packet too short");
@@ -990,26 +964,31 @@ final class NTLMEngineImpl implements NTLMEngine {
 
     /** Type 1 message assembly class */
     static class Type1Message extends NTLMMessage {
-        protected byte[] hostBytes;
-        protected byte[] domainBytes;
 
-        /** Constructor. Include the arguments the message will need */
+        private final byte[] hostBytes;
+        private final byte[] domainBytes;
+
         Type1Message(final String domain, final String host) throws NTLMEngineException {
             super();
-            try {
-                // Strip off domain name from the host!
-                final String unqualifiedHost = convertHost(host);
-                // Use only the base domain name!
-                final String unqualifiedDomain = convertDomain(domain);
-
-                hostBytes = unqualifiedHost != null? unqualifiedHost.getBytes("ASCII") : null;
-                domainBytes = unqualifiedDomain != null ? unqualifiedDomain
-                        .toUpperCase(Locale.ENGLISH).getBytes("ASCII") : null;
-            } catch (final UnsupportedEncodingException e) {
-                throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e);
+            if (UNICODE_LITTLE_UNMARKED == null) {
+                throw new NTLMEngineException("Unicode not supported");
             }
+            // Strip off domain name from the host!
+            final String unqualifiedHost = convertHost(host);
+            // Use only the base domain name!
+            final String unqualifiedDomain = convertDomain(domain);
+
+            hostBytes = unqualifiedHost != null ?
+                    unqualifiedHost.getBytes(UNICODE_LITTLE_UNMARKED) : null;
+            domainBytes = unqualifiedDomain != null ?
+                    unqualifiedDomain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED) : null;
         }
 
+        Type1Message() {
+            super();
+            hostBytes = null;
+            domainBytes = null;
+        }
         /**
          * Getting the response involves building the message before returning
          * it
@@ -1070,13 +1049,14 @@ final class NTLMEngineImpl implements NTLMEngine {
             // NTLM revision
             addUShort(0x0f00);
 
-
             // Host (workstation) String.
-            //addBytes(hostBytes);
-
+            if (hostBytes != null) {
+                addBytes(hostBytes);
+            }
             // Domain String.
-            //addBytes(domainBytes);
-
+            if (domainBytes != null) {
+                addBytes(domainBytes);
+            }
 
             return super.getResponse();
         }
@@ -1115,7 +1095,7 @@ final class NTLMEngineImpl implements NTLMEngine {
 
             if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0) {
                 throw new NTLMEngineException(
-                        "NTLM type 2 message has flags that make no sense: "
+                        "NTLM type 2 message indicates no support for Unicode. Flags are: "
                                 + Integer.toString(flags));
             }
 
@@ -1255,16 +1235,13 @@ final class NTLMEngineImpl implements NTLMEngine {
             } else {
                 sessionKey = null;
             }
-
-            try {
-                hostBytes = unqualifiedHost != null ? unqualifiedHost
-                        .getBytes("UnicodeLittleUnmarked") : null;
-                domainBytes = unqualifiedDomain != null ? unqualifiedDomain
-                        .toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked") : null;
-                userBytes = user.getBytes("UnicodeLittleUnmarked");
-            } catch (final UnsupportedEncodingException e) {
-                throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e);
+            if (UNICODE_LITTLE_UNMARKED == null) {
+                throw new NTLMEngineException("Unicode not supported");
             }
+            hostBytes = unqualifiedHost != null ? unqualifiedHost.getBytes(UNICODE_LITTLE_UNMARKED) : null;
+            domainBytes = unqualifiedDomain != null ? unqualifiedDomain
+                    .toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED) : null;
+            userBytes = user.getBytes(UNICODE_LITTLE_UNMARKED);
         }
 
         /** Assemble the response */
@@ -1644,12 +1621,14 @@ final class NTLMEngineImpl implements NTLMEngine {
 
     }
 
+    @Override
     public String generateType1Msg(
             final String domain,
             final String workstation) throws NTLMEngineException {
         return getType1Message(workstation, domain);
     }
 
+    @Override
     public String generateType3Msg(
             final String username,
             final String password,
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java
index 88bd9fa..1ec4957 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java
@@ -77,20 +77,24 @@ public class NTLMScheme extends AuthSchemeBase {
         this(new NTLMEngineImpl());
     }
 
+    @Override
     public String getSchemeName() {
         return "ntlm";
     }
 
+    @Override
     public String getParameter(final String name) {
         // String parameters not supported
         return null;
     }
 
+    @Override
     public String getRealm() {
         // NTLM does not support the concept of an authentication realm
         return null;
     }
 
+    @Override
     public boolean isConnectionBased() {
         return true;
     }
@@ -100,7 +104,7 @@ public class NTLMScheme extends AuthSchemeBase {
             final CharArrayBuffer buffer,
             final int beginIndex, final int endIndex) throws MalformedChallengeException {
         this.challenge = buffer.substringTrimmed(beginIndex, endIndex);
-        if (this.challenge.length() == 0) {
+        if (this.challenge.isEmpty()) {
             if (this.state == State.UNINITIATED) {
                 this.state = State.CHALLENGE_RECEIVED;
             } else {
@@ -116,6 +120,7 @@ public class NTLMScheme extends AuthSchemeBase {
         }
     }
 
+    @Override
     public Header authenticate(
             final Credentials credentials,
             final HttpRequest request) throws AuthenticationException {
@@ -157,6 +162,7 @@ public class NTLMScheme extends AuthSchemeBase {
         return new BufferedHeader(buffer);
     }
 
+    @Override
     public boolean isComplete() {
         return this.state == State.MSG_TYPE3_GENERATED || this.state == State.FAILED;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMSchemeFactory.java
index 55c0d84..8e38c82 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMSchemeFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMSchemeFactory.java
@@ -45,10 +45,12 @@ import org.apache.http.protocol.HttpContext;
 @SuppressWarnings("deprecation")
 public class NTLMSchemeFactory implements AuthSchemeFactory, AuthSchemeProvider {
 
+    @Override
     public AuthScheme newInstance(final HttpParams params) {
         return new NTLMScheme();
     }
 
+    @Override
     public AuthScheme create(final HttpContext context) {
         return new NTLMScheme();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java
index 4dce058..8415d48 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java
@@ -26,6 +26,11 @@
  */
 package org.apache.http.impl.auth;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Locale;
@@ -42,6 +47,7 @@ import org.apache.http.message.BasicHeaderValueParser;
 import org.apache.http.message.HeaderValueParser;
 import org.apache.http.message.ParserCursor;
 import org.apache.http.util.CharArrayBuffer;
+import org.apache.http.util.CharsetUtils;
 
 /**
  * Abstract authentication scheme class that lays foundation for all
@@ -52,13 +58,15 @@ import org.apache.http.util.CharArrayBuffer;
  */
 @SuppressWarnings("deprecation")
 @NotThreadSafe // AuthSchemeBase, params
-public abstract class RFC2617Scheme extends AuthSchemeBase {
+public abstract class RFC2617Scheme extends AuthSchemeBase implements Serializable {
+
+    private static final long serialVersionUID = -2845454858205884623L;
 
     private final Map<String, String> params;
-    private final Charset credentialsCharset;
+    private transient Charset credentialsCharset;
 
     /**
-     * Creates an instance of <tt>RFC2617Scheme</tt> with the given challenge
+     * Creates an instance of {@code RFC2617Scheme} with the given challenge
      * state.
      *
      * @since 4.2
@@ -90,7 +98,7 @@ public abstract class RFC2617Scheme extends AuthSchemeBase {
      * @since 4.3
      */
     public Charset getCredentialsCharset() {
-        return credentialsCharset;
+        return credentialsCharset != null ? credentialsCharset : Consts.ASCII;
     }
 
     String getCredentialsCharset(final HttpRequest request) {
@@ -107,12 +115,9 @@ public abstract class RFC2617Scheme extends AuthSchemeBase {
         final HeaderValueParser parser = BasicHeaderValueParser.INSTANCE;
         final ParserCursor cursor = new ParserCursor(pos, buffer.length());
         final HeaderElement[] elements = parser.parseElements(buffer, cursor);
-        if (elements.length == 0) {
-            throw new MalformedChallengeException("Authentication challenge is empty");
-        }
         this.params.clear();
         for (final HeaderElement element : elements) {
-            this.params.put(element.getName().toLowerCase(Locale.ENGLISH), element.getValue());
+            this.params.put(element.getName().toLowerCase(Locale.ROOT), element.getValue());
         }
     }
 
@@ -132,11 +137,12 @@ public abstract class RFC2617Scheme extends AuthSchemeBase {
      *
      * @return the parameter with the given name
      */
+    @Override
     public String getParameter(final String name) {
         if (name == null) {
             return null;
         }
-        return this.params.get(name.toLowerCase(Locale.ENGLISH));
+        return this.params.get(name.toLowerCase(Locale.ROOT));
     }
 
     /**
@@ -144,8 +150,26 @@ public abstract class RFC2617Scheme extends AuthSchemeBase {
      *
      * @return the authentication realm
      */
+    @Override
     public String getRealm() {
         return getParameter("realm");
     }
 
+    private void writeObject(final ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        out.writeUTF(this.credentialsCharset.name());
+    }
+
+    @SuppressWarnings("unchecked")
+    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        this.credentialsCharset = CharsetUtils.get(in.readUTF());
+        if (this.credentialsCharset == null) {
+            this.credentialsCharset = Consts.ASCII;
+        }
+    }
+
+    private void readObjectNoData() throws ObjectStreamException {
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java
index 365fc26..808738b 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java
@@ -47,14 +47,22 @@ public class SPNegoScheme extends GGSSchemeBase {
 
     private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
 
+    /**
+     * @since 4.4
+     */
+    public SPNegoScheme(final boolean stripPort, final boolean useCanonicalHostname) {
+        super(stripPort, useCanonicalHostname);
+    }
+
     public SPNegoScheme(final boolean stripPort) {
         super(stripPort);
     }
 
     public SPNegoScheme() {
-        super(false);
+        super();
     }
 
+    @Override
     public String getSchemeName() {
         return "Negotiate";
     }
@@ -79,17 +87,23 @@ public class SPNegoScheme extends GGSSchemeBase {
         return super.authenticate(credentials, request, context);
     }
 
-    @Override
+    @Override @SuppressWarnings("deprecation")
     protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
-        return generateGSSToken(input, new Oid(SPNEGO_OID), authServer);
+        return super.generateToken(input, authServer);
+    }
+
+    @Override
+    protected byte[] generateToken(final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
+        return generateGSSToken(input, new Oid(SPNEGO_OID), authServer, credentials);
     }
 
     /**
      * There are no valid parameters for SPNEGO authentication so this
-     * method always returns <code>null</code>.
+     * method always returns {@code null}.
      *
-     * @return <code>null</code>
+     * @return {@code null}
      */
+    @Override
     public String getParameter(final String name) {
         Args.notNull(name, "Parameter name");
         return null;
@@ -97,19 +111,21 @@ public class SPNegoScheme extends GGSSchemeBase {
 
     /**
      * The concept of an authentication realm is not supported by the Negotiate
-     * authentication scheme. Always returns <code>null</code>.
+     * authentication scheme. Always returns {@code null}.
      *
-     * @return <code>null</code>
+     * @return {@code null}
      */
+    @Override
     public String getRealm() {
         return null;
     }
 
     /**
-     * Returns <tt>true</tt>. SPNEGO authentication scheme is connection based.
+     * Returns {@code true}. SPNEGO authentication scheme is connection based.
      *
-     * @return <tt>true</tt>.
+     * @return {@code true}.
      */
+    @Override
     public boolean isConnectionBased() {
         return true;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoSchemeFactory.java
index 2afa548..42e506d 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoSchemeFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoSchemeFactory.java
@@ -44,26 +44,43 @@ import org.apache.http.protocol.HttpContext;
 public class SPNegoSchemeFactory implements AuthSchemeFactory, AuthSchemeProvider {
 
     private final boolean stripPort;
+    private final boolean useCanonicalHostname;
+
+    /**
+     * @since 4.4
+     */
+    public SPNegoSchemeFactory(final boolean stripPort, final boolean useCanonicalHostname) {
+        super();
+        this.stripPort = stripPort;
+        this.useCanonicalHostname = useCanonicalHostname;
+    }
 
     public SPNegoSchemeFactory(final boolean stripPort) {
         super();
         this.stripPort = stripPort;
+        this.useCanonicalHostname = true;
     }
 
     public SPNegoSchemeFactory() {
-        this(false);
+        this(true, true);
     }
 
     public boolean isStripPort() {
         return stripPort;
     }
 
+    public boolean isUseCanonicalHostname() {
+        return useCanonicalHostname;
+    }
+
+    @Override
     public AuthScheme newInstance(final HttpParams params) {
-        return new SPNegoScheme(this.stripPort);
+        return new SPNegoScheme(this.stripPort, this.useCanonicalHostname);
     }
 
+    @Override
     public AuthScheme create(final HttpContext context) {
-        return new SPNegoScheme(this.stripPort);
+        return new SPNegoScheme(this.stripPort, this.useCanonicalHostname);
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java b/httpclient/src/main/java/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java
index a546fa7..2d6b6ec 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.java
@@ -41,7 +41,7 @@ public class UnsupportedDigestAlgorithmException extends RuntimeException {
     private static final long serialVersionUID = 319558534317118022L;
 
     /**
-     * Creates a new UnsupportedAuthAlgoritmException with a <tt>null</tt> detail message.
+     * Creates a new UnsupportedAuthAlgoritmException with a {@code null} detail message.
      */
     public UnsupportedDigestAlgorithmException() {
         super();
@@ -60,8 +60,8 @@ public class UnsupportedDigestAlgorithmException extends RuntimeException {
      * Creates a new UnsupportedAuthAlgoritmException with the specified detail message and cause.
      *
      * @param message the exception detail message
-     * @param cause the <tt>Throwable</tt> that caused this exception, or <tt>null</tt>
-     * if the cause is unavailable, unknown, or not a <tt>Throwable</tt>
+     * @param cause the {@code Throwable} that caused this exception, or {@code null}
+     * if the cause is unavailable, unknown, or not a {@code Throwable}
      */
     public UnsupportedDigestAlgorithmException(final String message, final Throwable cause) {
         super(message, cause);
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/AIMDBackoffManager.java b/httpclient/src/main/java/org/apache/http/impl/client/AIMDBackoffManager.java
index 2ce2265..164febc 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/AIMDBackoffManager.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/AIMDBackoffManager.java
@@ -35,7 +35,7 @@ import org.apache.http.pool.ConnPoolControl;
 import org.apache.http.util.Args;
 
 /**
- * <p>The <code>AIMDBackoffManager</code> applies an additive increase,
+ * <p>The {@code AIMDBackoffManager} applies an additive increase,
  * multiplicative decrease (AIMD) to managing a dynamic limit to
  * the number of connections allowed to a given host. You may want
  * to experiment with the settings for the cooldown periods and the
@@ -65,7 +65,7 @@ public class AIMDBackoffManager implements BackoffManager {
     private int cap = 2; // Per RFC 2616 sec 8.1.4
 
     /**
-     * Creates an <code>AIMDBackoffManager</code> to manage
+     * Creates an {@code AIMDBackoffManager} to manage
      * per-host connection pool sizes represented by the
      * given {@link ConnPoolControl}.
      * @param connPerRoute per-host routing maximums to
@@ -82,6 +82,7 @@ public class AIMDBackoffManager implements BackoffManager {
         this.lastRouteBackoffs = new HashMap<HttpRoute,Long>();
     }
 
+    @Override
     public void backOff(final HttpRoute route) {
         synchronized(connPerRoute) {
             final int curr = connPerRoute.getMaxPerRoute(route);
@@ -102,6 +103,7 @@ public class AIMDBackoffManager implements BackoffManager {
         return (int)(Math.floor(backoffFactor * curr));
     }
 
+    @Override
     public void probe(final HttpRoute route) {
         synchronized(connPerRoute) {
             final int curr = connPerRoute.getMaxPerRoute(route);
@@ -128,7 +130,7 @@ public class AIMDBackoffManager implements BackoffManager {
     /**
      * Sets the factor to use when backing off; the new
      * per-host limit will be roughly the current max times
-     * this factor. <code>Math.floor</code> is applied in the
+     * this factor. {@code Math.floor} is applied in the
      * case of non-integer outcomes to ensure we actually
      * decrease the pool size. Pool sizes are never decreased
      * below 1, however. Defaults to 0.5.
@@ -154,7 +156,7 @@ public class AIMDBackoffManager implements BackoffManager {
     /**
      * Sets the absolute maximum per-host connection pool size to
      * probe up to; defaults to 2 (the default per-host max).
-     * @param cap must be >= 1
+     * @param cap must be >= 1
      */
     public void setPerHostConnectionCap(final int cap) {
         Args.positive(cap, "Per host connection cap");
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java b/httpclient/src/main/java/org/apache/http/impl/client/AbstractResponseHandler.java
similarity index 71%
copy from httpclient/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java
copy to httpclient/src/main/java/org/apache/http/impl/client/AbstractResponseHandler.java
index 3a86a99..290a88c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/AbstractResponseHandler.java
@@ -38,27 +38,29 @@ import org.apache.http.client.ResponseHandler;
 import org.apache.http.util.EntityUtils;
 
 /**
- * A {@link ResponseHandler} that returns the response body as a String
- * for successful (2xx) responses. If the response code was >= 300, the response
+ * A generic {@link ResponseHandler} that works with the response entity
+ * for successful (2xx) responses. If the response code was >= 300, the response
  * body is consumed and an {@link HttpResponseException} is thrown.
- * <p/>
+ * <p>
  * If this is used with
  * {@link org.apache.http.client.HttpClient#execute(
  *  org.apache.http.client.methods.HttpUriRequest, ResponseHandler)},
  * HttpClient may handle redirects (3xx responses) internally.
+ * </p>
  *
- * @since 4.0
+ * @since 4.4
  */
 @Immutable
-public class BasicResponseHandler implements ResponseHandler<String> {
+public abstract class AbstractResponseHandler<T> implements ResponseHandler<T> {
 
     /**
-     * Returns the response body as a String if the response was successful (a
-     * 2xx status code). If no response body exists, this returns null. If the
-     * response was unsuccessful (>= 300 status code), throws an
-     * {@link HttpResponseException}.
+     * Read the entity from the response body and pass it to the entity handler
+     * method if the response was successful (a 2xx status code). If no response
+     * body exists, this returns null. If the response was unsuccessful (>= 300
+     * status code), throws an {@link HttpResponseException}.
      */
-    public String handleResponse(final HttpResponse response)
+    @Override
+    public T handleResponse(final HttpResponse response)
             throws HttpResponseException, IOException {
         final StatusLine statusLine = response.getStatusLine();
         final HttpEntity entity = response.getEntity();
@@ -67,7 +69,13 @@ public class BasicResponseHandler implements ResponseHandler<String> {
             throw new HttpResponseException(statusLine.getStatusCode(),
                     statusLine.getReasonPhrase());
         }
-        return entity == null ? null : EntityUtils.toString(entity);
+        return entity == null ? null : handleEntity(entity);
     }
 
+    /**
+     * Handle the response entity and transform it into the actual response
+     * object.
+     */
+    public abstract T handleEntity(HttpEntity entity) throws IOException;
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java b/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java
index 8eff4a0..cd15aea 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java
@@ -68,7 +68,8 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
     private final Log log = LogFactory.getLog(getClass());
 
     private static final List<String> DEFAULT_SCHEME_PRIORITY =
-        Collections.unmodifiableList(Arrays.asList(AuthSchemes.SPNEGO,
+        Collections.unmodifiableList(Arrays.asList(
+                AuthSchemes.SPNEGO,
                 AuthSchemes.KERBEROS,
                 AuthSchemes.NTLM,
                 AuthSchemes.DIGEST,
@@ -77,12 +78,17 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
     private final int challengeCode;
     private final String headerName;
 
+    /**
+     * @param challengeCode for example SC_PROXY_AUTHENTICATION_REQUIRED or SC_UNAUTHORIZED
+     * @param headerName for example "Proxy-Authenticate" or "WWW-Authenticate"
+     */
     AuthenticationStrategyImpl(final int challengeCode, final String headerName) {
         super();
         this.challengeCode = challengeCode;
         this.headerName = headerName;
     }
 
+    @Override
     public boolean isAuthenticationRequested(
             final HttpHost authhost,
             final HttpResponse response,
@@ -92,6 +98,12 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
         return status == this.challengeCode;
     }
 
+    /**
+     * Generates a map of challenge auth-scheme => Header entries.
+     *
+     * @return map: key=lower-cased auth-scheme name, value=Header that contains the challenge
+     */
+    @Override
     public Map<String, Header> getChallenges(
             final HttpHost authhost,
             final HttpResponse response,
@@ -123,13 +135,14 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
             }
             final int endIndex = pos;
             final String s = buffer.substring(beginIndex, endIndex);
-            map.put(s.toLowerCase(Locale.ENGLISH), header);
+            map.put(s.toLowerCase(Locale.ROOT), header);
         }
         return map;
     }
 
     abstract Collection<String> getPreferredAuthSchemes(RequestConfig config);
 
+    @Override
     public Queue<AuthOption> select(
             final Map<String, Header> challenges,
             final HttpHost authhost,
@@ -162,7 +175,7 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
         }
 
         for (final String id: authPrefs) {
-            final Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
+            final Header challenge = challenges.get(id.toLowerCase(Locale.ROOT));
             if (challenge != null) {
                 final AuthSchemeProvider authSchemeProvider = registry.lookup(id);
                 if (authSchemeProvider == null) {
@@ -195,6 +208,7 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
         return options;
     }
 
+    @Override
     public void authSucceeded(
             final HttpHost authhost, final AuthScheme authScheme, final HttpContext context) {
         Args.notNull(authhost, "Host");
@@ -226,6 +240,7 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
                 schemeName.equalsIgnoreCase(AuthSchemes.DIGEST);
     }
 
+    @Override
     public void authFailed(
             final HttpHost authhost, final AuthScheme authScheme, final HttpContext context) {
         Args.notNull(authhost, "Host");
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java b/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
index bf3a2cf..bd4898c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
@@ -26,10 +26,19 @@
  */
 package org.apache.http.impl.client;
 
-import java.util.HashMap;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.http.HttpHost;
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.auth.AuthScheme;
 import org.apache.http.client.AuthCache;
 import org.apache.http.conn.SchemePortResolver;
@@ -38,14 +47,21 @@ import org.apache.http.impl.conn.DefaultSchemePortResolver;
 import org.apache.http.util.Args;
 
 /**
- * Default implementation of {@link AuthCache}.
+ * Default implementation of {@link org.apache.http.client.AuthCache}. This implements
+ * expects {@link org.apache.http.auth.AuthScheme} to be {@link java.io.Serializable}
+ * in order to be cacheable.
+ * <p>
+ * Instances of this class are thread safe as of version 4.4.
+ * </p>
  *
- * @since 4.0
+ * @since 4.1
  */
- at NotThreadSafe
+ at ThreadSafe
 public class BasicAuthCache implements AuthCache {
 
-    private final HashMap<HttpHost, AuthScheme> map;
+    private final Log log = LogFactory.getLog(getClass());
+
+    private final Map<HttpHost, byte[]> map;
     private final SchemePortResolver schemePortResolver;
 
     /**
@@ -55,7 +71,7 @@ public class BasicAuthCache implements AuthCache {
      */
     public BasicAuthCache(final SchemePortResolver schemePortResolver) {
         super();
-        this.map = new HashMap<HttpHost, AuthScheme>();
+        this.map = new ConcurrentHashMap<HttpHost, byte[]>();
         this.schemePortResolver = schemePortResolver != null ? schemePortResolver :
             DefaultSchemePortResolver.INSTANCE;
     }
@@ -78,21 +94,65 @@ public class BasicAuthCache implements AuthCache {
         }
     }
 
+    @Override
     public void put(final HttpHost host, final AuthScheme authScheme) {
         Args.notNull(host, "HTTP host");
-        this.map.put(getKey(host), authScheme);
+        if (authScheme == null) {
+            return;
+        }
+        if (authScheme instanceof Serializable) {
+            try {
+                final ByteArrayOutputStream buf = new ByteArrayOutputStream();
+                final ObjectOutputStream out = new ObjectOutputStream(buf);
+                out.writeObject(authScheme);
+                out.close();
+                this.map.put(getKey(host), buf.toByteArray());
+            } catch (IOException ex) {
+                if (log.isWarnEnabled()) {
+                    log.warn("Unexpected I/O error while serializing auth scheme", ex);
+                }
+            }
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("Auth scheme " + authScheme.getClass() + " is not serializable");
+            }
+        }
     }
 
+    @Override
     public AuthScheme get(final HttpHost host) {
         Args.notNull(host, "HTTP host");
-        return this.map.get(getKey(host));
+        final byte[] bytes = this.map.get(getKey(host));
+        if (bytes != null) {
+            try {
+                final ByteArrayInputStream buf = new ByteArrayInputStream(bytes);
+                final ObjectInputStream in = new ObjectInputStream(buf);
+                final AuthScheme authScheme = (AuthScheme) in.readObject();
+                in.close();
+                return authScheme;
+            } catch (IOException ex) {
+                if (log.isWarnEnabled()) {
+                    log.warn("Unexpected I/O error while de-serializing auth scheme", ex);
+                }
+                return null;
+            } catch (ClassNotFoundException ex) {
+                if (log.isWarnEnabled()) {
+                    log.warn("Unexpected error while de-serializing auth scheme", ex);
+                }
+                return null;
+            }
+        } else {
+            return null;
+        }
     }
 
+    @Override
     public void remove(final HttpHost host) {
         Args.notNull(host, "HTTP host");
         this.map.remove(getKey(host));
     }
 
+    @Override
     public void clear() {
         this.map.clear();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/BasicCookieStore.java b/httpclient/src/main/java/org/apache/http/impl/client/BasicCookieStore.java
index 9f1b5d1..52b76b1 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/BasicCookieStore.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/BasicCookieStore.java
@@ -68,6 +68,7 @@ public class BasicCookieStore implements CookieStore, Serializable {
      * @see #addCookies(Cookie[])
      *
      */
+    @Override
     public synchronized void addCookie(final Cookie cookie) {
         if (cookie != null) {
             // first remove any old cookie that is equivalent
@@ -102,6 +103,7 @@ public class BasicCookieStore implements CookieStore, Serializable {
      *
      * @return an array of {@link Cookie cookies}.
      */
+    @Override
     public synchronized List<Cookie> getCookies() {
         //create defensive copy so it won't be concurrently modified
         return new ArrayList<Cookie>(cookies);
@@ -115,6 +117,7 @@ public class BasicCookieStore implements CookieStore, Serializable {
      *
      * @see Cookie#isExpired(Date)
      */
+    @Override
     public synchronized boolean clearExpired(final Date date) {
         if (date == null) {
             return false;
@@ -132,6 +135,7 @@ public class BasicCookieStore implements CookieStore, Serializable {
     /**
      * Clears all cookies.
      */
+    @Override
     public synchronized void clear() {
         cookies.clear();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java b/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java
index b1dc663..352bbfd 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java
@@ -53,6 +53,7 @@ public class BasicCredentialsProvider implements CredentialsProvider {
         this.credMap = new ConcurrentHashMap<AuthScope, Credentials>();
     }
 
+    @Override
     public void setCredentials(
             final AuthScope authscope,
             final Credentials credentials) {
@@ -92,11 +93,13 @@ public class BasicCredentialsProvider implements CredentialsProvider {
         return creds;
     }
 
+    @Override
     public Credentials getCredentials(final AuthScope authscope) {
         Args.notNull(authscope, "Authentication scope");
         return matchCredentials(this.credMap, authscope);
     }
 
+    @Override
     public void clear() {
         this.credMap.clear();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java b/httpclient/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java
index 3a86a99..76766ea 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/BasicResponseHandler.java
@@ -31,43 +31,38 @@ import java.io.IOException;
 
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
 import org.apache.http.annotation.Immutable;
 import org.apache.http.client.HttpResponseException;
-import org.apache.http.client.ResponseHandler;
 import org.apache.http.util.EntityUtils;
 
 /**
- * A {@link ResponseHandler} that returns the response body as a String
- * for successful (2xx) responses. If the response code was >= 300, the response
- * body is consumed and an {@link HttpResponseException} is thrown.
- * <p/>
+ * A {@link org.apache.http.client.ResponseHandler} that returns the response body as a String
+ * for successful (2xx) responses. If the response code was >= 300, the response
+ * body is consumed and an {@link org.apache.http.client.HttpResponseException} is thrown.
+ * <p>
  * If this is used with
  * {@link org.apache.http.client.HttpClient#execute(
- *  org.apache.http.client.methods.HttpUriRequest, ResponseHandler)},
+ *  org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler)},
  * HttpClient may handle redirects (3xx responses) internally.
+ * </p>
  *
  * @since 4.0
  */
 @Immutable
-public class BasicResponseHandler implements ResponseHandler<String> {
+public class BasicResponseHandler extends AbstractResponseHandler<String> {
 
     /**
-     * Returns the response body as a String if the response was successful (a
-     * 2xx status code). If no response body exists, this returns null. If the
-     * response was unsuccessful (>= 300 status code), throws an
-     * {@link HttpResponseException}.
+     * Returns the entity as a body as a String.
      */
-    public String handleResponse(final HttpResponse response)
-            throws HttpResponseException, IOException {
-        final StatusLine statusLine = response.getStatusLine();
-        final HttpEntity entity = response.getEntity();
-        if (statusLine.getStatusCode() >= 300) {
-            EntityUtils.consume(entity);
-            throw new HttpResponseException(statusLine.getStatusCode(),
-                    statusLine.getReasonPhrase());
-        }
-        return entity == null ? null : EntityUtils.toString(entity);
+    @Override
+    public String handleEntity(final HttpEntity entity) throws IOException {
+        return EntityUtils.toString(entity);
+    }
+
+    @Override
+    public String handleResponse(
+            final HttpResponse response) throws HttpResponseException, IOException {
+        return super.handleResponse(response);
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/CloseableHttpClient.java b/httpclient/src/main/java/org/apache/http/impl/client/CloseableHttpClient.java
index 5835af8..16dfae2 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/CloseableHttpClient.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/CloseableHttpClient.java
@@ -29,7 +29,6 @@ package org.apache.http.impl.client;
 
 import java.io.Closeable;
 import java.io.IOException;
-import java.lang.reflect.UndeclaredThrowableException;
 import java.net.URI;
 
 import org.apache.commons.logging.Log;
@@ -37,7 +36,6 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
 import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.HttpClient;
@@ -65,6 +63,7 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
     /**
      * {@inheritDoc}
      */
+    @Override
     public CloseableHttpResponse execute(
             final HttpHost target,
             final HttpRequest request,
@@ -75,6 +74,7 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
     /**
      * {@inheritDoc}
      */
+    @Override
     public CloseableHttpResponse execute(
             final HttpUriRequest request,
             final HttpContext context) throws IOException, ClientProtocolException {
@@ -101,6 +101,7 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
     /**
      * {@inheritDoc}
      */
+    @Override
     public CloseableHttpResponse execute(
             final HttpUriRequest request) throws IOException, ClientProtocolException {
         return execute(request, (HttpContext) null);
@@ -109,10 +110,11 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
     /**
      * {@inheritDoc}
      */
+    @Override
     public CloseableHttpResponse execute(
             final HttpHost target,
             final HttpRequest request) throws IOException, ClientProtocolException {
-        return doExecute(target, request, (HttpContext) null);
+        return doExecute(target, request, null);
     }
 
     /**
@@ -130,6 +132,7 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
      * @throws IOException in case of a problem or the connection was aborted
      * @throws ClientProtocolException in case of an http protocol error
      */
+    @Override
     public <T> T execute(final HttpUriRequest request,
             final ResponseHandler<? extends T> responseHandler) throws IOException,
             ClientProtocolException {
@@ -147,12 +150,13 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
      * @param request   the request to execute
      * @param responseHandler the response handler
      * @param context   the context to use for the execution, or
-     *                  <code>null</code> to use the default context
+     *                  {@code null} to use the default context
      *
      * @return  the response object as generated by the response handler.
      * @throws IOException in case of a problem or the connection was aborted
      * @throws ClientProtocolException in case of an http protocol error
      */
+    @Override
     public <T> T execute(final HttpUriRequest request,
             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
             throws IOException, ClientProtocolException {
@@ -169,7 +173,7 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
      * resource deallocation internally.
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
@@ -179,6 +183,7 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
      * @throws IOException in case of a problem or the connection was aborted
      * @throws ClientProtocolException in case of an http protocol error
      */
+    @Override
     public <T> T execute(final HttpHost target, final HttpRequest request,
             final ResponseHandler<? extends T> responseHandler) throws IOException,
             ClientProtocolException {
@@ -194,29 +199,32 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
      * resource deallocation internally.
      *
      * @param target    the target host for the request.
-     *                  Implementations may accept <code>null</code>
+     *                  Implementations may accept {@code null}
      *                  if they can still determine a route, for example
      *                  to a default target or by inspecting the request.
      * @param request   the request to execute
      * @param responseHandler the response handler
      * @param context   the context to use for the execution, or
-     *                  <code>null</code> to use the default context
+     *                  {@code null} to use the default context
      *
      * @return  the response object as generated by the response handler.
      * @throws IOException in case of a problem or the connection was aborted
      * @throws ClientProtocolException in case of an http protocol error
      */
+    @Override
     public <T> T execute(final HttpHost target, final HttpRequest request,
             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
             throws IOException, ClientProtocolException {
         Args.notNull(responseHandler, "Response handler");
 
-        final HttpResponse response = execute(target, request, context);
-
-        final T result;
+        final CloseableHttpResponse response = execute(target, request, context);
         try {
-            result = responseHandler.handleResponse(response);
-        } catch (final Exception t) {
+            final T result = responseHandler.handleResponse(response);
+            final HttpEntity entity = response.getEntity();
+            EntityUtils.consume(entity);
+            return result;
+        } catch (final ClientProtocolException t) {
+            // Try to salvage the underlying connection in case of a protocol exception
             final HttpEntity entity = response.getEntity();
             try {
                 EntityUtils.consume(entity);
@@ -225,20 +233,10 @@ public abstract class CloseableHttpClient implements HttpClient, Closeable {
                 // important and will be thrown to the caller.
                 this.log.warn("Error consuming content after an exception.", t2);
             }
-            if (t instanceof RuntimeException) {
-                throw (RuntimeException) t;
-            }
-            if (t instanceof IOException) {
-                throw (IOException) t;
-            }
-            throw new UndeclaredThrowableException(t);
+            throw t;
+        } finally {
+            response.close();
         }
-
-        // Handling the response was successful. Ensure that the content has
-        // been fully consumed.
-        final HttpEntity entity = response.getEntity();
-        EntityUtils.consume(entity);
-        return result;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultBackoffStrategy.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultBackoffStrategy.java
index 3d79034..7a838af 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultBackoffStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultBackoffStrategy.java
@@ -42,11 +42,13 @@ import org.apache.http.client.ConnectionBackoffStrategy;
  */
 public class DefaultBackoffStrategy implements ConnectionBackoffStrategy {
 
+    @Override
     public boolean shouldBackoff(final Throwable t) {
         return (t instanceof SocketTimeoutException
                 || t instanceof ConnectException);
     }
 
+    @Override
     public boolean shouldBackoff(final HttpResponse resp) {
         return (resp.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE);
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java
index 129e1dd..6e757d1 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java
@@ -50,6 +50,7 @@ public class DefaultConnectionKeepAliveStrategy implements ConnectionKeepAliveSt
 
     public static final DefaultConnectionKeepAliveStrategy INSTANCE = new DefaultConnectionKeepAliveStrategy();
 
+    @Override
     public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
         Args.notNull(response, "HTTP response");
         final HeaderElementIterator it = new BasicHeaderElementIterator(
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java
index 502e3bd..b647cd3 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java
@@ -96,7 +96,7 @@ public class DefaultHttpRequestRetryHandler implements HttpRequestRetryHandler {
      * <li>SSLException</li>
      * </ul>
      * @param retryCount how many times to retry; 0 means no retries
-     * @param requestSentRetryEnabled true if it's OK to retry requests that have been sent
+     * @param requestSentRetryEnabled true if it's OK to retry non-idempotent requests that have been sent
      */
     @SuppressWarnings("unchecked")
     public DefaultHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled) {
@@ -121,9 +121,10 @@ public class DefaultHttpRequestRetryHandler implements HttpRequestRetryHandler {
         this(3, false);
     }
     /**
-     * Used <code>retryCount</code> and <code>requestSentRetryEnabled</code> to determine
+     * Used {@code retryCount} and {@code requestSentRetryEnabled} to determine
      * if the given method should be retried.
      */
+    @Override
     public boolean retryRequest(
             final IOException exception,
             final int executionCount,
@@ -165,8 +166,8 @@ public class DefaultHttpRequestRetryHandler implements HttpRequestRetryHandler {
     }
 
     /**
-     * @return <code>true</code> if this handler will retry methods that have
-     * successfully sent their request, <code>false</code> otherwise
+     * @return {@code true} if this handler will retry methods that have
+     * successfully sent their request, {@code false} otherwise
      */
     public boolean isRequestSentRetryEnabled() {
         return requestSentRetryEnabled;
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultRedirectStrategy.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultRedirectStrategy.java
index 4f7a6a6..47249ee 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultRedirectStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultRedirectStrategy.java
@@ -58,13 +58,14 @@ import org.apache.http.util.TextUtils;
 /**
  * Default implementation of {@link RedirectStrategy}. This strategy honors the restrictions
  * on automatic redirection of entity enclosing methods such as POST and PUT imposed by the
- * HTTP specification. <tt>302 Moved Temporarily</tt>, <tt>301 Moved Permanently</tt> and
- * <tt>307 Temporary Redirect</tt> status codes will result in an automatic redirect of
+ * HTTP specification. {@code 302 Moved Temporarily}, {@code 301 Moved Permanently} and
+ * {@code 307 Temporary Redirect} status codes will result in an automatic redirect of
  * HEAD and GET methods only. POST and PUT methods will not be automatically redirected
  * as requiring user confirmation.
- * <p/>
+ * <p>
  * The restriction on automatic redirection of POST methods can be relaxed by using
  * {@link LaxRedirectStrategy} instead of {@link DefaultRedirectStrategy}.
+ * </p>
  *
  * @see LaxRedirectStrategy
  * @since 4.1
@@ -94,6 +95,7 @@ public class DefaultRedirectStrategy implements RedirectStrategy {
         super();
     }
 
+    @Override
     public boolean isRedirected(
             final HttpRequest request,
             final HttpResponse response,
@@ -186,7 +188,7 @@ public class DefaultRedirectStrategy implements RedirectStrategy {
             final URIBuilder b = new URIBuilder(new URI(location).normalize());
             final String host = b.getHost();
             if (host != null) {
-                b.setHost(host.toLowerCase(Locale.ENGLISH));
+                b.setHost(host.toLowerCase(Locale.ROOT));
             }
             final String path = b.getPath();
             if (TextUtils.isEmpty(path)) {
@@ -210,6 +212,7 @@ public class DefaultRedirectStrategy implements RedirectStrategy {
         return false;
     }
 
+    @Override
     public HttpUriRequest getRedirect(
             final HttpRequest request,
             final HttpResponse response,
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultServiceUnavailableRetryStrategy.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultServiceUnavailableRetryStrategy.java
index b5d76ea..f007207 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultServiceUnavailableRetryStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultServiceUnavailableRetryStrategy.java
@@ -36,7 +36,7 @@ import org.apache.http.util.Args;
 
 /**
  * Default implementation of the {@link ServiceUnavailableRetryStrategy} interface.
- * that retries <code>503</code> (Service Unavailable) responses for a fixed number of times
+ * that retries {@code 503} (Service Unavailable) responses for a fixed number of times
  * at a fixed interval.
  *
  * @since 4.2
@@ -68,11 +68,13 @@ public class DefaultServiceUnavailableRetryStrategy implements ServiceUnavailabl
         this(1, 1000);
     }
 
+    @Override
     public boolean retryRequest(final HttpResponse response, final int executionCount, final HttpContext context) {
         return executionCount <= maxRetries &&
             response.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE;
     }
 
+    @Override
     public long getRetryInterval() {
         return retryInterval;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java
index 1ac4439..99fc922 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java
@@ -50,7 +50,7 @@ import org.apache.http.protocol.HttpContext;
  * DefaultUserTokenHandler will use the user principle of connection
  * based authentication schemes such as NTLM or that of the SSL session
  * with the client authentication turned on. If both are unavailable,
- * <code>null</code> token will be returned.
+ * {@code null} token will be returned.
  *
  * @since 4.0
  */
@@ -59,6 +59,7 @@ public class DefaultUserTokenHandler implements UserTokenHandler {
 
     public static final DefaultUserTokenHandler INSTANCE = new DefaultUserTokenHandler();
 
+    @Override
     public Object getUserToken(final HttpContext context) {
 
         final HttpClientContext clientContext = HttpClientContext.adapt(context);
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java b/httpclient/src/main/java/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java
index 59d17ae..15aedd5 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/EntityEnclosingRequestWrapper.java
@@ -43,9 +43,10 @@ import org.apache.http.protocol.HTTP;
  * A wrapper class for {@link HttpEntityEnclosingRequest}s that can
  * be used to change properties of the current request without
  * modifying the original object.
- * </p>
+ * <p>
  * This class is also capable of resetting the request headers to
  * the state of the original request.
+ * </p>
  *
  * @since 4.0
  *
@@ -65,15 +66,18 @@ public class EntityEnclosingRequestWrapper extends RequestWrapper
         setEntity(request.getEntity());
     }
 
+    @Override
     public HttpEntity getEntity() {
         return this.entity;
     }
 
+    @Override
     public void setEntity(final HttpEntity entity) {
         this.entity = entity != null ? new EntityWrapper(entity) : null;
         this.consumed = false;
     }
 
+    @Override
     public boolean expectContinue() {
         final Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
         return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/FutureRequestExecutionService.java b/httpclient/src/main/java/org/apache/http/impl/client/FutureRequestExecutionService.java
index 8e03fa3..0fcfd4d 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/FutureRequestExecutionService.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/FutureRequestExecutionService.java
@@ -80,7 +80,6 @@ public class FutureRequestExecutionService implements Closeable {
      * @param responseHandler
      *            handler that will process the response.
      * @return HttpAsyncClientFutureTask for the scheduled request.
-     * @throws InterruptedException
      */
     public <T> HttpRequestFutureTask<T> execute(
             final HttpUriRequest request,
@@ -104,7 +103,6 @@ public class FutureRequestExecutionService implements Closeable {
      *            callback handler that will be called when the request is scheduled,
      *            started, completed, failed, or cancelled.
      * @return HttpAsyncClientFutureTask for the scheduled request.
-     * @throws InterruptedException
      */
     public <T> HttpRequestFutureTask<T> execute(
             final HttpUriRequest request,
@@ -132,6 +130,7 @@ public class FutureRequestExecutionService implements Closeable {
         return metrics;
     }
 
+    @Override
     public void close() throws IOException {
         closed.set(true);
         executorService.shutdownNow();
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java b/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
index cee22db..ed5b22c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java
@@ -28,12 +28,17 @@
 package org.apache.http.impl.client;
 
 import java.io.Closeable;
+import java.io.IOException;
 import java.net.ProxySelector;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
+import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
 
@@ -56,6 +61,7 @@ import org.apache.http.client.UserTokenHandler;
 import org.apache.http.client.config.AuthSchemes;
 import org.apache.http.client.config.CookieSpecs;
 import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.InputStreamFactory;
 import org.apache.http.client.protocol.RequestAcceptEncoding;
 import org.apache.http.client.protocol.RequestAddCookies;
 import org.apache.http.client.protocol.RequestAuthCache;
@@ -75,9 +81,11 @@ import org.apache.http.conn.routing.HttpRoutePlanner;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLContexts;
 import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.apache.http.conn.util.PublicSuffixMatcherLoader;
 import org.apache.http.cookie.CookieSpecProvider;
 import org.apache.http.impl.DefaultConnectionReuseStrategy;
 import org.apache.http.impl.NoConnectionReuseStrategy;
@@ -91,12 +99,10 @@ import org.apache.http.impl.conn.DefaultRoutePlanner;
 import org.apache.http.impl.conn.DefaultSchemePortResolver;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
-import org.apache.http.impl.cookie.BestMatchSpecFactory;
-import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
-import org.apache.http.impl.cookie.IgnoreSpecFactory;
-import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
-import org.apache.http.impl.cookie.RFC2109SpecFactory;
-import org.apache.http.impl.cookie.RFC2965SpecFactory;
+import org.apache.http.impl.cookie.DefaultCookieSpecProvider;
+import org.apache.http.impl.cookie.IgnoreSpecProvider;
+import org.apache.http.impl.cookie.NetscapeDraftSpecProvider;
+import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
 import org.apache.http.impl.execchain.BackoffStrategyExec;
 import org.apache.http.impl.execchain.ClientExecChain;
 import org.apache.http.impl.execchain.MainClientExec;
@@ -107,20 +113,23 @@ import org.apache.http.impl.execchain.ServiceUnavailableRetryExec;
 import org.apache.http.protocol.HttpProcessor;
 import org.apache.http.protocol.HttpProcessorBuilder;
 import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.protocol.ImmutableHttpProcessor;
 import org.apache.http.protocol.RequestContent;
 import org.apache.http.protocol.RequestTargetHost;
 import org.apache.http.protocol.RequestUserAgent;
+import org.apache.http.ssl.SSLContexts;
 import org.apache.http.util.TextUtils;
 import org.apache.http.util.VersionInfo;
 
 /**
  * Builder for {@link CloseableHttpClient} instances.
- * <p/>
- * When a particular component is not explicitly this class will
+ * <p>
+ * When a particular component is not explicitly set this class will
  * use its default implementation. System properties will be taken
  * into account when configuring the default implementations when
  * {@link #useSystemProperties()} method is called prior to calling
  * {@link #build()}.
+ * </p>
  * <ul>
  *  <li>ssl.TrustManagerFactory.algorithm</li>
  *  <li>javax.net.ssl.trustStoreType</li>
@@ -141,10 +150,11 @@ import org.apache.http.util.VersionInfo;
  *  <li>http.maxConnections</li>
  *  <li>http.agent</li>
  * </ul>
- * <p/>
+ * <p>
  * Please note that some settings used by this class can be mutually
  * exclusive and may not apply when building {@link CloseableHttpClient}
  * instances.
+ * </p>
  *
  * @since 4.3
  */
@@ -152,10 +162,11 @@ import org.apache.http.util.VersionInfo;
 public class HttpClientBuilder {
 
     private HttpRequestExecutor requestExec;
-    private X509HostnameVerifier hostnameVerifier;
+    private HostnameVerifier hostnameVerifier;
     private LayeredConnectionSocketFactory sslSocketFactory;
     private SSLContext sslcontext;
     private HttpClientConnectionManager connManager;
+    private boolean connManagerShared;
     private SchemePortResolver schemePortResolver;
     private ConnectionReuseStrategy reuseStrategy;
     private ConnectionKeepAliveStrategy keepAliveStrategy;
@@ -177,6 +188,7 @@ public class HttpClientBuilder {
     private ServiceUnavailableRetryStrategy serviceUnavailStrategy;
     private Lookup<AuthSchemeProvider> authSchemeRegistry;
     private Lookup<CookieSpecProvider> cookieSpecRegistry;
+    private Map<String, InputStreamFactory> contentDecoderMap;
     private CookieStore cookieStore;
     private CredentialsProvider credentialsProvider;
     private String userAgent;
@@ -185,6 +197,10 @@ public class HttpClientBuilder {
     private SocketConfig defaultSocketConfig;
     private ConnectionConfig defaultConnectionConfig;
     private RequestConfig defaultRequestConfig;
+    private boolean evictExpiredConnections;
+    private boolean evictIdleConnections;
+    private long maxIdleTime;
+    private TimeUnit maxIdleTimeUnit;
 
     private boolean systemProperties;
     private boolean redirectHandlingDisabled;
@@ -197,16 +213,12 @@ public class HttpClientBuilder {
     private int maxConnTotal = 0;
     private int maxConnPerRoute = 0;
 
+    private long connTimeToLive = -1;
+    private TimeUnit connTimeToLiveTimeUnit = TimeUnit.MILLISECONDS;
+
     private List<Closeable> closeables;
 
-    static final String DEFAULT_USER_AGENT;
-    static {
-        final VersionInfo vi = VersionInfo.loadVersionInfo
-                ("org.apache.http.client", HttpClientBuilder.class.getClassLoader());
-        final String release = (vi != null) ?
-                vi.getRelease() : VersionInfo.UNAVAILABLE;
-        DEFAULT_USER_AGENT = "Apache-HttpClient/" + release + " (java 1.5)";
-    }
+    private PublicSuffixMatcher publicSuffixMatcher;
 
     public static HttpClientBuilder create() {
         return new HttpClientBuilder();
@@ -226,23 +238,56 @@ public class HttpClientBuilder {
 
     /**
      * Assigns {@link X509HostnameVerifier} instance.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setConnectionManager(
      *   org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
      *   org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
+     * </p>
+     *
+     *   @deprecated (4.4)
      */
+    @Deprecated
     public final HttpClientBuilder setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
         this.hostnameVerifier = hostnameVerifier;
         return this;
     }
 
     /**
+     * Assigns {@link javax.net.ssl.HostnameVerifier} instance.
+     * <p>
+     * Please note this value can be overridden by the {@link #setConnectionManager(
+     *   org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
+     *   org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
+     * </p>
+     *
+     *   @since 4.4
+     */
+    public final HttpClientBuilder setSSLHostnameVerifier(final HostnameVerifier hostnameVerifier) {
+        this.hostnameVerifier = hostnameVerifier;
+        return this;
+    }
+
+    /**
+     * Assigns file containing public suffix matcher. Instances of this class can be created
+     * with {@link org.apache.http.conn.util.PublicSuffixMatcherLoader}.
+     *
+     * @see org.apache.http.conn.util.PublicSuffixMatcher
+     * @see org.apache.http.conn.util.PublicSuffixMatcherLoader
+     *
+     *   @since 4.4
+     */
+    public final HttpClientBuilder setPublicSuffixMatcher(final PublicSuffixMatcher publicSuffixMatcher) {
+        this.publicSuffixMatcher = publicSuffixMatcher;
+        return this;
+    }
+
+    /**
      * Assigns {@link SSLContext} instance.
-     * <p/>
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setConnectionManager(
      *   org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
      *   org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
+     * </p>
      */
     public final HttpClientBuilder setSslcontext(final SSLContext sslcontext) {
         this.sslcontext = sslcontext;
@@ -251,9 +296,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns {@link LayeredConnectionSocketFactory} instance.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setConnectionManager(
      *   org.apache.http.conn.HttpClientConnectionManager)} method.
+     * </p>
      */
     public final HttpClientBuilder setSSLSocketFactory(
             final LayeredConnectionSocketFactory sslSocketFactory) {
@@ -263,9 +309,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns maximum total connection value.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setConnectionManager(
      *   org.apache.http.conn.HttpClientConnectionManager)} method.
+     * </p>
      */
     public final HttpClientBuilder setMaxConnTotal(final int maxConnTotal) {
         this.maxConnTotal = maxConnTotal;
@@ -274,9 +321,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns maximum connection per route value.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setConnectionManager(
      *   org.apache.http.conn.HttpClientConnectionManager)} method.
+     * </p>
      */
     public final HttpClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
         this.maxConnPerRoute = maxConnPerRoute;
@@ -285,9 +333,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns default {@link SocketConfig}.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setConnectionManager(
      *   org.apache.http.conn.HttpClientConnectionManager)} method.
+     * </p>
      */
     public final HttpClientBuilder setDefaultSocketConfig(final SocketConfig config) {
         this.defaultSocketConfig = config;
@@ -296,9 +345,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns default {@link ConnectionConfig}.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setConnectionManager(
      *   org.apache.http.conn.HttpClientConnectionManager)} method.
+     * </p>
      */
     public final HttpClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
         this.defaultConnectionConfig = config;
@@ -306,6 +356,21 @@ public class HttpClientBuilder {
     }
 
     /**
+     * Sets maximum time to live for persistent connections
+     * <p>
+     * Please note this value can be overridden by the {@link #setConnectionManager(
+     *   org.apache.http.conn.HttpClientConnectionManager)} method.
+     * </p>
+     *
+     * @since 4.4
+     */
+    public final HttpClientBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) {
+        this.connTimeToLive = connTimeToLive;
+        this.connTimeToLiveTimeUnit = connTimeToLiveTimeUnit;
+        return this;
+    }
+
+    /**
      * Assigns {@link HttpClientConnectionManager} instance.
      */
     public final HttpClientBuilder setConnectionManager(
@@ -315,6 +380,26 @@ public class HttpClientBuilder {
     }
 
     /**
+     * Defines the connection manager is to be shared by multiple
+     * client instances.
+     * <p>
+     * If the connection manager is shared its life-cycle is expected
+     * to be managed by the caller and it will not be shut down
+     * if the client is closed.
+     * </p>
+     *
+     * @param shared defines whether or not the connection manager can be shared
+     *  by multiple clients.
+     *
+     * @since 4.4
+     */
+    public final HttpClientBuilder setConnectionManagerShared(
+            final boolean shared) {
+        this.connManagerShared = shared;
+        return this;
+    }
+
+    /**
      * Assigns {@link ConnectionReuseStrategy} instance.
      */
     public final HttpClientBuilder setConnectionReuseStrategy(
@@ -333,8 +418,8 @@ public class HttpClientBuilder {
     }
 
     /**
-     * Assigns {@link AuthenticationStrategy} instance for proxy
-     * authentication.
+     * Assigns {@link AuthenticationStrategy} instance for target
+     * host authentication.
      */
     public final HttpClientBuilder setTargetAuthenticationStrategy(
             final AuthenticationStrategy targetAuthStrategy) {
@@ -343,8 +428,8 @@ public class HttpClientBuilder {
     }
 
     /**
-     * Assigns {@link AuthenticationStrategy} instance for target
-     * host authentication.
+     * Assigns {@link AuthenticationStrategy} instance for proxy
+     * authentication.
      */
     public final HttpClientBuilder setProxyAuthenticationStrategy(
             final AuthenticationStrategy proxyAuthStrategy) {
@@ -354,9 +439,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns {@link UserTokenHandler} instance.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #disableConnectionState()}
      * method.
+     * </p>
      */
     public final HttpClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
         this.userTokenHandler = userTokenHandler;
@@ -381,10 +467,11 @@ public class HttpClientBuilder {
     }
 
     /**
-     * Assigns <tt>User-Agent</tt> value.
-     * <p/>
+     * Assigns {@code User-Agent} value.
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
+     * </p>
      */
     public final HttpClientBuilder setUserAgent(final String userAgent) {
         this.userAgent = userAgent;
@@ -393,9 +480,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns default request header values.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
+     * </p>
      */
     public final HttpClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
         this.defaultHeaders = defaultHeaders;
@@ -404,9 +492,10 @@ public class HttpClientBuilder {
 
     /**
      * Adds this protocol interceptor to the head of the protocol processing list.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
+     * </p>
      */
     public final HttpClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
         if (itcp == null) {
@@ -421,9 +510,10 @@ public class HttpClientBuilder {
 
     /**
      * Adds this protocol interceptor to the tail of the protocol processing list.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
+     * </p>
      */
     public final HttpClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
         if (itcp == null) {
@@ -438,7 +528,7 @@ public class HttpClientBuilder {
 
     /**
      * Adds this protocol interceptor to the head of the protocol processing list.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
      */
@@ -455,7 +545,7 @@ public class HttpClientBuilder {
 
     /**
      * Adds this protocol interceptor to the tail of the protocol processing list.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
      */
@@ -472,7 +562,7 @@ public class HttpClientBuilder {
 
     /**
      * Disables state (cookie) management.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
      */
@@ -483,7 +573,7 @@ public class HttpClientBuilder {
 
     /**
      * Disables automatic content decompression.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
      */
@@ -494,7 +584,7 @@ public class HttpClientBuilder {
 
     /**
      * Disables authentication scheme caching.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setHttpProcessor(
      * org.apache.http.protocol.HttpProcessor)} method.
      */
@@ -513,7 +603,7 @@ public class HttpClientBuilder {
 
     /**
      * Assigns {@link HttpRequestRetryHandler} instance.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #disableAutomaticRetries()}
      * method.
      */
@@ -532,7 +622,7 @@ public class HttpClientBuilder {
 
     /**
      * Assigns default proxy value.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #setRoutePlanner(
      *   org.apache.http.conn.routing.HttpRoutePlanner)} method.
      */
@@ -551,9 +641,10 @@ public class HttpClientBuilder {
 
     /**
      * Assigns {@link RedirectStrategy} instance.
-     * <p/>
+     * <p>
      * Please note this value can be overridden by the {@link #disableRedirectHandling()}
      * method.
+     * </p>
 `     */
     public final HttpClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
         this.redirectStrategy = redirectStrategy;
@@ -636,6 +727,17 @@ public class HttpClientBuilder {
         return this;
     }
 
+
+    /**
+     * Assigns a map of {@link org.apache.http.client.entity.InputStreamFactory}s
+     * to be used for automatic content decompression.
+     */
+    public final HttpClientBuilder setContentDecoderRegistry(
+            final Map<String, InputStreamFactory> contentDecoderMap) {
+        this.contentDecoderMap = contentDecoderMap;
+        return this;
+    }
+
     /**
      * Assigns default {@link RequestConfig} instance which will be used
      * for request execution if not explicitly set in the client execution
@@ -651,11 +753,96 @@ public class HttpClientBuilder {
      * implementations.
      */
     public final HttpClientBuilder useSystemProperties() {
-        systemProperties = true;
+        this.systemProperties = true;
+        return this;
+    }
+
+    /**
+     * Makes this instance of HttpClient proactively evict expired connections from the
+     * connection pool using a background thread.
+     * <p>
+     * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
+     * to stop and release the background thread.
+     * <p>
+     * Please note this method has no effect if the instance of HttpClient is configuted to
+     * use a shared connection manager.
+     * <p>
+     * Please note this method may not be used when the instance of HttpClient is created
+     * inside an EJB container.
+     *
+     * @see #setConnectionManagerShared(boolean)
+     * @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
+     *
+     * @since 4.4
+     */
+    public final HttpClientBuilder evictExpiredConnections() {
+        evictExpiredConnections = true;
+        return this;
+    }
+
+    /**
+     * Makes this instance of HttpClient proactively evict idle connections from the
+     * connection pool using a background thread.
+     * <p>
+     * One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
+     * to stop and release the background thread.
+     * <p>
+     * Please note this method has no effect if the instance of HttpClient is configuted to
+     * use a shared connection manager.
+     * <p>
+     * Please note this method may not be used when the instance of HttpClient is created
+     * inside an EJB container.
+     *
+     * @see #setConnectionManagerShared(boolean)
+     * @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
+     *
+     * @param maxIdleTime maxium time persistent connections can stay idle while kept alive
+     * in the connection pool. Connections whose inactivity period exceeds this value will
+     * get closed and evicted from the pool.
+     * @param maxIdleTimeUnit time unit for the above parameter.
+     *
+     * @since 4.4
+     */
+    public final HttpClientBuilder evictIdleConnections(final Long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
+        this.evictIdleConnections = true;
+        this.maxIdleTime = maxIdleTime;
+        this.maxIdleTimeUnit = maxIdleTimeUnit;
         return this;
     }
 
     /**
+     * Produces an instance of {@link ClientExecChain} to be used as a main exec.
+     * <p>
+     * Default implementation produces an instance of {@link MainClientExec}
+     * </p>
+     * <p>
+     * For internal use.
+     * </p>
+     *
+     * @since 4.4
+     */
+    protected ClientExecChain createMainExec(
+            final HttpRequestExecutor requestExec,
+            final HttpClientConnectionManager connManager,
+            final ConnectionReuseStrategy reuseStrategy,
+            final ConnectionKeepAliveStrategy keepAliveStrategy,
+            final HttpProcessor proxyHttpProcessor,
+            final AuthenticationStrategy targetAuthStrategy,
+            final AuthenticationStrategy proxyAuthStrategy,
+            final UserTokenHandler userTokenHandler)
+    {
+        return new MainClientExec(
+                requestExec,
+                connManager,
+                reuseStrategy,
+                keepAliveStrategy,
+                proxyHttpProcessor,
+                targetAuthStrategy,
+                proxyAuthStrategy,
+                userTokenHandler);
+    }
+
+    /**
      * For internal use.
      */
     protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
@@ -691,34 +878,40 @@ public class HttpClientBuilder {
 
     public CloseableHttpClient build() {
         // Create main request executor
-        HttpRequestExecutor requestExec = this.requestExec;
-        if (requestExec == null) {
-            requestExec = new HttpRequestExecutor();
+        // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
+        PublicSuffixMatcher publicSuffixMatcherCopy = this.publicSuffixMatcher;
+        if (publicSuffixMatcherCopy == null) {
+            publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();
+        }
+
+        HttpRequestExecutor requestExecCopy = this.requestExec;
+        if (requestExecCopy == null) {
+            requestExecCopy = new HttpRequestExecutor();
         }
-        HttpClientConnectionManager connManager = this.connManager;
-        if (connManager == null) {
-            LayeredConnectionSocketFactory sslSocketFactory = this.sslSocketFactory;
-            if (sslSocketFactory == null) {
+        HttpClientConnectionManager connManagerCopy = this.connManager;
+        if (connManagerCopy == null) {
+            LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
+            if (sslSocketFactoryCopy == null) {
                 final String[] supportedProtocols = systemProperties ? split(
                         System.getProperty("https.protocols")) : null;
                 final String[] supportedCipherSuites = systemProperties ? split(
                         System.getProperty("https.cipherSuites")) : null;
-                X509HostnameVerifier hostnameVerifier = this.hostnameVerifier;
-                if (hostnameVerifier == null) {
-                    hostnameVerifier = SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
+                HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
+                if (hostnameVerifierCopy == null) {
+                    hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
                 }
                 if (sslcontext != null) {
-                    sslSocketFactory = new SSLConnectionSocketFactory(
-                            sslcontext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+                    sslSocketFactoryCopy = new SSLConnectionSocketFactory(
+                            sslcontext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
                 } else {
                     if (systemProperties) {
-                        sslSocketFactory = new SSLConnectionSocketFactory(
+                        sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                                 (SSLSocketFactory) SSLSocketFactory.getDefault(),
-                                supportedProtocols, supportedCipherSuites, hostnameVerifier);
+                                supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
                     } else {
-                        sslSocketFactory = new SSLConnectionSocketFactory(
+                        sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                                 SSLContexts.createDefault(),
-                                hostnameVerifier);
+                                hostnameVerifierCopy);
                     }
                 }
             }
@@ -726,8 +919,13 @@ public class HttpClientBuilder {
             final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
                     RegistryBuilder.<ConnectionSocketFactory>create()
                         .register("http", PlainConnectionSocketFactory.getSocketFactory())
-                        .register("https", sslSocketFactory)
-                        .build());
+                        .register("https", sslSocketFactoryCopy)
+                        .build(),
+                    null,
+                    null,
+                    null,
+                    connTimeToLive,
+                    connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
             if (defaultSocketConfig != null) {
                 poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
             }
@@ -749,64 +947,67 @@ public class HttpClientBuilder {
             if (maxConnPerRoute > 0) {
                 poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
             }
-            connManager = poolingmgr;
+            connManagerCopy = poolingmgr;
         }
-        ConnectionReuseStrategy reuseStrategy = this.reuseStrategy;
-        if (reuseStrategy == null) {
+        ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
+        if (reuseStrategyCopy == null) {
             if (systemProperties) {
                 final String s = System.getProperty("http.keepAlive", "true");
                 if ("true".equalsIgnoreCase(s)) {
-                    reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
+                    reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
                 } else {
-                    reuseStrategy = NoConnectionReuseStrategy.INSTANCE;
+                    reuseStrategyCopy = NoConnectionReuseStrategy.INSTANCE;
                 }
             } else {
-                reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
+                reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
             }
         }
-        ConnectionKeepAliveStrategy keepAliveStrategy = this.keepAliveStrategy;
-        if (keepAliveStrategy == null) {
-            keepAliveStrategy = DefaultConnectionKeepAliveStrategy.INSTANCE;
+        ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
+        if (keepAliveStrategyCopy == null) {
+            keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
         }
-        AuthenticationStrategy targetAuthStrategy = this.targetAuthStrategy;
-        if (targetAuthStrategy == null) {
-            targetAuthStrategy = TargetAuthenticationStrategy.INSTANCE;
+        AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
+        if (targetAuthStrategyCopy == null) {
+            targetAuthStrategyCopy = TargetAuthenticationStrategy.INSTANCE;
         }
-        AuthenticationStrategy proxyAuthStrategy = this.proxyAuthStrategy;
-        if (proxyAuthStrategy == null) {
-            proxyAuthStrategy = ProxyAuthenticationStrategy.INSTANCE;
+        AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
+        if (proxyAuthStrategyCopy == null) {
+            proxyAuthStrategyCopy = ProxyAuthenticationStrategy.INSTANCE;
         }
-        UserTokenHandler userTokenHandler = this.userTokenHandler;
-        if (userTokenHandler == null) {
+        UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
+        if (userTokenHandlerCopy == null) {
             if (!connectionStateDisabled) {
-                userTokenHandler = DefaultUserTokenHandler.INSTANCE;
+                userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
             } else {
-                userTokenHandler = NoopUserTokenHandler.INSTANCE;
+                userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
             }
         }
-        ClientExecChain execChain = new MainClientExec(
-                requestExec,
-                connManager,
-                reuseStrategy,
-                keepAliveStrategy,
-                targetAuthStrategy,
-                proxyAuthStrategy,
-                userTokenHandler);
 
-        execChain = decorateMainExec(execChain);
+        String userAgentCopy = this.userAgent;
+        if (userAgentCopy == null) {
+            if (systemProperties) {
+                userAgentCopy = System.getProperty("http.agent");
+            }
+            if (userAgentCopy == null) {
+                userAgentCopy = VersionInfo.getUserAgent("Apache-HttpClient",
+                        "org.apache.http.client", getClass());
+            }
+        }
 
-        HttpProcessor httpprocessor = this.httpprocessor;
-        if (httpprocessor == null) {
+        ClientExecChain execChain = createMainExec(
+                requestExecCopy,
+                connManagerCopy,
+                reuseStrategyCopy,
+                keepAliveStrategyCopy,
+                new ImmutableHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
+                targetAuthStrategyCopy,
+                proxyAuthStrategyCopy,
+                userTokenHandlerCopy);
 
-            String userAgent = this.userAgent;
-            if (userAgent == null) {
-                if (systemProperties) {
-                    userAgent = System.getProperty("http.agent");
-                }
-                if (userAgent == null) {
-                    userAgent = DEFAULT_USER_AGENT;
-                }
-            }
+        execChain = decorateMainExec(execChain);
+
+        HttpProcessor httpprocessorCopy = this.httpprocessor;
+        if (httpprocessorCopy == null) {
 
             final HttpProcessorBuilder b = HttpProcessorBuilder.create();
             if (requestFirst != null) {
@@ -824,13 +1025,19 @@ public class HttpClientBuilder {
                     new RequestContent(),
                     new RequestTargetHost(),
                     new RequestClientConnControl(),
-                    new RequestUserAgent(userAgent),
+                    new RequestUserAgent(userAgentCopy),
                     new RequestExpectContinue());
             if (!cookieManagementDisabled) {
                 b.add(new RequestAddCookies());
             }
             if (!contentCompressionDisabled) {
-                b.add(new RequestAcceptEncoding());
+                if (contentDecoderMap != null) {
+                    final List<String> encodings = new ArrayList<String>(contentDecoderMap.keySet());
+                    Collections.sort(encodings);
+                    b.add(new RequestAcceptEncoding(encodings));
+                } else {
+                    b.add(new RequestAcceptEncoding());
+                }
             }
             if (!authCachingDisabled) {
                 b.add(new RequestAuthCache());
@@ -839,7 +1046,15 @@ public class HttpClientBuilder {
                 b.add(new ResponseProcessCookies());
             }
             if (!contentCompressionDisabled) {
-                b.add(new ResponseContentEncoding());
+                if (contentDecoderMap != null) {
+                    final RegistryBuilder<InputStreamFactory> b2 = RegistryBuilder.create();
+                    for (Map.Entry<String, InputStreamFactory> entry: contentDecoderMap.entrySet()) {
+                        b2.register(entry.getKey(), entry.getValue());
+                    }
+                    b.add(new ResponseContentEncoding(b2.build()));
+                } else {
+                    b.add(new ResponseContentEncoding());
+                }
             }
             if (requestLast != null) {
                 for (final HttpRequestInterceptor i: requestLast) {
@@ -851,60 +1066,58 @@ public class HttpClientBuilder {
                     b.addLast(i);
                 }
             }
-            httpprocessor = b.build();
+            httpprocessorCopy = b.build();
         }
-        execChain = new ProtocolExec(execChain, httpprocessor);
+        execChain = new ProtocolExec(execChain, httpprocessorCopy);
 
         execChain = decorateProtocolExec(execChain);
 
         // Add request retry executor, if not disabled
         if (!automaticRetriesDisabled) {
-            HttpRequestRetryHandler retryHandler = this.retryHandler;
-            if (retryHandler == null) {
-                retryHandler = DefaultHttpRequestRetryHandler.INSTANCE;
+            HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
+            if (retryHandlerCopy == null) {
+                retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
             }
-            execChain = new RetryExec(execChain, retryHandler);
+            execChain = new RetryExec(execChain, retryHandlerCopy);
         }
 
-        HttpRoutePlanner routePlanner = this.routePlanner;
-        if (routePlanner == null) {
-            SchemePortResolver schemePortResolver = this.schemePortResolver;
-            if (schemePortResolver == null) {
-                schemePortResolver = DefaultSchemePortResolver.INSTANCE;
+        HttpRoutePlanner routePlannerCopy = this.routePlanner;
+        if (routePlannerCopy == null) {
+            SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
+            if (schemePortResolverCopy == null) {
+                schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
             }
             if (proxy != null) {
-                routePlanner = new DefaultProxyRoutePlanner(proxy, schemePortResolver);
+                routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
             } else if (systemProperties) {
-                routePlanner = new SystemDefaultRoutePlanner(
-                        schemePortResolver, ProxySelector.getDefault());
+                routePlannerCopy = new SystemDefaultRoutePlanner(
+                        schemePortResolverCopy, ProxySelector.getDefault());
             } else {
-                routePlanner = new DefaultRoutePlanner(schemePortResolver);
+                routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
             }
         }
         // Add redirect executor, if not disabled
         if (!redirectHandlingDisabled) {
-            RedirectStrategy redirectStrategy = this.redirectStrategy;
-            if (redirectStrategy == null) {
-                redirectStrategy = DefaultRedirectStrategy.INSTANCE;
+            RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
+            if (redirectStrategyCopy == null) {
+                redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
             }
-            execChain = new RedirectExec(execChain, routePlanner, redirectStrategy);
+            execChain = new RedirectExec(execChain, routePlannerCopy, redirectStrategyCopy);
         }
 
         // Optionally, add service unavailable retry executor
-        final ServiceUnavailableRetryStrategy serviceUnavailStrategy = this.serviceUnavailStrategy;
-        if (serviceUnavailStrategy != null) {
-            execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategy);
+        final ServiceUnavailableRetryStrategy serviceUnavailStrategyCopy = this.serviceUnavailStrategy;
+        if (serviceUnavailStrategyCopy != null) {
+            execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategyCopy);
         }
         // Optionally, add connection back-off executor
-        final BackoffManager backoffManager = this.backoffManager;
-        final ConnectionBackoffStrategy connectionBackoffStrategy = this.connectionBackoffStrategy;
-        if (backoffManager != null && connectionBackoffStrategy != null) {
-            execChain = new BackoffStrategyExec(execChain, connectionBackoffStrategy, backoffManager);
+        if (this.backoffManager != null && this.connectionBackoffStrategy != null) {
+            execChain = new BackoffStrategyExec(execChain, this.connectionBackoffStrategy, this.backoffManager);
         }
 
-        Lookup<AuthSchemeProvider> authSchemeRegistry = this.authSchemeRegistry;
-        if (authSchemeRegistry == null) {
-            authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
+        Lookup<AuthSchemeProvider> authSchemeRegistryCopy = this.authSchemeRegistry;
+        if (authSchemeRegistryCopy == null) {
+            authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeProvider>create()
                 .register(AuthSchemes.BASIC, new BasicSchemeFactory())
                 .register(AuthSchemes.DIGEST, new DigestSchemeFactory())
                 .register(AuthSchemes.NTLM, new NTLMSchemeFactory())
@@ -912,16 +1125,21 @@ public class HttpClientBuilder {
                 .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
                 .build();
         }
-        Lookup<CookieSpecProvider> cookieSpecRegistry = this.cookieSpecRegistry;
-        if (cookieSpecRegistry == null) {
-            cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
-                .register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
-                .register(CookieSpecs.STANDARD, new RFC2965SpecFactory())
-                .register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory())
-                .register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecFactory())
-                .register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecFactory())
-                .register("rfc2109", new RFC2109SpecFactory())
-                .register("rfc2965", new RFC2965SpecFactory())
+        Lookup<CookieSpecProvider> cookieSpecRegistryCopy = this.cookieSpecRegistry;
+        if (cookieSpecRegistryCopy == null) {
+            final CookieSpecProvider defaultProvider = new DefaultCookieSpecProvider(publicSuffixMatcherCopy);
+            final CookieSpecProvider laxStandardProvider = new RFC6265CookieSpecProvider(
+                    RFC6265CookieSpecProvider.CompatibilityLevel.RELAXED, publicSuffixMatcherCopy);
+            final CookieSpecProvider strictStandardProvider = new RFC6265CookieSpecProvider(
+                    RFC6265CookieSpecProvider.CompatibilityLevel.STRICT, publicSuffixMatcherCopy);
+            cookieSpecRegistryCopy = RegistryBuilder.<CookieSpecProvider>create()
+                .register(CookieSpecs.DEFAULT, defaultProvider)
+                .register("best-match", defaultProvider)
+                .register("compatibility", defaultProvider)
+                .register(CookieSpecs.STANDARD, laxStandardProvider)
+                .register(CookieSpecs.STANDARD_STRICT, strictStandardProvider)
+                .register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecProvider())
+                .register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecProvider())
                 .build();
         }
 
@@ -939,16 +1157,46 @@ public class HttpClientBuilder {
             }
         }
 
+        List<Closeable> closeablesCopy = closeables != null ? new ArrayList<Closeable>(closeables) : null;
+        if (!this.connManagerShared) {
+            if (closeablesCopy == null) {
+                closeablesCopy = new ArrayList<Closeable>(1);
+            }
+            final HttpClientConnectionManager cm = connManagerCopy;
+
+            if (evictExpiredConnections || evictIdleConnections) {
+                final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
+                        maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS);
+                closeablesCopy.add(new Closeable() {
+
+                    @Override
+                    public void close() throws IOException {
+                        connectionEvictor.shutdown();
+                    }
+
+                });
+                connectionEvictor.start();
+            }
+            closeablesCopy.add(new Closeable() {
+
+                @Override
+                public void close() throws IOException {
+                    cm.shutdown();
+                }
+
+            });
+        }
+
         return new InternalHttpClient(
                 execChain,
-                connManager,
-                routePlanner,
-                cookieSpecRegistry,
-                authSchemeRegistry,
+                connManagerCopy,
+                routePlannerCopy,
+                cookieSpecRegistryCopy,
+                authSchemeRegistryCopy,
                 defaultCookieStore,
                 defaultCredentialsProvider,
                 defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
-                closeables != null ? new ArrayList<Closeable>(closeables) : null);
+                closeablesCopy);
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/HttpRequestTaskCallable.java b/httpclient/src/main/java/org/apache/http/impl/client/HttpRequestTaskCallable.java
index a4577b5..47fb238 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/HttpRequestTaskCallable.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/HttpRequestTaskCallable.java
@@ -78,6 +78,7 @@ class HttpRequestTaskCallable<V> implements Callable<V> {
         return ended;
     }
 
+    @Override
     public V call() throws Exception {
         if (!cancelled.get()) {
             try {
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java b/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
new file mode 100644
index 0000000..6bd8c80
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/client/IdleConnectionEvictor.java
@@ -0,0 +1,123 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.util.Args;
+
+/**
+ * This class maintains a background thread to enforce an eviction policy for expired / idle
+ * persistent connections kept alive in the connection pool.
+ *
+ * @since 4.4
+ */
+public final class IdleConnectionEvictor {
+
+    private final HttpClientConnectionManager connectionManager;
+    private final ThreadFactory threadFactory;
+    private final Thread thread;
+    private final long sleepTimeMs;
+    private final long maxIdleTimeMs;
+
+    private volatile Exception exception;
+
+    public IdleConnectionEvictor(
+            final HttpClientConnectionManager connectionManager,
+            final ThreadFactory threadFactory,
+            final long sleepTime, final TimeUnit sleepTimeUnit,
+            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
+        this.connectionManager = Args.notNull(connectionManager, "Connection manager");
+        this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory();
+        this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;
+        this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime;
+        this.thread = this.threadFactory.newThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    while (!Thread.currentThread().isInterrupted()) {
+                        Thread.sleep(sleepTimeMs);
+                        connectionManager.closeExpiredConnections();
+                        if (maxIdleTimeMs > 0) {
+                            connectionManager.closeIdleConnections(maxIdleTimeMs, TimeUnit.MILLISECONDS);
+                        }
+                    }
+                } catch (Exception ex) {
+                    exception = ex;
+                }
+
+            }
+        });
+    }
+
+    public IdleConnectionEvictor(
+            final HttpClientConnectionManager connectionManager,
+            final long sleepTime, final TimeUnit sleepTimeUnit,
+            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
+        this(connectionManager, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit);
+    }
+
+    public IdleConnectionEvictor(
+            final HttpClientConnectionManager connectionManager,
+            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
+        this(connectionManager, null,
+                maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,
+                maxIdleTime, maxIdleTimeUnit);
+    }
+
+    public void start() {
+        thread.start();
+    }
+
+    public void shutdown() {
+        thread.interrupt();
+    }
+
+    public boolean isRunning() {
+        return thread.isAlive();
+    }
+
+    public void awaitTermination(final long time, final TimeUnit tunit) throws InterruptedException {
+        thread.join((tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(time));
+    }
+
+    static class DefaultThreadFactory implements ThreadFactory {
+
+        @Override
+        public Thread newThread(final Runnable r) {
+            final Thread t = new Thread(r, "Connection evictor");
+            t.setDaemon(true);
+            return t;
+        }
+
+    };
+
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/InternalHttpClient.java b/httpclient/src/main/java/org/apache/http/impl/client/InternalHttpClient.java
index 1123145..32bb5e0 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/InternalHttpClient.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/InternalHttpClient.java
@@ -74,7 +74,7 @@ import org.apache.http.util.Args;
  */
 @ThreadSafe
 @SuppressWarnings("deprecation")
-class InternalHttpClient extends CloseableHttpClient {
+class InternalHttpClient extends CloseableHttpClient implements Configurable {
 
     private final Log log = LogFactory.getLog(getClass());
 
@@ -159,7 +159,7 @@ class InternalHttpClient extends CloseableHttpClient {
             execAware = (HttpExecutionAware) request;
         }
         try {
-            final HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(request);
+            final HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(request, target);
             final HttpClientContext localcontext = HttpClientContext.adapt(
                     context != null ? context : new BasicHttpContext());
             RequestConfig config = null;
@@ -187,8 +187,13 @@ class InternalHttpClient extends CloseableHttpClient {
         }
     }
 
+    @Override
+    public RequestConfig getConfig() {
+        return this.defaultConfig;
+    }
+
+    @Override
     public void close() {
-        this.connManager.shutdown();
         if (this.closeables != null) {
             for (final Closeable closeable: this.closeables) {
                 try {
@@ -200,37 +205,45 @@ class InternalHttpClient extends CloseableHttpClient {
         }
     }
 
+    @Override
     public HttpParams getParams() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public ClientConnectionManager getConnectionManager() {
 
         return new ClientConnectionManager() {
 
+            @Override
             public void shutdown() {
                 connManager.shutdown();
             }
 
+            @Override
             public ClientConnectionRequest requestConnection(
                     final HttpRoute route, final Object state) {
                 throw new UnsupportedOperationException();
             }
 
+            @Override
             public void releaseConnection(
                     final ManagedClientConnection conn,
                     final long validDuration, final TimeUnit timeUnit) {
                 throw new UnsupportedOperationException();
             }
 
+            @Override
             public SchemeRegistry getSchemeRegistry() {
                 throw new UnsupportedOperationException();
             }
 
+            @Override
             public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
                 connManager.closeIdleConnections(idletime, tunit);
             }
 
+            @Override
             public void closeExpiredConnections() {
                 connManager.closeExpiredConnections();
             }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/MinimalHttpClient.java b/httpclient/src/main/java/org/apache/http/impl/client/MinimalHttpClient.java
index b8dd244..6d1ead7 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/MinimalHttpClient.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/MinimalHttpClient.java
@@ -110,41 +110,50 @@ class MinimalHttpClient extends CloseableHttpClient {
         }
     }
 
+    @Override
     public HttpParams getParams() {
         return this.params;
     }
 
+    @Override
     public void close() {
         this.connManager.shutdown();
     }
 
+    @Override
     public ClientConnectionManager getConnectionManager() {
 
         return new ClientConnectionManager() {
 
+            @Override
             public void shutdown() {
                 connManager.shutdown();
             }
 
+            @Override
             public ClientConnectionRequest requestConnection(
                     final HttpRoute route, final Object state) {
                 throw new UnsupportedOperationException();
             }
 
+            @Override
             public void releaseConnection(
                     final ManagedClientConnection conn,
                     final long validDuration, final TimeUnit timeUnit) {
                 throw new UnsupportedOperationException();
             }
 
+            @Override
             public SchemeRegistry getSchemeRegistry() {
                 throw new UnsupportedOperationException();
             }
 
+            @Override
             public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
                 connManager.closeIdleConnections(idletime, tunit);
             }
 
+            @Override
             public void closeExpiredConnections() {
                 connManager.closeExpiredConnections();
             }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/NoopUserTokenHandler.java b/httpclient/src/main/java/org/apache/http/impl/client/NoopUserTokenHandler.java
index 6276551..9d21a6b 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/NoopUserTokenHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/NoopUserTokenHandler.java
@@ -31,7 +31,7 @@ import org.apache.http.client.UserTokenHandler;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * Noop implementation of {@link UserTokenHandler} that always returns <code>null</code>.
+ * Noop implementation of {@link UserTokenHandler} that always returns {@code null}.
  *
  * @since 4.3
  */
@@ -40,6 +40,7 @@ public class NoopUserTokenHandler implements UserTokenHandler {
 
     public static final NoopUserTokenHandler INSTANCE = new NoopUserTokenHandler();
 
+    @Override
     public Object getUserToken(final HttpContext context) {
         return null;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/NullBackoffStrategy.java b/httpclient/src/main/java/org/apache/http/impl/client/NullBackoffStrategy.java
index 0c7a452..0b0b2fc 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/NullBackoffStrategy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/NullBackoffStrategy.java
@@ -37,10 +37,12 @@ import org.apache.http.client.ConnectionBackoffStrategy;
  */
 public class NullBackoffStrategy implements ConnectionBackoffStrategy {
 
+    @Override
     public boolean shouldBackoff(final Throwable t) {
         return false;
     }
 
+    @Override
     public boolean shouldBackoff(final HttpResponse resp) {
         return false;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/RedirectLocations.java b/httpclient/src/main/java/org/apache/http/impl/client/RedirectLocations.java
index 9f14842..e0d4464 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/RedirectLocations.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/RedirectLocations.java
@@ -106,7 +106,7 @@ public class RedirectLocations extends AbstractList<Object> {
      * @return the URI at the specified position in this list
      * @throws IndexOutOfBoundsException
      *             if the index is out of range (
-     *             <tt>index < 0 || index >= size()</tt>)
+     *             {@code index < 0 || index >= size()})
      * @since 4.3
      */
     @Override
@@ -116,8 +116,8 @@ public class RedirectLocations extends AbstractList<Object> {
 
     /**
      * Returns the number of elements in this list. If this list contains more
-     * than <tt>Integer.MAX_VALUE</tt> elements, returns
-     * <tt>Integer.MAX_VALUE</tt>.
+     * than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
      *
      * @return the number of elements in this list
      * @since 4.3
@@ -137,7 +137,7 @@ public class RedirectLocations extends AbstractList<Object> {
      *            URI to be stored at the specified position
      * @return the URI previously at the specified position
      * @throws UnsupportedOperationException
-     *             if the <tt>set</tt> operation is not supported by this list
+     *             if the {@code set} operation is not supported by this list
      * @throws ClassCastException
      *             if the element is not a {@link URI}
      * @throws NullPointerException
@@ -145,7 +145,7 @@ public class RedirectLocations extends AbstractList<Object> {
      *             permit null elements
      * @throws IndexOutOfBoundsException
      *             if the index is out of range (
-     *             <tt>index < 0 || index >= size()</tt>)
+     *             {@code index < 0 || index >= size()})
      * @since 4.3
      */
     @Override
@@ -169,7 +169,7 @@ public class RedirectLocations extends AbstractList<Object> {
      * @param element
      *            URI to be inserted
      * @throws UnsupportedOperationException
-     *             if the <tt>add</tt> operation is not supported by this list
+     *             if the {@code add} operation is not supported by this list
      * @throws ClassCastException
      *             if the element is not a {@link URI}
      * @throws NullPointerException
@@ -177,7 +177,7 @@ public class RedirectLocations extends AbstractList<Object> {
      *             permit null elements
      * @throws IndexOutOfBoundsException
      *             if the index is out of range (
-     *             <tt>index < 0 || index > size()</tt>)
+     *             {@code index < 0 || index > size()})
      * @since 4.3
      */
     @Override
@@ -196,7 +196,7 @@ public class RedirectLocations extends AbstractList<Object> {
      * @return the URI previously at the specified position
      * @throws IndexOutOfBoundsException
      *             if the index is out of range (
-     *             <tt>index < 0 || index >= size()</tt>)
+     *             {@code index < 0 || index >= size()})
      * @since 4.3
      */
     @Override
@@ -210,13 +210,13 @@ public class RedirectLocations extends AbstractList<Object> {
     }
 
     /**
-     * Returns <tt>true</tt> if this collection contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this collection
-     * contains at least one element <tt>e</tt> such that
-     * <tt>(o==null ? e==null : o.equals(e))</tt>.
+     * Returns {@code true} if this collection contains the specified element.
+     * More formally, returns {@code true} if and only if this collection
+     * contains at least one element {@code e} such that
+     * {@code (o==null ? e==null : o.equals(e))}.
      *
      * @param o element whose presence in this collection is to be tested
-     * @return <tt>true</tt> if this collection contains the specified
+     * @return {@code true} if this collection contains the specified
      *         element
      */
     @Override
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/RequestWrapper.java b/httpclient/src/main/java/org/apache/http/impl/client/RequestWrapper.java
index eb55192..be6a743 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/RequestWrapper.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/RequestWrapper.java
@@ -45,9 +45,10 @@ import org.apache.http.util.Args;
  * A wrapper class for {@link HttpRequest}s that can be used to change
  * properties of the current request without modifying the original
  * object.
- * </p>
+ * <p>
  * This class is also capable of resetting the request headers to
  * the state of the original request.
+ * </p>
  *
  * @since 4.0
  *
@@ -95,6 +96,7 @@ public class RequestWrapper extends AbstractHttpMessage implements HttpUriReques
         setHeaders(this.original.getAllHeaders());
     }
 
+    @Override
     public String getMethod() {
         return this.method;
     }
@@ -104,6 +106,7 @@ public class RequestWrapper extends AbstractHttpMessage implements HttpUriReques
         this.method = method;
     }
 
+    @Override
     public ProtocolVersion getProtocolVersion() {
         if (this.version == null) {
             this.version = HttpProtocolParams.getVersion(getParams());
@@ -116,6 +119,7 @@ public class RequestWrapper extends AbstractHttpMessage implements HttpUriReques
     }
 
 
+    @Override
     public URI getURI() {
         return this.uri;
     }
@@ -124,23 +128,25 @@ public class RequestWrapper extends AbstractHttpMessage implements HttpUriReques
         this.uri = uri;
     }
 
+    @Override
     public RequestLine getRequestLine() {
-        final String method = getMethod();
         final ProtocolVersion ver = getProtocolVersion();
         String uritext = null;
         if (uri != null) {
             uritext = uri.toASCIIString();
         }
-        if (uritext == null || uritext.length() == 0) {
+        if (uritext == null || uritext.isEmpty()) {
             uritext = "/";
         }
-        return new BasicRequestLine(method, uritext, ver);
+        return new BasicRequestLine(getMethod(), uritext, ver);
     }
 
+    @Override
     public void abort() throws UnsupportedOperationException {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public boolean isAborted() {
         return false;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/StandardHttpRequestRetryHandler.java b/httpclient/src/main/java/org/apache/http/impl/client/StandardHttpRequestRetryHandler.java
index 96bca34..ae3342b 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/StandardHttpRequestRetryHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/StandardHttpRequestRetryHandler.java
@@ -38,9 +38,10 @@ import org.apache.http.annotation.Immutable;
  * {@link org.apache.http.client.HttpRequestRetryHandler} which assumes
  * that all requested HTTP methods which should be idempotent according
  * to RFC-2616 are in fact idempotent and can be retried.
- * <p/>
+ * <p>
  * According to RFC-2616 section 9.1.2 the idempotent HTTP methods are:
  * GET, HEAD, PUT, DELETE, OPTIONS, and TRACE
+ * </p>
  *
  * @since 4.2
  */
@@ -72,7 +73,7 @@ public class StandardHttpRequestRetryHandler extends DefaultHttpRequestRetryHand
 
     @Override
     protected boolean handleAsIdempotent(final HttpRequest request) {
-        final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
+        final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
         final Boolean b = this.idempotentMethods.get(method);
         return b != null && b.booleanValue();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java b/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java
index cc62de3..865e132 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/SystemClock.java
@@ -33,6 +33,7 @@ package org.apache.http.impl.client;
  */
 class SystemClock implements Clock {
 
+    @Override
     public long getCurrentTime() {
         return System.currentTimeMillis();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/SystemDefaultCredentialsProvider.java b/httpclient/src/main/java/org/apache/http/impl/client/SystemDefaultCredentialsProvider.java
index f7dd918..69c4fde 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/SystemDefaultCredentialsProvider.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/SystemDefaultCredentialsProvider.java
@@ -32,6 +32,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.http.HttpHost;
 import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.Credentials;
@@ -54,11 +55,11 @@ public class SystemDefaultCredentialsProvider implements CredentialsProvider {
 
     static {
         SCHEME_MAP = new ConcurrentHashMap<String, String>();
-        SCHEME_MAP.put(AuthSchemes.BASIC.toUpperCase(Locale.ENGLISH), "Basic");
-        SCHEME_MAP.put(AuthSchemes.DIGEST.toUpperCase(Locale.ENGLISH), "Digest");
-        SCHEME_MAP.put(AuthSchemes.NTLM.toUpperCase(Locale.ENGLISH), "NTLM");
-        SCHEME_MAP.put(AuthSchemes.SPNEGO.toUpperCase(Locale.ENGLISH), "SPNEGO");
-        SCHEME_MAP.put(AuthSchemes.KERBEROS.toUpperCase(Locale.ENGLISH), "Kerberos");
+        SCHEME_MAP.put(AuthSchemes.BASIC.toUpperCase(Locale.ROOT), "Basic");
+        SCHEME_MAP.put(AuthSchemes.DIGEST.toUpperCase(Locale.ROOT), "Digest");
+        SCHEME_MAP.put(AuthSchemes.NTLM.toUpperCase(Locale.ROOT), "NTLM");
+        SCHEME_MAP.put(AuthSchemes.SPNEGO.toUpperCase(Locale.ROOT), "SPNEGO");
+        SCHEME_MAP.put(AuthSchemes.KERBEROS.toUpperCase(Locale.ROOT), "Kerberos");
     }
 
     private static String translateScheme(final String key) {
@@ -79,6 +80,7 @@ public class SystemDefaultCredentialsProvider implements CredentialsProvider {
         this.internal = new BasicCredentialsProvider();
     }
 
+    @Override
     public void setCredentials(final AuthScope authscope, final Credentials credentials) {
         internal.setCredentials(authscope, credentials);
     }
@@ -88,7 +90,9 @@ public class SystemDefaultCredentialsProvider implements CredentialsProvider {
             final Authenticator.RequestorType requestorType) {
         final String hostname = authscope.getHost();
         final int port = authscope.getPort();
-        final String protocol = port == 443 ? "https" : "http";
+        final HttpHost origin = authscope.getOrigin();
+        final String protocol = origin != null ? origin.getSchemeName() :
+                (port == 443 ? "https" : "http");
         return Authenticator.requestPasswordAuthentication(
                 hostname,
                 null,
@@ -100,6 +104,7 @@ public class SystemDefaultCredentialsProvider implements CredentialsProvider {
                 requestorType);
     }
 
+    @Override
     public Credentials getCredentials(final AuthScope authscope) {
         Args.notNull(authscope, "Auth scope");
         final Credentials localcreds = internal.getCredentials(authscope);
@@ -138,6 +143,7 @@ public class SystemDefaultCredentialsProvider implements CredentialsProvider {
         return null;
     }
 
+    @Override
     public void clear() {
         internal.clear();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/package-info.java b/httpclient/src/main/java/org/apache/http/impl/client/package-info.java
index 0b923eb..396f8d5 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/package-info.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/package-info.java
@@ -27,8 +27,9 @@
 
 /**
  * Default HTTP client implementation.
- * <p/>
+ * <p>
  * The usual execution flow can be demonstrated by the code snippet below:
+ * </p>
  * <pre>
  * CloseableHttpClient httpclient = HttpClients.createDefault();
  * try {
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/BasicHttpClientConnectionManager.java b/httpclient/src/main/java/org/apache/http/impl/conn/BasicHttpClientConnectionManager.java
index 7142a0c..92ca644 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/BasicHttpClientConnectionManager.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/BasicHttpClientConnectionManager.java
@@ -48,6 +48,7 @@ import org.apache.http.config.SocketConfig;
 import org.apache.http.conn.ConnectionRequest;
 import org.apache.http.conn.DnsResolver;
 import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.HttpClientConnectionOperator;
 import org.apache.http.conn.HttpConnectionFactory;
 import org.apache.http.conn.SchemePortResolver;
 import org.apache.http.conn.ManagedHttpClientConnection;
@@ -64,15 +65,17 @@ import org.apache.http.util.LangUtils;
  * A connection manager for a single connection. This connection manager maintains only one active
  * connection. Even though this class is fully thread-safe it ought to be used by one execution
  * thread only, as only one thread a time can lease the connection at a time.
- * <p/>
+ * <p>
  * This connection manager will make an effort to reuse the connection for subsequent requests
  * with the same {@link HttpRoute route}. It will, however, close the existing connection and
  * open it for the given route, if the route of the persistent connection does not match that
  * of the connection request. If the connection has been already been allocated
  * {@link IllegalStateException} is thrown.
- * <p/>
+ * </p>
+ * <p>
  * This connection manager implementation should be used inside an EJB container instead of
  * {@link PoolingHttpClientConnectionManager}.
+ * </p>
  *
  * @since 4.3
  */
@@ -118,13 +121,24 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
     }
 
     public BasicHttpClientConnectionManager(
-            final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
-            final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
-            final SchemePortResolver schemePortResolver,
-            final DnsResolver dnsResolver) {
+        final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
+        final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
+        final SchemePortResolver schemePortResolver,
+        final DnsResolver dnsResolver) {
+      this(
+          new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
+          connFactory
+      );
+    }
+
+    /**
+     * @since 4.4
+     */
+    public BasicHttpClientConnectionManager(
+            final HttpClientConnectionOperator httpClientConnectionOperator,
+            final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
         super();
-        this.connectionOperator = new HttpClientConnectionOperator(
-                socketFactoryRegistry, schemePortResolver, dnsResolver);
+        this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
         this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
         this.expiry = Long.MAX_VALUE;
         this.socketConfig = SocketConfig.DEFAULT;
@@ -156,6 +170,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         }
     }
 
+    @Override
     public void close() {
         shutdown();
     }
@@ -184,17 +199,20 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         this.connConfig = connConfig != null ? connConfig : ConnectionConfig.DEFAULT;
     }
 
+    @Override
     public final ConnectionRequest requestConnection(
             final HttpRoute route,
             final Object state) {
         Args.notNull(route, "Route");
         return new ConnectionRequest() {
 
+            @Override
             public boolean cancel() {
                 // Nothing to abort, since requests are immediate.
                 return false;
             }
 
+            @Override
             public HttpClientConnection get(final long timeout, final TimeUnit tunit) {
                 return BasicHttpClientConnectionManager.this.getConnection(
                         route, state);
@@ -259,6 +277,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         return this.conn;
     }
 
+    @Override
     public synchronized void releaseConnection(
             final HttpClientConnection conn,
             final Object state,
@@ -300,6 +319,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         }
     }
 
+    @Override
     public void connect(
             final HttpClientConnection conn,
             final HttpRoute route,
@@ -319,6 +339,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
                 connectTimeout, this.socketConfig, context);
     }
 
+    @Override
     public void upgrade(
             final HttpClientConnection conn,
             final HttpRoute route,
@@ -329,12 +350,14 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         this.connectionOperator.upgrade(this.conn, route.getTargetHost(), context);
     }
 
+    @Override
     public void routeComplete(
             final HttpClientConnection conn,
             final HttpRoute route,
             final HttpContext context) throws IOException {
     }
 
+    @Override
     public synchronized void closeExpiredConnections() {
         if (this.isShutdown.get()) {
             return;
@@ -344,6 +367,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         }
     }
 
+    @Override
     public synchronized void closeIdleConnections(final long idletime, final TimeUnit tunit) {
         Args.notNull(tunit, "Time unit");
         if (this.isShutdown.get()) {
@@ -361,6 +385,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
         }
     }
 
+    @Override
     public synchronized void shutdown() {
         if (this.isShutdown.compareAndSet(false, true)) {
             shutdownConnection();
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java b/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java
index a9318e7..00238e9 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/CPool.java
@@ -64,4 +64,9 @@ class CPool extends AbstractConnPool<HttpRoute, ManagedHttpClientConnection, CPo
         return new CPoolEntry(this.log, id, route, conn, this.timeToLive, this.tunit);
     }
 
+    @Override
+    protected boolean validate(final CPoolEntry entry) {
+        return !entry.getConnection().isStale();
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java b/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java
index a2d4cac..27b7f87 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/CPoolProxy.java
@@ -81,6 +81,7 @@ class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
         return conn;
     }
 
+    @Override
     public void close() throws IOException {
         final CPoolEntry local = this.poolEntry;
         if (local != null) {
@@ -88,6 +89,7 @@ class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
         }
     }
 
+    @Override
     public void shutdown() throws IOException {
         final CPoolEntry local = this.poolEntry;
         if (local != null) {
@@ -95,6 +97,7 @@ class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
         }
     }
 
+    @Override
     public boolean isOpen() {
         final CPoolEntry local = this.poolEntry;
         if (local != null) {
@@ -104,6 +107,7 @@ class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
         }
     }
 
+    @Override
     public boolean isStale() {
         final HttpClientConnection conn = getConnection();
         if (conn != null) {
@@ -113,74 +117,92 @@ class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
         }
     }
 
+    @Override
     public void setSocketTimeout(final int timeout) {
         getValidConnection().setSocketTimeout(timeout);
     }
 
+    @Override
     public int getSocketTimeout() {
         return getValidConnection().getSocketTimeout();
     }
 
+    @Override
     public String getId() {
         return getValidConnection().getId();
     }
 
+    @Override
     public void bind(final Socket socket) throws IOException {
         getValidConnection().bind(socket);
     }
 
+    @Override
     public Socket getSocket() {
         return getValidConnection().getSocket();
     }
 
+    @Override
     public SSLSession getSSLSession() {
         return getValidConnection().getSSLSession();
     }
 
+    @Override
     public boolean isResponseAvailable(final int timeout) throws IOException {
         return getValidConnection().isResponseAvailable(timeout);
     }
 
+    @Override
     public void sendRequestHeader(final HttpRequest request) throws HttpException, IOException {
         getValidConnection().sendRequestHeader(request);
     }
 
+    @Override
     public void sendRequestEntity(final HttpEntityEnclosingRequest request) throws HttpException, IOException {
         getValidConnection().sendRequestEntity(request);
     }
 
+    @Override
     public HttpResponse receiveResponseHeader() throws HttpException, IOException {
         return getValidConnection().receiveResponseHeader();
     }
 
+    @Override
     public void receiveResponseEntity(final HttpResponse response) throws HttpException, IOException {
         getValidConnection().receiveResponseEntity(response);
     }
 
+    @Override
     public void flush() throws IOException {
         getValidConnection().flush();
     }
 
+    @Override
     public HttpConnectionMetrics getMetrics() {
         return getValidConnection().getMetrics();
     }
 
+    @Override
     public InetAddress getLocalAddress() {
         return getValidConnection().getLocalAddress();
     }
 
+    @Override
     public int getLocalPort() {
         return getValidConnection().getLocalPort();
     }
 
+    @Override
     public InetAddress getRemoteAddress() {
         return getValidConnection().getRemoteAddress();
     }
 
+    @Override
     public int getRemotePort() {
         return getValidConnection().getRemotePort();
     }
 
+    @Override
     public Object getAttribute(final String id) {
         final ManagedHttpClientConnection conn = getValidConnection();
         if (conn instanceof HttpContext) {
@@ -190,6 +212,7 @@ class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
         }
     }
 
+    @Override
     public void setAttribute(final String id, final Object obj) {
         final ManagedHttpClientConnection conn = getValidConnection();
         if (conn instanceof HttpContext) {
@@ -197,6 +220,7 @@ class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
         }
     }
 
+    @Override
     public Object removeAttribute(final String id) {
         final ManagedHttpClientConnection conn = getValidConnection();
         if (conn instanceof HttpContext) {
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/ConnectionShutdownException.java b/httpclient/src/main/java/org/apache/http/impl/conn/ConnectionShutdownException.java
index 0d67453..b0b6bb6 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/ConnectionShutdownException.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/ConnectionShutdownException.java
@@ -41,7 +41,7 @@ public class ConnectionShutdownException extends IllegalStateException {
     private static final long serialVersionUID = 5868657401162844497L;
 
     /**
-     * Creates a new ConnectionShutdownException with a <tt>null</tt> detail message.
+     * Creates a new ConnectionShutdownException with a {@code null} detail message.
      */
     public ConnectionShutdownException() {
         super();
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionOperator.java b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpClientConnectionOperator.java
similarity index 89%
rename from httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionOperator.java
rename to httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpClientConnectionOperator.java
index 603b3a1..aef638c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionOperator.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpClientConnectionOperator.java
@@ -28,6 +28,7 @@ package org.apache.http.impl.conn;
 
 import java.io.IOException;
 import java.net.ConnectException;
+import java.net.NoRouteToHostException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
@@ -42,6 +43,7 @@ import org.apache.http.config.Lookup;
 import org.apache.http.config.SocketConfig;
 import org.apache.http.conn.ConnectTimeoutException;
 import org.apache.http.conn.DnsResolver;
+import org.apache.http.conn.HttpClientConnectionOperator;
 import org.apache.http.conn.HttpHostConnectException;
 import org.apache.http.conn.ManagedHttpClientConnection;
 import org.apache.http.conn.SchemePortResolver;
@@ -51,8 +53,15 @@ import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.Args;
 
+/**
+ * Default implementation of {@link HttpClientConnectionOperator} used as default in Http client,
+ * when no instance provided by user to {@link BasicHttpClientConnectionManager} or {@link
+ * PoolingHttpClientConnectionManager} constructor.
+ *
+ * @since 4.4
+ */
 @Immutable
-class HttpClientConnectionOperator {
+public class DefaultHttpClientConnectionOperator implements HttpClientConnectionOperator {
 
     static final String SOCKET_FACTORY_REGISTRY = "http.socket-factory-registry";
 
@@ -62,7 +71,7 @@ class HttpClientConnectionOperator {
     private final SchemePortResolver schemePortResolver;
     private final DnsResolver dnsResolver;
 
-    HttpClientConnectionOperator(
+    public DefaultHttpClientConnectionOperator(
             final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
             final SchemePortResolver schemePortResolver,
             final DnsResolver dnsResolver) {
@@ -85,6 +94,7 @@ class HttpClientConnectionOperator {
         return reg;
     }
 
+    @Override
     public void connect(
             final ManagedHttpClientConnection conn,
             final HttpHost host,
@@ -98,7 +108,8 @@ class HttpClientConnectionOperator {
             throw new UnsupportedSchemeException(host.getSchemeName() +
                     " protocol is not supported");
         }
-        final InetAddress[] addresses = this.dnsResolver.resolve(host.getHostName());
+        final InetAddress[] addresses = host.getAddress() != null ?
+                new InetAddress[] { host.getAddress() } : this.dnsResolver.resolve(host.getHostName());
         final int port = this.schemePortResolver.resolve(host);
         for (int i = 0; i < addresses.length; i++) {
             final InetAddress address = addresses[i];
@@ -111,7 +122,7 @@ class HttpClientConnectionOperator {
             sock.setKeepAlive(socketConfig.isSoKeepAlive());
             final int linger = socketConfig.getSoLinger();
             if (linger >= 0) {
-                sock.setSoLinger(linger > 0, linger);
+                sock.setSoLinger(true, linger);
             }
             conn.bind(sock);
 
@@ -140,6 +151,10 @@ class HttpClientConnectionOperator {
                         throw new HttpHostConnectException(ex, host, addresses);
                     }
                 }
+            } catch (final NoRouteToHostException ex) {
+                if (last) {
+                    throw ex;
+                }
             }
             if (this.log.isDebugEnabled()) {
                 this.log.debug("Connect to " + remoteAddress + " timed out. " +
@@ -148,6 +163,7 @@ class HttpClientConnectionOperator {
         }
     }
 
+    @Override
     public void upgrade(
             final ManagedHttpClientConnection conn,
             final HttpHost host,
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParser.java b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParser.java
index e20543d..c685bf2 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParser.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParser.java
@@ -83,11 +83,11 @@ public class DefaultHttpResponseParser extends AbstractMessageParser<HttpRespons
      * Creates new instance of DefaultHttpResponseParser.
      *
      * @param buffer the session input buffer.
-     * @param lineParser the line parser. If <code>null</code>
+     * @param lineParser the line parser. If {@code null}
      *   {@link org.apache.http.message.BasicLineParser#INSTANCE} will be used.
-     * @param responseFactory HTTP response factory. If <code>null</code>
+     * @param responseFactory HTTP response factory. If {@code null}
      *   {@link DefaultHttpResponseFactory#INSTANCE} will be used.
-     * @param constraints the message constraints. If <code>null</code>
+     * @param constraints the message constraints. If {@code null}
      *   {@link MessageConstraints#DEFAULT} will be used.
      *
      * @since 4.3
@@ -107,7 +107,7 @@ public class DefaultHttpResponseParser extends AbstractMessageParser<HttpRespons
      * Creates new instance of DefaultHttpResponseParser.
      *
      * @param buffer the session input buffer.
-     * @param constraints the message constraints. If <code>null</code>
+     * @param constraints the message constraints. If {@code null}
      *   {@link MessageConstraints#DEFAULT} will be used.
      *
      * @since 4.3
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParserFactory.java b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParserFactory.java
index 17ca1c9..f5c0af0 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParserFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultHttpResponseParserFactory.java
@@ -69,6 +69,7 @@ public class DefaultHttpResponseParserFactory implements HttpMessageParserFactor
         this(null, null);
     }
 
+    @Override
     public HttpMessageParser<HttpResponse> create(final SessionInputBuffer buffer,
             final MessageConstraints constraints) {
         return new DefaultHttpResponseParser(buffer, lineParser, responseFactory, constraints);
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultManagedHttpClientConnection.java b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultManagedHttpClientConnection.java
index 18d1d12..7eabfac 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultManagedHttpClientConnection.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultManagedHttpClientConnection.java
@@ -86,6 +86,7 @@ public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnec
         this(id, buffersize, buffersize, null, null, null, null, null, null, null);
     }
 
+    @Override
     public String getId() {
         return this.id;
     }
@@ -96,14 +97,17 @@ public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnec
         super.shutdown();
     }
 
+    @Override
     public Object getAttribute(final String id) {
         return this.attributes.get(id);
     }
 
+    @Override
     public Object removeAttribute(final String id) {
         return this.attributes.remove(id);
     }
 
+    @Override
     public void setAttribute(final String id, final Object obj) {
         this.attributes.put(id, obj);
     }
@@ -123,6 +127,7 @@ public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnec
         return super.getSocket();
     }
 
+    @Override
     public SSLSession getSSLSession() {
         final Socket socket = super.getSocket();
         if (socket instanceof SSLSocket) {
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultRoutePlanner.java b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultRoutePlanner.java
index 2b21f1a..b56d2f8 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultRoutePlanner.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultRoutePlanner.java
@@ -60,6 +60,7 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
             DefaultSchemePortResolver.INSTANCE;
     }
 
+    @Override
     public HttpRoute determineRoute(
             final HttpHost host,
             final HttpRequest request,
@@ -97,6 +98,11 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
         }
     }
 
+    /**
+     * This implementation returns null.
+     *
+     * @throws HttpException may be thrown if overridden
+     */
     protected HttpHost determineProxy(
             final HttpHost target,
             final HttpRequest request,
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultSchemePortResolver.java b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultSchemePortResolver.java
index c8abe8e..c5d54ed 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultSchemePortResolver.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultSchemePortResolver.java
@@ -42,6 +42,7 @@ public class DefaultSchemePortResolver implements SchemePortResolver {
 
     public static final DefaultSchemePortResolver INSTANCE = new DefaultSchemePortResolver();
 
+    @Override
     public int resolve(final HttpHost host) throws UnsupportedSchemeException {
         Args.notNull(host, "HTTP host");
         final int port = host.getPort();
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/InMemoryDnsResolver.java b/httpclient/src/main/java/org/apache/http/impl/conn/InMemoryDnsResolver.java
index d366549..c75fbeb 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/InMemoryDnsResolver.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/InMemoryDnsResolver.java
@@ -80,6 +80,7 @@ public class InMemoryDnsResolver implements DnsResolver {
     /**
      * {@inheritDoc}
      */
+    @Override
     public InetAddress[] resolve(final String host) throws UnknownHostException {
         final InetAddress[] resolvedAddresses = dnsMap.get(host);
         if (log.isInfoEnabled()) {
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/ManagedHttpClientConnectionFactory.java b/httpclient/src/main/java/org/apache/http/impl/conn/ManagedHttpClientConnectionFactory.java
index 32c2dfb..2d7d521 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/ManagedHttpClientConnectionFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/ManagedHttpClientConnectionFactory.java
@@ -42,6 +42,9 @@ import org.apache.http.config.ConnectionConfig;
 import org.apache.http.conn.HttpConnectionFactory;
 import org.apache.http.conn.ManagedHttpClientConnection;
 import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.entity.ContentLengthStrategy;
+import org.apache.http.impl.entity.LaxContentLengthStrategy;
+import org.apache.http.impl.entity.StrictContentLengthStrategy;
 import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
 import org.apache.http.io.HttpMessageParserFactory;
 import org.apache.http.io.HttpMessageWriterFactory;
@@ -64,15 +67,32 @@ public class ManagedHttpClientConnectionFactory
 
     private final HttpMessageWriterFactory<HttpRequest> requestWriterFactory;
     private final HttpMessageParserFactory<HttpResponse> responseParserFactory;
+    private final ContentLengthStrategy incomingContentStrategy;
+    private final ContentLengthStrategy outgoingContentStrategy;
 
+    /**
+     * @since 4.4
+     */
     public ManagedHttpClientConnectionFactory(
             final HttpMessageWriterFactory<HttpRequest> requestWriterFactory,
-            final HttpMessageParserFactory<HttpResponse> responseParserFactory) {
+            final HttpMessageParserFactory<HttpResponse> responseParserFactory,
+            final ContentLengthStrategy incomingContentStrategy,
+            final ContentLengthStrategy outgoingContentStrategy) {
         super();
         this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
-            DefaultHttpRequestWriterFactory.INSTANCE;
+                DefaultHttpRequestWriterFactory.INSTANCE;
         this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
-            DefaultHttpResponseParserFactory.INSTANCE;
+                DefaultHttpResponseParserFactory.INSTANCE;
+        this.incomingContentStrategy = incomingContentStrategy != null ? incomingContentStrategy :
+                LaxContentLengthStrategy.INSTANCE;
+        this.outgoingContentStrategy = outgoingContentStrategy != null ? outgoingContentStrategy :
+                StrictContentLengthStrategy.INSTANCE;
+    }
+
+    public ManagedHttpClientConnectionFactory(
+            final HttpMessageWriterFactory<HttpRequest> requestWriterFactory,
+            final HttpMessageParserFactory<HttpResponse> responseParserFactory) {
+        this(requestWriterFactory, responseParserFactory, null, null);
     }
 
     public ManagedHttpClientConnectionFactory(
@@ -84,6 +104,7 @@ public class ManagedHttpClientConnectionFactory
         this(null, null);
     }
 
+    @Override
     public ManagedHttpClientConnection create(final HttpRoute route, final ConnectionConfig config) {
         final ConnectionConfig cconfig = config != null ? config : ConnectionConfig.DEFAULT;
         CharsetDecoder chardecoder = null;
@@ -112,8 +133,8 @@ public class ManagedHttpClientConnectionFactory
                 chardecoder,
                 charencoder,
                 cconfig.getMessageConstraints(),
-                null,
-                null,
+                incomingContentStrategy,
+                outgoingContentStrategy,
                 requestWriterFactory,
                 responseParserFactory);
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java b/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
index aa2a677..4b06195 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
@@ -30,6 +30,7 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -51,6 +52,7 @@ import org.apache.http.conn.ConnectionPoolTimeoutException;
 import org.apache.http.conn.ConnectionRequest;
 import org.apache.http.conn.DnsResolver;
 import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.HttpClientConnectionOperator;
 import org.apache.http.conn.HttpConnectionFactory;
 import org.apache.http.conn.SchemePortResolver;
 import org.apache.http.conn.ManagedHttpClientConnection;
@@ -66,20 +68,29 @@ import org.apache.http.util.Args;
 import org.apache.http.util.Asserts;
 
 /**
- * <tt>ClientConnectionPoolManager</tt> maintains a pool of
+ * {@code ClientConnectionPoolManager} maintains a pool of
  * {@link HttpClientConnection}s and is able to service connection requests
  * from multiple execution threads. Connections are pooled on a per route
  * basis. A request for a route which already the manager has persistent
  * connections for available in the pool will be services by leasing
  * a connection from the pool rather than creating a brand new connection.
- * <p/>
- * <tt>ClientConnectionPoolManager</tt> maintains a maximum limit of connection
+ * <p>
+ * {@code ClientConnectionPoolManager} maintains a maximum limit of connection
  * on a per route basis and in total. Per default this implementation will
  * create no more than than 2 concurrent connections per given route
  * and no more 20 connections in total. For many real-world applications
  * these limits may prove too constraining, especially if they use HTTP
  * as a transport protocol for their services. Connection limits, however,
  * can be adjusted using {@link ConnPoolControl} methods.
+ * </p>
+ * <p>
+ * The handling of stale connections was changed in version 4.4.
+ * Previously, the code would check every connection by default before re-using it.
+ * The code now only checks the connection if the elapsed time since
+ * the last use of the connection exceeds the timeout that has been set.
+ * The default timeout is set to 5000ms - see
+ * {@link #PoolingHttpClientConnectionManager(HttpClientConnectionOperator, HttpConnectionFactory, long, TimeUnit)}
+ * </p>
  *
  * @since 4.3
  */
@@ -144,15 +155,32 @@ public class PoolingHttpClientConnectionManager
             final SchemePortResolver schemePortResolver,
             final DnsResolver dnsResolver,
             final long timeToLive, final TimeUnit tunit) {
+        this(
+            new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
+            connFactory,
+            timeToLive, tunit
+        );
+    }
+
+    /**
+     * @since 4.4
+     */
+    public PoolingHttpClientConnectionManager(
+        final HttpClientConnectionOperator httpClientConnectionOperator,
+        final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
+        final long timeToLive, final TimeUnit tunit) {
         super();
         this.configData = new ConfigData();
-        this.pool = new CPool(
-                new InternalConnectionFactory(this.configData, connFactory), 2, 20, timeToLive, tunit);
-        this.connectionOperator = new HttpClientConnectionOperator(
-                socketFactoryRegistry, schemePortResolver, dnsResolver);
+        this.pool = new CPool(new InternalConnectionFactory(
+                this.configData, connFactory), 2, 20, timeToLive, tunit);
+        this.pool.setValidateAfterInactivity(5000);
+        this.connectionOperator = Args.notNull(httpClientConnectionOperator, "HttpClientConnectionOperator");
         this.isShutDown = new AtomicBoolean(false);
     }
 
+    /**
+     * Visible for test.
+     */
     PoolingHttpClientConnectionManager(
             final CPool pool,
             final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
@@ -161,7 +189,7 @@ public class PoolingHttpClientConnectionManager
         super();
         this.configData = new ConfigData();
         this.pool = pool;
-        this.connectionOperator = new HttpClientConnectionOperator(
+        this.connectionOperator = new DefaultHttpClientConnectionOperator(
                 socketFactoryRegistry, schemePortResolver, dnsResolver);
         this.isShutDown = new AtomicBoolean(false);
     }
@@ -175,6 +203,7 @@ public class PoolingHttpClientConnectionManager
         }
     }
 
+    @Override
     public void close() {
         shutdown();
     }
@@ -211,6 +240,7 @@ public class PoolingHttpClientConnectionManager
         return buf.toString();
     }
 
+    @Override
     public ConnectionRequest requestConnection(
             final HttpRoute route,
             final Object state) {
@@ -221,10 +251,12 @@ public class PoolingHttpClientConnectionManager
         final Future<CPoolEntry> future = this.pool.lease(route, state, null);
         return new ConnectionRequest() {
 
+            @Override
             public boolean cancel() {
                 return future.cancel(true);
             }
 
+            @Override
             public HttpClientConnection get(
                     final long timeout,
                     final TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {
@@ -255,6 +287,7 @@ public class PoolingHttpClientConnectionManager
         }
     }
 
+    @Override
     public void releaseConnection(
             final HttpClientConnection managedConn,
             final Object state,
@@ -268,12 +301,13 @@ public class PoolingHttpClientConnectionManager
             final ManagedHttpClientConnection conn = entry.getConnection();
             try {
                 if (conn.isOpen()) {
+                    final TimeUnit effectiveUnit = tunit != null ? tunit : TimeUnit.MILLISECONDS;
                     entry.setState(state);
-                    entry.updateExpiry(keepalive, tunit != null ? tunit : TimeUnit.MILLISECONDS);
+                    entry.updateExpiry(keepalive, effectiveUnit);
                     if (this.log.isDebugEnabled()) {
                         final String s;
                         if (keepalive > 0) {
-                            s = "for " + (double) keepalive / 1000 + " seconds";
+                            s = "for " + (double) effectiveUnit.toMillis(keepalive) / 1000 + " seconds";
                         } else {
                             s = "indefinitely";
                         }
@@ -289,6 +323,7 @@ public class PoolingHttpClientConnectionManager
         }
     }
 
+    @Override
     public void connect(
             final HttpClientConnection managedConn,
             final HttpRoute route,
@@ -319,6 +354,7 @@ public class PoolingHttpClientConnectionManager
                 conn, host, localAddress, connectTimeout, socketConfig, context);
     }
 
+    @Override
     public void upgrade(
             final HttpClientConnection managedConn,
             final HttpRoute route,
@@ -333,6 +369,7 @@ public class PoolingHttpClientConnectionManager
         this.connectionOperator.upgrade(conn, route.getTargetHost(), context);
     }
 
+    @Override
     public void routeComplete(
             final HttpClientConnection managedConn,
             final HttpRoute route,
@@ -345,6 +382,7 @@ public class PoolingHttpClientConnectionManager
         }
     }
 
+    @Override
     public void shutdown() {
         if (this.isShutDown.compareAndSet(false, true)) {
             this.log.debug("Connection manager is shutting down");
@@ -357,6 +395,7 @@ public class PoolingHttpClientConnectionManager
         }
     }
 
+    @Override
     public void closeIdleConnections(final long idleTimeout, final TimeUnit tunit) {
         if (this.log.isDebugEnabled()) {
             this.log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit);
@@ -364,43 +403,59 @@ public class PoolingHttpClientConnectionManager
         this.pool.closeIdle(idleTimeout, tunit);
     }
 
+    @Override
     public void closeExpiredConnections() {
         this.log.debug("Closing expired connections");
         this.pool.closeExpired();
     }
 
+    @Override
     public int getMaxTotal() {
         return this.pool.getMaxTotal();
     }
 
+    @Override
     public void setMaxTotal(final int max) {
         this.pool.setMaxTotal(max);
     }
 
+    @Override
     public int getDefaultMaxPerRoute() {
         return this.pool.getDefaultMaxPerRoute();
     }
 
+    @Override
     public void setDefaultMaxPerRoute(final int max) {
         this.pool.setDefaultMaxPerRoute(max);
     }
 
+    @Override
     public int getMaxPerRoute(final HttpRoute route) {
         return this.pool.getMaxPerRoute(route);
     }
 
+    @Override
     public void setMaxPerRoute(final HttpRoute route, final int max) {
         this.pool.setMaxPerRoute(route, max);
     }
 
+    @Override
     public PoolStats getTotalStats() {
         return this.pool.getTotalStats();
     }
 
+    @Override
     public PoolStats getStats(final HttpRoute route) {
         return this.pool.getStats(route);
     }
 
+    /**
+     * @since 4.4
+     */
+    public Set<HttpRoute> getRoutes() {
+        return this.pool.getRoutes();
+    }
+
     public SocketConfig getDefaultSocketConfig() {
         return this.configData.getDefaultSocketConfig();
     }
@@ -433,6 +488,30 @@ public class PoolingHttpClientConnectionManager
         this.configData.setConnectionConfig(host, connectionConfig);
     }
 
+    /**
+     * @see #setValidateAfterInactivity(int)
+     *
+     * @since 4.4
+     */
+    public int getValidateAfterInactivity() {
+        return pool.getValidateAfterInactivity();
+    }
+
+    /**
+     * Defines period of inactivity in milliseconds after which persistent connections must
+     * be re-validated prior to being {@link #leaseConnection(java.util.concurrent.Future,
+     *   long, java.util.concurrent.TimeUnit) leased} to the consumer. Non-positive value passed
+     * to this method disables connection validation. This check helps detect connections
+     * that have become stale (half-closed) while kept inactive in the pool.
+     *
+     * @see #leaseConnection(java.util.concurrent.Future, long, java.util.concurrent.TimeUnit)
+     *
+     * @since 4.4
+     */
+    public void setValidateAfterInactivity(final int ms) {
+        pool.setValidateAfterInactivity(ms);
+    }
+
     static class ConfigData {
 
         private final Map<HttpHost, SocketConfig> socketConfigMap;
@@ -494,6 +573,7 @@ public class PoolingHttpClientConnectionManager
                 ManagedHttpClientConnectionFactory.INSTANCE;
         }
 
+        @Override
         public ManagedHttpClientConnection create(final HttpRoute route) throws IOException {
             ConnectionConfig config = null;
             if (route.getProxyHost() != null) {
diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/SystemDefaultDnsResolver.java b/httpclient/src/main/java/org/apache/http/impl/conn/SystemDefaultDnsResolver.java
index 8b9cb6b..94e213f 100644
--- a/httpclient/src/main/java/org/apache/http/impl/conn/SystemDefaultDnsResolver.java
+++ b/httpclient/src/main/java/org/apache/http/impl/conn/SystemDefaultDnsResolver.java
@@ -40,6 +40,7 @@ public class SystemDefaultDnsResolver implements DnsResolver {
 
     public static final SystemDefaultDnsResolver INSTANCE = new SystemDefaultDnsResolver();
 
+    @Override
     public InetAddress[] resolve(final String host) throws UnknownHostException {
         return InetAddress.getAllByName(host);
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java
index 8f1763e..ccf12dd 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.java
@@ -39,11 +39,13 @@ import org.apache.http.cookie.MalformedCookieException;
 @Immutable
 public abstract class AbstractCookieAttributeHandler implements CookieAttributeHandler {
 
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         // Do nothing
     }
 
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         // Always match
         return true;
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java b/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java
index 1afada3..054ee90 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java
@@ -30,11 +30,14 @@ package org.apache.http.impl.cookie;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieSpec;
 import org.apache.http.util.Args;
+import org.apache.http.util.Asserts;
 
 /**
  * Abstract cookie specification which can delegate the job of parsing,
@@ -44,7 +47,7 @@ import org.apache.http.util.Args;
  *
  * @since 4.0
  */
- at NotThreadSafe // HashMap is not thread-safe
+ at ThreadSafe
 public abstract class AbstractCookieSpec implements CookieSpec {
 
     /**
@@ -57,9 +60,35 @@ public abstract class AbstractCookieSpec implements CookieSpec {
      * */
     public AbstractCookieSpec() {
         super();
-        this.attribHandlerMap = new HashMap<String, CookieAttributeHandler>(10);
+        this.attribHandlerMap = new ConcurrentHashMap<String, CookieAttributeHandler>(10);
     }
 
+    /**
+     * @since 4.4
+     */
+    protected AbstractCookieSpec(final HashMap<String, CookieAttributeHandler> map) {
+        super();
+        Asserts.notNull(map, "Attribute handler map");
+        this.attribHandlerMap = new ConcurrentHashMap<String, CookieAttributeHandler>(map);
+    }
+
+    /**
+     * @since 4.4
+     */
+    protected AbstractCookieSpec(final CommonCookieAttributeHandler... handlers) {
+        super();
+        this.attribHandlerMap = new ConcurrentHashMap<String, CookieAttributeHandler>(handlers.length);
+        for (CommonCookieAttributeHandler handler: handlers) {
+            this.attribHandlerMap.put(handler.getAttributeName(), handler);
+        }
+    }
+
+    /**
+     * @deprecated (4.4) use {@link #AbstractCookieSpec(java.util.HashMap)} or
+     *  {@link #AbstractCookieSpec(org.apache.http.cookie.CommonCookieAttributeHandler...)}
+     *  constructors instead.
+     */
+    @Deprecated
     public void registerAttribHandler(
             final String name, final CookieAttributeHandler handler) {
         Args.notNull(name, "Attribute name");
@@ -69,11 +98,11 @@ public abstract class AbstractCookieSpec implements CookieSpec {
 
     /**
      * Finds an attribute handler {@link CookieAttributeHandler} for the
-     * given attribute. Returns <tt>null</tt> if no attribute handler is
+     * given attribute. Returns {@code null} if no attribute handler is
      * found for the specified attribute.
      *
      * @param name attribute name. e.g. Domain, Path, etc.
-     * @return an attribute handler or <tt>null</tt>
+     * @return an attribute handler or {@code null}
      */
     protected CookieAttributeHandler findAttribHandler(final String name) {
         return this.attribHandlerMap.get(name);
@@ -89,12 +118,9 @@ public abstract class AbstractCookieSpec implements CookieSpec {
      */
     protected CookieAttributeHandler getAttribHandler(final String name) {
         final CookieAttributeHandler handler = findAttribHandler(name);
-        if (handler == null) {
-            throw new IllegalStateException("Handler not registered for " +
-                                            name + " attribute.");
-        } else {
-            return handler;
-        }
+        Asserts.check(handler != null, "Handler not registered for " +
+                name + " attribute");
+        return handler;
     }
 
     protected Collection<CookieAttributeHandler> getAttribHandlers() {
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java
index fea4683..dc261ab 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java
@@ -67,6 +67,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @return String name The name
      */
+    @Override
     public String getName() {
         return this.name;
     }
@@ -76,6 +77,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @return String value The current value.
      */
+    @Override
     public String getValue() {
         return this.value;
     }
@@ -85,18 +87,20 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @param value
      */
+    @Override
     public void setValue(final String value) {
         this.value = value;
     }
 
     /**
      * Returns the comment describing the purpose of this cookie, or
-     * <tt>null</tt> if no such comment has been defined.
+     * {@code null} if no such comment has been defined.
      *
      * @return comment
      *
      * @see #setComment(String)
      */
+    @Override
     public String getComment() {
         return cookieComment;
     }
@@ -109,6 +113,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @see #getComment()
      */
+    @Override
     public void setComment(final String comment) {
         cookieComment = comment;
     }
@@ -117,22 +122,24 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
     /**
      * Returns null. Cookies prior to RFC2965 do not set this attribute
      */
+    @Override
     public String getCommentURL() {
         return null;
     }
 
 
     /**
-     * Returns the expiration {@link Date} of the cookie, or <tt>null</tt>
+     * Returns the expiration {@link Date} of the cookie, or {@code null}
      * if none exists.
      * <p><strong>Note:</strong> the object returned by this method is
      * considered immutable. Changing it (e.g. using setTime()) could result
      * in undefined behaviour. Do so at your peril. </p>
-     * @return Expiration {@link Date}, or <tt>null</tt>.
+     * @return Expiration {@link Date}, or {@code null}.
      *
      * @see #setExpiryDate(java.util.Date)
      *
      */
+    @Override
     public Date getExpiryDate() {
         return cookieExpiryDate;
     }
@@ -148,18 +155,20 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      * @see #getExpiryDate
      *
      */
+    @Override
     public void setExpiryDate (final Date expiryDate) {
         cookieExpiryDate = expiryDate;
     }
 
 
     /**
-     * Returns <tt>false</tt> if the cookie should be discarded at the end
-     * of the "session"; <tt>true</tt> otherwise.
+     * Returns {@code false} if the cookie should be discarded at the end
+     * of the "session"; {@code true} otherwise.
      *
-     * @return <tt>false</tt> if the cookie should be discarded at the end
-     *         of the "session"; <tt>true</tt> otherwise
+     * @return {@code false} if the cookie should be discarded at the end
+     *         of the "session"; {@code true} otherwise
      */
+    @Override
     public boolean isPersistent() {
         return (null != cookieExpiryDate);
     }
@@ -172,6 +181,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @see #setDomain(java.lang.String)
      */
+    @Override
     public String getDomain() {
         return cookieDomain;
     }
@@ -183,9 +193,10 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @see #getDomain
      */
+    @Override
     public void setDomain(final String domain) {
         if (domain != null) {
-            cookieDomain = domain.toLowerCase(Locale.ENGLISH);
+            cookieDomain = domain.toLowerCase(Locale.ROOT);
         } else {
             cookieDomain = null;
         }
@@ -199,6 +210,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @see #setPath(java.lang.String)
      */
+    @Override
     public String getPath() {
         return cookiePath;
     }
@@ -211,14 +223,16 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      * @see #getPath
      *
      */
+    @Override
     public void setPath(final String path) {
         cookiePath = path;
     }
 
     /**
-     * @return <code>true</code> if this cookie should only be sent over secure connections.
+     * @return {@code true} if this cookie should only be sent over secure connections.
      * @see #setSecure(boolean)
      */
+    @Override
     public boolean isSecure() {
         return isSecure;
     }
@@ -226,7 +240,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
     /**
      * Sets the secure attribute of the cookie.
      * <p>
-     * When <tt>true</tt> the cookie should only be sent
+     * When {@code true} the cookie should only be sent
      * using a secure protocol (https).  This should only be set when
      * the cookie's originating server used a secure protocol to set the
      * cookie's value.
@@ -235,6 +249,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @see #isSecure()
      */
+    @Override
     public void setSecure (final boolean secure) {
         isSecure = secure;
     }
@@ -243,6 +258,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
     /**
      * Returns null. Cookies prior to RFC2965 do not set this attribute
      */
+    @Override
     public int[] getPorts() {
         return null;
     }
@@ -257,6 +273,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      * @see #setVersion(int)
      *
      */
+    @Override
     public int getVersion() {
         return cookieVersion;
     }
@@ -269,6 +286,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      *
      * @see #getVersion
      */
+    @Override
     public void setVersion(final int version) {
         cookieVersion = version;
     }
@@ -277,24 +295,48 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
      * Returns true if this cookie has expired.
      * @param date Current time
      *
-     * @return <tt>true</tt> if the cookie has expired.
+     * @return {@code true} if the cookie has expired.
      */
+    @Override
     public boolean isExpired(final Date date) {
         Args.notNull(date, "Date");
         return (cookieExpiryDate != null
             && cookieExpiryDate.getTime() <= date.getTime());
     }
 
+    /**
+     * @since 4.4
+     */
+    public Date getCreationDate() {
+        return creationDate;
+    }
+
+    /**
+     * @since 4.4
+     */
+    public void setCreationDate(final Date creationDate) {
+        this.creationDate = creationDate;
+    }
+
     public void setAttribute(final String name, final String value) {
         this.attribs.put(name, value);
     }
 
+    @Override
     public String getAttribute(final String name) {
         return this.attribs.get(name);
     }
 
+    @Override
     public boolean containsAttribute(final String name) {
-        return this.attribs.get(name) != null;
+        return this.attribs.containsKey(name);
+    }
+
+    /**
+     * @since 4.4
+     */
+    public boolean removeAttribute(final String name) {
+        return this.attribs.remove(name) != null;
     }
 
     @Override
@@ -357,5 +399,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable, Se
     /** The version of the cookie specification I was created from. */
     private int cookieVersion;
 
+    private Date creationDate;
+
 }
 
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java
index c0aaacf..e9c50a3 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java
@@ -61,6 +61,7 @@ public class BasicClientCookie2 extends BasicClientCookie implements SetCookie2
         return this.ports;
     }
 
+    @Override
     public void setPorts(final int[] ports) {
         this.ports = ports;
     }
@@ -70,10 +71,12 @@ public class BasicClientCookie2 extends BasicClientCookie implements SetCookie2
         return this.commentURL;
     }
 
+    @Override
     public void setCommentURL(final String commentURL) {
         this.commentURL = commentURL;
     }
 
+    @Override
     public void setDiscard(final boolean discard) {
         this.discard = discard;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java
index 6270da1..14c9cfe 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicCommentHandler.java
@@ -27,6 +27,8 @@
 package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
@@ -36,16 +38,22 @@ import org.apache.http.util.Args;
  * @since 4.0
  */
 @Immutable
-public class BasicCommentHandler extends AbstractCookieAttributeHandler {
+public class BasicCommentHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
     public BasicCommentHandler() {
         super();
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         cookie.setComment(value);
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.COMMENT_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java
index 2680c51..7503971 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java
@@ -26,38 +26,51 @@
  */
 package org.apache.http.impl.cookie;
 
+import java.util.Locale;
+
 import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.util.InetAddressUtils;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
+import org.apache.http.util.TextUtils;
 
 /**
  *
  * @since 4.0
  */
 @Immutable
-public class BasicDomainHandler implements CookieAttributeHandler {
+public class BasicDomainHandler implements CommonCookieAttributeHandler {
 
     public BasicDomainHandler() {
         super();
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
-        if (value == null) {
-            throw new MalformedCookieException("Missing value for domain attribute");
+        if (TextUtils.isBlank(value)) {
+            throw new MalformedCookieException("Blank or null value for domain attribute");
+        }
+        // Ignore domain attributes ending with '.' per RFC 6265, 4.1.2.3
+        if (value.endsWith(".")) {
+            return;
         }
-        if (value.trim().length() == 0) {
-            throw new MalformedCookieException("Blank value for domain attribute");
+        String domain = value;
+        if (domain.startsWith(".")) {
+            domain = domain.substring(1);
         }
-        cookie.setDomain(value);
+        domain = domain.toLowerCase(Locale.ROOT);
+        cookie.setDomain(domain);
     }
 
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -68,34 +81,35 @@ public class BasicDomainHandler implements CookieAttributeHandler {
         // request-host and domain must be identical for the cookie to sent
         // back to the origin-server.
         final String host = origin.getHost();
-        String domain = cookie.getDomain();
+        final String domain = cookie.getDomain();
         if (domain == null) {
-            throw new CookieRestrictionViolationException("Cookie domain may not be null");
+            throw new CookieRestrictionViolationException("Cookie 'domain' may not be null");
         }
-        if (host.contains(".")) {
-            // Not required to have at least two dots.  RFC 2965.
-            // A Set-Cookie2 with Domain=ajax.com will be accepted.
+        if (!host.equals(domain) && !domainMatch(domain, host)) {
+            throw new CookieRestrictionViolationException(
+                    "Illegal 'domain' attribute \"" + domain + "\". Domain of origin: \"" + host + "\"");
+        }
+    }
 
-            // domain must match host
-            if (!host.endsWith(domain)) {
-                if (domain.startsWith(".")) {
-                    domain = domain.substring(1, domain.length());
-                }
-                if (!host.equals(domain)) {
-                    throw new CookieRestrictionViolationException(
-                        "Illegal domain attribute \"" + domain
-                        + "\". Domain of origin: \"" + host + "\"");
-                }
+    static boolean domainMatch(final String domain, final String host) {
+        if (InetAddressUtils.isIPv4Address(host) || InetAddressUtils.isIPv6Address(host)) {
+            return false;
+        }
+        final String normalizedDomain = domain.startsWith(".") ? domain.substring(1) : domain;
+        if (host.endsWith(normalizedDomain)) {
+            final int prefix = host.length() - normalizedDomain.length();
+            // Either a full match or a prefix endidng with a '.'
+            if (prefix == 0) {
+                return true;
             }
-        } else {
-            if (!host.equals(domain)) {
-                throw new CookieRestrictionViolationException(
-                    "Illegal domain attribute \"" + domain
-                    + "\". Domain of origin: \"" + host + "\"");
+            if (prefix > 1 && host.charAt(prefix - 1) == '.') {
+                return true;
             }
         }
+        return false;
     }
 
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         Args.notNull(cookie, "Cookie");
         Args.notNull(origin, "Cookie origin");
@@ -104,13 +118,24 @@ public class BasicDomainHandler implements CookieAttributeHandler {
         if (domain == null) {
             return false;
         }
+        if (domain.startsWith(".")) {
+            domain = domain.substring(1);
+        }
+        domain = domain.toLowerCase(Locale.ROOT);
         if (host.equals(domain)) {
             return true;
         }
-        if (!domain.startsWith(".")) {
-            domain = '.' + domain;
+        if (cookie instanceof ClientCookie) {
+            if (((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
+                return domainMatch(domain, host);
+            }
         }
-        return host.endsWith(domain) || host.equals(domain.substring(1));
+        return false;
+    }
+
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.DOMAIN_ATTR;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java
index d764c2c..21a2876 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java
@@ -30,6 +30,8 @@ import java.util.Date;
 
 import org.apache.http.annotation.Immutable;
 import org.apache.http.client.utils.DateUtils;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
@@ -39,7 +41,7 @@ import org.apache.http.util.Args;
  * @since 4.0
  */
 @Immutable
-public class BasicExpiresHandler extends AbstractCookieAttributeHandler {
+public class BasicExpiresHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
     /** Valid date patterns */
     private final String[] datepatterns;
@@ -49,18 +51,24 @@ public class BasicExpiresHandler extends AbstractCookieAttributeHandler {
         this.datepatterns = datepatterns;
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         if (value == null) {
-            throw new MalformedCookieException("Missing value for expires attribute");
+            throw new MalformedCookieException("Missing value for 'expires' attribute");
         }
         final Date expiry = DateUtils.parseDate(value, this.datepatterns);
         if (expiry == null) {
-            throw new MalformedCookieException("Unable to parse expires attribute: "
+            throw new MalformedCookieException("Invalid 'expires' attribute: "
                     + value);
         }
         cookie.setExpiryDate(expiry);
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.EXPIRES_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
index df1161c..02ee8ba 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
@@ -29,6 +29,8 @@ package org.apache.http.impl.cookie;
 import java.util.Date;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
@@ -38,30 +40,36 @@ import org.apache.http.util.Args;
  * @since 4.0
  */
 @Immutable
-public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler {
+public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
     public BasicMaxAgeHandler() {
         super();
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         if (value == null) {
-            throw new MalformedCookieException("Missing value for max-age attribute");
+            throw new MalformedCookieException("Missing value for 'max-age' attribute");
         }
         final int age;
         try {
             age = Integer.parseInt(value);
         } catch (final NumberFormatException e) {
-            throw new MalformedCookieException ("Invalid max-age attribute: "
+            throw new MalformedCookieException ("Invalid 'max-age' attribute: "
                     + value);
         }
         if (age < 0) {
-            throw new MalformedCookieException ("Negative max-age attribute: "
+            throw new MalformedCookieException ("Negative 'max-age' attribute: "
                     + value);
         }
         cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L));
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.MAX_AGE_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java
index babbabe..c7b3875 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java
@@ -27,8 +27,9 @@
 package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
 import org.apache.http.cookie.MalformedCookieException;
@@ -41,47 +42,61 @@ import org.apache.http.util.TextUtils;
  * @since 4.0
  */
 @Immutable
-public class BasicPathHandler implements CookieAttributeHandler {
+public class BasicPathHandler implements CommonCookieAttributeHandler {
 
     public BasicPathHandler() {
         super();
     }
 
+    @Override
     public void parse(
             final SetCookie cookie, final String value) throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         cookie.setPath(!TextUtils.isBlank(value) ? value : "/");
     }
 
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         if (!match(cookie, origin)) {
             throw new CookieRestrictionViolationException(
-                "Illegal path attribute \"" + cookie.getPath()
+                "Illegal 'path' attribute \"" + cookie.getPath()
                 + "\". Path of origin: \"" + origin.getPath() + "\"");
         }
     }
 
-    public boolean match(final Cookie cookie, final CookieOrigin origin) {
-        Args.notNull(cookie, "Cookie");
-        Args.notNull(origin, "Cookie origin");
-        final String targetpath = origin.getPath();
-        String topmostPath = cookie.getPath();
-        if (topmostPath == null) {
-            topmostPath = "/";
+    static boolean pathMatch(final String uriPath, final String cookiePath) {
+        String normalizedCookiePath = cookiePath;
+        if (normalizedCookiePath == null) {
+            normalizedCookiePath = "/";
         }
-        if (topmostPath.length() > 1 && topmostPath.endsWith("/")) {
-            topmostPath = topmostPath.substring(0, topmostPath.length() - 1);
+        if (normalizedCookiePath.length() > 1 && normalizedCookiePath.endsWith("/")) {
+            normalizedCookiePath = normalizedCookiePath.substring(0, normalizedCookiePath.length() - 1);
         }
-        boolean match = targetpath.startsWith (topmostPath);
-        // if there is a match and these values are not exactly the same we have
-        // to make sure we're not matcing "/foobar" and "/foo"
-        if (match && targetpath.length() != topmostPath.length()) {
-            if (!topmostPath.endsWith("/")) {
-                match = (targetpath.charAt(topmostPath.length()) == '/');
+        if (uriPath.startsWith(normalizedCookiePath)) {
+            if (normalizedCookiePath.equals("/")) {
+                return true;
+            }
+            if (uriPath.length() == normalizedCookiePath.length()) {
+                return true;
+            }
+            if (uriPath.charAt(normalizedCookiePath.length()) == '/') {
+                return true;
             }
         }
-        return match;
+        return false;
+    }
+
+    @Override
+    public boolean match(final Cookie cookie, final CookieOrigin origin) {
+        Args.notNull(cookie, "Cookie");
+        Args.notNull(origin, "Cookie origin");
+        return pathMatch(origin.getPath(), cookie.getPath());
+    }
+
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.PATH_ATTR;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java
index 2d9d024..5b8f55c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java
@@ -27,6 +27,8 @@
 package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.MalformedCookieException;
@@ -38,12 +40,13 @@ import org.apache.http.util.Args;
  * @since 4.0
  */
 @Immutable
-public class BasicSecureHandler extends AbstractCookieAttributeHandler {
+public class BasicSecureHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
     public BasicSecureHandler() {
         super();
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -57,4 +60,9 @@ public class BasicSecureHandler extends AbstractCookieAttributeHandler {
         return !cookie.isSecure() || origin.isSecure();
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.SECURE_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/CookieSpecBase.java b/httpclient/src/main/java/org/apache/http/impl/cookie/CookieSpecBase.java
index 411a359..32730d2 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/CookieSpecBase.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/CookieSpecBase.java
@@ -28,12 +28,14 @@
 package org.apache.http.impl.cookie;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 
 import org.apache.http.HeaderElement;
 import org.apache.http.NameValuePair;
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
@@ -43,12 +45,29 @@ import org.apache.http.util.Args;
 /**
  * Cookie management functions shared by all specification.
  *
- *
  * @since 4.0
  */
- at NotThreadSafe // AbstractCookieSpec is not thread-safe
+ at ThreadSafe
 public abstract class CookieSpecBase extends AbstractCookieSpec {
 
+    public CookieSpecBase() {
+        super();
+    }
+
+    /**
+     * @since 4.4
+     */
+    protected CookieSpecBase(final HashMap<String, CookieAttributeHandler> map) {
+        super(map);
+    }
+
+    /**
+     * @since 4.4
+     */
+    protected CookieSpecBase(final CommonCookieAttributeHandler... handlers) {
+        super(handlers);
+    }
+
     protected static String getDefaultPath(final CookieOrigin origin) {
         String defaultPath = origin.getPath();
         int lastSlashIndex = defaultPath.lastIndexOf('/');
@@ -72,7 +91,7 @@ public abstract class CookieSpecBase extends AbstractCookieSpec {
         for (final HeaderElement headerelement : elems) {
             final String name = headerelement.getName();
             final String value = headerelement.getValue();
-            if (name == null || name.length() == 0) {
+            if (name == null || name.isEmpty()) {
                 throw new MalformedCookieException("Cookie name may not be empty");
             }
 
@@ -84,7 +103,7 @@ public abstract class CookieSpecBase extends AbstractCookieSpec {
             final NameValuePair[] attribs = headerelement.getParameters();
             for (int j = attribs.length - 1; j >= 0; j--) {
                 final NameValuePair attrib = attribs[j];
-                final String s = attrib.getName().toLowerCase(Locale.ENGLISH);
+                final String s = attrib.getName().toLowerCase(Locale.ROOT);
 
                 cookie.setAttribute(s, attrib.getValue());
 
@@ -98,6 +117,7 @@ public abstract class CookieSpecBase extends AbstractCookieSpec {
         return cookies;
     }
 
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -107,6 +127,7 @@ public abstract class CookieSpecBase extends AbstractCookieSpec {
         }
     }
 
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         Args.notNull(cookie, "Cookie");
         Args.notNull(origin, "Cookie origin");
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BestMatchSpec.java b/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpec.java
similarity index 64%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/BestMatchSpec.java
rename to httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpec.java
index 5e1f15e..cb43078 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BestMatchSpec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpec.java
@@ -32,7 +32,7 @@ import java.util.List;
 import org.apache.http.FormattedHeader;
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieSpec;
@@ -44,53 +44,62 @@ import org.apache.http.util.Args;
 import org.apache.http.util.CharArrayBuffer;
 
 /**
- * 'Meta' cookie specification that picks up a cookie policy based on
+ * Default cookie specification that picks up the bests matching cookie policy based on
  * the format of cookies sent with the HTTP response.
  *
- * @since 4.0
+ * @since 4.4
  */
- at NotThreadSafe // CookieSpec fields are @NotThreadSafe
-public class BestMatchSpec implements CookieSpec {
-
-    private final String[] datepatterns;
-    private final boolean oneHeader;
-
-    // Cached values of CookieSpec instances
-    private RFC2965Spec strict; // @NotThreadSafe
-    private RFC2109Spec obsoleteStrict; // @NotThreadSafe
-    private BrowserCompatSpec compat; // @NotThreadSafe
+ at ThreadSafe
+public class DefaultCookieSpec implements CookieSpec {
+
+    private final RFC2965Spec strict;
+    private final RFC2109Spec obsoleteStrict;
+    private final NetscapeDraftSpec netscapeDraft;
+
+    DefaultCookieSpec(
+            final RFC2965Spec strict,
+            final RFC2109Spec obsoleteStrict,
+            final NetscapeDraftSpec netscapeDraft) {
+        this.strict = strict;
+        this.obsoleteStrict = obsoleteStrict;
+        this.netscapeDraft = netscapeDraft;
+    }
 
-    public BestMatchSpec(final String[] datepatterns, final boolean oneHeader) {
+    public DefaultCookieSpec(
+            final String[] datepatterns,
+            final boolean oneHeader) {
         super();
-        this.datepatterns = datepatterns == null ? null : datepatterns.clone();
-        this.oneHeader = oneHeader;
+        this.strict = new RFC2965Spec(oneHeader,
+                new RFC2965VersionAttributeHandler(),
+                new BasicPathHandler(),
+                new RFC2965DomainAttributeHandler(),
+                new RFC2965PortAttributeHandler(),
+                new BasicMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new BasicCommentHandler(),
+                new RFC2965CommentUrlAttributeHandler(),
+                new RFC2965DiscardAttributeHandler());
+        this.obsoleteStrict = new RFC2109Spec(oneHeader,
+                new RFC2109VersionHandler(),
+                new BasicPathHandler(),
+                new RFC2109DomainHandler(),
+                new BasicMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new BasicCommentHandler());
+        this.netscapeDraft = new NetscapeDraftSpec(
+                new BasicDomainHandler(),
+                new BasicPathHandler(),
+                new BasicSecureHandler(),
+                new BasicCommentHandler(),
+                new BasicExpiresHandler(
+                        datepatterns != null ? datepatterns.clone() : new String[]{NetscapeDraftSpec.EXPIRES_PATTERN}));
     }
 
-    public BestMatchSpec() {
+    public DefaultCookieSpec() {
         this(null, false);
     }
 
-    private RFC2965Spec getStrict() {
-        if (this.strict == null) {
-             this.strict = new RFC2965Spec(this.datepatterns, this.oneHeader);
-        }
-        return strict;
-    }
-
-    private RFC2109Spec getObsoleteStrict() {
-        if (this.obsoleteStrict == null) {
-             this.obsoleteStrict = new RFC2109Spec(this.datepatterns, this.oneHeader);
-        }
-        return obsoleteStrict;
-    }
-
-    private BrowserCompatSpec getCompat() {
-        if (this.compat == null) {
-            this.compat = new BrowserCompatSpec(this.datepatterns);
-        }
-        return compat;
-    }
-
+    @Override
     public List<Cookie> parse(
             final Header header,
             final CookieOrigin origin) throws MalformedCookieException {
@@ -128,16 +137,17 @@ public class BestMatchSpec implements CookieSpec {
                 cursor = new ParserCursor(0, buffer.length());
             }
             helems = new HeaderElement[] { parser.parseHeader(buffer, cursor) };
-            return getCompat().parse(helems, origin);
+            return netscapeDraft.parse(helems, origin);
         } else {
             if (SM.SET_COOKIE2.equals(header.getName())) {
-                return getStrict().parse(helems, origin);
+                return strict.parse(helems, origin);
             } else {
-                return getObsoleteStrict().parse(helems, origin);
+                return obsoleteStrict.parse(helems, origin);
             }
         }
     }
 
+    @Override
     public void validate(
             final Cookie cookie,
             final CookieOrigin origin) throws MalformedCookieException {
@@ -145,29 +155,31 @@ public class BestMatchSpec implements CookieSpec {
         Args.notNull(origin, "Cookie origin");
         if (cookie.getVersion() > 0) {
             if (cookie instanceof SetCookie2) {
-                getStrict().validate(cookie, origin);
+                strict.validate(cookie, origin);
             } else {
-                getObsoleteStrict().validate(cookie, origin);
+                obsoleteStrict.validate(cookie, origin);
             }
         } else {
-            getCompat().validate(cookie, origin);
+            netscapeDraft.validate(cookie, origin);
         }
     }
 
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         Args.notNull(cookie, "Cookie");
         Args.notNull(origin, "Cookie origin");
         if (cookie.getVersion() > 0) {
             if (cookie instanceof SetCookie2) {
-                return getStrict().match(cookie, origin);
+                return strict.match(cookie, origin);
             } else {
-                return getObsoleteStrict().match(cookie, origin);
+                return obsoleteStrict.match(cookie, origin);
             }
         } else {
-            return getCompat().match(cookie, origin);
+            return netscapeDraft.match(cookie, origin);
         }
     }
 
+    @Override
     public List<Header> formatCookies(final List<Cookie> cookies) {
         Args.notNull(cookies, "List of cookies");
         int version = Integer.MAX_VALUE;
@@ -182,26 +194,28 @@ public class BestMatchSpec implements CookieSpec {
         }
         if (version > 0) {
             if (isSetCookie2) {
-                return getStrict().formatCookies(cookies);
+                return strict.formatCookies(cookies);
             } else {
-                return getObsoleteStrict().formatCookies(cookies);
+                return obsoleteStrict.formatCookies(cookies);
             }
         } else {
-            return getCompat().formatCookies(cookies);
+            return netscapeDraft.formatCookies(cookies);
         }
     }
 
+    @Override
     public int getVersion() {
-        return getStrict().getVersion();
+        return strict.getVersion();
     }
 
+    @Override
     public Header getVersionHeader() {
-        return getStrict().getVersionHeader();
+        return null;
     }
 
     @Override
     public String toString() {
-        return "best-match";
+        return "default";
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java b/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java
new file mode 100644
index 0000000..1fe8f03
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java
@@ -0,0 +1,134 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecProvider;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link org.apache.http.impl.cookie.DefaultCookieSpec}. The instance returned by this factory can
+ * be shared by multiple threads.
+ *
+ * @since 4.4
+ */
+ at Immutable
+public class DefaultCookieSpecProvider implements CookieSpecProvider {
+
+    public enum CompatibilityLevel {
+        DEFAULT,
+        IE_MEDIUM_SECURITY
+    }
+
+    private final CompatibilityLevel compatibilityLevel;
+    private final PublicSuffixMatcher publicSuffixMatcher;
+    private final String[] datepatterns;
+    private final boolean oneHeader;
+
+    private volatile CookieSpec cookieSpec;
+
+    public DefaultCookieSpecProvider(
+            final CompatibilityLevel compatibilityLevel,
+            final PublicSuffixMatcher publicSuffixMatcher,
+            final String[] datepatterns,
+            final boolean oneHeader) {
+        super();
+        this.compatibilityLevel = compatibilityLevel != null ? compatibilityLevel : CompatibilityLevel.DEFAULT;
+        this.publicSuffixMatcher = publicSuffixMatcher;
+        this.datepatterns = datepatterns;
+        this.oneHeader = oneHeader;
+    }
+
+    public DefaultCookieSpecProvider(
+            final CompatibilityLevel compatibilityLevel,
+            final PublicSuffixMatcher publicSuffixMatcher) {
+        this(compatibilityLevel, publicSuffixMatcher, null, false);
+    }
+
+    public DefaultCookieSpecProvider(final PublicSuffixMatcher publicSuffixMatcher) {
+        this(CompatibilityLevel.DEFAULT, publicSuffixMatcher, null, false);
+    }
+
+    public DefaultCookieSpecProvider() {
+        this(CompatibilityLevel.DEFAULT, null, null, false);
+    }
+
+    @Override
+    public CookieSpec create(final HttpContext context) {
+        if (cookieSpec == null) {
+            synchronized (this) {
+                if (cookieSpec == null) {
+                    final RFC2965Spec strict = new RFC2965Spec(this.oneHeader,
+                            new RFC2965VersionAttributeHandler(),
+                            new BasicPathHandler(),
+                            PublicSuffixDomainFilter.decorate(
+                                    new RFC2965DomainAttributeHandler(), this.publicSuffixMatcher),
+                            new RFC2965PortAttributeHandler(),
+                            new BasicMaxAgeHandler(),
+                            new BasicSecureHandler(),
+                            new BasicCommentHandler(),
+                            new RFC2965CommentUrlAttributeHandler(),
+                            new RFC2965DiscardAttributeHandler());
+                    final RFC2109Spec obsoleteStrict = new RFC2109Spec(this.oneHeader,
+                            new RFC2109VersionHandler(),
+                            new BasicPathHandler(),
+                            PublicSuffixDomainFilter.decorate(
+                                    new RFC2109DomainHandler(), this.publicSuffixMatcher),
+                            new BasicMaxAgeHandler(),
+                            new BasicSecureHandler(),
+                            new BasicCommentHandler());
+                    final NetscapeDraftSpec netscapeDraft = new NetscapeDraftSpec(
+                            PublicSuffixDomainFilter.decorate(
+                                    new BasicDomainHandler(), this.publicSuffixMatcher),
+                            this.compatibilityLevel == CompatibilityLevel.IE_MEDIUM_SECURITY ?
+                                    new BasicPathHandler() {
+                                        @Override
+                                        public void validate(
+                                                final Cookie cookie,
+                                                final CookieOrigin origin) throws MalformedCookieException {
+                                            // No validation
+                                        }
+                                    } : new BasicPathHandler(),
+                            new BasicSecureHandler(),
+                            new BasicCommentHandler(),
+                            new BasicExpiresHandler(this.datepatterns != null ? this.datepatterns.clone() :
+                                    new String[]{NetscapeDraftSpec.EXPIRES_PATTERN}));
+                    this.cookieSpec = new DefaultCookieSpec(strict, obsoleteStrict, netscapeDraft);
+                }
+            }
+        }
+        return this.cookieSpec;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpec.java b/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpec.java
index 8c401fe..a6cd4f2 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpec.java
@@ -31,7 +31,7 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.http.Header;
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.MalformedCookieException;
@@ -41,22 +41,26 @@ import org.apache.http.cookie.MalformedCookieException;
  *
  * @since 4.1
  */
- at NotThreadSafe // superclass is @NotThreadSafe
+ at ThreadSafe
 public class IgnoreSpec extends CookieSpecBase {
 
+    @Override
     public int getVersion() {
         return 0;
     }
 
+    @Override
     public List<Cookie> parse(final Header header, final CookieOrigin origin)
             throws MalformedCookieException {
         return Collections.emptyList();
     }
 
+    @Override
     public List<Header> formatCookies(final List<Cookie> cookies) {
         return Collections.emptyList();
     }
 
+    @Override
     public Header getVersionHeader() {
         return null;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecFactory.java b/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecProvider.java
similarity index 75%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecFactory.java
rename to httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecProvider.java
index 51c7951..97bedf6 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/IgnoreSpecProvider.java
@@ -29,30 +29,33 @@ package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
 import org.apache.http.cookie.CookieSpec;
-import org.apache.http.cookie.CookieSpecFactory;
 import org.apache.http.cookie.CookieSpecProvider;
-import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that ignores all cookies.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that ignores all cookies.
  *
- * @since 4.1
+ * @since 4.4
  */
 @Immutable
- at SuppressWarnings("deprecation")
-public class IgnoreSpecFactory implements CookieSpecFactory, CookieSpecProvider {
+public class IgnoreSpecProvider implements CookieSpecProvider {
 
-    public IgnoreSpecFactory() {
-        super();
-    }
+    private volatile CookieSpec cookieSpec;
 
-    public CookieSpec newInstance(final HttpParams params) {
-        return new IgnoreSpec();
+    public IgnoreSpecProvider() {
+        super();
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
-        return new IgnoreSpec();
+        if (cookieSpec == null) {
+            synchronized (this) {
+                if (cookieSpec == null) {
+                    this.cookieSpec = new IgnoreSpec();
+                }
+            }
+        }
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java
new file mode 100644
index 0000000..28e2b4f
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java
@@ -0,0 +1,220 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.util.Args;
+
+/**
+ *
+ * @since 4.4
+ */
+ at Immutable
+public class LaxExpiresHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
+
+    static final TimeZone UTC = TimeZone.getTimeZone("UTC");
+
+    private static final BitSet DELIMS;
+    static {
+        final BitSet bitSet = new BitSet();
+        bitSet.set(0x9);
+        for (int b = 0x20; b <= 0x2f; b++) {
+            bitSet.set(b);
+        }
+        for (int b = 0x3b; b <= 0x40; b++) {
+            bitSet.set(b);
+        }
+        for (int b = 0x5b; b <= 0x60; b++) {
+            bitSet.set(b);
+        }
+        for (int b = 0x7b; b <= 0x7e; b++) {
+            bitSet.set(b);
+        }
+        DELIMS = bitSet;
+    }
+    private static final Map<String, Integer> MONTHS;
+    static {
+        final ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>(12);
+        map.put("jan", Calendar.JANUARY);
+        map.put("feb", Calendar.FEBRUARY);
+        map.put("mar", Calendar.MARCH);
+        map.put("apr", Calendar.APRIL);
+        map.put("may", Calendar.MAY);
+        map.put("jun", Calendar.JUNE);
+        map.put("jul", Calendar.JULY);
+        map.put("aug", Calendar.AUGUST);
+        map.put("sep", Calendar.SEPTEMBER);
+        map.put("oct", Calendar.OCTOBER);
+        map.put("nov", Calendar.NOVEMBER);
+        map.put("dec", Calendar.DECEMBER);
+        MONTHS = map;
+    }
+
+    private final static Pattern TIME_PATTERN = Pattern.compile(
+            "^([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})([^0-9].*)?$");
+    private final static Pattern DAY_OF_MONTH_PATTERN = Pattern.compile(
+            "^([0-9]{1,2})([^0-9].*)?$");
+    private final static Pattern MONTH_PATTERN = Pattern.compile(
+            "^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)(.*)?$", Pattern.CASE_INSENSITIVE);
+    private final static Pattern YEAR_PATTERN = Pattern.compile(
+            "^([0-9]{2,4})([^0-9].*)?$");
+
+    public LaxExpiresHandler() {
+        super();
+    }
+
+    @Override
+    public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
+        Args.notNull(cookie, "Cookie");
+        final ParserCursor cursor = new ParserCursor(0, value.length());
+        final StringBuilder content = new StringBuilder();
+
+        int second = 0, minute = 0, hour = 0, day = 0, month = 0, year = 0;
+        boolean foundTime = false, foundDayOfMonth = false, foundMonth = false, foundYear = false;
+        try {
+            while (!cursor.atEnd()) {
+                skipDelims(value, cursor);
+                content.setLength(0);
+                copyContent(value, cursor, content);
+
+                if (content.length() == 0) {
+                    break;
+                }
+                if (!foundTime) {
+                    final Matcher matcher = TIME_PATTERN.matcher(content);
+                    if (matcher.matches()) {
+                        foundTime = true;
+                        hour = Integer.parseInt(matcher.group(1));
+                        minute = Integer.parseInt(matcher.group(2));
+                        second =Integer.parseInt(matcher.group(3));
+                        continue;
+                    }
+                }
+                if (!foundDayOfMonth) {
+                    final Matcher matcher = DAY_OF_MONTH_PATTERN.matcher(content);
+                    if (matcher.matches()) {
+                        foundDayOfMonth = true;
+                        day = Integer.parseInt(matcher.group(1));
+                        continue;
+                    }
+                }
+                if (!foundMonth) {
+                    final Matcher matcher = MONTH_PATTERN.matcher(content);
+                    if (matcher.matches()) {
+                        foundMonth = true;
+                        month = MONTHS.get(matcher.group(1).toLowerCase(Locale.ROOT));
+                        continue;
+                    }
+                }
+                if (!foundYear) {
+                    final Matcher matcher = YEAR_PATTERN.matcher(content);
+                    if (matcher.matches()) {
+                        foundYear = true;
+                        year = Integer.parseInt(matcher.group(1));
+                        continue;
+                    }
+                }
+            }
+        } catch (NumberFormatException ignore) {
+            throw new MalformedCookieException("Invalid 'expires' attribute: " + value);
+        }
+        if (!foundTime || !foundDayOfMonth || !foundMonth || !foundYear) {
+            throw new MalformedCookieException("Invalid 'expires' attribute: " + value);
+        }
+        if (year >= 70 && year <= 99) {
+            year = 1900 + year;
+        }
+        if (year >= 0 && year <= 69) {
+            year = 2000 + year;
+        }
+        if (day < 1 || day > 31 || year < 1601 || hour > 23 || minute > 59 || second > 59) {
+            throw new MalformedCookieException("Invalid 'expires' attribute: " + value);
+        }
+
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(UTC);
+        c.setTimeInMillis(0L);
+        c.set(Calendar.SECOND, second);
+        c.set(Calendar.MINUTE, minute);
+        c.set(Calendar.HOUR_OF_DAY, hour);
+        c.set(Calendar.DAY_OF_MONTH, day);
+        c.set(Calendar.MONTH, month);
+        c.set(Calendar.YEAR, year);
+        cookie.setExpiryDate(c.getTime());
+    }
+
+    private void skipDelims(final CharSequence buf, final ParserCursor cursor) {
+        int pos = cursor.getPos();
+        final int indexFrom = cursor.getPos();
+        final int indexTo = cursor.getUpperBound();
+        for (int i = indexFrom; i < indexTo; i++) {
+            final char current = buf.charAt(i);
+            if (DELIMS.get(current)) {
+                pos++;
+            } else {
+                break;
+            }
+        }
+        cursor.updatePos(pos);
+    }
+
+    private void copyContent(final CharSequence buf, final ParserCursor cursor, final StringBuilder dst) {
+        int pos = cursor.getPos();
+        final int indexFrom = cursor.getPos();
+        final int indexTo = cursor.getUpperBound();
+        for (int i = indexFrom; i < indexTo; i++) {
+            final char current = buf.charAt(i);
+            if (DELIMS.get(current)) {
+                break;
+            } else {
+                pos++;
+                dst.append(current);
+            }
+        }
+        cursor.updatePos(pos);
+    }
+
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.MAX_AGE_ATTR;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java
similarity index 58%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
copy to httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java
index df1161c..8615286 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java
@@ -27,41 +27,53 @@
 package org.apache.http.impl.cookie;
 
 import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
+import org.apache.http.util.TextUtils;
 
 /**
  *
- * @since 4.0
+ * @since 4.4
  */
 @Immutable
-public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler {
+public class LaxMaxAgeHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
-    public BasicMaxAgeHandler() {
+    private final static Pattern MAX_AGE_PATTERN = Pattern.compile("^\\-?[0-9]+$");
+
+    public LaxMaxAgeHandler() {
         super();
     }
 
-    public void parse(final SetCookie cookie, final String value)
-            throws MalformedCookieException {
+    @Override
+    public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
-        if (value == null) {
-            throw new MalformedCookieException("Missing value for max-age attribute");
-        }
-        final int age;
-        try {
-            age = Integer.parseInt(value);
-        } catch (final NumberFormatException e) {
-            throw new MalformedCookieException ("Invalid max-age attribute: "
-                    + value);
+        if (TextUtils.isBlank(value)) {
+            return;
         }
-        if (age < 0) {
-            throw new MalformedCookieException ("Negative max-age attribute: "
-                    + value);
+        final Matcher matcher = MAX_AGE_PATTERN.matcher(value);
+        if (matcher.matches()) {
+            final int age;
+            try {
+                age = Integer.parseInt(value);
+            } catch (final NumberFormatException e) {
+                return;
+            }
+            final Date expiryDate = age >= 0 ? new Date(System.currentTimeMillis() + age * 1000L) :
+                    new Date(Long.MIN_VALUE);
+            cookie.setExpiryDate(expiryDate);
         }
-        cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L));
+    }
+
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.MAX_AGE_ATTR;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java
index 26c3f0d..1f92cc0 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java
@@ -30,11 +30,14 @@ import java.util.Locale;
 import java.util.StringTokenizer;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
 import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
+import org.apache.http.util.TextUtils;
 
 /**
  *
@@ -48,12 +51,23 @@ public class NetscapeDomainHandler extends BasicDomainHandler {
     }
 
     @Override
+    public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
+        Args.notNull(cookie, "Cookie");
+        if (TextUtils.isBlank(value)) {
+            throw new MalformedCookieException("Blank or null value for domain attribute");
+        }
+        cookie.setDomain(value);
+    }
+
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
-        super.validate(cookie, origin);
-        // Perform Netscape Cookie draft specific validation
         final String host = origin.getHost();
         final String domain = cookie.getDomain();
+        if (!host.equals(domain) && !BasicDomainHandler.domainMatch(domain, host)) {
+            throw new CookieRestrictionViolationException(
+                    "Illegal domain attribute \"" + domain + "\". Domain of origin: \"" + host + "\"");
+        }
         if (host.contains(".")) {
             final int domainParts = new StringTokenizer(domain, ".").countTokens();
 
@@ -81,7 +95,7 @@ public class NetscapeDomainHandler extends BasicDomainHandler {
     * @return True if the specified domain is "special"
     */
    private static boolean isSpecialDomain(final String domain) {
-       final String ucDomain = domain.toUpperCase(Locale.ENGLISH);
+       final String ucDomain = domain.toUpperCase(Locale.ROOT);
        return ucDomain.endsWith(".COM")
                || ucDomain.endsWith(".EDU")
                || ucDomain.endsWith(".NET")
@@ -103,4 +117,9 @@ public class NetscapeDomainHandler extends BasicDomainHandler {
        return host.endsWith(domain);
    }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.DOMAIN_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java
index 2f3aecb..a6a40de 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.java
@@ -28,6 +28,7 @@
 package org.apache.http.impl.cookie;
 
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.List;
 
 import org.apache.http.HeaderElement;
@@ -37,7 +38,7 @@ import org.apache.http.annotation.Immutable;
 import org.apache.http.message.BasicHeaderElement;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.message.ParserCursor;
-import org.apache.http.protocol.HTTP;
+import org.apache.http.message.TokenParser;
 import org.apache.http.util.Args;
 import org.apache.http.util.CharArrayBuffer;
 
@@ -50,8 +51,18 @@ public class NetscapeDraftHeaderParser {
 
     public final static NetscapeDraftHeaderParser DEFAULT = new NetscapeDraftHeaderParser();
 
+    private final static char PARAM_DELIMITER                = ';';
+
+    // IMPORTANT!
+    // These private static variables must be treated as immutable and never exposed outside this class
+    private static final BitSet TOKEN_DELIMS = TokenParser.INIT_BITSET('=', PARAM_DELIMITER);
+    private static final BitSet VALUE_DELIMS = TokenParser.INIT_BITSET(PARAM_DELIMITER);
+
+    private final TokenParser tokenParser;
+
     public NetscapeDraftHeaderParser() {
         super();
+        this.tokenParser = TokenParser.INSTANCE;
     }
 
     public HeaderElement parseHeader(
@@ -72,66 +83,19 @@ public class NetscapeDraftHeaderParser {
 
     private NameValuePair parseNameValuePair(
             final CharArrayBuffer buffer, final ParserCursor cursor) {
-        boolean terminated = false;
-
-        int pos = cursor.getPos();
-        final int indexFrom = cursor.getPos();
-        final int indexTo = cursor.getUpperBound();
-
-        // Find name
-        String name = null;
-        while (pos < indexTo) {
-            final char ch = buffer.charAt(pos);
-            if (ch == '=') {
-                break;
-            }
-            if (ch == ';') {
-                terminated = true;
-                break;
-            }
-            pos++;
-        }
-
-        if (pos == indexTo) {
-            terminated = true;
-            name = buffer.substringTrimmed(indexFrom, indexTo);
-        } else {
-            name = buffer.substringTrimmed(indexFrom, pos);
-            pos++;
-        }
-
-        if (terminated) {
-            cursor.updatePos(pos);
+        final String name = tokenParser.parseToken(buffer, cursor, TOKEN_DELIMS);
+        if (cursor.atEnd()) {
             return new BasicNameValuePair(name, null);
         }
-
-        // Find value
-        String value = null;
-        int i1 = pos;
-
-        while (pos < indexTo) {
-            final char ch = buffer.charAt(pos);
-            if (ch == ';') {
-                terminated = true;
-                break;
-            }
-            pos++;
-        }
-
-        int i2 = pos;
-        // Trim leading white spaces
-        while (i1 < i2 && (HTTP.isWhitespace(buffer.charAt(i1)))) {
-            i1++;
-        }
-        // Trim trailing white spaces
-        while ((i2 > i1) && (HTTP.isWhitespace(buffer.charAt(i2 - 1)))) {
-            i2--;
+        final int delim = buffer.charAt(cursor.getPos());
+        cursor.updatePos(cursor.getPos() + 1);
+        if (delim != '=') {
+            return new BasicNameValuePair(name, null);
         }
-        value = buffer.substring(i1, i2);
-        if (terminated) {
-            pos++;
+        final String value = tokenParser.parseToken(buffer, cursor, VALUE_DELIMS);
+        if (!cursor.atEnd()) {
+            cursor.updatePos(cursor.getPos() + 1);
         }
-        cursor.updatePos(pos);
         return new BasicNameValuePair(name, value);
     }
 
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpec.java b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpec.java
index 2778d21..caedd83 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpec.java
@@ -33,8 +33,9 @@ import java.util.List;
 import org.apache.http.FormattedHeader;
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
-import org.apache.http.annotation.NotThreadSafe;
-import org.apache.http.cookie.ClientCookie;
+import org.apache.http.annotation.Obsolete;
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.MalformedCookieException;
@@ -49,40 +50,38 @@ import org.apache.http.util.CharArrayBuffer;
  * the original draft specification published by Netscape Communications.
  * It should be avoided unless absolutely necessary for compatibility with
  * legacy applications.
+ * <p>
+ * Rendered obsolete by {@link org.apache.http.impl.cookie.RFC6265LaxSpec}.
  *
  * @since 4.0
+ * @see org.apache.http.impl.cookie.RFC6265LaxSpec
  */
- at NotThreadSafe // superclass is @NotThreadSafe
+ at Obsolete
+ at ThreadSafe
 public class NetscapeDraftSpec extends CookieSpecBase {
 
     protected static final String EXPIRES_PATTERN = "EEE, dd-MMM-yy HH:mm:ss z";
 
-    private final String[] datepatterns;
-
     /** Default constructor */
     public NetscapeDraftSpec(final String[] datepatterns) {
-        super();
-        if (datepatterns != null) {
-            this.datepatterns = datepatterns.clone();
-        } else {
-            this.datepatterns = new String[] { EXPIRES_PATTERN };
-        }
-        registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
-        registerAttribHandler(ClientCookie.DOMAIN_ATTR, new NetscapeDomainHandler());
-        registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
-        registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
-        registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
-        registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
-                this.datepatterns));
+        super(new BasicPathHandler(),
+                new NetscapeDomainHandler(),
+                new BasicSecureHandler(),
+                new BasicCommentHandler(),
+                new BasicExpiresHandler(
+                        datepatterns != null ? datepatterns.clone() : new String[]{EXPIRES_PATTERN}));
+    }
+
+    NetscapeDraftSpec(final CommonCookieAttributeHandler... handlers) {
+        super(handlers);
     }
 
-    /** Default constructor */
     public NetscapeDraftSpec() {
-        this(null);
+        this((String[]) null);
     }
 
     /**
-      * Parses the Set-Cookie value into an array of <tt>Cookie</tt>s.
+      * Parses the Set-Cookie value into an array of {@code Cookie}s.
       *
       * <p>Syntax of the Set-Cookie HTTP Response Header:</p>
       *
@@ -95,16 +94,17 @@ public class NetscapeDraftSpec extends CookieSpecBase {
       * </PRE>
       *
       * <p>Please note that the Netscape draft specification does not fully conform to the HTTP
-      * header format. Comma character if present in <code>Set-Cookie</code> will not be treated
+      * header format. Comma character if present in {@code Set-Cookie} will not be treated
       * as a header element separator</p>
       *
       * @see <a href="http://web.archive.org/web/20020803110822/http://wp.netscape.com/newsref/std/cookie_spec.html">
       *  The Cookie Spec.</a>
       *
-      * @param header the <tt>Set-Cookie</tt> received from the server
-      * @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie value
+      * @param header the {@code Set-Cookie} received from the server
+      * @return an array of {@code Cookie}s parsed from the Set-Cookie value
       * @throws MalformedCookieException if an exception occurs during parsing
       */
+    @Override
     public List<Cookie> parse(final Header header, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(header, "Header");
@@ -133,6 +133,7 @@ public class NetscapeDraftSpec extends CookieSpecBase {
         return parse(new HeaderElement[] { parser.parseHeader(buffer, cursor) }, origin);
     }
 
+    @Override
     public List<Header> formatCookies(final List<Cookie> cookies) {
         Args.notEmpty(cookies, "List of cookies");
         final CharArrayBuffer buffer = new CharArrayBuffer(20 * cookies.size());
@@ -155,10 +156,12 @@ public class NetscapeDraftSpec extends CookieSpecBase {
         return headers;
     }
 
+    @Override
     public int getVersion() {
         return 0;
     }
 
+    @Override
     public Header getVersionHeader() {
         return null;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecProvider.java
similarity index 59%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
rename to httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecProvider.java
index 0d91d7e..f4832f7 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDraftSpecProvider.java
@@ -27,55 +27,49 @@
 
 package org.apache.http.impl.cookie;
 
-import java.util.Collection;
-
 import org.apache.http.annotation.Immutable;
+import org.apache.http.annotation.Obsolete;
 import org.apache.http.cookie.CookieSpec;
-import org.apache.http.cookie.CookieSpecFactory;
 import org.apache.http.cookie.CookieSpecProvider;
-import org.apache.http.cookie.params.CookieSpecPNames;
-import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that creates and initializes
- * {@link NetscapeDraftSpec} instances.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link NetscapeDraftSpec}. The instance returned by this factory
+ * can be shared by multiple threads.
+ * <p>
+ * Rendered obsolete by {@link org.apache.http.impl.cookie.RFC6265CookieSpecProvider}
  *
- * @since 4.0
+ * @since 4.4
+ * @see org.apache.http.impl.cookie.RFC6265CookieSpecProvider
  */
+ at Obsolete
 @Immutable
- at SuppressWarnings("deprecation")
-public class NetscapeDraftSpecFactory implements CookieSpecFactory, CookieSpecProvider {
+public class NetscapeDraftSpecProvider implements CookieSpecProvider {
 
     private final String[] datepatterns;
 
-    public NetscapeDraftSpecFactory(final String[] datepatterns) {
+    private volatile CookieSpec cookieSpec;
+
+    public NetscapeDraftSpecProvider(final String[] datepatterns) {
         super();
         this.datepatterns = datepatterns;
     }
 
-    public NetscapeDraftSpecFactory() {
+    public NetscapeDraftSpecProvider() {
         this(null);
     }
 
-    public CookieSpec newInstance(final HttpParams params) {
-        if (params != null) {
-
-            String[] patterns = null;
-            final Collection<?> param = (Collection<?>) params.getParameter(
-                    CookieSpecPNames.DATE_PATTERNS);
-            if (param != null) {
-                patterns = new String[param.size()];
-                patterns = param.toArray(patterns);
+    @Override
+    public CookieSpec create(final HttpContext context) {
+        if (cookieSpec == null) {
+            synchronized (this) {
+                if (cookieSpec == null) {
+                    this.cookieSpec = new NetscapeDraftSpec(this.datepatterns);
+                }
             }
-            return new NetscapeDraftSpec(patterns);
-        } else {
-            return new NetscapeDraftSpec();
         }
-    }
-
-    public CookieSpec create(final HttpContext context) {
-        return new NetscapeDraftSpec(this.datepatterns);
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixDomainFilter.java b/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixDomainFilter.java
new file mode 100644
index 0000000..3e44ae8
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixDomainFilter.java
@@ -0,0 +1,104 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.cookie;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.util.PublicSuffixList;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+import org.apache.http.util.Args;
+
+/**
+ * Wraps a {@link org.apache.http.cookie.CookieAttributeHandler} and leverages its match method
+ * to never match a suffix from a black list. May be used to provide additional security for
+ * cross-site attack types by preventing cookies from apparent domains that are not publicly
+ * available.
+ *
+ *  @see org.apache.http.conn.util.PublicSuffixList
+ *  @see org.apache.http.conn.util.PublicSuffixMatcher
+ *
+ * @since 4.4
+ */
+ at Immutable // dependencies are expected to be immutable or thread-safe
+public class PublicSuffixDomainFilter implements CommonCookieAttributeHandler {
+
+    private final CommonCookieAttributeHandler handler;
+    private final PublicSuffixMatcher publicSuffixMatcher;
+
+    public PublicSuffixDomainFilter(
+            final CommonCookieAttributeHandler handler, final PublicSuffixMatcher publicSuffixMatcher) {
+        this.handler = Args.notNull(handler, "Cookie handler");
+        this.publicSuffixMatcher = Args.notNull(publicSuffixMatcher, "Public suffix matcher");
+    }
+
+    public PublicSuffixDomainFilter(
+            final CommonCookieAttributeHandler handler, final PublicSuffixList suffixList) {
+        Args.notNull(handler, "Cookie handler");
+        Args.notNull(suffixList, "Public suffix list");
+        this.handler = handler;
+        this.publicSuffixMatcher = new PublicSuffixMatcher(suffixList.getRules(), suffixList.getExceptions());
+    }
+
+    /**
+     * Never matches if the cookie's domain is from the blacklist.
+     */
+    @Override
+    public boolean match(final Cookie cookie, final CookieOrigin origin) {
+        final String domain = cookie.getDomain();
+        if (!domain.equalsIgnoreCase("localhost") && publicSuffixMatcher.matches(domain)) {
+            return false;
+        } else {
+            return handler.match(cookie, origin);
+        }
+    }
+
+    @Override
+    public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
+        handler.parse(cookie, value);
+    }
+
+    @Override
+    public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
+        handler.validate(cookie, origin);
+    }
+
+    @Override
+    public String getAttributeName() {
+        return handler.getAttributeName();
+    }
+
+    public static CommonCookieAttributeHandler decorate(
+            final CommonCookieAttributeHandler handler, final PublicSuffixMatcher publicSuffixMatcher) {
+        Args.notNull(handler, "Cookie attribute handler");
+        return publicSuffixMatcher != null ? new PublicSuffixDomainFilter(handler, publicSuffixMatcher) : handler;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109DomainHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109DomainHandler.java
index 6dd6e3e..fdbeb15 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109DomainHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109DomainHandler.java
@@ -29,8 +29,9 @@ package org.apache.http.impl.cookie;
 import java.util.Locale;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
 import org.apache.http.cookie.MalformedCookieException;
@@ -42,24 +43,26 @@ import org.apache.http.util.Args;
  * @since 4.0
  */
 @Immutable
-public class RFC2109DomainHandler implements CookieAttributeHandler {
+public class RFC2109DomainHandler implements CommonCookieAttributeHandler {
 
     public RFC2109DomainHandler() {
         super();
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         if (value == null) {
             throw new MalformedCookieException("Missing value for domain attribute");
         }
-        if (value.trim().length() == 0) {
+        if (value.trim().isEmpty()) {
             throw new MalformedCookieException("Blank value for domain attribute");
         }
         cookie.setDomain(value);
     }
 
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -90,7 +93,7 @@ public class RFC2109DomainHandler implements CookieAttributeHandler {
                     + domain
                     + "\" violates RFC 2109: domain must contain an embedded dot");
             }
-            host = host.toLowerCase(Locale.ENGLISH);
+            host = host.toLowerCase(Locale.ROOT);
             if (!host.endsWith(domain)) {
                 throw new CookieRestrictionViolationException(
                     "Illegal domain attribute \"" + domain
@@ -106,6 +109,7 @@ public class RFC2109DomainHandler implements CookieAttributeHandler {
         }
     }
 
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         Args.notNull(cookie, "Cookie");
         Args.notNull(origin, "Cookie origin");
@@ -117,4 +121,9 @@ public class RFC2109DomainHandler implements CookieAttributeHandler {
         return host.equals(domain) || (domain.startsWith(".") && host.endsWith(domain));
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.DOMAIN_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
index 58d25a0..1b4e783 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
@@ -33,9 +33,11 @@ import java.util.List;
 
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.annotation.Obsolete;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.client.utils.DateUtils;
 import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookiePathComparator;
@@ -48,44 +50,35 @@ import org.apache.http.util.CharArrayBuffer;
 
 /**
  * RFC 2109 compliant {@link org.apache.http.cookie.CookieSpec} implementation.
- * This is an older version of the official HTTP state management specification
- * superseded by RFC 2965.
- *
- * @see RFC2965Spec
+ * <p>
+ * Rendered obsolete by {@link org.apache.http.impl.cookie.RFC6265StrictSpec}.
  *
  * @since 4.0
+ * @see org.apache.http.impl.cookie.RFC6265StrictSpec
  */
- at NotThreadSafe // superclass is @NotThreadSafe
+ at Obsolete
+ at ThreadSafe
 public class RFC2109Spec extends CookieSpecBase {
 
-    private final static CookiePathComparator PATH_COMPARATOR = new CookiePathComparator();
-
-    private final static String[] DATE_PATTERNS = {
+    final static String[] DATE_PATTERNS = {
         DateUtils.PATTERN_RFC1123,
         DateUtils.PATTERN_RFC1036,
         DateUtils.PATTERN_ASCTIME
     };
 
-    private final String[] datepatterns;
     private final boolean oneHeader;
 
     /** Default constructor */
     public RFC2109Spec(final String[] datepatterns, final boolean oneHeader) {
-        super();
-        if (datepatterns != null) {
-            this.datepatterns = datepatterns.clone();
-        } else {
-            this.datepatterns = DATE_PATTERNS;
-        }
+        super(new RFC2109VersionHandler(),
+                new BasicPathHandler(),
+                new RFC2109DomainHandler(),
+                new BasicMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new BasicCommentHandler(),
+                new BasicExpiresHandler(
+                        datepatterns != null ? datepatterns.clone() : DATE_PATTERNS));
         this.oneHeader = oneHeader;
-        registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2109VersionHandler());
-        registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
-        registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2109DomainHandler());
-        registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
-        registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
-        registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
-        registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
-                this.datepatterns));
     }
 
     /** Default constructor */
@@ -93,6 +86,13 @@ public class RFC2109Spec extends CookieSpecBase {
         this(null, false);
     }
 
+    protected RFC2109Spec(final boolean oneHeader,
+                          final CommonCookieAttributeHandler... handlers) {
+        super(handlers);
+        this.oneHeader = oneHeader;
+    }
+
+    @Override
     public List<Cookie> parse(final Header header, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(header, "Header");
@@ -119,13 +119,14 @@ public class RFC2109Spec extends CookieSpecBase {
         super.validate(cookie, origin);
     }
 
+    @Override
     public List<Header> formatCookies(final List<Cookie> cookies) {
         Args.notEmpty(cookies, "List of cookies");
         List<Cookie> cookieList;
         if (cookies.size() > 1) {
             // Create a mutable copy and sort the copy.
             cookieList = new ArrayList<Cookie>(cookies);
-            Collections.sort(cookieList, PATH_COMPARATOR);
+            Collections.sort(cookieList, CookiePathComparator.INSTANCE);
         } else {
             cookieList = cookies;
         }
@@ -175,7 +176,7 @@ public class RFC2109Spec extends CookieSpecBase {
     }
 
     /**
-     * Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
+     * Return a name/value string suitable for sending in a {@code "Cookie"}
      * header as defined in RFC 2109 for backward compatibility with cookie
      * version 0
      * @param buffer The char array buffer to use for output
@@ -199,7 +200,7 @@ public class RFC2109Spec extends CookieSpecBase {
     }
 
     /**
-     * Return a string suitable for sending in a <tt>"Cookie"</tt> header
+     * Return a string suitable for sending in a {@code "Cookie"} header
      * as defined in RFC 2109 for backward compatibility with cookie version 0
      * @param buffer The char array buffer to use for output
      * @param cookie The {@link Cookie} to be formatted as string
@@ -224,10 +225,12 @@ public class RFC2109Spec extends CookieSpecBase {
         }
     }
 
+    @Override
     public int getVersion() {
         return 1;
     }
 
+    @Override
     public Header getVersionHeader() {
         return null;
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109SpecProvider.java
similarity index 50%
rename from httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java
rename to httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109SpecProvider.java
index 70e42d9..c7f9724 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109SpecProvider.java
@@ -27,60 +27,63 @@
 
 package org.apache.http.impl.cookie;
 
-import java.util.Collection;
-
 import org.apache.http.annotation.Immutable;
+import org.apache.http.annotation.Obsolete;
+import org.apache.http.conn.util.PublicSuffixMatcher;
 import org.apache.http.cookie.CookieSpec;
-import org.apache.http.cookie.CookieSpecFactory;
 import org.apache.http.cookie.CookieSpecProvider;
-import org.apache.http.cookie.params.CookieSpecPNames;
-import org.apache.http.params.HttpParams;
 import org.apache.http.protocol.HttpContext;
 
 /**
- * {@link CookieSpecProvider} implementation that creates and initializes
- * {@link RFC2965Spec} instances.
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link RFC2109Spec}. The instance returned by this factory
+ * can be shared by multiple threads.
+ * <p>
+ * Rendered obsolete by {@link org.apache.http.impl.cookie.RFC6265CookieSpecProvider}
  *
- * @since 4.0
+ * @since 4.4
+ * @see org.apache.http.impl.cookie.RFC6265CookieSpecProvider
  */
+ at Obsolete
 @Immutable
- at SuppressWarnings("deprecation")
-public class RFC2965SpecFactory implements CookieSpecFactory, CookieSpecProvider {
+public class RFC2109SpecProvider implements CookieSpecProvider {
 
-    private final String[] datepatterns;
+    private final PublicSuffixMatcher publicSuffixMatcher;
     private final boolean oneHeader;
 
-    public RFC2965SpecFactory(final String[] datepatterns, final boolean oneHeader) {
+    private volatile CookieSpec cookieSpec;
+
+    public RFC2109SpecProvider(final PublicSuffixMatcher publicSuffixMatcher, final boolean oneHeader) {
         super();
-        this.datepatterns = datepatterns;
         this.oneHeader = oneHeader;
+        this.publicSuffixMatcher = publicSuffixMatcher;
     }
 
-    public RFC2965SpecFactory() {
-        this(null, false);
+    public RFC2109SpecProvider(final PublicSuffixMatcher publicSuffixMatcher) {
+        this(publicSuffixMatcher, false);
     }
 
-    public CookieSpec newInstance(final HttpParams params) {
-        if (params != null) {
-
-            String[] patterns = null;
-            final Collection<?> param = (Collection<?>) params.getParameter(
-                    CookieSpecPNames.DATE_PATTERNS);
-            if (param != null) {
-                patterns = new String[param.size()];
-                patterns = param.toArray(patterns);
-            }
-            final boolean singleHeader = params.getBooleanParameter(
-                    CookieSpecPNames.SINGLE_COOKIE_HEADER, false);
-
-            return new RFC2965Spec(patterns, singleHeader);
-        } else {
-            return new RFC2965Spec();
-        }
+    public RFC2109SpecProvider() {
+        this(null, false);
     }
 
+    @Override
     public CookieSpec create(final HttpContext context) {
-        return new RFC2965Spec(this.datepatterns, this.oneHeader);
+        if (cookieSpec == null) {
+            synchronized (this) {
+                if (cookieSpec == null) {
+                    this.cookieSpec = new RFC2109Spec(this.oneHeader,
+                            new RFC2109VersionHandler(),
+                            new BasicPathHandler(),
+                            PublicSuffixDomainFilter.decorate(
+                                    new RFC2109DomainHandler(), this.publicSuffixMatcher),
+                            new BasicMaxAgeHandler(),
+                            new BasicSecureHandler(),
+                            new BasicCommentHandler());
+                }
+            }
+        }
+        return this.cookieSpec;
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109VersionHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109VersionHandler.java
index 99a51f9..a342e85 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109VersionHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109VersionHandler.java
@@ -27,6 +27,8 @@
 package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
@@ -39,19 +41,20 @@ import org.apache.http.util.Args;
  * @since 4.0
  */
 @Immutable
-public class RFC2109VersionHandler extends AbstractCookieAttributeHandler {
+public class RFC2109VersionHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
     public RFC2109VersionHandler() {
         super();
     }
 
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         if (value == null) {
             throw new MalformedCookieException("Missing value for version attribute");
         }
-        if (value.trim().length() == 0) {
+        if (value.trim().isEmpty()) {
             throw new MalformedCookieException("Blank value for version attribute");
         }
         try {
@@ -71,4 +74,9 @@ public class RFC2109VersionHandler extends AbstractCookieAttributeHandler {
         }
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.VERSION_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java
index 2d4feec..dd739bc 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.java
@@ -28,25 +28,27 @@
 package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.cookie.SetCookie2;
 
 /**
- * <tt>"CommentURL"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ * {@code "CommentURL"} cookie attribute handler for RFC 2965 cookie spec.
  *
  * @since 4.0
  */
 @Immutable
-public class RFC2965CommentUrlAttributeHandler implements CookieAttributeHandler {
+public class RFC2965CommentUrlAttributeHandler implements CommonCookieAttributeHandler {
 
       public RFC2965CommentUrlAttributeHandler() {
           super();
       }
 
+      @Override
       public void parse(final SetCookie cookie, final String commenturl)
               throws MalformedCookieException {
           if (cookie instanceof SetCookie2) {
@@ -55,12 +57,19 @@ public class RFC2965CommentUrlAttributeHandler implements CookieAttributeHandler
           }
       }
 
+      @Override
       public void validate(final Cookie cookie, final CookieOrigin origin)
               throws MalformedCookieException {
       }
 
+      @Override
       public boolean match(final Cookie cookie, final CookieOrigin origin) {
           return true;
       }
 
-  }
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.COMMENTURL_ATTR;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java
index b3c58de..62d1f45 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.java
@@ -28,25 +28,27 @@
 package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.MalformedCookieException;
 import org.apache.http.cookie.SetCookie;
 import org.apache.http.cookie.SetCookie2;
 
 /**
- * <tt>"Discard"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ * {@code "Discard"} cookie attribute handler for RFC 2965 cookie spec.
  *
  * @since 4.0
  */
 @Immutable
-public class RFC2965DiscardAttributeHandler implements CookieAttributeHandler {
+public class RFC2965DiscardAttributeHandler implements CommonCookieAttributeHandler {
 
       public RFC2965DiscardAttributeHandler() {
           super();
       }
 
+      @Override
       public void parse(final SetCookie cookie, final String commenturl)
               throws MalformedCookieException {
           if (cookie instanceof SetCookie2) {
@@ -55,12 +57,19 @@ public class RFC2965DiscardAttributeHandler implements CookieAttributeHandler {
           }
       }
 
+      @Override
       public void validate(final Cookie cookie, final CookieOrigin origin)
               throws MalformedCookieException {
       }
 
+      @Override
       public boolean match(final Cookie cookie, final CookieOrigin origin) {
           return true;
       }
 
-  }
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.DISCARD_ATTR;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java
index b8d3fbc..42e790e 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java
@@ -31,8 +31,8 @@ import java.util.Locale;
 
 import org.apache.http.annotation.Immutable;
 import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
 import org.apache.http.cookie.MalformedCookieException;
@@ -40,13 +40,13 @@ import org.apache.http.cookie.SetCookie;
 import org.apache.http.util.Args;
 
 /**
- * <tt>"Domain"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ * {@code "Domain"} cookie attribute handler for RFC 2965 cookie spec.
  *
  *
  * @since 3.1
  */
 @Immutable
-public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
+public class RFC2965DomainAttributeHandler implements CommonCookieAttributeHandler {
 
     public RFC2965DomainAttributeHandler() {
         super();
@@ -55,6 +55,7 @@ public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
     /**
      * Parse cookie domain attribute.
      */
+    @Override
     public void parse(
             final SetCookie cookie, final String domain) throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -62,12 +63,12 @@ public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
             throw new MalformedCookieException(
                     "Missing value for domain attribute");
         }
-        if (domain.trim().length() == 0) {
+        if (domain.trim().isEmpty()) {
             throw new MalformedCookieException(
                     "Blank value for domain attribute");
         }
         String s = domain;
-        s = s.toLowerCase(Locale.ENGLISH);
+        s = s.toLowerCase(Locale.ROOT);
         if (!domain.startsWith(".")) {
             // Per RFC 2965 section 3.2.2
             // "... If an explicitly specified value does not start with
@@ -83,11 +84,12 @@ public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
      * Performs domain-match as defined by the RFC2965.
      * <p>
      * Host A's name domain-matches host B's if
+     * </p>
      * <ol>
-     *   <ul>their host name strings string-compare equal; or</ul>
-     *   <ul>A is a HDN string and has the form NB, where N is a non-empty
+     *   <li>their host name strings string-compare equal; or</li>
+     *   <li>A is a HDN string and has the form NB, where N is a non-empty
      *       name string, B has the form .B', and B' is a HDN string.  (So,
-     *       x.y.com domain-matches .Y.com but not Y.com.)</ul>
+     *       x.y.com domain-matches .Y.com but not Y.com.)</li>
      * </ol>
      *
      * @param host host name where cookie is received from or being sent to.
@@ -104,16 +106,17 @@ public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
     /**
      * Validate cookie domain attribute.
      */
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         Args.notNull(origin, "Cookie origin");
-        final String host = origin.getHost().toLowerCase(Locale.ENGLISH);
+        final String host = origin.getHost().toLowerCase(Locale.ROOT);
         if (cookie.getDomain() == null) {
             throw new CookieRestrictionViolationException("Invalid cookie state: " +
                                                "domain not specified");
         }
-        final String cookieDomain = cookie.getDomain().toLowerCase(Locale.ENGLISH);
+        final String cookieDomain = cookie.getDomain().toLowerCase(Locale.ROOT);
 
         if (cookie instanceof ClientCookie
                 && ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
@@ -165,10 +168,11 @@ public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
     /**
      * Match cookie domain attribute.
      */
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         Args.notNull(cookie, "Cookie");
         Args.notNull(origin, "Cookie origin");
-        final String host = origin.getHost().toLowerCase(Locale.ENGLISH);
+        final String host = origin.getHost().toLowerCase(Locale.ROOT);
         final String cookieDomain = cookie.getDomain();
 
         // The effective host name MUST domain-match the Domain
@@ -182,4 +186,9 @@ public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
         return effectiveHostWithoutDomain.indexOf('.') == -1;
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.DOMAIN_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
index 4632305..004f254 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
@@ -31,8 +31,8 @@ import java.util.StringTokenizer;
 
 import org.apache.http.annotation.Immutable;
 import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
 import org.apache.http.cookie.MalformedCookieException;
@@ -41,12 +41,12 @@ import org.apache.http.cookie.SetCookie2;
 import org.apache.http.util.Args;
 
 /**
- * <tt>"Port"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ * {@code "Port"} cookie attribute handler for RFC 2965 cookie spec.
  *
  * @since 4.0
  */
 @Immutable
-public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
+public class RFC2965PortAttributeHandler implements CommonCookieAttributeHandler {
 
     public RFC2965PortAttributeHandler() {
         super();
@@ -82,13 +82,13 @@ public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
     }
 
     /**
-     * Returns <tt>true</tt> if the given port exists in the given
+     * Returns {@code true} if the given port exists in the given
      * ports list.
      *
      * @param port port of host where cookie was received from or being sent to.
      * @param ports port list
-     * @return true returns <tt>true</tt> if the given port exists in
-     *         the given ports list; <tt>false</tt> otherwise.
+     * @return true returns {@code true} if the given port exists in
+     *         the given ports list; {@code false} otherwise.
      */
     private static boolean portMatch(final int port, final int[] ports) {
         boolean portInList = false;
@@ -104,12 +104,13 @@ public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
     /**
      * Parse cookie port attribute.
      */
+    @Override
     public void parse(final SetCookie cookie, final String portValue)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
         if (cookie instanceof SetCookie2) {
             final SetCookie2 cookie2 = (SetCookie2) cookie;
-            if (portValue != null && portValue.trim().length() > 0) {
+            if (portValue != null && !portValue.trim().isEmpty()) {
                 final int[] ports = parsePortAttribute(portValue);
                 cookie2.setPorts(ports);
             }
@@ -120,6 +121,7 @@ public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
      * Validate cookie port attribute. If the Port attribute was specified
      * in header, the request port must be in cookie's port list.
      */
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -140,6 +142,7 @@ public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
      * in header, the cookie can be sent to any port. Otherwise, the request port
      * must be in the cookie's port list.
      */
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         Args.notNull(cookie, "Cookie");
         Args.notNull(origin, "Cookie origin");
@@ -157,4 +160,9 @@ public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
         return true;
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.PORT_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java
index a341ff3..ca836c1 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java
@@ -35,8 +35,10 @@ import java.util.Map;
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
 import org.apache.http.NameValuePair;
-import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.annotation.Obsolete;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
@@ -48,10 +50,14 @@ import org.apache.http.util.CharArrayBuffer;
 
 /**
  * RFC 2965 compliant {@link org.apache.http.cookie.CookieSpec} implementation.
+ * <p>
+ * Rendered obsolete by {@link org.apache.http.impl.cookie.RFC6265StrictSpec}.
  *
  * @since 4.0
+ * @see org.apache.http.impl.cookie.RFC6265StrictSpec
  */
- at NotThreadSafe // superclass is @NotThreadSafe
+ at Obsolete
+ at ThreadSafe
 public class RFC2965Spec extends RFC2109Spec {
 
     /**
@@ -63,12 +69,23 @@ public class RFC2965Spec extends RFC2109Spec {
     }
 
     public RFC2965Spec(final String[] datepatterns, final boolean oneHeader) {
-        super(datepatterns, oneHeader);
-        registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2965DomainAttributeHandler());
-        registerAttribHandler(ClientCookie.PORT_ATTR, new RFC2965PortAttributeHandler());
-        registerAttribHandler(ClientCookie.COMMENTURL_ATTR, new RFC2965CommentUrlAttributeHandler());
-        registerAttribHandler(ClientCookie.DISCARD_ATTR, new RFC2965DiscardAttributeHandler());
-        registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2965VersionAttributeHandler());
+        super(oneHeader,
+                new RFC2965VersionAttributeHandler(),
+                new BasicPathHandler(),
+                new RFC2965DomainAttributeHandler(),
+                new RFC2965PortAttributeHandler(),
+                new BasicMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new BasicCommentHandler(),
+                new BasicExpiresHandler(
+                        datepatterns != null ? datepatterns.clone() : DATE_PATTERNS),
+                new RFC2965CommentUrlAttributeHandler(),
+                new RFC2965DiscardAttributeHandler());
+    }
+
+    RFC2965Spec(final boolean oneHeader,
+                final CommonCookieAttributeHandler... handlers) {
+        super(oneHeader, handlers);
     }
 
     @Override
@@ -99,7 +116,7 @@ public class RFC2965Spec extends RFC2109Spec {
         for (final HeaderElement headerelement : elems) {
             final String name = headerelement.getName();
             final String value = headerelement.getValue();
-            if (name == null || name.length() == 0) {
+            if (name == null || name.isEmpty()) {
                 throw new MalformedCookieException("Cookie name may not be empty");
             }
 
@@ -116,11 +133,11 @@ public class RFC2965Spec extends RFC2109Spec {
                     new HashMap<String, NameValuePair>(attribs.length);
             for (int j = attribs.length - 1; j >= 0; j--) {
                 final NameValuePair param = attribs[j];
-                attribmap.put(param.getName().toLowerCase(Locale.ENGLISH), param);
+                attribmap.put(param.getName().toLowerCase(Locale.ROOT), param);
             }
             for (final Map.Entry<String, NameValuePair> entry : attribmap.entrySet()) {
                 final NameValuePair attrib = entry.getValue();
-                final String s = attrib.getName().toLowerCase(Locale.ENGLISH);
+                final String s = attrib.getName().toLowerCase(Locale.ROOT);
 
                 cookie.setAttribute(s, attrib.getValue());
 
@@ -163,7 +180,7 @@ public class RFC2965Spec extends RFC2109Spec {
             if (s != null) {
                 buffer.append("; $Port");
                 buffer.append("=\"");
-                if (s.trim().length() > 0) {
+                if (!s.trim().isEmpty()) {
                     final int[] ports = cookie.getPorts();
                     if (ports != null) {
                         final int len = ports.length;
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecProvider.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecProvider.java
new file mode 100644
index 0000000..ba303a6
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965SpecProvider.java
@@ -0,0 +1,92 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.annotation.Obsolete;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecProvider;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * {@link RFC2965Spec}. The instance returned by this factory can
+ * be shared by multiple threads.
+ * <p>
+ * Rendered obsolete by {@link org.apache.http.impl.cookie.RFC6265CookieSpecProvider}
+ *
+ * @since 4.4
+ * @see org.apache.http.impl.cookie.RFC6265CookieSpecProvider
+ */
+ at Obsolete
+ at Immutable
+public class RFC2965SpecProvider implements CookieSpecProvider {
+
+    private final PublicSuffixMatcher publicSuffixMatcher;
+    private final boolean oneHeader;
+
+    private volatile CookieSpec cookieSpec;
+
+    public RFC2965SpecProvider(final PublicSuffixMatcher publicSuffixMatcher, final boolean oneHeader) {
+        super();
+        this.oneHeader = oneHeader;
+        this.publicSuffixMatcher = publicSuffixMatcher;
+    }
+
+    public RFC2965SpecProvider(final PublicSuffixMatcher publicSuffixMatcher) {
+        this(publicSuffixMatcher, false);
+    }
+
+    public RFC2965SpecProvider() {
+        this(null, false);
+    }
+
+    @Override
+    public CookieSpec create(final HttpContext context) {
+        if (cookieSpec == null) {
+            synchronized (this) {
+                if (cookieSpec == null) {
+                    this.cookieSpec = new RFC2965Spec(this.oneHeader,
+                            new RFC2965VersionAttributeHandler(),
+                            new BasicPathHandler(),
+                            PublicSuffixDomainFilter.decorate(
+                                    new RFC2965DomainAttributeHandler(), this.publicSuffixMatcher),
+                            new RFC2965PortAttributeHandler(),
+                            new BasicMaxAgeHandler(),
+                            new BasicSecureHandler(),
+                            new BasicCommentHandler(),
+                            new RFC2965CommentUrlAttributeHandler(),
+                            new RFC2965DiscardAttributeHandler());
+                }
+            }
+        }
+        return this.cookieSpec;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
index 7be9833..ac682d8 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
@@ -29,8 +29,8 @@ package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.Immutable;
 import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieRestrictionViolationException;
 import org.apache.http.cookie.MalformedCookieException;
@@ -39,12 +39,12 @@ import org.apache.http.cookie.SetCookie2;
 import org.apache.http.util.Args;
 
 /**
- * <tt>"Version"</tt> cookie attribute handler for RFC 2965 cookie spec.
+ * {@code "Version"} cookie attribute handler for RFC 2965 cookie spec.
  *
  * @since 4.0
  */
 @Immutable
-public class RFC2965VersionAttributeHandler implements CookieAttributeHandler {
+public class RFC2965VersionAttributeHandler implements CommonCookieAttributeHandler {
 
     public RFC2965VersionAttributeHandler() {
         super();
@@ -53,6 +53,7 @@ public class RFC2965VersionAttributeHandler implements CookieAttributeHandler {
     /**
      * Parse cookie version attribute.
      */
+    @Override
     public void parse(final SetCookie cookie, final String value)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -75,6 +76,7 @@ public class RFC2965VersionAttributeHandler implements CookieAttributeHandler {
     /**
      * validate cookie version attribute. Version attribute is REQUIRED.
      */
+    @Override
     public void validate(final Cookie cookie, final CookieOrigin origin)
             throws MalformedCookieException {
         Args.notNull(cookie, "Cookie");
@@ -87,8 +89,14 @@ public class RFC2965VersionAttributeHandler implements CookieAttributeHandler {
         }
     }
 
+    @Override
     public boolean match(final Cookie cookie, final CookieOrigin origin) {
         return true;
     }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.VERSION_ATTR;
+    }
+
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java
new file mode 100644
index 0000000..bec959a
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java
@@ -0,0 +1,276 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.http.FormattedHeader;
+import org.apache.http.Header;
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookiePriorityComparator;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SM;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.message.ParserCursor;
+import org.apache.http.message.TokenParser;
+import org.apache.http.util.Args;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * Cookie management functions shared by RFC C6265 compliant specification.
+ *
+ * @since 4.4
+ */
+ at ThreadSafe
+class RFC6265CookieSpecBase implements CookieSpec {
+
+    private final static char PARAM_DELIMITER  = ';';
+    private final static char COMMA_CHAR       = ',';
+    private final static char EQUAL_CHAR       = '=';
+    private final static char DQUOTE_CHAR      = '"';
+    private final static char ESCAPE_CHAR      = '\\';
+
+    // IMPORTANT!
+    // These private static variables must be treated as immutable and never exposed outside this class
+    private static final BitSet TOKEN_DELIMS = TokenParser.INIT_BITSET(EQUAL_CHAR, PARAM_DELIMITER);
+    private static final BitSet VALUE_DELIMS = TokenParser.INIT_BITSET(PARAM_DELIMITER);
+    private static final BitSet SPECIAL_CHARS = TokenParser.INIT_BITSET(' ',
+            DQUOTE_CHAR, COMMA_CHAR, PARAM_DELIMITER, ESCAPE_CHAR);
+
+    private final CookieAttributeHandler[] attribHandlers;
+    private final Map<String, CookieAttributeHandler> attribHandlerMap;
+    private final TokenParser tokenParser;
+
+    RFC6265CookieSpecBase(final CommonCookieAttributeHandler... handlers) {
+        super();
+        this.attribHandlers = handlers.clone();
+        this.attribHandlerMap = new ConcurrentHashMap<String, CookieAttributeHandler>(handlers.length);
+        for (CommonCookieAttributeHandler handler: handlers) {
+            this.attribHandlerMap.put(handler.getAttributeName().toLowerCase(Locale.ROOT), handler);
+        }
+        this.tokenParser = TokenParser.INSTANCE;
+    }
+
+    static String getDefaultPath(final CookieOrigin origin) {
+        String defaultPath = origin.getPath();
+        int lastSlashIndex = defaultPath.lastIndexOf('/');
+        if (lastSlashIndex >= 0) {
+            if (lastSlashIndex == 0) {
+                //Do not remove the very first slash
+                lastSlashIndex = 1;
+            }
+            defaultPath = defaultPath.substring(0, lastSlashIndex);
+        }
+        return defaultPath;
+    }
+
+    static String getDefaultDomain(final CookieOrigin origin) {
+        return origin.getHost();
+    }
+
+    @Override
+    public final List<Cookie> parse(final Header header, final CookieOrigin origin) throws MalformedCookieException {
+        Args.notNull(header, "Header");
+        Args.notNull(origin, "Cookie origin");
+        if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE)) {
+            throw new MalformedCookieException("Unrecognized cookie header: '" + header.toString() + "'");
+        }
+        final CharArrayBuffer buffer;
+        final ParserCursor cursor;
+        if (header instanceof FormattedHeader) {
+            buffer = ((FormattedHeader) header).getBuffer();
+            cursor = new ParserCursor(((FormattedHeader) header).getValuePos(), buffer.length());
+        } else {
+            final String s = header.getValue();
+            if (s == null) {
+                throw new MalformedCookieException("Header value is null");
+            }
+            buffer = new CharArrayBuffer(s.length());
+            buffer.append(s);
+            cursor = new ParserCursor(0, buffer.length());
+        }
+        final String name = tokenParser.parseToken(buffer, cursor, TOKEN_DELIMS);
+        if (name.length() == 0) {
+            throw new MalformedCookieException("Cookie name is invalid: '" + header.toString() + "'");
+        }
+        if (cursor.atEnd()) {
+            throw new MalformedCookieException("Cookie value is invalid: '" + header.toString() + "'");
+        }
+        final int valueDelim = buffer.charAt(cursor.getPos());
+        cursor.updatePos(cursor.getPos() + 1);
+        if (valueDelim != '=') {
+            throw new MalformedCookieException("Cookie value is invalid: '" + header.toString() + "'");
+        }
+        final String value = tokenParser.parseValue(buffer, cursor, VALUE_DELIMS);
+        if (!cursor.atEnd()) {
+            cursor.updatePos(cursor.getPos() + 1);
+        }
+        final BasicClientCookie cookie = new BasicClientCookie(name, value);
+        cookie.setPath(getDefaultPath(origin));
+        cookie.setDomain(getDefaultDomain(origin));
+        cookie.setCreationDate(new Date());
+
+        final Map<String, String> attribMap = new LinkedHashMap<String, String>();
+        while (!cursor.atEnd()) {
+            final String paramName = tokenParser.parseToken(buffer, cursor, TOKEN_DELIMS);
+            String paramValue = null;
+            if (!cursor.atEnd()) {
+                final int paramDelim = buffer.charAt(cursor.getPos());
+                cursor.updatePos(cursor.getPos() + 1);
+                if (paramDelim == EQUAL_CHAR) {
+                    paramValue = tokenParser.parseToken(buffer, cursor, VALUE_DELIMS);
+                    if (!cursor.atEnd()) {
+                        cursor.updatePos(cursor.getPos() + 1);
+                    }
+                }
+            }
+            cookie.setAttribute(paramName.toLowerCase(Locale.ROOT), paramValue);
+            attribMap.put(paramName, paramValue);
+        }
+        // Ignore 'Expires' if 'Max-Age' is present
+        if (attribMap.containsKey(ClientCookie.MAX_AGE_ATTR)) {
+            attribMap.remove(ClientCookie.EXPIRES_ATTR);
+        }
+
+        for (Map.Entry<String, String> entry: attribMap.entrySet()) {
+            final String paramName = entry.getKey();
+            final String paramValue = entry.getValue();
+            final CookieAttributeHandler handler = this.attribHandlerMap.get(paramName);
+            if (handler != null) {
+                handler.parse(cookie, paramValue);
+            }
+        }
+
+        return Collections.<Cookie>singletonList(cookie);
+    }
+
+    @Override
+    public final void validate(final Cookie cookie, final CookieOrigin origin)
+            throws MalformedCookieException {
+        Args.notNull(cookie, "Cookie");
+        Args.notNull(origin, "Cookie origin");
+        for (final CookieAttributeHandler handler: this.attribHandlers) {
+            handler.validate(cookie, origin);
+        }
+    }
+
+    @Override
+    public final boolean match(final Cookie cookie, final CookieOrigin origin) {
+        Args.notNull(cookie, "Cookie");
+        Args.notNull(origin, "Cookie origin");
+        for (final CookieAttributeHandler handler: this.attribHandlers) {
+            if (!handler.match(cookie, origin)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public List<Header> formatCookies(final List<Cookie> cookies) {
+        Args.notEmpty(cookies, "List of cookies");
+        final List<? extends Cookie> sortedCookies;
+        if (cookies.size() > 1) {
+            // Create a mutable copy and sort the copy.
+            sortedCookies = new ArrayList<Cookie>(cookies);
+            Collections.sort(sortedCookies, CookiePriorityComparator.INSTANCE);
+        } else {
+            sortedCookies = cookies;
+        }
+        final CharArrayBuffer buffer = new CharArrayBuffer(20 * sortedCookies.size());
+        buffer.append(SM.COOKIE);
+        buffer.append(": ");
+        for (int n = 0; n < sortedCookies.size(); n++) {
+            final Cookie cookie = sortedCookies.get(n);
+            if (n > 0) {
+                buffer.append(PARAM_DELIMITER);
+                buffer.append(' ');
+            }
+            buffer.append(cookie.getName());
+            final String s = cookie.getValue();
+            if (s != null) {
+                buffer.append(EQUAL_CHAR);
+                if (containsSpecialChar(s)) {
+                    buffer.append(DQUOTE_CHAR);
+                    for (int i = 0; i < s.length(); i++) {
+                        final char ch = s.charAt(i);
+                        if (ch == DQUOTE_CHAR || ch == ESCAPE_CHAR) {
+                            buffer.append(ESCAPE_CHAR);
+                        }
+                        buffer.append(ch);
+                    }
+                    buffer.append(DQUOTE_CHAR);
+                } else {
+                    buffer.append(s);
+                }
+            }
+        }
+        final List<Header> headers = new ArrayList<Header>(1);
+        headers.add(new BufferedHeader(buffer));
+        return headers;
+    }
+
+    boolean containsSpecialChar(final CharSequence s) {
+        return containsChars(s, SPECIAL_CHARS);
+    }
+
+    boolean containsChars(final CharSequence s, final BitSet chars) {
+        for (int i = 0; i < s.length(); i++) {
+            final char ch = s.charAt(i);
+            if (chars.get(ch)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public final int getVersion() {
+        return 0;
+    }
+
+    @Override
+    public final Header getVersionHeader() {
+        return null;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java
new file mode 100644
index 0000000..e4f24dc
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java
@@ -0,0 +1,122 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecProvider;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
+ * RFC 6265 conformant cookie policy. The instance returned by this factory can be shared by
+ * multiple threads.
+ *
+ * @since 4.4
+ */
+ at Immutable
+public class RFC6265CookieSpecProvider implements CookieSpecProvider {
+
+    public enum CompatibilityLevel {
+        STRICT,
+        RELAXED,
+        IE_MEDIUM_SECURITY
+    }
+
+    private final CompatibilityLevel compatibilityLevel;
+    private final PublicSuffixMatcher publicSuffixMatcher;
+
+    private volatile CookieSpec cookieSpec;
+
+    public RFC6265CookieSpecProvider(
+            final CompatibilityLevel compatibilityLevel,
+            final PublicSuffixMatcher publicSuffixMatcher) {
+        super();
+        this.compatibilityLevel = compatibilityLevel != null ? compatibilityLevel : CompatibilityLevel.RELAXED;
+        this.publicSuffixMatcher = publicSuffixMatcher;
+    }
+
+    public RFC6265CookieSpecProvider(final PublicSuffixMatcher publicSuffixMatcher) {
+        this(CompatibilityLevel.RELAXED, publicSuffixMatcher);
+    }
+
+    public RFC6265CookieSpecProvider() {
+        this(CompatibilityLevel.RELAXED, null);
+    }
+
+    @Override
+    public CookieSpec create(final HttpContext context) {
+        if (cookieSpec == null) {
+            synchronized (this) {
+                if (cookieSpec == null) {
+                    switch (this.compatibilityLevel) {
+                        case STRICT:
+                            this.cookieSpec = new RFC6265StrictSpec(
+                                    new BasicPathHandler(),
+                                    PublicSuffixDomainFilter.decorate(
+                                            new BasicDomainHandler(), this.publicSuffixMatcher),
+                                    new BasicMaxAgeHandler(),
+                                    new BasicSecureHandler(),
+                                    new BasicExpiresHandler(RFC6265StrictSpec.DATE_PATTERNS));
+                            break;
+                        case IE_MEDIUM_SECURITY:
+                            this.cookieSpec = new RFC6265LaxSpec(
+                                    new BasicPathHandler() {
+                                        @Override
+                                        public void validate(
+                                                final Cookie cookie,
+                                                final CookieOrigin origin) throws MalformedCookieException {
+                                            // No validation
+                                        }
+                                    },
+                                    PublicSuffixDomainFilter.decorate(
+                                            new BasicDomainHandler(), this.publicSuffixMatcher),
+                                    new BasicMaxAgeHandler(),
+                                    new BasicSecureHandler(),
+                                    new BasicExpiresHandler(RFC6265StrictSpec.DATE_PATTERNS));
+                            break;
+                        default:
+                            this.cookieSpec = new RFC6265LaxSpec(
+                                    new BasicPathHandler(),
+                                    PublicSuffixDomainFilter.decorate(
+                                            new BasicDomainHandler(), this.publicSuffixMatcher),
+                                    new LaxMaxAgeHandler(),
+                                    new BasicSecureHandler(),
+                                    new LaxExpiresHandler());
+                    }
+                }
+            }
+        }
+        return this.cookieSpec;
+    }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java
similarity index 59%
copy from httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java
copy to httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java
index 2d9d024..8455c83 100644
--- a/httpclient/src/main/java/org/apache/http/impl/cookie/BasicSecureHandler.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java
@@ -24,37 +24,38 @@
  * <http://www.apache.org/>.
  *
  */
+
 package org.apache.http.impl.cookie;
 
-import org.apache.http.annotation.Immutable;
-import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieOrigin;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.cookie.SetCookie;
-import org.apache.http.util.Args;
+import org.apache.http.annotation.ThreadSafe;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 
 /**
+ * Standard {@link org.apache.http.cookie.CookieSpec} implementation that enforces a more relaxed
+ * interpretation of the HTTP state management specification (RFC 6265, section 5)
+ * for interoperability with existing servers that do not conform to the well behaved profile
+ * (RFC 6265, section 4).
  *
- * @since 4.0
+ * @since 4.4
  */
- at Immutable
-public class BasicSecureHandler extends AbstractCookieAttributeHandler {
+ at ThreadSafe
+public class RFC6265LaxSpec extends RFC6265CookieSpecBase {
 
-    public BasicSecureHandler() {
-        super();
+    public RFC6265LaxSpec() {
+        super(new BasicPathHandler(),
+                new BasicDomainHandler(),
+                new LaxMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new LaxExpiresHandler());
     }
 
-    public void parse(final SetCookie cookie, final String value)
-            throws MalformedCookieException {
-        Args.notNull(cookie, "Cookie");
-        cookie.setSecure(true);
+    RFC6265LaxSpec(final CommonCookieAttributeHandler... handlers) {
+        super(handlers);
     }
 
     @Override
-    public boolean match(final Cookie cookie, final CookieOrigin origin) {
-        Args.notNull(cookie, "Cookie");
-        Args.notNull(origin, "Cookie origin");
-        return !cookie.isSecure() || origin.isSecure();
+    public String toString() {
+        return "rfc6265-lax";
     }
 
 }
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java
similarity index 55%
copy from httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java
copy to httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java
index 03e2d5f..1765d27 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java
+++ b/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java
@@ -24,54 +24,44 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.client.cache;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
+package org.apache.http.impl.cookie;
 
 import org.apache.http.annotation.ThreadSafe;
-import org.apache.http.client.cache.Resource;
+import org.apache.http.client.utils.DateUtils;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
 
 /**
- * Cache resource backed by a file.
+ * Standard {@link org.apache.http.cookie.CookieSpec} implementation that enforces syntax
+ * and semantics of the well-behaved profile of the HTTP state management specification
+ * (RFC 6265, section 4).
  *
- * @since 4.1
+ * @since 4.4
  */
 @ThreadSafe
-public class FileResource implements Resource {
+public class RFC6265StrictSpec extends RFC6265CookieSpecBase {
 
-    private static final long serialVersionUID = 4132244415919043397L;
+    final static String[] DATE_PATTERNS = {
+        DateUtils.PATTERN_RFC1123,
+        DateUtils.PATTERN_RFC1036,
+        DateUtils.PATTERN_ASCTIME
+    };
 
-    private final File file;
-
-    private volatile boolean disposed;
-
-    public FileResource(final File file) {
-        super();
-        this.file = file;
-        this.disposed = false;
-    }
-
-    synchronized File getFile() {
-        return this.file;
-    }
-
-    public synchronized InputStream getInputStream() throws IOException {
-        return new FileInputStream(this.file);
+    public RFC6265StrictSpec() {
+        super(new BasicPathHandler(),
+                new BasicDomainHandler(),
+                new BasicMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new BasicExpiresHandler(DATE_PATTERNS));
     }
 
-    public synchronized long length() {
-        return this.file.length();
+    RFC6265StrictSpec(final CommonCookieAttributeHandler... handlers) {
+        super(handlers);
     }
 
-    public synchronized void dispose() {
-        if (this.disposed) {
-            return;
-        }
-        this.disposed = true;
-        this.file.delete();
+    @Override
+    public String toString() {
+        return "rfc6265-strict";
     }
 
 }
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/BackoffStrategyExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/BackoffStrategyExec.java
index 0cd9433..7c9025b 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/BackoffStrategyExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/BackoffStrategyExec.java
@@ -64,6 +64,7 @@ public class BackoffStrategyExec implements ClientExecChain {
         this.backoffManager = backoffManager;
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/ClientExecChain.java b/httpclient/src/main/java/org/apache/http/impl/execchain/ClientExecChain.java
index 2b03e29..25cea9a 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/ClientExecChain.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/ClientExecChain.java
@@ -40,11 +40,12 @@ import org.apache.http.conn.routing.HttpRoute;
  * This interface represents an element in the HTTP request execution chain. Each element can
  * either be a decorator around another element that implements a cross cutting aspect or
  * a self-contained executor capable of producing a response for the given request.
- * <p/>
+ * <p>
  * Important: please note it is required for decorators that implement post execution aspects
  * or response post-processing of any sort to release resources associated with the response
  * by calling {@link CloseableHttpResponse#close()} methods in case of an I/O, protocol or
  * runtime exception, or in case the response is not propagated to the caller.
+ * </p>
  *
  * @since 4.3
  */
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/ConnectionHolder.java b/httpclient/src/main/java/org/apache/http/impl/execchain/ConnectionHolder.java
index 45b8ec1..1ebf02d 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/ConnectionHolder.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/ConnectionHolder.java
@@ -90,6 +90,7 @@ class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeab
         }
     }
 
+    @Override
     public void releaseConnection() {
         synchronized (this.managedConn) {
             if (this.released) {
@@ -115,6 +116,7 @@ class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeab
         }
     }
 
+    @Override
     public void abortConnection() {
         synchronized (this.managedConn) {
             if (this.released) {
@@ -135,6 +137,7 @@ class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeab
         }
     }
 
+    @Override
     public boolean cancel() {
         final boolean alreadyReleased = this.released;
         log.debug("Cancelling request execution");
@@ -146,6 +149,7 @@ class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeab
         return this.released;
     }
 
+    @Override
     public void close() throws IOException {
         abortConnection();
     }
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java b/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java
index 413bf0e..4a6ca05 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/HttpResponseProxy.java
@@ -58,117 +58,145 @@ class HttpResponseProxy implements CloseableHttpResponse {
         ResponseEntityProxy.enchance(original, connHolder);
     }
 
+    @Override
     public void close() throws IOException {
         if (this.connHolder != null) {
             this.connHolder.abortConnection();
         }
     }
 
+    @Override
     public StatusLine getStatusLine() {
         return original.getStatusLine();
     }
 
+    @Override
     public void setStatusLine(final StatusLine statusline) {
         original.setStatusLine(statusline);
     }
 
+    @Override
     public void setStatusLine(final ProtocolVersion ver, final int code) {
         original.setStatusLine(ver, code);
     }
 
+    @Override
     public void setStatusLine(final ProtocolVersion ver, final int code, final String reason) {
         original.setStatusLine(ver, code, reason);
     }
 
+    @Override
     public void setStatusCode(final int code) throws IllegalStateException {
         original.setStatusCode(code);
     }
 
+    @Override
     public void setReasonPhrase(final String reason) throws IllegalStateException {
         original.setReasonPhrase(reason);
     }
 
+    @Override
     public HttpEntity getEntity() {
         return original.getEntity();
     }
 
+    @Override
     public void setEntity(final HttpEntity entity) {
         original.setEntity(entity);
     }
 
+    @Override
     public Locale getLocale() {
         return original.getLocale();
     }
 
+    @Override
     public void setLocale(final Locale loc) {
         original.setLocale(loc);
     }
 
+    @Override
     public ProtocolVersion getProtocolVersion() {
         return original.getProtocolVersion();
     }
 
+    @Override
     public boolean containsHeader(final String name) {
         return original.containsHeader(name);
     }
 
+    @Override
     public Header[] getHeaders(final String name) {
         return original.getHeaders(name);
     }
 
+    @Override
     public Header getFirstHeader(final String name) {
         return original.getFirstHeader(name);
     }
 
+    @Override
     public Header getLastHeader(final String name) {
         return original.getLastHeader(name);
     }
 
+    @Override
     public Header[] getAllHeaders() {
         return original.getAllHeaders();
     }
 
+    @Override
     public void addHeader(final Header header) {
         original.addHeader(header);
     }
 
+    @Override
     public void addHeader(final String name, final String value) {
         original.addHeader(name, value);
     }
 
+    @Override
     public void setHeader(final Header header) {
         original.setHeader(header);
     }
 
+    @Override
     public void setHeader(final String name, final String value) {
         original.setHeader(name, value);
     }
 
+    @Override
     public void setHeaders(final Header[] headers) {
         original.setHeaders(headers);
     }
 
+    @Override
     public void removeHeader(final Header header) {
         original.removeHeader(header);
     }
 
+    @Override
     public void removeHeaders(final String name) {
         original.removeHeaders(name);
     }
 
+    @Override
     public HeaderIterator headerIterator() {
         return original.headerIterator();
     }
 
+    @Override
     public HeaderIterator headerIterator(final String name) {
         return original.headerIterator(name);
     }
 
+    @Override
     @Deprecated
     public HttpParams getParams() {
         return original.getParams();
     }
 
+    @Override
     @Deprecated
     public void setParams(final HttpParams params) {
         original.setParams(params);
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java
index f985f29..9496813 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java
@@ -54,7 +54,6 @@ import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpExecutionAware;
 import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
-import org.apache.http.client.protocol.RequestClientConnControl;
 import org.apache.http.conn.ConnectionKeepAliveStrategy;
 import org.apache.http.conn.ConnectionRequest;
 import org.apache.http.conn.HttpClientConnectionManager;
@@ -84,6 +83,7 @@ import org.apache.http.util.EntityUtils;
  *
  * @since 4.3
  */
+ at SuppressWarnings("deprecation")
 @Immutable
 public class MainClientExec implements ClientExecChain {
 
@@ -100,12 +100,15 @@ public class MainClientExec implements ClientExecChain {
     private final UserTokenHandler userTokenHandler;
     private final HttpRouteDirector routeDirector;
 
-
+    /**
+     * @since 4.4
+     */
     public MainClientExec(
             final HttpRequestExecutor requestExecutor,
             final HttpClientConnectionManager connManager,
             final ConnectionReuseStrategy reuseStrategy,
             final ConnectionKeepAliveStrategy keepAliveStrategy,
+            final HttpProcessor proxyHttpProcessor,
             final AuthenticationStrategy targetAuthStrategy,
             final AuthenticationStrategy proxyAuthStrategy,
             final UserTokenHandler userTokenHandler) {
@@ -113,22 +116,36 @@ public class MainClientExec implements ClientExecChain {
         Args.notNull(connManager, "Client connection manager");
         Args.notNull(reuseStrategy, "Connection reuse strategy");
         Args.notNull(keepAliveStrategy, "Connection keep alive strategy");
+        Args.notNull(proxyHttpProcessor, "Proxy HTTP processor");
         Args.notNull(targetAuthStrategy, "Target authentication strategy");
         Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
         Args.notNull(userTokenHandler, "User token handler");
         this.authenticator      = new HttpAuthenticator();
-        this.proxyHttpProcessor = new ImmutableHttpProcessor(
-                new RequestTargetHost(), new RequestClientConnControl());
         this.routeDirector      = new BasicRouteDirector();
         this.requestExecutor    = requestExecutor;
         this.connManager        = connManager;
         this.reuseStrategy      = reuseStrategy;
         this.keepAliveStrategy  = keepAliveStrategy;
+        this.proxyHttpProcessor = proxyHttpProcessor;
         this.targetAuthStrategy = targetAuthStrategy;
         this.proxyAuthStrategy  = proxyAuthStrategy;
         this.userTokenHandler   = userTokenHandler;
     }
 
+    public MainClientExec(
+            final HttpRequestExecutor requestExecutor,
+            final HttpClientConnectionManager connManager,
+            final ConnectionReuseStrategy reuseStrategy,
+            final ConnectionKeepAliveStrategy keepAliveStrategy,
+            final AuthenticationStrategy targetAuthStrategy,
+            final AuthenticationStrategy proxyAuthStrategy,
+            final UserTokenHandler userTokenHandler) {
+        this(requestExecutor, connManager, reuseStrategy, keepAliveStrategy,
+                new ImmutableHttpProcessor(new RequestTargetHost()),
+                targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
+    }
+
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java
index 859946a..adca0a2 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/MinimalClientExec.java
@@ -128,6 +128,7 @@ public class MinimalClientExec implements ClientExecChain {
         }
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java
index 5bdde8c..0f9b75c 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java
@@ -61,10 +61,11 @@ import org.apache.http.util.Args;
  * Internally this executor relies on a {@link HttpProcessor} to populate
  * requisite HTTP request headers, process HTTP response headers and update
  * session state in {@link HttpClientContext}.
- * <p/>
+ * <p>
  * Further responsibilities such as communication with the opposite
  * endpoint is delegated to the next executor in the request execution
  * chain.
+ * </p>
  *
  * @since 4.3
  */
@@ -87,32 +88,17 @@ public class ProtocolExec implements ClientExecChain {
     void rewriteRequestURI(
             final HttpRequestWrapper request,
             final HttpRoute route) throws ProtocolException {
-        try {
-            URI uri = request.getURI();
-            if (uri != null) {
-                if (route.getProxyHost() != null && !route.isTunnelled()) {
-                    // Make sure the request URI is absolute
-                    if (!uri.isAbsolute()) {
-                        final HttpHost target = route.getTargetHost();
-                        uri = URIUtils.rewriteURI(uri, target, true);
-                    } else {
-                        uri = URIUtils.rewriteURI(uri);
-                    }
-                } else {
-                    // Make sure the request URI is relative
-                    if (uri.isAbsolute()) {
-                        uri = URIUtils.rewriteURI(uri, null, true);
-                    } else {
-                        uri = URIUtils.rewriteURI(uri);
-                    }
-                }
-                request.setURI(uri);
+        final URI uri = request.getURI();
+        if (uri != null) {
+            try {
+                request.setURI(URIUtils.rewriteURIForRoute(uri, route));
+            } catch (final URISyntaxException ex) {
+                throw new ProtocolException("Invalid URI: " + uri, ex);
             }
-        } catch (final URISyntaxException ex) {
-            throw new ProtocolException("Invalid URI: " + request.getRequestLine().getUri(), ex);
         }
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
@@ -167,6 +153,9 @@ public class ProtocolExec implements ClientExecChain {
             }
         }
         if (target == null) {
+            target = request.getTarget();
+        }
+        if (target == null) {
             target = route.getTargetHost();
         }
 
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java
index 7c912ee..f9c1d79 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/RedirectExec.java
@@ -57,10 +57,11 @@ import org.apache.http.util.EntityUtils;
 /**
  * Request executor in the request execution chain that is responsible
  * for handling of request redirects.
- * <p/>
+ * <p>
  * Further responsibilities such as communication with the opposite
  * endpoint is delegated to the next executor in the request execution
  * chain.
+ * </p>
  *
  * @since 4.3
  */
@@ -86,6 +87,7 @@ public class RedirectExec implements ClientExecChain {
         this.redirectStrategy = redirectStrategy;
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java b/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java
index 20f5001..e4ed35b 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/RequestEntityProxy.java
@@ -87,39 +87,48 @@ class RequestEntityProxy implements HttpEntity  {
         return consumed;
     }
 
+    @Override
     public boolean isRepeatable() {
         return original.isRepeatable();
     }
 
+    @Override
     public boolean isChunked() {
         return original.isChunked();
     }
 
+    @Override
     public long getContentLength() {
         return original.getContentLength();
     }
 
+    @Override
     public Header getContentType() {
         return original.getContentType();
     }
 
+    @Override
     public Header getContentEncoding() {
         return original.getContentEncoding();
     }
 
+    @Override
     public InputStream getContent() throws IOException, IllegalStateException {
         return original.getContent();
     }
 
+    @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         consumed = true;
         original.writeTo(outstream);
     }
 
+    @Override
     public boolean isStreaming() {
         return original.isStreaming();
     }
 
+    @Override
     @Deprecated
     public void consumeContent() throws IOException {
         consumed = true;
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java b/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java
index 28f21ae..9f66de6 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/ResponseEntityProxy.java
@@ -105,6 +105,7 @@ class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher
         }
     }
 
+    @Override
     public boolean eofDetected(final InputStream wrapped) throws IOException {
         try {
             // there may be some cleanup required, such as
@@ -117,6 +118,7 @@ class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher
         return false;
     }
 
+    @Override
     public boolean streamClosed(final InputStream wrapped) throws IOException {
         try {
             final boolean open = connHolder != null && !connHolder.isReleased();
@@ -136,6 +138,7 @@ class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher
         return false;
     }
 
+    @Override
     public boolean streamAbort(final InputStream wrapped) throws IOException {
         cleanup();
         return false;
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java
index 82bae9d..cade164 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/RetryExec.java
@@ -48,10 +48,11 @@ import org.apache.http.util.Args;
  * Request executor in the request execution chain that is responsible
  * for making a decision whether a request failed due to an I/O error
  * should be re-executed.
- * <p/>
+ * <p>
  * Further responsibilities such as communication with the opposite
  * endpoint is delegated to the next executor in the request execution
  * chain.
+ * </p>
  *
  * @since 4.3
  */
@@ -72,6 +73,7 @@ public class RetryExec implements ClientExecChain {
         this.retryHandler = retryHandler;
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/ServiceUnavailableRetryExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/ServiceUnavailableRetryExec.java
index 549b61d..6fb6ef3 100644
--- a/httpclient/src/main/java/org/apache/http/impl/execchain/ServiceUnavailableRetryExec.java
+++ b/httpclient/src/main/java/org/apache/http/impl/execchain/ServiceUnavailableRetryExec.java
@@ -47,10 +47,11 @@ import org.apache.http.util.Args;
  * Request executor in the request execution chain that is responsible
  * for making a decision whether a request that received a non-2xx response
  * from the target server should be re-executed.
- * <p/>
+ * <p>
  * Further responsibilities such as communication with the opposite
  * endpoint is delegated to the next executor in the request execution
  * chain.
+ * </p>
  *
  * @since 4.3
  */
@@ -72,6 +73,7 @@ public class ServiceUnavailableRetryExec implements ClientExecChain {
         this.retryStrategy = retryStrategy;
     }
 
+    @Override
     public CloseableHttpResponse execute(
             final HttpRoute route,
             final HttpRequestWrapper request,
diff --git a/httpclient/src/main/resources/mozilla/public-suffix-list.txt b/httpclient/src/main/resources/mozilla/public-suffix-list.txt
new file mode 100644
index 0000000..d5c9924
--- /dev/null
+++ b/httpclient/src/main/resources/mozilla/public-suffix-list.txt
@@ -0,0 +1,10309 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// ===BEGIN ICANN DOMAINS===
+
+// ac : http://en.wikipedia.org/wiki/.ac
+ac
+com.ac
+edu.ac
+gov.ac
+net.ac
+mil.ac
+org.ac
+
+// ad : http://en.wikipedia.org/wiki/.ad
+ad
+nom.ad
+
+// ae : http://en.wikipedia.org/wiki/.ae
+// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php
+ae
+co.ae
+net.ae
+org.ae
+sch.ae
+ac.ae
+gov.ae
+mil.ae
+
+// aero : see http://www.information.aero/index.php?id=66
+aero
+accident-investigation.aero
+accident-prevention.aero
+aerobatic.aero
+aeroclub.aero
+aerodrome.aero
+agents.aero
+aircraft.aero
+airline.aero
+airport.aero
+air-surveillance.aero
+airtraffic.aero
+air-traffic-control.aero
+ambulance.aero
+amusement.aero
+association.aero
+author.aero
+ballooning.aero
+broker.aero
+caa.aero
+cargo.aero
+catering.aero
+certification.aero
+championship.aero
+charter.aero
+civilaviation.aero
+club.aero
+conference.aero
+consultant.aero
+consulting.aero
+control.aero
+council.aero
+crew.aero
+design.aero
+dgca.aero
+educator.aero
+emergency.aero
+engine.aero
+engineer.aero
+entertainment.aero
+equipment.aero
+exchange.aero
+express.aero
+federation.aero
+flight.aero
+freight.aero
+fuel.aero
+gliding.aero
+government.aero
+groundhandling.aero
+group.aero
+hanggliding.aero
+homebuilt.aero
+insurance.aero
+journal.aero
+journalist.aero
+leasing.aero
+logistics.aero
+magazine.aero
+maintenance.aero
+marketplace.aero
+media.aero
+microlight.aero
+modelling.aero
+navigation.aero
+parachuting.aero
+paragliding.aero
+passenger-association.aero
+pilot.aero
+press.aero
+production.aero
+recreation.aero
+repbody.aero
+res.aero
+research.aero
+rotorcraft.aero
+safety.aero
+scientist.aero
+services.aero
+show.aero
+skydiving.aero
+software.aero
+student.aero
+taxi.aero
+trader.aero
+trading.aero
+trainer.aero
+union.aero
+workinggroup.aero
+works.aero
+
+// af : http://www.nic.af/help.jsp
+af
+gov.af
+com.af
+org.af
+net.af
+edu.af
+
+// ag : http://www.nic.ag/prices.htm
+ag
+com.ag
+org.ag
+net.ag
+co.ag
+nom.ag
+
+// ai : http://nic.com.ai/
+ai
+off.ai
+com.ai
+net.ai
+org.ai
+
+// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31
+al
+com.al
+edu.al
+gov.al
+mil.al
+net.al
+org.al
+
+// am : http://en.wikipedia.org/wiki/.am
+am
+
+// an : http://www.una.an/an_domreg/default.asp
+an
+com.an
+net.an
+org.an
+edu.an
+
+// ao : http://en.wikipedia.org/wiki/.ao
+// http://www.dns.ao/REGISTR.DOC
+ao
+ed.ao
+gv.ao
+og.ao
+co.ao
+pb.ao
+it.ao
+
+// aq : http://en.wikipedia.org/wiki/.aq
+aq
+
+// ar : https://nic.ar/normativa-vigente.xhtml
+ar
+com.ar
+edu.ar
+gob.ar
+gov.ar
+int.ar
+mil.ar
+net.ar
+org.ar
+tur.ar
+
+// arpa : http://en.wikipedia.org/wiki/.arpa
+// Confirmed by registry <iana-questions at icann.org> 2008-06-18
+arpa
+e164.arpa
+in-addr.arpa
+ip6.arpa
+iris.arpa
+uri.arpa
+urn.arpa
+
+// as : http://en.wikipedia.org/wiki/.as
+as
+gov.as
+
+// asia : http://en.wikipedia.org/wiki/.asia
+asia
+
+// at : http://en.wikipedia.org/wiki/.at
+// Confirmed by registry <it at nic.at> 2008-06-17
+at
+ac.at
+co.at
+gv.at
+or.at
+
+// au : http://en.wikipedia.org/wiki/.au
+// http://www.auda.org.au/
+au
+// 2LDs
+com.au
+net.au
+org.au
+edu.au
+gov.au
+asn.au
+id.au
+// Historic 2LDs (closed to new registration, but sites still exist)
+info.au
+conf.au
+oz.au
+// CGDNs - http://www.cgdn.org.au/
+act.au
+nsw.au
+nt.au
+qld.au
+sa.au
+tas.au
+vic.au
+wa.au
+// 3LDs
+act.edu.au
+nsw.edu.au
+nt.edu.au
+qld.edu.au
+sa.edu.au
+tas.edu.au
+vic.edu.au
+wa.edu.au
+// act.gov.au  Bug 984824 - Removed at request of Greg Tankard
+// nsw.gov.au  Bug 547985 - Removed at request of <Shae.Donelan at services.nsw.gov.au>
+// nt.gov.au  Bug 940478 - Removed at request of Greg Connors <Greg.Connors at nt.gov.au>
+qld.gov.au
+sa.gov.au
+tas.gov.au
+vic.gov.au
+wa.gov.au
+
+// aw : http://en.wikipedia.org/wiki/.aw
+aw
+com.aw
+
+// ax : http://en.wikipedia.org/wiki/.ax
+ax
+
+// az : http://en.wikipedia.org/wiki/.az
+az
+com.az
+net.az
+int.az
+gov.az
+org.az
+edu.az
+info.az
+pp.az
+mil.az
+name.az
+pro.az
+biz.az
+
+// ba : http://en.wikipedia.org/wiki/.ba
+ba
+org.ba
+net.ba
+edu.ba
+gov.ba
+mil.ba
+unsa.ba
+unbi.ba
+co.ba
+com.ba
+rs.ba
+
+// bb : http://en.wikipedia.org/wiki/.bb
+bb
+biz.bb
+co.bb
+com.bb
+edu.bb
+gov.bb
+info.bb
+net.bb
+org.bb
+store.bb
+tv.bb
+
+// bd : http://en.wikipedia.org/wiki/.bd
+*.bd
+
+// be : http://en.wikipedia.org/wiki/.be
+// Confirmed by registry <tech at dns.be> 2008-06-08
+be
+ac.be
+
+// bf : http://en.wikipedia.org/wiki/.bf
+bf
+gov.bf
+
+// bg : http://en.wikipedia.org/wiki/.bg
+// https://www.register.bg/user/static/rules/en/index.html
+bg
+a.bg
+b.bg
+c.bg
+d.bg
+e.bg
+f.bg
+g.bg
+h.bg
+i.bg
+j.bg
+k.bg
+l.bg
+m.bg
+n.bg
+o.bg
+p.bg
+q.bg
+r.bg
+s.bg
+t.bg
+u.bg
+v.bg
+w.bg
+x.bg
+y.bg
+z.bg
+0.bg
+1.bg
+2.bg
+3.bg
+4.bg
+5.bg
+6.bg
+7.bg
+8.bg
+9.bg
+
+// bh : http://en.wikipedia.org/wiki/.bh
+bh
+com.bh
+edu.bh
+net.bh
+org.bh
+gov.bh
+
+// bi : http://en.wikipedia.org/wiki/.bi
+// http://whois.nic.bi/
+bi
+co.bi
+com.bi
+edu.bi
+or.bi
+org.bi
+
+// biz : http://en.wikipedia.org/wiki/.biz
+biz
+
+// bj : http://en.wikipedia.org/wiki/.bj
+bj
+asso.bj
+barreau.bj
+gouv.bj
+
+// bm : http://www.bermudanic.bm/dnr-text.txt
+bm
+com.bm
+edu.bm
+gov.bm
+net.bm
+org.bm
+
+// bn : http://en.wikipedia.org/wiki/.bn
+*.bn
+
+// bo : http://www.nic.bo/
+bo
+com.bo
+edu.bo
+gov.bo
+gob.bo
+int.bo
+org.bo
+net.bo
+mil.bo
+tv.bo
+
+// br : http://registro.br/dominio/categoria.html
+// Submitted by registry <fneves at registro.br> 2014-08-11
+br
+adm.br
+adv.br
+agr.br
+am.br
+arq.br
+art.br
+ato.br
+b.br
+bio.br
+blog.br
+bmd.br
+cim.br
+cng.br
+cnt.br
+com.br
+coop.br
+ecn.br
+eco.br
+edu.br
+emp.br
+eng.br
+esp.br
+etc.br
+eti.br
+far.br
+flog.br
+fm.br
+fnd.br
+fot.br
+fst.br
+g12.br
+ggf.br
+gov.br
+imb.br
+ind.br
+inf.br
+jor.br
+jus.br
+leg.br
+lel.br
+mat.br
+med.br
+mil.br
+mp.br
+mus.br
+net.br
+*.nom.br
+not.br
+ntr.br
+odo.br
+org.br
+ppg.br
+pro.br
+psc.br
+psi.br
+qsl.br
+radio.br
+rec.br
+slg.br
+srv.br
+taxi.br
+teo.br
+tmp.br
+trd.br
+tur.br
+tv.br
+vet.br
+vlog.br
+wiki.br
+zlg.br
+
+// bs : http://www.nic.bs/rules.html
+bs
+com.bs
+net.bs
+org.bs
+edu.bs
+gov.bs
+
+// bt : http://en.wikipedia.org/wiki/.bt
+bt
+com.bt
+edu.bt
+gov.bt
+net.bt
+org.bt
+
+// bv : No registrations at this time.
+// Submitted by registry <jarle at uninett.no> 2006-06-16
+bv
+
+// bw : http://en.wikipedia.org/wiki/.bw
+// http://www.gobin.info/domainname/bw.doc
+// list of other 2nd level tlds ?
+bw
+co.bw
+org.bw
+
+// by : http://en.wikipedia.org/wiki/.by
+// http://tld.by/rules_2006_en.html
+// list of other 2nd level tlds ?
+by
+gov.by
+mil.by
+// Official information does not indicate that com.by is a reserved
+// second-level domain, but it's being used as one (see www.google.com.by and
+// www.yahoo.com.by, for example), so we list it here for safety's sake.
+com.by
+
+// http://hoster.by/
+of.by
+
+// bz : http://en.wikipedia.org/wiki/.bz
+// http://www.belizenic.bz/
+bz
+com.bz
+net.bz
+org.bz
+edu.bz
+gov.bz
+
+// ca : http://en.wikipedia.org/wiki/.ca
+ca
+// ca geographical names
+ab.ca
+bc.ca
+mb.ca
+nb.ca
+nf.ca
+nl.ca
+ns.ca
+nt.ca
+nu.ca
+on.ca
+pe.ca
+qc.ca
+sk.ca
+yk.ca
+// gc.ca: http://en.wikipedia.org/wiki/.gc.ca
+// see also: http://registry.gc.ca/en/SubdomainFAQ
+gc.ca
+
+// cat : http://en.wikipedia.org/wiki/.cat
+cat
+
+// cc : http://en.wikipedia.org/wiki/.cc
+cc
+
+// cd : http://en.wikipedia.org/wiki/.cd
+// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1
+cd
+gov.cd
+
+// cf : http://en.wikipedia.org/wiki/.cf
+cf
+
+// cg : http://en.wikipedia.org/wiki/.cg
+cg
+
+// ch : http://en.wikipedia.org/wiki/.ch
+ch
+
+// ci : http://en.wikipedia.org/wiki/.ci
+// http://www.nic.ci/index.php?page=charte
+ci
+org.ci
+or.ci
+com.ci
+co.ci
+edu.ci
+ed.ci
+ac.ci
+net.ci
+go.ci
+asso.ci
+aéroport.ci
+int.ci
+presse.ci
+md.ci
+gouv.ci
+
+// ck : http://en.wikipedia.org/wiki/.ck
+*.ck
+!www.ck
+
+// cl : http://en.wikipedia.org/wiki/.cl
+cl
+gov.cl
+gob.cl
+co.cl
+mil.cl
+
+// cm : http://en.wikipedia.org/wiki/.cm plus bug 981927
+cm
+co.cm
+com.cm
+gov.cm
+net.cm
+
+// cn : http://en.wikipedia.org/wiki/.cn
+// Submitted by registry <tanyaling at cnnic.cn> 2008-06-11
+cn
+ac.cn
+com.cn
+edu.cn
+gov.cn
+net.cn
+org.cn
+mil.cn
+公司.cn
+网络.cn
+網絡.cn
+// cn geographic names
+ah.cn
+bj.cn
+cq.cn
+fj.cn
+gd.cn
+gs.cn
+gz.cn
+gx.cn
+ha.cn
+hb.cn
+he.cn
+hi.cn
+hl.cn
+hn.cn
+jl.cn
+js.cn
+jx.cn
+ln.cn
+nm.cn
+nx.cn
+qh.cn
+sc.cn
+sd.cn
+sh.cn
+sn.cn
+sx.cn
+tj.cn
+xj.cn
+xz.cn
+yn.cn
+zj.cn
+hk.cn
+mo.cn
+tw.cn
+
+// co : http://en.wikipedia.org/wiki/.co
+// Submitted by registry <tecnico at uniandes.edu.co> 2008-06-11
+co
+arts.co
+com.co
+edu.co
+firm.co
+gov.co
+info.co
+int.co
+mil.co
+net.co
+nom.co
+org.co
+rec.co
+web.co
+
+// com : http://en.wikipedia.org/wiki/.com
+com
+
+// coop : http://en.wikipedia.org/wiki/.coop
+coop
+
+// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do
+cr
+ac.cr
+co.cr
+ed.cr
+fi.cr
+go.cr
+or.cr
+sa.cr
+
+// cu : http://en.wikipedia.org/wiki/.cu
+cu
+com.cu
+edu.cu
+org.cu
+net.cu
+gov.cu
+inf.cu
+
+// cv : http://en.wikipedia.org/wiki/.cv
+cv
+
+// cw : http://www.una.cw/cw_registry/
+// Confirmed by registry <registry at una.net> 2013-03-26
+cw
+com.cw
+edu.cw
+net.cw
+org.cw
+
+// cx : http://en.wikipedia.org/wiki/.cx
+// list of other 2nd level tlds ?
+cx
+gov.cx
+
+// cy : http://en.wikipedia.org/wiki/.cy
+*.cy
+
+// cz : http://en.wikipedia.org/wiki/.cz
+cz
+
+// de : http://en.wikipedia.org/wiki/.de
+// Confirmed by registry <ops at denic.de> (with technical
+// reservations) 2008-07-01
+de
+
+// dj : http://en.wikipedia.org/wiki/.dj
+dj
+
+// dk : http://en.wikipedia.org/wiki/.dk
+// Confirmed by registry <robert at dk-hostmaster.dk> 2008-06-17
+dk
+
+// dm : http://en.wikipedia.org/wiki/.dm
+dm
+com.dm
+net.dm
+org.dm
+edu.dm
+gov.dm
+
+// do : http://en.wikipedia.org/wiki/.do
+do
+art.do
+com.do
+edu.do
+gob.do
+gov.do
+mil.do
+net.do
+org.do
+sld.do
+web.do
+
+// dz : http://en.wikipedia.org/wiki/.dz
+dz
+com.dz
+org.dz
+net.dz
+gov.dz
+edu.dz
+asso.dz
+pol.dz
+art.dz
+
+// ec : http://www.nic.ec/reg/paso1.asp
+// Submitted by registry <vabboud at nic.ec> 2008-07-04
+ec
+com.ec
+info.ec
+net.ec
+fin.ec
+k12.ec
+med.ec
+pro.ec
+org.ec
+edu.ec
+gov.ec
+gob.ec
+mil.ec
+
+// edu : http://en.wikipedia.org/wiki/.edu
+edu
+
+// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B
+ee
+edu.ee
+gov.ee
+riik.ee
+lib.ee
+med.ee
+com.ee
+pri.ee
+aip.ee
+org.ee
+fie.ee
+
+// eg : http://en.wikipedia.org/wiki/.eg
+eg
+com.eg
+edu.eg
+eun.eg
+gov.eg
+mil.eg
+name.eg
+net.eg
+org.eg
+sci.eg
+
+// er : http://en.wikipedia.org/wiki/.er
+*.er
+
+// es : https://www.nic.es/site_ingles/ingles/dominios/index.html
+es
+com.es
+nom.es
+org.es
+gob.es
+edu.es
+
+// et : http://en.wikipedia.org/wiki/.et
+et
+com.et
+gov.et
+org.et
+edu.et
+biz.et
+name.et
+info.et
+net.et
+
+// eu : http://en.wikipedia.org/wiki/.eu
+eu
+
+// fi : http://en.wikipedia.org/wiki/.fi
+fi
+// aland.fi : http://en.wikipedia.org/wiki/.ax
+// This domain is being phased out in favor of .ax. As there are still many
+// domains under aland.fi, we still keep it on the list until aland.fi is
+// completely removed.
+// TODO: Check for updates (expected to be phased out around Q1/2009)
+aland.fi
+
+// fj : http://en.wikipedia.org/wiki/.fj
+*.fj
+
+// fk : http://en.wikipedia.org/wiki/.fk
+*.fk
+
+// fm : http://en.wikipedia.org/wiki/.fm
+fm
+
+// fo : http://en.wikipedia.org/wiki/.fo
+fo
+
+// fr : http://www.afnic.fr/
+// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs
+fr
+com.fr
+asso.fr
+nom.fr
+prd.fr
+presse.fr
+tm.fr
+// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels
+aeroport.fr
+assedic.fr
+avocat.fr
+avoues.fr
+cci.fr
+chambagri.fr
+chirurgiens-dentistes.fr
+experts-comptables.fr
+geometre-expert.fr
+gouv.fr
+greta.fr
+huissier-justice.fr
+medecin.fr
+notaires.fr
+pharmacien.fr
+port.fr
+veterinaire.fr
+
+// ga : http://en.wikipedia.org/wiki/.ga
+ga
+
+// gb : This registry is effectively dormant
+// Submitted by registry <Damien.Shaw at ja.net> 2008-06-12
+gb
+
+// gd : http://en.wikipedia.org/wiki/.gd
+gd
+
+// ge : http://www.nic.net.ge/policy_en.pdf
+ge
+com.ge
+edu.ge
+gov.ge
+org.ge
+mil.ge
+net.ge
+pvt.ge
+
+// gf : http://en.wikipedia.org/wiki/.gf
+gf
+
+// gg : http://www.channelisles.net/register-domains/
+// Confirmed by registry <nigel at channelisles.net> 2013-11-28
+gg
+co.gg
+net.gg
+org.gg
+
+// gh : http://en.wikipedia.org/wiki/.gh
+// see also: http://www.nic.gh/reg_now.php
+// Although domains directly at second level are not possible at the moment,
+// they have been possible for some time and may come back.
+gh
+com.gh
+edu.gh
+gov.gh
+org.gh
+mil.gh
+
+// gi : http://www.nic.gi/rules.html
+gi
+com.gi
+ltd.gi
+gov.gi
+mod.gi
+edu.gi
+org.gi
+
+// gl : http://en.wikipedia.org/wiki/.gl
+// http://nic.gl
+gl
+co.gl
+com.gl
+edu.gl
+net.gl
+org.gl
+
+// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm
+gm
+
+// gn : http://psg.com/dns/gn/gn.txt
+// Submitted by registry <randy at psg.com> 2008-06-17
+gn
+ac.gn
+com.gn
+edu.gn
+gov.gn
+org.gn
+net.gn
+
+// gov : http://en.wikipedia.org/wiki/.gov
+gov
+
+// gp : http://www.nic.gp/index.php?lang=en
+gp
+com.gp
+net.gp
+mobi.gp
+edu.gp
+org.gp
+asso.gp
+
+// gq : http://en.wikipedia.org/wiki/.gq
+gq
+
+// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html
+// Submitted by registry <segred at ics.forth.gr> 2008-06-09
+gr
+com.gr
+edu.gr
+net.gr
+org.gr
+gov.gr
+
+// gs : http://en.wikipedia.org/wiki/.gs
+gs
+
+// gt : http://www.gt/politicas_de_registro.html
+gt
+com.gt
+edu.gt
+gob.gt
+ind.gt
+mil.gt
+net.gt
+org.gt
+
+// gu : http://gadao.gov.gu/registration.txt
+*.gu
+
+// gw : http://en.wikipedia.org/wiki/.gw
+gw
+
+// gy : http://en.wikipedia.org/wiki/.gy
+// http://registry.gy/
+gy
+co.gy
+com.gy
+net.gy
+
+// hk : https://www.hkdnr.hk
+// Submitted by registry <hk.tech at hkirc.hk> 2008-06-11
+hk
+com.hk
+edu.hk
+gov.hk
+idv.hk
+net.hk
+org.hk
+公司.hk
+教育.hk
+敎育.hk
+政府.hk
+個人.hk
+个人.hk
+箇人.hk
+網络.hk
+网络.hk
+组織.hk
+網絡.hk
+网絡.hk
+组织.hk
+組織.hk
+組织.hk
+
+// hm : http://en.wikipedia.org/wiki/.hm
+hm
+
+// hn : http://www.nic.hn/politicas/ps02,,05.html
+hn
+com.hn
+edu.hn
+org.hn
+net.hn
+mil.hn
+gob.hn
+
+// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf
+hr
+iz.hr
+from.hr
+name.hr
+com.hr
+
+// ht : http://www.nic.ht/info/charte.cfm
+ht
+com.ht
+shop.ht
+firm.ht
+info.ht
+adult.ht
+net.ht
+pro.ht
+org.ht
+med.ht
+art.ht
+coop.ht
+pol.ht
+asso.ht
+edu.ht
+rel.ht
+gouv.ht
+perso.ht
+
+// hu : http://www.domain.hu/domain/English/sld.html
+// Confirmed by registry <pasztor at iszt.hu> 2008-06-12
+hu
+co.hu
+info.hu
+org.hu
+priv.hu
+sport.hu
+tm.hu
+2000.hu
+agrar.hu
+bolt.hu
+casino.hu
+city.hu
+erotica.hu
+erotika.hu
+film.hu
+forum.hu
+games.hu
+hotel.hu
+ingatlan.hu
+jogasz.hu
+konyvelo.hu
+lakas.hu
+media.hu
+news.hu
+reklam.hu
+sex.hu
+shop.hu
+suli.hu
+szex.hu
+tozsde.hu
+utazas.hu
+video.hu
+
+// id : https://register.pandi.or.id/
+id
+ac.id
+biz.id
+co.id
+desa.id
+go.id
+mil.id
+my.id
+net.id
+or.id
+sch.id
+web.id
+
+// ie : http://en.wikipedia.org/wiki/.ie
+ie
+gov.ie
+
+// il : http://en.wikipedia.org/wiki/.il
+*.il
+
+// im : https://www.nic.im/
+// Submitted by registry <info at nic.im> 2013-11-15
+im
+ac.im
+co.im
+com.im
+ltd.co.im
+net.im
+org.im
+plc.co.im
+tt.im
+tv.im
+
+// in : http://en.wikipedia.org/wiki/.in
+// see also: https://registry.in/Policies
+// Please note, that nic.in is not an offical eTLD, but used by most
+// government institutions.
+in
+co.in
+firm.in
+net.in
+org.in
+gen.in
+ind.in
+nic.in
+ac.in
+edu.in
+res.in
+gov.in
+mil.in
+
+// info : http://en.wikipedia.org/wiki/.info
+info
+
+// int : http://en.wikipedia.org/wiki/.int
+// Confirmed by registry <iana-questions at icann.org> 2008-06-18
+int
+eu.int
+
+// io : http://www.nic.io/rules.html
+// list of other 2nd level tlds ?
+io
+com.io
+
+// iq : http://www.cmc.iq/english/iq/iqregister1.htm
+iq
+gov.iq
+edu.iq
+mil.iq
+com.iq
+org.iq
+net.iq
+
+// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules
+// Also see http://www.nic.ir/Internationalized_Domain_Names
+// Two <iran>.ir entries added at request of <tech-team at nic.ir>, 2010-04-16
+ir
+ac.ir
+co.ir
+gov.ir
+id.ir
+net.ir
+org.ir
+sch.ir
+// xn--mgba3a4f16a.ir (<iran>.ir, Persian YEH)
+ایران.ir
+// xn--mgba3a4fra.ir (<iran>.ir, Arabic YEH)
+ايران.ir
+
+// is : http://www.isnic.is/domain/rules.php
+// Confirmed by registry <marius at isgate.is> 2008-12-06
+is
+net.is
+com.is
+edu.is
+gov.is
+org.is
+int.is
+
+// it : http://en.wikipedia.org/wiki/.it
+it
+gov.it
+edu.it
+// Reserved geo-names:
+// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf
+// There is also a list of reserved geo-names corresponding to Italian municipalities
+// http://www.nic.it/documenti/appendice-c.pdf, but it is not included here.
+// Regions
+abr.it
+abruzzo.it
+aosta-valley.it
+aostavalley.it
+bas.it
+basilicata.it
+cal.it
+calabria.it
+cam.it
+campania.it
+emilia-romagna.it
+emiliaromagna.it
+emr.it
+friuli-v-giulia.it
+friuli-ve-giulia.it
+friuli-vegiulia.it
+friuli-venezia-giulia.it
+friuli-veneziagiulia.it
+friuli-vgiulia.it
+friuliv-giulia.it
+friulive-giulia.it
+friulivegiulia.it
+friulivenezia-giulia.it
+friuliveneziagiulia.it
+friulivgiulia.it
+fvg.it
+laz.it
+lazio.it
+lig.it
+liguria.it
+lom.it
+lombardia.it
+lombardy.it
+lucania.it
+mar.it
+marche.it
+mol.it
+molise.it
+piedmont.it
+piemonte.it
+pmn.it
+pug.it
+puglia.it
+sar.it
+sardegna.it
+sardinia.it
+sic.it
+sicilia.it
+sicily.it
+taa.it
+tos.it
+toscana.it
+trentino-a-adige.it
+trentino-aadige.it
+trentino-alto-adige.it
+trentino-altoadige.it
+trentino-s-tirol.it
+trentino-stirol.it
+trentino-sud-tirol.it
+trentino-sudtirol.it
+trentino-sued-tirol.it
+trentino-suedtirol.it
+trentinoa-adige.it
+trentinoaadige.it
+trentinoalto-adige.it
+trentinoaltoadige.it
+trentinos-tirol.it
+trentinostirol.it
+trentinosud-tirol.it
+trentinosudtirol.it
+trentinosued-tirol.it
+trentinosuedtirol.it
+tuscany.it
+umb.it
+umbria.it
+val-d-aosta.it
+val-daosta.it
+vald-aosta.it
+valdaosta.it
+valle-aosta.it
+valle-d-aosta.it
+valle-daosta.it
+valleaosta.it
+valled-aosta.it
+valledaosta.it
+vallee-aoste.it
+valleeaoste.it
+vao.it
+vda.it
+ven.it
+veneto.it
+// Provinces
+ag.it
+agrigento.it
+al.it
+alessandria.it
+alto-adige.it
+altoadige.it
+an.it
+ancona.it
+andria-barletta-trani.it
+andria-trani-barletta.it
+andriabarlettatrani.it
+andriatranibarletta.it
+ao.it
+aosta.it
+aoste.it
+ap.it
+aq.it
+aquila.it
+ar.it
+arezzo.it
+ascoli-piceno.it
+ascolipiceno.it
+asti.it
+at.it
+av.it
+avellino.it
+ba.it
+balsan.it
+bari.it
+barletta-trani-andria.it
+barlettatraniandria.it
+belluno.it
+benevento.it
+bergamo.it
+bg.it
+bi.it
+biella.it
+bl.it
+bn.it
+bo.it
+bologna.it
+bolzano.it
+bozen.it
+br.it
+brescia.it
+brindisi.it
+bs.it
+bt.it
+bz.it
+ca.it
+cagliari.it
+caltanissetta.it
+campidano-medio.it
+campidanomedio.it
+campobasso.it
+carbonia-iglesias.it
+carboniaiglesias.it
+carrara-massa.it
+carraramassa.it
+caserta.it
+catania.it
+catanzaro.it
+cb.it
+ce.it
+cesena-forli.it
+cesenaforli.it
+ch.it
+chieti.it
+ci.it
+cl.it
+cn.it
+co.it
+como.it
+cosenza.it
+cr.it
+cremona.it
+crotone.it
+cs.it
+ct.it
+cuneo.it
+cz.it
+dell-ogliastra.it
+dellogliastra.it
+en.it
+enna.it
+fc.it
+fe.it
+fermo.it
+ferrara.it
+fg.it
+fi.it
+firenze.it
+florence.it
+fm.it
+foggia.it
+forli-cesena.it
+forlicesena.it
+fr.it
+frosinone.it
+ge.it
+genoa.it
+genova.it
+go.it
+gorizia.it
+gr.it
+grosseto.it
+iglesias-carbonia.it
+iglesiascarbonia.it
+im.it
+imperia.it
+is.it
+isernia.it
+kr.it
+la-spezia.it
+laquila.it
+laspezia.it
+latina.it
+lc.it
+le.it
+lecce.it
+lecco.it
+li.it
+livorno.it
+lo.it
+lodi.it
+lt.it
+lu.it
+lucca.it
+macerata.it
+mantova.it
+massa-carrara.it
+massacarrara.it
+matera.it
+mb.it
+mc.it
+me.it
+medio-campidano.it
+mediocampidano.it
+messina.it
+mi.it
+milan.it
+milano.it
+mn.it
+mo.it
+modena.it
+monza-brianza.it
+monza-e-della-brianza.it
+monza.it
+monzabrianza.it
+monzaebrianza.it
+monzaedellabrianza.it
+ms.it
+mt.it
+na.it
+naples.it
+napoli.it
+no.it
+novara.it
+nu.it
+nuoro.it
+og.it
+ogliastra.it
+olbia-tempio.it
+olbiatempio.it
+or.it
+oristano.it
+ot.it
+pa.it
+padova.it
+padua.it
+palermo.it
+parma.it
+pavia.it
+pc.it
+pd.it
+pe.it
+perugia.it
+pesaro-urbino.it
+pesarourbino.it
+pescara.it
+pg.it
+pi.it
+piacenza.it
+pisa.it
+pistoia.it
+pn.it
+po.it
+pordenone.it
+potenza.it
+pr.it
+prato.it
+pt.it
+pu.it
+pv.it
+pz.it
+ra.it
+ragusa.it
+ravenna.it
+rc.it
+re.it
+reggio-calabria.it
+reggio-emilia.it
+reggiocalabria.it
+reggioemilia.it
+rg.it
+ri.it
+rieti.it
+rimini.it
+rm.it
+rn.it
+ro.it
+roma.it
+rome.it
+rovigo.it
+sa.it
+salerno.it
+sassari.it
+savona.it
+si.it
+siena.it
+siracusa.it
+so.it
+sondrio.it
+sp.it
+sr.it
+ss.it
+suedtirol.it
+sv.it
+ta.it
+taranto.it
+te.it
+tempio-olbia.it
+tempioolbia.it
+teramo.it
+terni.it
+tn.it
+to.it
+torino.it
+tp.it
+tr.it
+trani-andria-barletta.it
+trani-barletta-andria.it
+traniandriabarletta.it
+tranibarlettaandria.it
+trapani.it
+trentino.it
+trento.it
+treviso.it
+trieste.it
+ts.it
+turin.it
+tv.it
+ud.it
+udine.it
+urbino-pesaro.it
+urbinopesaro.it
+va.it
+varese.it
+vb.it
+vc.it
+ve.it
+venezia.it
+venice.it
+verbania.it
+vercelli.it
+verona.it
+vi.it
+vibo-valentia.it
+vibovalentia.it
+vicenza.it
+viterbo.it
+vr.it
+vs.it
+vt.it
+vv.it
+
+// je : http://www.channelisles.net/register-domains/
+// Confirmed by registry <nigel at channelisles.net> 2013-11-28
+je
+co.je
+net.je
+org.je
+
+// jm : http://www.com.jm/register.html
+*.jm
+
+// jo : http://www.dns.jo/Registration_policy.aspx
+jo
+com.jo
+org.jo
+net.jo
+edu.jo
+sch.jo
+gov.jo
+mil.jo
+name.jo
+
+// jobs : http://en.wikipedia.org/wiki/.jobs
+jobs
+
+// jp : http://en.wikipedia.org/wiki/.jp
+// http://jprs.co.jp/en/jpdomain.html
+// Submitted by registry <info at jprs.jp> 2014-10-30
+jp
+// jp organizational type names
+ac.jp
+ad.jp
+co.jp
+ed.jp
+go.jp
+gr.jp
+lg.jp
+ne.jp
+or.jp
+// jp prefecture type names
+aichi.jp
+akita.jp
+aomori.jp
+chiba.jp
+ehime.jp
+fukui.jp
+fukuoka.jp
+fukushima.jp
+gifu.jp
+gunma.jp
+hiroshima.jp
+hokkaido.jp
+hyogo.jp
+ibaraki.jp
+ishikawa.jp
+iwate.jp
+kagawa.jp
+kagoshima.jp
+kanagawa.jp
+kochi.jp
+kumamoto.jp
+kyoto.jp
+mie.jp
+miyagi.jp
+miyazaki.jp
+nagano.jp
+nagasaki.jp
+nara.jp
+niigata.jp
+oita.jp
+okayama.jp
+okinawa.jp
+osaka.jp
+saga.jp
+saitama.jp
+shiga.jp
+shimane.jp
+shizuoka.jp
+tochigi.jp
+tokushima.jp
+tokyo.jp
+tottori.jp
+toyama.jp
+wakayama.jp
+yamagata.jp
+yamaguchi.jp
+yamanashi.jp
+栃木.jp
+愛知.jp
+愛媛.jp
+兵庫.jp
+熊本.jp
+茨城.jp
+北海道.jp
+千葉.jp
+和歌山.jp
+長崎.jp
+長野.jp
+新潟.jp
+青森.jp
+静岡.jp
+東京.jp
+石川.jp
+埼玉.jp
+三重.jp
+京都.jp
+佐賀.jp
+大分.jp
+大阪.jp
+奈良.jp
+宮城.jp
+宮崎.jp
+富山.jp
+山口.jp
+山形.jp
+山梨.jp
+岩手.jp
+岐阜.jp
+岡山.jp
+島根.jp
+広島.jp
+徳島.jp
+沖縄.jp
+滋賀.jp
+神奈川.jp
+福井.jp
+福岡.jp
+福島.jp
+秋田.jp
+群馬.jp
+香川.jp
+高知.jp
+鳥取.jp
+鹿児島.jp
+// jp geographic type names
+// http://jprs.jp/doc/rule/saisoku-1.html
+*.kawasaki.jp
+*.kitakyushu.jp
+*.kobe.jp
+*.nagoya.jp
+*.sapporo.jp
+*.sendai.jp
+*.yokohama.jp
+!city.kawasaki.jp
+!city.kitakyushu.jp
+!city.kobe.jp
+!city.nagoya.jp
+!city.sapporo.jp
+!city.sendai.jp
+!city.yokohama.jp
+// 4th level registration
+aisai.aichi.jp
+ama.aichi.jp
+anjo.aichi.jp
+asuke.aichi.jp
+chiryu.aichi.jp
+chita.aichi.jp
+fuso.aichi.jp
+gamagori.aichi.jp
+handa.aichi.jp
+hazu.aichi.jp
+hekinan.aichi.jp
+higashiura.aichi.jp
+ichinomiya.aichi.jp
+inazawa.aichi.jp
+inuyama.aichi.jp
+isshiki.aichi.jp
+iwakura.aichi.jp
+kanie.aichi.jp
+kariya.aichi.jp
+kasugai.aichi.jp
+kira.aichi.jp
+kiyosu.aichi.jp
+komaki.aichi.jp
+konan.aichi.jp
+kota.aichi.jp
+mihama.aichi.jp
+miyoshi.aichi.jp
+nishio.aichi.jp
+nisshin.aichi.jp
+obu.aichi.jp
+oguchi.aichi.jp
+oharu.aichi.jp
+okazaki.aichi.jp
+owariasahi.aichi.jp
+seto.aichi.jp
+shikatsu.aichi.jp
+shinshiro.aichi.jp
+shitara.aichi.jp
+tahara.aichi.jp
+takahama.aichi.jp
+tobishima.aichi.jp
+toei.aichi.jp
+togo.aichi.jp
+tokai.aichi.jp
+tokoname.aichi.jp
+toyoake.aichi.jp
+toyohashi.aichi.jp
+toyokawa.aichi.jp
+toyone.aichi.jp
+toyota.aichi.jp
+tsushima.aichi.jp
+yatomi.aichi.jp
+akita.akita.jp
+daisen.akita.jp
+fujisato.akita.jp
+gojome.akita.jp
+hachirogata.akita.jp
+happou.akita.jp
+higashinaruse.akita.jp
+honjo.akita.jp
+honjyo.akita.jp
+ikawa.akita.jp
+kamikoani.akita.jp
+kamioka.akita.jp
+katagami.akita.jp
+kazuno.akita.jp
+kitaakita.akita.jp
+kosaka.akita.jp
+kyowa.akita.jp
+misato.akita.jp
+mitane.akita.jp
+moriyoshi.akita.jp
+nikaho.akita.jp
+noshiro.akita.jp
+odate.akita.jp
+oga.akita.jp
+ogata.akita.jp
+semboku.akita.jp
+yokote.akita.jp
+yurihonjo.akita.jp
+aomori.aomori.jp
+gonohe.aomori.jp
+hachinohe.aomori.jp
+hashikami.aomori.jp
+hiranai.aomori.jp
+hirosaki.aomori.jp
+itayanagi.aomori.jp
+kuroishi.aomori.jp
+misawa.aomori.jp
+mutsu.aomori.jp
+nakadomari.aomori.jp
+noheji.aomori.jp
+oirase.aomori.jp
+owani.aomori.jp
+rokunohe.aomori.jp
+sannohe.aomori.jp
+shichinohe.aomori.jp
+shingo.aomori.jp
+takko.aomori.jp
+towada.aomori.jp
+tsugaru.aomori.jp
+tsuruta.aomori.jp
+abiko.chiba.jp
+asahi.chiba.jp
+chonan.chiba.jp
+chosei.chiba.jp
+choshi.chiba.jp
+chuo.chiba.jp
+funabashi.chiba.jp
+futtsu.chiba.jp
+hanamigawa.chiba.jp
+ichihara.chiba.jp
+ichikawa.chiba.jp
+ichinomiya.chiba.jp
+inzai.chiba.jp
+isumi.chiba.jp
+kamagaya.chiba.jp
+kamogawa.chiba.jp
+kashiwa.chiba.jp
+katori.chiba.jp
+katsuura.chiba.jp
+kimitsu.chiba.jp
+kisarazu.chiba.jp
+kozaki.chiba.jp
+kujukuri.chiba.jp
+kyonan.chiba.jp
+matsudo.chiba.jp
+midori.chiba.jp
+mihama.chiba.jp
+minamiboso.chiba.jp
+mobara.chiba.jp
+mutsuzawa.chiba.jp
+nagara.chiba.jp
+nagareyama.chiba.jp
+narashino.chiba.jp
+narita.chiba.jp
+noda.chiba.jp
+oamishirasato.chiba.jp
+omigawa.chiba.jp
+onjuku.chiba.jp
+otaki.chiba.jp
+sakae.chiba.jp
+sakura.chiba.jp
+shimofusa.chiba.jp
+shirako.chiba.jp
+shiroi.chiba.jp
+shisui.chiba.jp
+sodegaura.chiba.jp
+sosa.chiba.jp
+tako.chiba.jp
+tateyama.chiba.jp
+togane.chiba.jp
+tohnosho.chiba.jp
+tomisato.chiba.jp
+urayasu.chiba.jp
+yachimata.chiba.jp
+yachiyo.chiba.jp
+yokaichiba.chiba.jp
+yokoshibahikari.chiba.jp
+yotsukaido.chiba.jp
+ainan.ehime.jp
+honai.ehime.jp
+ikata.ehime.jp
+imabari.ehime.jp
+iyo.ehime.jp
+kamijima.ehime.jp
+kihoku.ehime.jp
+kumakogen.ehime.jp
+masaki.ehime.jp
+matsuno.ehime.jp
+matsuyama.ehime.jp
+namikata.ehime.jp
+niihama.ehime.jp
+ozu.ehime.jp
+saijo.ehime.jp
+seiyo.ehime.jp
+shikokuchuo.ehime.jp
+tobe.ehime.jp
+toon.ehime.jp
+uchiko.ehime.jp
+uwajima.ehime.jp
+yawatahama.ehime.jp
+echizen.fukui.jp
+eiheiji.fukui.jp
+fukui.fukui.jp
+ikeda.fukui.jp
+katsuyama.fukui.jp
+mihama.fukui.jp
+minamiechizen.fukui.jp
+obama.fukui.jp
+ohi.fukui.jp
+ono.fukui.jp
+sabae.fukui.jp
+sakai.fukui.jp
+takahama.fukui.jp
+tsuruga.fukui.jp
+wakasa.fukui.jp
+ashiya.fukuoka.jp
+buzen.fukuoka.jp
+chikugo.fukuoka.jp
+chikuho.fukuoka.jp
+chikujo.fukuoka.jp
+chikushino.fukuoka.jp
+chikuzen.fukuoka.jp
+chuo.fukuoka.jp
+dazaifu.fukuoka.jp
+fukuchi.fukuoka.jp
+hakata.fukuoka.jp
+higashi.fukuoka.jp
+hirokawa.fukuoka.jp
+hisayama.fukuoka.jp
+iizuka.fukuoka.jp
+inatsuki.fukuoka.jp
+kaho.fukuoka.jp
+kasuga.fukuoka.jp
+kasuya.fukuoka.jp
+kawara.fukuoka.jp
+keisen.fukuoka.jp
+koga.fukuoka.jp
+kurate.fukuoka.jp
+kurogi.fukuoka.jp
+kurume.fukuoka.jp
+minami.fukuoka.jp
+miyako.fukuoka.jp
+miyama.fukuoka.jp
+miyawaka.fukuoka.jp
+mizumaki.fukuoka.jp
+munakata.fukuoka.jp
+nakagawa.fukuoka.jp
+nakama.fukuoka.jp
+nishi.fukuoka.jp
+nogata.fukuoka.jp
+ogori.fukuoka.jp
+okagaki.fukuoka.jp
+okawa.fukuoka.jp
+oki.fukuoka.jp
+omuta.fukuoka.jp
+onga.fukuoka.jp
+onojo.fukuoka.jp
+oto.fukuoka.jp
+saigawa.fukuoka.jp
+sasaguri.fukuoka.jp
+shingu.fukuoka.jp
+shinyoshitomi.fukuoka.jp
+shonai.fukuoka.jp
+soeda.fukuoka.jp
+sue.fukuoka.jp
+tachiarai.fukuoka.jp
+tagawa.fukuoka.jp
+takata.fukuoka.jp
+toho.fukuoka.jp
+toyotsu.fukuoka.jp
+tsuiki.fukuoka.jp
+ukiha.fukuoka.jp
+umi.fukuoka.jp
+usui.fukuoka.jp
+yamada.fukuoka.jp
+yame.fukuoka.jp
+yanagawa.fukuoka.jp
+yukuhashi.fukuoka.jp
+aizubange.fukushima.jp
+aizumisato.fukushima.jp
+aizuwakamatsu.fukushima.jp
+asakawa.fukushima.jp
+bandai.fukushima.jp
+date.fukushima.jp
+fukushima.fukushima.jp
+furudono.fukushima.jp
+futaba.fukushima.jp
+hanawa.fukushima.jp
+higashi.fukushima.jp
+hirata.fukushima.jp
+hirono.fukushima.jp
+iitate.fukushima.jp
+inawashiro.fukushima.jp
+ishikawa.fukushima.jp
+iwaki.fukushima.jp
+izumizaki.fukushima.jp
+kagamiishi.fukushima.jp
+kaneyama.fukushima.jp
+kawamata.fukushima.jp
+kitakata.fukushima.jp
+kitashiobara.fukushima.jp
+koori.fukushima.jp
+koriyama.fukushima.jp
+kunimi.fukushima.jp
+miharu.fukushima.jp
+mishima.fukushima.jp
+namie.fukushima.jp
+nango.fukushima.jp
+nishiaizu.fukushima.jp
+nishigo.fukushima.jp
+okuma.fukushima.jp
+omotego.fukushima.jp
+ono.fukushima.jp
+otama.fukushima.jp
+samegawa.fukushima.jp
+shimogo.fukushima.jp
+shirakawa.fukushima.jp
+showa.fukushima.jp
+soma.fukushima.jp
+sukagawa.fukushima.jp
+taishin.fukushima.jp
+tamakawa.fukushima.jp
+tanagura.fukushima.jp
+tenei.fukushima.jp
+yabuki.fukushima.jp
+yamato.fukushima.jp
+yamatsuri.fukushima.jp
+yanaizu.fukushima.jp
+yugawa.fukushima.jp
+anpachi.gifu.jp
+ena.gifu.jp
+gifu.gifu.jp
+ginan.gifu.jp
+godo.gifu.jp
+gujo.gifu.jp
+hashima.gifu.jp
+hichiso.gifu.jp
+hida.gifu.jp
+higashishirakawa.gifu.jp
+ibigawa.gifu.jp
+ikeda.gifu.jp
+kakamigahara.gifu.jp
+kani.gifu.jp
+kasahara.gifu.jp
+kasamatsu.gifu.jp
+kawaue.gifu.jp
+kitagata.gifu.jp
+mino.gifu.jp
+minokamo.gifu.jp
+mitake.gifu.jp
+mizunami.gifu.jp
+motosu.gifu.jp
+nakatsugawa.gifu.jp
+ogaki.gifu.jp
+sakahogi.gifu.jp
+seki.gifu.jp
+sekigahara.gifu.jp
+shirakawa.gifu.jp
+tajimi.gifu.jp
+takayama.gifu.jp
+tarui.gifu.jp
+toki.gifu.jp
+tomika.gifu.jp
+wanouchi.gifu.jp
+yamagata.gifu.jp
+yaotsu.gifu.jp
+yoro.gifu.jp
+annaka.gunma.jp
+chiyoda.gunma.jp
+fujioka.gunma.jp
+higashiagatsuma.gunma.jp
+isesaki.gunma.jp
+itakura.gunma.jp
+kanna.gunma.jp
+kanra.gunma.jp
+katashina.gunma.jp
+kawaba.gunma.jp
+kiryu.gunma.jp
+kusatsu.gunma.jp
+maebashi.gunma.jp
+meiwa.gunma.jp
+midori.gunma.jp
+minakami.gunma.jp
+naganohara.gunma.jp
+nakanojo.gunma.jp
+nanmoku.gunma.jp
+numata.gunma.jp
+oizumi.gunma.jp
+ora.gunma.jp
+ota.gunma.jp
+shibukawa.gunma.jp
+shimonita.gunma.jp
+shinto.gunma.jp
+showa.gunma.jp
+takasaki.gunma.jp
+takayama.gunma.jp
+tamamura.gunma.jp
+tatebayashi.gunma.jp
+tomioka.gunma.jp
+tsukiyono.gunma.jp
+tsumagoi.gunma.jp
+ueno.gunma.jp
+yoshioka.gunma.jp
+asaminami.hiroshima.jp
+daiwa.hiroshima.jp
+etajima.hiroshima.jp
+fuchu.hiroshima.jp
+fukuyama.hiroshima.jp
+hatsukaichi.hiroshima.jp
+higashihiroshima.hiroshima.jp
+hongo.hiroshima.jp
+jinsekikogen.hiroshima.jp
+kaita.hiroshima.jp
+kui.hiroshima.jp
+kumano.hiroshima.jp
+kure.hiroshima.jp
+mihara.hiroshima.jp
+miyoshi.hiroshima.jp
+naka.hiroshima.jp
+onomichi.hiroshima.jp
+osakikamijima.hiroshima.jp
+otake.hiroshima.jp
+saka.hiroshima.jp
+sera.hiroshima.jp
+seranishi.hiroshima.jp
+shinichi.hiroshima.jp
+shobara.hiroshima.jp
+takehara.hiroshima.jp
+abashiri.hokkaido.jp
+abira.hokkaido.jp
+aibetsu.hokkaido.jp
+akabira.hokkaido.jp
+akkeshi.hokkaido.jp
+asahikawa.hokkaido.jp
+ashibetsu.hokkaido.jp
+ashoro.hokkaido.jp
+assabu.hokkaido.jp
+atsuma.hokkaido.jp
+bibai.hokkaido.jp
+biei.hokkaido.jp
+bifuka.hokkaido.jp
+bihoro.hokkaido.jp
+biratori.hokkaido.jp
+chippubetsu.hokkaido.jp
+chitose.hokkaido.jp
+date.hokkaido.jp
+ebetsu.hokkaido.jp
+embetsu.hokkaido.jp
+eniwa.hokkaido.jp
+erimo.hokkaido.jp
+esan.hokkaido.jp
+esashi.hokkaido.jp
+fukagawa.hokkaido.jp
+fukushima.hokkaido.jp
+furano.hokkaido.jp
+furubira.hokkaido.jp
+haboro.hokkaido.jp
+hakodate.hokkaido.jp
+hamatonbetsu.hokkaido.jp
+hidaka.hokkaido.jp
+higashikagura.hokkaido.jp
+higashikawa.hokkaido.jp
+hiroo.hokkaido.jp
+hokuryu.hokkaido.jp
+hokuto.hokkaido.jp
+honbetsu.hokkaido.jp
+horokanai.hokkaido.jp
+horonobe.hokkaido.jp
+ikeda.hokkaido.jp
+imakane.hokkaido.jp
+ishikari.hokkaido.jp
+iwamizawa.hokkaido.jp
+iwanai.hokkaido.jp
+kamifurano.hokkaido.jp
+kamikawa.hokkaido.jp
+kamishihoro.hokkaido.jp
+kamisunagawa.hokkaido.jp
+kamoenai.hokkaido.jp
+kayabe.hokkaido.jp
+kembuchi.hokkaido.jp
+kikonai.hokkaido.jp
+kimobetsu.hokkaido.jp
+kitahiroshima.hokkaido.jp
+kitami.hokkaido.jp
+kiyosato.hokkaido.jp
+koshimizu.hokkaido.jp
+kunneppu.hokkaido.jp
+kuriyama.hokkaido.jp
+kuromatsunai.hokkaido.jp
+kushiro.hokkaido.jp
+kutchan.hokkaido.jp
+kyowa.hokkaido.jp
+mashike.hokkaido.jp
+matsumae.hokkaido.jp
+mikasa.hokkaido.jp
+minamifurano.hokkaido.jp
+mombetsu.hokkaido.jp
+moseushi.hokkaido.jp
+mukawa.hokkaido.jp
+muroran.hokkaido.jp
+naie.hokkaido.jp
+nakagawa.hokkaido.jp
+nakasatsunai.hokkaido.jp
+nakatombetsu.hokkaido.jp
+nanae.hokkaido.jp
+nanporo.hokkaido.jp
+nayoro.hokkaido.jp
+nemuro.hokkaido.jp
+niikappu.hokkaido.jp
+niki.hokkaido.jp
+nishiokoppe.hokkaido.jp
+noboribetsu.hokkaido.jp
+numata.hokkaido.jp
+obihiro.hokkaido.jp
+obira.hokkaido.jp
+oketo.hokkaido.jp
+okoppe.hokkaido.jp
+otaru.hokkaido.jp
+otobe.hokkaido.jp
+otofuke.hokkaido.jp
+otoineppu.hokkaido.jp
+oumu.hokkaido.jp
+ozora.hokkaido.jp
+pippu.hokkaido.jp
+rankoshi.hokkaido.jp
+rebun.hokkaido.jp
+rikubetsu.hokkaido.jp
+rishiri.hokkaido.jp
+rishirifuji.hokkaido.jp
+saroma.hokkaido.jp
+sarufutsu.hokkaido.jp
+shakotan.hokkaido.jp
+shari.hokkaido.jp
+shibecha.hokkaido.jp
+shibetsu.hokkaido.jp
+shikabe.hokkaido.jp
+shikaoi.hokkaido.jp
+shimamaki.hokkaido.jp
+shimizu.hokkaido.jp
+shimokawa.hokkaido.jp
+shinshinotsu.hokkaido.jp
+shintoku.hokkaido.jp
+shiranuka.hokkaido.jp
+shiraoi.hokkaido.jp
+shiriuchi.hokkaido.jp
+sobetsu.hokkaido.jp
+sunagawa.hokkaido.jp
+taiki.hokkaido.jp
+takasu.hokkaido.jp
+takikawa.hokkaido.jp
+takinoue.hokkaido.jp
+teshikaga.hokkaido.jp
+tobetsu.hokkaido.jp
+tohma.hokkaido.jp
+tomakomai.hokkaido.jp
+tomari.hokkaido.jp
+toya.hokkaido.jp
+toyako.hokkaido.jp
+toyotomi.hokkaido.jp
+toyoura.hokkaido.jp
+tsubetsu.hokkaido.jp
+tsukigata.hokkaido.jp
+urakawa.hokkaido.jp
+urausu.hokkaido.jp
+uryu.hokkaido.jp
+utashinai.hokkaido.jp
+wakkanai.hokkaido.jp
+wassamu.hokkaido.jp
+yakumo.hokkaido.jp
+yoichi.hokkaido.jp
+aioi.hyogo.jp
+akashi.hyogo.jp
+ako.hyogo.jp
+amagasaki.hyogo.jp
+aogaki.hyogo.jp
+asago.hyogo.jp
+ashiya.hyogo.jp
+awaji.hyogo.jp
+fukusaki.hyogo.jp
+goshiki.hyogo.jp
+harima.hyogo.jp
+himeji.hyogo.jp
+ichikawa.hyogo.jp
+inagawa.hyogo.jp
+itami.hyogo.jp
+kakogawa.hyogo.jp
+kamigori.hyogo.jp
+kamikawa.hyogo.jp
+kasai.hyogo.jp
+kasuga.hyogo.jp
+kawanishi.hyogo.jp
+miki.hyogo.jp
+minamiawaji.hyogo.jp
+nishinomiya.hyogo.jp
+nishiwaki.hyogo.jp
+ono.hyogo.jp
+sanda.hyogo.jp
+sannan.hyogo.jp
+sasayama.hyogo.jp
+sayo.hyogo.jp
+shingu.hyogo.jp
+shinonsen.hyogo.jp
+shiso.hyogo.jp
+sumoto.hyogo.jp
+taishi.hyogo.jp
+taka.hyogo.jp
+takarazuka.hyogo.jp
+takasago.hyogo.jp
+takino.hyogo.jp
+tamba.hyogo.jp
+tatsuno.hyogo.jp
+toyooka.hyogo.jp
+yabu.hyogo.jp
+yashiro.hyogo.jp
+yoka.hyogo.jp
+yokawa.hyogo.jp
+ami.ibaraki.jp
+asahi.ibaraki.jp
+bando.ibaraki.jp
+chikusei.ibaraki.jp
+daigo.ibaraki.jp
+fujishiro.ibaraki.jp
+hitachi.ibaraki.jp
+hitachinaka.ibaraki.jp
+hitachiomiya.ibaraki.jp
+hitachiota.ibaraki.jp
+ibaraki.ibaraki.jp
+ina.ibaraki.jp
+inashiki.ibaraki.jp
+itako.ibaraki.jp
+iwama.ibaraki.jp
+joso.ibaraki.jp
+kamisu.ibaraki.jp
+kasama.ibaraki.jp
+kashima.ibaraki.jp
+kasumigaura.ibaraki.jp
+koga.ibaraki.jp
+miho.ibaraki.jp
+mito.ibaraki.jp
+moriya.ibaraki.jp
+naka.ibaraki.jp
+namegata.ibaraki.jp
+oarai.ibaraki.jp
+ogawa.ibaraki.jp
+omitama.ibaraki.jp
+ryugasaki.ibaraki.jp
+sakai.ibaraki.jp
+sakuragawa.ibaraki.jp
+shimodate.ibaraki.jp
+shimotsuma.ibaraki.jp
+shirosato.ibaraki.jp
+sowa.ibaraki.jp
+suifu.ibaraki.jp
+takahagi.ibaraki.jp
+tamatsukuri.ibaraki.jp
+tokai.ibaraki.jp
+tomobe.ibaraki.jp
+tone.ibaraki.jp
+toride.ibaraki.jp
+tsuchiura.ibaraki.jp
+tsukuba.ibaraki.jp
+uchihara.ibaraki.jp
+ushiku.ibaraki.jp
+yachiyo.ibaraki.jp
+yamagata.ibaraki.jp
+yawara.ibaraki.jp
+yuki.ibaraki.jp
+anamizu.ishikawa.jp
+hakui.ishikawa.jp
+hakusan.ishikawa.jp
+kaga.ishikawa.jp
+kahoku.ishikawa.jp
+kanazawa.ishikawa.jp
+kawakita.ishikawa.jp
+komatsu.ishikawa.jp
+nakanoto.ishikawa.jp
+nanao.ishikawa.jp
+nomi.ishikawa.jp
+nonoichi.ishikawa.jp
+noto.ishikawa.jp
+shika.ishikawa.jp
+suzu.ishikawa.jp
+tsubata.ishikawa.jp
+tsurugi.ishikawa.jp
+uchinada.ishikawa.jp
+wajima.ishikawa.jp
+fudai.iwate.jp
+fujisawa.iwate.jp
+hanamaki.iwate.jp
+hiraizumi.iwate.jp
+hirono.iwate.jp
+ichinohe.iwate.jp
+ichinoseki.iwate.jp
+iwaizumi.iwate.jp
+iwate.iwate.jp
+joboji.iwate.jp
+kamaishi.iwate.jp
+kanegasaki.iwate.jp
+karumai.iwate.jp
+kawai.iwate.jp
+kitakami.iwate.jp
+kuji.iwate.jp
+kunohe.iwate.jp
+kuzumaki.iwate.jp
+miyako.iwate.jp
+mizusawa.iwate.jp
+morioka.iwate.jp
+ninohe.iwate.jp
+noda.iwate.jp
+ofunato.iwate.jp
+oshu.iwate.jp
+otsuchi.iwate.jp
+rikuzentakata.iwate.jp
+shiwa.iwate.jp
+shizukuishi.iwate.jp
+sumita.iwate.jp
+tanohata.iwate.jp
+tono.iwate.jp
+yahaba.iwate.jp
+yamada.iwate.jp
+ayagawa.kagawa.jp
+higashikagawa.kagawa.jp
+kanonji.kagawa.jp
+kotohira.kagawa.jp
+manno.kagawa.jp
+marugame.kagawa.jp
+mitoyo.kagawa.jp
+naoshima.kagawa.jp
+sanuki.kagawa.jp
+tadotsu.kagawa.jp
+takamatsu.kagawa.jp
+tonosho.kagawa.jp
+uchinomi.kagawa.jp
+utazu.kagawa.jp
+zentsuji.kagawa.jp
+akune.kagoshima.jp
+amami.kagoshima.jp
+hioki.kagoshima.jp
+isa.kagoshima.jp
+isen.kagoshima.jp
+izumi.kagoshima.jp
+kagoshima.kagoshima.jp
+kanoya.kagoshima.jp
+kawanabe.kagoshima.jp
+kinko.kagoshima.jp
+kouyama.kagoshima.jp
+makurazaki.kagoshima.jp
+matsumoto.kagoshima.jp
+minamitane.kagoshima.jp
+nakatane.kagoshima.jp
+nishinoomote.kagoshima.jp
+satsumasendai.kagoshima.jp
+soo.kagoshima.jp
+tarumizu.kagoshima.jp
+yusui.kagoshima.jp
+aikawa.kanagawa.jp
+atsugi.kanagawa.jp
+ayase.kanagawa.jp
+chigasaki.kanagawa.jp
+ebina.kanagawa.jp
+fujisawa.kanagawa.jp
+hadano.kanagawa.jp
+hakone.kanagawa.jp
+hiratsuka.kanagawa.jp
+isehara.kanagawa.jp
+kaisei.kanagawa.jp
+kamakura.kanagawa.jp
+kiyokawa.kanagawa.jp
+matsuda.kanagawa.jp
+minamiashigara.kanagawa.jp
+miura.kanagawa.jp
+nakai.kanagawa.jp
+ninomiya.kanagawa.jp
+odawara.kanagawa.jp
+oi.kanagawa.jp
+oiso.kanagawa.jp
+sagamihara.kanagawa.jp
+samukawa.kanagawa.jp
+tsukui.kanagawa.jp
+yamakita.kanagawa.jp
+yamato.kanagawa.jp
+yokosuka.kanagawa.jp
+yugawara.kanagawa.jp
+zama.kanagawa.jp
+zushi.kanagawa.jp
+aki.kochi.jp
+geisei.kochi.jp
+hidaka.kochi.jp
+higashitsuno.kochi.jp
+ino.kochi.jp
+kagami.kochi.jp
+kami.kochi.jp
+kitagawa.kochi.jp
+kochi.kochi.jp
+mihara.kochi.jp
+motoyama.kochi.jp
+muroto.kochi.jp
+nahari.kochi.jp
+nakamura.kochi.jp
+nankoku.kochi.jp
+nishitosa.kochi.jp
+niyodogawa.kochi.jp
+ochi.kochi.jp
+okawa.kochi.jp
+otoyo.kochi.jp
+otsuki.kochi.jp
+sakawa.kochi.jp
+sukumo.kochi.jp
+susaki.kochi.jp
+tosa.kochi.jp
+tosashimizu.kochi.jp
+toyo.kochi.jp
+tsuno.kochi.jp
+umaji.kochi.jp
+yasuda.kochi.jp
+yusuhara.kochi.jp
+amakusa.kumamoto.jp
+arao.kumamoto.jp
+aso.kumamoto.jp
+choyo.kumamoto.jp
+gyokuto.kumamoto.jp
+hitoyoshi.kumamoto.jp
+kamiamakusa.kumamoto.jp
+kashima.kumamoto.jp
+kikuchi.kumamoto.jp
+kosa.kumamoto.jp
+kumamoto.kumamoto.jp
+mashiki.kumamoto.jp
+mifune.kumamoto.jp
+minamata.kumamoto.jp
+minamioguni.kumamoto.jp
+nagasu.kumamoto.jp
+nishihara.kumamoto.jp
+oguni.kumamoto.jp
+ozu.kumamoto.jp
+sumoto.kumamoto.jp
+takamori.kumamoto.jp
+uki.kumamoto.jp
+uto.kumamoto.jp
+yamaga.kumamoto.jp
+yamato.kumamoto.jp
+yatsushiro.kumamoto.jp
+ayabe.kyoto.jp
+fukuchiyama.kyoto.jp
+higashiyama.kyoto.jp
+ide.kyoto.jp
+ine.kyoto.jp
+joyo.kyoto.jp
+kameoka.kyoto.jp
+kamo.kyoto.jp
+kita.kyoto.jp
+kizu.kyoto.jp
+kumiyama.kyoto.jp
+kyotamba.kyoto.jp
+kyotanabe.kyoto.jp
+kyotango.kyoto.jp
+maizuru.kyoto.jp
+minami.kyoto.jp
+minamiyamashiro.kyoto.jp
+miyazu.kyoto.jp
+muko.kyoto.jp
+nagaokakyo.kyoto.jp
+nakagyo.kyoto.jp
+nantan.kyoto.jp
+oyamazaki.kyoto.jp
+sakyo.kyoto.jp
+seika.kyoto.jp
+tanabe.kyoto.jp
+uji.kyoto.jp
+ujitawara.kyoto.jp
+wazuka.kyoto.jp
+yamashina.kyoto.jp
+yawata.kyoto.jp
+asahi.mie.jp
+inabe.mie.jp
+ise.mie.jp
+kameyama.mie.jp
+kawagoe.mie.jp
+kiho.mie.jp
+kisosaki.mie.jp
+kiwa.mie.jp
+komono.mie.jp
+kumano.mie.jp
+kuwana.mie.jp
+matsusaka.mie.jp
+meiwa.mie.jp
+mihama.mie.jp
+minamiise.mie.jp
+misugi.mie.jp
+miyama.mie.jp
+nabari.mie.jp
+shima.mie.jp
+suzuka.mie.jp
+tado.mie.jp
+taiki.mie.jp
+taki.mie.jp
+tamaki.mie.jp
+toba.mie.jp
+tsu.mie.jp
+udono.mie.jp
+ureshino.mie.jp
+watarai.mie.jp
+yokkaichi.mie.jp
+furukawa.miyagi.jp
+higashimatsushima.miyagi.jp
+ishinomaki.miyagi.jp
+iwanuma.miyagi.jp
+kakuda.miyagi.jp
+kami.miyagi.jp
+kawasaki.miyagi.jp
+kesennuma.miyagi.jp
+marumori.miyagi.jp
+matsushima.miyagi.jp
+minamisanriku.miyagi.jp
+misato.miyagi.jp
+murata.miyagi.jp
+natori.miyagi.jp
+ogawara.miyagi.jp
+ohira.miyagi.jp
+onagawa.miyagi.jp
+osaki.miyagi.jp
+rifu.miyagi.jp
+semine.miyagi.jp
+shibata.miyagi.jp
+shichikashuku.miyagi.jp
+shikama.miyagi.jp
+shiogama.miyagi.jp
+shiroishi.miyagi.jp
+tagajo.miyagi.jp
+taiwa.miyagi.jp
+tome.miyagi.jp
+tomiya.miyagi.jp
+wakuya.miyagi.jp
+watari.miyagi.jp
+yamamoto.miyagi.jp
+zao.miyagi.jp
+aya.miyazaki.jp
+ebino.miyazaki.jp
+gokase.miyazaki.jp
+hyuga.miyazaki.jp
+kadogawa.miyazaki.jp
+kawaminami.miyazaki.jp
+kijo.miyazaki.jp
+kitagawa.miyazaki.jp
+kitakata.miyazaki.jp
+kitaura.miyazaki.jp
+kobayashi.miyazaki.jp
+kunitomi.miyazaki.jp
+kushima.miyazaki.jp
+mimata.miyazaki.jp
+miyakonojo.miyazaki.jp
+miyazaki.miyazaki.jp
+morotsuka.miyazaki.jp
+nichinan.miyazaki.jp
+nishimera.miyazaki.jp
+nobeoka.miyazaki.jp
+saito.miyazaki.jp
+shiiba.miyazaki.jp
+shintomi.miyazaki.jp
+takaharu.miyazaki.jp
+takanabe.miyazaki.jp
+takazaki.miyazaki.jp
+tsuno.miyazaki.jp
+achi.nagano.jp
+agematsu.nagano.jp
+anan.nagano.jp
+aoki.nagano.jp
+asahi.nagano.jp
+azumino.nagano.jp
+chikuhoku.nagano.jp
+chikuma.nagano.jp
+chino.nagano.jp
+fujimi.nagano.jp
+hakuba.nagano.jp
+hara.nagano.jp
+hiraya.nagano.jp
+iida.nagano.jp
+iijima.nagano.jp
+iiyama.nagano.jp
+iizuna.nagano.jp
+ikeda.nagano.jp
+ikusaka.nagano.jp
+ina.nagano.jp
+karuizawa.nagano.jp
+kawakami.nagano.jp
+kiso.nagano.jp
+kisofukushima.nagano.jp
+kitaaiki.nagano.jp
+komagane.nagano.jp
+komoro.nagano.jp
+matsukawa.nagano.jp
+matsumoto.nagano.jp
+miasa.nagano.jp
+minamiaiki.nagano.jp
+minamimaki.nagano.jp
+minamiminowa.nagano.jp
+minowa.nagano.jp
+miyada.nagano.jp
+miyota.nagano.jp
+mochizuki.nagano.jp
+nagano.nagano.jp
+nagawa.nagano.jp
+nagiso.nagano.jp
+nakagawa.nagano.jp
+nakano.nagano.jp
+nozawaonsen.nagano.jp
+obuse.nagano.jp
+ogawa.nagano.jp
+okaya.nagano.jp
+omachi.nagano.jp
+omi.nagano.jp
+ookuwa.nagano.jp
+ooshika.nagano.jp
+otaki.nagano.jp
+otari.nagano.jp
+sakae.nagano.jp
+sakaki.nagano.jp
+saku.nagano.jp
+sakuho.nagano.jp
+shimosuwa.nagano.jp
+shinanomachi.nagano.jp
+shiojiri.nagano.jp
+suwa.nagano.jp
+suzaka.nagano.jp
+takagi.nagano.jp
+takamori.nagano.jp
+takayama.nagano.jp
+tateshina.nagano.jp
+tatsuno.nagano.jp
+togakushi.nagano.jp
+togura.nagano.jp
+tomi.nagano.jp
+ueda.nagano.jp
+wada.nagano.jp
+yamagata.nagano.jp
+yamanouchi.nagano.jp
+yasaka.nagano.jp
+yasuoka.nagano.jp
+chijiwa.nagasaki.jp
+futsu.nagasaki.jp
+goto.nagasaki.jp
+hasami.nagasaki.jp
+hirado.nagasaki.jp
+iki.nagasaki.jp
+isahaya.nagasaki.jp
+kawatana.nagasaki.jp
+kuchinotsu.nagasaki.jp
+matsuura.nagasaki.jp
+nagasaki.nagasaki.jp
+obama.nagasaki.jp
+omura.nagasaki.jp
+oseto.nagasaki.jp
+saikai.nagasaki.jp
+sasebo.nagasaki.jp
+seihi.nagasaki.jp
+shimabara.nagasaki.jp
+shinkamigoto.nagasaki.jp
+togitsu.nagasaki.jp
+tsushima.nagasaki.jp
+unzen.nagasaki.jp
+ando.nara.jp
+gose.nara.jp
+heguri.nara.jp
+higashiyoshino.nara.jp
+ikaruga.nara.jp
+ikoma.nara.jp
+kamikitayama.nara.jp
+kanmaki.nara.jp
+kashiba.nara.jp
+kashihara.nara.jp
+katsuragi.nara.jp
+kawai.nara.jp
+kawakami.nara.jp
+kawanishi.nara.jp
+koryo.nara.jp
+kurotaki.nara.jp
+mitsue.nara.jp
+miyake.nara.jp
+nara.nara.jp
+nosegawa.nara.jp
+oji.nara.jp
+ouda.nara.jp
+oyodo.nara.jp
+sakurai.nara.jp
+sango.nara.jp
+shimoichi.nara.jp
+shimokitayama.nara.jp
+shinjo.nara.jp
+soni.nara.jp
+takatori.nara.jp
+tawaramoto.nara.jp
+tenkawa.nara.jp
+tenri.nara.jp
+uda.nara.jp
+yamatokoriyama.nara.jp
+yamatotakada.nara.jp
+yamazoe.nara.jp
+yoshino.nara.jp
+aga.niigata.jp
+agano.niigata.jp
+gosen.niigata.jp
+itoigawa.niigata.jp
+izumozaki.niigata.jp
+joetsu.niigata.jp
+kamo.niigata.jp
+kariwa.niigata.jp
+kashiwazaki.niigata.jp
+minamiuonuma.niigata.jp
+mitsuke.niigata.jp
+muika.niigata.jp
+murakami.niigata.jp
+myoko.niigata.jp
+nagaoka.niigata.jp
+niigata.niigata.jp
+ojiya.niigata.jp
+omi.niigata.jp
+sado.niigata.jp
+sanjo.niigata.jp
+seiro.niigata.jp
+seirou.niigata.jp
+sekikawa.niigata.jp
+shibata.niigata.jp
+tagami.niigata.jp
+tainai.niigata.jp
+tochio.niigata.jp
+tokamachi.niigata.jp
+tsubame.niigata.jp
+tsunan.niigata.jp
+uonuma.niigata.jp
+yahiko.niigata.jp
+yoita.niigata.jp
+yuzawa.niigata.jp
+beppu.oita.jp
+bungoono.oita.jp
+bungotakada.oita.jp
+hasama.oita.jp
+hiji.oita.jp
+himeshima.oita.jp
+hita.oita.jp
+kamitsue.oita.jp
+kokonoe.oita.jp
+kuju.oita.jp
+kunisaki.oita.jp
+kusu.oita.jp
+oita.oita.jp
+saiki.oita.jp
+taketa.oita.jp
+tsukumi.oita.jp
+usa.oita.jp
+usuki.oita.jp
+yufu.oita.jp
+akaiwa.okayama.jp
+asakuchi.okayama.jp
+bizen.okayama.jp
+hayashima.okayama.jp
+ibara.okayama.jp
+kagamino.okayama.jp
+kasaoka.okayama.jp
+kibichuo.okayama.jp
+kumenan.okayama.jp
+kurashiki.okayama.jp
+maniwa.okayama.jp
+misaki.okayama.jp
+nagi.okayama.jp
+niimi.okayama.jp
+nishiawakura.okayama.jp
+okayama.okayama.jp
+satosho.okayama.jp
+setouchi.okayama.jp
+shinjo.okayama.jp
+shoo.okayama.jp
+soja.okayama.jp
+takahashi.okayama.jp
+tamano.okayama.jp
+tsuyama.okayama.jp
+wake.okayama.jp
+yakage.okayama.jp
+aguni.okinawa.jp
+ginowan.okinawa.jp
+ginoza.okinawa.jp
+gushikami.okinawa.jp
+haebaru.okinawa.jp
+higashi.okinawa.jp
+hirara.okinawa.jp
+iheya.okinawa.jp
+ishigaki.okinawa.jp
+ishikawa.okinawa.jp
+itoman.okinawa.jp
+izena.okinawa.jp
+kadena.okinawa.jp
+kin.okinawa.jp
+kitadaito.okinawa.jp
+kitanakagusuku.okinawa.jp
+kumejima.okinawa.jp
+kunigami.okinawa.jp
+minamidaito.okinawa.jp
+motobu.okinawa.jp
+nago.okinawa.jp
+naha.okinawa.jp
+nakagusuku.okinawa.jp
+nakijin.okinawa.jp
+nanjo.okinawa.jp
+nishihara.okinawa.jp
+ogimi.okinawa.jp
+okinawa.okinawa.jp
+onna.okinawa.jp
+shimoji.okinawa.jp
+taketomi.okinawa.jp
+tarama.okinawa.jp
+tokashiki.okinawa.jp
+tomigusuku.okinawa.jp
+tonaki.okinawa.jp
+urasoe.okinawa.jp
+uruma.okinawa.jp
+yaese.okinawa.jp
+yomitan.okinawa.jp
+yonabaru.okinawa.jp
+yonaguni.okinawa.jp
+zamami.okinawa.jp
+abeno.osaka.jp
+chihayaakasaka.osaka.jp
+chuo.osaka.jp
+daito.osaka.jp
+fujiidera.osaka.jp
+habikino.osaka.jp
+hannan.osaka.jp
+higashiosaka.osaka.jp
+higashisumiyoshi.osaka.jp
+higashiyodogawa.osaka.jp
+hirakata.osaka.jp
+ibaraki.osaka.jp
+ikeda.osaka.jp
+izumi.osaka.jp
+izumiotsu.osaka.jp
+izumisano.osaka.jp
+kadoma.osaka.jp
+kaizuka.osaka.jp
+kanan.osaka.jp
+kashiwara.osaka.jp
+katano.osaka.jp
+kawachinagano.osaka.jp
+kishiwada.osaka.jp
+kita.osaka.jp
+kumatori.osaka.jp
+matsubara.osaka.jp
+minato.osaka.jp
+minoh.osaka.jp
+misaki.osaka.jp
+moriguchi.osaka.jp
+neyagawa.osaka.jp
+nishi.osaka.jp
+nose.osaka.jp
+osakasayama.osaka.jp
+sakai.osaka.jp
+sayama.osaka.jp
+sennan.osaka.jp
+settsu.osaka.jp
+shijonawate.osaka.jp
+shimamoto.osaka.jp
+suita.osaka.jp
+tadaoka.osaka.jp
+taishi.osaka.jp
+tajiri.osaka.jp
+takaishi.osaka.jp
+takatsuki.osaka.jp
+tondabayashi.osaka.jp
+toyonaka.osaka.jp
+toyono.osaka.jp
+yao.osaka.jp
+ariake.saga.jp
+arita.saga.jp
+fukudomi.saga.jp
+genkai.saga.jp
+hamatama.saga.jp
+hizen.saga.jp
+imari.saga.jp
+kamimine.saga.jp
+kanzaki.saga.jp
+karatsu.saga.jp
+kashima.saga.jp
+kitagata.saga.jp
+kitahata.saga.jp
+kiyama.saga.jp
+kouhoku.saga.jp
+kyuragi.saga.jp
+nishiarita.saga.jp
+ogi.saga.jp
+omachi.saga.jp
+ouchi.saga.jp
+saga.saga.jp
+shiroishi.saga.jp
+taku.saga.jp
+tara.saga.jp
+tosu.saga.jp
+yoshinogari.saga.jp
+arakawa.saitama.jp
+asaka.saitama.jp
+chichibu.saitama.jp
+fujimi.saitama.jp
+fujimino.saitama.jp
+fukaya.saitama.jp
+hanno.saitama.jp
+hanyu.saitama.jp
+hasuda.saitama.jp
+hatogaya.saitama.jp
+hatoyama.saitama.jp
+hidaka.saitama.jp
+higashichichibu.saitama.jp
+higashimatsuyama.saitama.jp
+honjo.saitama.jp
+ina.saitama.jp
+iruma.saitama.jp
+iwatsuki.saitama.jp
+kamiizumi.saitama.jp
+kamikawa.saitama.jp
+kamisato.saitama.jp
+kasukabe.saitama.jp
+kawagoe.saitama.jp
+kawaguchi.saitama.jp
+kawajima.saitama.jp
+kazo.saitama.jp
+kitamoto.saitama.jp
+koshigaya.saitama.jp
+kounosu.saitama.jp
+kuki.saitama.jp
+kumagaya.saitama.jp
+matsubushi.saitama.jp
+minano.saitama.jp
+misato.saitama.jp
+miyashiro.saitama.jp
+miyoshi.saitama.jp
+moroyama.saitama.jp
+nagatoro.saitama.jp
+namegawa.saitama.jp
+niiza.saitama.jp
+ogano.saitama.jp
+ogawa.saitama.jp
+ogose.saitama.jp
+okegawa.saitama.jp
+omiya.saitama.jp
+otaki.saitama.jp
+ranzan.saitama.jp
+ryokami.saitama.jp
+saitama.saitama.jp
+sakado.saitama.jp
+satte.saitama.jp
+sayama.saitama.jp
+shiki.saitama.jp
+shiraoka.saitama.jp
+soka.saitama.jp
+sugito.saitama.jp
+toda.saitama.jp
+tokigawa.saitama.jp
+tokorozawa.saitama.jp
+tsurugashima.saitama.jp
+urawa.saitama.jp
+warabi.saitama.jp
+yashio.saitama.jp
+yokoze.saitama.jp
+yono.saitama.jp
+yorii.saitama.jp
+yoshida.saitama.jp
+yoshikawa.saitama.jp
+yoshimi.saitama.jp
+aisho.shiga.jp
+gamo.shiga.jp
+higashiomi.shiga.jp
+hikone.shiga.jp
+koka.shiga.jp
+konan.shiga.jp
+kosei.shiga.jp
+koto.shiga.jp
+kusatsu.shiga.jp
+maibara.shiga.jp
+moriyama.shiga.jp
+nagahama.shiga.jp
+nishiazai.shiga.jp
+notogawa.shiga.jp
+omihachiman.shiga.jp
+otsu.shiga.jp
+ritto.shiga.jp
+ryuoh.shiga.jp
+takashima.shiga.jp
+takatsuki.shiga.jp
+torahime.shiga.jp
+toyosato.shiga.jp
+yasu.shiga.jp
+akagi.shimane.jp
+ama.shimane.jp
+gotsu.shimane.jp
+hamada.shimane.jp
+higashiizumo.shimane.jp
+hikawa.shimane.jp
+hikimi.shimane.jp
+izumo.shimane.jp
+kakinoki.shimane.jp
+masuda.shimane.jp
+matsue.shimane.jp
+misato.shimane.jp
+nishinoshima.shimane.jp
+ohda.shimane.jp
+okinoshima.shimane.jp
+okuizumo.shimane.jp
+shimane.shimane.jp
+tamayu.shimane.jp
+tsuwano.shimane.jp
+unnan.shimane.jp
+yakumo.shimane.jp
+yasugi.shimane.jp
+yatsuka.shimane.jp
+arai.shizuoka.jp
+atami.shizuoka.jp
+fuji.shizuoka.jp
+fujieda.shizuoka.jp
+fujikawa.shizuoka.jp
+fujinomiya.shizuoka.jp
+fukuroi.shizuoka.jp
+gotemba.shizuoka.jp
+haibara.shizuoka.jp
+hamamatsu.shizuoka.jp
+higashiizu.shizuoka.jp
+ito.shizuoka.jp
+iwata.shizuoka.jp
+izu.shizuoka.jp
+izunokuni.shizuoka.jp
+kakegawa.shizuoka.jp
+kannami.shizuoka.jp
+kawanehon.shizuoka.jp
+kawazu.shizuoka.jp
+kikugawa.shizuoka.jp
+kosai.shizuoka.jp
+makinohara.shizuoka.jp
+matsuzaki.shizuoka.jp
+minamiizu.shizuoka.jp
+mishima.shizuoka.jp
+morimachi.shizuoka.jp
+nishiizu.shizuoka.jp
+numazu.shizuoka.jp
+omaezaki.shizuoka.jp
+shimada.shizuoka.jp
+shimizu.shizuoka.jp
+shimoda.shizuoka.jp
+shizuoka.shizuoka.jp
+susono.shizuoka.jp
+yaizu.shizuoka.jp
+yoshida.shizuoka.jp
+ashikaga.tochigi.jp
+bato.tochigi.jp
+haga.tochigi.jp
+ichikai.tochigi.jp
+iwafune.tochigi.jp
+kaminokawa.tochigi.jp
+kanuma.tochigi.jp
+karasuyama.tochigi.jp
+kuroiso.tochigi.jp
+mashiko.tochigi.jp
+mibu.tochigi.jp
+moka.tochigi.jp
+motegi.tochigi.jp
+nasu.tochigi.jp
+nasushiobara.tochigi.jp
+nikko.tochigi.jp
+nishikata.tochigi.jp
+nogi.tochigi.jp
+ohira.tochigi.jp
+ohtawara.tochigi.jp
+oyama.tochigi.jp
+sakura.tochigi.jp
+sano.tochigi.jp
+shimotsuke.tochigi.jp
+shioya.tochigi.jp
+takanezawa.tochigi.jp
+tochigi.tochigi.jp
+tsuga.tochigi.jp
+ujiie.tochigi.jp
+utsunomiya.tochigi.jp
+yaita.tochigi.jp
+aizumi.tokushima.jp
+anan.tokushima.jp
+ichiba.tokushima.jp
+itano.tokushima.jp
+kainan.tokushima.jp
+komatsushima.tokushima.jp
+matsushige.tokushima.jp
+mima.tokushima.jp
+minami.tokushima.jp
+miyoshi.tokushima.jp
+mugi.tokushima.jp
+nakagawa.tokushima.jp
+naruto.tokushima.jp
+sanagochi.tokushima.jp
+shishikui.tokushima.jp
+tokushima.tokushima.jp
+wajiki.tokushima.jp
+adachi.tokyo.jp
+akiruno.tokyo.jp
+akishima.tokyo.jp
+aogashima.tokyo.jp
+arakawa.tokyo.jp
+bunkyo.tokyo.jp
+chiyoda.tokyo.jp
+chofu.tokyo.jp
+chuo.tokyo.jp
+edogawa.tokyo.jp
+fuchu.tokyo.jp
+fussa.tokyo.jp
+hachijo.tokyo.jp
+hachioji.tokyo.jp
+hamura.tokyo.jp
+higashikurume.tokyo.jp
+higashimurayama.tokyo.jp
+higashiyamato.tokyo.jp
+hino.tokyo.jp
+hinode.tokyo.jp
+hinohara.tokyo.jp
+inagi.tokyo.jp
+itabashi.tokyo.jp
+katsushika.tokyo.jp
+kita.tokyo.jp
+kiyose.tokyo.jp
+kodaira.tokyo.jp
+koganei.tokyo.jp
+kokubunji.tokyo.jp
+komae.tokyo.jp
+koto.tokyo.jp
+kouzushima.tokyo.jp
+kunitachi.tokyo.jp
+machida.tokyo.jp
+meguro.tokyo.jp
+minato.tokyo.jp
+mitaka.tokyo.jp
+mizuho.tokyo.jp
+musashimurayama.tokyo.jp
+musashino.tokyo.jp
+nakano.tokyo.jp
+nerima.tokyo.jp
+ogasawara.tokyo.jp
+okutama.tokyo.jp
+ome.tokyo.jp
+oshima.tokyo.jp
+ota.tokyo.jp
+setagaya.tokyo.jp
+shibuya.tokyo.jp
+shinagawa.tokyo.jp
+shinjuku.tokyo.jp
+suginami.tokyo.jp
+sumida.tokyo.jp
+tachikawa.tokyo.jp
+taito.tokyo.jp
+tama.tokyo.jp
+toshima.tokyo.jp
+chizu.tottori.jp
+hino.tottori.jp
+kawahara.tottori.jp
+koge.tottori.jp
+kotoura.tottori.jp
+misasa.tottori.jp
+nanbu.tottori.jp
+nichinan.tottori.jp
+sakaiminato.tottori.jp
+tottori.tottori.jp
+wakasa.tottori.jp
+yazu.tottori.jp
+yonago.tottori.jp
+asahi.toyama.jp
+fuchu.toyama.jp
+fukumitsu.toyama.jp
+funahashi.toyama.jp
+himi.toyama.jp
+imizu.toyama.jp
+inami.toyama.jp
+johana.toyama.jp
+kamiichi.toyama.jp
+kurobe.toyama.jp
+nakaniikawa.toyama.jp
+namerikawa.toyama.jp
+nanto.toyama.jp
+nyuzen.toyama.jp
+oyabe.toyama.jp
+taira.toyama.jp
+takaoka.toyama.jp
+tateyama.toyama.jp
+toga.toyama.jp
+tonami.toyama.jp
+toyama.toyama.jp
+unazuki.toyama.jp
+uozu.toyama.jp
+yamada.toyama.jp
+arida.wakayama.jp
+aridagawa.wakayama.jp
+gobo.wakayama.jp
+hashimoto.wakayama.jp
+hidaka.wakayama.jp
+hirogawa.wakayama.jp
+inami.wakayama.jp
+iwade.wakayama.jp
+kainan.wakayama.jp
+kamitonda.wakayama.jp
+katsuragi.wakayama.jp
+kimino.wakayama.jp
+kinokawa.wakayama.jp
+kitayama.wakayama.jp
+koya.wakayama.jp
+koza.wakayama.jp
+kozagawa.wakayama.jp
+kudoyama.wakayama.jp
+kushimoto.wakayama.jp
+mihama.wakayama.jp
+misato.wakayama.jp
+nachikatsuura.wakayama.jp
+shingu.wakayama.jp
+shirahama.wakayama.jp
+taiji.wakayama.jp
+tanabe.wakayama.jp
+wakayama.wakayama.jp
+yuasa.wakayama.jp
+yura.wakayama.jp
+asahi.yamagata.jp
+funagata.yamagata.jp
+higashine.yamagata.jp
+iide.yamagata.jp
+kahoku.yamagata.jp
+kaminoyama.yamagata.jp
+kaneyama.yamagata.jp
+kawanishi.yamagata.jp
+mamurogawa.yamagata.jp
+mikawa.yamagata.jp
+murayama.yamagata.jp
+nagai.yamagata.jp
+nakayama.yamagata.jp
+nanyo.yamagata.jp
+nishikawa.yamagata.jp
+obanazawa.yamagata.jp
+oe.yamagata.jp
+oguni.yamagata.jp
+ohkura.yamagata.jp
+oishida.yamagata.jp
+sagae.yamagata.jp
+sakata.yamagata.jp
+sakegawa.yamagata.jp
+shinjo.yamagata.jp
+shirataka.yamagata.jp
+shonai.yamagata.jp
+takahata.yamagata.jp
+tendo.yamagata.jp
+tozawa.yamagata.jp
+tsuruoka.yamagata.jp
+yamagata.yamagata.jp
+yamanobe.yamagata.jp
+yonezawa.yamagata.jp
+yuza.yamagata.jp
+abu.yamaguchi.jp
+hagi.yamaguchi.jp
+hikari.yamaguchi.jp
+hofu.yamaguchi.jp
+iwakuni.yamaguchi.jp
+kudamatsu.yamaguchi.jp
+mitou.yamaguchi.jp
+nagato.yamaguchi.jp
+oshima.yamaguchi.jp
+shimonoseki.yamaguchi.jp
+shunan.yamaguchi.jp
+tabuse.yamaguchi.jp
+tokuyama.yamaguchi.jp
+toyota.yamaguchi.jp
+ube.yamaguchi.jp
+yuu.yamaguchi.jp
+chuo.yamanashi.jp
+doshi.yamanashi.jp
+fuefuki.yamanashi.jp
+fujikawa.yamanashi.jp
+fujikawaguchiko.yamanashi.jp
+fujiyoshida.yamanashi.jp
+hayakawa.yamanashi.jp
+hokuto.yamanashi.jp
+ichikawamisato.yamanashi.jp
+kai.yamanashi.jp
+kofu.yamanashi.jp
+koshu.yamanashi.jp
+kosuge.yamanashi.jp
+minami-alps.yamanashi.jp
+minobu.yamanashi.jp
+nakamichi.yamanashi.jp
+nanbu.yamanashi.jp
+narusawa.yamanashi.jp
+nirasaki.yamanashi.jp
+nishikatsura.yamanashi.jp
+oshino.yamanashi.jp
+otsuki.yamanashi.jp
+showa.yamanashi.jp
+tabayama.yamanashi.jp
+tsuru.yamanashi.jp
+uenohara.yamanashi.jp
+yamanakako.yamanashi.jp
+yamanashi.yamanashi.jp
+
+// ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145
+*.ke
+
+// kg : http://www.domain.kg/dmn_n.html
+kg
+org.kg
+net.kg
+com.kg
+edu.kg
+gov.kg
+mil.kg
+
+// kh : http://www.mptc.gov.kh/dns_registration.htm
+*.kh
+
+// ki : http://www.ki/dns/index.html
+ki
+edu.ki
+biz.ki
+net.ki
+org.ki
+gov.ki
+info.ki
+com.ki
+
+// km : http://en.wikipedia.org/wiki/.km
+// http://www.domaine.km/documents/charte.doc
+km
+org.km
+nom.km
+gov.km
+prd.km
+tm.km
+edu.km
+mil.km
+ass.km
+com.km
+// These are only mentioned as proposed suggestions at domaine.km, but
+// http://en.wikipedia.org/wiki/.km says they're available for registration:
+coop.km
+asso.km
+presse.km
+medecin.km
+notaires.km
+pharmaciens.km
+veterinaire.km
+gouv.km
+
+// kn : http://en.wikipedia.org/wiki/.kn
+// http://www.dot.kn/domainRules.html
+kn
+net.kn
+org.kn
+edu.kn
+gov.kn
+
+// kp : http://www.kcce.kp/en_index.php
+kp
+com.kp
+edu.kp
+gov.kp
+org.kp
+rep.kp
+tra.kp
+
+// kr : http://en.wikipedia.org/wiki/.kr
+// see also: http://domain.nida.or.kr/eng/registration.jsp
+kr
+ac.kr
+co.kr
+es.kr
+go.kr
+hs.kr
+kg.kr
+mil.kr
+ms.kr
+ne.kr
+or.kr
+pe.kr
+re.kr
+sc.kr
+// kr geographical names
+busan.kr
+chungbuk.kr
+chungnam.kr
+daegu.kr
+daejeon.kr
+gangwon.kr
+gwangju.kr
+gyeongbuk.kr
+gyeonggi.kr
+gyeongnam.kr
+incheon.kr
+jeju.kr
+jeonbuk.kr
+jeonnam.kr
+seoul.kr
+ulsan.kr
+
+// kw : http://en.wikipedia.org/wiki/.kw
+*.kw
+
+// ky : http://www.icta.ky/da_ky_reg_dom.php
+// Confirmed by registry <kysupport at perimeterusa.com> 2008-06-17
+ky
+edu.ky
+gov.ky
+com.ky
+org.ky
+net.ky
+
+// kz : http://en.wikipedia.org/wiki/.kz
+// see also: http://www.nic.kz/rules/index.jsp
+kz
+org.kz
+edu.kz
+net.kz
+gov.kz
+mil.kz
+com.kz
+
+// la : http://en.wikipedia.org/wiki/.la
+// Submitted by registry <gavin.brown at nic.la> 2008-06-10
+la
+int.la
+net.la
+info.la
+edu.la
+gov.la
+per.la
+com.la
+org.la
+
+// lb : http://en.wikipedia.org/wiki/.lb
+// Submitted by registry <randy at psg.com> 2008-06-17
+lb
+com.lb
+edu.lb
+gov.lb
+net.lb
+org.lb
+
+// lc : http://en.wikipedia.org/wiki/.lc
+// see also: http://www.nic.lc/rules.htm
+lc
+com.lc
+net.lc
+co.lc
+org.lc
+edu.lc
+gov.lc
+
+// li : http://en.wikipedia.org/wiki/.li
+li
+
+// lk : http://www.nic.lk/seclevpr.html
+lk
+gov.lk
+sch.lk
+net.lk
+int.lk
+com.lk
+org.lk
+edu.lk
+ngo.lk
+soc.lk
+web.lk
+ltd.lk
+assn.lk
+grp.lk
+hotel.lk
+ac.lk
+
+// lr : http://psg.com/dns/lr/lr.txt
+// Submitted by registry <randy at psg.com> 2008-06-17
+lr
+com.lr
+edu.lr
+gov.lr
+org.lr
+net.lr
+
+// ls : http://en.wikipedia.org/wiki/.ls
+ls
+co.ls
+org.ls
+
+// lt : http://en.wikipedia.org/wiki/.lt
+lt
+// gov.lt : http://www.gov.lt/index_en.php
+gov.lt
+
+// lu : http://www.dns.lu/en/
+lu
+
+// lv : http://www.nic.lv/DNS/En/generic.php
+lv
+com.lv
+edu.lv
+gov.lv
+org.lv
+mil.lv
+id.lv
+net.lv
+asn.lv
+conf.lv
+
+// ly : http://www.nic.ly/regulations.php
+ly
+com.ly
+net.ly
+gov.ly
+plc.ly
+edu.ly
+sch.ly
+med.ly
+org.ly
+id.ly
+
+// ma : http://en.wikipedia.org/wiki/.ma
+// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf
+ma
+co.ma
+net.ma
+gov.ma
+org.ma
+ac.ma
+press.ma
+
+// mc : http://www.nic.mc/
+mc
+tm.mc
+asso.mc
+
+// md : http://en.wikipedia.org/wiki/.md
+md
+
+// me : http://en.wikipedia.org/wiki/.me
+me
+co.me
+net.me
+org.me
+edu.me
+ac.me
+gov.me
+its.me
+priv.me
+
+// mg : http://www.nic.mg/tarif.htm
+mg
+org.mg
+nom.mg
+gov.mg
+prd.mg
+tm.mg
+edu.mg
+mil.mg
+com.mg
+
+// mh : http://en.wikipedia.org/wiki/.mh
+mh
+
+// mil : http://en.wikipedia.org/wiki/.mil
+mil
+
+// mk : http://en.wikipedia.org/wiki/.mk
+// see also: http://dns.marnet.net.mk/postapka.php
+mk
+com.mk
+org.mk
+net.mk
+edu.mk
+gov.mk
+inf.mk
+name.mk
+
+// ml : http://www.gobin.info/domainname/ml-template.doc
+// see also: http://en.wikipedia.org/wiki/.ml
+ml
+com.ml
+edu.ml
+gouv.ml
+gov.ml
+net.ml
+org.ml
+presse.ml
+
+// mm : http://en.wikipedia.org/wiki/.mm
+*.mm
+
+// mn : http://en.wikipedia.org/wiki/.mn
+mn
+gov.mn
+edu.mn
+org.mn
+
+// mo : http://www.monic.net.mo/
+mo
+com.mo
+net.mo
+org.mo
+edu.mo
+gov.mo
+
+// mobi : http://en.wikipedia.org/wiki/.mobi
+mobi
+
+// mp : http://www.dot.mp/
+// Confirmed by registry <dcamacho at saipan.com> 2008-06-17
+mp
+
+// mq : http://en.wikipedia.org/wiki/.mq
+mq
+
+// mr : http://en.wikipedia.org/wiki/.mr
+mr
+gov.mr
+
+// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf
+ms
+com.ms
+edu.ms
+gov.ms
+net.ms
+org.ms
+
+// mt : https://www.nic.org.mt/go/policy
+// Submitted by registry <help at nic.org.mt> 2013-11-19
+mt
+com.mt
+edu.mt
+net.mt
+org.mt
+
+// mu : http://en.wikipedia.org/wiki/.mu
+mu
+com.mu
+net.mu
+org.mu
+gov.mu
+ac.mu
+co.mu
+or.mu
+
+// museum : http://about.museum/naming/
+// http://index.museum/
+museum
+academy.museum
+agriculture.museum
+air.museum
+airguard.museum
+alabama.museum
+alaska.museum
+amber.museum
+ambulance.museum
+american.museum
+americana.museum
+americanantiques.museum
+americanart.museum
+amsterdam.museum
+and.museum
+annefrank.museum
+anthro.museum
+anthropology.museum
+antiques.museum
+aquarium.museum
+arboretum.museum
+archaeological.museum
+archaeology.museum
+architecture.museum
+art.museum
+artanddesign.museum
+artcenter.museum
+artdeco.museum
+arteducation.museum
+artgallery.museum
+arts.museum
+artsandcrafts.museum
+asmatart.museum
+assassination.museum
+assisi.museum
+association.museum
+astronomy.museum
+atlanta.museum
+austin.museum
+australia.museum
+automotive.museum
+aviation.museum
+axis.museum
+badajoz.museum
+baghdad.museum
+bahn.museum
+bale.museum
+baltimore.museum
+barcelona.museum
+baseball.museum
+basel.museum
+baths.museum
+bauern.museum
+beauxarts.museum
+beeldengeluid.museum
+bellevue.museum
+bergbau.museum
+berkeley.museum
+berlin.museum
+bern.museum
+bible.museum
+bilbao.museum
+bill.museum
+birdart.museum
+birthplace.museum
+bonn.museum
+boston.museum
+botanical.museum
+botanicalgarden.museum
+botanicgarden.museum
+botany.museum
+brandywinevalley.museum
+brasil.museum
+bristol.museum
+british.museum
+britishcolumbia.museum
+broadcast.museum
+brunel.museum
+brussel.museum
+brussels.museum
+bruxelles.museum
+building.museum
+burghof.museum
+bus.museum
+bushey.museum
+cadaques.museum
+california.museum
+cambridge.museum
+can.museum
+canada.museum
+capebreton.museum
+carrier.museum
+cartoonart.museum
+casadelamoneda.museum
+castle.museum
+castres.museum
+celtic.museum
+center.museum
+chattanooga.museum
+cheltenham.museum
+chesapeakebay.museum
+chicago.museum
+children.museum
+childrens.museum
+childrensgarden.museum
+chiropractic.museum
+chocolate.museum
+christiansburg.museum
+cincinnati.museum
+cinema.museum
+circus.museum
+civilisation.museum
+civilization.museum
+civilwar.museum
+clinton.museum
+clock.museum
+coal.museum
+coastaldefence.museum
+cody.museum
+coldwar.museum
+collection.museum
+colonialwilliamsburg.museum
+coloradoplateau.museum
+columbia.museum
+columbus.museum
+communication.museum
+communications.museum
+community.museum
+computer.museum
+computerhistory.museum
+comunicações.museum
+contemporary.museum
+contemporaryart.museum
+convent.museum
+copenhagen.museum
+corporation.museum
+correios-e-telecomunicações.museum
+corvette.museum
+costume.museum
+countryestate.museum
+county.museum
+crafts.museum
+cranbrook.museum
+creation.museum
+cultural.museum
+culturalcenter.museum
+culture.museum
+cyber.museum
+cymru.museum
+dali.museum
+dallas.museum
+database.museum
+ddr.museum
+decorativearts.museum
+delaware.museum
+delmenhorst.museum
+denmark.museum
+depot.museum
+design.museum
+detroit.museum
+dinosaur.museum
+discovery.museum
+dolls.museum
+donostia.museum
+durham.museum
+eastafrica.museum
+eastcoast.museum
+education.museum
+educational.museum
+egyptian.museum
+eisenbahn.museum
+elburg.museum
+elvendrell.museum
+embroidery.museum
+encyclopedic.museum
+england.museum
+entomology.museum
+environment.museum
+environmentalconservation.museum
+epilepsy.museum
+essex.museum
+estate.museum
+ethnology.museum
+exeter.museum
+exhibition.museum
+family.museum
+farm.museum
+farmequipment.museum
+farmers.museum
+farmstead.museum
+field.museum
+figueres.museum
+filatelia.museum
+film.museum
+fineart.museum
+finearts.museum
+finland.museum
+flanders.museum
+florida.museum
+force.museum
+fortmissoula.museum
+fortworth.museum
+foundation.museum
+francaise.museum
+frankfurt.museum
+franziskaner.museum
+freemasonry.museum
+freiburg.museum
+fribourg.museum
+frog.museum
+fundacio.museum
+furniture.museum
+gallery.museum
+garden.museum
+gateway.museum
+geelvinck.museum
+gemological.museum
+geology.museum
+georgia.museum
+giessen.museum
+glas.museum
+glass.museum
+gorge.museum
+grandrapids.museum
+graz.museum
+guernsey.museum
+halloffame.museum
+hamburg.museum
+handson.museum
+harvestcelebration.museum
+hawaii.museum
+health.museum
+heimatunduhren.museum
+hellas.museum
+helsinki.museum
+hembygdsforbund.museum
+heritage.museum
+histoire.museum
+historical.museum
+historicalsociety.museum
+historichouses.museum
+historisch.museum
+historisches.museum
+history.museum
+historyofscience.museum
+horology.museum
+house.museum
+humanities.museum
+illustration.museum
+imageandsound.museum
+indian.museum
+indiana.museum
+indianapolis.museum
+indianmarket.museum
+intelligence.museum
+interactive.museum
+iraq.museum
+iron.museum
+isleofman.museum
+jamison.museum
+jefferson.museum
+jerusalem.museum
+jewelry.museum
+jewish.museum
+jewishart.museum
+jfk.museum
+journalism.museum
+judaica.museum
+judygarland.museum
+juedisches.museum
+juif.museum
+karate.museum
+karikatur.museum
+kids.museum
+koebenhavn.museum
+koeln.museum
+kunst.museum
+kunstsammlung.museum
+kunstunddesign.museum
+labor.museum
+labour.museum
+lajolla.museum
+lancashire.museum
+landes.museum
+lans.museum
+läns.museum
+larsson.museum
+lewismiller.museum
+lincoln.museum
+linz.museum
+living.museum
+livinghistory.museum
+localhistory.museum
+london.museum
+losangeles.museum
+louvre.museum
+loyalist.museum
+lucerne.museum
+luxembourg.museum
+luzern.museum
+mad.museum
+madrid.museum
+mallorca.museum
+manchester.museum
+mansion.museum
+mansions.museum
+manx.museum
+marburg.museum
+maritime.museum
+maritimo.museum
+maryland.museum
+marylhurst.museum
+media.museum
+medical.museum
+medizinhistorisches.museum
+meeres.museum
+memorial.museum
+mesaverde.museum
+michigan.museum
+midatlantic.museum
+military.museum
+mill.museum
+miners.museum
+mining.museum
+minnesota.museum
+missile.museum
+missoula.museum
+modern.museum
+moma.museum
+money.museum
+monmouth.museum
+monticello.museum
+montreal.museum
+moscow.museum
+motorcycle.museum
+muenchen.museum
+muenster.museum
+mulhouse.museum
+muncie.museum
+museet.museum
+museumcenter.museum
+museumvereniging.museum
+music.museum
+national.museum
+nationalfirearms.museum
+nationalheritage.museum
+nativeamerican.museum
+naturalhistory.museum
+naturalhistorymuseum.museum
+naturalsciences.museum
+nature.museum
+naturhistorisches.museum
+natuurwetenschappen.museum
+naumburg.museum
+naval.museum
+nebraska.museum
+neues.museum
+newhampshire.museum
+newjersey.museum
+newmexico.museum
+newport.museum
+newspaper.museum
+newyork.museum
+niepce.museum
+norfolk.museum
+north.museum
+nrw.museum
+nuernberg.museum
+nuremberg.museum
+nyc.museum
+nyny.museum
+oceanographic.museum
+oceanographique.museum
+omaha.museum
+online.museum
+ontario.museum
+openair.museum
+oregon.museum
+oregontrail.museum
+otago.museum
+oxford.museum
+pacific.museum
+paderborn.museum
+palace.museum
+paleo.museum
+palmsprings.museum
+panama.museum
+paris.museum
+pasadena.museum
+pharmacy.museum
+philadelphia.museum
+philadelphiaarea.museum
+philately.museum
+phoenix.museum
+photography.museum
+pilots.museum
+pittsburgh.museum
+planetarium.museum
+plantation.museum
+plants.museum
+plaza.museum
+portal.museum
+portland.museum
+portlligat.museum
+posts-and-telecommunications.museum
+preservation.museum
+presidio.museum
+press.museum
+project.museum
+public.museum
+pubol.museum
+quebec.museum
+railroad.museum
+railway.museum
+research.museum
+resistance.museum
+riodejaneiro.museum
+rochester.museum
+rockart.museum
+roma.museum
+russia.museum
+saintlouis.museum
+salem.museum
+salvadordali.museum
+salzburg.museum
+sandiego.museum
+sanfrancisco.museum
+santabarbara.museum
+santacruz.museum
+santafe.museum
+saskatchewan.museum
+satx.museum
+savannahga.museum
+schlesisches.museum
+schoenbrunn.museum
+schokoladen.museum
+school.museum
+schweiz.museum
+science.museum
+scienceandhistory.museum
+scienceandindustry.museum
+sciencecenter.museum
+sciencecenters.museum
+science-fiction.museum
+sciencehistory.museum
+sciences.museum
+sciencesnaturelles.museum
+scotland.museum
+seaport.museum
+settlement.museum
+settlers.museum
+shell.museum
+sherbrooke.museum
+sibenik.museum
+silk.museum
+ski.museum
+skole.museum
+society.museum
+sologne.museum
+soundandvision.museum
+southcarolina.museum
+southwest.museum
+space.museum
+spy.museum
+square.museum
+stadt.museum
+stalbans.museum
+starnberg.museum
+state.museum
+stateofdelaware.museum
+station.museum
+steam.museum
+steiermark.museum
+stjohn.museum
+stockholm.museum
+stpetersburg.museum
+stuttgart.museum
+suisse.museum
+surgeonshall.museum
+surrey.museum
+svizzera.museum
+sweden.museum
+sydney.museum
+tank.museum
+tcm.museum
+technology.museum
+telekommunikation.museum
+television.museum
+texas.museum
+textile.museum
+theater.museum
+time.museum
+timekeeping.museum
+topology.museum
+torino.museum
+touch.museum
+town.museum
+transport.museum
+tree.museum
+trolley.museum
+trust.museum
+trustee.museum
+uhren.museum
+ulm.museum
+undersea.museum
+university.museum
+usa.museum
+usantiques.museum
+usarts.museum
+uscountryestate.museum
+usculture.museum
+usdecorativearts.museum
+usgarden.museum
+ushistory.museum
+ushuaia.museum
+uslivinghistory.museum
+utah.museum
+uvic.museum
+valley.museum
+vantaa.museum
+versailles.museum
+viking.museum
+village.museum
+virginia.museum
+virtual.museum
+virtuel.museum
+vlaanderen.museum
+volkenkunde.museum
+wales.museum
+wallonie.museum
+war.museum
+washingtondc.museum
+watchandclock.museum
+watch-and-clock.museum
+western.museum
+westfalen.museum
+whaling.museum
+wildlife.museum
+williamsburg.museum
+windmill.museum
+workshop.museum
+york.museum
+yorkshire.museum
+yosemite.museum
+youth.museum
+zoological.museum
+zoology.museum
+ירושלים.museum
+иком.museum
+
+// mv : http://en.wikipedia.org/wiki/.mv
+// "mv" included because, contra Wikipedia, google.mv exists.
+mv
+aero.mv
+biz.mv
+com.mv
+coop.mv
+edu.mv
+gov.mv
+info.mv
+int.mv
+mil.mv
+museum.mv
+name.mv
+net.mv
+org.mv
+pro.mv
+
+// mw : http://www.registrar.mw/
+mw
+ac.mw
+biz.mw
+co.mw
+com.mw
+coop.mw
+edu.mw
+gov.mw
+int.mw
+museum.mw
+net.mw
+org.mw
+
+// mx : http://www.nic.mx/
+// Submitted by registry <farias at nic.mx> 2008-06-19
+mx
+com.mx
+org.mx
+gob.mx
+edu.mx
+net.mx
+
+// my : http://www.mynic.net.my/
+my
+com.my
+net.my
+org.my
+gov.my
+edu.my
+mil.my
+name.my
+
+// mz : http://www.gobin.info/domainname/mz-template.doc
+*.mz
+!teledata.mz
+
+// na : http://www.na-nic.com.na/
+// http://www.info.na/domain/
+na
+info.na
+pro.na
+name.na
+school.na
+or.na
+dr.na
+us.na
+mx.na
+ca.na
+in.na
+cc.na
+tv.na
+ws.na
+mobi.na
+co.na
+com.na
+org.na
+
+// name : has 2nd-level tlds, but there's no list of them
+name
+
+// nc : http://www.cctld.nc/
+nc
+asso.nc
+
+// ne : http://en.wikipedia.org/wiki/.ne
+ne
+
+// net : http://en.wikipedia.org/wiki/.net
+net
+
+// nf : http://en.wikipedia.org/wiki/.nf
+nf
+com.nf
+net.nf
+per.nf
+rec.nf
+web.nf
+arts.nf
+firm.nf
+info.nf
+other.nf
+store.nf
+
+// ng : http://psg.com/dns/ng/
+ng
+com.ng
+edu.ng
+name.ng
+net.ng
+org.ng
+sch.ng
+gov.ng
+mil.ng
+mobi.ng
+
+// ni : http://www.nic.ni/dominios.htm
+*.ni
+
+// nl : http://en.wikipedia.org/wiki/.nl
+//      https://www.sidn.nl/
+//      ccTLD for the Netherlands
+nl
+
+// BV.nl will be a registry for dutch BV's (besloten vennootschap)
+bv.nl
+
+// no : http://www.norid.no/regelverk/index.en.html
+// The Norwegian registry has declined to notify us of updates. The web pages
+// referenced below are the official source of the data. There is also an
+// announce mailing list:
+// https://postlister.uninett.no/sympa/info/norid-diskusjon
+no
+// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html
+fhs.no
+vgs.no
+fylkesbibl.no
+folkebibl.no
+museum.no
+idrett.no
+priv.no
+// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html
+mil.no
+stat.no
+dep.no
+kommune.no
+herad.no
+// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html
+// counties
+aa.no
+ah.no
+bu.no
+fm.no
+hl.no
+hm.no
+jan-mayen.no
+mr.no
+nl.no
+nt.no
+of.no
+ol.no
+oslo.no
+rl.no
+sf.no
+st.no
+svalbard.no
+tm.no
+tr.no
+va.no
+vf.no
+// primary and lower secondary schools per county
+gs.aa.no
+gs.ah.no
+gs.bu.no
+gs.fm.no
+gs.hl.no
+gs.hm.no
+gs.jan-mayen.no
+gs.mr.no
+gs.nl.no
+gs.nt.no
+gs.of.no
+gs.ol.no
+gs.oslo.no
+gs.rl.no
+gs.sf.no
+gs.st.no
+gs.svalbard.no
+gs.tm.no
+gs.tr.no
+gs.va.no
+gs.vf.no
+// cities
+akrehamn.no
+åkrehamn.no
+algard.no
+ålgård.no
+arna.no
+brumunddal.no
+bryne.no
+bronnoysund.no
+brønnøysund.no
+drobak.no
+drøbak.no
+egersund.no
+fetsund.no
+floro.no
+florø.no
+fredrikstad.no
+hokksund.no
+honefoss.no
+hønefoss.no
+jessheim.no
+jorpeland.no
+jørpeland.no
+kirkenes.no
+kopervik.no
+krokstadelva.no
+langevag.no
+langevåg.no
+leirvik.no
+mjondalen.no
+mjøndalen.no
+mo-i-rana.no
+mosjoen.no
+mosjøen.no
+nesoddtangen.no
+orkanger.no
+osoyro.no
+osøyro.no
+raholt.no
+råholt.no
+sandnessjoen.no
+sandnessjøen.no
+skedsmokorset.no
+slattum.no
+spjelkavik.no
+stathelle.no
+stavern.no
+stjordalshalsen.no
+stjørdalshalsen.no
+tananger.no
+tranby.no
+vossevangen.no
+// communities
+afjord.no
+åfjord.no
+agdenes.no
+al.no
+ål.no
+alesund.no
+ålesund.no
+alstahaug.no
+alta.no
+áltá.no
+alaheadju.no
+álaheadju.no
+alvdal.no
+amli.no
+åmli.no
+amot.no
+åmot.no
+andebu.no
+andoy.no
+andøy.no
+andasuolo.no
+ardal.no
+årdal.no
+aremark.no
+arendal.no
+ås.no
+aseral.no
+åseral.no
+asker.no
+askim.no
+askvoll.no
+askoy.no
+askøy.no
+asnes.no
+åsnes.no
+audnedaln.no
+aukra.no
+aure.no
+aurland.no
+aurskog-holand.no
+aurskog-høland.no
+austevoll.no
+austrheim.no
+averoy.no
+averøy.no
+balestrand.no
+ballangen.no
+balat.no
+bálát.no
+balsfjord.no
+bahccavuotna.no
+báhccavuotna.no
+bamble.no
+bardu.no
+beardu.no
+beiarn.no
+bajddar.no
+bájddar.no
+baidar.no
+báidár.no
+berg.no
+bergen.no
+berlevag.no
+berlevåg.no
+bearalvahki.no
+bearalváhki.no
+bindal.no
+birkenes.no
+bjarkoy.no
+bjarkøy.no
+bjerkreim.no
+bjugn.no
+bodo.no
+bodø.no
+badaddja.no
+bådåddjå.no
+budejju.no
+bokn.no
+bremanger.no
+bronnoy.no
+brønnøy.no
+bygland.no
+bykle.no
+barum.no
+bærum.no
+bo.telemark.no
+bø.telemark.no
+bo.nordland.no
+bø.nordland.no
+bievat.no
+bievát.no
+bomlo.no
+bømlo.no
+batsfjord.no
+båtsfjord.no
+bahcavuotna.no
+báhcavuotna.no
+dovre.no
+drammen.no
+drangedal.no
+dyroy.no
+dyrøy.no
+donna.no
+dønna.no
+eid.no
+eidfjord.no
+eidsberg.no
+eidskog.no
+eidsvoll.no
+eigersund.no
+elverum.no
+enebakk.no
+engerdal.no
+etne.no
+etnedal.no
+evenes.no
+evenassi.no
+evenášši.no
+evje-og-hornnes.no
+farsund.no
+fauske.no
+fuossko.no
+fuoisku.no
+fedje.no
+fet.no
+finnoy.no
+finnøy.no
+fitjar.no
+fjaler.no
+fjell.no
+flakstad.no
+flatanger.no
+flekkefjord.no
+flesberg.no
+flora.no
+fla.no
+flå.no
+folldal.no
+forsand.no
+fosnes.no
+frei.no
+frogn.no
+froland.no
+frosta.no
+frana.no
+fræna.no
+froya.no
+frøya.no
+fusa.no
+fyresdal.no
+forde.no
+førde.no
+gamvik.no
+gangaviika.no
+gáŋgaviika.no
+gaular.no
+gausdal.no
+gildeskal.no
+gildeskål.no
+giske.no
+gjemnes.no
+gjerdrum.no
+gjerstad.no
+gjesdal.no
+gjovik.no
+gjøvik.no
+gloppen.no
+gol.no
+gran.no
+grane.no
+granvin.no
+gratangen.no
+grimstad.no
+grong.no
+kraanghke.no
+kråanghke.no
+grue.no
+gulen.no
+hadsel.no
+halden.no
+halsa.no
+hamar.no
+hamaroy.no
+habmer.no
+hábmer.no
+hapmir.no
+hápmir.no
+hammerfest.no
+hammarfeasta.no
+hámmárfeasta.no
+haram.no
+hareid.no
+harstad.no
+hasvik.no
+aknoluokta.no
+ákŋoluokta.no
+hattfjelldal.no
+aarborte.no
+haugesund.no
+hemne.no
+hemnes.no
+hemsedal.no
+heroy.more-og-romsdal.no
+herøy.møre-og-romsdal.no
+heroy.nordland.no
+herøy.nordland.no
+hitra.no
+hjartdal.no
+hjelmeland.no
+hobol.no
+hobøl.no
+hof.no
+hol.no
+hole.no
+holmestrand.no
+holtalen.no
+holtålen.no
+hornindal.no
+horten.no
+hurdal.no
+hurum.no
+hvaler.no
+hyllestad.no
+hagebostad.no
+hægebostad.no
+hoyanger.no
+høyanger.no
+hoylandet.no
+høylandet.no
+ha.no
+hå.no
+ibestad.no
+inderoy.no
+inderøy.no
+iveland.no
+jevnaker.no
+jondal.no
+jolster.no
+jølster.no
+karasjok.no
+karasjohka.no
+kárášjohka.no
+karlsoy.no
+galsa.no
+gálsá.no
+karmoy.no
+karmøy.no
+kautokeino.no
+guovdageaidnu.no
+klepp.no
+klabu.no
+klæbu.no
+kongsberg.no
+kongsvinger.no
+kragero.no
+kragerø.no
+kristiansand.no
+kristiansund.no
+krodsherad.no
+krødsherad.no
+kvalsund.no
+rahkkeravju.no
+ráhkkerávju.no
+kvam.no
+kvinesdal.no
+kvinnherad.no
+kviteseid.no
+kvitsoy.no
+kvitsøy.no
+kvafjord.no
+kvæfjord.no
+giehtavuoatna.no
+kvanangen.no
+kvænangen.no
+navuotna.no
+návuotna.no
+kafjord.no
+kåfjord.no
+gaivuotna.no
+gáivuotna.no
+larvik.no
+lavangen.no
+lavagis.no
+loabat.no
+loabát.no
+lebesby.no
+davvesiida.no
+leikanger.no
+leirfjord.no
+leka.no
+leksvik.no
+lenvik.no
+leangaviika.no
+leaŋgaviika.no
+lesja.no
+levanger.no
+lier.no
+lierne.no
+lillehammer.no
+lillesand.no
+lindesnes.no
+lindas.no
+lindås.no
+lom.no
+loppa.no
+lahppi.no
+láhppi.no
+lund.no
+lunner.no
+luroy.no
+lurøy.no
+luster.no
+lyngdal.no
+lyngen.no
+ivgu.no
+lardal.no
+lerdal.no
+lærdal.no
+lodingen.no
+lødingen.no
+lorenskog.no
+lørenskog.no
+loten.no
+løten.no
+malvik.no
+masoy.no
+måsøy.no
+muosat.no
+muosát.no
+mandal.no
+marker.no
+marnardal.no
+masfjorden.no
+meland.no
+meldal.no
+melhus.no
+meloy.no
+meløy.no
+meraker.no
+meråker.no
+moareke.no
+moåreke.no
+midsund.no
+midtre-gauldal.no
+modalen.no
+modum.no
+molde.no
+moskenes.no
+moss.no
+mosvik.no
+malselv.no
+målselv.no
+malatvuopmi.no
+málatvuopmi.no
+namdalseid.no
+aejrie.no
+namsos.no
+namsskogan.no
+naamesjevuemie.no
+nååmesjevuemie.no
+laakesvuemie.no
+nannestad.no
+narvik.no
+narviika.no
+naustdal.no
+nedre-eiker.no
+nes.akershus.no
+nes.buskerud.no
+nesna.no
+nesodden.no
+nesseby.no
+unjarga.no
+unjárga.no
+nesset.no
+nissedal.no
+nittedal.no
+nord-aurdal.no
+nord-fron.no
+nord-odal.no
+norddal.no
+nordkapp.no
+davvenjarga.no
+davvenjárga.no
+nordre-land.no
+nordreisa.no
+raisa.no
+ráisa.no
+nore-og-uvdal.no
+notodden.no
+naroy.no
+nærøy.no
+notteroy.no
+nøtterøy.no
+odda.no
+oksnes.no
+øksnes.no
+oppdal.no
+oppegard.no
+oppegård.no
+orkdal.no
+orland.no
+ørland.no
+orskog.no
+ørskog.no
+orsta.no
+ørsta.no
+os.hedmark.no
+os.hordaland.no
+osen.no
+osteroy.no
+osterøy.no
+ostre-toten.no
+østre-toten.no
+overhalla.no
+ovre-eiker.no
+øvre-eiker.no
+oyer.no
+øyer.no
+oygarden.no
+øygarden.no
+oystre-slidre.no
+øystre-slidre.no
+porsanger.no
+porsangu.no
+porsáŋgu.no
+porsgrunn.no
+radoy.no
+radøy.no
+rakkestad.no
+rana.no
+ruovat.no
+randaberg.no
+rauma.no
+rendalen.no
+rennebu.no
+rennesoy.no
+rennesøy.no
+rindal.no
+ringebu.no
+ringerike.no
+ringsaker.no
+rissa.no
+risor.no
+risør.no
+roan.no
+rollag.no
+rygge.no
+ralingen.no
+rælingen.no
+rodoy.no
+rødøy.no
+romskog.no
+rømskog.no
+roros.no
+røros.no
+rost.no
+røst.no
+royken.no
+røyken.no
+royrvik.no
+røyrvik.no
+rade.no
+råde.no
+salangen.no
+siellak.no
+saltdal.no
+salat.no
+sálát.no
+sálat.no
+samnanger.no
+sande.more-og-romsdal.no
+sande.møre-og-romsdal.no
+sande.vestfold.no
+sandefjord.no
+sandnes.no
+sandoy.no
+sandøy.no
+sarpsborg.no
+sauda.no
+sauherad.no
+sel.no
+selbu.no
+selje.no
+seljord.no
+sigdal.no
+siljan.no
+sirdal.no
+skaun.no
+skedsmo.no
+ski.no
+skien.no
+skiptvet.no
+skjervoy.no
+skjervøy.no
+skierva.no
+skiervá.no
+skjak.no
+skjåk.no
+skodje.no
+skanland.no
+skånland.no
+skanit.no
+skánit.no
+smola.no
+smøla.no
+snillfjord.no
+snasa.no
+snåsa.no
+snoasa.no
+snaase.no
+snåase.no
+sogndal.no
+sokndal.no
+sola.no
+solund.no
+songdalen.no
+sortland.no
+spydeberg.no
+stange.no
+stavanger.no
+steigen.no
+steinkjer.no
+stjordal.no
+stjørdal.no
+stokke.no
+stor-elvdal.no
+stord.no
+stordal.no
+storfjord.no
+omasvuotna.no
+strand.no
+stranda.no
+stryn.no
+sula.no
+suldal.no
+sund.no
+sunndal.no
+surnadal.no
+sveio.no
+svelvik.no
+sykkylven.no
+sogne.no
+søgne.no
+somna.no
+sømna.no
+sondre-land.no
+søndre-land.no
+sor-aurdal.no
+sør-aurdal.no
+sor-fron.no
+sør-fron.no
+sor-odal.no
+sør-odal.no
+sor-varanger.no
+sør-varanger.no
+matta-varjjat.no
+mátta-várjjat.no
+sorfold.no
+sørfold.no
+sorreisa.no
+sørreisa.no
+sorum.no
+sørum.no
+tana.no
+deatnu.no
+time.no
+tingvoll.no
+tinn.no
+tjeldsund.no
+dielddanuorri.no
+tjome.no
+tjøme.no
+tokke.no
+tolga.no
+torsken.no
+tranoy.no
+tranøy.no
+tromso.no
+tromsø.no
+tromsa.no
+romsa.no
+trondheim.no
+troandin.no
+trysil.no
+trana.no
+træna.no
+trogstad.no
+trøgstad.no
+tvedestrand.no
+tydal.no
+tynset.no
+tysfjord.no
+divtasvuodna.no
+divttasvuotna.no
+tysnes.no
+tysvar.no
+tysvær.no
+tonsberg.no
+tønsberg.no
+ullensaker.no
+ullensvang.no
+ulvik.no
+utsira.no
+vadso.no
+vadsø.no
+cahcesuolo.no
+čáhcesuolo.no
+vaksdal.no
+valle.no
+vang.no
+vanylven.no
+vardo.no
+vardø.no
+varggat.no
+várggát.no
+vefsn.no
+vaapste.no
+vega.no
+vegarshei.no
+vegårshei.no
+vennesla.no
+verdal.no
+verran.no
+vestby.no
+vestnes.no
+vestre-slidre.no
+vestre-toten.no
+vestvagoy.no
+vestvågøy.no
+vevelstad.no
+vik.no
+vikna.no
+vindafjord.no
+volda.no
+voss.no
+varoy.no
+værøy.no
+vagan.no
+vågan.no
+voagat.no
+vagsoy.no
+vågsøy.no
+vaga.no
+vågå.no
+valer.ostfold.no
+våler.østfold.no
+valer.hedmark.no
+våler.hedmark.no
+
+// np : http://www.mos.com.np/register.html
+*.np
+
+// nr : http://cenpac.net.nr/dns/index.html
+// Confirmed by registry <technician at cenpac.net.nr> 2008-06-17
+nr
+biz.nr
+info.nr
+gov.nr
+edu.nr
+org.nr
+net.nr
+com.nr
+
+// nu : http://en.wikipedia.org/wiki/.nu
+nu
+
+// nz : http://en.wikipedia.org/wiki/.nz
+// Confirmed by registry <jay at nzrs.net.nz> 2014-05-19
+nz
+ac.nz
+co.nz
+cri.nz
+geek.nz
+gen.nz
+govt.nz
+health.nz
+iwi.nz
+kiwi.nz
+maori.nz
+mil.nz
+māori.nz
+net.nz
+org.nz
+parliament.nz
+school.nz
+
+// om : http://en.wikipedia.org/wiki/.om
+om
+co.om
+com.om
+edu.om
+gov.om
+med.om
+museum.om
+net.om
+org.om
+pro.om
+
+// org : http://en.wikipedia.org/wiki/.org
+org
+
+// pa : http://www.nic.pa/
+// Some additional second level "domains" resolve directly as hostnames, such as
+// pannet.pa, so we add a rule for "pa".
+pa
+ac.pa
+gob.pa
+com.pa
+org.pa
+sld.pa
+edu.pa
+net.pa
+ing.pa
+abo.pa
+med.pa
+nom.pa
+
+// pe : https://www.nic.pe/InformeFinalComision.pdf
+pe
+edu.pe
+gob.pe
+nom.pe
+mil.pe
+org.pe
+com.pe
+net.pe
+
+// pf : http://www.gobin.info/domainname/formulaire-pf.pdf
+pf
+com.pf
+org.pf
+edu.pf
+
+// pg : http://en.wikipedia.org/wiki/.pg
+*.pg
+
+// ph : http://www.domains.ph/FAQ2.asp
+// Submitted by registry <jed at email.com.ph> 2008-06-13
+ph
+com.ph
+net.ph
+org.ph
+gov.ph
+edu.ph
+ngo.ph
+mil.ph
+i.ph
+
+// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK
+pk
+com.pk
+net.pk
+edu.pk
+org.pk
+fam.pk
+biz.pk
+web.pk
+gov.pk
+gob.pk
+gok.pk
+gon.pk
+gop.pk
+gos.pk
+info.pk
+
+// pl http://www.dns.pl/english/index.html
+// updated by .PL registry on 2015-04-28
+pl
+com.pl
+net.pl
+org.pl
+// pl functional domains (http://www.dns.pl/english/index.html)
+aid.pl
+agro.pl
+atm.pl
+auto.pl
+biz.pl
+edu.pl
+gmina.pl
+gsm.pl
+info.pl
+mail.pl
+miasta.pl
+media.pl
+mil.pl
+nieruchomosci.pl
+nom.pl
+pc.pl
+powiat.pl
+priv.pl
+realestate.pl
+rel.pl
+sex.pl
+shop.pl
+sklep.pl
+sos.pl
+szkola.pl
+targi.pl
+tm.pl
+tourism.pl
+travel.pl
+turystyka.pl
+// Government domains
+gov.pl
+ap.gov.pl
+ic.gov.pl
+is.gov.pl
+us.gov.pl
+kmpsp.gov.pl
+kppsp.gov.pl
+kwpsp.gov.pl
+psp.gov.pl
+wskr.gov.pl
+kwp.gov.pl
+mw.gov.pl
+ug.gov.pl
+um.gov.pl
+umig.gov.pl
+ugim.gov.pl
+upow.gov.pl
+uw.gov.pl
+starostwo.gov.pl
+pa.gov.pl
+po.gov.pl
+psse.gov.pl
+pup.gov.pl
+rzgw.gov.pl
+sa.gov.pl
+so.gov.pl
+sr.gov.pl
+wsa.gov.pl
+sko.gov.pl
+uzs.gov.pl
+wiih.gov.pl
+winb.gov.pl
+pinb.gov.pl
+wios.gov.pl
+witd.gov.pl
+wzmiuw.gov.pl
+piw.gov.pl
+wiw.gov.pl
+griw.gov.pl
+wif.gov.pl
+oum.gov.pl
+sdn.gov.pl
+zp.gov.pl
+uppo.gov.pl
+mup.gov.pl
+wuoz.gov.pl
+konsulat.gov.pl
+oirm.gov.pl
+// pl regional domains (http://www.dns.pl/english/index.html)
+augustow.pl
+babia-gora.pl
+bedzin.pl
+beskidy.pl
+bialowieza.pl
+bialystok.pl
+bielawa.pl
+bieszczady.pl
+boleslawiec.pl
+bydgoszcz.pl
+bytom.pl
+cieszyn.pl
+czeladz.pl
+czest.pl
+dlugoleka.pl
+elblag.pl
+elk.pl
+glogow.pl
+gniezno.pl
+gorlice.pl
+grajewo.pl
+ilawa.pl
+jaworzno.pl
+jelenia-gora.pl
+jgora.pl
+kalisz.pl
+kazimierz-dolny.pl
+karpacz.pl
+kartuzy.pl
+kaszuby.pl
+katowice.pl
+kepno.pl
+ketrzyn.pl
+klodzko.pl
+kobierzyce.pl
+kolobrzeg.pl
+konin.pl
+konskowola.pl
+kutno.pl
+lapy.pl
+lebork.pl
+legnica.pl
+lezajsk.pl
+limanowa.pl
+lomza.pl
+lowicz.pl
+lubin.pl
+lukow.pl
+malbork.pl
+malopolska.pl
+mazowsze.pl
+mazury.pl
+mielec.pl
+mielno.pl
+mragowo.pl
+naklo.pl
+nowaruda.pl
+nysa.pl
+olawa.pl
+olecko.pl
+olkusz.pl
+olsztyn.pl
+opoczno.pl
+opole.pl
+ostroda.pl
+ostroleka.pl
+ostrowiec.pl
+ostrowwlkp.pl
+pila.pl
+pisz.pl
+podhale.pl
+podlasie.pl
+polkowice.pl
+pomorze.pl
+pomorskie.pl
+prochowice.pl
+pruszkow.pl
+przeworsk.pl
+pulawy.pl
+radom.pl
+rawa-maz.pl
+rybnik.pl
+rzeszow.pl
+sanok.pl
+sejny.pl
+slask.pl
+slupsk.pl
+sosnowiec.pl
+stalowa-wola.pl
+skoczow.pl
+starachowice.pl
+stargard.pl
+suwalki.pl
+swidnica.pl
+swiebodzin.pl
+swinoujscie.pl
+szczecin.pl
+szczytno.pl
+tarnobrzeg.pl
+tgory.pl
+turek.pl
+tychy.pl
+ustka.pl
+walbrzych.pl
+warmia.pl
+warszawa.pl
+waw.pl
+wegrow.pl
+wielun.pl
+wlocl.pl
+wloclawek.pl
+wodzislaw.pl
+wolomin.pl
+wroclaw.pl
+zachpomor.pl
+zagan.pl
+zarow.pl
+zgora.pl
+zgorzelec.pl
+
+// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+pm
+
+// pn : http://www.government.pn/PnRegistry/policies.htm
+pn
+gov.pn
+co.pn
+org.pn
+edu.pn
+net.pn
+
+// post : http://en.wikipedia.org/wiki/.post
+post
+
+// pr : http://www.nic.pr/index.asp?f=1
+pr
+com.pr
+net.pr
+org.pr
+gov.pr
+edu.pr
+isla.pr
+pro.pr
+biz.pr
+info.pr
+name.pr
+// these aren't mentioned on nic.pr, but on http://en.wikipedia.org/wiki/.pr
+est.pr
+prof.pr
+ac.pr
+
+// pro : http://www.nic.pro/support_faq.htm
+pro
+aca.pro
+bar.pro
+cpa.pro
+jur.pro
+law.pro
+med.pro
+eng.pro
+
+// ps : http://en.wikipedia.org/wiki/.ps
+// http://www.nic.ps/registration/policy.html#reg
+ps
+edu.ps
+gov.ps
+sec.ps
+plo.ps
+com.ps
+org.ps
+net.ps
+
+// pt : http://online.dns.pt/dns/start_dns
+pt
+net.pt
+gov.pt
+org.pt
+edu.pt
+int.pt
+publ.pt
+com.pt
+nome.pt
+
+// pw : http://en.wikipedia.org/wiki/.pw
+pw
+co.pw
+ne.pw
+or.pw
+ed.pw
+go.pw
+belau.pw
+
+// py : http://www.nic.py/pautas.html#seccion_9
+// Confirmed by registry 2012-10-03
+py
+com.py
+coop.py
+edu.py
+gov.py
+mil.py
+net.py
+org.py
+
+// qa : http://domains.qa/en/
+qa
+com.qa
+edu.qa
+gov.qa
+mil.qa
+name.qa
+net.qa
+org.qa
+sch.qa
+
+// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs
+re
+com.re
+asso.re
+nom.re
+
+// ro : http://www.rotld.ro/
+ro
+com.ro
+org.ro
+tm.ro
+nt.ro
+nom.ro
+info.ro
+rec.ro
+arts.ro
+firm.ro
+store.ro
+www.ro
+
+// rs : http://en.wikipedia.org/wiki/.rs
+rs
+co.rs
+org.rs
+edu.rs
+ac.rs
+gov.rs
+in.rs
+
+// ru : http://www.cctld.ru/ru/docs/aktiv_8.php
+// Industry domains
+ru
+ac.ru
+com.ru
+edu.ru
+int.ru
+net.ru
+org.ru
+pp.ru
+// Geographical domains
+adygeya.ru
+altai.ru
+amur.ru
+arkhangelsk.ru
+astrakhan.ru
+bashkiria.ru
+belgorod.ru
+bir.ru
+bryansk.ru
+buryatia.ru
+cbg.ru
+chel.ru
+chelyabinsk.ru
+chita.ru
+chukotka.ru
+chuvashia.ru
+dagestan.ru
+dudinka.ru
+e-burg.ru
+grozny.ru
+irkutsk.ru
+ivanovo.ru
+izhevsk.ru
+jar.ru
+joshkar-ola.ru
+kalmykia.ru
+kaluga.ru
+kamchatka.ru
+karelia.ru
+kazan.ru
+kchr.ru
+kemerovo.ru
+khabarovsk.ru
+khakassia.ru
+khv.ru
+kirov.ru
+koenig.ru
+komi.ru
+kostroma.ru
+krasnoyarsk.ru
+kuban.ru
+kurgan.ru
+kursk.ru
+lipetsk.ru
+magadan.ru
+mari.ru
+mari-el.ru
+marine.ru
+mordovia.ru
+// mosreg.ru  Bug 1090800 - removed at request of Aleksey Konstantinov <konstantinovav at mosreg.ru>
+msk.ru
+murmansk.ru
+nalchik.ru
+nnov.ru
+nov.ru
+novosibirsk.ru
+nsk.ru
+omsk.ru
+orenburg.ru
+oryol.ru
+palana.ru
+penza.ru
+perm.ru
+ptz.ru
+rnd.ru
+ryazan.ru
+sakhalin.ru
+samara.ru
+saratov.ru
+simbirsk.ru
+smolensk.ru
+spb.ru
+stavropol.ru
+stv.ru
+surgut.ru
+tambov.ru
+tatarstan.ru
+tom.ru
+tomsk.ru
+tsaritsyn.ru
+tsk.ru
+tula.ru
+tuva.ru
+tver.ru
+tyumen.ru
+udm.ru
+udmurtia.ru
+ulan-ude.ru
+vladikavkaz.ru
+vladimir.ru
+vladivostok.ru
+volgograd.ru
+vologda.ru
+voronezh.ru
+vrn.ru
+vyatka.ru
+yakutia.ru
+yamal.ru
+yaroslavl.ru
+yekaterinburg.ru
+yuzhno-sakhalinsk.ru
+// More geographical domains
+amursk.ru
+baikal.ru
+cmw.ru
+fareast.ru
+jamal.ru
+kms.ru
+k-uralsk.ru
+kustanai.ru
+kuzbass.ru
+magnitka.ru
+mytis.ru
+nakhodka.ru
+nkz.ru
+norilsk.ru
+oskol.ru
+pyatigorsk.ru
+rubtsovsk.ru
+snz.ru
+syzran.ru
+vdonsk.ru
+zgrad.ru
+// State domains
+gov.ru
+mil.ru
+// Technical domains
+test.ru
+
+// rw : http://www.nic.rw/cgi-bin/policy.pl
+rw
+gov.rw
+net.rw
+edu.rw
+ac.rw
+com.rw
+co.rw
+int.rw
+mil.rw
+gouv.rw
+
+// sa : http://www.nic.net.sa/
+sa
+com.sa
+net.sa
+org.sa
+gov.sa
+med.sa
+pub.sa
+edu.sa
+sch.sa
+
+// sb : http://www.sbnic.net.sb/
+// Submitted by registry <lee.humphries at telekom.com.sb> 2008-06-08
+sb
+com.sb
+edu.sb
+gov.sb
+net.sb
+org.sb
+
+// sc : http://www.nic.sc/
+sc
+com.sc
+gov.sc
+net.sc
+org.sc
+edu.sc
+
+// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm
+// Submitted by registry <admin at isoc.sd> 2008-06-17
+sd
+com.sd
+net.sd
+org.sd
+edu.sd
+med.sd
+tv.sd
+gov.sd
+info.sd
+
+// se : http://en.wikipedia.org/wiki/.se
+// Submitted by registry <patrik.wallstrom at iis.se> 2014-03-18
+se
+a.se
+ac.se
+b.se
+bd.se
+brand.se
+c.se
+d.se
+e.se
+f.se
+fh.se
+fhsk.se
+fhv.se
+g.se
+h.se
+i.se
+k.se
+komforb.se
+kommunalforbund.se
+komvux.se
+l.se
+lanbib.se
+m.se
+n.se
+naturbruksgymn.se
+o.se
+org.se
+p.se
+parti.se
+pp.se
+press.se
+r.se
+s.se
+t.se
+tm.se
+u.se
+w.se
+x.se
+y.se
+z.se
+
+// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines
+sg
+com.sg
+net.sg
+org.sg
+gov.sg
+edu.sg
+per.sg
+
+// sh : http://www.nic.sh/registrar.html
+sh
+com.sh
+net.sh
+gov.sh
+org.sh
+mil.sh
+
+// si : http://en.wikipedia.org/wiki/.si
+si
+
+// sj : No registrations at this time.
+// Submitted by registry <jarle at uninett.no> 2008-06-16
+sj
+
+// sk : http://en.wikipedia.org/wiki/.sk
+// list of 2nd level domains ?
+sk
+
+// sl : http://www.nic.sl
+// Submitted by registry <adam at neoip.com> 2008-06-12
+sl
+com.sl
+net.sl
+edu.sl
+gov.sl
+org.sl
+
+// sm : http://en.wikipedia.org/wiki/.sm
+sm
+
+// sn : http://en.wikipedia.org/wiki/.sn
+sn
+art.sn
+com.sn
+edu.sn
+gouv.sn
+org.sn
+perso.sn
+univ.sn
+
+// so : http://www.soregistry.com/
+so
+com.so
+net.so
+org.so
+
+// sr : http://en.wikipedia.org/wiki/.sr
+sr
+
+// st : http://www.nic.st/html/policyrules/
+st
+co.st
+com.st
+consulado.st
+edu.st
+embaixada.st
+gov.st
+mil.st
+net.st
+org.st
+principe.st
+saotome.st
+store.st
+
+// su : http://en.wikipedia.org/wiki/.su
+su
+adygeya.su
+arkhangelsk.su
+balashov.su
+bashkiria.su
+bryansk.su
+dagestan.su
+grozny.su
+ivanovo.su
+kalmykia.su
+kaluga.su
+karelia.su
+khakassia.su
+krasnodar.su
+kurgan.su
+lenug.su
+mordovia.su
+msk.su
+murmansk.su
+nalchik.su
+nov.su
+obninsk.su
+penza.su
+pokrovsk.su
+sochi.su
+spb.su
+togliatti.su
+troitsk.su
+tula.su
+tuva.su
+vladikavkaz.su
+vladimir.su
+vologda.su
+
+// sv : http://www.svnet.org.sv/niveldos.pdf
+sv
+com.sv
+edu.sv
+gob.sv
+org.sv
+red.sv
+
+// sx : http://en.wikipedia.org/wiki/.sx
+// Confirmed by registry <jcvignes at openregistry.com> 2012-05-31
+sx
+gov.sx
+
+// sy : http://en.wikipedia.org/wiki/.sy
+// see also: http://www.gobin.info/domainname/sy.doc
+sy
+edu.sy
+gov.sy
+net.sy
+mil.sy
+com.sy
+org.sy
+
+// sz : http://en.wikipedia.org/wiki/.sz
+// http://www.sispa.org.sz/
+sz
+co.sz
+ac.sz
+org.sz
+
+// tc : http://en.wikipedia.org/wiki/.tc
+tc
+
+// td : http://en.wikipedia.org/wiki/.td
+td
+
+// tel: http://en.wikipedia.org/wiki/.tel
+// http://www.telnic.org/
+tel
+
+// tf : http://en.wikipedia.org/wiki/.tf
+tf
+
+// tg : http://en.wikipedia.org/wiki/.tg
+// http://www.nic.tg/
+tg
+
+// th : http://en.wikipedia.org/wiki/.th
+// Submitted by registry <krit at thains.co.th> 2008-06-17
+th
+ac.th
+co.th
+go.th
+in.th
+mi.th
+net.th
+or.th
+
+// tj : http://www.nic.tj/policy.html
+tj
+ac.tj
+biz.tj
+co.tj
+com.tj
+edu.tj
+go.tj
+gov.tj
+int.tj
+mil.tj
+name.tj
+net.tj
+nic.tj
+org.tj
+test.tj
+web.tj
+
+// tk : http://en.wikipedia.org/wiki/.tk
+tk
+
+// tl : http://en.wikipedia.org/wiki/.tl
+tl
+gov.tl
+
+// tm : http://www.nic.tm/local.html
+tm
+com.tm
+co.tm
+org.tm
+net.tm
+nom.tm
+gov.tm
+mil.tm
+edu.tm
+
+// tn : http://en.wikipedia.org/wiki/.tn
+// http://whois.ati.tn/
+tn
+com.tn
+ens.tn
+fin.tn
+gov.tn
+ind.tn
+intl.tn
+nat.tn
+net.tn
+org.tn
+info.tn
+perso.tn
+tourism.tn
+edunet.tn
+rnrt.tn
+rns.tn
+rnu.tn
+mincom.tn
+agrinet.tn
+defense.tn
+turen.tn
+
+// to : http://en.wikipedia.org/wiki/.to
+// Submitted by registry <egullich at colo.to> 2008-06-17
+to
+com.to
+gov.to
+net.to
+org.to
+edu.to
+mil.to
+
+// tp : No registrations at this time.
+// Submitted by Ryan Sleevi <ryan.sleevi at gmail.com> 2014-01-03
+tp
+
+// subTLDs: https://www.nic.tr/forms/eng/policies.pdf
+//     and: https://www.nic.tr/forms/politikalar.pdf
+// Submitted by <mehmetgurevin at gmail.com> 2014-07-19
+tr
+com.tr
+info.tr
+biz.tr
+net.tr
+org.tr
+web.tr
+gen.tr
+tv.tr
+av.tr
+dr.tr
+bbs.tr
+name.tr
+tel.tr
+gov.tr
+bel.tr
+pol.tr
+mil.tr
+k12.tr
+edu.tr
+kep.tr
+
+// Used by Northern Cyprus
+nc.tr
+
+// Used by government agencies of Northern Cyprus
+gov.nc.tr
+
+// travel : http://en.wikipedia.org/wiki/.travel
+travel
+
+// tt : http://www.nic.tt/
+tt
+co.tt
+com.tt
+org.tt
+net.tt
+biz.tt
+info.tt
+pro.tt
+int.tt
+coop.tt
+jobs.tt
+mobi.tt
+travel.tt
+museum.tt
+aero.tt
+name.tt
+gov.tt
+edu.tt
+
+// tv : http://en.wikipedia.org/wiki/.tv
+// Not listing any 2LDs as reserved since none seem to exist in practice,
+// Wikipedia notwithstanding.
+tv
+
+// tw : http://en.wikipedia.org/wiki/.tw
+tw
+edu.tw
+gov.tw
+mil.tw
+com.tw
+net.tw
+org.tw
+idv.tw
+game.tw
+ebiz.tw
+club.tw
+網路.tw
+組織.tw
+商業.tw
+
+// tz : http://www.tznic.or.tz/index.php/domains
+// Confirmed by registry <manager at tznic.or.tz> 2013-01-22
+tz
+ac.tz
+co.tz
+go.tz
+hotel.tz
+info.tz
+me.tz
+mil.tz
+mobi.tz
+ne.tz
+or.tz
+sc.tz
+tv.tz
+
+// ua : https://hostmaster.ua/policy/?ua
+// Submitted by registry <dk at cctld.ua> 2012-04-27
+ua
+// ua 2LD
+com.ua
+edu.ua
+gov.ua
+in.ua
+net.ua
+org.ua
+// ua geographic names
+// https://hostmaster.ua/2ld/
+cherkassy.ua
+cherkasy.ua
+chernigov.ua
+chernihiv.ua
+chernivtsi.ua
+chernovtsy.ua
+ck.ua
+cn.ua
+cr.ua
+crimea.ua
+cv.ua
+dn.ua
+dnepropetrovsk.ua
+dnipropetrovsk.ua
+dominic.ua
+donetsk.ua
+dp.ua
+if.ua
+ivano-frankivsk.ua
+kh.ua
+kharkiv.ua
+kharkov.ua
+kherson.ua
+khmelnitskiy.ua
+khmelnytskyi.ua
+kiev.ua
+kirovograd.ua
+km.ua
+kr.ua
+krym.ua
+ks.ua
+kv.ua
+kyiv.ua
+lg.ua
+lt.ua
+lugansk.ua
+lutsk.ua
+lv.ua
+lviv.ua
+mk.ua
+mykolaiv.ua
+nikolaev.ua
+od.ua
+odesa.ua
+odessa.ua
+pl.ua
+poltava.ua
+rivne.ua
+rovno.ua
+rv.ua
+sb.ua
+sebastopol.ua
+sevastopol.ua
+sm.ua
+sumy.ua
+te.ua
+ternopil.ua
+uz.ua
+uzhgorod.ua
+vinnica.ua
+vinnytsia.ua
+vn.ua
+volyn.ua
+yalta.ua
+zaporizhzhe.ua
+zaporizhzhia.ua
+zhitomir.ua
+zhytomyr.ua
+zp.ua
+zt.ua
+
+// Private registries in .ua
+co.ua
+pp.ua
+
+// ug : https://www.registry.co.ug/
+ug
+co.ug
+or.ug
+ac.ug
+sc.ug
+go.ug
+ne.ug
+com.ug
+org.ug
+
+// uk : http://en.wikipedia.org/wiki/.uk
+// Submitted by registry <Michael.Daly at nominet.org.uk>
+uk
+ac.uk
+co.uk
+gov.uk
+ltd.uk
+me.uk
+net.uk
+nhs.uk
+org.uk
+plc.uk
+police.uk
+*.sch.uk
+
+// us : http://en.wikipedia.org/wiki/.us
+us
+dni.us
+fed.us
+isa.us
+kids.us
+nsn.us
+// us geographic names
+ak.us
+al.us
+ar.us
+as.us
+az.us
+ca.us
+co.us
+ct.us
+dc.us
+de.us
+fl.us
+ga.us
+gu.us
+hi.us
+ia.us
+id.us
+il.us
+in.us
+ks.us
+ky.us
+la.us
+ma.us
+md.us
+me.us
+mi.us
+mn.us
+mo.us
+ms.us
+mt.us
+nc.us
+nd.us
+ne.us
+nh.us
+nj.us
+nm.us
+nv.us
+ny.us
+oh.us
+ok.us
+or.us
+pa.us
+pr.us
+ri.us
+sc.us
+sd.us
+tn.us
+tx.us
+ut.us
+vi.us
+vt.us
+va.us
+wa.us
+wi.us
+wv.us
+wy.us
+// The registrar notes several more specific domains available in each state,
+// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat
+// haphazard; in some states these domains resolve as addresses, while in others
+// only subdomains are available, or even nothing at all. We include the
+// most common ones where it's clear that different sites are different
+// entities.
+k12.ak.us
+k12.al.us
+k12.ar.us
+k12.as.us
+k12.az.us
+k12.ca.us
+k12.co.us
+k12.ct.us
+k12.dc.us
+k12.de.us
+k12.fl.us
+k12.ga.us
+k12.gu.us
+// k12.hi.us  Bug 614565 - Hawaii has a state-wide DOE login
+k12.ia.us
+k12.id.us
+k12.il.us
+k12.in.us
+k12.ks.us
+k12.ky.us
+k12.la.us
+k12.ma.us
+k12.md.us
+k12.me.us
+k12.mi.us
+k12.mn.us
+k12.mo.us
+k12.ms.us
+k12.mt.us
+k12.nc.us
+// k12.nd.us  Bug 1028347 - Removed at request of Travis Rosso <trossow at nd.gov>
+k12.ne.us
+k12.nh.us
+k12.nj.us
+k12.nm.us
+k12.nv.us
+k12.ny.us
+k12.oh.us
+k12.ok.us
+k12.or.us
+k12.pa.us
+k12.pr.us
+k12.ri.us
+k12.sc.us
+// k12.sd.us  Bug 934131 - Removed at request of James Booze <James.Booze at k12.sd.us>
+k12.tn.us
+k12.tx.us
+k12.ut.us
+k12.vi.us
+k12.vt.us
+k12.va.us
+k12.wa.us
+k12.wi.us
+// k12.wv.us  Bug 947705 - Removed at request of Verne Britton <verne at wvnet.edu>
+k12.wy.us
+cc.ak.us
+cc.al.us
+cc.ar.us
+cc.as.us
+cc.az.us
+cc.ca.us
+cc.co.us
+cc.ct.us
+cc.dc.us
+cc.de.us
+cc.fl.us
+cc.ga.us
+cc.gu.us
+cc.hi.us
+cc.ia.us
+cc.id.us
+cc.il.us
+cc.in.us
+cc.ks.us
+cc.ky.us
+cc.la.us
+cc.ma.us
+cc.md.us
+cc.me.us
+cc.mi.us
+cc.mn.us
+cc.mo.us
+cc.ms.us
+cc.mt.us
+cc.nc.us
+cc.nd.us
+cc.ne.us
+cc.nh.us
+cc.nj.us
+cc.nm.us
+cc.nv.us
+cc.ny.us
+cc.oh.us
+cc.ok.us
+cc.or.us
+cc.pa.us
+cc.pr.us
+cc.ri.us
+cc.sc.us
+cc.sd.us
+cc.tn.us
+cc.tx.us
+cc.ut.us
+cc.vi.us
+cc.vt.us
+cc.va.us
+cc.wa.us
+cc.wi.us
+cc.wv.us
+cc.wy.us
+lib.ak.us
+lib.al.us
+lib.ar.us
+lib.as.us
+lib.az.us
+lib.ca.us
+lib.co.us
+lib.ct.us
+lib.dc.us
+lib.de.us
+lib.fl.us
+lib.ga.us
+lib.gu.us
+lib.hi.us
+lib.ia.us
+lib.id.us
+lib.il.us
+lib.in.us
+lib.ks.us
+lib.ky.us
+lib.la.us
+lib.ma.us
+lib.md.us
+lib.me.us
+lib.mi.us
+lib.mn.us
+lib.mo.us
+lib.ms.us
+lib.mt.us
+lib.nc.us
+lib.nd.us
+lib.ne.us
+lib.nh.us
+lib.nj.us
+lib.nm.us
+lib.nv.us
+lib.ny.us
+lib.oh.us
+lib.ok.us
+lib.or.us
+lib.pa.us
+lib.pr.us
+lib.ri.us
+lib.sc.us
+lib.sd.us
+lib.tn.us
+lib.tx.us
+lib.ut.us
+lib.vi.us
+lib.vt.us
+lib.va.us
+lib.wa.us
+lib.wi.us
+// lib.wv.us  Bug 941670 - Removed at request of Larry W Arnold <arnold at wvlc.lib.wv.us>
+lib.wy.us
+// k12.ma.us contains school districts in Massachusetts. The 4LDs are
+//  managed indepedently except for private (PVT), charter (CHTR) and
+//  parochial (PAROCH) schools.  Those are delegated dorectly to the
+//  5LD operators.   <k12-ma-hostmaster _ at _ rsuc.gweep.net>
+pvt.k12.ma.us
+chtr.k12.ma.us
+paroch.k12.ma.us
+
+// uy : http://www.nic.org.uy/
+uy
+com.uy
+edu.uy
+gub.uy
+mil.uy
+net.uy
+org.uy
+
+// uz : http://www.reg.uz/
+uz
+co.uz
+com.uz
+net.uz
+org.uz
+
+// va : http://en.wikipedia.org/wiki/.va
+va
+
+// vc : http://en.wikipedia.org/wiki/.vc
+// Submitted by registry <kshah at ca.afilias.info> 2008-06-13
+vc
+com.vc
+net.vc
+org.vc
+gov.vc
+mil.vc
+edu.vc
+
+// ve : https://registro.nic.ve/
+// Confirmed by registry 2012-10-04
+// Updated 2014-05-20 - Bug 940478
+ve
+arts.ve
+co.ve
+com.ve
+e12.ve
+edu.ve
+firm.ve
+gob.ve
+gov.ve
+info.ve
+int.ve
+mil.ve
+net.ve
+org.ve
+rec.ve
+store.ve
+tec.ve
+web.ve
+
+// vg : http://en.wikipedia.org/wiki/.vg
+vg
+
+// vi : http://www.nic.vi/newdomainform.htm
+// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other
+// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they
+// are available for registration (which they do not seem to be).
+vi
+co.vi
+com.vi
+k12.vi
+net.vi
+org.vi
+
+// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp
+vn
+com.vn
+net.vn
+org.vn
+edu.vn
+gov.vn
+int.vn
+ac.vn
+biz.vn
+info.vn
+name.vn
+pro.vn
+health.vn
+
+// vu : http://en.wikipedia.org/wiki/.vu
+// http://www.vunic.vu/
+vu
+com.vu
+edu.vu
+net.vu
+org.vu
+
+// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+wf
+
+// ws : http://en.wikipedia.org/wiki/.ws
+// http://samoanic.ws/index.dhtml
+ws
+com.ws
+net.ws
+org.ws
+gov.ws
+edu.ws
+
+// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+yt
+
+// IDN ccTLDs
+// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then
+// U-label, and follow this format:
+// // A-Label ("<Latin renderings>", <language name>[, variant info]) : <ISO 3166 ccTLD>
+// // [sponsoring org]
+// U-Label
+
+// xn--mgbaam7a8h ("Emerat", Arabic) : AE
+// http://nic.ae/english/arabicdomain/rules.jsp
+امارات
+
+// xn--y9a3aq ("hye", Armenian) : AM
+// ISOC AM (operated by .am Registry)
+հայ
+
+// xn--54b7fta0cc ("Bangla", Bangla) : BD
+বাংলা
+
+// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY
+// Operated by .by registry
+бел
+
+// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+中国
+
+// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+中國
+
+// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ
+الجزائر
+
+// xn--wgbh1c ("Egypt/Masr", Arabic) : EG
+// http://www.dotmasr.eg/
+مصر
+
+// xn--node ("ge", Georgian Mkhedruli) : GE
+გე
+
+// xn--qxam ("el", Greek) : GR
+// Hellenic Ministry of Infrastructure, Transport, and Networks
+ελ
+
+// xn--j6w193g ("Hong Kong", Chinese) : HK
+// https://www2.hkirc.hk/register/rules.jsp
+香港
+
+// xn--h2brj9c ("Bharat", Devanagari) : IN
+// India
+भारत
+
+// xn--mgbbh1a71e ("Bharat", Arabic) : IN
+// India
+بھارت
+
+// xn--fpcrj9c3d ("Bharat", Telugu) : IN
+// India
+భారత్
+
+// xn--gecrj9c ("Bharat", Gujarati) : IN
+// India
+ભારત
+
+// xn--s9brj9c ("Bharat", Gurmukhi) : IN
+// India
+ਭਾਰਤ
+
+// xn--45brj9c ("Bharat", Bengali) : IN
+// India
+ভারত
+
+// xn--xkc2dl3a5ee0h ("India", Tamil) : IN
+// India
+இந்தியா
+
+// xn--mgba3a4f16a ("Iran", Persian) : IR
+ایران
+
+// xn--mgba3a4fra ("Iran", Arabic) : IR
+ايران
+
+// xn--mgbtx2b ("Iraq", Arabic) : IQ
+// Communications and Media Commission
+عراق
+
+// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO
+// National Information Technology Center (NITC)
+// Royal Scientific Society, Al-Jubeiha
+الاردن
+
+// xn--3e0b707e ("Republic of Korea", Hangul) : KR
+한국
+
+// xn--80ao21a ("Kaz", Kazakh) : KZ
+қаз
+
+// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK
+// http://nic.lk
+ලංකා
+
+// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK
+// http://nic.lk
+இலங்கை
+
+// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA
+المغرب
+
+// xn--d1alf ("mkd", Macedonian) : MK
+// MARnet
+мкд
+
+// xn--l1acc ("mon", Mongolian) : MN
+мон
+
+// xn--mix891f ("Macao", Chinese, Traditional) : MO
+// MONIC / HNET Asia (Registry Operator for .mo)
+澳門
+
+// xn--mix082f ("Macao", Chinese, Simplified) : MO
+澳门
+
+// xn--mgbx4cd0ab ("Malaysia", Malay) : MY
+مليسيا
+
+// xn--mgb9awbf ("Oman", Arabic) : OM
+عمان
+
+// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK
+پاکستان
+
+// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK
+پاكستان
+
+// xn--ygbi2ammx ("Falasteen", Arabic) : PS
+// The Palestinian National Internet Naming Authority (PNINA)
+// http://www.pnina.ps
+فلسطين
+
+// xn--90a3ac ("srb", Cyrillic) : RS
+// http://www.rnids.rs/en/the-.срб-domain
+срб
+пр.срб
+орг.срб
+обр.срб
+од.срб
+упр.срб
+ак.срб
+
+// xn--p1ai ("rf", Russian-Cyrillic) : RU
+// http://www.cctld.ru/en/docs/rulesrf.php
+рф
+
+// xn--wgbl6a ("Qatar", Arabic) : QA
+// http://www.ict.gov.qa/
+قطر
+
+// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA
+// http://www.nic.net.sa/
+السعودية
+
+// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant)  : SA
+السعودیة
+
+// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA
+السعودیۃ
+
+// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA
+السعوديه
+
+// xn--mgbpl2fh ("sudan", Arabic) : SD
+// Operated by .sd registry
+سودان
+
+// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG
+新加坡
+
+// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG
+சிங்கப்பூர்
+
+// xn--ogbpf8fl ("Syria", Arabic) : SY
+سورية
+
+// xn--mgbtf8fl ("Syria", Arabic, variant) : SY
+سوريا
+
+// xn--o3cw4h ("Thai", Thai) : TH
+// http://www.thnic.co.th
+ไทย
+
+// xn--pgbs0dh ("Tunisia", Arabic) : TN
+// http://nic.tn
+تونس
+
+// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+台灣
+
+// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+台湾
+
+// xn--nnx388a ("Taiwan", Chinese, variant) : TW
+臺灣
+
+// xn--j1amh ("ukr", Cyrillic) : UA
+укр
+
+// xn--mgb2ddes ("AlYemen", Arabic) : YE
+اليمن
+
+// xxx : http://icmregistry.com
+xxx
+
+// ye : http://www.y.net.ye/services/domain_name.htm
+*.ye
+
+// za : http://www.zadna.org.za/slds.html
+*.za
+
+// zm : http://en.wikipedia.org/wiki/.zm
+*.zm
+
+// zw : http://en.wikipedia.org/wiki/.zw
+*.zw
+
+
+// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-05-06T09:31:08Z
+
+// aaa : 2015-02-26 American Automobile Association, Inc.
+aaa
+
+// abb : 2014-10-24 ABB Ltd
+abb
+
+// abbott : 2014-07-24 Abbott Laboratories, Inc.
+abbott
+
+// abogado : 2014-04-24 Top Level Domain Holdings Limited
+abogado
+
+// academy : 2013-11-07 Half Oaks, LLC
+academy
+
+// accenture : 2014-08-15 Accenture plc
+accenture
+
+// accountant : 2014-11-20 dot Accountant Limited
+accountant
+
+// accountants : 2014-03-20 Knob Town, LLC
+accountants
+
+// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG
+aco
+
+// active : 2014-05-01 The Active Network, Inc
+active
+
+// actor : 2013-12-12 United TLD Holdco Ltd.
+actor
+
+// ads : 2014-12-04 Charleston Road Registry Inc.
+ads
+
+// adult : 2014-10-16 ICM Registry AD LLC
+adult
+
+// aeg : 2015-03-19 Aktiebolaget Electrolux
+aeg
+
+// afl : 2014-10-02 Australian Football League
+afl
+
+// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa
+africa
+
+// africamagic : 2015-03-05 Electronic Media Network (Pty) Ltd
+africamagic
+
+// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+agakhan
+
+// agency : 2013-11-14 Steel Falls, LLC
+agency
+
+// aig : 2014-12-18 American International Group, Inc.
+aig
+
+// airforce : 2014-03-06 United TLD Holdco Ltd.
+airforce
+
+// airtel : 2014-10-24 Bharti Airtel Limited
+airtel
+
+// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+akdn
+
+// alibaba : 2015-01-15 Alibaba Group Holding Limited
+alibaba
+
+// alipay : 2015-01-15 Alibaba Group Holding Limited
+alipay
+
+// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft
+allfinanz
+
+// alsace : 2014-07-02 REGION D ALSACE
+alsace
+
+// amsterdam : 2014-07-24 Gemeente Amsterdam
+amsterdam
+
+// analytics : 2014-12-18 Campus IP LLC
+analytics
+
+// android : 2014-08-07 Charleston Road Registry Inc.
+android
+
+// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+anquan
+
+// apartments : 2014-12-11 June Maple, LLC
+apartments
+
+// aquarelle : 2014-07-24 Aquarelle.com
+aquarelle
+
+// aramco : 2014-11-20 Aramco Services Company
+aramco
+
+// archi : 2014-02-06 STARTING DOT LIMITED
+archi
+
+// army : 2014-03-06 United TLD Holdco Ltd.
+army
+
+// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E.
+arte
+
+// associates : 2014-03-06 Baxter Hill, LLC
+associates
+
+// attorney : 2014-03-20
+attorney
+
+// auction : 2014-03-20
+auction
+
+// audio : 2014-03-20 Uniregistry, Corp.
+audio
+
+// author : 2014-12-18 Amazon EU S.à r.l.
+author
+
+// auto : 2014-11-13 Uniregistry, Corp.
+auto
+
+// autos : 2014-01-09 DERAutos, LLC
+autos
+
+// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca
+avianca
+
+// axa : 2013-12-19 AXA SA
+axa
+
+// azure : 2014-12-18 Microsoft Corporation
+azure
+
+// baby : 2015-04-09 Johnson & Johnson Services, Inc.
+baby
+
+// baidu : 2015-01-08 Baidu, Inc.
+baidu
+
+// band : 2014-06-12
+band
+
+// bank : 2014-09-25 fTLD Registry Services LLC
+bank
+
+// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+bar
+
+// barcelona : 2014-07-24 Municipi de Barcelona
+barcelona
+
+// barclaycard : 2014-11-20 Barclays Bank PLC
+barclaycard
+
+// barclays : 2014-11-20 Barclays Bank PLC
+barclays
+
+// bargains : 2013-11-14 Half Hallow, LLC
+bargains
+
+// bauhaus : 2014-04-17 Werkhaus GmbH
+bauhaus
+
+// bayern : 2014-01-23 Bayern Connect GmbH
+bayern
+
+// bbc : 2014-12-18 British Broadcasting Corporation
+bbc
+
+// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+bbva
+
+// bcg : 2015-04-02 The Boston Consulting Group, Inc.
+bcg
+
+// bcn : 2014-07-24 Municipi de Barcelona
+bcn
+
+// beer : 2014-01-09 Top Level Domain Holdings Limited
+beer
+
+// bentley : 2014-12-18 Bentley Motors Limited
+bentley
+
+// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG
+berlin
+
+// best : 2013-12-19 BestTLD Pty Ltd
+best
+
+// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited
+bharti
+
+// bible : 2014-06-19 American Bible Society
+bible
+
+// bid : 2013-12-19 dot Bid Limited
+bid
+
+// bike : 2013-08-27 Grand Hollow, LLC
+bike
+
+// bing : 2014-12-18 Microsoft Corporation
+bing
+
+// bingo : 2014-12-04 Sand Cedar, LLC
+bingo
+
+// bio : 2014-03-06 STARTING DOT LIMITED
+bio
+
+// black : 2014-01-16 Afilias Limited
+black
+
+// blackfriday : 2014-01-16 Uniregistry, Corp.
+blackfriday
+
+// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC
+bloomberg
+
+// blue : 2013-11-07 Afilias Limited
+blue
+
+// bms : 2014-10-30 Bristol-Myers Squibb Company
+bms
+
+// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+bmw
+
+// bnl : 2014-07-24 Banca Nazionale del Lavoro
+bnl
+
+// bnpparibas : 2014-05-29 BNP Paribas
+bnpparibas
+
+// boats : 2014-12-04 DERBoats, LLC
+boats
+
+// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+bom
+
+// bond : 2014-06-05 Bond University Limited
+bond
+
+// boo : 2014-01-30 Charleston Road Registry Inc.
+boo
+
+// boots : 2015-01-08 THE BOOTS COMPANY PLC
+boots
+
+// bot : 2014-12-18 Amazon EU S.à r.l.
+bot
+
+// boutique : 2013-11-14 Over Galley, LLC
+boutique
+
+// bradesco : 2014-12-18 Banco Bradesco S.A.
+bradesco
+
+// bridgestone : 2014-12-18 Bridgestone Corporation
+bridgestone
+
+// broadway : 2014-12-22 Celebrate Broadway, Inc.
+broadway
+
+// broker : 2014-12-11 IG Group Holdings PLC
+broker
+
+// brother : 2015-01-29 Brother Industries, Ltd.
+brother
+
+// brussels : 2014-02-06 DNS.be vzw
+brussels
+
+// budapest : 2013-11-21 Top Level Domain Holdings Limited
+budapest
+
+// build : 2013-11-07 Plan Bee LLC
+build
+
+// builders : 2013-11-07 Atomic Madison, LLC
+builders
+
+// business : 2013-11-07 Spring Cross, LLC
+business
+
+// buy : 2014-12-18 Amazon EU S.à r.l.
+buy
+
+// buzz : 2013-10-02 DOTSTRATEGY CO.
+buzz
+
+// bzh : 2014-02-27 Association www.bzh
+bzh
+
+// cab : 2013-10-24 Half Sunset, LLC
+cab
+
+// cafe : 2015-02-11 Pioneer Canyon, LLC
+cafe
+
+// cal : 2014-07-24 Charleston Road Registry Inc.
+cal
+
+// call : 2014-12-18 Amazon EU S.à r.l.
+call
+
+// camera : 2013-08-27 Atomic Maple, LLC
+camera
+
+// camp : 2013-11-07 Delta Dynamite, LLC
+camp
+
+// cancerresearch : 2014-05-15 Australian Cancer Research Foundation
+cancerresearch
+
+// canon : 2014-09-12 Canon Inc.
+canon
+
+// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+capetown
+
+// capital : 2014-03-06 Delta Mill, LLC
+capital
+
+// car : 2015-01-22 Charleston Road Registry Inc.
+car
+
+// caravan : 2013-12-12 Caravan International, Inc.
+caravan
+
+// cards : 2013-12-05 Foggy Hollow, LLC
+cards
+
+// care : 2014-03-06 Goose Cross
+care
+
+// career : 2013-10-09 dotCareer LLC
+career
+
+// careers : 2013-10-02 Wild Corner, LLC
+careers
+
+// cars : 2014-11-13 Uniregistry, Corp.
+cars
+
+// cartier : 2014-06-23 Richemont DNS Inc.
+cartier
+
+// casa : 2013-11-21 Top Level Domain Holdings Limited
+casa
+
+// cash : 2014-03-06 Delta Lake, LLC
+cash
+
+// casino : 2014-12-18 Binky Sky, LLC
+casino
+
+// catering : 2013-12-05 New Falls. LLC
+catering
+
+// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+cba
+
+// cbn : 2014-08-22 The Christian Broadcasting Network, Inc.
+cbn
+
+// ceb : 2015-04-09 The Corporate Executive Board Company
+ceb
+
+// center : 2013-11-07 Tin Mill, LLC
+center
+
+// ceo : 2013-11-07 CEOTLD Pty Ltd
+ceo
+
+// cern : 2014-06-05 European Organization for Nuclear Research ("CERN")
+cern
+
+// cfa : 2014-08-28 CFA Institute
+cfa
+
+// cfd : 2014-12-11 IG Group Holdings PLC
+cfd
+
+// chanel : 2015-04-09 Chanel International B.V.
+chanel
+
+// channel : 2014-05-08 Charleston Road Registry Inc.
+channel
+
+// chase : 2015-04-30 JPMorgan Chase & Co.
+chase
+
+// chat : 2014-12-04 Sand Fields, LLC
+chat
+
+// cheap : 2013-11-14 Sand Cover, LLC
+cheap
+
+// chloe : 2014-10-16 Richemont DNS Inc.
+chloe
+
+// christmas : 2013-11-21 Uniregistry, Corp.
+christmas
+
+// chrome : 2014-07-24 Charleston Road Registry Inc.
+chrome
+
+// church : 2014-02-06 Holly Fields, LLC
+church
+
+// cipriani : 2015-02-19 Hotel Cipriani Srl
+cipriani
+
+// circle : 2014-12-18 Amazon EU S.à r.l.
+circle
+
+// cisco : 2014-12-22 Cisco Technology, Inc.
+cisco
+
+// citic : 2014-01-09 CITIC Group Corporation
+citic
+
+// city : 2014-05-29 Snow Sky, LLC
+city
+
+// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc.
+cityeats
+
+// claims : 2014-03-20 Black Corner, LLC
+claims
+
+// cleaning : 2013-12-05 Fox Shadow, LLC
+cleaning
+
+// click : 2014-06-05 Uniregistry, Corp.
+click
+
+// clinic : 2014-03-20 Goose Park, LLC
+clinic
+
+// clothing : 2013-08-27 Steel Lake, LLC
+clothing
+
+// cloud : 2015-04-16 ARUBA S.p.A.
+cloud
+
+// club : 2013-11-08 .CLUB DOMAINS, LLC
+club
+
+// coach : 2014-10-09 Koko Island, LLC
+coach
+
+// codes : 2013-10-31 Puff Willow, LLC
+codes
+
+// coffee : 2013-10-17 Trixy Cover, LLC
+coffee
+
+// college : 2014-01-16 XYZ.COM LLC
+college
+
+// cologne : 2014-02-05 NetCologne Gesellschaft für Telekommunikation mbH
+cologne
+
+// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+commbank
+
+// community : 2013-12-05 Fox Orchard, LLC
+community
+
+// company : 2013-11-07 Silver Avenue, LLC
+company
+
+// computer : 2013-10-24 Pine Mill, LLC
+computer
+
+// comsec : 2015-01-08 VeriSign, Inc.
+comsec
+
+// condos : 2013-12-05 Pine House, LLC
+condos
+
+// construction : 2013-09-16 Fox Dynamite, LLC
+construction
+
+// consulting : 2013-12-05
+consulting
+
+// contact : 2015-01-08 Top Level Spectrum, Inc.
+contact
+
+// contractors : 2013-09-10 Magic Woods, LLC
+contractors
+
+// cooking : 2013-11-21 Top Level Domain Holdings Limited
+cooking
+
+// cool : 2013-11-14 Koko Lake, LLC
+cool
+
+// corsica : 2014-09-25 Collectivité Territoriale de Corse
+corsica
+
+// country : 2013-12-19 Top Level Domain Holdings Limited
+country
+
+// coupon : 2015-02-26 Amazon EU S.à r.l.
+coupon
+
+// coupons : 2015-03-26 Black Island, LLC
+coupons
+
+// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+courses
+
+// credit : 2014-03-20 Snow Shadow, LLC
+credit
+
+// creditcard : 2014-03-20 Binky Frostbite, LLC
+creditcard
+
+// creditunion : 2015-01-22 CUNA Performance Resources, LLC
+creditunion
+
+// cricket : 2014-10-09 dot Cricket Limited
+cricket
+
+// crown : 2014-10-24 Crown Equipment Corporation
+crown
+
+// crs : 2014-04-03 Federated Co-operatives Limited
+crs
+
+// cruises : 2013-12-05 Spring Way, LLC
+cruises
+
+// csc : 2014-09-25 Alliance-One Services, Inc.
+csc
+
+// cuisinella : 2014-04-03 SALM S.A.S.
+cuisinella
+
+// cymru : 2014-05-08 Nominet UK
+cymru
+
+// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd.
+cyou
+
+// dabur : 2014-02-06 Dabur India Limited
+dabur
+
+// dad : 2014-01-23 Charleston Road Registry Inc.
+dad
+
+// dance : 2013-10-24 United TLD Holdco Ltd.
+dance
+
+// date : 2014-11-20 dot Date Limited
+date
+
+// dating : 2013-12-05 Pine Fest, LLC
+dating
+
+// datsun : 2014-03-27 NISSAN MOTOR CO., LTD.
+datsun
+
+// day : 2014-01-30 Charleston Road Registry Inc.
+day
+
+// dclk : 2014-11-20 Charleston Road Registry Inc.
+dclk
+
+// dealer : 2014-12-22 Dealer Dot Com, Inc.
+dealer
+
+// deals : 2014-05-22 Sand Sunset, LLC
+deals
+
+// degree : 2014-03-06
+degree
+
+// delivery : 2014-09-11 Steel Station, LLC
+delivery
+
+// dell : 2014-10-24 Dell Inc.
+dell
+
+// delta : 2015-02-19 Delta Air Lines, Inc.
+delta
+
+// democrat : 2013-10-24 United TLD Holdco Ltd.
+democrat
+
+// dental : 2014-03-20 Tin Birch, LLC
+dental
+
+// dentist : 2014-03-20
+dentist
+
+// desi : 2013-11-14 Desi Networks LLC
+desi
+
+// design : 2014-11-07 Top Level Design, LLC
+design
+
+// dev : 2014-10-16 Charleston Road Registry Inc.
+dev
+
+// diamonds : 2013-09-22 John Edge, LLC
+diamonds
+
+// diet : 2014-06-26 Uniregistry, Corp.
+diet
+
+// digital : 2014-03-06 Dash Park, LLC
+digital
+
+// direct : 2014-04-10 Half Trail, LLC
+direct
+
+// directory : 2013-09-20 Extra Madison, LLC
+directory
+
+// discount : 2014-03-06 Holly Hill, LLC
+discount
+
+// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
+dnp
+
+// docs : 2014-10-16 Charleston Road Registry Inc.
+docs
+
+// dog : 2014-12-04 Koko Mill, LLC
+dog
+
+// doha : 2014-09-18 Communications Regulatory Authority (CRA)
+doha
+
+// domains : 2013-10-17 Sugar Cross, LLC
+domains
+
+// doosan : 2014-04-03 Doosan Corporation
+doosan
+
+// download : 2014-11-20 dot Support Limited
+download
+
+// drive : 2015-03-05 Charleston Road Registry Inc.
+drive
+
+// dstv : 2015-03-12 MultiChoice (Proprietary) Limited
+dstv
+
+// dubai : 2015-01-01 Dubai Smart Government Department
+dubai
+
+// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+durban
+
+// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+dvag
+
+// earth : 2014-12-04 Interlink Co., Ltd.
+earth
+
+// eat : 2014-01-23 Charleston Road Registry Inc.
+eat
+
+// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V.
+edeka
+
+// education : 2013-11-07 Brice Way, LLC
+education
+
+// email : 2013-10-31 Spring Madison, LLC
+email
+
+// emerck : 2014-04-03 Merck KGaA
+emerck
+
+// energy : 2014-09-11 Binky Birch, LLC
+energy
+
+// engineer : 2014-03-06 United TLD Holdco Ltd.
+engineer
+
+// engineering : 2014-03-06 Romeo Canyon
+engineering
+
+// enterprises : 2013-09-20 Snow Oaks, LLC
+enterprises
+
+// epson : 2014-12-04 Seiko Epson Corporation
+epson
+
+// equipment : 2013-08-27 Corn Station, LLC
+equipment
+
+// erni : 2014-04-03 ERNI Group Holding AG
+erni
+
+// esq : 2014-05-08 Charleston Road Registry Inc.
+esq
+
+// estate : 2013-08-27 Trixy Park, LLC
+estate
+
+// eurovision : 2014-04-24 European Broadcasting Union (EBU)
+eurovision
+
+// eus : 2013-12-12 Puntueus Fundazioa
+eus
+
+// events : 2013-12-05 Pioneer Maple, LLC
+events
+
+// everbank : 2014-05-15 EverBank
+everbank
+
+// exchange : 2014-03-06 Spring Falls, LLC
+exchange
+
+// expert : 2013-11-21 Magic Pass, LLC
+expert
+
+// exposed : 2013-12-05 Victor Beach, LLC
+exposed
+
+// express : 2015-02-11 Sea Sunset, LLC
+express
+
+// fage : 2014-12-18 Fage International S.A.
+fage
+
+// fail : 2014-03-06 Atomic Pipe, LLC
+fail
+
+// fairwinds : 2014-11-13 FairWinds Partners, LLC
+fairwinds
+
+// faith : 2014-11-20 dot Faith Limited
+faith
+
+// family : 2015-04-02 Bitter Galley, LLC
+family
+
+// fan : 2014-03-06
+fan
+
+// fans : 2014-11-07 Asiamix Digital Limited
+fans
+
+// farm : 2013-11-07 Just Maple, LLC
+farm
+
+// fashion : 2014-07-03 Top Level Domain Holdings Limited
+fashion
+
+// fast : 2014-12-18 Amazon EU S.à r.l.
+fast
+
+// feedback : 2013-12-19 Top Level Spectrum, Inc.
+feedback
+
+// ferrero : 2014-12-18 Ferrero Trading Lux S.A.
+ferrero
+
+// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd
+film
+
+// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+final
+
+// finance : 2014-03-20 Cotton Cypress, LLC
+finance
+
+// financial : 2014-03-06 Just Cover, LLC
+financial
+
+// firestone : 2014-12-18 Bridgestone Corporation
+firestone
+
+// firmdale : 2014-03-27 Firmdale Holdings Limited
+firmdale
+
+// fish : 2013-12-12 Fox Woods, LLC
+fish
+
+// fishing : 2013-11-21 Top Level Domain Holdings Limited
+fishing
+
+// fit : 2014-11-07 Top Level Domain Holdings Limited
+fit
+
+// fitness : 2014-03-06 Brice Orchard, LLC
+fitness
+
+// flickr : 2015-04-02 Yahoo! Domain Services Inc.
+flickr
+
+// flights : 2013-12-05 Fox Station, LLC
+flights
+
+// florist : 2013-11-07 Half Cypress, LLC
+florist
+
+// flowers : 2014-10-09 Uniregistry, Corp.
+flowers
+
+// flsmidth : 2014-07-24 FLSmidth A/S
+flsmidth
+
+// fly : 2014-05-08 Charleston Road Registry Inc.
+fly
+
+// foo : 2014-01-23 Charleston Road Registry Inc.
+foo
+
+// football : 2014-12-18 Foggy Farms, LLC
+football
+
+// ford : 2014-11-13 Ford Motor Company
+ford
+
+// forex : 2014-12-11 IG Group Holdings PLC
+forex
+
+// forsale : 2014-05-22
+forsale
+
+// forum : 2015-04-02 Fegistry, LLC
+forum
+
+// foundation : 2013-12-05 John Dale, LLC
+foundation
+
+// frl : 2014-05-15 FRLregistry B.V.
+frl
+
+// frogans : 2013-12-19 OP3FT
+frogans
+
+// frontier : 2015-02-05 Frontier Communications Corporation
+frontier
+
+// fund : 2014-03-20 John Castle, LLC
+fund
+
+// furniture : 2014-03-20 Lone Fields, LLC
+furniture
+
+// futbol : 2013-09-20
+futbol
+
+// fyi : 2015-04-02 Silver Tigers, LLC
+fyi
+
+// gal : 2013-11-07 Asociación puntoGAL
+gal
+
+// gallery : 2013-09-13 Sugar House, LLC
+gallery
+
+// gallup : 2015-02-19 Gallup, Inc.
+gallup
+
+// garden : 2014-06-26 Top Level Domain Holdings Limited
+garden
+
+// gbiz : 2014-07-17 Charleston Road Registry Inc.
+gbiz
+
+// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems"
+gdn
+
+// gea : 2014-12-04 GEA Group Aktiengesellschaft
+gea
+
+// gent : 2014-01-23 COMBELL GROUP NV/SA
+gent
+
+// genting : 2015-03-12 Resorts World Inc Pte. Ltd.
+genting
+
+// ggee : 2014-01-09 GMO Internet, Inc.
+ggee
+
+// gift : 2013-10-17 Uniregistry, Corp.
+gift
+
+// gifts : 2014-07-03 Goose Sky, LLC
+gifts
+
+// gives : 2014-03-06 United TLD Holdco Ltd.
+gives
+
+// giving : 2014-11-13 Giving Limited
+giving
+
+// glass : 2013-11-07 Black Cover, LLC
+glass
+
+// gle : 2014-07-24 Charleston Road Registry Inc.
+gle
+
+// global : 2014-04-17 Dot GLOBAL AS
+global
+
+// globo : 2013-12-19 Globo Comunicação e Participações S.A
+globo
+
+// gmail : 2014-05-01 Charleston Road Registry Inc.
+gmail
+
+// gmo : 2014-01-09 GMO Internet, Inc.
+gmo
+
+// gmx : 2014-04-24 1&1 Mail & Media GmbH
+gmx
+
+// gold : 2015-01-22 June Edge, LLC
+gold
+
+// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+goldpoint
+
+// golf : 2014-12-18 Lone falls, LLC
+golf
+
+// goo : 2014-12-18 NTT Resonant Inc.
+goo
+
+// goog : 2014-11-20 Charleston Road Registry Inc.
+goog
+
+// google : 2014-07-24 Charleston Road Registry Inc.
+google
+
+// gop : 2014-01-16 Republican State Leadership Committee, Inc.
+gop
+
+// got : 2014-12-18 Amazon EU S.à r.l.
+got
+
+// gotv : 2015-03-12 MultiChoice (Proprietary) Limited
+gotv
+
+// graphics : 2013-09-13 Over Madison, LLC
+graphics
+
+// gratis : 2014-03-20 Pioneer Tigers, LLC
+gratis
+
+// green : 2014-05-08 Afilias Limited
+green
+
+// gripe : 2014-03-06 Corn Sunset, LLC
+gripe
+
+// group : 2014-08-15 Romeo Town, LLC
+group
+
+// gucci : 2014-11-13 Guccio Gucci S.p.a.
+gucci
+
+// guge : 2014-08-28 Charleston Road Registry Inc.
+guge
+
+// guide : 2013-09-13 Snow Moon, LLC
+guide
+
+// guitars : 2013-11-14 Uniregistry, Corp.
+guitars
+
+// guru : 2013-08-27 Pioneer Cypress, LLC
+guru
+
+// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH
+hamburg
+
+// hangout : 2014-11-13 Charleston Road Registry Inc.
+hangout
+
+// haus : 2013-12-05
+haus
+
+// hdfcbank : 2015-02-12 HDFC Bank Limited
+hdfcbank
+
+// health : 2015-02-11 DotHealth, LLC
+health
+
+// healthcare : 2014-06-12 Silver Glen, LLC
+healthcare
+
+// help : 2014-06-26 Uniregistry, Corp.
+help
+
+// helsinki : 2015-02-05 City of Helsinki
+helsinki
+
+// here : 2014-02-06 Charleston Road Registry Inc.
+here
+
+// hermes : 2014-07-10 HERMES INTERNATIONAL
+hermes
+
+// hiphop : 2014-03-06 Uniregistry, Corp.
+hiphop
+
+// hitachi : 2014-10-31 Hitachi, Ltd.
+hitachi
+
+// hiv : 2014-03-13 dotHIV gemeinnuetziger e.V.
+hiv
+
+// hockey : 2015-03-19 Half Willow, LLC
+hockey
+
+// holdings : 2013-08-27 John Madison, LLC
+holdings
+
+// holiday : 2013-11-07 Goose Woods, LLC
+holiday
+
+// homedepot : 2015-04-02 Homer TLC, Inc.
+homedepot
+
+// homes : 2014-01-09 DERHomes, LLC
+homes
+
+// honda : 2014-12-18 Honda Motor Co., Ltd.
+honda
+
+// horse : 2013-11-21 Top Level Domain Holdings Limited
+horse
+
+// host : 2014-04-17 DotHost Inc.
+host
+
+// hosting : 2014-05-29 Uniregistry, Corp.
+hosting
+
+// hoteles : 2015-03-05 Travel Reservations SRL
+hoteles
+
+// hotmail : 2014-12-18 Microsoft Corporation
+hotmail
+
+// house : 2013-11-07 Sugar Park, LLC
+house
+
+// how : 2014-01-23 Charleston Road Registry Inc.
+how
+
+// hsbc : 2014-10-24 HSBC Holdings PLC
+hsbc
+
+// htc : 2015-04-02 HTC corporation
+htc
+
+// ibm : 2014-07-31 International Business Machines Corporation
+ibm
+
+// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited
+icbc
+
+// ice : 2014-10-30 IntercontinentalExchange, Inc.
+ice
+
+// icu : 2015-01-08 One.com A/S
+icu
+
+// ifm : 2014-01-30 ifm electronic gmbh
+ifm
+
+// iinet : 2014-07-03 Connect West Pty. Ltd.
+iinet
+
+// immo : 2014-07-10 Auburn Bloom, LLC
+immo
+
+// immobilien : 2013-11-07 United TLD Holdco Ltd.
+immobilien
+
+// industries : 2013-12-05 Outer House, LLC
+industries
+
+// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD.
+infiniti
+
+// ing : 2014-01-23 Charleston Road Registry Inc.
+ing
+
+// ink : 2013-12-05 Top Level Design, LLC
+ink
+
+// institute : 2013-11-07 Outer Maple, LLC
+institute
+
+// insurance : 2015-02-19 fTLD Registry Services LLC
+insurance
+
+// insure : 2014-03-20 Pioneer Willow, LLC
+insure
+
+// international : 2013-11-07 Wild Way, LLC
+international
+
+// investments : 2014-03-20 Holly Glen, LLC
+investments
+
+// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A.
+ipiranga
+
+// irish : 2014-08-07 Dot-Irish LLC
+irish
+
+// iselect : 2015-02-11 iSelect Ltd
+iselect
+
+// ist : 2014-08-28 Istanbul Metropolitan Municipality
+ist
+
+// istanbul : 2014-08-28 Istanbul Metropolitan Municipality
+istanbul
+
+// itau : 2014-10-02 Itau Unibanco Holding S.A.
+itau
+
+// iwc : 2014-06-23 Richemont DNS Inc.
+iwc
+
+// jaguar : 2014-11-13 Jaguar Land Rover Ltd
+jaguar
+
+// java : 2014-06-19 Oracle Corporation
+java
+
+// jcb : 2014-11-20 JCB Co., Ltd.
+jcb
+
+// jcp : 2015-04-23 JCP Media, Inc.
+jcp
+
+// jetzt : 2014-01-09 New TLD Company AB
+jetzt
+
+// jewelry : 2015-03-05 Wild Bloom, LLC
+jewelry
+
+// jio : 2015-04-02 Affinity Names, Inc.
+jio
+
+// jlc : 2014-12-04 Richemont DNS Inc.
+jlc
+
+// jll : 2015-04-02 Jones Lang LaSalle Incorporated
+jll
+
+// jmp : 2015-03-26 Matrix IP LLC
+jmp
+
+// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+joburg
+
+// jot : 2014-12-18 Amazon EU S.à r.l.
+jot
+
+// joy : 2014-12-18 Amazon EU S.à r.l.
+joy
+
+// jpmorgan : 2015-04-30 JPMorgan Chase & Co.
+jpmorgan
+
+// jprs : 2014-09-18 Japan Registry Services Co., Ltd.
+jprs
+
+// juegos : 2014-03-20 Uniregistry, Corp.
+juegos
+
+// kaufen : 2013-11-07 United TLD Holdco Ltd.
+kaufen
+
+// kddi : 2014-09-12 KDDI CORPORATION
+kddi
+
+// kerryhotels : 2015-04-30 Kerry Trading Co. Limited
+kerryhotels
+
+// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited
+kerrylogistics
+
+// kerryproperties : 2015-04-09 Kerry Trading Co. Limited
+kerryproperties
+
+// kfh : 2014-12-04 Kuwait Finance House
+kfh
+
+// kim : 2013-09-23 Afilias Limited
+kim
+
+// kinder : 2014-11-07 Ferrero Trading Lux S.A.
+kinder
+
+// kitchen : 2013-09-20 Just Goodbye, LLC
+kitchen
+
+// kiwi : 2013-09-20 DOT KIWI LIMITED
+kiwi
+
+// koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH
+koeln
+
+// komatsu : 2015-01-08 Komatsu Ltd.
+komatsu
+
+// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft)
+kpmg
+
+// kpn : 2015-01-08 Koninklijke KPN N.V.
+kpn
+
+// krd : 2013-12-05 KRG Department of Information Technology
+krd
+
+// kred : 2013-12-19 KredTLD Pty Ltd
+kred
+
+// kuokgroup : 2015-04-09 Kerry Trading Co. Limited
+kuokgroup
+
+// kyknet : 2015-03-05 Electronic Media Network (Pty) Ltd
+kyknet
+
+// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen
+kyoto
+
+// lacaixa : 2014-01-09 CAIXA D'ESTALVIS I PENSIONS DE BARCELONA
+lacaixa
+
+// lancaster : 2015-02-12 LANCASTER
+lancaster
+
+// land : 2013-09-10 Pine Moon, LLC
+land
+
+// landrover : 2014-11-13 Jaguar Land Rover Ltd
+landrover
+
+// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated
+lasalle
+
+// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico
+lat
+
+// latrobe : 2014-06-16 La Trobe University
+latrobe
+
+// law : 2015-01-22 Minds + Machines Group Limited
+law
+
+// lawyer : 2014-03-20
+lawyer
+
+// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant")
+lds
+
+// lease : 2014-03-06 Victor Trail, LLC
+lease
+
+// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
+leclerc
+
+// legal : 2014-10-16 Blue Falls, LLC
+legal
+
+// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION
+lexus
+
+// lgbt : 2014-05-08 Afilias Limited
+lgbt
+
+// liaison : 2014-10-02 Liaison Technologies, Incorporated
+liaison
+
+// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+lidl
+
+// life : 2014-02-06 Trixy Oaks, LLC
+life
+
+// lifeinsurance : 2015-01-15 American Council of Life Insurers
+lifeinsurance
+
+// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc.
+lifestyle
+
+// lighting : 2013-08-27 John McCook, LLC
+lighting
+
+// like : 2014-12-18 Amazon EU S.à r.l.
+like
+
+// limited : 2014-03-06 Big Fest, LLC
+limited
+
+// limo : 2013-10-17 Hidden Frostbite, LLC
+limo
+
+// lincoln : 2014-11-13 Ford Motor Company
+lincoln
+
+// linde : 2014-12-04 Linde Aktiengesellschaft
+linde
+
+// link : 2013-11-14 Uniregistry, Corp.
+link
+
+// live : 2014-12-04 Half Woods, LLC
+live
+
+// lixil : 2015-03-19 LIXIL Group Corporation
+lixil
+
+// loan : 2014-11-20 dot Loan Limited
+loan
+
+// loans : 2014-03-20 June Woods, LLC
+loans
+
+// lol : 2015-01-30 Uniregistry, Corp.
+lol
+
+// london : 2013-11-14 Dot London Domains Limited
+london
+
+// lotte : 2014-11-07 Lotte Holdings Co., Ltd.
+lotte
+
+// lotto : 2014-04-10 Afilias Limited
+lotto
+
+// love : 2014-12-22 Merchant Law Group LLP
+love
+
+// ltd : 2014-09-25 Over Corner, LLC
+ltd
+
+// ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA
+ltda
+
+// lupin : 2014-11-07 LUPIN LIMITED
+lupin
+
+// luxe : 2014-01-09 Top Level Domain Holdings Limited
+luxe
+
+// luxury : 2013-10-17 Luxury Partners, LLC
+luxury
+
+// madrid : 2014-05-01 Comunidad de Madrid
+madrid
+
+// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF)
+maif
+
+// maison : 2013-12-05 Victor Frostbite, LLC
+maison
+
+// makeup : 2015-01-15 L'Oréal
+makeup
+
+// man : 2014-12-04 MAN SE
+man
+
+// management : 2013-11-07 John Goodbye, LLC
+management
+
+// mango : 2013-10-24 PUNTO FA S.L.
+mango
+
+// market : 2014-03-06
+market
+
+// marketing : 2013-11-07 Fern Pass, LLC
+marketing
+
+// markets : 2014-12-11 IG Group Holdings PLC
+markets
+
+// marriott : 2014-10-09 Marriott Worldwide Corporation
+marriott
+
+// mba : 2015-04-02 Lone Hollow, LLC
+mba
+
+// media : 2014-03-06 Grand Glen, LLC
+media
+
+// meet : 2014-01-16
+meet
+
+// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation
+melbourne
+
+// meme : 2014-01-30 Charleston Road Registry Inc.
+meme
+
+// memorial : 2014-10-16 Dog Beach, LLC
+memorial
+
+// men : 2015-02-26 Exclusive Registry Limited
+men
+
+// menu : 2013-09-11 Wedding TLD2, LLC
+menu
+
+// meo : 2014-11-07 PT Comunicacoes S.A.
+meo
+
+// miami : 2013-12-19 Top Level Domain Holdings Limited
+miami
+
+// microsoft : 2014-12-18 Microsoft Corporation
+microsoft
+
+// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+mini
+
+// mls : 2015-04-23 The Canadian Real Estate Association
+mls
+
+// mma : 2014-11-07 MMA IARD
+mma
+
+// mnet : 2015-03-05 Electronic Media Network (Pty) Ltd
+mnet
+
+// mobily : 2014-12-18 GreenTech Consultancy Company W.L.L.
+mobily
+
+// moda : 2013-11-07 United TLD Holdco Ltd.
+moda
+
+// moe : 2013-11-13 Interlink Co., Ltd.
+moe
+
+// moi : 2014-12-18 Amazon EU S.à r.l.
+moi
+
+// mom : 2015-04-16 Uniregistry, Corp.
+mom
+
+// monash : 2013-09-30 Monash University
+monash
+
+// money : 2014-10-16 Outer McCook, LLC
+money
+
+// montblanc : 2014-06-23 Richemont DNS Inc.
+montblanc
+
+// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant")
+mormon
+
+// mortgage : 2014-03-20
+mortgage
+
+// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+moscow
+
+// motorcycles : 2014-01-09 DERMotorcycles, LLC
+motorcycles
+
+// mov : 2014-01-30 Charleston Road Registry Inc.
+mov
+
+// movie : 2015-02-05 New Frostbite, LLC
+movie
+
+// movistar : 2014-10-16 Telefónica S.A.
+movistar
+
+// mtn : 2014-12-04 MTN Dubai Limited
+mtn
+
+// mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation
+mtpc
+
+// mtr : 2015-03-12 MTR Corporation Limited
+mtr
+
+// multichoice : 2015-03-12 MultiChoice (Proprietary) Limited
+multichoice
+
+// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC
+mutual
+
+// mzansimagic : 2015-03-05 Electronic Media Network (Pty) Ltd
+mzansimagic
+
+// nadex : 2014-12-11 IG Group Holdings PLC
+nadex
+
+// nagoya : 2013-10-24 GMO Registry, Inc.
+nagoya
+
+// naspers : 2015-02-12 Intelprop (Proprietary) Limited
+naspers
+
+// natura : 2015-03-12 NATURA COSMÉTICOS S.A.
+natura
+
+// navy : 2014-03-06 United TLD Holdco Ltd.
+navy
+
+// nec : 2015-01-08 NEC Corporation
+nec
+
+// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+netbank
+
+// network : 2013-11-14 Trixy Manor, LLC
+network
+
+// neustar : 2013-12-05 NeuStar, Inc.
+neustar
+
+// new : 2014-01-30 Charleston Road Registry Inc.
+new
+
+// news : 2014-12-18
+news
+
+// nexus : 2014-07-24 Charleston Road Registry Inc.
+nexus
+
+// ngo : 2014-03-06 Public Interest Registry
+ngo
+
+// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK)
+nhk
+
+// nico : 2014-12-04 DWANGO Co., Ltd.
+nico
+
+// ninja : 2013-11-07 United TLD Holdco Ltd.
+ninja
+
+// nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
+nissan
+
+// nokia : 2015-01-08 Nokia Corporation
+nokia
+
+// norton : 2014-12-04 Symantec Corporation
+norton
+
+// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+nowruz
+
+// nra : 2014-05-22 NRA Holdings Company, INC.
+nra
+
+// nrw : 2013-11-21 Minds + Machines GmbH
+nrw
+
+// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+ntt
+
+// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications
+nyc
+
+// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA
+obi
+
+// observer : 2015-04-30 Guardian News and Media Limited
+observer
+
+// office : 2015-03-12 Microsoft Corporation
+office
+
+// okinawa : 2013-12-05 BusinessRalliart Inc.
+okinawa
+
+// omega : 2015-01-08 The Swatch Group Ltd
+omega
+
+// one : 2014-11-07 One.com A/S
+one
+
+// ong : 2014-03-06 Public Interest Registry
+ong
+
+// onl : 2013-09-16 I-Registry Ltd.
+onl
+
+// online : 2015-01-15 DotOnline Inc.
+online
+
+// ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED
+ooo
+
+// oracle : 2014-06-19 Oracle Corporation
+oracle
+
+// orange : 2015-03-12 Orange Brand Services Limited
+orange
+
+// organic : 2014-03-27 Afilias Limited
+organic
+
+// orientexpress : 2015-02-05 Belmond Ltd.
+orientexpress
+
+// osaka : 2014-09-04 Interlink Co., Ltd.
+osaka
+
+// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd.
+otsuka
+
+// ovh : 2014-01-16 OVH SAS
+ovh
+
+// page : 2014-12-04 Charleston Road Registry Inc.
+page
+
+// pamperedchef : 2015-02-05 The Pampered Chef, Ltd.
+pamperedchef
+
+// panerai : 2014-11-07 Richemont DNS Inc.
+panerai
+
+// paris : 2014-01-30 City of Paris
+paris
+
+// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+pars
+
+// partners : 2013-12-05 Magic Glen, LLC
+partners
+
+// parts : 2013-12-05 Sea Goodbye, LLC
+parts
+
+// party : 2014-09-11 Blue Sky Registry Limited
+party
+
+// passagens : 2015-03-05 Travel Reservations SRL
+passagens
+
+// payu : 2015-02-12 MIH PayU B.V.
+payu
+
+// pharmacy : 2014-06-19 National Association of Boards of Pharmacy
+pharmacy
+
+// philips : 2014-11-07 Koninklijke Philips N.V.
+philips
+
+// photo : 2013-11-14 Uniregistry, Corp.
+photo
+
+// photography : 2013-09-20 Sugar Glen, LLC
+photography
+
+// photos : 2013-10-17 Sea Corner, LLC
+photos
+
+// physio : 2014-05-01 PhysBiz Pty Ltd
+physio
+
+// piaget : 2014-10-16 Richemont DNS Inc.
+piaget
+
+// pics : 2013-11-14 Uniregistry, Corp.
+pics
+
+// pictet : 2014-06-26 Pictet Europe S.A.
+pictet
+
+// pictures : 2014-03-06 Foggy Sky, LLC
+pictures
+
+// pid : 2015-01-08 Top Level Spectrum, Inc.
+pid
+
+// pin : 2014-12-18 Amazon EU S.à r.l.
+pin
+
+// pink : 2013-10-01 Afilias Limited
+pink
+
+// pizza : 2014-06-26 Foggy Moon, LLC
+pizza
+
+// place : 2014-04-24 Snow Galley, LLC
+place
+
+// play : 2015-03-05 Charleston Road Registry Inc.
+play
+
+// plumbing : 2013-09-10 Spring Tigers, LLC
+plumbing
+
+// plus : 2015-02-05 Sugar Mill, LLC
+plus
+
+// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+pohl
+
+// poker : 2014-07-03 Afilias Domains No. 5 Limited
+poker
+
+// porn : 2014-10-16 ICM Registry PN LLC
+porn
+
+// praxi : 2013-12-05 Praxi S.p.A.
+praxi
+
+// press : 2014-04-03 DotPress Inc.
+press
+
+// prod : 2014-01-23 Charleston Road Registry Inc.
+prod
+
+// productions : 2013-12-05 Magic Birch, LLC
+productions
+
+// prof : 2014-07-24 Charleston Road Registry Inc.
+prof
+
+// promo : 2014-12-18 Play.PROMO Oy
+promo
+
+// properties : 2013-12-05 Big Pass, LLC
+properties
+
+// property : 2014-05-22 Uniregistry, Corp.
+property
+
+// protection : 2015-04-23 Symantec Corporation
+protection
+
+// pub : 2013-12-12 United TLD Holdco Ltd.
+pub
+
+// qpon : 2013-11-14 dotCOOL, Inc.
+qpon
+
+// quebec : 2013-12-19 PointQuébec Inc
+quebec
+
+// quest : 2015-03-26 Quest ION Limited
+quest
+
+// racing : 2014-12-04 Premier Registry Limited
+racing
+
+// read : 2014-12-18 Amazon EU S.à r.l.
+read
+
+// realtor : 2014-05-29 Real Estate Domains LLC
+realtor
+
+// realty : 2015-03-19 Fegistry, LLC
+realty
+
+// recipes : 2013-10-17 Grand Island, LLC
+recipes
+
+// red : 2013-11-07 Afilias Limited
+red
+
+// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd.
+redstone
+
+// redumbrella : 2015-03-26 Travelers TLD, LLC
+redumbrella
+
+// rehab : 2014-03-06 United TLD Holdco Ltd.
+rehab
+
+// reise : 2014-03-13 dotreise GmbH
+reise
+
+// reisen : 2014-03-06 New Cypress, LLC
+reisen
+
+// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc.
+reit
+
+// reliance : 2015-04-02 Reliance Industries Limited
+reliance
+
+// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd.
+ren
+
+// rent : 2014-12-04 DERRent, LLC
+rent
+
+// rentals : 2013-12-05 Big Hollow,LLC
+rentals
+
+// repair : 2013-11-07 Lone Sunset, LLC
+repair
+
+// report : 2013-12-05 Binky Glen, LLC
+report
+
+// republican : 2014-03-20 United TLD Holdco Ltd.
+republican
+
+// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+rest
+
+// restaurant : 2014-07-03 Snow Avenue, LLC
+restaurant
+
+// review : 2014-11-20 dot Review Limited
+review
+
+// reviews : 2013-09-13
+reviews
+
+// rich : 2013-11-21 I-Registry Ltd.
+rich
+
+// ricoh : 2014-11-20 Ricoh Company, Ltd.
+ricoh
+
+// ril : 2015-04-02 Reliance Industries Limited
+ril
+
+// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO
+rio
+
+// rip : 2014-07-10 United TLD Holdco Ltd.
+rip
+
+// rocher : 2014-12-18 Ferrero Trading Lux S.A.
+rocher
+
+// rocks : 2013-11-14
+rocks
+
+// rodeo : 2013-12-19 Top Level Domain Holdings Limited
+rodeo
+
+// room : 2014-12-18 Amazon EU S.à r.l.
+room
+
+// rsvp : 2014-05-08 Charleston Road Registry Inc.
+rsvp
+
+// ruhr : 2013-10-02 regiodot GmbH & Co. KG
+ruhr
+
+// run : 2015-03-19 Snow Park, LLC
+run
+
+// rwe : 2015-04-02 RWE AG
+rwe
+
+// ryukyu : 2014-01-09 BusinessRalliart Inc.
+ryukyu
+
+// saarland : 2013-12-12 dotSaarland GmbH
+saarland
+
+// safe : 2014-12-18 Amazon EU S.à r.l.
+safe
+
+// safety : 2015-01-08 Safety Registry Services, LLC.
+safety
+
+// sakura : 2014-12-18 SAKURA Internet Inc.
+sakura
+
+// sale : 2014-10-16
+sale
+
+// salon : 2014-12-11 Outer Orchard, LLC
+salon
+
+// samsung : 2014-04-03 SAMSUNG SDS CO., LTD
+samsung
+
+// sandvik : 2014-11-13 Sandvik AB
+sandvik
+
+// sandvikcoromant : 2014-11-07 Sandvik AB
+sandvikcoromant
+
+// sanofi : 2014-10-09 Sanofi
+sanofi
+
+// sap : 2014-03-27 SAP AG
+sap
+
+// sapo : 2014-11-07 PT Comunicacoes S.A.
+sapo
+
+// sarl : 2014-07-03 Delta Orchard, LLC
+sarl
+
+// sas : 2015-04-02 Research IP LLC
+sas
+
+// saxo : 2014-10-31 Saxo Bank A/S
+saxo
+
+// sbi : 2015-03-12 STATE BANK OF INDIA
+sbi
+
+// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION
+sbs
+
+// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ)
+sca
+
+// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB")
+scb
+
+// schmidt : 2014-04-03 SALM S.A.S.
+schmidt
+
+// scholarships : 2014-04-24 Scholarships.com, LLC
+scholarships
+
+// school : 2014-12-18 Little Galley, LLC
+school
+
+// schule : 2014-03-06 Outer Moon, LLC
+schule
+
+// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+schwarz
+
+// science : 2014-09-11 dot Science Limited
+science
+
+// scor : 2014-10-31 SCOR SE
+scor
+
+// scot : 2014-01-23 Dot Scot Registry Limited
+scot
+
+// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal)
+seat
+
+// seek : 2014-12-04 Seek Limited
+seek
+
+// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A.
+sener
+
+// services : 2014-02-27 Fox Castle, LLC
+services
+
+// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG
+sew
+
+// sex : 2014-11-13 ICM Registry SX LLC
+sex
+
+// sexy : 2013-09-11 Uniregistry, Corp.
+sexy
+
+// sharp : 2014-05-01 Sharp Corporation
+sharp
+
+// shaw : 2015-04-23 Shaw Cablesystems G.P.
+shaw
+
+// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+shia
+
+// shiksha : 2013-11-14 Afilias Limited
+shiksha
+
+// shoes : 2013-10-02 Binky Galley, LLC
+shoes
+
+// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+shouji
+
+// show : 2015-03-05 Snow Beach, LLC
+show
+
+// shriram : 2014-01-23 Shriram Capital Ltd.
+shriram
+
+// sina : 2015-03-12 Sina Corporation
+sina
+
+// singles : 2013-08-27 Fern Madison, LLC
+singles
+
+// site : 2015-01-15 DotSite Inc.
+site
+
+// ski : 2015-04-09 STARTING DOT LIMITED
+ski
+
+// skin : 2015-01-15 L'Oréal
+skin
+
+// sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch
+sky
+
+// skype : 2014-12-18 Microsoft Corporation
+skype
+
+// smile : 2014-12-18 Amazon EU S.à r.l.
+smile
+
+// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F
+sncf
+
+// soccer : 2015-03-26 Foggy Shadow, LLC
+soccer
+
+// social : 2013-11-07 United TLD Holdco Ltd.
+social
+
+// software : 2014-03-20
+software
+
+// sohu : 2013-12-19 Sohu.com Limited
+sohu
+
+// solar : 2013-11-07 Ruby Town, LLC
+solar
+
+// solutions : 2013-11-07 Silver Cover, LLC
+solutions
+
+// song : 2015-02-26 Amazon EU S.à r.l.
+song
+
+// sony : 2015-01-08 Sony Corporation
+sony
+
+// soy : 2014-01-23 Charleston Road Registry Inc.
+soy
+
+// space : 2014-04-03 DotSpace Inc.
+space
+
+// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG
+spiegel
+
+// spot : 2015-02-26 Amazon EU S.à r.l.
+spot
+
+// spreadbetting : 2014-12-11 IG Group Holdings PLC
+spreadbetting
+
+// stada : 2014-11-13 STADA Arzneimittel AG
+stada
+
+// star : 2015-01-08 Star India Private Limited
+star
+
+// starhub : 2015-02-05 StarHub Limited
+starhub
+
+// statebank : 2015-03-12 STATE BANK OF INDIA
+statebank
+
+// statoil : 2014-12-04 Statoil ASA
+statoil
+
+// stc : 2014-10-09 Saudi Telecom Company
+stc
+
+// stcgroup : 2014-10-09 Saudi Telecom Company
+stcgroup
+
+// stockholm : 2014-12-18 Stockholms kommun
+stockholm
+
+// storage : 2014-12-22 Self Storage Company LLC
+storage
+
+// store : 2015-04-09 DotStore Inc.
+store
+
+// studio : 2015-02-11 Spring Goodbye, LLC
+studio
+
+// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+study
+
+// style : 2014-12-04 Binky Moon, LLC
+style
+
+// sucks : 2014-12-22 Vox Populi Registry Inc.
+sucks
+
+// supersport : 2015-03-05 SuperSport International Holdings Proprietary Limited
+supersport
+
+// supplies : 2013-12-19 Atomic Fields, LLC
+supplies
+
+// supply : 2013-12-19 Half Falls, LLC
+supply
+
+// support : 2013-10-24 Grand Orchard, LLC
+support
+
+// surf : 2014-01-09 Top Level Domain Holdings Limited
+surf
+
+// surgery : 2014-03-20 Tin Avenue, LLC
+surgery
+
+// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION
+suzuki
+
+// swatch : 2015-01-08 The Swatch Group Ltd
+swatch
+
+// swiss : 2014-10-16 Swiss Confederation
+swiss
+
+// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet
+sydney
+
+// symantec : 2014-12-04 Symantec Corporation
+symantec
+
+// systems : 2013-11-07 Dash Cypress, LLC
+systems
+
+// tab : 2014-12-04 Tabcorp Holdings Limited
+tab
+
+// taipei : 2014-07-10 Taipei City Government
+taipei
+
+// talk : 2015-04-09 Amazon EU S.à r.l.
+talk
+
+// taobao : 2015-01-15 Alibaba Group Holding Limited
+taobao
+
+// tatamotors : 2015-03-12 Tata Motors Ltd
+tatamotors
+
+// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic"
+tatar
+
+// tattoo : 2013-08-30 Uniregistry, Corp.
+tattoo
+
+// tax : 2014-03-20 Storm Orchard, LLC
+tax
+
+// taxi : 2015-03-19 Pine Falls, LLC
+taxi
+
+// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+tci
+
+// team : 2015-03-05 Atomic Lake, LLC
+team
+
+// tech : 2015-01-30 Dot Tech LLC
+tech
+
+// technology : 2013-09-13 Auburn Falls
+technology
+
+// telecity : 2015-02-19 TelecityGroup International Limited
+telecity
+
+// telefonica : 2014-10-16 Telefónica S.A.
+telefonica
+
+// temasek : 2014-08-07 Temasek Holdings (Private) Limited
+temasek
+
+// tennis : 2014-12-04 Cotton Bloom, LLC
+tennis
+
+// thd : 2015-04-02 Homer TLC, Inc.
+thd
+
+// theater : 2015-03-19 Blue Tigers, LLC
+theater
+
+// theguardian : 2015-04-30 Guardian News and Media Limited
+theguardian
+
+// tickets : 2015-02-05 Accent Media Limited
+tickets
+
+// tienda : 2013-11-14 Victor Manor, LLC
+tienda
+
+// tiffany : 2015-01-30 Tiffany and Company
+tiffany
+
+// tips : 2013-09-20 Corn Willow, LLC
+tips
+
+// tires : 2014-11-07 Dog Edge, LLC
+tires
+
+// tirol : 2014-04-24 punkt Tirol GmbH
+tirol
+
+// tmall : 2015-01-15 Alibaba Group Holding Limited
+tmall
+
+// today : 2013-09-20 Pearl Woods, LLC
+today
+
+// tokyo : 2013-11-13 GMO Registry, Inc.
+tokyo
+
+// tools : 2013-11-21 Pioneer North, LLC
+tools
+
+// top : 2014-03-20 Jiangsu Bangning Science & Technology Co.,Ltd.
+top
+
+// toray : 2014-12-18 Toray Industries, Inc.
+toray
+
+// toshiba : 2014-04-10 TOSHIBA Corporation
+toshiba
+
+// tours : 2015-01-22 Sugar Station, LLC
+tours
+
+// town : 2014-03-06 Koko Moon, LLC
+town
+
+// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION
+toyota
+
+// toys : 2014-03-06 Pioneer Orchard, LLC
+toys
+
+// trade : 2014-01-23 Elite Registry Limited
+trade
+
+// trading : 2014-12-11 IG Group Holdings PLC
+trading
+
+// training : 2013-11-07 Wild Willow, LLC
+training
+
+// travelers : 2015-03-26 Travelers TLD, LLC
+travelers
+
+// travelersinsurance : 2015-03-26 Travelers TLD, LLC
+travelersinsurance
+
+// trust : 2014-10-16
+trust
+
+// trv : 2015-03-26 Travelers TLD, LLC
+trv
+
+// tui : 2014-07-03 TUI AG
+tui
+
+// tunes : 2015-02-26 Amazon EU S.à r.l.
+tunes
+
+// tushu : 2014-12-18 Amazon EU S.à r.l.
+tushu
+
+// tvs : 2015-02-19 T V SUNDRAM IYENGAR  & SONS LIMITED
+tvs
+
+// ubs : 2014-12-11 UBS AG
+ubs
+
+// university : 2014-03-06 Little Station, LLC
+university
+
+// uno : 2013-09-11 Dot Latin LLC
+uno
+
+// uol : 2014-05-01 UBN INTERNET LTDA.
+uol
+
+// vacations : 2013-12-05 Atomic Tigers, LLC
+vacations
+
+// vana : 2014-12-11 Lifestyle Domain Holdings, Inc.
+vana
+
+// vegas : 2014-01-16 Dot Vegas, Inc.
+vegas
+
+// ventures : 2013-08-27 Binky Lake, LLC
+ventures
+
+// versicherung : 2014-03-20 dotversicherung-registry GmbH
+versicherung
+
+// vet : 2014-03-06
+vet
+
+// viajes : 2013-10-17 Black Madison, LLC
+viajes
+
+// video : 2014-10-16
+video
+
+// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd.
+viking
+
+// villas : 2013-12-05 New Sky, LLC
+villas
+
+// vip : 2015-01-22 Minds + Machines Group Limited
+vip
+
+// virgin : 2014-09-25 Virgin Enterprises Limited
+virgin
+
+// vision : 2013-12-05 Koko Station, LLC
+vision
+
+// vista : 2014-09-18 Vistaprint Limited
+vista
+
+// vistaprint : 2014-09-18 Vistaprint Limited
+vistaprint
+
+// viva : 2014-11-07 Saudi Telecom Company
+viva
+
+// vlaanderen : 2014-02-06 DNS.be vzw
+vlaanderen
+
+// vodka : 2013-12-19 Top Level Domain Holdings Limited
+vodka
+
+// vote : 2013-11-21 Monolith Registry LLC
+vote
+
+// voting : 2013-11-13 Valuetainment Corp.
+voting
+
+// voto : 2013-11-21 Monolith Registry LLC
+voto
+
+// voyage : 2013-08-27 Ruby House, LLC
+voyage
+
+// vuelos : 2015-03-05 Travel Reservations SRL
+vuelos
+
+// wales : 2014-05-08 Nominet UK
+wales
+
+// walter : 2014-11-13 Sandvik AB
+walter
+
+// wang : 2013-10-24 Zodiac Leo Limited
+wang
+
+// wanggou : 2014-12-18 Amazon EU S.à r.l.
+wanggou
+
+// watch : 2013-11-14 Sand Shadow, LLC
+watch
+
+// watches : 2014-12-22 Richemont DNS Inc.
+watches
+
+// weather : 2015-01-08 The Weather Channel, LLC
+weather
+
+// weatherchannel : 2015-03-12 The Weather Channel, LLC
+weatherchannel
+
+// webcam : 2014-01-23 dot Webcam Limited
+webcam
+
+// website : 2014-04-03 DotWebsite Inc.
+website
+
+// wed : 2013-10-01 Atgron, Inc.
+wed
+
+// wedding : 2014-04-24 Top Level Domain Holdings Limited
+wedding
+
+// weibo : 2015-03-05 Sina Corporation
+weibo
+
+// weir : 2015-01-29 Weir Group IP Limited
+weir
+
+// whoswho : 2014-02-20 Who's Who Registry
+whoswho
+
+// wien : 2013-10-28 punkt.wien GmbH
+wien
+
+// wiki : 2013-11-07 Top Level Design, LLC
+wiki
+
+// williamhill : 2014-03-13 William Hill Organization Limited
+williamhill
+
+// win : 2014-11-20 First Registry Limited
+win
+
+// windows : 2014-12-18 Microsoft Corporation
+windows
+
+// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC
+wme
+
+// work : 2013-12-19 Top Level Domain Holdings Limited
+work
+
+// works : 2013-11-14 Little Dynamite, LLC
+works
+
+// world : 2014-06-12 Bitter Fields, LLC
+world
+
+// wtc : 2013-12-19 World Trade Centers Association, Inc.
+wtc
+
+// wtf : 2014-03-06 Hidden Way, LLC
+wtf
+
+// xbox : 2014-12-18 Microsoft Corporation
+xbox
+
+// xerox : 2014-10-24 Xerox DNHC LLC
+xerox
+
+// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+xihuan
+
+// xin : 2014-12-11 Elegant Leader Limited
+xin
+
+// xn--11b4c3d : 2015-01-15 VeriSign Sarl
+कॉम
+
+// xn--1ck2e1b : 2015-02-26 Amazon EU S.à r.l.
+セール
+
+// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd.
+佛山
+
+// xn--30rr7y : 2014-06-12 Excellent First Limited
+慈善
+
+// xn--3bst00m : 2013-09-13 Eagle Horizon Limited
+集团
+
+// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED
+在线
+
+// xn--3pxu8k : 2015-01-15 VeriSign Sarl
+点看
+
+// xn--42c2d9a : 2015-01-15 VeriSign Sarl
+คอม
+
+// xn--45q11c : 2013-11-21 Zodiac Scorpio Limited
+八卦
+
+// xn--4gbrim : 2013-10-04 Suhub Electronic Establishment
+موقع
+
+// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center
+公益
+
+// xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center)
+公司
+
+// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited
+网站
+
+// xn--6frz82g : 2013-09-23 Afilias Limited
+移动
+
+// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited
+我爱你
+
+// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+москва
+
+// xn--80asehdb : 2013-07-14 CORE Association
+онлайн
+
+// xn--80aswg : 2013-07-14 CORE Association
+сайт
+
+// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited
+联通
+
+// xn--9dbq2a : 2015-01-15 VeriSign Sarl
+קום
+
+// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED
+时尚
+
+// xn--9krt00a : 2015-03-12 Sina Corporation
+微博
+
+// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited
+淡马锡
+
+// xn--bck1b9a5dre4c : 2015-02-26 Amazon EU S.à r.l.
+ファッション
+
+// xn--c1avg : 2013-11-14 Public Interest Registry
+орг
+
+// xn--c2br7g : 2015-01-15 VeriSign Sarl
+नेट
+
+// xn--cck2b3b : 2015-02-26 Amazon EU S.à r.l.
+ストア
+
+// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD
+삼성
+
+// xn--czr694b : 2014-01-16 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY.HONGKONG LIMITED
+商标
+
+// xn--czrs0t : 2013-12-19 Wild Island, LLC
+商店
+
+// xn--czru2d : 2013-11-21 Zodiac Capricorn Limited
+商城
+
+// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet”
+дети
+
+// xn--eckvdtc9d : 2014-12-18 Amazon EU S.à r.l.
+ポイント
+
+// xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社
+新闻
+
+// xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited
+工行
+
+// xn--fct429k : 2015-04-09 Amazon EU S.à r.l.
+家電
+
+// xn--fhbei : 2015-01-15 VeriSign Sarl
+كوم
+
+// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED
+中文网
+
+// xn--fiq64b : 2013-10-14 CITIC Group Corporation
+中信
+
+// xn--fjq720a : 2014-05-22 Will Bloom, LLC
+娱乐
+
+// xn--flw351e : 2014-07-31 Charleston Road Registry Inc.
+谷歌
+
+// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited
+购物
+
+// xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l.
+クラウド
+
+// xn--hxt814e : 2014-05-15 Zodiac Libra Limited
+网店
+
+// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry
+संगठन
+
+// xn--imr513n : 2014-12-11 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY. HONGKONG LIMITED
+餐厅
+
+// xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center)
+网络
+
+// xn--j1aef : 2015-01-15 VeriSign Sarl
+ком
+
+// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation
+诺基亚
+
+// xn--jvr189m : 2015-02-26 Amazon EU S.à r.l.
+食品
+
+// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V.
+飞利浦
+
+// xn--kpu716f : 2014-12-22 Richemont DNS Inc.
+手表
+
+// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd
+手机
+
+// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company
+ارامكو
+
+// xn--mgbab2bd : 2013-10-31 CORE Association
+بازار
+
+// xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L.
+موبايلي
+
+// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+همراه
+
+// xn--mk1bu44c : 2015-01-15 VeriSign Sarl
+닷컴
+
+// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd.
+政府
+
+// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd.
+شبكة
+
+// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House
+بيتك
+
+// xn--nqv7f : 2013-11-14 Public Interest Registry
+机构
+
+// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry
+组织机构
+
+// xn--nyqy26a : 2014-11-07 Stable Tone Limited
+健康
+
+// xn--p1acf : 2013-12-12 Rusnames Limited
+рус
+
+// xn--pbt977c : 2014-12-22 Richemont DNS Inc.
+珠宝
+
+// xn--pssy2u : 2015-01-15 VeriSign Sarl
+大拿
+
+// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc.
+みんな
+
+// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc.
+グーグル
+
+// xn--rhqv96g : 2013-09-11 Stable Tone Limited
+世界
+
+// xn--rovu88b : 2015-02-26 Amazon EU S.à r.l.
+書籍
+
+// xn--ses554g : 2014-01-16
+网址
+
+// xn--t60b56a : 2015-01-15 VeriSign Sarl
+닷넷
+
+// xn--tckwe : 2015-01-15 VeriSign Sarl
+コム
+
+// xn--unup4y : 2013-07-14 Spring Fields, LLC
+游戏
+
+// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+vermögensberater
+
+// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+vermögensberatung
+
+// xn--vhquv : 2013-08-27 Dash McCook, LLC
+企业
+
+// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd.
+信息
+
+// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited
+嘉里大酒店
+
+// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd.
+广东
+
+// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center
+政务
+
+// xyz : 2013-12-05 XYZ.COM LLC
+xyz
+
+// yachts : 2014-01-09 DERYachts, LLC
+yachts
+
+// yahoo : 2015-04-02 Yahoo! Domain Services Inc.
+yahoo
+
+// yamaxun : 2014-12-18 Amazon EU S.à r.l.
+yamaxun
+
+// yandex : 2014-04-10 YANDEX, LLC
+yandex
+
+// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+yodobashi
+
+// yoga : 2014-05-29 Top Level Domain Holdings Limited
+yoga
+
+// yokohama : 2013-12-12 GMO Registry, Inc.
+yokohama
+
+// you : 2015-04-09 Amazon EU S.à r.l.
+you
+
+// youtube : 2014-05-01 Charleston Road Registry Inc.
+youtube
+
+// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+yun
+
+// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.)
+zara
+
+// zero : 2014-12-18 Amazon EU S.à r.l.
+zero
+
+// zip : 2014-05-08 Charleston Road Registry Inc.
+zip
+
+// zone : 2013-11-14 Outer Falls, LLC
+zone
+
+// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich)
+zuerich
+
+
+// ===END ICANN DOMAINS===
+// ===BEGIN PRIVATE DOMAINS===
+// (Note: these are in alphabetical order by company name)
+
+// Amazon CloudFront : https://aws.amazon.com/cloudfront/
+// Submitted by Donavan Miller <donavanm at amazon.com> 2013-03-22
+cloudfront.net
+
+// Amazon Elastic Compute Cloud: https://aws.amazon.com/ec2/
+// Submitted by Osman Surkatty <osmans at amazon.com> 2014-12-16
+ap-northeast-1.compute.amazonaws.com
+ap-southeast-1.compute.amazonaws.com
+ap-southeast-2.compute.amazonaws.com
+cn-north-1.compute.amazonaws.cn
+compute.amazonaws.cn
+compute.amazonaws.com
+compute-1.amazonaws.com
+eu-west-1.compute.amazonaws.com
+eu-central-1.compute.amazonaws.com
+sa-east-1.compute.amazonaws.com
+us-east-1.amazonaws.com
+us-gov-west-1.compute.amazonaws.com
+us-west-1.compute.amazonaws.com
+us-west-2.compute.amazonaws.com
+z-1.compute-1.amazonaws.com
+z-2.compute-1.amazonaws.com
+
+// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/
+// Submitted by Adam Stein <astein at amazon.com> 2013-04-02
+elasticbeanstalk.com
+
+// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/
+// Submitted by Scott Vidmar <svidmar at amazon.com> 2013-03-27
+elb.amazonaws.com
+
+// Amazon S3 : https://aws.amazon.com/s3/
+// Submitted by Courtney Eckhardt <coec at amazon.com> 2013-03-22
+s3.amazonaws.com
+s3-us-west-2.amazonaws.com
+s3-us-west-1.amazonaws.com
+s3-eu-west-1.amazonaws.com
+s3-ap-southeast-1.amazonaws.com
+s3-ap-southeast-2.amazonaws.com
+s3-ap-northeast-1.amazonaws.com
+s3-sa-east-1.amazonaws.com
+s3-us-gov-west-1.amazonaws.com
+s3-fips-us-gov-west-1.amazonaws.com
+s3-website-us-east-1.amazonaws.com
+s3-website-us-west-2.amazonaws.com
+s3-website-us-west-1.amazonaws.com
+s3-website-eu-west-1.amazonaws.com
+s3-website-ap-southeast-1.amazonaws.com
+s3-website-ap-southeast-2.amazonaws.com
+s3-website-ap-northeast-1.amazonaws.com
+s3-website-sa-east-1.amazonaws.com
+s3-website-us-gov-west-1.amazonaws.com
+
+// BetaInABox
+// Submitted by adrian at betainabox.com 2012-09-13
+betainabox.com
+
+// CentralNic : http://www.centralnic.com/names/domains
+// Submitted by registry <gavin.brown at centralnic.com> 2012-09-27
+ae.org
+ar.com
+br.com
+cn.com
+com.de
+com.se
+de.com
+eu.com
+gb.com
+gb.net
+hu.com
+hu.net
+jp.net
+jpn.com
+kr.com
+mex.com
+no.com
+qc.com
+ru.com
+sa.com
+se.com
+se.net
+uk.com
+uk.net
+us.com
+uy.com
+za.bz
+za.com
+
+// Africa.com Web Solutions Ltd : https://registry.africa.com
+// Submitted by Gavin Brown <gavin.brown at centralnic.com> 2014-02-04
+africa.com
+
+// iDOT Services Limited : http://www.domain.gr.com
+// Submitted by Gavin Brown <gavin.brown at centralnic.com> 2014-02-04
+gr.com
+
+// Radix FZC : http://domains.in.net
+// Submitted by Gavin Brown <gavin.brown at centralnic.com> 2014-02-04
+in.net
+
+// US REGISTRY LLC : http://us.org
+// Submitted by Gavin Brown <gavin.brown at centralnic.com> 2014-02-04
+us.org
+
+// co.com Registry, LLC : https://registry.co.com
+// Submitted by Gavin Brown <gavin.brown at centralnic.com> 2014-02-04
+co.com
+
+// c.la : http://www.c.la/
+c.la
+
+// cloudControl : https://www.cloudcontrol.com/
+// Submitted by Tobias Wilken <tw at cloudcontrol.com> 2013-07-23
+cloudcontrolled.com
+cloudcontrolapp.com
+
+// co.ca : http://registry.co.ca/
+co.ca
+
+// CoDNS B.V.
+co.nl
+co.no
+
+// Commerce Guys, SAS
+// Submitted by Damien Tournoud <damien at commerceguys.com> 2015-01-22
+*.platform.sh
+
+// Cupcake : https://cupcake.io/
+// Submitted by Jonathan Rudenberg <jonathan at cupcake.io> 2013-10-08
+cupcake.is
+
+// DreamHost : http://www.dreamhost.com/
+// Submitted by Andrew Farmer <andrew.farmer at dreamhost.com> 2012-10-02
+dreamhosters.com
+
+// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/
+dyndns-at-home.com
+dyndns-at-work.com
+dyndns-blog.com
+dyndns-free.com
+dyndns-home.com
+dyndns-ip.com
+dyndns-mail.com
+dyndns-office.com
+dyndns-pics.com
+dyndns-remote.com
+dyndns-server.com
+dyndns-web.com
+dyndns-wiki.com
+dyndns-work.com
+dyndns.biz
+dyndns.info
+dyndns.org
+dyndns.tv
+at-band-camp.net
+ath.cx
+barrel-of-knowledge.info
+barrell-of-knowledge.info
+better-than.tv
+blogdns.com
+blogdns.net
+blogdns.org
+blogsite.org
+boldlygoingnowhere.org
+broke-it.net
+buyshouses.net
+cechire.com
+dnsalias.com
+dnsalias.net
+dnsalias.org
+dnsdojo.com
+dnsdojo.net
+dnsdojo.org
+does-it.net
+doesntexist.com
+doesntexist.org
+dontexist.com
+dontexist.net
+dontexist.org
+doomdns.com
+doomdns.org
+dvrdns.org
+dyn-o-saur.com
+dynalias.com
+dynalias.net
+dynalias.org
+dynathome.net
+dyndns.ws
+endofinternet.net
+endofinternet.org
+endoftheinternet.org
+est-a-la-maison.com
+est-a-la-masion.com
+est-le-patron.com
+est-mon-blogueur.com
+for-better.biz
+for-more.biz
+for-our.info
+for-some.biz
+for-the.biz
+forgot.her.name
+forgot.his.name
+from-ak.com
+from-al.com
+from-ar.com
+from-az.net
+from-ca.com
+from-co.net
+from-ct.com
+from-dc.com
+from-de.com
+from-fl.com
+from-ga.com
+from-hi.com
+from-ia.com
+from-id.com
+from-il.com
+from-in.com
+from-ks.com
+from-ky.com
+from-la.net
+from-ma.com
+from-md.com
+from-me.org
+from-mi.com
+from-mn.com
+from-mo.com
+from-ms.com
+from-mt.com
+from-nc.com
+from-nd.com
+from-ne.com
+from-nh.com
+from-nj.com
+from-nm.com
+from-nv.com
+from-ny.net
+from-oh.com
+from-ok.com
+from-or.com
+from-pa.com
+from-pr.com
+from-ri.com
+from-sc.com
+from-sd.com
+from-tn.com
+from-tx.com
+from-ut.com
+from-va.com
+from-vt.com
+from-wa.com
+from-wi.com
+from-wv.com
+from-wy.com
+ftpaccess.cc
+fuettertdasnetz.de
+game-host.org
+game-server.cc
+getmyip.com
+gets-it.net
+go.dyndns.org
+gotdns.com
+gotdns.org
+groks-the.info
+groks-this.info
+ham-radio-op.net
+here-for-more.info
+hobby-site.com
+hobby-site.org
+home.dyndns.org
+homedns.org
+homeftp.net
+homeftp.org
+homeip.net
+homelinux.com
+homelinux.net
+homelinux.org
+homeunix.com
+homeunix.net
+homeunix.org
+iamallama.com
+in-the-band.net
+is-a-anarchist.com
+is-a-blogger.com
+is-a-bookkeeper.com
+is-a-bruinsfan.org
+is-a-bulls-fan.com
+is-a-candidate.org
+is-a-caterer.com
+is-a-celticsfan.org
+is-a-chef.com
+is-a-chef.net
+is-a-chef.org
+is-a-conservative.com
+is-a-cpa.com
+is-a-cubicle-slave.com
+is-a-democrat.com
+is-a-designer.com
+is-a-doctor.com
+is-a-financialadvisor.com
+is-a-geek.com
+is-a-geek.net
+is-a-geek.org
+is-a-green.com
+is-a-guru.com
+is-a-hard-worker.com
+is-a-hunter.com
+is-a-knight.org
+is-a-landscaper.com
+is-a-lawyer.com
+is-a-liberal.com
+is-a-libertarian.com
+is-a-linux-user.org
+is-a-llama.com
+is-a-musician.com
+is-a-nascarfan.com
+is-a-nurse.com
+is-a-painter.com
+is-a-patsfan.org
+is-a-personaltrainer.com
+is-a-photographer.com
+is-a-player.com
+is-a-republican.com
+is-a-rockstar.com
+is-a-socialist.com
+is-a-soxfan.org
+is-a-student.com
+is-a-teacher.com
+is-a-techie.com
+is-a-therapist.com
+is-an-accountant.com
+is-an-actor.com
+is-an-actress.com
+is-an-anarchist.com
+is-an-artist.com
+is-an-engineer.com
+is-an-entertainer.com
+is-by.us
+is-certified.com
+is-found.org
+is-gone.com
+is-into-anime.com
+is-into-cars.com
+is-into-cartoons.com
+is-into-games.com
+is-leet.com
+is-lost.org
+is-not-certified.com
+is-saved.org
+is-slick.com
+is-uberleet.com
+is-very-bad.org
+is-very-evil.org
+is-very-good.org
+is-very-nice.org
+is-very-sweet.org
+is-with-theband.com
+isa-geek.com
+isa-geek.net
+isa-geek.org
+isa-hockeynut.com
+issmarterthanyou.com
+isteingeek.de
+istmein.de
+kicks-ass.net
+kicks-ass.org
+knowsitall.info
+land-4-sale.us
+lebtimnetz.de
+leitungsen.de
+likes-pie.com
+likescandy.com
+merseine.nu
+mine.nu
+misconfused.org
+mypets.ws
+myphotos.cc
+neat-url.com
+office-on-the.net
+on-the-web.tv
+podzone.net
+podzone.org
+readmyblog.org
+saves-the-whales.com
+scrapper-site.net
+scrapping.cc
+selfip.biz
+selfip.com
+selfip.info
+selfip.net
+selfip.org
+sells-for-less.com
+sells-for-u.com
+sells-it.net
+sellsyourhome.org
+servebbs.com
+servebbs.net
+servebbs.org
+serveftp.net
+serveftp.org
+servegame.org
+shacknet.nu
+simple-url.com
+space-to-rent.com
+stuff-4-sale.org
+stuff-4-sale.us
+teaches-yoga.com
+thruhere.net
+traeumtgerade.de
+webhop.biz
+webhop.info
+webhop.net
+webhop.org
+worse-than.tv
+writesthisblog.com
+
+// EU.org https://eu.org/
+// Submitted by Pierre Beyssac <hostmaster at eu.org> 2015-04-17
+
+eu.org
+al.eu.org
+asso.eu.org
+at.eu.org
+au.eu.org
+be.eu.org
+bg.eu.org
+ca.eu.org
+cd.eu.org
+ch.eu.org
+cn.eu.org
+cy.eu.org
+cz.eu.org
+de.eu.org
+dk.eu.org
+edu.eu.org
+ee.eu.org
+es.eu.org
+fi.eu.org
+fr.eu.org
+gr.eu.org
+hr.eu.org
+hu.eu.org
+ie.eu.org
+il.eu.org
+in.eu.org
+int.eu.org
+is.eu.org
+it.eu.org
+jp.eu.org
+kr.eu.org
+lt.eu.org
+lu.eu.org
+lv.eu.org
+mc.eu.org
+me.eu.org
+mk.eu.org
+mt.eu.org
+my.eu.org
+net.eu.org
+ng.eu.org
+nl.eu.org
+no.eu.org
+nz.eu.org
+paris.eu.org
+pl.eu.org
+pt.eu.org
+q-a.eu.org
+ro.eu.org
+ru.eu.org
+se.eu.org
+si.eu.org
+sk.eu.org
+tr.eu.org
+uk.eu.org
+us.eu.org
+
+// Fastly Inc. http://www.fastly.com/
+// Submitted by Vladimir Vuksan <vladimir at fastly.com> 2013-05-31
+a.ssl.fastly.net
+b.ssl.fastly.net
+global.ssl.fastly.net
+a.prod.fastly.net
+global.prod.fastly.net
+
+// Firebase, Inc.
+// Submitted by Chris Raynor <chris at firebase.com> 2014-01-21
+firebaseapp.com
+
+// Flynn : https://flynn.io
+// Submitted by Jonathan Rudenberg <jonathan at flynn.io> 2014-07-12
+flynnhub.com
+
+// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains
+// Submitted by David Illsley <david.illsley at digital.cabinet-office.gov.uk> 2014-08-28
+service.gov.uk
+
+// GitHub, Inc.
+// Submitted by Ben Toews <btoews at github.com> 2014-02-06
+github.io
+githubusercontent.com
+
+// GlobeHosting, Inc.
+// Submitted by Zoltan Egresi <egresi at globehosting.com> 2013-07-12
+ro.com
+
+// Google, Inc.
+// Submitted by Eduardo Vela <evn at google.com> 2014-12-19
+appspot.com
+blogspot.ae
+blogspot.be
+blogspot.bj
+blogspot.ca
+blogspot.cf
+blogspot.ch
+blogspot.co.at
+blogspot.co.il
+blogspot.co.nz
+blogspot.co.uk
+blogspot.com
+blogspot.com.ar
+blogspot.com.au
+blogspot.com.br
+blogspot.com.es
+blogspot.com.tr
+blogspot.cv
+blogspot.cz
+blogspot.de
+blogspot.dk
+blogspot.fi
+blogspot.fr
+blogspot.gr
+blogspot.hk
+blogspot.hu
+blogspot.ie
+blogspot.in
+blogspot.it
+blogspot.jp
+blogspot.kr
+blogspot.mr
+blogspot.mx
+blogspot.nl
+blogspot.no
+blogspot.pt
+blogspot.re
+blogspot.ro
+blogspot.ru
+blogspot.se
+blogspot.sg
+blogspot.sk
+blogspot.td
+blogspot.tw
+codespot.com
+googleapis.com
+googlecode.com
+pagespeedmobilizer.com
+withgoogle.com
+
+// Heroku : https://www.heroku.com/
+// Submitted by Tom Maher <tmaher at heroku.com> 2013-05-02
+herokuapp.com
+herokussl.com
+
+// iki.fi
+// Submitted by Hannu Aronsson <haa at iki.fi> 2009-11-05
+iki.fi
+
+// info.at : http://www.info.at/
+biz.at
+info.at
+
+// Michau Enterprises Limited : http://www.co.pl/
+co.pl
+
+// Microsoft : http://microsoft.com
+// Submitted by Barry Dorrans <bdorrans at microsoft.com> 2014-01-24
+azurewebsites.net
+azure-mobile.net
+cloudapp.net
+
+// Neustar Inc.
+// Submitted by Trung Tran <Trung.Tran at neustar.biz> 2015-04-23
+4u.com
+
+// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/
+// Submitted by Jeff Wheelhouse <support at nearlyfreespeech.net> 2014-02-02
+nfshost.com
+
+// NYC.mn : http://www.information.nyc.mn
+// Submitted by Matthew Brown <mattbrown at nyc.mn> 2013-03-11
+nyc.mn
+
+// One Fold Media : http://www.onefoldmedia.com/
+// Submitted by Eddie Jones <eddie at onefoldmedia.com> 2014-06-10
+nid.io
+
+// Opera Software, A.S.A.
+// Submitted by Yngve Pettersen <yngve at opera.com> 2009-11-26
+operaunite.com
+
+// OutSystems
+// Submitted by Duarte Santos <domain-admin at outsystemscloud.com> 2014-03-11
+outsystemscloud.com
+
+// .pl domains (grandfathered)
+art.pl
+gliwice.pl
+krakow.pl
+poznan.pl
+wroc.pl
+zakopane.pl
+
+// priv.at : http://www.nic.priv.at/
+// Submitted by registry <lendl at nic.at> 2008-06-09
+priv.at
+
+// Red Hat, Inc. OpenShift : https://openshift.redhat.com/
+// Submitted by Tim Kramer <tkramer at rhcloud.com> 2012-10-24
+rhcloud.com
+
+// SinaAppEngine : http://sae.sina.com.cn/
+// Submitted by SinaAppEngine <saesupport at sinacloud.com> 2015-02-02
+sinaapp.com
+vipsinaapp.com
+1kapp.com
+
+// TASK geographical domains (www.task.gda.pl/uslugi/dns)
+gda.pl
+gdansk.pl
+gdynia.pl
+med.pl
+sopot.pl
+
+// UDR Limited : http://www.udr.hk.com
+// Submitted by registry <hostmaster at udr.hk.com> 2014-11-07
+hk.com
+hk.org
+ltd.hk
+inc.hk
+
+// Yola : https://www.yola.com/
+// Submitted by Stefano Rivera <stefano at yola.com> 2014-07-09
+yolasite.com
+
+// ZaNiC : http://www.za.net/
+// Submitted by registry <hostmaster at nic.za.net> 2009-10-03
+za.net
+za.org
+
+// ===END PRIVATE DOMAINS===
diff --git a/httpclient/src/test/java/org/apache/http/auth/TestAuthScope.java b/httpclient/src/test/java/org/apache/http/auth/TestAuthScope.java
new file mode 100644
index 0000000..ce8f28d
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/auth/TestAuthScope.java
@@ -0,0 +1,185 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.auth;
+
+import org.apache.http.HttpHost;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests for {@link org.apache.http.auth.AuthScope}.
+ */
+public class TestAuthScope {
+
+    @Test
+    public void testBasics() {
+        final AuthScope authscope = new AuthScope("somehost", 80, "somerealm", "somescheme");
+        Assert.assertEquals("SOMESCHEME", authscope.getScheme());
+        Assert.assertEquals("somehost", authscope.getHost());
+        Assert.assertEquals(80, authscope.getPort());
+        Assert.assertEquals("somerealm", authscope.getRealm());
+        Assert.assertEquals("SOMESCHEME 'somerealm'@somehost:80", authscope.toString());
+    }
+
+    @Test
+    public void testBasicsOptionalRealm() {
+        final AuthScope authscope = new AuthScope("somehost", 80, AuthScope.ANY_REALM, "somescheme");
+        Assert.assertEquals("SOMESCHEME", authscope.getScheme());
+        Assert.assertEquals("somehost", authscope.getHost());
+        Assert.assertEquals(80, authscope.getPort());
+        Assert.assertEquals(null, authscope.getRealm());
+        Assert.assertEquals("SOMESCHEME <any realm>@somehost:80", authscope.toString());
+    }
+
+    @Test
+    public void testBasicsOptionalScheme() {
+        final AuthScope authscope = new AuthScope("somehost", 80, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME);
+        Assert.assertEquals(null, authscope.getScheme());
+        Assert.assertEquals("somehost", authscope.getHost());
+        Assert.assertEquals(80, authscope.getPort());
+        Assert.assertEquals(null, authscope.getRealm());
+        Assert.assertEquals("<any realm>@somehost:80", authscope.toString());
+    }
+
+    @Test
+    public void testBasicsOptionalPort() {
+        final AuthScope authscope = new AuthScope("somehost", AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME);
+        Assert.assertEquals(null, authscope.getScheme());
+        Assert.assertEquals("somehost", authscope.getHost());
+        Assert.assertEquals(-1, authscope.getPort());
+        Assert.assertEquals(null, authscope.getRealm());
+        Assert.assertEquals("<any realm>@somehost", authscope.toString());
+    }
+
+    @Test
+    public void testByOrigin() {
+        final HttpHost host = new HttpHost("somehost", 8080, "http");
+        final AuthScope authscope = new AuthScope(host);
+        Assert.assertEquals(null, authscope.getScheme());
+        Assert.assertEquals("somehost", authscope.getHost());
+        Assert.assertEquals(8080, authscope.getPort());
+        Assert.assertEquals(null, authscope.getRealm());
+        Assert.assertEquals(host, authscope.getOrigin());
+        Assert.assertEquals("<any realm>@somehost:8080", authscope.toString());
+    }
+
+    @Test
+    public void testMixedCaseHostname() {
+        final AuthScope authscope = new AuthScope("SomeHost", 80);
+        Assert.assertEquals(null, authscope.getScheme());
+        Assert.assertEquals("somehost", authscope.getHost());
+        Assert.assertEquals(80, authscope.getPort());
+        Assert.assertEquals(null, authscope.getRealm());
+        Assert.assertEquals("<any realm>@somehost:80", authscope.toString());
+    }
+
+    public void testByOriginMixedCaseHostname() throws Exception {
+        final HttpHost host = new HttpHost("SomeHost", 8080, "http");
+        final AuthScope authscope = new AuthScope(host);
+        Assert.assertEquals("somehost", authscope.getHost());
+        Assert.assertEquals(host, authscope.getOrigin());
+    }
+
+    @Test
+    public void testBasicsOptionalHost() {
+        final AuthScope authscope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME);
+        Assert.assertEquals(null, authscope.getScheme());
+        Assert.assertEquals(null, authscope.getHost());
+        Assert.assertEquals(-1, authscope.getPort());
+        Assert.assertEquals(null, authscope.getRealm());
+        Assert.assertEquals("<any realm>", authscope.toString());
+    }
+
+    @Test
+    public void testScopeMatching() {
+        final AuthScope authscope1 = new AuthScope("somehost", 80, "somerealm", "somescheme");
+        final AuthScope authscope2 = new AuthScope("someotherhost", 80, "somerealm", "somescheme");
+        Assert.assertTrue(authscope1.match(authscope2) < 0);
+
+        int m1 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
+        int m2 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", AuthScope.ANY_SCHEME));
+        Assert.assertTrue(m2 > m1);
+
+        m1 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
+        m2 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", AuthScope.ANY_SCHEME));
+        Assert.assertTrue(m2 > m1);
+
+        m1 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", "somescheme"));
+        m2 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, 80, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME));
+        Assert.assertTrue(m2 > m1);
+
+        m1 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, 80, "somerealm", "somescheme"));
+        m2 = authscope1.match(
+                new AuthScope("somehost", AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME));
+        Assert.assertTrue(m2 > m1);
+
+        m1 = authscope1.match(AuthScope.ANY);
+        m2 = authscope1.match(
+                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
+        Assert.assertTrue(m2 > m1);
+    }
+
+    @Test
+    public void testEquals() {
+        final AuthScope authscope1 = new AuthScope("somehost", 80, "somerealm", "somescheme");
+        final AuthScope authscope2 = new AuthScope("someotherhost", 80, "somerealm", "somescheme");
+        final AuthScope authscope3 = new AuthScope("somehost", 80, "somerealm", "somescheme");
+        final AuthScope authscope4 = new AuthScope("somehost", 8080, "somerealm", "somescheme");
+        final AuthScope authscope5 = new AuthScope("somehost", 80, "someotherrealm", "somescheme");
+        final AuthScope authscope6 = new AuthScope("somehost", 80, "somerealm", "someotherscheme");
+        Assert.assertTrue(authscope1.equals(authscope1));
+        Assert.assertFalse(authscope1.equals(authscope2));
+        Assert.assertTrue(authscope1.equals(authscope3));
+        Assert.assertFalse(authscope1.equals(authscope4));
+        Assert.assertFalse(authscope1.equals(authscope5));
+        Assert.assertFalse(authscope1.equals(authscope6));
+    }
+
+    @Test
+    public void testHash() {
+        final AuthScope authscope1 = new AuthScope("somehost", 80, "somerealm", "somescheme");
+        final AuthScope authscope2 = new AuthScope("someotherhost", 80, "somerealm", "somescheme");
+        final AuthScope authscope3 = new AuthScope("somehost", 80, "somerealm", "somescheme");
+        final AuthScope authscope4 = new AuthScope("somehost", 8080, "somerealm", "somescheme");
+        final AuthScope authscope5 = new AuthScope("somehost", 80, "someotherrealm", "somescheme");
+        final AuthScope authscope6 = new AuthScope("somehost", 80, "somerealm", "someotherscheme");
+        Assert.assertTrue(authscope1.hashCode() == authscope1.hashCode());
+        Assert.assertFalse(authscope1.hashCode() == authscope2.hashCode());
+        Assert.assertTrue(authscope1.hashCode() == authscope3.hashCode());
+        Assert.assertFalse(authscope1.hashCode() == authscope4.hashCode());
+        Assert.assertFalse(authscope1.hashCode() == authscope5.hashCode());
+        Assert.assertFalse(authscope1.hashCode() == authscope6.hashCode());
+    }
+
+}
diff --git a/httpclient/src/test/java/org/apache/http/client/config/TestRequestConfig.java b/httpclient/src/test/java/org/apache/http/client/config/TestRequestConfig.java
index b34fbf4..f37f64d 100644
--- a/httpclient/src/test/java/org/apache/http/client/config/TestRequestConfig.java
+++ b/httpclient/src/test/java/org/apache/http/client/config/TestRequestConfig.java
@@ -27,13 +27,13 @@
 
 package org.apache.http.client.config;
 
-import junit.framework.Assert;
-import org.apache.http.HttpHost;
-import org.junit.Test;
-
 import java.net.InetAddress;
 import java.util.Arrays;
 
+import org.apache.http.HttpHost;
+import org.junit.Assert;
+import org.junit.Test;
+
 public class TestRequestConfig {
 
     @Test
@@ -49,7 +49,6 @@ public class TestRequestConfig {
         Assert.assertEquals(-1, config.getConnectTimeout());
         Assert.assertEquals(-1, config.getConnectionRequestTimeout());
         Assert.assertEquals(false, config.isExpectContinueEnabled());
-        Assert.assertEquals(true, config.isStaleConnectionCheckEnabled());
         Assert.assertEquals(true, config.isAuthenticationEnabled());
         Assert.assertEquals(true, config.isRedirectsEnabled());
         Assert.assertEquals(true, config.isRelativeRedirectsAllowed());
@@ -69,7 +68,6 @@ public class TestRequestConfig {
                 .setConnectTimeout(33)
                 .setConnectionRequestTimeout(44)
                 .setExpectContinueEnabled(true)
-                .setStaleConnectionCheckEnabled(false)
                 .setAuthenticationEnabled(false)
                 .setRedirectsEnabled(false)
                 .setRelativeRedirectsAllowed(false)
@@ -86,7 +84,6 @@ public class TestRequestConfig {
         Assert.assertEquals(33, config.getConnectTimeout());
         Assert.assertEquals(44, config.getConnectionRequestTimeout());
         Assert.assertEquals(true, config.isExpectContinueEnabled());
-        Assert.assertEquals(false, config.isStaleConnectionCheckEnabled());
         Assert.assertEquals(false, config.isAuthenticationEnabled());
         Assert.assertEquals(false, config.isRedirectsEnabled());
         Assert.assertEquals(false, config.isRelativeRedirectsAllowed());
diff --git a/httpclient/src/test/java/org/apache/http/client/entity/TestDecompressingEntity.java b/httpclient/src/test/java/org/apache/http/client/entity/TestDecompressingEntity.java
index 09b48ed..347d99d 100644
--- a/httpclient/src/test/java/org/apache/http/client/entity/TestDecompressingEntity.java
+++ b/httpclient/src/test/java/org/apache/http/client/entity/TestDecompressingEntity.java
@@ -35,6 +35,7 @@ import java.util.zip.CRC32;
 import java.util.zip.CheckedInputStream;
 import java.util.zip.Checksum;
 
+import org.apache.http.Consts;
 import org.apache.http.HttpEntity;
 import org.apache.http.entity.InputStreamEntity;
 import org.apache.http.entity.StringEntity;
@@ -61,7 +62,7 @@ public class TestDecompressingEntity {
     @Test
     public void testStreaming() throws Exception {
         final CRC32 crc32 = new CRC32();
-        final ByteArrayInputStream in = new ByteArrayInputStream("1234567890".getBytes("ASCII"));
+        final ByteArrayInputStream in = new ByteArrayInputStream("1234567890".getBytes(Consts.ASCII));
         final InputStreamEntity wrapped = new InputStreamEntity(in, -1);
         final ChecksumEntity entity = new ChecksumEntity(wrapped, crc32);
         Assert.assertTrue(entity.isStreaming());
@@ -92,16 +93,15 @@ public class TestDecompressingEntity {
 
     static class ChecksumEntity extends DecompressingEntity {
 
-        private final Checksum checksum;
-
         public ChecksumEntity(final HttpEntity wrapped, final Checksum checksum) {
-            super(wrapped);
-            this.checksum = checksum;
-        }
+            super(wrapped, new InputStreamFactory() {
+
+                @Override
+                public InputStream create(final InputStream instream) throws IOException {
+                    return new CheckedInputStream(instream, checksum);
+                }
 
-        @Override
-        InputStream decorate(final InputStream wrapped) throws IOException {
-            return new CheckedInputStream(wrapped, this.checksum);
+            });
         }
 
     }
diff --git a/httpclient/src/test/java/org/apache/http/client/entity/TestEntityBuilder.java b/httpclient/src/test/java/org/apache/http/client/entity/TestEntityBuilder.java
index 875de6f..595ae69 100644
--- a/httpclient/src/test/java/org/apache/http/client/entity/TestEntityBuilder.java
+++ b/httpclient/src/test/java/org/apache/http/client/entity/TestEntityBuilder.java
@@ -71,6 +71,7 @@ public class TestEntityBuilder {
         Assert.assertNotNull(entity);
         Assert.assertNotNull(entity.getContent());
         Assert.assertNotNull(entity.getContentType());
+        Assert.assertEquals(-1, entity.getContentLength());
         Assert.assertEquals("application/octet-stream", entity.getContentType().getValue());
     }
 
diff --git a/httpclient/src/test/java/org/apache/http/client/methods/TestRequestBuilder.java b/httpclient/src/test/java/org/apache/http/client/methods/TestRequestBuilder.java
index e27c6e3..f839268 100644
--- a/httpclient/src/test/java/org/apache/http/client/methods/TestRequestBuilder.java
+++ b/httpclient/src/test/java/org/apache/http/client/methods/TestRequestBuilder.java
@@ -28,13 +28,16 @@
 package org.apache.http.client.methods;
 
 import java.net.URI;
+import java.util.List;
 
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpVersion;
+import org.apache.http.NameValuePair;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.entity.BasicHttpEntity;
+import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicNameValuePair;
@@ -160,6 +163,46 @@ public class TestRequestBuilder {
     }
 
     @Test
+    public void testCopyWithQueryParams() throws Exception {
+        final HttpGet get = new HttpGet("/stuff?p1=this&p2=that");
+        final RequestBuilder builder = RequestBuilder.copy(get);
+        final List<NameValuePair> parameters = builder.getParameters();
+        Assert.assertNotNull(parameters);
+        Assert.assertEquals(2, parameters.size());
+        Assert.assertEquals(new BasicNameValuePair("p1", "this"), parameters.get(0));
+        Assert.assertEquals(new BasicNameValuePair("p2", "that"), parameters.get(1));
+        Assert.assertEquals(new URI("/stuff"), builder.getUri());
+    }
+
+    @Test
+    public void testCopyWithFormParams() throws Exception {
+        final HttpPost post = new HttpPost("/stuff?p1=wtf");
+        post.setEntity(new StringEntity("p1=this&p2=that", ContentType.APPLICATION_FORM_URLENCODED));
+        final RequestBuilder builder = RequestBuilder.copy(post);
+        final List<NameValuePair> parameters = builder.getParameters();
+        Assert.assertNotNull(parameters);
+        Assert.assertEquals(2, parameters.size());
+        Assert.assertEquals(new BasicNameValuePair("p1", "this"), parameters.get(0));
+        Assert.assertEquals(new BasicNameValuePair("p2", "that"), parameters.get(1));
+        Assert.assertEquals(new URI("/stuff?p1=wtf"), builder.getUri());
+        Assert.assertNull(builder.getEntity());
+    }
+
+    @Test
+    public void testCopyWithStringEntity() throws Exception {
+        final HttpPost post = new HttpPost("/stuff?p1=wtf");
+        final HttpEntity entity = new StringEntity("p1=this&p2=that", ContentType.TEXT_PLAIN);
+        post.setEntity(entity);
+        final RequestBuilder builder = RequestBuilder.copy(post);
+        final List<NameValuePair> parameters = builder.getParameters();
+        Assert.assertNotNull(parameters);
+        Assert.assertEquals(1, parameters.size());
+        Assert.assertEquals(new BasicNameValuePair("p1", "wtf"), parameters.get(0));
+        Assert.assertEquals(new URI("/stuff"), builder.getUri());
+        Assert.assertSame(entity, builder.getEntity());
+    }
+
+    @Test
     public void testGettersAndMutators() throws Exception {
         final HttpEntity entity = new StringEntity("stuff");
         final RequestConfig config = RequestConfig.custom().build();
diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java
index b8d986b..1c8cf42 100644
--- a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java
+++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java
@@ -47,17 +47,17 @@ import org.apache.http.cookie.SM;
 import org.apache.http.impl.client.BasicCookieStore;
 import org.apache.http.impl.cookie.BasicClientCookie;
 import org.apache.http.impl.cookie.BasicClientCookie2;
-import org.apache.http.impl.cookie.BestMatchSpecFactory;
-import org.apache.http.impl.cookie.BrowserCompatSpec;
-import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
-import org.apache.http.impl.cookie.IgnoreSpecFactory;
-import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
-import org.apache.http.impl.cookie.RFC2965SpecFactory;
+import org.apache.http.impl.cookie.DefaultCookieSpecProvider;
+import org.apache.http.impl.cookie.IgnoreSpecProvider;
+import org.apache.http.impl.cookie.NetscapeDraftSpec;
+import org.apache.http.impl.cookie.NetscapeDraftSpecProvider;
+import org.apache.http.impl.cookie.RFC2965SpecProvider;
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.protocol.HttpCoreContext;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 public class TestRequestAddCookies {
 
@@ -81,11 +81,10 @@ public class TestRequestAddCookies {
         this.cookieStore.addCookie(cookie2);
 
         this.cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
-            .register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
-            .register(CookieSpecs.STANDARD, new RFC2965SpecFactory())
-            .register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory())
-            .register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecFactory())
-            .register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecFactory())
+            .register(CookieSpecs.DEFAULT, new DefaultCookieSpecProvider())
+            .register(CookieSpecs.STANDARD, new RFC2965SpecProvider())
+            .register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecProvider())
+            .register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecProvider())
             .build();
     }
 
@@ -252,7 +251,7 @@ public class TestRequestAddCookies {
     public void testAddCookiesUsingExplicitCookieSpec() throws Exception {
         final HttpRequest request = new BasicHttpRequest("GET", "/");
         final RequestConfig config = RequestConfig.custom()
-            .setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY).build();
+            .setCookieSpec(CookieSpecs.NETSCAPE).build();
         final HttpRoute route = new HttpRoute(this.target, null, false);
 
         final HttpClientContext context = HttpClientContext.create();
@@ -266,7 +265,7 @@ public class TestRequestAddCookies {
         interceptor.process(request, context);
 
         final CookieSpec cookieSpec = context.getCookieSpec();
-        Assert.assertTrue(cookieSpec instanceof BrowserCompatSpec);
+        Assert.assertTrue(cookieSpec instanceof NetscapeDraftSpec);
 
         final Header[] headers1 = request.getHeaders(SM.COOKIE);
         Assert.assertNotNull(headers1);
@@ -373,10 +372,13 @@ public class TestRequestAddCookies {
         cookie3.setVersion(1);
         cookie3.setDomain("localhost.local");
         cookie3.setPath("/");
-        cookie3.setExpiryDate(new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000)));
-
+        cookie3.setExpiryDate(new Date(System.currentTimeMillis() + 100));
         this.cookieStore.addCookie(cookie3);
 
+        Assert.assertEquals(3, this.cookieStore.getCookies().size());
+
+        this.cookieStore = Mockito.spy(this.cookieStore);
+
         final HttpRoute route = new HttpRoute(this.target, null, false);
 
         final HttpClientContext context = HttpClientContext.create();
@@ -385,6 +387,9 @@ public class TestRequestAddCookies {
         context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
         context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
 
+        // Make sure the third cookie expires
+        Thread.sleep(200);
+
         final HttpRequestInterceptor interceptor = new RequestAddCookies();
         interceptor.process(request, context);
 
@@ -396,6 +401,8 @@ public class TestRequestAddCookies {
         final Header[] headers2 = request.getHeaders(SM.COOKIE2);
         Assert.assertNotNull(headers2);
         Assert.assertEquals(0, headers2.length);
+
+        Mockito.verify(this.cookieStore, Mockito.times(1)).clearExpired(Mockito.<Date>any());
     }
 
     @Test
@@ -465,41 +472,4 @@ public class TestRequestAddCookies {
         Assert.assertEquals("name1=value; name2=value; name3=value", headers1[0].getValue());
     }
 
-    @Test
-    public void testAddSpecVersionHeader() throws Exception {
-        final HttpRequest request = new BasicHttpRequest("GET", "/");
-
-        this.cookieStore.clear();
-        final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value1");
-        cookie1.setVersion(0);
-        cookie1.setDomain("localhost.local");
-        cookie1.setPath("/");
-        this.cookieStore.addCookie(cookie1);
-        final BasicClientCookie cookie2 = new BasicClientCookie("name2", "value2");
-        cookie2.setVersion(0);
-        cookie2.setDomain("localhost.local");
-        cookie2.setPath("/");
-        this.cookieStore.addCookie(cookie2);
-
-        final HttpRoute route = new HttpRoute(this.target, null, false);
-
-        final HttpClientContext context = HttpClientContext.create();
-        context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, this.target);
-        context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
-        context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
-        context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
-
-        final HttpRequestInterceptor interceptor = new RequestAddCookies();
-        interceptor.process(request, context);
-
-        final Header[] headers1 = request.getHeaders(SM.COOKIE);
-        Assert.assertNotNull(headers1);
-        Assert.assertEquals(1, headers1.length);
-        Assert.assertEquals("name1=value1; name2=value2", headers1[0].getValue());
-        final Header[] headers2 = request.getHeaders(SM.COOKIE2);
-        Assert.assertNotNull(headers2);
-        Assert.assertEquals(1, headers2.length);
-        Assert.assertEquals("$Version=1", headers2[0].getValue());
-    }
-
 }
diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java
index 2a31d2a..6bc3d95 100644
--- a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java
+++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java
@@ -112,9 +112,9 @@ public class TestRequestAuthCache {
 
         final HttpRequestInterceptor interceptor = new RequestAuthCache();
         interceptor.process(request, context);
-        Assert.assertSame(this.authscheme1, this.targetState.getAuthScheme());
+        Assert.assertNotNull(this.targetState.getAuthScheme());
         Assert.assertSame(this.creds1, this.targetState.getCredentials());
-        Assert.assertSame(this.authscheme2, this.proxyState.getAuthScheme());
+        Assert.assertNotNull(this.proxyState.getAuthScheme());
         Assert.assertSame(this.creds2, this.proxyState.getCredentials());
     }
 
diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseContentEncoding.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseContentEncoding.java
index 796e142..07735df 100644
--- a/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseContentEncoding.java
+++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseContentEncoding.java
@@ -31,7 +31,8 @@ import org.apache.http.HttpException;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpResponseInterceptor;
 import org.apache.http.HttpVersion;
-import org.apache.http.client.entity.DeflateDecompressingEntity;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.DecompressingEntity;
 import org.apache.http.client.entity.GzipDecompressingEntity;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.message.BasicHttpResponse;
@@ -79,7 +80,7 @@ public class TestResponseContentEncoding {
         interceptor.process(response, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertNotNull(entity);
-        Assert.assertTrue(entity instanceof GzipDecompressingEntity);
+        Assert.assertTrue(entity instanceof DecompressingEntity);
     }
 
     @Test
@@ -109,7 +110,7 @@ public class TestResponseContentEncoding {
         interceptor.process(response, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertNotNull(entity);
-        Assert.assertTrue(entity instanceof GzipDecompressingEntity);
+        Assert.assertTrue(entity instanceof DecompressingEntity);
     }
 
     @Test
@@ -124,7 +125,7 @@ public class TestResponseContentEncoding {
         interceptor.process(response, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertNotNull(entity);
-        Assert.assertTrue(entity instanceof DeflateDecompressingEntity);
+        Assert.assertTrue(entity instanceof DecompressingEntity);
     }
 
     @Test
@@ -154,4 +155,25 @@ public class TestResponseContentEncoding {
         interceptor.process(response, context);
     }
 
+    @Test
+    public void testContentEncodingRequestParameter() throws Exception {
+        final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        final StringEntity original = new StringEntity("encoded stuff");
+        original.setContentEncoding("GZip");
+        response.setEntity(original);
+
+        final RequestConfig config = RequestConfig.custom()
+                .setDecompressionEnabled(false)
+                .build();
+
+        final HttpContext context = new BasicHttpContext();
+        context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
+
+        final HttpResponseInterceptor interceptor = new ResponseContentEncoding();
+        interceptor.process(response, context);
+        final HttpEntity entity = response.getEntity();
+        Assert.assertNotNull(entity);
+        Assert.assertFalse(entity instanceof GzipDecompressingEntity);
+    }
+
 }
diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseProcessCookies.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseProcessCookies.java
index 6a0bab7..30a7d0f 100644
--- a/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseProcessCookies.java
+++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseProcessCookies.java
@@ -37,7 +37,7 @@ import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.CookieSpec;
 import org.apache.http.cookie.SM;
 import org.apache.http.impl.client.BasicCookieStore;
-import org.apache.http.impl.cookie.BestMatchSpec;
+import org.apache.http.impl.cookie.DefaultCookieSpec;
 import org.apache.http.message.BasicHttpResponse;
 import org.junit.Assert;
 import org.junit.Before;
@@ -52,7 +52,7 @@ public class TestResponseProcessCookies {
     @Before
     public void setUp() throws Exception {
         this.cookieOrigin = new CookieOrigin("localhost", 80, "/", false);
-        this.cookieSpec = new BestMatchSpec();
+        this.cookieSpec = new DefaultCookieSpec();
         this.cookieStore = new BasicCookieStore();
     }
 
diff --git a/httpclient/src/test/java/org/apache/http/client/utils/TestDateUtils.java b/httpclient/src/test/java/org/apache/http/client/utils/TestDateUtils.java
index 1d6b213..06fa723 100644
--- a/httpclient/src/test/java/org/apache/http/client/utils/TestDateUtils.java
+++ b/httpclient/src/test/java/org/apache/http/client/utils/TestDateUtils.java
@@ -30,7 +30,6 @@ package org.apache.http.client.utils;
 import java.util.Calendar;
 import java.util.Date;
 
-import org.apache.http.impl.cookie.DateParseException;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -138,9 +137,4 @@ public class TestDateUtils {
         Assert.assertEquals("Fri, 14 Oct 2005 00:00:00 GMT", DateUtils.formatDate(date, DateUtils.PATTERN_RFC1123));
     }
 
-    @Test
-    public void testConstructor() {
-        new DateParseException();
-        new DateParseException("Oppsie");
-    }
 }
diff --git a/httpclient/src/test/java/org/apache/http/client/utils/TestHttpClientUtils.java b/httpclient/src/test/java/org/apache/http/client/utils/TestHttpClientUtils.java
index 7b054eb..b1fa88d 100644
--- a/httpclient/src/test/java/org/apache/http/client/utils/TestHttpClientUtils.java
+++ b/httpclient/src/test/java/org/apache/http/client/utils/TestHttpClientUtils.java
@@ -36,7 +36,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
 import org.junit.Test;
 import org.mockito.Mockito;
 
- at SuppressWarnings({"boxing"}) // test code
+ at SuppressWarnings("boxing") // test code
 public class TestHttpClientUtils {
 
     @Test
diff --git a/httpclient/src/test/java/org/apache/http/client/utils/TestRequestBuilder.java b/httpclient/src/test/java/org/apache/http/client/utils/TestRequestBuilder.java
new file mode 100644
index 0000000..d71c018
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/client/utils/TestRequestBuilder.java
@@ -0,0 +1,74 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.client.utils;
+
+
+import org.apache.http.Consts;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.message.BasicNameValuePair;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
+
+public class TestRequestBuilder {
+
+    @Test
+    public void testBuildGETwithUTF8() throws Exception {
+        assertBuild(Consts.UTF_8);
+    }
+
+    @Test
+    public void testBuildGETwithISO88591() throws Exception {
+        assertBuild(Consts.ISO_8859_1);
+    }
+
+    private void assertBuild(final Charset charset) throws Exception {
+        final RequestBuilder requestBuilder = RequestBuilder.create("GET").setCharset(charset);
+        requestBuilder.setUri("https://somehost.com/stuff");
+        requestBuilder.addParameters(createParameters());
+
+        final String encodedData1 = URLEncoder.encode("\"1\u00aa position\"", charset.displayName());
+        final String encodedData2 = URLEncoder.encode("Jos\u00e9 Abra\u00e3o", charset.displayName());
+
+        final String uriExpected = String.format("https://somehost.com/stuff?parameter1=value1&parameter2=%s&parameter3=%s", encodedData1, encodedData2);
+
+        final HttpUriRequest request = requestBuilder.build();
+        Assert.assertEquals(uriExpected, request.getURI().toString());
+    }
+
+    private NameValuePair[] createParameters() {
+        final NameValuePair parameters[] = new NameValuePair[3];
+        parameters[0] = new BasicNameValuePair("parameter1", "value1");
+        parameters[1] = new BasicNameValuePair("parameter2", "\"1\u00aa position\"");
+        parameters[2] = new BasicNameValuePair("parameter3", "Jos\u00e9 Abra\u00e3o");
+        return parameters;
+    }
+}
diff --git a/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java b/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java
deleted file mode 100644
index 6866b1c..0000000
--- a/httpclient/src/test/java/org/apache/http/client/utils/TestRfc3492Idn.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.http.client.utils;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class TestRfc3492Idn {
-
-    /**
-     * Some of the sample strings from RFC 3492
-     */
-    @Test
-    public void testDecode() throws Exception {
-        final Rfc3492Idn idn = new Rfc3492Idn();
-        // (A) Arabic
-        Assert.assertEquals("\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" +
-                     "\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F",
-                     idn.decode("egbpdaj6bu4bxfgehfvwxn"));
-
-        // (B) Chinese (simplified)
-        Assert.assertEquals("\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2D\u6587",
-                     idn.decode("ihqwcrb4cv8a8dqg056pqjye"));
-
-        // (I) Russian (Cyrillic)
-        Assert.assertEquals("\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E"+
-                     "\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440"+
-                     "\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A"+
-                     "\u0438",
-                     idn.decode("b1abfaaepdrnnbgefbaDotcwatmq2g4l"));
-
-        // (P) Maji<de>Koi<suru>5<byou><mae>
-        Assert.assertEquals("\u004D\u0061\u006A\u0069\u3067\u004B\u006F\u0069\u3059" +
-                     "\u308B\u0035\u79D2\u524D",
-                     idn.decode("MajiKoi5-783gue6qz075azm5e"));
-
-    }
-
-    @Test
-    public void testToUnicode() throws Exception {
-        final Rfc3492Idn idn = new Rfc3492Idn();
-        // (A) Arabic
-        Assert.assertEquals("\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" +
-                     "\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F",
-                     idn.toUnicode("xn--egbpdaj6bu4bxfgehfvwxn"));
-
-        // some real-world domains
-        Assert.assertEquals("www.z\u00fcrich.ch",
-                     idn.toUnicode("www.xn--zrich-kva.ch"));
-
-        Assert.assertEquals("www.g\u00e4ggelig\u00e4\u00e4l.ch",
-                     idn.toUnicode("www.xn--gggeligl-0zaga.ch"));
-    }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/client/utils/TestURIBuilder.java b/httpclient/src/test/java/org/apache/http/client/utils/TestURIBuilder.java
index 4d7bdfc..6ed9d7a 100644
--- a/httpclient/src/test/java/org/apache/http/client/utils/TestURIBuilder.java
+++ b/httpclient/src/test/java/org/apache/http/client/utils/TestURIBuilder.java
@@ -27,7 +27,14 @@
 package org.apache.http.client.utils;
 
 import java.net.URI;
-
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.http.Consts;
+import org.apache.http.NameValuePair;
+import org.apache.http.message.BasicNameValuePair;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -232,4 +239,57 @@ public class TestURIBuilder {
 
     }
 
+    @Test
+    public void testBuildAddParametersUTF8() throws Exception {
+        assertAddParameters(Consts.UTF_8);
+    }
+
+    @Test
+    public void testBuildAddParametersISO88591() throws Exception {
+        assertAddParameters(Consts.ISO_8859_1);
+    }
+
+    public void assertAddParameters(final Charset charset) throws Exception {
+        final URI uri = new URIBuilder("https://somehost.com/stuff")
+                .setCharset(charset)
+                .addParameters(createParameters()).build();
+
+        assertBuild(charset, uri);
+    }
+
+    @Test
+    public void testBuildSetParametersUTF8() throws Exception {
+        assertSetParameters(Consts.UTF_8);
+    }
+
+    @Test
+    public void testBuildSetParametersISO88591() throws Exception {
+        assertSetParameters(Consts.ISO_8859_1);
+    }
+
+    public void assertSetParameters(final Charset charset) throws Exception {
+        final URI uri = new URIBuilder("https://somehost.com/stuff")
+                .setCharset(charset)
+                .setParameters(createParameters()).build();
+
+        assertBuild(charset, uri);
+    }
+
+    public void assertBuild(final Charset charset, final URI uri) throws Exception {
+        final String encodedData1 = URLEncoder.encode("\"1\u00aa position\"", charset.displayName());
+        final String encodedData2 = URLEncoder.encode("Jos\u00e9 Abra\u00e3o", charset.displayName());
+
+        final String uriExpected = String.format("https://somehost.com/stuff?parameter1=value1&parameter2=%s&parameter3=%s", encodedData1, encodedData2);
+
+        Assert.assertEquals(uriExpected, uri.toString());
+    }
+
+    private List<NameValuePair> createParameters() {
+        final List<NameValuePair> parameters = new ArrayList<NameValuePair>();
+        parameters.add(new BasicNameValuePair("parameter1", "value1"));
+        parameters.add(new BasicNameValuePair("parameter2", "\"1\u00aa position\""));
+        parameters.add(new BasicNameValuePair("parameter3", "Jos\u00e9 Abra\u00e3o"));
+        return parameters;
+    }
+
 }
diff --git a/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java b/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java
index a0fb7eb..4d09cb5 100644
--- a/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java
+++ b/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java
@@ -30,6 +30,7 @@ import java.net.URI;
 import java.util.Arrays;
 
 import org.apache.http.HttpHost;
+import org.apache.http.conn.routing.HttpRoute;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -101,6 +102,34 @@ public class TestURIUtils {
     }
 
     @Test
+    public void testRewriteForRoute() throws Exception {
+
+        final HttpHost target1 = new HttpHost("foo", 80);
+        final HttpHost target2 = new HttpHost("foo", 443, "https");
+        final HttpHost proxy = new HttpHost("bar", 8888);
+
+        // Direct route
+        Assert.assertEquals(new URI("/test"), URIUtils
+                .rewriteURIForRoute(new URI("http://foo/test"), new HttpRoute(target1)));
+
+        // Direct route
+        Assert.assertEquals(new URI("/"), URIUtils
+                .rewriteURIForRoute(new URI(""), new HttpRoute(target1)));
+
+        // Via proxy
+        Assert.assertEquals(new URI("http://foo/test"), URIUtils
+                .rewriteURIForRoute(new URI("http://foo/test"), new HttpRoute(target1, proxy)));
+
+        // Via proxy
+        Assert.assertEquals(new URI("http://foo:80/test"), URIUtils
+                .rewriteURIForRoute(new URI("/test"), new HttpRoute(target1, proxy)));
+
+        // Via proxy tunnel
+        Assert.assertEquals(new URI("/test"), URIUtils
+                .rewriteURIForRoute(new URI("https://foo:443/test"), new HttpRoute(target2, null, proxy, true)));
+    }
+
+    @Test
     public void testNormalization() {
         Assert.assertEquals("example://a/b/c/%7Bfoo%7D", URIUtils.resolve(this.baseURI, "eXAMPLE://a/./b/../b/%63/%7bfoo%7d").toString());
         Assert.assertEquals("http://www.example.com/%3C", URIUtils.resolve(this.baseURI, "http://www.example.com/%3c").toString());
@@ -231,6 +260,8 @@ public class TestURIUtils {
                 URIUtils.extractHost(new URI("http://localhost:;sessionid=stuff/abcd")));
         Assert.assertEquals(null,
                 URIUtils.extractHost(new URI("http://:80/robots.txt")));
+        Assert.assertEquals(null,
+                URIUtils.extractHost(new URI("http://some%20domain:80/robots.txt")));
     }
 
     @Test
diff --git a/httpclient/src/test/java/org/apache/http/client/utils/TestURLEncodedUtils.java b/httpclient/src/test/java/org/apache/http/client/utils/TestURLEncodedUtils.java
index 6e7d136..60d1eaf 100644
--- a/httpclient/src/test/java/org/apache/http/client/utils/TestURLEncodedUtils.java
+++ b/httpclient/src/test/java/org/apache/http/client/utils/TestURLEncodedUtils.java
@@ -192,7 +192,7 @@ public class TestURLEncodedUtils {
     };
 
     private static String constructString(final int [] unicodeChars) {
-        final StringBuffer buffer = new StringBuffer();
+        final StringBuilder buffer = new StringBuilder();
         if (unicodeChars != null) {
             for (final int unicodeChar : unicodeChars) {
                 buffer.append((char)unicodeChar);
diff --git a/httpclient/src/test/java/org/apache/http/conn/TestExceptions.java b/httpclient/src/test/java/org/apache/http/conn/TestExceptions.java
index 14eba94..7b13e65 100644
--- a/httpclient/src/test/java/org/apache/http/conn/TestExceptions.java
+++ b/httpclient/src/test/java/org/apache/http/conn/TestExceptions.java
@@ -119,7 +119,7 @@ public class TestExceptions {
     public void testConnectionPoolTimeoutException() {
         final String msg = "sample exception message";
         ConnectionPoolTimeoutException cptx = new ConnectionPoolTimeoutException(msg);
-        Assert.assertFalse(cptx.toString().indexOf(msg) < 0);
+        Assert.assertFalse(!cptx.toString().contains(msg));
         Assert.assertSame(msg, cptx.getMessage());
 
         cptx = new ConnectionPoolTimeoutException();
diff --git a/httpclient/src/test/java/org/apache/http/conn/routing/TestHttpRoute.java b/httpclient/src/test/java/org/apache/http/conn/routing/TestHttpRoute.java
index a429645..e066303 100644
--- a/httpclient/src/test/java/org/apache/http/conn/routing/TestHttpRoute.java
+++ b/httpclient/src/test/java/org/apache/http/conn/routing/TestHttpRoute.java
@@ -45,7 +45,7 @@ public class TestHttpRoute {
 
     // a selection of constants for generating routes
     public final static
-        HttpHost TARGET1 = new HttpHost("target1.test.invalid");
+        HttpHost TARGET1 = new HttpHost("target1.test.invalid", 80);
     public final static
         HttpHost TARGET2 = new HttpHost("target2.test.invalid", 8080);
     // It is not necessary to have extra targets for https.
@@ -111,15 +111,15 @@ public class TestHttpRoute {
 
         final String routestr = route.toString();
         Assert.assertTrue("missing target in toString",
-                   routestr.indexOf(TARGET1.getHostName()) >= 0);
+                routestr.contains(TARGET1.getHostName()));
         Assert.assertTrue("missing local address in toString",
-                   routestr.indexOf(LOCAL41.toString()) >= 0);
+                routestr.contains(LOCAL41.toString()));
         Assert.assertTrue("missing proxy 1 in toString",
-                   routestr.indexOf(PROXY1.getHostName()) >= 0);
+                routestr.contains(PROXY1.getHostName()));
         Assert.assertTrue("missing proxy 2 in toString",
-                   routestr.indexOf(PROXY2.getHostName()) >= 0);
+                routestr.contains(PROXY2.getHostName()));
         Assert.assertTrue("missing proxy 3 in toString",
-                   routestr.indexOf(PROXY3.getHostName()) >= 0);
+                routestr.contains(PROXY3.getHostName()));
     }
 
     @Test
@@ -224,6 +224,7 @@ public class TestHttpRoute {
                      8, routestrings.size());
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void testInvalidArguments() {
         final HttpHost[] chain1 = { PROXY1 };
@@ -510,6 +511,7 @@ public class TestHttpRoute {
         Assert.assertEquals("bad convenience route 3/secure", route, should);
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void testCstr4() {
         // test convenience constructor with 4 arguments
@@ -575,4 +577,48 @@ public class TestHttpRoute {
         Assert.assertEquals("route was modified", route3, route1);
     }
 
+    @Test
+    public void testTargetHostNormalizationHttp() {
+        final HttpHost target = new HttpHost("somehost", -1, "http");
+        final HttpRoute route = new HttpRoute(target);
+        final HttpHost targetHost = route.getTargetHost();
+        Assert.assertEquals("somehost", targetHost.getHostName());
+        Assert.assertEquals(80, targetHost.getPort());
+        Assert.assertEquals("http", targetHost.getSchemeName());
+        Assert.assertEquals(null, targetHost.getAddress());
+    }
+
+    @Test
+    public void testTargetHostNormalizationHttps() {
+        final HttpHost target = new HttpHost("somehost", -1, "https");
+        final HttpRoute route = new HttpRoute(target);
+        final HttpHost targetHost = route.getTargetHost();
+        Assert.assertEquals("somehost", targetHost.getHostName());
+        Assert.assertEquals(443, targetHost.getPort());
+        Assert.assertEquals("https", targetHost.getSchemeName());
+        Assert.assertEquals(null, targetHost.getAddress());
+    }
+
+    @Test
+    public void testTargetHostNormalizationUnknownPorotocol() {
+        final HttpHost target = new HttpHost("somehost", -1, "blah");
+        final HttpRoute route = new HttpRoute(target);
+        final HttpHost targetHost = route.getTargetHost();
+        Assert.assertEquals("somehost", targetHost.getHostName());
+        Assert.assertEquals(-1, targetHost.getPort());
+        Assert.assertEquals("blah", targetHost.getSchemeName());
+        Assert.assertEquals(null, targetHost.getAddress());
+    }
+
+    @Test
+    public void testTargetHostNormalizationAddress() throws Exception {
+        final InetAddress address = InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
+        final HttpHost target = new HttpHost(address, -1, "http");
+        final HttpRoute route = new HttpRoute(target);
+        final HttpHost targetHost = route.getTargetHost();
+        Assert.assertEquals(80, targetHost.getPort());
+        Assert.assertEquals("http", targetHost.getSchemeName());
+        Assert.assertEquals(address, targetHost.getAddress());
+    }
+
 }
diff --git a/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteDirector.java b/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteDirector.java
index e0d356f..802ab95 100644
--- a/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteDirector.java
+++ b/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteDirector.java
@@ -42,7 +42,7 @@ public class TestRouteDirector {
 
     // a selection of constants for generating routes
     public final static
-        HttpHost TARGET1 = new HttpHost("target1.test.invalid");
+        HttpHost TARGET1 = new HttpHost("target1.test.invalid", 80);
     public final static
         HttpHost TARGET2 = new HttpHost("target2.test.invalid", 8080);
     // It is not necessary to have extra targets for https.
@@ -50,7 +50,7 @@ public class TestRouteDirector {
     // for routes, they will not be determined from the scheme.
 
     public final static
-        HttpHost PROXY1 = new HttpHost("proxy1.test.invalid");
+        HttpHost PROXY1 = new HttpHost("proxy1.test.invalid", 80);
     public final static
         HttpHost PROXY2 = new HttpHost("proxy2.test.invalid", 1080);
     public final static
diff --git a/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteTracker.java b/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteTracker.java
index c9c0172..4e87f85 100644
--- a/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteTracker.java
+++ b/httpclient/src/test/java/org/apache/http/conn/routing/TestRouteTracker.java
@@ -40,12 +40,12 @@ import org.junit.Test;
 /**
  * Tests for {@link RouteTracker}.
  */
- at SuppressWarnings({"boxing"}) // test code
+ at SuppressWarnings("boxing") // test code
 public class TestRouteTracker {
 
     // a selection of constants for generating routes
     public final static
-        HttpHost TARGET1 = new HttpHost("target1.test.invalid");
+        HttpHost TARGET1 = new HttpHost("target1.test.invalid", 80);
     public final static
         HttpHost TARGET2 = new HttpHost("target2.test.invalid", 8080);
     // It is not necessary to have extra targets for https.
@@ -53,7 +53,7 @@ public class TestRouteTracker {
     // for routes, they will not be determined from the scheme.
 
     public final static
-        HttpHost PROXY1 = new HttpHost("proxy1.test.invalid");
+        HttpHost PROXY1 = new HttpHost("proxy1.test.invalid", 80);
     public final static
         HttpHost PROXY2 = new HttpHost("proxy2.test.invalid", 1080);
     public final static
@@ -82,6 +82,7 @@ public class TestRouteTracker {
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void testCstrTargetLocal() {
 
@@ -122,6 +123,7 @@ public class TestRouteTracker {
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void testCstrRoute() {
 
@@ -582,7 +584,7 @@ public class TestRouteTracker {
      * @param rd        the director to check with
      * @param steps     the step count for this invocation
      *
-     * @return  <code>true</code> iff the route is complete
+     * @return  {@code true} iff the route is complete
      */
     public final static boolean checkVia(final RouteTracker rt, final HttpRoute r,
                                          final HttpRouteDirector rd, final int steps) {
@@ -686,11 +688,11 @@ public class TestRouteTracker {
 
 
     /**
-     * Checks the output of <code>toString</code>.
+     * Checks the output of {@code toString}.
      *
      * @param rt        the tracker for which to check the output
      *
-     * @return  the result of <code>rt.toString()</code>
+     * @return  the result of {@code rt.toString()}
      */
     public final static String checkToString(final RouteTracker rt) {
         if (rt == null) {
@@ -702,13 +704,13 @@ public class TestRouteTracker {
         if (rt.getLocalAddress() != null) {
             final String las = rt.getLocalAddress().toString();
             Assert.assertFalse("no local address in toString(): " + rts,
-                        rts.indexOf(las) < 0);
+                    !rts.contains(las));
         }
 
         for (int i=0; i<rt.getHopCount(); i++) {
             final String hts = rt.getHopTarget(i).toString();
             Assert.assertFalse("hop "+i+" ("+hts+") missing in toString(): " + rts,
-                        rts.indexOf(hts) < 0);
+                    !rts.contains(hts));
         }
 
         return rts;
diff --git a/httpclient/src/test/java/org/apache/http/conn/ssl/CertificatesToPlayWith.java b/httpclient/src/test/java/org/apache/http/conn/ssl/CertificatesToPlayWith.java
index 4b3156d..4b9d1b9 100644
--- a/httpclient/src/test/java/org/apache/http/conn/ssl/CertificatesToPlayWith.java
+++ b/httpclient/src/test/java/org/apache/http/conn/ssl/CertificatesToPlayWith.java
@@ -29,13 +29,14 @@ package org.apache.http.conn.ssl;
 
 /**
  * Some X509 certificates to test against.
- * <p/>
+ * <p>
  * Note:  some of these certificates have Japanese Kanji in the "subjectAlt"
  * field (UTF8).  Not sure how realistic that is since international characters
  * in DNS names usually get translated into ASCII using "xn--" style DNS
  * entries.  "xn--i8s592g.co.jp" is what FireFox actually uses when trying to
  * find &#x82b1;&#x5b50;.co.jp.  So would the CN in the certificate contain
  * "xn--i8s592g.co.jp" in ASCII, or "&#x82b1;&#x5b50;.co.jp" in UTF8?  (Both?)
+ * </p>
  *
  * @since 11-Dec-2006
  */
diff --git a/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java b/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java
new file mode 100644
index 0000000..b809bcb
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java
@@ -0,0 +1,300 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+
+import javax.net.ssl.SSLException;
+
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link org.apache.http.conn.ssl.DefaultHostnameVerifier}.
+ */
+public class TestDefaultHostnameVerifier {
+
+    private DefaultHostnameVerifier impl;
+    private PublicSuffixMatcher publicSuffixMatcher;
+    private DefaultHostnameVerifier implWithPublicSuffixCheck;
+
+    @Before
+    public void setup() {
+        impl = new DefaultHostnameVerifier();
+        publicSuffixMatcher = new PublicSuffixMatcher(Arrays.asList("com", "co.jp", "gov.uk"), null);
+        implWithPublicSuffixCheck = new DefaultHostnameVerifier(publicSuffixMatcher);
+    }
+
+    @Test
+    public void testVerify() throws Exception {
+        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        InputStream in;
+        X509Certificate x509;
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+
+        impl.verify("foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        exceptionPlease(impl, "bar.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        impl.verify("bar.com", x509);
+        exceptionPlease(impl, "a.bar.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        impl.verify("bar.com", x509);
+        exceptionPlease(impl, "a.bar.com", x509);
+
+        /*
+           Java isn't extracting international subjectAlts properly.  (Or
+           OpenSSL isn't storing them properly).
+        */
+        // DEFAULT.verify("\u82b1\u5b50.co.jp", x509 );
+        // impl.verify("\u82b1\u5b50.co.jp", x509 );
+        exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_NO_CNS_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_NO_CNS_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_THREE_CNS_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        exceptionPlease(impl, "bar.com", x509);
+        exceptionPlease(impl, "a.bar.com", x509);
+        impl.verify("\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        impl.verify("www.foo.com", x509);
+        impl.verify("\u82b1\u5b50.foo.com", x509);
+        exceptionPlease(impl, "a.b.foo.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_CO_JP);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        // Silly test because no-one would ever be able to lookup an IP address
+        // using "*.co.jp".
+        impl.verify("*.co.jp", x509);
+        impl.verify("foo.co.jp", x509);
+        impl.verify("\u82b1\u5b50.co.jp", x509);
+
+        exceptionPlease(implWithPublicSuffixCheck, "foo.co.jp", x509);
+        exceptionPlease(implWithPublicSuffixCheck, "\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        // try the foo.com variations
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "www.foo.com", x509);
+        exceptionPlease(impl, "\u82b1\u5b50.foo.com", x509);
+        exceptionPlease(impl, "a.b.foo.com", x509);
+        // try the bar.com variations
+        exceptionPlease(impl, "bar.com", x509);
+        impl.verify("www.bar.com", x509);
+        impl.verify("\u82b1\u5b50.bar.com", x509);
+        exceptionPlease(impl, "a.b.bar.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_VALUE_AVA);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("repository.infonotary.com", x509);
+    }
+
+    @Test
+    public void testSubjectAlt() throws Exception {
+        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        final InputStream in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_SUBJECT_ALT);
+        final X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
+
+        Assert.assertEquals("CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=CH",
+                x509.getSubjectDN().getName());
+
+        impl.verify("localhost.localdomain", x509);
+        impl.verify("127.0.0.1", x509);
+
+        try {
+            impl.verify("localhost", x509);
+            Assert.fail("SSLException should have been thrown");
+        } catch (final SSLException ex) {
+            // expected
+        }
+        try {
+            impl.verify("local.host", x509);
+            Assert.fail("SSLException should have been thrown");
+        } catch (final SSLException ex) {
+            // expected
+        }
+        try {
+            impl.verify("127.0.0.2", x509);
+            Assert.fail("SSLException should have been thrown");
+        } catch (final SSLException ex) {
+            // expected
+        }
+    }
+
+    public void exceptionPlease(final DefaultHostnameVerifier hv, final String host,
+                                final X509Certificate x509) {
+        try {
+            hv.verify(host, x509);
+            Assert.fail("HostnameVerifier shouldn't allow [" + host + "]");
+        }
+        catch(final SSLException e) {
+            // whew!  we're okay!
+        }
+    }
+
+    @Test
+    public void testDomainRootMatching() {
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchDomainRoot("a.b.c", null));
+        Assert.assertTrue(DefaultHostnameVerifier.matchDomainRoot("a.b.c", "a.b.c"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchDomainRoot("aa.b.c", "a.b.c"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchDomainRoot("a.b.c", "aa.b.c"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchDomainRoot("a.a.b.c", "a.b.c"));
+    }
+
+    @Test
+    public void testIdentityMatching() {
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.b.c"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.b.c"));
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.b.c", "*.b.c"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.b.c", "*.b.c")); // subdomain not OK
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.gov.uk", "*.gov.uk", publicSuffixMatcher));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.gov.uk", "*.gov.uk", publicSuffixMatcher));  // Bad 2TLD
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "*.a.gov.uk", publicSuffixMatcher));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "*.a.gov.uk", publicSuffixMatcher));
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "*.gov.uk", publicSuffixMatcher));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "*.gov.uk", publicSuffixMatcher));  // BBad 2TLD/no subdomain allowed
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.gov.com", "*.gov.com", publicSuffixMatcher));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.gov.com", "*.gov.com", publicSuffixMatcher));
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.gov.com", "*.gov.com", publicSuffixMatcher));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.com", "*.gov.com", publicSuffixMatcher)); // no subdomain allowed
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.gov.uk", "a*.gov.uk", publicSuffixMatcher));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.gov.uk", "a*.gov.uk", publicSuffixMatcher)); // Bad 2TLD
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "a*.gov.uk", publicSuffixMatcher)); // Bad 2TLD
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "a*.gov.uk", publicSuffixMatcher)); // Bad 2TLD/no subdomain allowed
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.b.*"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.b.*"));
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.*.c"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.*.c"));
+    }
+
+    @Test
+    public void testHTTPCLIENT_1097() {
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "a*.b.c"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "a*.b.c"));
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.a.b.c", "a*.b.c"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.a.b.c", "a*.b.c"));
+    }
+
+    @Test
+    public void testHTTPCLIENT_1255() {
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("mail.a.b.c.com", "m*.a.b.c.com"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("mail.a.b.c.com", "m*.a.b.c.com"));
+    }
+
+    @Test // Check compressed IPv6 hostname matching
+    public void testHTTPCLIENT_1316() throws Exception{
+        final String host1 = "2001:0db8:aaaa:bbbb:cccc:0:0:0001";
+        DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList("2001:0db8:aaaa:bbbb:cccc:0:0:0001"));
+        DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::1"));
+        try {
+            DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::10"));
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
+        final String host2 = "2001:0db8:aaaa:bbbb:cccc::1";
+        DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList("2001:0db8:aaaa:bbbb:cccc:0:0:0001"));
+        DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::1"));
+        try {
+            DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::10"));
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
+    }
+
+    @Test
+    public void testExtractCN() throws Exception {
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=blah, ou=blah, o=blah"));
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=blah, cn=yada, cn=booh"));
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("c = pampa ,  cn  =    blah    , ou = blah , o = blah"));
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=\"blah\", ou=blah, o=blah"));
+        Assert.assertEquals("blah  blah", DefaultHostnameVerifier.extractCN("cn=\"blah  blah\", ou=blah, o=blah"));
+        Assert.assertEquals("blah, blah", DefaultHostnameVerifier.extractCN("cn=\"blah, blah\", ou=blah, o=blah"));
+        Assert.assertEquals("blah, blah", DefaultHostnameVerifier.extractCN("cn=blah\\, blah, ou=blah, o=blah"));
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("c = cn=uuh, cn=blah, ou=blah, o=blah"));
+        try {
+            DefaultHostnameVerifier.extractCN("blah,blah");
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
+        try {
+            DefaultHostnameVerifier.extractCN("cn,o=blah");
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
+    }
+
+}
diff --git a/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java b/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java
index b6c63ed..657f8df 100644
--- a/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java
+++ b/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java
@@ -39,8 +39,9 @@ import org.junit.Assert;
 import org.junit.Test;
 
 /**
- * Unit tests for {@link X509HostnameVerifier}.
+ * Unit tests for deprecated {@link X509HostnameVerifier} implementations.
  */
+ at Deprecated
 public class TestHostnameVerifier {
 
     @Test
@@ -73,8 +74,8 @@ public class TestHostnameVerifier {
 
         in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR);
         x509 = (X509Certificate) cf.generateCertificate(in);
-        DEFAULT.verify("foo.com", x509);
-        STRICT.verify("foo.com", x509);
+        exceptionPlease(DEFAULT, "foo.com", x509);
+        exceptionPlease(STRICT, "foo.com", x509);
         exceptionPlease(DEFAULT, "a.foo.com", x509);
         exceptionPlease(STRICT, "a.foo.com", x509);
         DEFAULT.verify("bar.com", x509);
@@ -84,8 +85,8 @@ public class TestHostnameVerifier {
 
         in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR_HANAKO);
         x509 = (X509Certificate) cf.generateCertificate(in);
-        DEFAULT.verify("foo.com", x509);
-        STRICT.verify("foo.com", x509);
+        exceptionPlease(DEFAULT, "foo.com", x509);
+        exceptionPlease(STRICT, "foo.com", x509);
         exceptionPlease(DEFAULT, "a.foo.com", x509);
         exceptionPlease(STRICT, "a.foo.com", x509);
         DEFAULT.verify("bar.com", x509);
@@ -158,11 +159,11 @@ public class TestHostnameVerifier {
         // try the foo.com variations
         exceptionPlease(DEFAULT, "foo.com", x509);
         exceptionPlease(STRICT, "foo.com", x509);
-        DEFAULT.verify("www.foo.com", x509);
-        STRICT.verify("www.foo.com", x509);
-        DEFAULT.verify("\u82b1\u5b50.foo.com", x509);
-        STRICT.verify("\u82b1\u5b50.foo.com", x509);
-        DEFAULT.verify("a.b.foo.com", x509);
+        exceptionPlease(DEFAULT, "www.foo.com", x509);
+        exceptionPlease(STRICT, "www.foo.com", x509);
+        exceptionPlease(DEFAULT, "\u82b1\u5b50.foo.com", x509);
+        exceptionPlease(STRICT, "\u82b1\u5b50.foo.com", x509);
+        exceptionPlease(DEFAULT, "a.b.foo.com", x509);
         exceptionPlease(STRICT, "a.b.foo.com", x509);
         // try the bar.com variations
         exceptionPlease(DEFAULT, "bar.com", x509);
@@ -173,19 +174,6 @@ public class TestHostnameVerifier {
         STRICT.verify("\u82b1\u5b50.bar.com", x509);
         DEFAULT.verify("a.b.bar.com", x509);
         exceptionPlease(STRICT, "a.b.bar.com", x509);
-        // try the \u82b1\u5b50.co.jp variations
-        /*
-           Java isn't extracting international subjectAlts properly.  (Or
-           OpenSSL isn't storing them properly).
-        */
-        //exceptionPlease( DEFAULT, "\u82b1\u5b50.co.jp", x509 );
-        //exceptionPlease( STRICT, "\u82b1\u5b50.co.jp", x509 );
-        //DEFAULT.verify("www.\u82b1\u5b50.co.jp", x509 );
-        //STRICT.verify("www.\u82b1\u5b50.co.jp", x509 );
-        //DEFAULT.verify("\u82b1\u5b50.\u82b1\u5b50.co.jp", x509 );
-        //STRICT.verify("\u82b1\u5b50.\u82b1\u5b50.co.jp", x509 );
-        //DEFAULT.verify("a.b.\u82b1\u5b50.co.jp", x509 );
-        //exceptionPlease(STRICT,"a.b.\u82b1\u5b50.co.jp", x509 );
 
         in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_VALUE_AVA);
         x509 = (X509Certificate) cf.generateCertificate(in);
@@ -200,16 +188,21 @@ public class TestHostnameVerifier {
         final InputStream in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_SUBJECT_ALT);
         final X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
 
-        final X509HostnameVerifier verifier = SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
+        final X509HostnameVerifier verifier = BrowserCompatHostnameVerifier.INSTANCE;
 
         Assert.assertEquals("CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=CH",
                 x509.getSubjectDN().getName());
 
-        verifier.verify("localhost", x509);
         verifier.verify("localhost.localdomain", x509);
         verifier.verify("127.0.0.1", x509);
 
         try {
+            verifier.verify("localhost", x509);
+            Assert.fail("SSLException should have been thrown");
+        } catch (final SSLException ex) {
+            // expected
+        }
+        try {
             verifier.verify("local.host", x509);
             Assert.fail("SSLException should have been thrown");
         } catch (final SSLException ex) {
@@ -288,7 +281,6 @@ public class TestHostnameVerifier {
 
         checkMatching(bhv, "s.a.gov.uk", cns, alt, false); // OK
         checkMatching(shv, "s.a.gov.uk", cns, alt, true); // Bad 2TLD/no subdomain allowed
-
         alt = new String []{"*.gov.com"};
         checkMatching(bhv, "a.gov.com", cns, alt, false); // OK, gov not 2TLD here
         checkMatching(shv, "a.gov.com", cns, alt, false); // OK, gov not 2TLD here
@@ -296,7 +288,7 @@ public class TestHostnameVerifier {
         checkMatching(bhv, "s.a.gov.com", cns, alt, false); // OK, gov not 2TLD here
         checkMatching(shv, "s.a.gov.com", cns, alt, true); // no subdomain allowed
 
-        cns = new String []{"a*.gov.uk"}; // 2TLD check applies to wildcards
+        alt = new String []{"a*.gov.uk"}; // 2TLD check applies to wildcards
         checkMatching(bhv, "a.gov.uk", cns, alt, false); // OK
         checkMatching(shv, "a.gov.uk", cns, alt, true); // Bad 2TLD
 
@@ -321,6 +313,7 @@ public class TestHostnameVerifier {
         // TODO need some more samples
     }
 
+
     @Test
     public void testHTTPCLIENT_1097() {
         String cns[];
@@ -347,27 +340,4 @@ public class TestHostnameVerifier {
         checkMatching(shv, "mail.a.b.c.com", cns, alt, false); // OK
     }
 
-    @Test
-    public void testExtractCN() throws Exception {
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractVerifier.extractCNs("cn=blah, ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah", "yada", "booh"}, AbstractVerifier.extractCNs("cn=blah, cn=yada, cn=booh"));
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractVerifier.extractCNs("c = pampa ,  cn  =    blah    , ou = blah , o = blah"));
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractVerifier.extractCNs("cn=\"blah\", ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah  blah"}, AbstractVerifier.extractCNs("cn=\"blah  blah\", ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah, blah"}, AbstractVerifier.extractCNs("cn=\"blah, blah\", ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah, blah"}, AbstractVerifier.extractCNs("cn=blah\\, blah, ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractVerifier.extractCNs("c = cn=uuh, cn=blah, ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {""}, AbstractVerifier.extractCNs("cn=   , ou=blah, o=blah"));
-    }
-
-    @Test(expected = SSLException.class)
-    public void testExtractCNInvalid1() throws Exception {
-        AbstractVerifier.extractCNs("blah,blah");
-    }
-
-    @Test(expected = SSLException.class)
-    public void testExtractCNInvalid2() throws Exception {
-        AbstractVerifier.extractCNs("cn,o=blah");
-    }
-
 }
diff --git a/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java b/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java
deleted file mode 100644
index 976223d..0000000
--- a/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.http.conn.ssl;
-
-import java.io.InputStream;
-import java.net.URL;
-import java.security.KeyStore;
-import java.security.UnrecoverableKeyException;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link org.apache.http.conn.ssl.SSLContextBuilder}.
- */
-public class TestSSLContextBuilder {
-
-    private static KeyStore load(final String res, final char[] passwd) throws Exception {
-        final KeyStore keystore  = KeyStore.getInstance("jks");
-        final ClassLoader cl = TestSSLContextBuilder.class.getClassLoader();
-        final URL url = cl.getResource(res);
-        final InputStream instream = url.openStream();
-        try {
-            keystore.load(instream, passwd);
-        } finally {
-            instream.close();
-        }
-        return keystore;
-    }
-
-    @Test
-    public void testBuildDefault() throws Exception {
-        new SSLContextBuilder().build();
-    }
-
-    @Test
-    public void testBuildAllNull() throws Exception {
-        new SSLContextBuilder()
-                .useProtocol(null)
-                .setSecureRandom(null)
-                .loadTrustMaterial(null)
-                .loadKeyMaterial(null, null)
-                .build();
-    }
-
-    @Test
-    public void testLoadTrustMultipleMaterial() throws Exception {
-        final KeyStore truststore1 = load("hc-test-1.truststore", "nopassword".toCharArray());
-        final KeyStore truststore2 = load("hc-test-2.truststore", "nopassword".toCharArray());
-        new SSLContextBuilder()
-                .loadTrustMaterial(truststore1)
-                .loadTrustMaterial(truststore2)
-                .build();
-    }
-
-    @Test
-    public void testKeyWithAlternatePassword() throws Exception {
-        final KeyStore keystore = load("test-keypasswd.keystore", "nopassword".toCharArray());
-        final String keyPassword = "password";
-        new SSLContextBuilder()
-                .loadKeyMaterial(keystore, keyPassword.toCharArray())
-                .loadTrustMaterial(keystore)
-                .build();
-    }
-
-    @Test(expected=UnrecoverableKeyException.class)
-    public void testKeyWithAlternatePasswordInvalid() throws Exception {
-        final KeyStore keystore = load("test-keypasswd.keystore", "nopassword".toCharArray());
-        final String keyPassword = "!password";
-        new SSLContextBuilder()
-                .loadKeyMaterial(keystore, keyPassword != null ? keyPassword.toCharArray() : null)
-                .loadTrustMaterial(keystore)
-                .build();
-    }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java b/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
index 9b2b831..8272ac4 100644
--- a/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
+++ b/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
@@ -28,75 +28,54 @@
 package org.apache.http.conn.ssl;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.InetSocketAddress;
 import java.net.Socket;
-import java.net.URL;
-import java.security.KeyStore;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
-import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
+import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLServerSocket;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
 
 import org.apache.http.HttpHost;
+import org.apache.http.impl.bootstrap.HttpServer;
+import org.apache.http.impl.bootstrap.SSLServerSetupHandler;
+import org.apache.http.impl.bootstrap.ServerBootstrap;
 import org.apache.http.localserver.LocalServerTestBase;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.SSLTestContexts;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.ssl.SSLContexts;
+import org.junit.After;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * Unit tests for {@link SSLConnectionSocketFactory}.
  */
-public class TestSSLSocketFactory extends LocalServerTestBase {
+public class TestSSLSocketFactory {
 
-    private KeyStore keystore;
+    private HttpServer server;
 
-    @Before
-    public void setUp() throws Exception {
-        keystore  = KeyStore.getInstance("jks");
-        final ClassLoader cl = getClass().getClassLoader();
-        final URL url = cl.getResource("hc-test.keystore");
-        final InputStream instream = url.openStream();
-        try {
-            keystore.load(instream, "nopassword".toCharArray());
-        } finally {
-            instream.close();
+    @After
+    public void shutDown() throws Exception {
+        if (this.server != null) {
+            this.server.shutdown(10, TimeUnit.SECONDS);
         }
     }
 
-    @Override
-    protected HttpHost getServerHttp() {
-        final InetSocketAddress address = this.localServer.getServiceAddress();
-        return new HttpHost(
-                address.getHostName(),
-                address.getPort(),
-                "https");
-    }
-
-    static class TestX509HostnameVerifier implements X509HostnameVerifier {
+    static class TestX509HostnameVerifier implements HostnameVerifier {
 
         private boolean fired = false;
 
+        @Override
         public boolean verify(final String host, final SSLSession session) {
-            return true;
-        }
-
-        public void verify(final String host, final SSLSocket ssl) throws IOException {
             this.fired = true;
-        }
-
-        public void verify(final String host, final String[] cns, final String[] subjectAlts) throws SSLException {
-        }
-
-        public void verify(final String host, final X509Certificate cert) throws SSLException {
+            return true;
         }
 
         public boolean isFired() {
@@ -107,177 +86,149 @@ public class TestSSLSocketFactory extends LocalServerTestBase {
 
     @Test
     public void testBasicSSL() throws Exception {
-        final SSLContext serverSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray())
-                .build();
-        final SSLContext clientSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .build();
-
-        this.localServer = new LocalTestServer(serverSSLContext);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-
-        final HttpHost host = new HttpHost("localhost", 443, "https");
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .create();
+        this.server.start();
+
         final HttpContext context = new BasicHttpContext();
         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
-                clientSSLContext, hostVerifier);
+                SSLTestContexts.createClientSSLContext(), hostVerifier);
         final Socket socket = socketFactory.createSocket(context);
-        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
-        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress, null, context);
-        final SSLSession sslsession = sslSocket.getSession();
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+        try {
+            final SSLSession sslsession = sslSocket.getSession();
 
-        Assert.assertNotNull(sslsession);
-        Assert.assertTrue(hostVerifier.isFired());
+            Assert.assertNotNull(sslsession);
+            Assert.assertTrue(hostVerifier.isFired());
+        } finally {
+            sslSocket.close();
+        }
     }
 
     @Test
-    public void testClientAuthSSL() throws Exception {
-        final SSLContext serverSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray())
-                .build();
-        final SSLContext clientSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray())
-                .build();
-
-        this.localServer = new LocalTestServer(serverSSLContext, true);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-
-        final HttpHost host = new HttpHost("localhost", 443, "https");
+    public void testBasicDefaultHostnameVerifier() throws Exception {
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .create();
+        this.server.start();
+
         final HttpContext context = new BasicHttpContext();
-        final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
-        final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(clientSSLContext, hostVerifier);
+        final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
+                SSLTestContexts.createClientSSLContext(), SSLConnectionSocketFactory.getDefaultHostnameVerifier());
         final Socket socket = socketFactory.createSocket(context);
-        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
-        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress, null, context);
-        final SSLSession sslsession = sslSocket.getSession();
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+        try {
+            final SSLSession sslsession = sslSocket.getSession();
 
-        Assert.assertNotNull(sslsession);
-        Assert.assertTrue(hostVerifier.isFired());
+            Assert.assertNotNull(sslsession);
+        } finally {
+            sslSocket.close();
+        }
     }
 
-    @Test(expected=IOException.class)
-    public void testClientAuthSSLFailure() throws Exception {
-        final SSLContext serverSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray())
-                .build();
-        final SSLContext clientSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .build();
-
-        this.localServer = new LocalTestServer(serverSSLContext, true);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-
-        final HttpHost host = new HttpHost("localhost", 443, "https");
+    @Test
+    public void testClientAuthSSL() throws Exception {
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .create();
+        this.server.start();
+
         final HttpContext context = new BasicHttpContext();
         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
-        final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(clientSSLContext, hostVerifier);
+        final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
+                SSLTestContexts.createClientSSLContext(), hostVerifier);
         final Socket socket = socketFactory.createSocket(context);
-        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
-        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress, null, context);
-        final SSLSession sslsession = sslSocket.getSession();
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+        try {
+            final SSLSession sslsession = sslSocket.getSession();
 
-        Assert.assertNotNull(sslsession);
-        Assert.assertTrue(hostVerifier.isFired());
+            Assert.assertNotNull(sslsession);
+            Assert.assertTrue(hostVerifier.isFired());
+        } finally {
+            sslSocket.close();
+        }
     }
 
-    @Test
-    public void testClientAuthSSLAliasChoice() throws Exception {
-        final PrivateKeyStrategy aliasStrategy = new PrivateKeyStrategy() {
-
-            public String chooseAlias(
-                    final Map<String, PrivateKeyDetails> aliases, final Socket socket) {
-                Assert.assertEquals(2, aliases.size());
-                Assert.assertTrue(aliases.containsKey("hc-test-key-1"));
-                Assert.assertTrue(aliases.containsKey("hc-test-key-2"));
-                return "hc-test-key-2";
-            }
+    @Test(expected=IOException.class)
+    public void testClientAuthSSLFailure() throws Exception {
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .setSslSetupHandler(new SSLServerSetupHandler() {
 
-        };
+                    @Override
+                    public void initialize(final SSLServerSocket socket) throws SSLException {
+                        socket.setNeedClientAuth(true);
+                    }
+
+                })
+                .create();
+        this.server.start();
 
-        final SSLContext serverSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray())
-                .build();
-        final SSLContext clientSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray(), aliasStrategy)
-                .build();
-
-        this.localServer = new LocalTestServer(serverSSLContext, true);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-
-        final HttpHost host = new HttpHost("localhost", 443, "https");
         final HttpContext context = new BasicHttpContext();
         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
-        final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(clientSSLContext, hostVerifier);
+        final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
+                SSLTestContexts.createClientSSLContext(), hostVerifier);
         final Socket socket = socketFactory.createSocket(context);
-        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
-        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress, null, context);
-        final SSLSession sslsession = sslSocket.getSession();
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+        try {
+            final SSLSession sslsession = sslSocket.getSession();
 
-        Assert.assertNotNull(sslsession);
-        Assert.assertTrue(hostVerifier.isFired());
+            Assert.assertNotNull(sslsession);
+            Assert.assertTrue(hostVerifier.isFired());
+        } finally {
+            sslSocket.close();
+        }
     }
 
-    @Test(expected=SSLHandshakeException.class)
+    @Test(expected=SSLException.class)
     public void testSSLTrustVerification() throws Exception {
-        final SSLContext serverSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray())
-                .build();
-
-        this.localServer = new LocalTestServer(serverSSLContext);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .create();
+        this.server.start();
 
-        final HttpHost host = new HttpHost("localhost", 443, "https");
         final HttpContext context = new BasicHttpContext();
         // Use default SSL context
         final SSLContext defaultsslcontext = SSLContexts.createDefault();
 
         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(defaultsslcontext,
-                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+                NoopHostnameVerifier.INSTANCE);
 
         final Socket socket = socketFactory.createSocket(context);
-        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
-        socketFactory.connectSocket(0, socket, host, remoteAddress, null, context);
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+        sslSocket.close();
     }
 
     @Test
     public void testSSLTrustVerificationOverride() throws Exception {
-        final SSLContext serverSSLContext = SSLContexts.custom()
-                .useProtocol("TLS")
-                .loadTrustMaterial(keystore)
-                .loadKeyMaterial(keystore, "nopassword".toCharArray())
-                .build();
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .create();
+        this.server.start();
 
-        this.localServer = new LocalTestServer(serverSSLContext);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-
-        final HttpHost host = new HttpHost("localhost", 443, "https");
         final HttpContext context = new BasicHttpContext();
 
         final TrustStrategy trustStrategy = new TrustStrategy() {
 
+            @Override
             public boolean isTrusted(
                     final X509Certificate[] chain, final String authType) throws CertificateException {
                 return chain.length == 1;
@@ -289,19 +240,64 @@ public class TestSSLSocketFactory extends LocalServerTestBase {
             .build();
         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
                 sslcontext,
-                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+                NoopHostnameVerifier.INSTANCE);
 
         final Socket socket = socketFactory.createSocket(context);
-        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
-        socketFactory.connectSocket(0, socket, host, remoteAddress, null, context);
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+        sslSocket.close();
     }
 
     @Test
-    public void testDefaultHostnameVerifier() throws Exception {
+    public void testTLSOnly() throws Exception {
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .setSslSetupHandler(new SSLServerSetupHandler() {
+
+                    @Override
+                    public void initialize(final SSLServerSocket socket) throws SSLException {
+                        socket.setEnabledProtocols(new String[] {"TLSv1"});
+                    }
+
+                })
+                .create();
+        this.server.start();
+
+        final HttpContext context = new BasicHttpContext();
         final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
-                SSLContexts.createDefault(),
-                null);
-        Assert.assertNotNull(socketFactory.getHostnameVerifier());
+                SSLTestContexts.createClientSSLContext());
+        final Socket socket = socketFactory.createSocket(context);
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+        final SSLSession sslsession = sslSocket.getSession();
+        Assert.assertNotNull(sslsession);
     }
 
+    @Test(expected=IOException.class)
+    public void testSSLDisabledByDefault() throws Exception {
+        this.server = ServerBootstrap.bootstrap()
+                .setServerInfo(LocalServerTestBase.ORIGIN)
+                .setSslContext(SSLTestContexts.createServerSSLContext())
+                .setSslSetupHandler(new SSLServerSetupHandler() {
+
+                    @Override
+                    public void initialize(final SSLServerSocket socket) throws SSLException {
+                        socket.setEnabledProtocols(new String[] {"SSLv3"});
+                    }
+
+                })
+                .create();
+        this.server.start();
+
+        final HttpContext context = new BasicHttpContext();
+        final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
+                SSLTestContexts.createClientSSLContext());
+        final Socket socket = socketFactory.createSocket(context);
+        final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
+        socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
+    }
 }
diff --git a/httpclient/src/test/java/org/apache/http/conn/util/TestInetAddressUtils.java b/httpclient/src/test/java/org/apache/http/conn/util/TestInetAddressUtils.java
index 6749bda..0d6f73a 100644
--- a/httpclient/src/test/java/org/apache/http/conn/util/TestInetAddressUtils.java
+++ b/httpclient/src/test/java/org/apache/http/conn/util/TestInetAddressUtils.java
@@ -48,6 +48,7 @@ public class TestInetAddressUtils {
         Assert.assertFalse(InetAddressUtils.isIPv4Address("g.ar.ba.ge"));
         Assert.assertFalse(InetAddressUtils.isIPv4Address("192.168.0"));
         Assert.assertFalse(InetAddressUtils.isIPv4Address("256.255.255.255"));
+        Assert.assertFalse(InetAddressUtils.isIPv4Address("0.168.0.0"));    //IP address that starts with zero not allowed
     }
 
     @Test
@@ -55,6 +56,7 @@ public class TestInetAddressUtils {
         Assert.assertTrue(InetAddressUtils.isIPv6StdAddress("2001:0db8:0000:0000:0000:0000:1428:57ab"));
         Assert.assertTrue(InetAddressUtils.isIPv6StdAddress("2001:db8:0:0:0:0:1428:57ab"));
         Assert.assertTrue(InetAddressUtils.isIPv6StdAddress("0:0:0:0:0:0:0:0"));
+        Assert.assertTrue(InetAddressUtils.isIPv6StdAddress("0:0:0:0:0:0:0:1"));
         Assert.assertTrue(InetAddressUtils.isIPv6HexCompressedAddress("2001:0db8:0:0::1428:57ab"));
         Assert.assertTrue(InetAddressUtils.isIPv6HexCompressedAddress("2001:0db8::1428:57ab"));
         Assert.assertTrue(InetAddressUtils.isIPv6HexCompressedAddress("2001:db8::1428:57ab"));
@@ -73,6 +75,7 @@ public class TestInetAddressUtils {
         Assert.assertFalse(InetAddressUtils.isIPv6HexCompressedAddress("1:2:3:4:5:6:7::9")); // too many fields before ::
         Assert.assertFalse(InetAddressUtils.isIPv6HexCompressedAddress("1::3:4:5:6:7:8:9")); // too many fields after ::
         Assert.assertFalse(InetAddressUtils.isIPv6HexCompressedAddress("::3:4:5:6:7:8:9")); // too many fields after ::
+        Assert.assertFalse(InetAddressUtils.isIPv6Address("")); // empty
     }
 
     @Test
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java b/httpclient/src/test/java/org/apache/http/conn/util/TestPublicSuffixListParser.java
similarity index 54%
copy from httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java
copy to httpclient/src/test/java/org/apache/http/conn/util/TestPublicSuffixListParser.java
index 03e2d5f..191e9c0 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResource.java
+++ b/httpclient/src/test/java/org/apache/http/conn/util/TestPublicSuffixListParser.java
@@ -24,54 +24,36 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.client.cache;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.http.annotation.ThreadSafe;
-import org.apache.http.client.cache.Resource;
-
-/**
- * Cache resource backed by a file.
- *
- * @since 4.1
- */
- at ThreadSafe
-public class FileResource implements Resource {
+package org.apache.http.conn.util;
 
-    private static final long serialVersionUID = 4132244415919043397L;
-
-    private final File file;
-
-    private volatile boolean disposed;
-
-    public FileResource(final File file) {
-        super();
-        this.file = file;
-        this.disposed = false;
-    }
-
-    synchronized File getFile() {
-        return this.file;
-    }
-
-    public synchronized InputStream getInputStream() throws IOException {
-        return new FileInputStream(this.file);
-    }
-
-    public synchronized long length() {
-        return this.file.length();
-    }
-
-    public synchronized void dispose() {
-        if (this.disposed) {
-            return;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+import org.apache.http.Consts;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestPublicSuffixListParser {
+
+    private static final String SOURCE_FILE = "suffixlist.txt";
+
+    @Test
+    public void testParse() throws Exception {
+        final ClassLoader classLoader = getClass().getClassLoader();
+        final InputStream in = classLoader.getResourceAsStream(SOURCE_FILE);
+        Assert.assertNotNull(in);
+        final PublicSuffixList suffixList;
+        try {
+            final PublicSuffixListParser parser = new PublicSuffixListParser();
+            suffixList = parser.parse(new InputStreamReader(in, Consts.UTF_8));
+        } finally {
+            in.close();
         }
-        this.disposed = true;
-        this.file.delete();
+        Assert.assertNotNull(suffixList);
+        Assert.assertEquals(Arrays.asList("jp", "ac.jp", "*.tokyo.jp", "no", "h\u00E5.no", "xx"), suffixList.getRules());
+        Assert.assertEquals(Arrays.asList("metro.tokyo.jp"), suffixList.getExceptions());
     }
 
 }
diff --git a/httpclient/src/test/java/org/apache/http/conn/util/TestPublicSuffixMatcher.java b/httpclient/src/test/java/org/apache/http/conn/util/TestPublicSuffixMatcher.java
new file mode 100644
index 0000000..8c124ff
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/conn/util/TestPublicSuffixMatcher.java
@@ -0,0 +1,92 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.util;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.http.Consts;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestPublicSuffixMatcher {
+
+    private static final String SOURCE_FILE = "suffixlist.txt";
+
+    private PublicSuffixMatcher matcher;
+
+    @Before
+    public void setUp() throws Exception {
+        final ClassLoader classLoader = getClass().getClassLoader();
+        final InputStream in = classLoader.getResourceAsStream(SOURCE_FILE);
+        Assert.assertNotNull(in);
+        final PublicSuffixList suffixList;
+        try {
+            final PublicSuffixListParser parser = new PublicSuffixListParser();
+            suffixList = parser.parse(new InputStreamReader(in, Consts.UTF_8));
+        } finally {
+            in.close();
+        }
+        matcher = new PublicSuffixMatcher(suffixList.getRules(), suffixList.getExceptions());
+    }
+
+    @Test
+    public void testGetDomainRoot() throws Exception {
+        Assert.assertEquals("example.xx", matcher.getDomainRoot("example.XX"));
+        Assert.assertEquals("example.xx", matcher.getDomainRoot("www.example.XX"));
+        Assert.assertEquals("example.xx", matcher.getDomainRoot("www.blah.blah.example.XX"));
+        Assert.assertEquals(null, matcher.getDomainRoot("xx"));
+        Assert.assertEquals(null, matcher.getDomainRoot("jp"));
+        Assert.assertEquals(null, matcher.getDomainRoot("example"));
+        Assert.assertEquals("example.example", matcher.getDomainRoot("example.example"));
+        Assert.assertEquals(null, matcher.getDomainRoot("ac.jp"));
+        Assert.assertEquals(null, matcher.getDomainRoot("any.tokyo.jp"));
+        Assert.assertEquals("metro.tokyo.jp", matcher.getDomainRoot("metro.tokyo.jp"));
+        Assert.assertEquals("blah.blah.tokyo.jp", matcher.getDomainRoot("blah.blah.tokyo.jp"));
+        Assert.assertEquals("blah.ac.jp", matcher.getDomainRoot("blah.blah.ac.jp"));
+    }
+
+    @Test
+    public void testMatch() throws Exception {
+        Assert.assertTrue(matcher.matches(".jp"));
+        Assert.assertTrue(matcher.matches(".ac.jp"));
+        Assert.assertTrue(matcher.matches(".any.tokyo.jp"));
+        // exception
+        Assert.assertFalse(matcher.matches(".metro.tokyo.jp"));
+    }
+
+    @Test
+    public void testMatchUnicode() throws Exception {
+        Assert.assertTrue(matcher.matches(".h\u00E5.no")); // \u00E5 is <aring>
+        Assert.assertTrue(matcher.matches(".xn--h-2fa.no"));
+        Assert.assertTrue(matcher.matches(".h\u00E5.no"));
+        Assert.assertTrue(matcher.matches(".xn--h-2fa.no"));
+    }
+
+}
diff --git a/httpclient/src/test/java/org/apache/http/cookie/TestCookieOrigin.java b/httpclient/src/test/java/org/apache/http/cookie/TestCookieOrigin.java
index 681c96e..ca721c4 100644
--- a/httpclient/src/test/java/org/apache/http/cookie/TestCookieOrigin.java
+++ b/httpclient/src/test/java/org/apache/http/cookie/TestCookieOrigin.java
@@ -44,21 +44,25 @@ public class TestCookieOrigin {
         Assert.assertFalse(origin.isSecure());
     }
 
+    @SuppressWarnings("unused")
     @Test(expected=IllegalArgumentException.class)
     public void testNullHost() {
         new CookieOrigin(null, 80, "/", false);
     }
 
+    @SuppressWarnings("unused")
     @Test(expected=IllegalArgumentException.class)
     public void testEmptyHost() {
         new CookieOrigin("   ", 80, "/", false);
     }
 
+    @SuppressWarnings("unused")
     @Test(expected=IllegalArgumentException.class)
     public void testNegativePort() {
         new CookieOrigin("www.apache.org", -80, "/", false);
     }
 
+    @SuppressWarnings("unused")
     @Test(expected=IllegalArgumentException.class)
     public void testNullPath() {
         new CookieOrigin("www.apache.org", 80, null, false);
diff --git a/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java b/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java
new file mode 100644
index 0000000..5878173
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java
@@ -0,0 +1,113 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.cookie;
+
+import java.util.Comparator;
+import java.util.Date;
+
+import org.apache.http.impl.cookie.BasicClientCookie;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test cases for {@link org.apache.http.cookie.CookiePriorityComparator}.
+ */
+public class TestCookiePriorityComparator {
+
+    private Comparator<Cookie> comparator;
+
+    @Before
+    public void setup() {
+        comparator = CookiePriorityComparator.INSTANCE;
+    }
+
+    @Test
+    public void testUnequality() {
+        final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
+        cookie1.setPath("/a/b/");
+        final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
+        cookie2.setPath("/a/");
+        Assert.assertTrue(comparator.compare(cookie1, cookie2) < 0);
+        Assert.assertTrue(comparator.compare(cookie2, cookie1) > 0);
+    }
+
+    @Test
+    public void testEquality() {
+        final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
+        cookie1.setPath("/a");
+        final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
+        cookie2.setPath("/a");
+        Assert.assertTrue(comparator.compare(cookie1, cookie2) == 0);
+        Assert.assertTrue(comparator.compare(cookie2, cookie1) == 0);
+    }
+
+    @Test
+    public void testUnequalityTrailingSlash() {
+        final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
+        cookie1.setPath("/a/");
+        final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
+        cookie2.setPath("/a");
+        Assert.assertTrue(comparator.compare(cookie1, cookie2) < 0);
+        Assert.assertTrue(comparator.compare(cookie2, cookie1) > 0);
+    }
+
+    @Test
+    public void testEqualityNullPath() {
+        final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
+        cookie1.setPath(null);
+        final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
+        cookie2.setPath("/");
+        Assert.assertTrue(comparator.compare(cookie1, cookie2) == 0);
+        Assert.assertTrue(comparator.compare(cookie2, cookie1) == 0);
+    }
+
+    @Test
+    public void testEqualitySameLength() {
+        final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
+        cookie1.setPath("/this");
+        final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
+        cookie2.setPath("/that");
+        Assert.assertTrue(comparator.compare(cookie1, cookie2) == 0);
+        Assert.assertTrue(comparator.compare(cookie2, cookie1) == 0);
+    }
+
+    @Test
+    public void testUnequalityCreationDate() {
+        final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
+        cookie1.setPath("/blah");
+        cookie1.setCreationDate(new Date(System.currentTimeMillis() - 200000));
+        final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
+        cookie2.setPath("/blah");
+        cookie2.setCreationDate(new Date(System.currentTimeMillis()));
+        Assert.assertTrue(comparator.compare(cookie1, cookie2) < 0);
+        Assert.assertTrue(comparator.compare(cookie2, cookie1) > 0);
+    }
+
+}
+
diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java
index c34130d..de8808c 100644
--- a/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java
+++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java
@@ -26,13 +26,17 @@
  */
 package org.apache.http.impl.auth;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
 import org.apache.commons.codec.binary.Base64;
 import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.HttpRequest;
 import org.apache.http.auth.AUTH;
 import org.apache.http.auth.AuthScheme;
-import org.apache.http.auth.MalformedChallengeException;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicHttpRequest;
@@ -47,12 +51,13 @@ import org.junit.Test;
  */
 public class TestBasicScheme {
 
-    @Test(expected=MalformedChallengeException.class)
-    public void testBasicAuthenticationWithNoRealm() throws Exception {
+    @Test
+    public void testBasicAuthenticationEmptyChallenge() throws Exception {
         final String challenge = "Basic";
         final Header header = new BasicHeader(AUTH.WWW_AUTH, challenge);
         final AuthScheme authscheme = new BasicScheme();
         authscheme.processChallenge(header);
+        Assert.assertNull(authscheme.getRealm());
     }
 
     @Test
@@ -118,4 +123,25 @@ public class TestBasicScheme {
         Assert.assertFalse(authscheme.isConnectionBased());
     }
 
+    @Test
+    public void testSerialization() throws Exception {
+        final Header challenge = new BasicHeader(AUTH.PROXY_AUTH, "Basic realm=\"test\"");
+
+        final BasicScheme basicScheme = new BasicScheme();
+        basicScheme.processChallenge(challenge);
+
+        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        final ObjectOutputStream out = new ObjectOutputStream(buffer);
+        out.writeObject(basicScheme);
+        out.flush();
+        final byte[] raw = buffer.toByteArray();
+        final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
+        final BasicScheme authScheme = (BasicScheme) in.readObject();
+
+        Assert.assertEquals(basicScheme.getSchemeName(), authScheme.getSchemeName());
+        Assert.assertEquals(basicScheme.getRealm(), authScheme.getRealm());
+        Assert.assertEquals(basicScheme.isComplete(), authScheme.isComplete());
+
+    }
+
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
index da61ce5..809225d 100644
--- a/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
+++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
@@ -27,7 +27,10 @@
 package org.apache.http.impl.auth;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.security.MessageDigest;
 import java.util.HashMap;
 import java.util.Map;
@@ -634,4 +637,28 @@ public class TestDigestScheme {
         authscheme.authenticate(cred, request, context);
     }
 
+    @Test
+    public void testSerialization() throws Exception {
+        final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
+                "qop=\"auth,auth-int\"";
+        final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+        final DigestScheme digestScheme = new DigestScheme();
+        digestScheme.processChallenge(authChallenge);
+
+        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        final ObjectOutputStream out = new ObjectOutputStream(buffer);
+        out.writeObject(digestScheme);
+        out.flush();
+        final byte[] raw = buffer.toByteArray();
+        final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
+        final DigestScheme authScheme = (DigestScheme) in.readObject();
+
+        Assert.assertEquals(digestScheme.getSchemeName(), authScheme.getSchemeName());
+        Assert.assertEquals(digestScheme.getRealm(), authScheme.getRealm());
+        Assert.assertEquals(digestScheme.isComplete(), authScheme.isComplete());
+        Assert.assertEquals(digestScheme.getA1(), authScheme.getA1());
+        Assert.assertEquals(digestScheme.getA2(), authScheme.getA2());
+        Assert.assertEquals(digestScheme.getCnonce(), authScheme.getCnonce());
+    }
+
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java
index 9a3d254..aec2f11 100644
--- a/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java
+++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java
@@ -64,14 +64,14 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 
- at SuppressWarnings({"boxing","static-access"}) // test code
+ at SuppressWarnings({"boxing","static-access"})
 public class TestHttpAuthenticator {
 
-    private AuthenticationStrategy authStrategy;
+    private AuthenticationStrategy defltAuthStrategy;
     private AuthState authState;
     private ContextAwareAuthScheme authScheme;
     private HttpContext context;
-    private HttpHost host;
+    private HttpHost defaultHost;
     private Credentials credentials;
     private BasicCredentialsProvider credentialsProvider;
     private Lookup<AuthSchemeProvider> authSchemeRegistry;
@@ -80,14 +80,14 @@ public class TestHttpAuthenticator {
 
     @Before
     public void setUp() throws Exception {
-        this.authStrategy = Mockito.mock(AuthenticationStrategy.class);
+        this.defltAuthStrategy = Mockito.mock(AuthenticationStrategy.class);
         this.authState = new AuthState();
         this.authScheme = Mockito.mock(ContextAwareAuthScheme.class);
         Mockito.when(this.authScheme.getSchemeName()).thenReturn("Basic");
         Mockito.when(this.authScheme.isComplete()).thenReturn(Boolean.TRUE);
         this.context = new BasicHttpContext();
-        this.host = new HttpHost("localhost", 80);
-        this.context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, this.host);
+        this.defaultHost = new HttpHost("localhost", 80);
+        this.context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, this.defaultHost);
         this.credentials = Mockito.mock(Credentials.class);
         this.credentialsProvider = new BasicCredentialsProvider();
         this.credentialsProvider.setCredentials(AuthScope.ANY, this.credentials);
@@ -105,21 +105,21 @@ public class TestHttpAuthenticator {
     @Test
     public void testAuthenticationRequested() throws Exception {
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
-        Mockito.when(this.authStrategy.isAuthenticationRequested(
+        Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
                 Mockito.any(HttpHost.class),
                 Mockito.any(HttpResponse.class),
                 Mockito.any(HttpContext.class))).thenReturn(Boolean.TRUE);
 
         Assert.assertTrue(this.httpAuthenticator.isAuthenticationRequested(
-                this.host, response, this.authStrategy, this.authState, this.context));
+                this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
 
-        Mockito.verify(this.authStrategy).isAuthenticationRequested(this.host, response, this.context);
+        Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
     }
 
     @Test
     public void testAuthenticationRequestedAfterSuccess() throws Exception {
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
-        Mockito.when(this.authStrategy.isAuthenticationRequested(
+        Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
                 Mockito.any(HttpHost.class),
                 Mockito.any(HttpResponse.class),
                 Mockito.any(HttpContext.class))).thenReturn(Boolean.TRUE);
@@ -128,31 +128,31 @@ public class TestHttpAuthenticator {
         this.authState.setState(AuthProtocolState.SUCCESS);
 
         Assert.assertTrue(this.httpAuthenticator.isAuthenticationRequested(
-                this.host, response, this.authStrategy, this.authState, this.context));
+                this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
 
-        Mockito.verify(this.authStrategy).isAuthenticationRequested(this.host, response, this.context);
-        Mockito.verify(this.authStrategy).authFailed(this.host, this.authScheme, this.context);
+        Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
+        Mockito.verify(this.defltAuthStrategy).authFailed(this.defaultHost, this.authScheme, this.context);
     }
 
     @Test
     public void testAuthenticationNotRequestedUnchallenged() throws Exception {
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
-        Mockito.when(this.authStrategy.isAuthenticationRequested(
+        Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
                 Mockito.any(HttpHost.class),
                 Mockito.any(HttpResponse.class),
                 Mockito.any(HttpContext.class))).thenReturn(Boolean.FALSE);
 
         Assert.assertFalse(this.httpAuthenticator.isAuthenticationRequested(
-                this.host, response, this.authStrategy, this.authState, this.context));
+                this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
         Assert.assertEquals(AuthProtocolState.UNCHALLENGED, this.authState.getState());
 
-        Mockito.verify(this.authStrategy).isAuthenticationRequested(this.host, response, this.context);
+        Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
     }
 
     @Test
     public void testAuthenticationNotRequestedSuccess1() throws Exception {
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
-        Mockito.when(this.authStrategy.isAuthenticationRequested(
+        Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
                 Mockito.any(HttpHost.class),
                 Mockito.any(HttpResponse.class),
                 Mockito.any(HttpContext.class))).thenReturn(Boolean.FALSE);
@@ -160,17 +160,17 @@ public class TestHttpAuthenticator {
         this.authState.setState(AuthProtocolState.CHALLENGED);
 
         Assert.assertFalse(this.httpAuthenticator.isAuthenticationRequested(
-                this.host, response, this.authStrategy, this.authState, this.context));
+                this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
         Assert.assertEquals(AuthProtocolState.SUCCESS, this.authState.getState());
 
-        Mockito.verify(this.authStrategy).isAuthenticationRequested(this.host, response, this.context);
-        Mockito.verify(this.authStrategy).authSucceeded(this.host, this.authScheme, this.context);
+        Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
+        Mockito.verify(this.defltAuthStrategy).authSucceeded(this.defaultHost, this.authScheme, this.context);
     }
 
     @Test
     public void testAuthenticationNotRequestedSuccess2() throws Exception {
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
-        Mockito.when(this.authStrategy.isAuthenticationRequested(
+        Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
                 Mockito.any(HttpHost.class),
                 Mockito.any(HttpResponse.class),
                 Mockito.any(HttpContext.class))).thenReturn(Boolean.FALSE);
@@ -178,11 +178,11 @@ public class TestHttpAuthenticator {
         this.authState.setState(AuthProtocolState.HANDSHAKE);
 
         Assert.assertFalse(this.httpAuthenticator.isAuthenticationRequested(
-                this.host, response, this.authStrategy, this.authState, this.context));
+                this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
         Assert.assertEquals(AuthProtocolState.SUCCESS, this.authState.getState());
 
-        Mockito.verify(this.authStrategy).isAuthenticationRequested(this.host, response, this.context);
-        Mockito.verify(this.authStrategy).authSucceeded(this.host, this.authScheme, this.context);
+        Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
+        Mockito.verify(this.defltAuthStrategy).authSucceeded(this.defaultHost, this.authScheme, this.context);
     }
 
     @Test
@@ -215,13 +215,13 @@ public class TestHttpAuthenticator {
         final HttpHost host = new HttpHost("somehost", 80);
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
 
-        Mockito.when(this.authStrategy.getChallenges(
+        Mockito.when(this.defltAuthStrategy.getChallenges(
                 Mockito.any(HttpHost.class),
                 Mockito.any(HttpResponse.class),
                 Mockito.any(HttpContext.class))).thenReturn(new HashMap<String, Header>());
 
         Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
-                response, this.authStrategy, this.authState, this.context));
+                response, this.defltAuthStrategy, this.authState, this.context));
     }
 
     @Test
@@ -358,13 +358,13 @@ public class TestHttpAuthenticator {
 
         this.authState.setState(AuthProtocolState.CHALLENGED);
 
-        Mockito.doThrow(new MalformedChallengeException()).when(this.authStrategy).getChallenges(
+        Mockito.doThrow(new MalformedChallengeException()).when(this.defltAuthStrategy).getChallenges(
                 Mockito.any(HttpHost.class),
                 Mockito.any(HttpResponse.class),
                 Mockito.any(HttpContext.class));
 
         Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
-                response, this.authStrategy, this.authState, this.context));
+                response, this.defltAuthStrategy, this.authState, this.context));
 
         Assert.assertEquals(AuthProtocolState.UNCHALLENGED, this.authState.getState());
         Assert.assertNull(this.authState.getAuthScheme());
diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java
index 87e5e68..03900e2 100644
--- a/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java
+++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java
@@ -26,6 +26,7 @@
  */
 package org.apache.http.impl.auth;
 
+import org.apache.http.Consts;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -69,7 +70,7 @@ public class TestNTLMEngineImpl {
     static void checkMD4(final String input, final String hexOutput) throws Exception {
         NTLMEngineImpl.MD4 md4;
         md4 = new NTLMEngineImpl.MD4();
-        md4.update(input.getBytes("ASCII"));
+        md4.update(input.getBytes(Consts.ASCII));
         final byte[] answer = md4.getOutput();
         final byte[] correctAnswer = toBytes(hexOutput);
         if (answer.length != correctAnswer.length) {
diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java
index 3a7a9eb..dc5e8c2 100644
--- a/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java
+++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java
@@ -27,6 +27,13 @@
 
 package org.apache.http.impl.auth;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.charset.Charset;
+
+import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.HttpRequest;
 import org.apache.http.auth.AUTH;
@@ -43,6 +50,17 @@ public class TestRFC2617Scheme {
 
     static class TestAuthScheme extends RFC2617Scheme {
 
+        private static final long serialVersionUID = 1L;
+
+        public TestAuthScheme() {
+            super();
+        }
+
+        public TestAuthScheme(final Charset charset) {
+            super(charset);
+        }
+
+        @Override
         @Deprecated
         public Header authenticate(
                 final Credentials credentials,
@@ -50,14 +68,17 @@ public class TestRFC2617Scheme {
             return null;
         }
 
+        @Override
         public String getSchemeName() {
             return "test";
         }
 
+        @Override
         public boolean isComplete() {
             return false;
         }
 
+        @Override
         public boolean isConnectionBased() {
             return false;
         }
@@ -79,7 +100,7 @@ public class TestRFC2617Scheme {
         Assert.assertEquals(null, authscheme.getParameter("test"));
         Assert.assertEquals("stuff", authscheme.getParameter("test1"));
         Assert.assertEquals("stuff, stuff", authscheme.getParameter("test2"));
-        Assert.assertEquals("\"crap", authscheme.getParameter("test3"));
+        Assert.assertEquals("crap", authscheme.getParameter("test3"));
         Assert.assertEquals(null, authscheme.getParameter(null));
     }
 
@@ -122,18 +143,32 @@ public class TestRFC2617Scheme {
     }
 
     @Test(expected=MalformedChallengeException.class)
-    public void testEmptyHeader() throws Exception {
-        final TestAuthScheme authscheme = new TestAuthScheme();
-        final Header header = new BasicHeader(AUTH.WWW_AUTH, "Test    ");
-        authscheme.processChallenge(header);
-    }
-
-    @Test(expected=MalformedChallengeException.class)
     public void testInvalidHeaderValue() throws Exception {
         final TestAuthScheme authscheme = new TestAuthScheme();
         final Header header = new BasicHeader("whatever", "whatever");
         authscheme.processChallenge(header);
     }
 
+    @Test
+    public void testSerialization() throws Exception {
+        final Header challenge = new BasicHeader(AUTH.WWW_AUTH, "test realm=\"test\", blah=blah, yada=\"yada yada\"");
+
+        final TestAuthScheme testScheme = new TestAuthScheme(Consts.ISO_8859_1);
+        testScheme.processChallenge(challenge);
+
+        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        final ObjectOutputStream out = new ObjectOutputStream(buffer);
+        out.writeObject(testScheme);
+        out.flush();
+        final byte[] raw = buffer.toByteArray();
+        final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
+        final TestAuthScheme authScheme = (TestAuthScheme) in.readObject();
+
+        Assert.assertEquals(Consts.ISO_8859_1, authScheme.getCredentialsCharset());
+        Assert.assertEquals("test", authScheme.getParameter("realm"));
+        Assert.assertEquals("blah", authScheme.getParameter("blah"));
+        Assert.assertEquals("yada yada", authScheme.getParameter("yada"));
+    }
+
 }
 
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/MockClock.java b/httpclient/src/test/java/org/apache/http/impl/client/MockClock.java
index 0f0e96b..2d68d2a 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/MockClock.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/MockClock.java
@@ -30,6 +30,7 @@ public class MockClock implements Clock {
 
     private long t = System.currentTimeMillis();
 
+    @Override
     public long getCurrentTime() {
         return t;
     }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/MockConnPoolControl.java b/httpclient/src/test/java/org/apache/http/impl/client/MockConnPoolControl.java
index 1b55dbc..d8a4c3d 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/MockConnPoolControl.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/MockConnPoolControl.java
@@ -47,34 +47,42 @@ public final class MockConnPoolControl implements ConnPoolControl<HttpRoute> {
         this.defaultMax = 2;
     }
 
+    @Override
     public void setMaxTotal(final int max) {
         this.totalMax = max;
     }
 
+    @Override
     public int getMaxTotal() {
         return this.totalMax;
     }
 
+    @Override
     public PoolStats getTotalStats() {
         return new PoolStats(-1, -1, -1, this.totalMax);
     }
 
+    @Override
     public PoolStats getStats(final HttpRoute route) {
         return new PoolStats(-1, -1, -1, getMaxPerRoute(route));
     }
 
+    @Override
     public int getDefaultMaxPerRoute() {
         return this.defaultMax;
     }
 
+    @Override
     public void setDefaultMaxPerRoute(final int max) {
         this.defaultMax = max;
     }
 
+    @Override
     public void setMaxPerRoute(final HttpRoute route, final int max) {
         this.maxPerHostMap.put(route, Integer.valueOf(max));
     }
 
+    @Override
     public int getMaxPerRoute(final HttpRoute route) {
         final Integer max = this.maxPerHostMap.get(route);
         if (max != null) {
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestAIMDBackoffManager.java b/httpclient/src/test/java/org/apache/http/impl/client/TestAIMDBackoffManager.java
index 5ac3b86..06dec0f 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestAIMDBackoffManager.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestAIMDBackoffManager.java
@@ -47,7 +47,7 @@ public class TestAIMDBackoffManager {
     @Before
     public void setUp() {
         connPerRoute = new MockConnPoolControl();
-        route = new HttpRoute(new HttpHost("localhost:80"));
+        route = new HttpRoute(new HttpHost("localhost", 80));
         clock = new MockClock();
         impl = new AIMDBackoffManager(connPerRoute, clock);
         impl.setPerHostConnectionCap(10);
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicResponseHandler.java b/httpclient/src/test/java/org/apache/http/impl/client/TestAbstractResponseHandler.java
similarity index 84%
copy from httpclient/src/test/java/org/apache/http/impl/client/TestBasicResponseHandler.java
copy to httpclient/src/test/java/org/apache/http/impl/client/TestAbstractResponseHandler.java
index e917cd6..6a2930c 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicResponseHandler.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestAbstractResponseHandler.java
@@ -27,6 +27,7 @@
 
 package org.apache.http.impl.client;
 
+import java.io.IOException;
 import java.io.InputStream;
 
 import org.apache.http.HttpEntity;
@@ -36,6 +37,7 @@ import org.apache.http.StatusLine;
 import org.apache.http.client.HttpResponseException;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.message.BasicStatusLine;
+import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -43,19 +45,25 @@ import org.mockito.Mockito;
 /**
  * Unit tests for {@link BasicResponseHandler}.
  */
-public class TestBasicResponseHandler {
+public class TestAbstractResponseHandler {
 
     @Test
     public void testSuccessfulResponse() throws Exception {
         final StatusLine sl = new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK");
         final HttpResponse response = Mockito.mock(HttpResponse.class);
-        final HttpEntity entity = new StringEntity("stuff");
+        final HttpEntity entity = new StringEntity("42");
         Mockito.when(response.getStatusLine()).thenReturn(sl);
         Mockito.when(response.getEntity()).thenReturn(entity);
 
-        final BasicResponseHandler handler = new BasicResponseHandler();
-        final String s = handler.handleResponse(response);
-        Assert.assertEquals("stuff", s);
+        final AbstractResponseHandler<Integer> handler = new AbstractResponseHandler<Integer>() {
+
+          @Override
+          public Integer handleEntity(final HttpEntity entity) throws IOException {
+            return Integer.valueOf(EntityUtils.toString(entity));
+          }
+        };
+        final Integer number = handler.handleResponse(response);
+        Assert.assertEquals(42, number.intValue());
     }
 
     @SuppressWarnings("boxing")
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestAuthenticationStrategy.java b/httpclient/src/test/java/org/apache/http/impl/client/TestAuthenticationStrategy.java
index 39f34f2..b934aff 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestAuthenticationStrategy.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestAuthenticationStrategy.java
@@ -62,7 +62,7 @@ import org.mockito.Mockito;
 /**
  * Simple tests for {@link AuthenticationStrategyImpl}.
  */
- at SuppressWarnings({"boxing"}) // test code
+ at SuppressWarnings("boxing") // test code
 public class TestAuthenticationStrategy {
 
     @Test(expected=IllegalArgumentException.class)
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicAuthCache.java b/httpclient/src/test/java/org/apache/http/impl/client/TestBasicAuthCache.java
index b7561c7..702ca82 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicAuthCache.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestBasicAuthCache.java
@@ -30,6 +30,8 @@ package org.apache.http.impl.client;
 import org.apache.http.HttpHost;
 import org.apache.http.auth.AuthScheme;
 import org.apache.http.conn.SchemePortResolver;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.auth.NTLMScheme;
 import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -37,14 +39,15 @@ import org.mockito.Mockito;
 /**
  * Unit tests for {@link BasicAuthCache}.
  */
+ at SuppressWarnings("boxing") // test code
 public class TestBasicAuthCache {
 
     @Test
-    public void testBasics() throws Exception {
+    public void testBasicStoreRestore() throws Exception {
         final BasicAuthCache cache = new BasicAuthCache();
-        final AuthScheme authScheme = Mockito.mock(AuthScheme.class);
+        final AuthScheme authScheme = new BasicScheme();
         cache.put(new HttpHost("localhost", 80), authScheme);
-        Assert.assertSame(authScheme, cache.get(new HttpHost("localhost", 80)));
+        Assert.assertNotNull(cache.get(new HttpHost("localhost", 80)));
         cache.remove(new HttpHost("localhost", 80));
         Assert.assertNull(cache.get(new HttpHost("localhost", 80)));
         cache.put(new HttpHost("localhost", 80), authScheme);
@@ -52,6 +55,20 @@ public class TestBasicAuthCache {
         Assert.assertNull(cache.get(new HttpHost("localhost", 80)));
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullKey() throws Exception {
+        final BasicAuthCache cache = new BasicAuthCache();
+        final AuthScheme authScheme = new BasicScheme();
+        cache.put(null, authScheme);
+    }
+
+    @Test
+    public void testNullAuthScheme() throws Exception {
+        final BasicAuthCache cache = new BasicAuthCache();
+        cache.put(new HttpHost("localhost", 80), null);
+        Assert.assertNull(cache.get(new HttpHost("localhost", 80)));
+    }
+
     @Test
     public void testGetKey() throws Exception {
         final BasicAuthCache cache = new BasicAuthCache();
@@ -70,4 +87,12 @@ public class TestBasicAuthCache {
         Assert.assertEquals(target, cache.getKey(new HttpHost("localhost", -1, "https")));
     }
 
+    @Test
+    public void testStoreNonserializable() throws Exception {
+        final BasicAuthCache cache = new BasicAuthCache();
+        final AuthScheme authScheme = new NTLMScheme();
+        cache.put(new HttpHost("localhost", 80), authScheme);
+        Assert.assertNull(cache.get(new HttpHost("localhost", 80)));
+    }
+
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicCredentialsProvider.java b/httpclient/src/test/java/org/apache/http/impl/client/TestBasicCredentialsProvider.java
index a50c8a9..def37bb 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicCredentialsProvider.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestBasicCredentialsProvider.java
@@ -26,6 +26,7 @@
  */
 package org.apache.http.impl.client;
 
+import org.apache.http.HttpHost;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.Credentials;
 import org.apache.http.auth.UsernamePasswordCredentials;
@@ -125,39 +126,13 @@ public class TestBasicCredentialsProvider {
     }
 
     @Test
-    public void testScopeMatching() {
-        final AuthScope authscope1 = new AuthScope("somehost", 80, "somerealm", "somescheme");
-        final AuthScope authscope2 = new AuthScope("someotherhost", 80, "somerealm", "somescheme");
-        Assert.assertTrue(authscope1.match(authscope2) < 0);
-
-        int m1 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
-        int m2 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", AuthScope.ANY_SCHEME));
-        Assert.assertTrue(m2 > m1);
-
-        m1 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
-        m2 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", AuthScope.ANY_SCHEME));
-        Assert.assertTrue(m2 > m1);
-
-        m1 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", "somescheme"));
-        m2 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, 80, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME));
-        Assert.assertTrue(m2 > m1);
-
-        m1 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, 80, "somerealm", "somescheme"));
-        m2 = authscope1.match(
-            new AuthScope("somehost", AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME));
-        Assert.assertTrue(m2 > m1);
-
-        m1 = authscope1.match(AuthScope.ANY);
-        m2 = authscope1.match(
-            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
-        Assert.assertTrue(m2 > m1);
+    public void testMixedCaseHostname() throws Exception {
+        final HttpHost httpHost = new HttpHost("hOsT", 80);
+        final BasicCredentialsProvider state = new BasicCredentialsProvider();
+        final Credentials expected = new UsernamePasswordCredentials("name", "pass");
+        state.setCredentials(new AuthScope(httpHost), expected);
+        final Credentials got = state.getCredentials(DEFSCOPE);
+        Assert.assertEquals(expected, got);
     }
 
     @Test
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicResponseHandler.java b/httpclient/src/test/java/org/apache/http/impl/client/TestBasicResponseHandler.java
index e917cd6..8a4f0ed 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestBasicResponseHandler.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestBasicResponseHandler.java
@@ -43,6 +43,7 @@ import org.mockito.Mockito;
 /**
  * Unit tests for {@link BasicResponseHandler}.
  */
+ at SuppressWarnings("boxing") // test code
 public class TestBasicResponseHandler {
 
     @Test
@@ -58,7 +59,6 @@ public class TestBasicResponseHandler {
         Assert.assertEquals("stuff", s);
     }
 
-    @SuppressWarnings("boxing")
     @Test
     public void testUnsuccessfulResponse() throws Exception {
         final InputStream instream = Mockito.mock(InputStream.class);
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestCloseableHttpClient.java b/httpclient/src/test/java/org/apache/http/impl/client/TestCloseableHttpClient.java
index 93b9e6f..766f233 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestCloseableHttpClient.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestCloseableHttpClient.java
@@ -46,6 +46,7 @@ import org.mockito.Mockito;
 /**
  *  Simple tests for {@link CloseableHttpClient}.
  */
+ at SuppressWarnings({"boxing","static-access"}) // test code
 public class TestCloseableHttpClient {
 
     static abstract class NoopCloseableHttpClient extends CloseableHttpClient {
@@ -165,7 +166,7 @@ public class TestCloseableHttpClient {
                     Mockito.eq(new HttpHost("somehost", 444, "https")),
                     Mockito.same(httpget),
                     (HttpContext) Mockito.isNull());
-            Mockito.verify(content).close();
+            Mockito.verify(response).close();
             throw ex;
         }
     }
@@ -189,7 +190,7 @@ public class TestCloseableHttpClient {
                     Mockito.eq(new HttpHost("somehost", 444, "https")),
                     Mockito.same(httpget),
                     (HttpContext) Mockito.isNull());
-            Mockito.verify(content).close();
+            Mockito.verify(response).close();
             throw ex;
         }
     }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestFutureRequestExecutionService.java b/httpclient/src/test/java/org/apache/http/impl/client/TestFutureRequestExecutionService.java
index 2e6c76e..0d368a8 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestFutureRequestExecutionService.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestFutureRequestExecutionService.java
@@ -27,7 +27,6 @@
 package org.apache.http.impl.client;
 
 import java.io.IOException;
-import java.net.InetSocketAddress;
 import java.util.LinkedList;
 import java.util.Queue;
 import java.util.concurrent.CancellationException;
@@ -40,8 +39,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import junit.framework.Assert;
-
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
@@ -51,16 +48,19 @@ import org.apache.http.client.ResponseHandler;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.concurrent.FutureCallback;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.impl.bootstrap.HttpServer;
+import org.apache.http.impl.bootstrap.ServerBootstrap;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+ at SuppressWarnings("boxing") // test code
 public class TestFutureRequestExecutionService {
 
-    private LocalTestServer localServer;
+    private HttpServer localServer;
     private String uri;
     private FutureRequestExecutionService httpAsyncClientWithFuture;
 
@@ -68,9 +68,10 @@ public class TestFutureRequestExecutionService {
 
     @Before
     public void before() throws Exception {
-            this.localServer = new LocalTestServer(null, null);
-            this.localServer.register("/wait", new HttpRequestHandler() {
+            this.localServer = ServerBootstrap.bootstrap()
+                    .registerHandler("/wait", new HttpRequestHandler() {
 
+                @Override
                 public void handle(
                         final HttpRequest request, final HttpResponse response,
                         final HttpContext context) throws HttpException, IOException {
@@ -83,10 +84,10 @@ public class TestFutureRequestExecutionService {
                     }
                     response.setStatusCode(200);
                 }
-            });
+            }).create();
+
             this.localServer.start();
-            final InetSocketAddress address = localServer.getServiceAddress();
-            uri = "http://" + address.getHostName() + ":" + address.getPort() + "/wait";
+            uri = "http://localhost:" + this.localServer.getLocalPort() + "/wait";
             final HttpClient httpClient = HttpClientBuilder.create()
                     .setMaxConnPerRoute(5)
                     .build();
@@ -168,14 +169,17 @@ public class TestFutureRequestExecutionService {
             this.latch = latch;
         }
 
+        @Override
         public void failed(final Exception ex) {
             latch.countDown();
         }
 
+        @Override
         public void completed(final Boolean result) {
             latch.countDown();
         }
 
+        @Override
         public void cancelled() {
             latch.countDown();
         }
@@ -183,6 +187,7 @@ public class TestFutureRequestExecutionService {
 
 
     private final class OkidokiHandler implements ResponseHandler<Boolean> {
+        @Override
         public Boolean handleResponse(
                 final HttpResponse response) throws ClientProtocolException, IOException {
             return response.getStatusLine().getStatusCode() == 200;
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java b/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
new file mode 100644
index 0000000..135f634
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestIdleConnectionEvictor.java
@@ -0,0 +1,80 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.client;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Unit tests for {@link org.apache.http.impl.client.IdleConnectionEvictor}.
+ */
+public class TestIdleConnectionEvictor {
+
+    @Test
+    public void testEvictExpiredAndIdle() throws Exception {
+        final HttpClientConnectionManager cm = Mockito.mock(HttpClientConnectionManager.class);
+        final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
+                500, TimeUnit.MILLISECONDS, 3, TimeUnit.SECONDS);
+        connectionEvictor.start();
+
+        Thread.sleep(1000);
+
+        Mockito.verify(cm, Mockito.atLeast(1)).closeExpiredConnections();
+        Mockito.verify(cm, Mockito.atLeast(1)).closeIdleConnections(3000, TimeUnit.MILLISECONDS);
+
+        Assert.assertTrue(connectionEvictor.isRunning());
+
+        connectionEvictor.shutdown();
+        connectionEvictor.awaitTermination(1, TimeUnit.SECONDS);
+        Assert.assertFalse(connectionEvictor.isRunning());
+    }
+
+    @Test
+    public void testEvictExpiredOnly() throws Exception {
+        final HttpClientConnectionManager cm = Mockito.mock(HttpClientConnectionManager.class);
+        final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
+                500, TimeUnit.MILLISECONDS, 0, TimeUnit.SECONDS);
+        connectionEvictor.start();
+
+        Thread.sleep(1000);
+
+        Mockito.verify(cm, Mockito.atLeast(1)).closeExpiredConnections();
+        Mockito.verify(cm, Mockito.never()).closeIdleConnections(Mockito.anyLong(), Mockito.<TimeUnit>any());
+
+        Assert.assertTrue(connectionEvictor.isRunning());
+
+        connectionEvictor.shutdown();
+        connectionEvictor.awaitTermination(1, TimeUnit.SECONDS);
+        Assert.assertFalse(connectionEvictor.isRunning());
+    }
+
+}
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestInternalHttpClient.java b/httpclient/src/test/java/org/apache/http/impl/client/TestInternalHttpClient.java
index edf1743..9567073 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/TestInternalHttpClient.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/TestInternalHttpClient.java
@@ -55,7 +55,7 @@ import org.mockito.Mockito;
 /**
  *  Simple tests for {@link InternalHttpClient}.
  */
- at SuppressWarnings("deprecation")
+ at SuppressWarnings({"static-access"}) // test code
 public class TestInternalHttpClient {
 
     private ClientExecChain execChain;
@@ -94,7 +94,7 @@ public class TestInternalHttpClient {
     @Test
     public void testExecute() throws Exception {
         final HttpGet httpget = new HttpGet("http://somehost/stuff");
-        final HttpRoute route = new HttpRoute(new HttpHost("somehost"));
+        final HttpRoute route = new HttpRoute(new HttpHost("somehost", 80));
 
         final ArgumentCaptor<HttpRequestWrapper> argcap = ArgumentCaptor.forClass(HttpRequestWrapper.class);
         Mockito.when(routePlanner.determineRoute(
@@ -117,7 +117,7 @@ public class TestInternalHttpClient {
     @Test(expected=ClientProtocolException.class)
     public void testExecuteHttpException() throws Exception {
         final HttpGet httpget = new HttpGet("http://somehost/stuff");
-        final HttpRoute route = new HttpRoute(new HttpHost("somehost"));
+        final HttpRoute route = new HttpRoute(new HttpHost("somehost", 80));
 
         Mockito.when(routePlanner.determineRoute(
                 Mockito.eq(new HttpHost("somehost")),
@@ -188,7 +188,6 @@ public class TestInternalHttpClient {
     public void testClientClose() throws Exception {
         client.close();
 
-        Mockito.verify(connManager).shutdown();
         Mockito.verify(closeable1).close();
         Mockito.verify(closeable2).close();
     }
@@ -199,7 +198,6 @@ public class TestInternalHttpClient {
 
         client.close();
 
-        Mockito.verify(connManager).shutdown();
         Mockito.verify(closeable1).close();
         Mockito.verify(closeable2).close();
     }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/IntegrationTestBase.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/IntegrationTestBase.java
deleted file mode 100644
index 2ce310a..0000000
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/IntegrationTestBase.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.http.impl.client.integration;
-
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.localserver.LocalServerTestBase;
-import org.junit.After;
-
-public class IntegrationTestBase extends LocalServerTestBase {
-
-    protected CloseableHttpClient httpclient;
-
-    @After
-    public void shutDownClient() throws Exception {
-        if (this.httpclient != null) {
-            this.httpclient.close();
-        }
-    }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestAbortHandling.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestAbortHandling.java
index f7de48c..282e11b 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestAbortHandling.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestAbortHandling.java
@@ -49,36 +49,32 @@ import org.apache.http.conn.ConnectionRequest;
 import org.apache.http.conn.HttpClientConnectionManager;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.UriHttpRequestHandlerMapper;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 
 /**
  *  Tests for Abort handling.
  */
-public class TestAbortHandling extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-    }
+ at SuppressWarnings("static-access") // test code
+public class TestAbortHandling extends LocalServerTestBase {
 
     @Test
     public void testAbortRetry_HTTPCLIENT_1120() throws Exception {
-        final int port = this.localServer.getServiceAddress().getPort();
         final CountDownLatch wait = new CountDownLatch(1);
 
-        this.localServer.register("*", new HttpRequestHandler(){
+        this.serverBootstrap.registerHandler("*", new HttpRequestHandler() {
+            @Override
             public void handle(final HttpRequest request, final HttpResponse response,
-                    final HttpContext context) throws HttpException, IOException {
+                               final HttpContext context) throws HttpException, IOException {
                 try {
                     wait.countDown(); // trigger abort
                     Thread.sleep(2000); // allow time for abort to happen
@@ -88,10 +84,11 @@ public class TestAbortHandling extends IntegrationTestBase {
                 } catch (final Exception e) {
                     response.setStatusCode(HttpStatus.SC_REQUEST_TIMEOUT);
                 }
-            }});
+            }
+        });
 
-        final String s = "http://localhost:" + port + "/path";
-        final HttpGet httpget = new HttpGet(s);
+        final HttpHost target = start();
+        final HttpGet httpget = new HttpGet("/");
 
         final Thread t = new Thread() {
              @Override
@@ -106,11 +103,9 @@ public class TestAbortHandling extends IntegrationTestBase {
 
         t.start();
 
-        this.httpclient = HttpClients.createDefault();
-
         final HttpClientContext context = HttpClientContext.create();
         try {
-            this.httpclient.execute(getServerHttp(), httpget, context);
+            this.httpclient.execute(target, httpget, context);
         } catch (final IllegalStateException e) {
         } catch (final IOException e) {
         }
@@ -126,15 +121,17 @@ public class TestAbortHandling extends IntegrationTestBase {
         final ConMan conMan = new ConMan(connLatch, awaitLatch);
         final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
         final CountDownLatch getLatch = new CountDownLatch(1);
-        final CloseableHttpClient client = HttpClients.custom().setConnectionManager(conMan).build();
+        this.clientBuilder.setConnectionManager(conMan);
         final HttpContext context = new BasicHttpContext();
         final HttpGet httpget = new HttpGet("http://www.example.com/a");
-        this.httpclient = client;
+
+        start();
 
         new Thread(new Runnable() {
+            @Override
             public void run() {
                 try {
-                    client.execute(httpget, context);
+                    httpclient.execute(httpget, context);
                 } catch(final Throwable t) {
                     throwableRef.set(t);
                 } finally {
@@ -160,21 +157,21 @@ public class TestAbortHandling extends IntegrationTestBase {
      */
     @Test
     public void testAbortAfterAllocateBeforeRequest() throws Exception {
-        this.localServer.register("*", new BasicService());
+        this.serverBootstrap.registerHandler("*", new BasicService());
 
         final CountDownLatch releaseLatch = new CountDownLatch(1);
-        final PoolingHttpClientConnectionManager conMan = new PoolingHttpClientConnectionManager();
         final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
         final CountDownLatch getLatch = new CountDownLatch(1);
-        final CloseableHttpClient client = HttpClients.custom().setConnectionManager(conMan).build();
         final HttpContext context = new BasicHttpContext();
         final HttpGet httpget = new CustomGet("a", releaseLatch);
-        this.httpclient = client;
+
+        final HttpHost target = start();
 
         new Thread(new Runnable() {
+            @Override
             public void run() {
                 try {
-                    client.execute(getServerHttp(), httpget, context);
+                    httpclient.execute(target, httpget, context);
                 } catch(final Throwable t) {
                     throwableRef.set(t);
                 } finally {
@@ -200,18 +197,18 @@ public class TestAbortHandling extends IntegrationTestBase {
      */
     @Test
     public void testAbortBeforeExecute() throws Exception {
-        this.localServer.register("*", new BasicService());
+        this.serverBootstrap.registerHandler("*", new BasicService());
 
-        final PoolingHttpClientConnectionManager conMan = new PoolingHttpClientConnectionManager();
         final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
         final CountDownLatch getLatch = new CountDownLatch(1);
         final CountDownLatch startLatch = new CountDownLatch(1);
-        final CloseableHttpClient client = HttpClients.custom().setConnectionManager(conMan).build();
         final HttpContext context = new BasicHttpContext();
         final HttpGet httpget = new HttpGet("a");
-        this.httpclient = client;
+
+        final HttpHost target = start();
 
         new Thread(new Runnable() {
+            @Override
             public void run() {
                 try {
                     try {
@@ -221,7 +218,7 @@ public class TestAbortHandling extends IntegrationTestBase {
                     } catch(final InterruptedException interrupted) {
                         throw new RuntimeException("Never started!", interrupted);
                     }
-                    client.execute(getServerHttp(), httpget, context);
+                    httpclient.execute(target, httpget, context);
                 } catch(final Throwable t) {
                     throwableRef.set(t);
                 } finally {
@@ -245,24 +242,27 @@ public class TestAbortHandling extends IntegrationTestBase {
      */
     @Test
     public void testAbortAfterRedirectedRoute() throws Exception {
-        final int port = this.localServer.getServiceAddress().getPort();
-        this.localServer.register("*", new BasicRedirectService(port));
+        final UriHttpRequestHandlerMapper reqistry = new UriHttpRequestHandlerMapper();
+        this.serverBootstrap.setHandlerMapper(reqistry);
 
         final CountDownLatch connLatch = new CountDownLatch(1);
         final CountDownLatch awaitLatch = new CountDownLatch(1);
         final ConnMan4 conMan = new ConnMan4(connLatch, awaitLatch);
         final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
         final CountDownLatch getLatch = new CountDownLatch(1);
-        final CloseableHttpClient client = HttpClients.custom().setConnectionManager(conMan).build();
+        this.clientBuilder.setConnectionManager(conMan);
         final HttpContext context = new BasicHttpContext();
         final HttpGet httpget = new HttpGet("a");
-        this.httpclient = client;
+
+        final HttpHost target = start();
+        reqistry.register("*", new BasicRedirectService(target.getPort()));
 
         new Thread(new Runnable() {
+            @Override
             public void run() {
                 try {
-                    final HttpHost host = new HttpHost("127.0.0.1", port);
-                    client.execute(host, httpget, context);
+                    final HttpHost host = new HttpHost("127.0.0.1", target.getPort());
+                    httpclient.execute(host, httpget, context);
                 } catch(final Throwable t) {
                     throwableRef.set(t);
                 } finally {
@@ -316,6 +316,7 @@ public class TestAbortHandling extends IntegrationTestBase {
     }
 
     private static class BasicService implements HttpRequestHandler {
+        @Override
         public void handle(final HttpRequest request,
                 final HttpResponse response,
                 final HttpContext context) throws HttpException, IOException {
@@ -332,6 +333,7 @@ public class TestAbortHandling extends IntegrationTestBase {
             this.port = port;
         }
 
+        @Override
         public void handle(final HttpRequest request,
                 final HttpResponse response, final HttpContext context)
                 throws HttpException, IOException {
@@ -362,11 +364,13 @@ public class TestAbortHandling extends IntegrationTestBase {
 
                 return new ConnectionRequest() {
 
+                    @Override
                     public boolean cancel() {
                         currentThread.interrupt();
                         return true;
                     }
 
+                    @Override
                     public HttpClientConnection get(
                             final long timeout,
                             final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
@@ -396,10 +400,12 @@ public class TestAbortHandling extends IntegrationTestBase {
             this.awaitLatch = awaitLatch;
         }
 
+        @Override
         public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
             throw new UnsupportedOperationException("just a mockup");
         }
 
+        @Override
         public void closeExpiredConnections() {
             throw new UnsupportedOperationException("just a mockup");
         }
@@ -409,6 +415,7 @@ public class TestAbortHandling extends IntegrationTestBase {
             throw new UnsupportedOperationException("just a mockup");
         }
 
+        @Override
         public ConnectionRequest requestConnection(
                 final HttpRoute route,
                 final Object state) {
@@ -417,11 +424,13 @@ public class TestAbortHandling extends IntegrationTestBase {
 
             return new ConnectionRequest() {
 
+                @Override
                 public boolean cancel() {
                     currentThread.interrupt();
                     return true;
                 }
 
+                @Override
                 public HttpClientConnection get(
                         final long timeout,
                         final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
@@ -438,12 +447,14 @@ public class TestAbortHandling extends IntegrationTestBase {
             };
         }
 
+        @Override
         public void shutdown() {
         }
 
         public void close() {
         }
 
+        @Override
         public void releaseConnection(
                 final HttpClientConnection conn,
                 final Object newState,
@@ -451,6 +462,7 @@ public class TestAbortHandling extends IntegrationTestBase {
             throw new UnsupportedOperationException("just a mockup");
         }
 
+        @Override
         public void connect(
                 final HttpClientConnection conn,
                 final HttpRoute route,
@@ -459,6 +471,7 @@ public class TestAbortHandling extends IntegrationTestBase {
             throw new UnsupportedOperationException("just a mockup");
         }
 
+        @Override
         public void upgrade(
                 final HttpClientConnection conn,
                 final HttpRoute route,
@@ -466,6 +479,7 @@ public class TestAbortHandling extends IntegrationTestBase {
             throw new UnsupportedOperationException("just a mockup");
         }
 
+        @Override
         public void routeComplete(
                 final HttpClientConnection conn,
                 final HttpRoute route,
@@ -478,14 +492,14 @@ public class TestAbortHandling extends IntegrationTestBase {
                 final HttpHost host,
                 final InetSocketAddress localAddress,
                 final int connectTimeout,
-                final HttpContext context) throws IOException {
+                final HttpContext context) {
             throw new UnsupportedOperationException("just a mockup");
         }
 
         public void upgrade(
                 final HttpClientConnection conn,
                 final HttpHost host,
-                final HttpContext context) throws IOException {
+                final HttpContext context) {
             throw new UnsupportedOperationException("just a mockup");
         }
     }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestBasicConnectionManager.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestBasicConnectionManager.java
index 395b204..ab48672 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestBasicConnectionManager.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestBasicConnectionManager.java
@@ -26,43 +26,22 @@
  */
 package org.apache.http.impl.client.integration;
 
-import junit.framework.Assert;
 import org.apache.http.HttpHost;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.util.EntityUtils;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.Assert;
 import org.junit.Test;
 
-import java.io.IOException;
-import java.net.InetSocketAddress;
-
-public class TestBasicConnectionManager extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        this.localServer = new LocalTestServer(null, null);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-
-        this.httpclient = HttpClients.custom()
-                .setConnectionManager(new BasicHttpClientConnectionManager())
-                .build();
-    }
-
-    @After
-    public void cleanup() throws IOException {
-        this.httpclient.close();
-    }
+public class TestBasicConnectionManager extends LocalServerTestBase {
 
     @Test
     public void testBasics() throws Exception {
-        final InetSocketAddress address = localServer.getServiceAddress();
-        final HttpHost target = new HttpHost(address.getHostName(), address.getPort());
+        this.clientBuilder.setConnectionManager(new BasicHttpClientConnectionManager());
+
+        final HttpHost target = start();
         final HttpGet get = new HttpGet("/random/1024");
         final CloseableHttpResponse response = this.httpclient.execute(target, get);
         try {
@@ -75,8 +54,9 @@ public class TestBasicConnectionManager extends IntegrationTestBase {
 
     @Test(expected=IllegalStateException.class)
     public void testConnectionStillInUse() throws Exception {
-        final InetSocketAddress address = localServer.getServiceAddress();
-        final HttpHost target = new HttpHost(address.getHostName(), address.getPort());
+        this.clientBuilder.setConnectionManager(new BasicHttpClientConnectionManager());
+
+        final HttpHost target = start();
         final HttpGet get1 = new HttpGet("/random/1024");
         this.httpclient.execute(target, get1);
         final HttpGet get2 = new HttpGet("/random/1024");
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java
index 5f4af90..4cb082f 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java
@@ -38,6 +38,7 @@ import org.apache.http.HttpInetConnection;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
+import org.apache.http.auth.AUTH;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.Credentials;
 import org.apache.http.auth.UsernamePasswordCredentials;
@@ -55,10 +56,9 @@ import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.auth.BasicScheme;
 import org.apache.http.impl.client.BasicAuthCache;
 import org.apache.http.impl.client.BasicCredentialsProvider;
-import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.client.TargetAuthenticationStrategy;
 import org.apache.http.localserver.BasicAuthTokenExtractor;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.localserver.RequestBasicAuth;
 import org.apache.http.localserver.ResponseBasicUnauthorized;
 import org.apache.http.message.BasicHeader;
@@ -81,23 +81,24 @@ import org.junit.Test;
 /**
  * Unit tests for automatic client authentication.
  */
-public class TestClientAuthentication extends IntegrationTestBase {
+public class TestClientAuthentication extends LocalServerTestBase {
 
-    @Before
+    @Before @Override
     public void setUp() throws Exception {
+        super.setUp();
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer())
+            .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new ResponseConnControl())
             .add(new RequestBasicAuth())
             .add(new ResponseBasicUnauthorized()).build();
-        this.localServer = new LocalTestServer(httpproc, null);
-        startServer();
+        this.serverBootstrap.setHttpProcessor(httpproc);
     }
 
     static class AuthHandler implements HttpRequestHandler {
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -123,6 +124,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
             this.authTokenExtractor = new BasicAuthTokenExtractor();
         }
 
+        @Override
         public void verify(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -147,14 +149,17 @@ public class TestClientAuthentication extends IntegrationTestBase {
             this.creds = creds;
         }
 
+        @Override
         public void clear() {
         }
 
+        @Override
         public Credentials getCredentials(final AuthScope authscope) {
             this.authscope = authscope;
             return this.creds;
         }
 
+        @Override
         public void setCredentials(final AuthScope authscope, final Credentials credentials) {
         }
 
@@ -166,14 +171,16 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testBasicAuthenticationNoCreds() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
-        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+        final HttpHost target = start();
 
+        final HttpClientContext context = HttpClientContext.create();
+        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
+        context.setCredentialsProvider(credsProvider);
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -185,16 +192,17 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testBasicAuthenticationFailure() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
+
+        final HttpHost target = start();
 
+        final HttpClientContext context = HttpClientContext.create();
         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
                 new UsernamePasswordCredentials("test", "all-wrong"));
-
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
-
+        context.setCredentialsProvider(credsProvider);
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -206,16 +214,17 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testBasicAuthenticationSuccess() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
+        final HttpGet httpget = new HttpGet("/");
+        final HttpClientContext context = HttpClientContext.create();
         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
                 new UsernamePasswordCredentials("test", "test"));
+        context.setCredentialsProvider(credsProvider);
 
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
-
-        final HttpGet httpget = new HttpGet("/");
+        final HttpHost target = start();
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -229,30 +238,32 @@ public class TestClientAuthentication extends IntegrationTestBase {
     public void testBasicAuthenticationSuccessOnNonRepeatablePutExpectContinue() throws Exception {
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer(LocalTestServer.ORIGIN))
+            .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new ResponseConnControl())
             .add(new RequestBasicAuth())
             .add(new ResponseBasicUnauthorized()).build();
-        this.localServer = new LocalTestServer(
-                httpproc, null, null, new AuthExpectationVerifier(), null, false);
-        this.localServer.register("*", new AuthHandler());
-        this.localServer.start();
-
-        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
-                new UsernamePasswordCredentials("test", "test"));
+        this.serverBootstrap.setHttpProcessor(httpproc)
+            .setExpectationVerifier(new AuthExpectationVerifier())
+            .registerHandler("*", new AuthHandler());
 
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+        final HttpHost target = start();
 
-        final RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(true).build();
+        final RequestConfig config = RequestConfig.custom()
+                .setExpectContinueEnabled(true)
+                .build();
         final HttpPut httpput = new HttpPut("/");
         httpput.setConfig(config);
         httpput.setEntity(new InputStreamEntity(
                 new ByteArrayInputStream(
                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
                         -1));
+        final HttpClientContext context = HttpClientContext.create();
+        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
+                new UsernamePasswordCredentials("test", "test"));
+        context.setCredentialsProvider(credsProvider);
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpput);
+        final HttpResponse response = this.httpclient.execute(target, httpput, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -260,12 +271,9 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testBasicAuthenticationFailureOnNonRepeatablePutDontExpectContinue() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
-        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
-                new UsernamePasswordCredentials("test", "boom"));
-
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+        final HttpHost target = start();
 
         final RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(true).build();
         final HttpPut httpput = new HttpPut("/");
@@ -275,8 +283,13 @@ public class TestClientAuthentication extends IntegrationTestBase {
                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
                         -1));
 
+        final HttpClientContext context = HttpClientContext.create();
+        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
+                new UsernamePasswordCredentials("test", "boom"));
+        context.setCredentialsProvider(credsProvider);
+
         try {
-            this.httpclient.execute(getServerHttp(), httpput);
+            this.httpclient.execute(target, httpput, context);
             Assert.fail("ClientProtocolException should have been thrown");
         } catch (final ClientProtocolException ex) {
             final Throwable cause = ex.getCause();
@@ -288,17 +301,19 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testBasicAuthenticationSuccessOnRepeatablePost() throws Exception {
-        this.localServer.register("*", new AuthHandler());
-
-        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
-                new UsernamePasswordCredentials("test", "test"));
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+        final HttpHost target = start();
 
         final HttpPost httppost = new HttpPost("/");
         httppost.setEntity(new StringEntity("some important stuff", Consts.ASCII));
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httppost);
+        final HttpClientContext context = HttpClientContext.create();
+        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
+                new UsernamePasswordCredentials("test", "test"));
+        context.setCredentialsProvider(credsProvider);
+
+        final HttpResponse response = this.httpclient.execute(target, httppost, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -310,19 +325,22 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testBasicAuthenticationFailureOnNonRepeatablePost() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
-        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
-                new UsernamePasswordCredentials("test", "test"));
-
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+        final HttpHost target = start();
 
         final HttpPost httppost = new HttpPost("/");
         httppost.setEntity(new InputStreamEntity(
                 new ByteArrayInputStream(
                         new byte[] { 0,1,2,3,4,5,6,7,8,9 }), -1));
+
+        final HttpClientContext context = HttpClientContext.create();
+        final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
+                new UsernamePasswordCredentials("test", "test"));
+        context.setCredentialsProvider(credsProvider);
+
         try {
-            this.httpclient.execute(getServerHttp(), httppost);
+            this.httpclient.execute(target, httppost, context);
             Assert.fail("ClientProtocolException should have been thrown");
         } catch (final ClientProtocolException ex) {
             final Throwable cause = ex.getCause();
@@ -361,48 +379,123 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testBasicAuthenticationCredentialsCaching() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
+
+        final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
+        this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
+
+        final HttpHost target = start();
 
+        final HttpClientContext context = HttpClientContext.create();
         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY,
                 new UsernamePasswordCredentials("test", "test"));
+        context.setCredentialsProvider(credsProvider);
+
+        final HttpGet httpget = new HttpGet("/");
+
+        final HttpResponse response1 = this.httpclient.execute(target, httpget, context);
+        final HttpEntity entity1 = response1.getEntity();
+        Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
+        Assert.assertNotNull(entity1);
+        EntityUtils.consume(entity1);
+
+        final HttpResponse response2 = this.httpclient.execute(target, httpget, context);
+        final HttpEntity entity2 = response1.getEntity();
+        Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
+        Assert.assertNotNull(entity2);
+        EntityUtils.consume(entity2);
+
+        Assert.assertEquals(1, authStrategy.getCount());
+    }
+
+    static class RealmAuthHandler implements HttpRequestHandler {
+
+        final String realm;
+        final String realmCreds;
+
+        public RealmAuthHandler(final String realm, final String realmCreds) {
+            this.realm = realm;
+            this.realmCreds = realmCreds;
+        }
+
+        @Override
+        public void handle(
+                final HttpRequest request,
+                final HttpResponse response,
+                final HttpContext context) throws HttpException, IOException {
+            final String givenCreds = (String) context.getAttribute("creds");
+            if (givenCreds == null || !givenCreds.equals(this.realmCreds)) {
+                response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
+                response.addHeader(AUTH.WWW_AUTH, "Basic realm=\"" + this.realm + "\"");
+            } else {
+                response.setStatusCode(HttpStatus.SC_OK);
+                final StringEntity entity = new StringEntity("success", Consts.ASCII);
+                response.setEntity(entity);
+            }
+        }
+
+    }
+
+    @Test
+    public void testAuthenticationCredentialsCachingReauthenticationOnDifferentRealm() throws Exception {
+        this.serverBootstrap.registerHandler("/this", new RealmAuthHandler("this realm", "test:this"));
+        this.serverBootstrap.registerHandler("/that", new RealmAuthHandler("that realm", "test:that"));
+
+        this.server = this.serverBootstrap.create();
+        this.server.start();
+
+        final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), this.scheme.name());
+
         final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
+        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(target, "this realm", null),
+                new UsernamePasswordCredentials("test", "this"));
+        credsProvider.setCredentials(new AuthScope(target, "that realm", null),
+                new UsernamePasswordCredentials("test", "that"));
 
-        this.httpclient = HttpClients.custom()
-            .setDefaultCredentialsProvider(credsProvider)
-            .setTargetAuthenticationStrategy(authStrategy)
-            .build();
+        this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
+        this.httpclient = this.clientBuilder.build();
 
         final HttpClientContext context = HttpClientContext.create();
+        context.setCredentialsProvider(credsProvider);
 
-        final HttpHost targethost = getServerHttp();
-        final HttpGet httpget = new HttpGet("/");
+        final HttpGet httpget1 = new HttpGet("/this");
 
-        final HttpResponse response1 = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response1 = this.httpclient.execute(target, httpget1, context);
         final HttpEntity entity1 = response1.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity1);
         EntityUtils.consume(entity1);
 
-        final HttpResponse response2 = this.httpclient.execute(targethost, httpget, context);
+        final HttpGet httpget2 = new HttpGet("/this");
+
+        final HttpResponse response2 = this.httpclient.execute(target, httpget2, context);
         final HttpEntity entity2 = response1.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity2);
         EntityUtils.consume(entity2);
 
-        Assert.assertEquals(1, authStrategy.getCount());
+        final HttpGet httpget3 = new HttpGet("/that");
+
+        final HttpResponse response3 = this.httpclient.execute(target, httpget3, context);
+        final HttpEntity entity3 = response1.getEntity();
+        Assert.assertEquals(HttpStatus.SC_OK, response3.getStatusLine().getStatusCode());
+        Assert.assertNotNull(entity3);
+        EntityUtils.consume(entity3);
+
+        Assert.assertEquals(2, authStrategy.getCount());
     }
 
     @Test
     public void testAuthenticationUserinfoInRequestSuccess() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpGet httpget = new HttpGet("http://test:test@" +  target.toHostString() + "/");
 
-        this.httpclient = HttpClients.custom().build();
-
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpClientContext context = HttpClientContext.create();
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -411,14 +504,13 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testAuthenticationUserinfoInRequestFailure() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpGet httpget = new HttpGet("http://test:all-wrong@" +  target.toHostString() + "/");
 
-        this.httpclient = HttpClients.custom().build();
-
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpClientContext context = HttpClientContext.create();
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -431,6 +523,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -447,15 +540,15 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testAuthenticationUserinfoInRedirectSuccess() throws Exception {
-        this.localServer.register("*", new AuthHandler());
-        this.localServer.register("/thatway", new RedirectHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("/thatway", new RedirectHandler());
 
-        final HttpHost target = getServerHttp();
-        final HttpGet httpget = new HttpGet("http://" +  target.toHostString() + "/thatway");
+        final HttpHost target = start();
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpGet httpget = new HttpGet("http://" +  target.toHostString() + "/thatway");
+        final HttpClientContext context = HttpClientContext.create();
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
@@ -471,6 +564,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
             this.count = new AtomicLong();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -495,26 +589,21 @@ public class TestClientAuthentication extends IntegrationTestBase {
     @Test
     public void testPreemptiveAuthentication() throws Exception {
         final CountingAuthHandler requestHandler = new CountingAuthHandler();
-        this.localServer.register("*", requestHandler);
+        this.serverBootstrap.registerHandler("*", requestHandler);
 
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(AuthScope.ANY,
-                new UsernamePasswordCredentials("test", "test"));
-
-        this.httpclient = HttpClients.custom()
-            .setDefaultCredentialsProvider(credsProvider)
-            .build();
-
-        final HttpHost targethost = getServerHttp();
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
         final AuthCache authCache = new BasicAuthCache();
-        authCache.put(targethost, new BasicScheme());
+        authCache.put(target, new BasicScheme());
         context.setAuthCache(authCache);
+        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(AuthScope.ANY,
+                new UsernamePasswordCredentials("test", "test"));
+        context.setCredentialsProvider(credsProvider);
 
         final HttpGet httpget = new HttpGet("/");
-
-        final HttpResponse response1 = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response1 = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity1 = response1.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity1);
@@ -526,26 +615,21 @@ public class TestClientAuthentication extends IntegrationTestBase {
     @Test
     public void testPreemptiveAuthenticationFailure() throws Exception {
         final CountingAuthHandler requestHandler = new CountingAuthHandler();
-        this.localServer.register("*", requestHandler);
-
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(AuthScope.ANY,
-                new UsernamePasswordCredentials("test", "stuff"));
-
-        this.httpclient = HttpClients.custom()
-            .setDefaultCredentialsProvider(credsProvider)
-            .build();
+        this.serverBootstrap.registerHandler("*", requestHandler);
 
-        final HttpHost targethost = getServerHttp();
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
         final AuthCache authCache = new BasicAuthCache();
-        authCache.put(targethost, new BasicScheme());
+        authCache.put(target, new BasicScheme());
         context.setAuthCache(authCache);
+        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(AuthScope.ANY,
+                new UsernamePasswordCredentials("test", "stuff"));
+        context.setCredentialsProvider(credsProvider);
 
         final HttpGet httpget = new HttpGet("/");
-
-        final HttpResponse response1 = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response1 = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity1 = response1.getEntity();
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response1.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity1);
@@ -556,6 +640,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     static class ProxyAuthHandler implements HttpRequestHandler {
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -574,14 +659,16 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testAuthenticationTargetAsProxy() throws Exception {
-        this.localServer.register("*", new ProxyAuthHandler());
+        this.serverBootstrap.registerHandler("*", new ProxyAuthHandler());
+
+        final HttpHost target = start();
 
+        final HttpClientContext context = HttpClientContext.create();
         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+        context.setCredentialsProvider(credsProvider);
 
         final HttpGet httpget = new HttpGet("/");
-
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED,
                 response.getStatusLine().getStatusCode());
@@ -590,6 +677,7 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     static class ClosingAuthHandler implements HttpRequestHandler {
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -609,24 +697,20 @@ public class TestClientAuthentication extends IntegrationTestBase {
 
     @Test
     public void testConnectionCloseAfterAuthenticationSuccess() throws Exception {
-        this.localServer.register("*", new ClosingAuthHandler());
+        this.serverBootstrap.registerHandler("*", new ClosingAuthHandler());
+
+        final HttpHost target = start();
 
+        final HttpClientContext context = HttpClientContext.create();
         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY,
                 new UsernamePasswordCredentials("test", "test"));
-
-        this.httpclient = HttpClients.custom()
-                .setDefaultCredentialsProvider(credsProvider)
-                .build();
-
-        final HttpClientContext context = HttpClientContext.create();
-
-        final HttpHost targethost = getServerHttp();
+        context.setCredentialsProvider(credsProvider);
 
         for (int i = 0; i < 2; i++) {
             final HttpGet httpget = new HttpGet("/");
 
-            final HttpResponse response = this.httpclient.execute(targethost, httpget, context);
+            final HttpResponse response = this.httpclient.execute(target, httpget, context);
             EntityUtils.consume(response.getEntity());
             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
         }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFakeNTLM.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFakeNTLM.java
index 09e7e8a..a8d0ad4 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFakeNTLM.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFakeNTLM.java
@@ -26,6 +26,8 @@
  */
 package org.apache.http.impl.client.integration;
 
+import java.io.IOException;
+
 import org.apache.http.HttpException;
 import org.apache.http.HttpHeaders;
 import org.apache.http.HttpHost;
@@ -39,29 +41,22 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.HttpClients;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.message.BasicStatusLine;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
-import java.io.IOException;
-
 /**
  * Unit tests for some of the NTLM auth functionality..
  */
-public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        this.localServer = new LocalTestServer(null, null);
-    }
+public class TestClientAuthenticationFakeNTLM extends LocalServerTestBase {
 
     static class NtlmResponseHandler implements HttpRequestHandler {
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -77,8 +72,9 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
 
     @Test
     public void testNTLMAuthenticationFailure() throws Exception {
-        this.localServer.register("*", new NtlmResponseHandler());
-        this.localServer.start();
+        this.serverBootstrap.registerHandler("*", new NtlmResponseHandler());
+
+        final HttpHost target = start();
 
         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY,
@@ -89,11 +85,9 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
                 .build();
 
         final HttpContext context = HttpClientContext.create();
-
-        final HttpHost targethost = getServerHttp();
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         EntityUtils.consume(response.getEntity());
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED,
                 response.getStatusLine().getStatusCode());
@@ -107,6 +101,7 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
             this.authenticateHeaderValue = "NTLM " + type2Message;
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -126,10 +121,10 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
 
     @Test
     public void testNTLMv1Type2Message() throws Exception {
-        this.localServer.register("*", new NtlmType2MessageResponseHandler("TlRMTVNTUAACAA" +
+        this.serverBootstrap.registerHandler("*", new NtlmType2MessageResponseHandler("TlRMTVNTUAACAA" +
                 "AADAAMADgAAAAzggLiASNFZ4mrze8AAAAAAAAAAAAAAAAAAAAABgBwFwAAAA9T" +
                 "AGUAcgB2AGUAcgA="));
-        this.localServer.start();
+        final HttpHost target = start();
 
         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY,
@@ -140,11 +135,9 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
                 .build();
 
         final HttpContext context = HttpClientContext.create();
-
-        final HttpHost targethost = getServerHttp();
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         EntityUtils.consume(response.getEntity());
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED,
                 response.getStatusLine().getStatusCode());
@@ -152,10 +145,10 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
 
     @Test
     public void testNTLMv2Type2Message() throws Exception {
-        this.localServer.register("*", new NtlmType2MessageResponseHandler("TlRMTVNTUAACAA" +
+        this.serverBootstrap.registerHandler("*", new NtlmType2MessageResponseHandler("TlRMTVNTUAACAA" +
                 "AADAAMADgAAAAzgoriASNFZ4mrze8AAAAAAAAAACQAJABEAAAABgBwFwAAAA9T" +
                 "AGUAcgB2AGUAcgACAAwARABvAG0AYQBpAG4AAQAMAFMAZQByAHYAZQByAAAAAAA="));
-        this.localServer.start();
+        final HttpHost target = start();
 
         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY,
@@ -166,11 +159,9 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
                 .build();
 
         final HttpContext context = HttpClientContext.create();
-
-        final HttpHost targethost = getServerHttp();
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         EntityUtils.consume(response.getEntity());
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED,
                 response.getStatusLine().getStatusCode());
@@ -184,6 +175,7 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
             this.authenticateHeaderValue = "NTLM " + type2Message;
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -199,25 +191,20 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
 
     @Test
     public void testNTLMType2MessageOnlyAuthenticationFailure() throws Exception {
-        this.localServer.register("*", new NtlmType2MessageOnlyResponseHandler("TlRMTVNTUAACAA" +
+        this.serverBootstrap.registerHandler("*", new NtlmType2MessageOnlyResponseHandler("TlRMTVNTUAACAA" +
                 "AADAAMADgAAAAzggLiASNFZ4mrze8AAAAAAAAAAAAAAAAAAAAABgBwFwAAAA9T" +
                 "AGUAcgB2AGUAcgA="));
-        this.localServer.start();
 
+        final HttpHost target = start();
+
+        final HttpClientContext context = HttpClientContext.create();
         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY,
                 new NTCredentials("test", "test", null, null));
-
-        this.httpclient = HttpClients.custom()
-                .setDefaultCredentialsProvider(credsProvider)
-                .build();
-
-        final HttpContext context = HttpClientContext.create();
-
-        final HttpHost targethost = getServerHttp();
+        context.setCredentialsProvider(credsProvider);
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         EntityUtils.consume(response.getEntity());
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED,
                 response.getStatusLine().getStatusCode());
@@ -225,25 +212,20 @@ public class TestClientAuthenticationFakeNTLM extends IntegrationTestBase {
 
     @Test
     public void testNTLMType2NonUnicodeMessageOnlyAuthenticationFailure() throws Exception {
-        this.localServer.register("*", new NtlmType2MessageOnlyResponseHandler("TlRMTVNTUAACAA" +
+        this.serverBootstrap.registerHandler("*", new NtlmType2MessageOnlyResponseHandler("TlRMTVNTUAACAA" +
                 "AABgAGADgAAAAyggLiASNFZ4mrze8AAAAAAAAAAAAAAAAAAAAABgBwFwAAAA9T" +
                 "ZXJ2ZXI="));
-        this.localServer.start();
 
+        final HttpHost target = start();
+
+        final HttpClientContext context = HttpClientContext.create();
         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY,
                 new NTCredentials("test", "test", null, null));
-
-        this.httpclient = HttpClients.custom()
-                .setDefaultCredentialsProvider(credsProvider)
-                .build();
-
-        final HttpContext context = HttpClientContext.create();
-
-        final HttpHost targethost = getServerHttp();
+        context.setCredentialsProvider(credsProvider);
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(targethost, httpget, context);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         EntityUtils.consume(response.getEntity());
         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED,
                 response.getStatusLine().getStatusCode());
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFallBack.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFallBack.java
index 7c6f0d2..d4117ac 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFallBack.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthenticationFallBack.java
@@ -31,6 +31,7 @@ import java.io.IOException;
 import org.apache.http.Consts;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpResponseInterceptor;
@@ -41,9 +42,9 @@ import org.apache.http.auth.Credentials;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.CredentialsProvider;
 import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.localserver.RequestBasicAuth;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpProcessor;
@@ -58,10 +59,11 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-public class TestClientAuthenticationFallBack extends IntegrationTestBase {
+public class TestClientAuthenticationFallBack extends LocalServerTestBase {
 
     public class ResponseBasicUnauthorized implements HttpResponseInterceptor {
 
+        @Override
         public void process(
                 final HttpResponse response,
                 final HttpContext context) throws HttpException, IOException {
@@ -73,21 +75,22 @@ public class TestClientAuthenticationFallBack extends IntegrationTestBase {
 
     }
 
-    @Before
+    @Before @Override
     public void setUp() throws Exception {
+        super.setUp();
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer(LocalTestServer.ORIGIN))
+            .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new ResponseConnControl())
             .add(new RequestBasicAuth())
             .add(new ResponseBasicUnauthorized()).build();
-        this.localServer = new LocalTestServer(httpproc, null);
-        startServer();
+        this.serverBootstrap.setHttpProcessor(httpproc);
     }
 
     static class AuthHandler implements HttpRequestHandler {
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -114,14 +117,17 @@ public class TestClientAuthenticationFallBack extends IntegrationTestBase {
             this.creds = creds;
         }
 
+        @Override
         public void clear() {
         }
 
+        @Override
         public Credentials getCredentials(final AuthScope authscope) {
             this.authscope = authscope;
             return this.creds;
         }
 
+        @Override
         public void setCredentials(final AuthScope authscope, final Credentials credentials) {
         }
 
@@ -133,16 +139,17 @@ public class TestClientAuthenticationFallBack extends IntegrationTestBase {
 
     @Test
     public void testBasicAuthenticationSuccess() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
+        final HttpHost target = start();
+
+        final HttpClientContext context = HttpClientContext.create();
         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
                 new UsernamePasswordCredentials("test", "test"));
-
-        this.httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
-
+        context.setCredentialsProvider(credsProvider);
         final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         final HttpEntity entity = response.getEntity();
         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
         Assert.assertNotNull(entity);
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java
index 9a4bf50..e9897c5 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java
@@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.apache.http.Consts;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpResponseInterceptor;
@@ -52,9 +53,8 @@ import org.apache.http.config.RegistryBuilder;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.auth.BasicScheme;
 import org.apache.http.impl.auth.BasicSchemeFactory;
-import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.client.TargetAuthenticationStrategy;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.localserver.RequestBasicAuth;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpProcessor;
@@ -69,10 +69,11 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-public class TestClientReauthentication extends IntegrationTestBase {
+public class TestClientReauthentication extends LocalServerTestBase {
 
     public class ResponseBasicUnauthorized implements HttpResponseInterceptor {
 
+        @Override
         public void process(
                 final HttpResponse response,
                 final HttpContext context) throws HttpException, IOException {
@@ -83,24 +84,24 @@ public class TestClientReauthentication extends IntegrationTestBase {
 
     }
 
-    @Before
+    @Before @Override
     public void setUp() throws Exception {
+        super.setUp();
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer(LocalTestServer.ORIGIN))
+            .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new ResponseConnControl())
             .add(new RequestBasicAuth())
             .add(new ResponseBasicUnauthorized()).build();
-
-        this.localServer = new LocalTestServer(httpproc, null);
-        startServer();
+        this.serverBootstrap.setHttpProcessor(httpproc);
     }
 
     static class AuthHandler implements HttpRequestHandler {
 
         private final AtomicLong count = new AtomicLong(0);
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -132,14 +133,17 @@ public class TestClientReauthentication extends IntegrationTestBase {
             this.creds = creds;
         }
 
+        @Override
         public void clear() {
         }
 
+        @Override
         public Credentials getCredentials(final AuthScope authscope) {
             this.authscope = authscope;
             return this.creds;
         }
 
+        @Override
         public void setCredentials(final AuthScope authscope, final Credentials credentials) {
         }
 
@@ -151,13 +155,14 @@ public class TestClientReauthentication extends IntegrationTestBase {
 
     @Test
     public void testBasicAuthenticationSuccess() throws Exception {
-        this.localServer.register("*", new AuthHandler());
+        this.serverBootstrap.registerHandler("*", new AuthHandler());
 
         final BasicSchemeFactory myBasicAuthSchemeFactory = new BasicSchemeFactory() {
 
             @Override
             public AuthScheme create(final HttpContext context) {
                 return new BasicScheme() {
+                    private static final long serialVersionUID = 1L;
 
                     @Override
                     public String getSchemeName() {
@@ -187,17 +192,19 @@ public class TestClientReauthentication extends IntegrationTestBase {
         final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
             .register("MyBasic", myBasicAuthSchemeFactory)
             .build();
-        this.httpclient = HttpClients.custom()
+        this.httpclient = this.clientBuilder
             .setDefaultAuthSchemeRegistry(authSchemeRegistry)
             .setTargetAuthenticationStrategy(myAuthStrategy)
             .setDefaultCredentialsProvider(credsProvider)
             .build();
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
         for (int i = 0; i < 10; i++) {
             final HttpGet httpget = new HttpGet("/");
             httpget.setConfig(config);
-            final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget, context);
+            final HttpResponse response = this.httpclient.execute(target, httpget, context);
             final HttpEntity entity = response.getEntity();
             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
             Assert.assertNotNull(entity);
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientRequestExecution.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientRequestExecution.java
index f8a2919..640b015 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientRequestExecution.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientRequestExecution.java
@@ -49,25 +49,19 @@ import org.apache.http.client.utils.URIBuilder;
 import org.apache.http.client.utils.URIUtils;
 import org.apache.http.entity.InputStreamEntity;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.HttpClients;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestExecutor;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * Client protocol handling tests.
  */
-public class TestClientRequestExecution extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-    }
+public class TestClientRequestExecution extends LocalServerTestBase {
 
     private static class SimpleService implements HttpRequestHandler {
 
@@ -75,6 +69,7 @@ public class TestClientRequestExecution extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -114,11 +109,11 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
     @Test
     public void testAutoGeneratedHeaders() throws Exception {
-        final int port = this.localServer.getServiceAddress().getPort();
-        this.localServer.register("*", new SimpleService());
+        this.serverBootstrap.registerHandler("*", new SimpleService());
 
         final HttpRequestInterceptor interceptor = new HttpRequestInterceptor() {
 
+            @Override
             public void process(
                     final HttpRequest request,
                     final HttpContext context) throws HttpException, IOException {
@@ -129,6 +124,7 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
         final HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
 
+            @Override
             public boolean retryRequest(
                     final IOException exception,
                     final int executionCount,
@@ -138,18 +134,19 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
         };
 
-        this.httpclient = HttpClients.custom()
+        this.httpclient = this.clientBuilder
             .addInterceptorFirst(interceptor)
             .setRequestExecutor(new FaultyHttpRequestExecutor("Oppsie"))
             .setRetryHandler(requestRetryHandler)
             .build();
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
-        final String s = "http://localhost:" + port;
-        final HttpGet httpget = new HttpGet(s);
+        final HttpGet httpget = new HttpGet("/");
 
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), httpget, context);
+        final HttpResponse response = this.httpclient.execute(target, httpget, context);
         EntityUtils.consume(response.getEntity());
 
         final HttpRequest reqWrapper = context.getRequest();
@@ -163,11 +160,11 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testNonRepeatableEntity() throws Exception {
-        final int port = this.localServer.getServiceAddress().getPort();
-        this.localServer.register("*", new SimpleService());
+        this.serverBootstrap.registerHandler("*", new SimpleService());
 
         final HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
 
+            @Override
             public boolean retryRequest(
                     final IOException exception,
                     final int executionCount,
@@ -177,22 +174,23 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
         };
 
-        this.httpclient = HttpClients.custom()
+        this.httpclient = this.clientBuilder
             .setRequestExecutor(new FaultyHttpRequestExecutor("a message showing that this failed"))
             .setRetryHandler(requestRetryHandler)
             .build();
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
-        final String s = "http://localhost:" + port;
-        final HttpPost httppost = new HttpPost(s);
+        final HttpPost httppost = new HttpPost("/");
         httppost.setEntity(new InputStreamEntity(
                 new ByteArrayInputStream(
                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
                         -1));
 
         try {
-            this.httpclient.execute(getServerHttp(), httppost, context);
+            this.httpclient.execute(target, httppost, context);
         } catch (final ClientProtocolException ex) {
             Assert.assertTrue(ex.getCause() instanceof NonRepeatableRequestException);
             final NonRepeatableRequestException nonRepeat = (NonRepeatableRequestException)ex.getCause();
@@ -204,12 +202,13 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
     @Test
     public void testNonCompliantURI() throws Exception {
-        this.localServer.register("*", new SimpleService());
-        this.httpclient = HttpClients.createDefault();
+        this.serverBootstrap.registerHandler("*", new SimpleService());
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
         final BasicHttpRequest request = new BasicHttpRequest("GET", "blah.:.blah.:.");
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), request, context);
+        final HttpResponse response = this.httpclient.execute(target, request, context);
         EntityUtils.consume(response.getEntity());
 
         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
@@ -221,9 +220,9 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
     @Test
     public void testRelativeRequestURIWithFragment() throws Exception {
-        this.localServer.register("*", new SimpleService());
-        this.httpclient = HttpClients.createDefault();
-        final HttpHost target = getServerHttp();
+        this.serverBootstrap.registerHandler("*", new SimpleService());
+
+        final HttpHost target = start();
 
         final HttpGet httpget = new HttpGet("/stuff#blahblah");
         final HttpClientContext context = HttpClientContext.create();
@@ -238,9 +237,9 @@ public class TestClientRequestExecution extends IntegrationTestBase {
 
     @Test
     public void testAbsoluteRequestURIWithFragment() throws Exception {
-        this.localServer.register("*", new SimpleService());
-        this.httpclient = HttpClients.createDefault();
-        final HttpHost target = getServerHttp();
+        this.serverBootstrap.registerHandler("*", new SimpleService());
+
+        final HttpHost target = start();
 
         final URI uri = new URIBuilder()
             .setHost(target.getHostName())
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionAutoRelease.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionAutoRelease.java
index 175dcef..a4de80d 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionAutoRelease.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionAutoRelease.java
@@ -45,44 +45,32 @@ import org.apache.http.conn.ConnectionRequest;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.entity.BasicHttpEntity;
 import org.apache.http.impl.DefaultBHttpServerConnection;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.pool.PoolStats;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
-public class TestConnectionAutoRelease extends IntegrationTestBase {
-
-    private PoolingHttpClientConnectionManager mgr;
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-        this.mgr = new PoolingHttpClientConnectionManager();
-        this.httpclient = HttpClients.custom().setConnectionManager(this.mgr).build();
-    }
+public class TestConnectionAutoRelease extends LocalServerTestBase {
 
     @Test
     public void testReleaseOnEntityConsumeContent() throws Exception {
-        this.mgr.setDefaultMaxPerRoute(1);
-        this.mgr.setMaxTotal(1);
+        this.connManager.setDefaultMaxPerRoute(1);
+        this.connManager.setMaxTotal(1);
 
         // Zero connections in the pool
-        PoolStats stats = this.mgr.getTotalStats();
+        PoolStats stats = this.connManager.getTotalStats();
         Assert.assertEquals(0, stats.getAvailable());
 
+        final HttpHost target = start();
         // Get some random data
         final HttpGet httpget = new HttpGet("/random/20000");
-        final HttpHost target = getServerHttp();
-
         final HttpResponse response = this.httpclient.execute(target, httpget);
 
-        ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         try {
             connreq.get(250, TimeUnit.MILLISECONDS);
             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
@@ -94,32 +82,31 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
         EntityUtils.consume(e);
 
         // Expect one connection in the pool
-        stats = this.mgr.getTotalStats();
+        stats = this.connManager.getTotalStats();
         Assert.assertEquals(1, stats.getAvailable());
 
         // Make sure one connection is available
-        connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
 
-        this.mgr.releaseConnection(conn, null, -1, null);
+        this.connManager.releaseConnection(conn, null, -1, null);
     }
 
     @Test
     public void testReleaseOnEntityWriteTo() throws Exception {
-        this.mgr.setDefaultMaxPerRoute(1);
-        this.mgr.setMaxTotal(1);
+        this.connManager.setDefaultMaxPerRoute(1);
+        this.connManager.setMaxTotal(1);
 
         // Zero connections in the pool
-        PoolStats stats = this.mgr.getTotalStats();
+        PoolStats stats = this.connManager.getTotalStats();
         Assert.assertEquals(0, stats.getAvailable());
 
+        final HttpHost target = start();
         // Get some random data
         final HttpGet httpget = new HttpGet("/random/20000");
-        final HttpHost target = getServerHttp();
-
         final HttpResponse response = this.httpclient.execute(target, httpget);
 
-        ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         try {
             connreq.get(250, TimeUnit.MILLISECONDS);
             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
@@ -132,32 +119,32 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
         e.writeTo(outsteam);
 
         // Expect one connection in the pool
-        stats = this.mgr.getTotalStats();
+        stats = this.connManager.getTotalStats();
         Assert.assertEquals(1, stats.getAvailable());
 
         // Make sure one connection is available
-        connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
 
-        this.mgr.releaseConnection(conn, null, -1, null);
+        this.connManager.releaseConnection(conn, null, -1, null);
     }
 
     @Test
     public void testReleaseOnAbort() throws Exception {
-        this.mgr.setDefaultMaxPerRoute(1);
-        this.mgr.setMaxTotal(1);
+        this.connManager.setDefaultMaxPerRoute(1);
+        this.connManager.setMaxTotal(1);
 
         // Zero connections in the pool
-        final PoolStats stats = this.mgr.getTotalStats();
+        final PoolStats stats = this.connManager.getTotalStats();
         Assert.assertEquals(0, stats.getAvailable());
 
+        final HttpHost target = start();
+
         // Get some random data
         final HttpGet httpget = new HttpGet("/random/20000");
-        final HttpHost target = getServerHttp();
-
         final HttpResponse response = this.httpclient.execute(target, httpget);
 
-        ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         try {
             connreq.get(250, TimeUnit.MILLISECONDS);
             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
@@ -169,19 +156,20 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
         httpget.abort();
 
         // Expect zero connections in the pool
-        Assert.assertEquals(0, this.mgr.getTotalStats().getAvailable());
+        Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
 
         // Make sure one connection is available
-        connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
 
-        this.mgr.releaseConnection(conn, null, -1, null);
+        this.connManager.releaseConnection(conn, null, -1, null);
     }
 
     @Test
     public void testReleaseOnIOException() throws Exception {
-        this.localServer.register("/dropdead", new HttpRequestHandler() {
+        this.serverBootstrap.registerHandler("/dropdead", new HttpRequestHandler() {
 
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -198,33 +186,33 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
                         // do something comletely ugly in order to trigger
                         // MalformedChunkCodingException
                         final DefaultBHttpServerConnection conn = (DefaultBHttpServerConnection)
-                            context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
+                                context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
                         try {
                             conn.sendResponseHeader(response);
                         } catch (final HttpException ignore) {
                         }
                     }
 
-                } ;
+                };
                 entity.setChunked(true);
                 response.setEntity(entity);
             }
 
         });
 
-        this.mgr.setDefaultMaxPerRoute(1);
-        this.mgr.setMaxTotal(1);
+        this.connManager.setDefaultMaxPerRoute(1);
+        this.connManager.setMaxTotal(1);
 
         // Zero connections in the pool
-        Assert.assertEquals(0, this.mgr.getTotalStats().getAvailable());
+        Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
+
+        final HttpHost target = start();
 
         // Get some random data
         final HttpGet httpget = new HttpGet("/dropdead");
-        final HttpHost target = getServerHttp();
-
         final HttpResponse response = this.httpclient.execute(target, httpget);
 
-        ConnectionRequest connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         try {
             connreq.get(250, TimeUnit.MILLISECONDS);
             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
@@ -242,13 +230,13 @@ public class TestConnectionAutoRelease extends IntegrationTestBase {
         }
 
         // Expect zero connections in the pool
-        Assert.assertEquals(0, this.mgr.getTotalStats().getAvailable());
+        Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
 
         // Make sure one connection is available
-        connreq = this.mgr.requestConnection(new HttpRoute(target), null);
+        connreq = this.connManager.requestConnection(new HttpRoute(target), null);
         final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
 
-        this.mgr.releaseConnection(conn, null, -1, null);
+        this.connManager.releaseConnection(conn, null, -1, null);
     }
 
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionManagement.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionManagement.java
index 7121bc7..5862f76 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionManagement.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionManagement.java
@@ -31,6 +31,7 @@ import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketException;
+import java.util.Collections;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -65,20 +66,14 @@ import org.apache.http.protocol.RequestConnControl;
 import org.apache.http.protocol.RequestContent;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
- * Tests for <code>PoolingHttpClientConnectionManager</code> that do require a server
+ * Tests for {@code PoolingHttpClientConnectionManager} that do require a server
  * to communicate with.
  */
 public class TestConnectionManagement extends LocalServerTestBase {
 
-    @Before
-    public void setup() throws Exception {
-        startServer();
-    }
-
     private static HttpClientConnection getConnection(
             final HttpClientConnectionManager mgr,
             final HttpRoute route,
@@ -101,10 +96,9 @@ public class TestConnectionManagement extends LocalServerTestBase {
     @Test
     public void testReleaseConnection() throws Exception {
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(1);
+        this.connManager.setMaxTotal(1);
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final int      rsplen = 8;
         final String      uri = "/random/" + rsplen;
@@ -112,9 +106,9 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
         final HttpContext context = new BasicHttpContext();
 
-        HttpClientConnection conn = getConnection(mgr, route);
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        HttpClientConnection conn = getConnection(this.connManager, route);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
         context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
         context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
@@ -137,19 +131,19 @@ public class TestConnectionManagement extends LocalServerTestBase {
         // check that there is no auto-release by default
         try {
             // this should fail quickly, connection has not been released
-            getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
+            getConnection(this.connManager, route, 10L, TimeUnit.MILLISECONDS);
             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
         } catch (final ConnectionPoolTimeoutException e) {
             // expected
         }
 
         conn.close();
-        mgr.releaseConnection(conn, null, -1, null);
-        conn = getConnection(mgr, route);
+        this.connManager.releaseConnection(conn, null, -1, null);
+        conn = getConnection(this.connManager, route);
         Assert.assertFalse("connection should have been closed", conn.isOpen());
 
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
         // repeat the communication, no need to prepare the request again
         context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
@@ -165,8 +159,8 @@ public class TestConnectionManagement extends LocalServerTestBase {
 
         // release connection after marking it for re-use
         // expect the next connection obtained to be open
-        mgr.releaseConnection(conn, null, -1, null);
-        conn = getConnection(mgr, route);
+        this.connManager.releaseConnection(conn, null, -1, null);
+        conn = getConnection(this.connManager, route);
         Assert.assertTrue("connection should have been open", conn.isOpen());
 
         // repeat the communication, no need to prepare the request again
@@ -181,8 +175,8 @@ public class TestConnectionManagement extends LocalServerTestBase {
                      rsplen, data.length);
         // ignore data, but it must be read
 
-        mgr.releaseConnection(conn, null, -1, null);
-        mgr.shutdown();
+        this.connManager.releaseConnection(conn, null, -1, null);
+        this.connManager.shutdown();
     }
 
     /**
@@ -191,10 +185,9 @@ public class TestConnectionManagement extends LocalServerTestBase {
     @Test
     public void testReleaseConnectionWithTimeLimits() throws Exception {
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(1);
+        this.connManager.setMaxTotal(1);
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final int      rsplen = 8;
         final String      uri = "/random/" + rsplen;
@@ -202,9 +195,9 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
         final HttpContext context = new BasicHttpContext();
 
-        HttpClientConnection conn = getConnection(mgr, route);
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        HttpClientConnection conn = getConnection(this.connManager, route);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
         context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
         context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
@@ -227,20 +220,20 @@ public class TestConnectionManagement extends LocalServerTestBase {
         // check that there is no auto-release by default
         try {
             // this should fail quickly, connection has not been released
-            getConnection(mgr, route, 10L, TimeUnit.MILLISECONDS);
+            getConnection(this.connManager, route, 10L, TimeUnit.MILLISECONDS);
             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
         } catch (final ConnectionPoolTimeoutException e) {
             // expected
         }
 
         conn.close();
-        mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
-        conn = getConnection(mgr, route);
+        this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
+        conn = getConnection(this.connManager, route);
         Assert.assertFalse("connection should have been closed", conn.isOpen());
 
         // repeat the communication, no need to prepare the request again
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
         context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
         response = exec.execute(request, conn, context);
@@ -253,8 +246,8 @@ public class TestConnectionManagement extends LocalServerTestBase {
                      rsplen, data.length);
         // ignore data, but it must be read
 
-        mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
-        conn = getConnection(mgr, route);
+        this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
+        conn = getConnection(this.connManager, route);
         Assert.assertTrue("connection should have been open", conn.isOpen());
 
         // repeat the communication, no need to prepare the request again
@@ -269,14 +262,14 @@ public class TestConnectionManagement extends LocalServerTestBase {
                      rsplen, data.length);
         // ignore data, but it must be read
 
-        mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
+        this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
         Thread.sleep(150);
-        conn = getConnection(mgr, route);
+        conn = getConnection(this.connManager, route);
         Assert.assertTrue("connection should have been closed", !conn.isOpen());
 
         // repeat the communication, no need to prepare the request again
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
         context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
         response = exec.execute(request, conn, context);
@@ -289,88 +282,97 @@ public class TestConnectionManagement extends LocalServerTestBase {
                      rsplen, data.length);
         // ignore data, but it must be read
 
-        mgr.shutdown();
+        this.connManager.shutdown();
     }
 
     @Test
     public void testCloseExpiredIdleConnections() throws Exception {
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(1);
+        this.connManager.setMaxTotal(1);
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final HttpContext context = new BasicHttpContext();
 
-        final HttpClientConnection conn = getConnection(mgr, route);
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        final HttpClientConnection conn = getConnection(this.connManager, route);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
-        Assert.assertEquals(1, mgr.getTotalStats().getLeased());
-        Assert.assertEquals(1, mgr.getStats(route).getLeased());
+        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
+        Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
 
-        mgr.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
+        this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
 
         // Released, still active.
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(1, mgr.getStats(route).getAvailable());
+        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
+        Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
-        mgr.closeExpiredConnections();
+        this.connManager.closeExpiredConnections();
 
         // Time has not expired yet.
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(1, mgr.getStats(route).getAvailable());
+        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
+        Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
         Thread.sleep(150);
 
-        mgr.closeExpiredConnections();
+        this.connManager.closeExpiredConnections();
 
         // Time expired now, connections are destroyed.
-        Assert.assertEquals(0, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(0, mgr.getStats(route).getAvailable());
+        Assert.assertEquals(Collections.emptySet(), this.connManager.getRoutes());
+        Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
+        Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
 
-        mgr.shutdown();
+        this.connManager.shutdown();
     }
 
     @Test
     public void testCloseExpiredTTLConnections() throws Exception {
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(
+        this.connManager = new PoolingHttpClientConnectionManager(
                 100, TimeUnit.MILLISECONDS);
-        mgr.setMaxTotal(1);
+        this.clientBuilder.setConnectionManager(this.connManager);
 
-        final HttpHost target = getServerHttp();
+        this.connManager.setMaxTotal(1);
+
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final HttpContext context = new BasicHttpContext();
 
-        final HttpClientConnection conn = getConnection(mgr, route);
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        final HttpClientConnection conn = getConnection(this.connManager, route);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
-        Assert.assertEquals(1, mgr.getTotalStats().getLeased());
-        Assert.assertEquals(1, mgr.getStats(route).getLeased());
+        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
+        Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
         // Release, let remain idle for forever
-        mgr.releaseConnection(conn, null, -1, TimeUnit.MILLISECONDS);
+        this.connManager.releaseConnection(conn, null, -1, TimeUnit.MILLISECONDS);
 
         // Released, still active.
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(1, mgr.getStats(route).getAvailable());
+        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
+        Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
-        mgr.closeExpiredConnections();
+        this.connManager.closeExpiredConnections();
 
         // Time has not expired yet.
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(1, mgr.getStats(route).getAvailable());
+        Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
+        Assert.assertEquals(1, this.connManager.getStats(route).getAvailable());
 
         Thread.sleep(150);
 
-        mgr.closeExpiredConnections();
+        this.connManager.closeExpiredConnections();
 
         // TTL expired now, connections are destroyed.
-        Assert.assertEquals(0, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(0, mgr.getStats(route).getAvailable());
+        Assert.assertEquals(Collections.emptySet(), this.connManager.getRoutes());
+        Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
+        Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
 
-        mgr.shutdown();
+        this.connManager.shutdown();
     }
 
     /**
@@ -380,10 +382,9 @@ public class TestConnectionManagement extends LocalServerTestBase {
     @Test
     public void testReleaseConnectionOnAbort() throws Exception {
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(1);
+        this.connManager.setMaxTotal(1);
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final int      rsplen = 8;
         final String      uri = "/random/" + rsplen;
@@ -392,9 +393,9 @@ public class TestConnectionManagement extends LocalServerTestBase {
         final HttpRequest request =
             new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
 
-        HttpClientConnection conn = getConnection(mgr, route);
-        mgr.connect(conn, route, 0, context);
-        mgr.routeComplete(conn, route, context);
+        HttpClientConnection conn = getConnection(this.connManager, route);
+        this.connManager.connect(conn, route, 0, context);
+        this.connManager.routeComplete(conn, route, context);
 
         context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
         context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
@@ -413,7 +414,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
         // check that there are no connections available
         try {
             // this should fail quickly, connection has not been released
-            getConnection(mgr, route, 100L, TimeUnit.MILLISECONDS);
+            getConnection(this.connManager, route, 100L, TimeUnit.MILLISECONDS);
             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
         } catch (final ConnectionPoolTimeoutException e) {
             // expected
@@ -422,14 +423,14 @@ public class TestConnectionManagement extends LocalServerTestBase {
         // abort the connection
         Assert.assertTrue(conn instanceof HttpClientConnection);
         conn.shutdown();
-        mgr.releaseConnection(conn, null, -1, null);
+        this.connManager.releaseConnection(conn, null, -1, null);
 
         // the connection is expected to be released back to the manager
-        conn = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
+        conn = getConnection(this.connManager, route, 5L, TimeUnit.SECONDS);
         Assert.assertFalse("connection should have been closed", conn.isOpen());
 
-        mgr.releaseConnection(conn, null, -1, null);
-        mgr.shutdown();
+        this.connManager.releaseConnection(conn, null, -1, null);
+        this.connManager.shutdown();
     }
 
     @Test
@@ -441,22 +442,25 @@ public class TestConnectionManagement extends LocalServerTestBase {
             .register("http", stallingSocketFactory)
             .build();
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(registry);
-        mgr.setMaxTotal(1);
+        this.connManager = new PoolingHttpClientConnectionManager(registry);
+        this.clientBuilder.setConnectionManager(this.connManager);
+
+        this.connManager.setMaxTotal(1);
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final HttpContext context = new BasicHttpContext();
 
-        final HttpClientConnection conn = getConnection(mgr, route);
+        final HttpClientConnection conn = getConnection(this.connManager, route);
 
         final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
         final Thread abortingThread = new Thread(new Runnable() {
+            @Override
             public void run() {
                 try {
                     stallingSocketFactory.waitForState();
                     conn.shutdown();
-                    mgr.releaseConnection(conn, null, -1, null);
+                    connManager.releaseConnection(conn, null, -1, null);
                     connectLatch.countDown();
                 } catch (final Throwable e) {
                     throwRef.set(e);
@@ -466,8 +470,8 @@ public class TestConnectionManagement extends LocalServerTestBase {
         abortingThread.start();
 
         try {
-            mgr.connect(conn, route, 0, context);
-            mgr.routeComplete(conn, route, context);
+            this.connManager.connect(conn, route, 0, context);
+            this.connManager.routeComplete(conn, route, context);
             Assert.fail("expected SocketException");
         } catch(final SocketException expected) {}
 
@@ -477,14 +481,13 @@ public class TestConnectionManagement extends LocalServerTestBase {
         }
 
         Assert.assertFalse(conn.isOpen());
-        Assert.assertEquals(0, localServer.getAcceptedConnectionCount());
 
         // the connection is expected to be released back to the manager
-        final HttpClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
+        final HttpClientConnection conn2 = getConnection(this.connManager, route, 5L, TimeUnit.SECONDS);
         Assert.assertFalse("connection should have been closed", conn2.isOpen());
 
-        mgr.releaseConnection(conn2, null, -1, null);
-        mgr.shutdown();
+        this.connManager.releaseConnection(conn2, null, -1, null);
+        this.connManager.shutdown();
     }
 
     @Test
@@ -496,22 +499,25 @@ public class TestConnectionManagement extends LocalServerTestBase {
             .register("http", stallingSocketFactory)
             .build();
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(registry);
-        mgr.setMaxTotal(1);
+        this.connManager = new PoolingHttpClientConnectionManager(registry);
+        this.clientBuilder.setConnectionManager(this.connManager);
 
-        final HttpHost target = getServerHttp();
+        this.connManager.setMaxTotal(1);
+
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final HttpContext context = new BasicHttpContext();
 
-        final HttpClientConnection conn = getConnection(mgr, route);
+        final HttpClientConnection conn = getConnection(this.connManager, route);
 
         final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
         final Thread abortingThread = new Thread(new Runnable() {
+            @Override
             public void run() {
                 try {
                     stallingSocketFactory.waitForState();
                     conn.shutdown();
-                    mgr.releaseConnection(conn, null, -1, null);
+                    connManager.releaseConnection(conn, null, -1, null);
                     connectLatch.countDown();
                 } catch (final Throwable e) {
                     throwRef.set(e);
@@ -521,8 +527,8 @@ public class TestConnectionManagement extends LocalServerTestBase {
         abortingThread.start();
 
         try {
-            mgr.connect(conn, route, 0, context);
-            mgr.routeComplete(conn, route, context);
+            this.connManager.connect(conn, route, 0, context);
+            this.connManager.routeComplete(conn, route, context);
             Assert.fail("IOException expected");
         } catch(final IOException expected) {
         }
@@ -533,14 +539,13 @@ public class TestConnectionManagement extends LocalServerTestBase {
         }
 
         Assert.assertFalse(conn.isOpen());
-        Assert.assertEquals(0, localServer.getAcceptedConnectionCount());
 
         // the connection is expected to be released back to the manager
-        final HttpClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
+        final HttpClientConnection conn2 = getConnection(this.connManager, route, 5L, TimeUnit.SECONDS);
         Assert.assertFalse("connection should have been closed", conn2.isOpen());
 
-        mgr.releaseConnection(conn2, null, -1, null);
-        mgr.shutdown();
+        this.connManager.releaseConnection(conn2, null, -1, null);
+        this.connManager.shutdown();
     }
 
     @Test
@@ -552,22 +557,25 @@ public class TestConnectionManagement extends LocalServerTestBase {
             .register("http", stallingSocketFactory)
             .build();
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(registry);
-        mgr.setMaxTotal(1);
+        this.connManager = new PoolingHttpClientConnectionManager(registry);
+        this.clientBuilder.setConnectionManager(this.connManager);
+
+        this.connManager.setMaxTotal(1);
 
-        final HttpHost target = getServerHttp();
+        final HttpHost target = start();
         final HttpRoute route = new HttpRoute(target, null, false);
         final HttpContext context = new BasicHttpContext();
 
-        final HttpClientConnection conn = getConnection(mgr, route);
+        final HttpClientConnection conn = getConnection(this.connManager, route);
 
         final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
         final Thread abortingThread = new Thread(new Runnable() {
+            @Override
             public void run() {
                 try {
                     stallingSocketFactory.waitForState();
                     conn.shutdown();
-                    mgr.releaseConnection(conn, null, -1, null);
+                    connManager.releaseConnection(conn, null, -1, null);
                     connectLatch.countDown();
                 } catch (final Throwable e) {
                     throwRef.set(e);
@@ -577,8 +585,8 @@ public class TestConnectionManagement extends LocalServerTestBase {
         abortingThread.start();
 
         try {
-            mgr.connect(conn, route, 0, context);
-            mgr.routeComplete(conn, route, context);
+            this.connManager.connect(conn, route, 0, context);
+            this.connManager.routeComplete(conn, route, context);
             Assert.fail("IOException expected");
         } catch(final IOException expected) {
         }
@@ -589,22 +597,13 @@ public class TestConnectionManagement extends LocalServerTestBase {
         }
 
         Assert.assertFalse(conn.isOpen());
-        // Give the server a bit of time to accept the connection, but
-        // ensure that it can accept it.
-        for(int i = 0; i < 10; i++) {
-            if(localServer.getAcceptedConnectionCount() == 1) {
-                break;
-            }
-            Thread.sleep(100);
-        }
-        Assert.assertEquals(1, localServer.getAcceptedConnectionCount());
 
         // the connection is expected to be released back to the manager
-        final HttpClientConnection conn2 = getConnection(mgr, route, 5L, TimeUnit.SECONDS);
+        final HttpClientConnection conn2 = getConnection(this.connManager, route, 5L, TimeUnit.SECONDS);
         Assert.assertFalse("connection should have been closed", conn2.isOpen());
 
-        mgr.releaseConnection(conn2, null, -1, null);
-        mgr.shutdown();
+        this.connManager.releaseConnection(conn2, null, -1, null);
+        this.connManager.shutdown();
     }
 
     static class LatchSupport {
@@ -648,6 +647,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
             this.delegate = delegate;
         }
 
+        @Override
         public Socket connectSocket(
                 final int connectTimeout,
                 final Socket sock,
@@ -669,6 +669,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
             return socket;
         }
 
+        @Override
         public Socket createSocket(final HttpContext context) throws IOException {
             if(waitPolicy == WaitPolicy.BEFORE_CREATE) {
                 latch();
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionReuse.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionReuse.java
index cdae688..b30ff00 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionReuse.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestConnectionReuse.java
@@ -28,7 +28,6 @@
 package org.apache.http.impl.client.integration;
 
 import java.io.IOException;
-import java.net.InetSocketAddress;
 import java.net.URI;
 
 import org.apache.http.Header;
@@ -38,9 +37,7 @@ import org.apache.http.HttpResponse;
 import org.apache.http.HttpResponseInterceptor;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.localserver.RandomHandler;
 import org.apache.http.protocol.HTTP;
 import org.apache.http.protocol.HttpContext;
@@ -51,46 +48,31 @@ import org.apache.http.protocol.ResponseContent;
 import org.apache.http.protocol.ResponseDate;
 import org.apache.http.protocol.ResponseServer;
 import org.apache.http.util.EntityUtils;
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
 
-public class TestConnectionReuse {
-
-    protected LocalTestServer localServer;
-
-    @After
-    public void tearDown() throws Exception {
-        if (this.localServer != null) {
-            this.localServer.stop();
-        }
-    }
+public class TestConnectionReuse extends LocalServerTestBase {
 
     @Test
     public void testReuseOfPersistentConnections() throws Exception {
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer())
+            .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new ResponseConnControl()).build();
 
-        this.localServer = new LocalTestServer(httpproc, null);
-        this.localServer.register("/random/*", new RandomHandler());
-        this.localServer.start();
-
-        final InetSocketAddress saddress = this.localServer.getServiceAddress();
+        this.serverBootstrap.setHttpProcessor(httpproc)
+                .registerHandler("/random/*", new RandomHandler());
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(5);
-        mgr.setDefaultMaxPerRoute(5);
+        this.connManager.setMaxTotal(5);
+        this.connManager.setDefaultMaxPerRoute(5);
 
-        final HttpClient client = HttpClients.custom().setConnectionManager(mgr).build();
-        final HttpHost target = new HttpHost(saddress.getHostName(), saddress.getPort(), "http");
+        final HttpHost target = start();
 
         final WorkerThread[] workers = new WorkerThread[10];
         for (int i = 0; i < workers.length; i++) {
             workers[i] = new WorkerThread(
-                    client,
+                    this.httpclient,
                     target,
                     new URI("/random/2000"),
                     10, false);
@@ -108,13 +90,12 @@ public class TestConnectionReuse {
         }
 
         // Expect some connection in the pool
-        Assert.assertTrue(mgr.getTotalStats().getAvailable() > 0);
-
-        mgr.shutdown();
+        Assert.assertTrue(this.connManager.getTotalStats().getAvailable() > 0);
     }
 
     private static class AlwaysCloseConn implements HttpResponseInterceptor {
 
+        @Override
         public void process(
                 final HttpResponse response,
                 final HttpContext context) throws HttpException, IOException {
@@ -127,28 +108,22 @@ public class TestConnectionReuse {
     public void testReuseOfClosedConnections() throws Exception {
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer())
+            .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new AlwaysCloseConn()).build();
 
-        this.localServer = new LocalTestServer(httpproc, null);
-        this.localServer.register("/random/*", new RandomHandler());
-        this.localServer.start();
-
-        final InetSocketAddress saddress = this.localServer.getServiceAddress();
-
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(5);
-        mgr.setDefaultMaxPerRoute(5);
+        this.serverBootstrap.setHttpProcessor(httpproc)
+                .registerHandler("/random/*", new RandomHandler());
 
-        final HttpClient client = HttpClients.custom().setConnectionManager(mgr).build();
+        this.connManager.setMaxTotal(5);
+        this.connManager.setDefaultMaxPerRoute(5);
 
-        final HttpHost target = new HttpHost(saddress.getHostName(), saddress.getPort(), "http");
+        final HttpHost target = start();
 
         final WorkerThread[] workers = new WorkerThread[10];
         for (int i = 0; i < workers.length; i++) {
             workers[i] = new WorkerThread(
-                    client,
+                    this.httpclient,
                     target,
                     new URI("/random/2000"),
                     10, false);
@@ -166,37 +141,29 @@ public class TestConnectionReuse {
         }
 
         // Expect zero connections in the pool
-        Assert.assertEquals(0, mgr.getTotalStats().getAvailable());
-
-        mgr.shutdown();
+        Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
     }
 
     @Test
     public void testReuseOfAbortedConnections() throws Exception {
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer())
+            .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new ResponseConnControl()).build();
 
-        this.localServer = new LocalTestServer(httpproc, null);
-        this.localServer.register("/random/*", new RandomHandler());
-        this.localServer.start();
-
-        final InetSocketAddress saddress = this.localServer.getServiceAddress();
-
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(5);
-        mgr.setDefaultMaxPerRoute(5);
+        this.serverBootstrap.setHttpProcessor(httpproc)
+                .registerHandler("/random/*", new RandomHandler());
 
-        final HttpClient client = HttpClients.custom().setConnectionManager(mgr).build();
+        this.connManager.setMaxTotal(5);
+        this.connManager.setDefaultMaxPerRoute(5);
 
-        final HttpHost target = new HttpHost(saddress.getHostName(), saddress.getPort(), "http");
+        final HttpHost target = start();
 
         final WorkerThread[] workers = new WorkerThread[10];
         for (int i = 0; i < workers.length; i++) {
             workers[i] = new WorkerThread(
-                    client,
+                    this.httpclient,
                     target,
                     new URI("/random/2000"),
                     10, true);
@@ -214,65 +181,50 @@ public class TestConnectionReuse {
         }
 
         // Expect zero connections in the pool
-        Assert.assertEquals(0, mgr.getTotalStats().getAvailable());
-
-        mgr.shutdown();
+        Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
     }
 
     @Test
     public void testKeepAliveHeaderRespected() throws Exception {
         final HttpProcessor httpproc = HttpProcessorBuilder.create()
             .add(new ResponseDate())
-            .add(new ResponseServer())
+                .add(new ResponseServer(LocalServerTestBase.ORIGIN))
             .add(new ResponseContent())
             .add(new ResponseConnControl())
             .add(new ResponseKeepAlive()).build();
 
-        this.localServer = new LocalTestServer(httpproc, null);
-        this.localServer.register("/random/*", new RandomHandler());
-        this.localServer.start();
-
-        final InetSocketAddress saddress = this.localServer.getServiceAddress();
+        this.serverBootstrap.setHttpProcessor(httpproc)
+                .registerHandler("/random/*", new RandomHandler());
 
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(1);
-        mgr.setDefaultMaxPerRoute(1);
+        this.connManager.setMaxTotal(1);
+        this.connManager.setDefaultMaxPerRoute(1);
 
-        final HttpClient client = HttpClients.custom().setConnectionManager(mgr).build();
+        final HttpHost target = start();
 
-        final HttpHost target = new HttpHost(saddress.getHostName(), saddress.getPort(), "http");
-
-        HttpResponse response = client.execute(target, new HttpGet("/random/2000"));
+        HttpResponse response = this.httpclient.execute(target, new HttpGet("/random/2000"));
         EntityUtils.consume(response.getEntity());
 
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(1, localServer.getAcceptedConnectionCount());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
 
-        response = client.execute(target, new HttpGet("/random/2000"));
+        response = this.httpclient.execute(target, new HttpGet("/random/2000"));
         EntityUtils.consume(response.getEntity());
 
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(1, localServer.getAcceptedConnectionCount());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
 
         // Now sleep for 1.1 seconds and let the timeout do its work
         Thread.sleep(1100);
-        response = client.execute(target, new HttpGet("/random/2000"));
+        response = this.httpclient.execute(target, new HttpGet("/random/2000"));
         EntityUtils.consume(response.getEntity());
 
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(2, localServer.getAcceptedConnectionCount());
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
 
         // Do another request just under the 1 second limit & make
         // sure we reuse that connection.
         Thread.sleep(500);
-        response = client.execute(target, new HttpGet("/random/2000"));
+        response = this.httpclient.execute(target, new HttpGet("/random/2000"));
         EntityUtils.consume(response.getEntity());
 
-        Assert.assertEquals(1, mgr.getTotalStats().getAvailable());
-        Assert.assertEquals(2, localServer.getAcceptedConnectionCount());
-
-
-        mgr.shutdown();
+        Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
     }
 
     private static class WorkerThread extends Thread {
@@ -327,6 +279,7 @@ public class TestConnectionReuse {
     // A very basic keep-alive header interceptor, to add Keep-Alive: timeout=1
     // if there is no Connection: close header.
     private static class ResponseKeepAlive implements HttpResponseInterceptor {
+        @Override
         public void process(final HttpResponse response, final HttpContext context)
                 throws HttpException, IOException {
             final Header connection = response.getFirstHeader(HTTP.CONN_DIRECTIVE);
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestContentCodings.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestContentCodings.java
index 41f12b9..6ae970f 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestContentCodings.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestContentCodings.java
@@ -39,9 +39,11 @@ import java.util.concurrent.Executors;
 import java.util.zip.Deflater;
 import java.util.zip.GZIPOutputStream;
 
+import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
 import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
@@ -50,13 +52,11 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.entity.InputStreamEntity;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.BasicResponseHandler;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -64,12 +64,7 @@ import org.junit.Test;
  * require no intervention from the user of HttpClient, but we still want to let clients do their
  * own thing if they so wish.
  */
-public class TestContentCodings extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-    }
+public class TestContentCodings extends LocalServerTestBase {
 
     /**
      * Test for when we don't get an entity back; e.g. for a 204 or 304 response; nothing blows
@@ -80,11 +75,12 @@ public class TestContentCodings extends IntegrationTestBase {
      */
     @Test
     public void testResponseWithNoContent() throws Exception {
-        this.localServer.register("*", new HttpRequestHandler() {
+        this.serverBootstrap.registerHandler("*", new HttpRequestHandler() {
 
             /**
              * {@inheritDoc}
              */
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -93,16 +89,17 @@ public class TestContentCodings extends IntegrationTestBase {
             }
         });
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
+
         final HttpGet request = new HttpGet("/some-resource");
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), request);
+        final HttpResponse response = this.httpclient.execute(target, request);
         Assert.assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatusLine().getStatusCode());
         Assert.assertNull(response.getEntity());
     }
 
     /**
      * Test for when we are handling content from a server that has correctly interpreted RFC2616
-     * to return RFC1950 streams for <code>deflate</code> content coding.
+     * to return RFC1950 streams for {@code deflate} content coding.
      *
      * @throws Exception
      */
@@ -110,19 +107,19 @@ public class TestContentCodings extends IntegrationTestBase {
     public void testDeflateSupportForServerReturningRfc1950Stream() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createDeflateEncodingRequestHandler(entityText, false));
+        this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, false));
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
 
         final HttpGet request = new HttpGet("/some-resource");
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), request);
+        final HttpResponse response = this.httpclient.execute(target, request);
         Assert.assertEquals("The entity text is correctly transported", entityText,
                 EntityUtils.toString(response.getEntity()));
     }
 
     /**
      * Test for when we are handling content from a server that has incorrectly interpreted RFC2616
-     * to return RFC1951 streams for <code>deflate</code> content coding.
+     * to return RFC1951 streams for {@code deflate} content coding.
      *
      * @throws Exception
      */
@@ -130,12 +127,12 @@ public class TestContentCodings extends IntegrationTestBase {
     public void testDeflateSupportForServerReturningRfc1951Stream() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createDeflateEncodingRequestHandler(entityText, true));
+        this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, true));
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
 
         final HttpGet request = new HttpGet("/some-resource");
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), request);
+        final HttpResponse response = this.httpclient.execute(target, request);
         Assert.assertEquals("The entity text is correctly transported", entityText,
                 EntityUtils.toString(response.getEntity()));
     }
@@ -149,12 +146,12 @@ public class TestContentCodings extends IntegrationTestBase {
     public void testGzipSupport() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createGzipEncodingRequestHandler(entityText));
+        this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
 
         final HttpGet request = new HttpGet("/some-resource");
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), request);
+        final HttpResponse response = this.httpclient.execute(target, request);
         Assert.assertEquals("The entity text is correctly transported", entityText,
                 EntityUtils.toString(response.getEntity()));
     }
@@ -169,7 +166,7 @@ public class TestContentCodings extends IntegrationTestBase {
     public void testThreadSafetyOfContentCodings() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createGzipEncodingRequestHandler(entityText));
+        this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
 
         /*
          * Create a load of workers which will access the resource. Half will use the default
@@ -177,10 +174,9 @@ public class TestContentCodings extends IntegrationTestBase {
          */
         final int clients = 100;
 
-        final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
-        cm.setMaxTotal(clients);
+        this.connManager.setMaxTotal(clients);
 
-        this.httpclient = HttpClients.custom().setConnectionManager(cm).build();
+        final HttpHost target = start();
 
         final ExecutorService executor = Executors.newFixedThreadPool(clients);
 
@@ -190,7 +186,7 @@ public class TestContentCodings extends IntegrationTestBase {
         final List<WorkerTask> workers = new ArrayList<WorkerTask>();
 
         for (int i = 0; i < clients; ++i) {
-            workers.add(new WorkerTask(this.httpclient, i % 2 == 0, startGate, endGate));
+            workers.add(new WorkerTask(this.httpclient, target, i % 2 == 0, startGate, endGate));
         }
 
         for (final WorkerTask workerTask : workers) {
@@ -216,12 +212,12 @@ public class TestContentCodings extends IntegrationTestBase {
     public void testHttpEntityWriteToForGzip() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createGzipEncodingRequestHandler(entityText));
+        this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
 
         final HttpGet request = new HttpGet("/some-resource");
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), request);
+        final HttpResponse response = this.httpclient.execute(target, request);
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
 
         response.getEntity().writeTo(out);
@@ -233,12 +229,12 @@ public class TestContentCodings extends IntegrationTestBase {
     public void testHttpEntityWriteToForDeflate() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createDeflateEncodingRequestHandler(entityText, true));
+        this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, true));
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
 
         final HttpGet request = new HttpGet("/some-resource");
-        final HttpResponse response = this.httpclient.execute(getServerHttp(), request);
+        final HttpResponse response = this.httpclient.execute(target, request);
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
 
         response.getEntity().writeTo(out);
@@ -250,12 +246,12 @@ public class TestContentCodings extends IntegrationTestBase {
     public void gzipResponsesWorkWithBasicResponseHandler() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createGzipEncodingRequestHandler(entityText));
+        this.serverBootstrap.registerHandler("*", createGzipEncodingRequestHandler(entityText));
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
 
         final HttpGet request = new HttpGet("/some-resource");
-        final String response = this.httpclient.execute(getServerHttp(), request, new BasicResponseHandler());
+        final String response = this.httpclient.execute(target, request, new BasicResponseHandler());
         Assert.assertEquals("The entity text is correctly transported", entityText, response);
     }
 
@@ -263,12 +259,12 @@ public class TestContentCodings extends IntegrationTestBase {
     public void deflateResponsesWorkWithBasicResponseHandler() throws Exception {
         final String entityText = "Hello, this is some plain text coming back.";
 
-        this.localServer.register("*", createDeflateEncodingRequestHandler(entityText, false));
+        this.serverBootstrap.registerHandler("*", createDeflateEncodingRequestHandler(entityText, false));
 
-        this.httpclient = HttpClients.custom().build();
+        final HttpHost target = start();
 
         final HttpGet request = new HttpGet("/some-resource");
-        final String response = this.httpclient.execute(getServerHttp(), request, new BasicResponseHandler());
+        final String response = this.httpclient.execute(target, request, new BasicResponseHandler());
         Assert.assertEquals("The entity text is correctly transported", entityText, response);
     }
 
@@ -291,6 +287,7 @@ public class TestContentCodings extends IntegrationTestBase {
             /**
              * {@inheritDoc}
              */
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -308,7 +305,7 @@ public class TestContentCodings extends IntegrationTestBase {
                             // response.setEntity(new InputStreamEntity(new DeflaterInputStream(new
                             // ByteArrayInputStream(
                             // entityText.getBytes("utf-8"))), -1));
-                            final byte[] uncompressed = entityText.getBytes("utf-8");
+                            final byte[] uncompressed = entityText.getBytes(Consts.UTF_8);
                             final Deflater compressor = new Deflater(Deflater.DEFAULT_COMPRESSION, rfc1951);
                             compressor.setInput(uncompressed);
                             compressor.finish();
@@ -340,6 +337,7 @@ public class TestContentCodings extends IntegrationTestBase {
             /**
              * {@inheritDoc}
              */
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -365,7 +363,7 @@ public class TestContentCodings extends IntegrationTestBase {
                             final OutputStream out = new GZIPOutputStream(bytes);
 
                             final ByteArrayInputStream uncompressed = new ByteArrayInputStream(
-                                    entityText.getBytes("utf-8"));
+                                    entityText.getBytes(Consts.UTF_8));
 
                             final byte[] buf = new byte[60];
 
@@ -396,38 +394,18 @@ public class TestContentCodings extends IntegrationTestBase {
      */
     class WorkerTask implements Runnable {
 
-        /**
-         * The {@link HttpClient} used to make requests.
-         */
         private final HttpClient client;
-
-        /**
-         * The {@link HttpRequest} to be executed.
-         */
+        private final HttpHost target;
         private final HttpGet request;
-
-        /**
-         * Flag indicating if there were failures.
-         */
-        private boolean failed = false;
-
-        /**
-         * The latch that this runnable instance should wait on.
-         */
         private final CountDownLatch startGate;
-
-        /**
-         * The latch that this runnable instance should countdown on when the runnable is finished.
-         */
         private final CountDownLatch endGate;
 
-        /**
-         * The text returned from the HTTP server.
-         */
+        private boolean failed = false;
         private String text;
 
-        WorkerTask(final HttpClient client, final boolean identity, final CountDownLatch startGate, final CountDownLatch endGate) {
+        WorkerTask(final HttpClient client, final HttpHost target, final boolean identity, final CountDownLatch startGate, final CountDownLatch endGate) {
             this.client = client;
+            this.target = target;
             this.request = new HttpGet("/some-resource");
             if (identity) {
                 request.addHeader("Accept-Encoding", "identity");
@@ -448,11 +426,12 @@ public class TestContentCodings extends IntegrationTestBase {
         /**
          * {@inheritDoc}
          */
+        @Override
         public void run() {
             try {
                 startGate.await();
                 try {
-                    final HttpResponse response = client.execute(TestContentCodings.this.getServerHttp(), request);
+                    final HttpResponse response = client.execute(target, request);
                     text = EntityUtils.toString(response.getEntity());
                 } catch (final Exception e) {
                     failed = true;
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestCookie2Support.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestCookie2Support.java
deleted file mode 100644
index 6a4faef..0000000
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestCookie2Support.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.http.impl.client.integration;
-
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpException;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.ProtocolVersion;
-import org.apache.http.client.CookieStore;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.protocol.HttpClientContext;
-import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.SM;
-import org.apache.http.cookie.SetCookie2;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.BasicCookieStore;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.protocol.HttpRequestHandler;
-import org.apache.http.util.EntityUtils;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Cookie2 support tests.
- */
-public class TestCookie2Support extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-        this.httpclient = HttpClients.createDefault();
-    }
-
-    private static class CookieVer0Service implements HttpRequestHandler {
-
-        public void handle(
-                final HttpRequest request,
-                final HttpResponse response,
-                final HttpContext context) throws HttpException, IOException {
-            final ProtocolVersion httpversion = request.getRequestLine().getProtocolVersion();
-            response.setStatusLine(httpversion, HttpStatus.SC_OK);
-            response.addHeader(new BasicHeader("Set-Cookie", "name1=value1; path=/test"));
-            final StringEntity entity = new StringEntity("whatever");
-            response.setEntity(entity);
-        }
-
-    }
-
-    @Test
-    public void testCookieVersionSupportHeader1() throws Exception {
-        this.localServer.register("*", new CookieVer0Service());
-
-        final CookieStore cookieStore = new BasicCookieStore();
-        final HttpClientContext context = HttpClientContext.create();
-        context.setCookieStore(cookieStore);
-
-        final HttpGet httpget = new HttpGet("/test/");
-
-        final HttpResponse response1 = this.httpclient.execute(getServerHttp(), httpget, context);
-        final HttpEntity e1 = response1.getEntity();
-        EntityUtils.consume(e1);
-
-        final List<Cookie> cookies = cookieStore.getCookies();
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(1, cookies.size());
-
-        final HttpResponse response2 = this.httpclient.execute(getServerHttp(), httpget, context);
-        final HttpEntity e2 = response2.getEntity();
-        EntityUtils.consume(e2);
-
-        final HttpRequest reqWrapper = context.getRequest();
-
-        final Header cookiesupport = reqWrapper.getFirstHeader("Cookie2");
-        Assert.assertNotNull(cookiesupport);
-        Assert.assertEquals("$Version=1", cookiesupport.getValue());
-    }
-
-    private static class CookieVer1Service implements HttpRequestHandler {
-
-        public void handle(
-                final HttpRequest request,
-                final HttpResponse response,
-                final HttpContext context) throws HttpException, IOException {
-            final ProtocolVersion httpversion = request.getRequestLine().getProtocolVersion();
-            response.setStatusLine(httpversion, HttpStatus.SC_OK);
-            response.addHeader(new BasicHeader("Set-Cookie", "name1=value1; Path=\"/test\"; Version=1"));
-            response.addHeader(new BasicHeader("Set-Cookie2", "name2=value2; Path=\"/test\"; Version=1"));
-            final StringEntity entity = new StringEntity("whatever");
-            response.setEntity(entity);
-        }
-
-    }
-
-    @Test
-    public void testCookieVersionSupportHeader2() throws Exception {
-        this.localServer.register("*", new CookieVer1Service());
-
-        final CookieStore cookieStore = new BasicCookieStore();
-        final HttpClientContext context = HttpClientContext.create();
-        context.setCookieStore(cookieStore);
-
-        final HttpGet httpget = new HttpGet("/test/");
-
-        final HttpResponse response1 = this.httpclient.execute(getServerHttp(), httpget, context);
-        final HttpEntity e1 = response1.getEntity();
-        EntityUtils.consume(e1);
-
-        final List<Cookie> cookies = cookieStore.getCookies();
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(2, cookies.size());
-
-        final HttpResponse response2 = this.httpclient.execute(getServerHttp(), httpget, context);
-        final HttpEntity e2 = response2.getEntity();
-        EntityUtils.consume(e2);
-
-        final HttpRequest reqWrapper = context.getRequest();
-
-        final Header cookiesupport = reqWrapper.getFirstHeader(SM.COOKIE2);
-        Assert.assertNotNull(cookiesupport);
-        Assert.assertEquals("$Version=1", cookiesupport.getValue());
-    }
-
-    private static class CookieVer2Service implements HttpRequestHandler {
-
-        public void handle(
-                final HttpRequest request,
-                final HttpResponse response,
-                final HttpContext context) throws HttpException, IOException {
-            final ProtocolVersion httpversion = request.getRequestLine().getProtocolVersion();
-            response.setStatusLine(httpversion, HttpStatus.SC_OK);
-            response.addHeader(new BasicHeader("Set-Cookie2", "name2=value2; Path=\"/test\"; Version=2"));
-            final StringEntity entity = new StringEntity("whatever");
-            response.setEntity(entity);
-        }
-
-    }
-
-    @Test
-    public void testCookieVersionSupportHeader3() throws Exception {
-        this.localServer.register("*", new CookieVer2Service());
-
-        final CookieStore cookieStore = new BasicCookieStore();
-        final HttpClientContext context = HttpClientContext.create();
-        context.setCookieStore(cookieStore);
-
-        final HttpGet httpget = new HttpGet("/test/");
-
-        final HttpResponse response1 = this.httpclient.execute(getServerHttp(), httpget, context);
-        final HttpEntity e1 = response1.getEntity();
-        EntityUtils.consume(e1);
-
-        final List<Cookie> cookies = cookieStore.getCookies();
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(1, cookies.size());
-
-        final HttpResponse response2 = this.httpclient.execute(getServerHttp(), httpget, context);
-        final HttpEntity e2 = response2.getEntity();
-        EntityUtils.consume(e2);
-
-        final HttpRequest reqWrapper = context.getRequest();
-
-        final Header cookiesupport = reqWrapper.getFirstHeader("Cookie2");
-        Assert.assertNotNull(cookiesupport);
-        Assert.assertEquals("$Version=1", cookiesupport.getValue());
-    }
-
-    private static class SetCookieVersionMixService implements HttpRequestHandler {
-
-        public void handle(
-                final HttpRequest request,
-                final HttpResponse response,
-                final HttpContext context) throws HttpException, IOException {
-            final ProtocolVersion httpversion = request.getRequestLine().getProtocolVersion();
-            response.setStatusLine(httpversion, HttpStatus.SC_OK);
-            response.addHeader(new BasicHeader("Set-Cookie", "name=wrong; Path=/test"));
-            response.addHeader(new BasicHeader("Set-Cookie2", "name=right; Path=\"/test\"; Version=1"));
-            final StringEntity entity = new StringEntity("whatever");
-            response.setEntity(entity);
-        }
-
-    }
-
-    @Test
-    public void testSetCookieVersionMix() throws Exception {
-        this.localServer.register("*", new SetCookieVersionMixService());
-
-        final CookieStore cookieStore = new BasicCookieStore();
-        final HttpClientContext context = HttpClientContext.create();
-        context.setCookieStore(cookieStore);
-
-        final HttpGet httpget = new HttpGet("/test/");
-
-        final HttpResponse response1 = this.httpclient.execute(getServerHttp(), httpget, context);
-        final HttpEntity e1 = response1.getEntity();
-        EntityUtils.consume(e1);
-
-        final List<Cookie> cookies = cookieStore.getCookies();
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(1, cookies.size());
-        Assert.assertEquals("right", cookies.get(0).getValue());
-        Assert.assertTrue(cookies.get(0) instanceof SetCookie2);
-    }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestCookieVirtualHost.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestCookieVirtualHost.java
index ae3f639..60a8a9d 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestCookieVirtualHost.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestCookieVirtualHost.java
@@ -30,42 +30,35 @@ import java.io.IOException;
 import java.net.URI;
 import java.util.List;
 
-import org.apache.http.HttpEntity;
 import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
 import org.apache.http.client.CookieStore;
+import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.cookie.Cookie;
 import org.apache.http.impl.client.BasicCookieStore;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.localserver.LocalTestServer;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * This class tests cookie matching when using Virtual Host.
  */
-public class TestCookieVirtualHost extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        this.localServer = new LocalTestServer(null, null);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-    }
+public class TestCookieVirtualHost extends LocalServerTestBase {
 
     @Test
     public void testCookieMatchingWithVirtualHosts() throws Exception {
-        this.localServer.register("*", new HttpRequestHandler() {
+        this.serverBootstrap.registerHandler("*", new HttpRequestHandler() {
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -106,12 +99,15 @@ public class TestCookieVirtualHost extends IntegrationTestBase {
                     response.setStatusLine(HttpVersion.HTTP_1_1,
                             HttpStatus.SC_OK);
                     break;
+                default:
+                    Assert.fail("Unexpected value: " + n);
+                    break;
                 }
             }
 
         });
 
-        this.httpclient = HttpClients.createDefault();
+        final HttpHost target = start();
 
         final CookieStore cookieStore = new BasicCookieStore();
         final HttpClientContext context = HttpClientContext.create();
@@ -121,10 +117,12 @@ public class TestCookieVirtualHost extends IntegrationTestBase {
         URI uri = new URI("http://app.mydomain.fr");
         HttpRequest httpRequest = new HttpGet(uri);
         httpRequest.addHeader("X-Request", "1");
-        final HttpResponse response1 = this.httpclient.execute(getServerHttp(),
-                httpRequest, context);
-        final HttpEntity e1 = response1.getEntity();
-        EntityUtils.consume(e1);
+        final CloseableHttpResponse response1 = this.httpclient.execute(target, httpRequest, context);
+        try {
+            EntityUtils.consume(response1.getEntity());
+        } finally {
+            response1.close();
+        }
 
         // We should have one cookie set on domain.
         final List<Cookie> cookies = cookieStore.getCookies();
@@ -136,19 +134,23 @@ public class TestCookieVirtualHost extends IntegrationTestBase {
         uri = new URI("http://app.mydomain.fr");
         httpRequest = new HttpGet(uri);
         httpRequest.addHeader("X-Request", "2");
-        final HttpResponse response2 = this.httpclient.execute(getServerHttp(),
-                httpRequest, context);
-        final HttpEntity e2 = response2.getEntity();
-        EntityUtils.consume(e2);
+        final CloseableHttpResponse response2 = this.httpclient.execute(target, httpRequest, context);
+        try {
+            EntityUtils.consume(response2.getEntity());
+        } finally {
+            response2.close();
+        }
 
         // Third request : Host header
         uri = new URI("http://app.mydomain.fr");
         httpRequest = new HttpGet(uri);
         httpRequest.addHeader("X-Request", "3");
-        final HttpResponse response3 = this.httpclient.execute(getServerHttp(),
-                httpRequest, context);
-        final HttpEntity e3 = response3.getEntity();
-        EntityUtils.consume(e3);
+        final CloseableHttpResponse response3 = this.httpclient.execute(target, httpRequest, context);
+        try {
+            EntityUtils.consume(response3.getEntity());
+        } finally {
+            response3.close();
+        }
     }
 
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java
index 8ba76be..eee9d36 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestIdleConnectionEviction.java
@@ -27,7 +27,6 @@
 
 package org.apache.http.impl.client.integration;
 
-import java.net.InetSocketAddress;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.http.HttpHost;
@@ -36,39 +35,24 @@ import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.HttpClientConnectionManager;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.impl.client.IdleConnectionEvictor;
 import org.apache.http.localserver.LocalServerTestBase;
-import org.apache.http.localserver.LocalTestServer;
 import org.apache.http.util.EntityUtils;
-import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class TestIdleConnectionEviction extends LocalServerTestBase {
 
-    @Before
-    public void setUp() throws Exception {
-        this.localServer = new LocalTestServer(null, null);
-        this.localServer.registerDefaultHandlers();
-        this.localServer.start();
-    }
-
     @Test
-    @Ignore("We have a concurrency bug in HttpCore which will be addressed after HttpClient 4.3.2 is released")
     public void testIdleConnectionEviction() throws Exception {
-        final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
-        cm.setDefaultMaxPerRoute(10);
-        cm.setMaxTotal(50);
+        this.connManager.setDefaultMaxPerRoute(10);
+        this.connManager.setMaxTotal(50);
 
-        final HttpClient httpclient = HttpClients.custom().setConnectionManager(cm).build();
+        final HttpHost target = start();
 
-        final IdleConnectionMonitor idleConnectionMonitor = new IdleConnectionMonitor(cm);
+        final IdleConnectionEvictor idleConnectionMonitor = new IdleConnectionEvictor(
+                this.connManager, 50, TimeUnit.MILLISECONDS);
         idleConnectionMonitor.start();
 
-        final InetSocketAddress address = this.localServer.getServiceAddress();
-        final HttpHost target = new HttpHost(address.getHostName(), address.getPort());
         final HttpGet httpget = new HttpGet("/random/1024");
         final WorkerThread[] workers = new WorkerThread[5];
         for (int i = 0; i < workers.length; i++) {
@@ -132,38 +116,4 @@ public class TestIdleConnectionEviction extends LocalServerTestBase {
 
     }
 
-    public static class IdleConnectionMonitor extends Thread {
-
-        private final HttpClientConnectionManager cm;
-        private volatile boolean shutdown;
-
-        public IdleConnectionMonitor(final HttpClientConnectionManager cm) {
-            super();
-            this.cm = cm;
-            setDaemon(true);
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!this.shutdown) {
-                    synchronized (this) {
-                        wait(250);
-                        this.cm.closeIdleConnections(1, TimeUnit.MILLISECONDS);
-                    }
-                }
-            } catch (final InterruptedException ex) {
-                // terminate
-            }
-        }
-
-        public void shutdown() {
-            this.shutdown = true;
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-
-    }
-
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestMalformedServerResponse.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestMalformedServerResponse.java
new file mode 100644
index 0000000..b18f8fc
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestMalformedServerResponse.java
@@ -0,0 +1,132 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.client.integration;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import org.apache.http.HttpConnectionFactory;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.DefaultBHttpServerConnection;
+import org.apache.http.localserver.LocalServerTestBase;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.util.EntityUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestMalformedServerResponse extends LocalServerTestBase {
+
+    static class BrokenServerConnection extends DefaultBHttpServerConnection {
+
+        public BrokenServerConnection(final int buffersize) {
+            super(buffersize);
+        }
+
+        @Override
+        public void sendResponseHeader(final HttpResponse response) throws HttpException, IOException {
+            super.sendResponseHeader(response);
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NO_CONTENT) {
+                response.setEntity(new StringEntity(
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n" +
+                        "garbage\ngarbage\n"));
+                sendResponseEntity(response);
+            }
+        }
+    }
+
+    static class BrokenServerConnectionFactory implements HttpConnectionFactory<DefaultBHttpServerConnection> {
+
+        @Override
+        public DefaultBHttpServerConnection createConnection(final Socket socket) throws IOException {
+            final BrokenServerConnection conn = new BrokenServerConnection(4096);
+            conn.bind(socket);
+            return conn;
+        }
+    }
+
+    @Test
+    public void testNoContentResponseWithGarbage() throws Exception {
+        this.serverBootstrap.setConnectionFactory(new BrokenServerConnectionFactory());
+        this.serverBootstrap.registerHandler("/nostuff", new HttpRequestHandler() {
+
+            @Override
+            public void handle(
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
+                response.setStatusCode(HttpStatus.SC_NO_CONTENT);
+            }
+
+        });
+        this.serverBootstrap.registerHandler("/stuff", new HttpRequestHandler() {
+
+            @Override
+            public void handle(
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
+                response.setStatusCode(HttpStatus.SC_OK);
+                response.setEntity(new StringEntity("Some important stuff"));
+            }
+
+        });
+
+        final HttpHost target = start();
+        final HttpGet get1 = new HttpGet("/nostuff");
+        final CloseableHttpResponse response1 = this.httpclient.execute(target, get1);
+        try {
+            Assert.assertEquals(HttpStatus.SC_NO_CONTENT, response1.getStatusLine().getStatusCode());
+            EntityUtils.consume(response1.getEntity());
+        } finally {
+            response1.close();
+        }
+        final HttpGet get2 = new HttpGet("/stuff");
+        final CloseableHttpResponse response2 = this.httpclient.execute(target, get2);
+        try {
+            Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
+            EntityUtils.consume(response2.getEntity());
+        } finally {
+            response2.close();
+        }
+    }
+
+}
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestMinimalClientRequestExecution.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestMinimalClientRequestExecution.java
index 001d4d5..203a29d 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestMinimalClientRequestExecution.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestMinimalClientRequestExecution.java
@@ -33,6 +33,7 @@ import java.util.Set;
 
 import org.apache.http.Header;
 import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
@@ -40,22 +41,17 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * Client protocol handling tests.
  */
-public class TestMinimalClientRequestExecution extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-    }
+public class TestMinimalClientRequestExecution extends LocalServerTestBase {
 
     private static class SimpleService implements HttpRequestHandler {
 
@@ -63,6 +59,7 @@ public class TestMinimalClientRequestExecution extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -75,13 +72,14 @@ public class TestMinimalClientRequestExecution extends IntegrationTestBase {
 
     @Test
     public void testNonCompliantURI() throws Exception {
-        this.localServer.register("*", new SimpleService());
+        this.serverBootstrap.registerHandler("*", new SimpleService());
         this.httpclient = HttpClients.createMinimal();
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
         for (int i = 0; i < 10; i++) {
             final HttpGet request = new HttpGet("/");
-            final HttpResponse response = this.httpclient.execute(getServerHttp(), request, context);
+            final HttpResponse response = this.httpclient.execute(target, request, context);
             EntityUtils.consume(response.getEntity());
             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
 
@@ -91,7 +89,7 @@ public class TestMinimalClientRequestExecution extends IntegrationTestBase {
             final Header[] headers = reqWrapper.getAllHeaders();
             final Set<String> headerSet = new HashSet<String>();
             for (final Header header: headers) {
-                headerSet.add(header.getName().toLowerCase(Locale.ENGLISH));
+                headerSet.add(header.getName().toLowerCase(Locale.ROOT));
             }
             Assert.assertEquals(3, headerSet.size());
             Assert.assertTrue(headerSet.contains("connection"));
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestRedirects.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestRedirects.java
index 9ae609d..ffa0ec4 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestRedirects.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestRedirects.java
@@ -51,28 +51,22 @@ import org.apache.http.client.utils.URIUtils;
 import org.apache.http.cookie.SM;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.BasicCookieStore;
-import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.cookie.BasicClientCookie;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.protocol.HTTP;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.UriHttpRequestHandlerMapper;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * Redirection test cases.
  */
-public class TestRedirects extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-        this.httpclient = HttpClients.createDefault();
-    }
+public class TestRedirects extends LocalServerTestBase {
 
     private static class BasicRedirectService implements HttpRequestHandler {
 
@@ -87,12 +81,16 @@ public class TestRedirects extends IntegrationTestBase {
             this(-1);
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
                 final HttpContext context) throws HttpException, IOException {
             final HttpInetConnection conn = (HttpInetConnection) context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
-            final String localhost = conn.getLocalAddress().getHostName();
+            String localhost = conn.getLocalAddress().getHostName();
+            if (localhost.equals("127.0.0.1")) {
+                localhost = "localhost";
+            }
             final int port = conn.getLocalPort();
             final String uri = request.getRequestLine().getUri();
             if (uri.equals("/oldlocation/")) {
@@ -117,6 +115,7 @@ public class TestRedirects extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -140,6 +139,7 @@ public class TestRedirects extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -164,6 +164,7 @@ public class TestRedirects extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -188,6 +189,7 @@ public class TestRedirects extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -212,6 +214,7 @@ public class TestRedirects extends IntegrationTestBase {
             this.url = redirectUrl;
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -232,10 +235,11 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect300() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        this.serverBootstrap.registerHandler("*",
                 new BasicRedirectService(HttpStatus.SC_MULTIPLE_CHOICES));
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -254,10 +258,11 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect301() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        this.serverBootstrap.registerHandler("*",
                 new BasicRedirectService(HttpStatus.SC_MOVED_PERMANENTLY));
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -282,10 +287,11 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect302() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        this.serverBootstrap.registerHandler("*",
                 new BasicRedirectService(HttpStatus.SC_MOVED_TEMPORARILY));
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -303,9 +309,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect302NoLocation() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new HttpRequestHandler() {
+        this.serverBootstrap.registerHandler("*", new HttpRequestHandler() {
 
+            @Override
             public void handle(
                     final HttpRequest request,
                     final HttpResponse response,
@@ -315,6 +321,8 @@ public class TestRedirects extends IntegrationTestBase {
 
         });
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -332,10 +340,11 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect303() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        this.serverBootstrap.registerHandler("*",
                 new BasicRedirectService(HttpStatus.SC_SEE_OTHER));
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -353,10 +362,11 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect304() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        this.serverBootstrap.registerHandler("*",
                 new BasicRedirectService(HttpStatus.SC_NOT_MODIFIED));
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -372,9 +382,10 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect305() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        this.serverBootstrap.registerHandler("*",
                 new BasicRedirectService(HttpStatus.SC_USE_PROXY));
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -390,10 +401,11 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testBasicRedirect307() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        this.serverBootstrap.registerHandler("*",
                 new BasicRedirectService(HttpStatus.SC_TEMPORARY_REDIRECT));
 
+        final HttpHost target = start();
+
         final HttpClientContext context = HttpClientContext.create();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -411,8 +423,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testMaxRedirectCheck() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new CircularRedirectService());
+        this.serverBootstrap.registerHandler("*", new CircularRedirectService());
+
+        final HttpHost target = start();
 
         final RequestConfig config = RequestConfig.custom()
             .setCircularRedirectsAllowed(true)
@@ -431,8 +444,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testCircularRedirect() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new CircularRedirectService());
+        this.serverBootstrap.registerHandler("*", new CircularRedirectService());
+
+        final HttpHost target = start();
 
         final RequestConfig config = RequestConfig.custom()
             .setCircularRedirectsAllowed(false)
@@ -450,8 +464,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testRepeatRequest() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new RomeRedirectService());
+        this.serverBootstrap.registerHandler("*", new RomeRedirectService());
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
@@ -477,8 +492,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testRepeatRequestRedirect() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new RomeRedirectService());
+        this.serverBootstrap.registerHandler("*", new RomeRedirectService());
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
@@ -505,8 +521,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testDifferentRequestSameRedirect() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new RomeRedirectService());
+        this.serverBootstrap.registerHandler("*", new RomeRedirectService());
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
@@ -533,8 +550,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testPostNoRedirect() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new BasicRedirectService());
+        this.serverBootstrap.registerHandler("*", new BasicRedirectService());
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
@@ -553,8 +571,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testPostRedirectSeeOther() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new BasicRedirectService(HttpStatus.SC_SEE_OTHER));
+        this.serverBootstrap.registerHandler("*", new BasicRedirectService(HttpStatus.SC_SEE_OTHER));
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
@@ -573,8 +592,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testRelativeRedirect() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new RelativeRedirectService());
+        this.serverBootstrap.registerHandler("*", new RelativeRedirectService());
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
@@ -595,8 +615,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testRelativeRedirect2() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new RelativeRedirectService2());
+        this.serverBootstrap.registerHandler("*", new RelativeRedirectService2());
+
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
@@ -617,8 +638,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testRejectRelativeRedirect() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new RelativeRedirectService());
+        this.serverBootstrap.registerHandler("*", new RelativeRedirectService());
+
+        final HttpHost target = start();
 
         final RequestConfig config = RequestConfig.custom().setRelativeRedirectsAllowed(false).build();
         final HttpGet httpget = new HttpGet("/oldlocation/");
@@ -633,8 +655,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testRejectBogusRedirectLocation() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*", new BogusRedirectService("xxx://bogus"));
+        this.serverBootstrap.registerHandler("*", new BogusRedirectService("xxx://bogus"));
+
+        final HttpHost target = start();
 
         final HttpGet httpget = new HttpGet("/oldlocation/");
 
@@ -649,8 +672,12 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test(expected=ClientProtocolException.class)
     public void testRejectInvalidRedirectLocation() throws Exception {
-        final HttpHost target = getServerHttp();
-        this.localServer.register("*",
+        final UriHttpRequestHandlerMapper reqistry = new UriHttpRequestHandlerMapper();
+        this.serverBootstrap.setHandlerMapper(reqistry);
+
+        final HttpHost target = start();
+
+        reqistry.register("*",
                 new BogusRedirectService("http://" + target.toHostString() +
                         "/newlocation/?p=I have spaces"));
 
@@ -666,9 +693,9 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testRedirectWithCookie() throws Exception {
-        final HttpHost target = getServerHttp();
+        this.serverBootstrap.registerHandler("*", new BasicRedirectService());
 
-        this.localServer.register("*", new BasicRedirectService());
+        final HttpHost target = start();
 
         final CookieStore cookieStore = new BasicCookieStore();
 
@@ -682,7 +709,6 @@ public class TestRedirects extends IntegrationTestBase {
         context.setCookieStore(cookieStore);
         final HttpGet httpget = new HttpGet("/oldlocation/");
 
-
         final HttpResponse response = this.httpclient.execute(target, httpget, context);
         EntityUtils.consume(response.getEntity());
 
@@ -697,12 +723,11 @@ public class TestRedirects extends IntegrationTestBase {
 
     @Test
     public void testDefaultHeadersRedirect() throws Exception {
-        this.httpclient = HttpClients.custom()
-            .setDefaultHeaders(Arrays.asList(new BasicHeader(HTTP.USER_AGENT, "my-test-client")))
-            .build();
-        final HttpHost target = getServerHttp();
+        this.clientBuilder.setDefaultHeaders(Arrays.asList(new BasicHeader(HTTP.USER_AGENT, "my-test-client")));
+
+        this.serverBootstrap.registerHandler("*", new BasicRedirectService());
 
-        this.localServer.register("*", new BasicRedirectService());
+        final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
 
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestSPNegoScheme.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestSPNegoScheme.java
index 6ec81cb..f638031 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestSPNegoScheme.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestSPNegoScheme.java
@@ -47,6 +47,7 @@ import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.auth.SPNegoScheme;
 import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
@@ -57,7 +58,6 @@ import org.ietf.jgss.GSSManager;
 import org.ietf.jgss.GSSName;
 import org.ietf.jgss.Oid;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Matchers;
 import org.mockito.Mockito;
@@ -65,18 +65,14 @@ import org.mockito.Mockito;
 /**
  * Tests for {@link SPNegoScheme}.
  */
-public class TestSPNegoScheme extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-    }
+public class TestSPNegoScheme extends LocalServerTestBase {
 
     /**
      * This service will continue to ask for authentication.
      */
     private static class PleaseNegotiateService implements HttpRequestHandler {
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -122,10 +118,12 @@ public class TestSPNegoScheme extends IntegrationTestBase {
 
     private static class UseJaasCredentials implements Credentials {
 
+        @Override
         public String getPassword() {
             return null;
         }
 
+        @Override
         public Principal getUserPrincipal() {
             return null;
         }
@@ -140,6 +138,7 @@ public class TestSPNegoScheme extends IntegrationTestBase {
             scheme = new NegotiateSchemeWithMockGssManager();
         }
 
+        @Override
         public AuthScheme create(final HttpContext context) {
             return scheme;
         }
@@ -152,10 +151,8 @@ public class TestSPNegoScheme extends IntegrationTestBase {
      */
     @Test
     public void testDontTryToAuthenticateEndlessly() throws Exception {
-        final int port = this.localServer.getServiceAddress().getPort();
-        this.localServer.register("*", new PleaseNegotiateService());
-
-        final HttpHost target = new HttpHost("localhost", port);
+        this.serverBootstrap.registerHandler("*", new PleaseNegotiateService());
+        final HttpHost target = start();
 
         final AuthSchemeProvider nsf = new NegotiateSchemeProviderWithMockGssManager();
         final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
@@ -184,10 +181,8 @@ public class TestSPNegoScheme extends IntegrationTestBase {
      */
     @Test
     public void testNoTokenGeneratedError() throws Exception {
-        final int port = this.localServer.getServiceAddress().getPort();
-        this.localServer.register("*", new PleaseNegotiateService());
-
-        final HttpHost target = new HttpHost("localhost", port);
+        this.serverBootstrap.registerHandler("*", new PleaseNegotiateService());
+        final HttpHost target = start();
 
         final AuthSchemeProvider nsf = new NegotiateSchemeProviderWithMockGssManager();
 
diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestStatefulConnManagement.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestStatefulConnManagement.java
index 63fcdbb..e6b8739 100644
--- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestStatefulConnManagement.java
+++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestStatefulConnManagement.java
@@ -39,25 +39,18 @@ import org.apache.http.client.UserTokenHandler;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.localserver.LocalServerTestBase;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.util.EntityUtils;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * Test cases for state-ful connections.
  */
-public class TestStatefulConnManagement extends IntegrationTestBase {
-
-    @Before
-    public void setUp() throws Exception {
-        startServer();
-    }
+public class TestStatefulConnManagement extends LocalServerTestBase {
 
     private static class SimpleService implements HttpRequestHandler {
 
@@ -65,6 +58,7 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
             super();
         }
 
+        @Override
         public void handle(
                 final HttpRequest request,
                 final HttpResponse response,
@@ -81,28 +75,23 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
         final int workerCount = 5;
         final int requestCount = 5;
 
-        final int port = this.localServer.getServiceAddress().getPort();
-        this.localServer.register("*", new SimpleService());
+        this.serverBootstrap.registerHandler("*", new SimpleService());
 
-        final HttpHost target = new HttpHost("localhost", port);
-
-        final PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
-        mgr.setMaxTotal(workerCount);
-        mgr.setDefaultMaxPerRoute(workerCount);
+        this.connManager.setMaxTotal(workerCount);
+        this.connManager.setDefaultMaxPerRoute(workerCount);
 
         final UserTokenHandler userTokenHandler = new UserTokenHandler() {
 
+            @Override
             public Object getUserToken(final HttpContext context) {
                 final String id = (String) context.getAttribute("user");
                 return id;
             }
 
         };
+        this.clientBuilder.setUserTokenHandler(userTokenHandler);
 
-        this.httpclient = HttpClients.custom()
-            .setConnectionManager(mgr)
-            .setUserTokenHandler(userTokenHandler)
-            .build();
+        final HttpHost target = start();
 
         final HttpClientContext[] contexts = new HttpClientContext[workerCount];
         final HttpWorker[] workers = new HttpWorker[workerCount];
@@ -212,32 +201,29 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
 
         final int maxConn = 2;
 
-        final int port = this.localServer.getServiceAddress().getPort();
-        this.localServer.register("*", new SimpleService());
+        this.serverBootstrap.registerHandler("*", new SimpleService());
 
-        // We build a client with 2 max active // connections, and 2 max per route.
-        final PoolingHttpClientConnectionManager connMngr = new PoolingHttpClientConnectionManager();
-        connMngr.setMaxTotal(maxConn);
-        connMngr.setDefaultMaxPerRoute(maxConn);
+        this.connManager.setMaxTotal(maxConn);
+        this.connManager.setDefaultMaxPerRoute(maxConn);
 
         final UserTokenHandler userTokenHandler = new UserTokenHandler() {
 
+            @Override
             public Object getUserToken(final HttpContext context) {
                 return context.getAttribute("user");
             }
 
         };
 
-        this.httpclient = HttpClients.custom()
-            .setConnectionManager(connMngr)
-            .setUserTokenHandler(userTokenHandler)
-            .build();
+        this.clientBuilder.setUserTokenHandler(userTokenHandler);
+
+        final HttpHost target = start();
 
         // Bottom of the pool : a *keep alive* connection to Route 1.
         final HttpContext context1 = new BasicHttpContext();
         context1.setAttribute("user", "stuff");
         final HttpResponse response1 = this.httpclient.execute(
-                new HttpHost("localhost", port), new HttpGet("/"), context1);
+                target, new HttpGet("/"), context1);
         EntityUtils.consume(response1.getEntity());
 
         // The ConnPoolByRoute now has 1 free connection, out of 2 max
@@ -250,7 +236,7 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
         // Send it to another route. Must be a keepalive.
         final HttpContext context2 = new BasicHttpContext();
         final HttpResponse response2 = this.httpclient.execute(
-                new HttpHost("127.0.0.1", port), new HttpGet("/"), context2);
+                new HttpHost("127.0.0.1", this.server.getLocalPort()), new HttpGet("/"), context2);
         EntityUtils.consume(response2.getEntity());
         // ConnPoolByRoute now has 2 free connexions, out of its 2 max.
         // The [localhost][stuff] RouteSpcfcPool is the same as earlier
@@ -265,7 +251,7 @@ public class TestStatefulConnManagement extends IntegrationTestBase {
         // When this happens, the RouteSpecificPool becomes empty.
         final HttpContext context3 = new BasicHttpContext();
         final HttpResponse response3 = this.httpclient.execute(
-                new HttpHost("localhost", port), new HttpGet("/"), context3);
+                target, new HttpGet("/"), context3);
 
         // If the ConnPoolByRoute did not behave coherently with the RouteSpecificPool
         // this may fail. Ex : if the ConnPool discared the route pool because it was empty,
diff --git a/httpclient/src/test/java/org/apache/http/impl/conn/SessionInputBufferMock.java b/httpclient/src/test/java/org/apache/http/impl/conn/SessionInputBufferMock.java
index cab6287..15c9f20 100644
--- a/httpclient/src/test/java/org/apache/http/impl/conn/SessionInputBufferMock.java
+++ b/httpclient/src/test/java/org/apache/http/impl/conn/SessionInputBufferMock.java
@@ -30,7 +30,6 @@ package org.apache.http.impl.conn;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
 
@@ -99,8 +98,8 @@ public class SessionInputBufferMock extends SessionInputBufferImpl {
 
     public SessionInputBufferMock(
             final String s,
-            final Charset charset) throws UnsupportedEncodingException {
-        this(s.getBytes(charset.name()), charset);
+            final Charset charset) {
+        this(s.getBytes(charset), charset);
     }
 
     @Override
diff --git a/httpclient/src/test/java/org/apache/http/impl/conn/TestBasicHttpClientConnectionManager.java b/httpclient/src/test/java/org/apache/http/impl/conn/TestBasicHttpClientConnectionManager.java
index da6419d..b64bb7e 100644
--- a/httpclient/src/test/java/org/apache/http/impl/conn/TestBasicHttpClientConnectionManager.java
+++ b/httpclient/src/test/java/org/apache/http/impl/conn/TestBasicHttpClientConnectionManager.java
@@ -85,7 +85,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testLeaseReleaseNonReusable() throws Exception {
-        final HttpHost target = new HttpHost("localhost");
+        final HttpHost target = new HttpHost("localhost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(
@@ -112,7 +112,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testLeaseReleaseReusable() throws Exception {
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
@@ -142,7 +142,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testLeaseReleaseReusableWithState() throws Exception {
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(
@@ -173,7 +173,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testLeaseDifferentRoute() throws Exception {
-        final HttpHost target1 = new HttpHost("somehost");
+        final HttpHost target1 = new HttpHost("somehost", 80);
         final HttpRoute route1 = new HttpRoute(target1);
 
         Mockito.when(connFactory.create(
@@ -193,7 +193,7 @@ public class TestBasicHttpClientConnectionManager {
         Assert.assertEquals(route1, mgr.getRoute());
         Assert.assertEquals(null, mgr.getState());
 
-        final HttpHost target2 = new HttpHost("otherhost");
+        final HttpHost target2 = new HttpHost("otherhost", 80);
         final HttpRoute route2 = new HttpRoute(target2);
         final ConnectionRequest connRequest2 = mgr.requestConnection(route2, null);
         final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
@@ -209,7 +209,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testLeaseExpired() throws Exception {
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(
@@ -259,7 +259,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testShutdown() throws Exception {
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(
@@ -297,7 +297,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testCloseExpired() throws Exception {
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(
@@ -326,7 +326,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testCloseIdle() throws Exception {
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(
@@ -355,7 +355,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test(expected=IllegalStateException.class)
     public void testAlreadyLeased() throws Exception {
-        final HttpHost target = new HttpHost("somehost");
+        final HttpHost target = new HttpHost("somehost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(connFactory.create(
@@ -372,7 +372,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testTargetConnect() throws Exception {
-        final HttpHost target = new HttpHost("somehost", -1, "https");
+        final HttpHost target = new HttpHost("somehost", 443, "https");
         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
         final HttpRoute route = new HttpRoute(target, local, true);
@@ -415,7 +415,7 @@ public class TestBasicHttpClientConnectionManager {
 
     @Test
     public void testProxyConnectAndUpgrade() throws Exception {
-        final HttpHost target = new HttpHost("somehost", -1, "https");
+        final HttpHost target = new HttpHost("somehost", 443, "https");
         final HttpHost proxy = new HttpHost("someproxy", 8080);
         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
diff --git a/httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionOperator.java b/httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionOperator.java
index 41377e2..42aa337 100644
--- a/httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionOperator.java
+++ b/httpclient/src/test/java/org/apache/http/impl/conn/TestHttpClientConnectionOperator.java
@@ -60,7 +60,7 @@ public class TestHttpClientConnectionOperator {
     private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
     private SchemePortResolver schemePortResolver;
     private DnsResolver dnsResolver;
-    private HttpClientConnectionOperator connectionOperator;
+    private DefaultHttpClientConnectionOperator connectionOperator;
 
     @SuppressWarnings("unchecked")
     @Before
@@ -72,7 +72,7 @@ public class TestHttpClientConnectionOperator {
         socketFactoryRegistry = Mockito.mock(Lookup.class);
         schemePortResolver = Mockito.mock(SchemePortResolver.class);
         dnsResolver = Mockito.mock(DnsResolver.class);
-        connectionOperator = new HttpClientConnectionOperator(
+        connectionOperator = new DefaultHttpClientConnectionOperator(
                 socketFactoryRegistry, schemePortResolver, dnsResolver);
     }
 
@@ -207,6 +207,38 @@ public class TestHttpClientConnectionOperator {
     }
 
     @Test
+    public void testConnectExplicitAddress() throws Exception {
+        final HttpContext context = new BasicHttpContext();
+        final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 0});
+        final InetAddress ip = InetAddress.getByAddress(new byte[] {127, 0, 0, 23});
+        final HttpHost host = new HttpHost(ip);
+
+        Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
+        Mockito.when(schemePortResolver.resolve(host)).thenReturn(80);
+        Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
+        Mockito.when(plainSocketFactory.connectSocket(
+                Mockito.anyInt(),
+                Mockito.<Socket>any(),
+                Mockito.<HttpHost>any(),
+                Mockito.<InetSocketAddress>any(),
+                Mockito.<InetSocketAddress>any(),
+                Mockito.<HttpContext>any())).thenReturn(socket);
+
+        final InetSocketAddress localAddress = new InetSocketAddress(local, 0);
+        connectionOperator.connect(conn, host, localAddress, 1000, SocketConfig.DEFAULT, context);
+
+        Mockito.verify(plainSocketFactory).connectSocket(
+                1000,
+                socket,
+                host,
+                new InetSocketAddress(ip, 80),
+                localAddress,
+                context);
+        Mockito.verify(dnsResolver, Mockito.never()).resolve(Mockito.anyString());
+        Mockito.verify(conn, Mockito.times(2)).bind(socket);
+    }
+
+    @Test
     public void testUpgrade() throws Exception {
         final HttpContext context = new BasicHttpContext();
         final HttpHost host = new HttpHost("somehost", -1, "https");
diff --git a/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java b/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java
index a2abfdb..5b379d3 100644
--- a/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java
+++ b/httpclient/src/test/java/org/apache/http/impl/conn/TestPoolingHttpClientConnectionManager.java
@@ -60,7 +60,7 @@ import org.mockito.MockitoAnnotations;
 /**
  * {@link PoolingHttpClientConnectionManager} tests.
  */
- at SuppressWarnings({"boxing","static-access"}) // test code
+ at SuppressWarnings({"boxing","static-access","resource"}) // test code
 public class TestPoolingHttpClientConnectionManager {
 
     @Mock
@@ -92,7 +92,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test
     public void testLeaseRelease() throws Exception {
-        final HttpHost target = new HttpHost("localhost");
+        final HttpHost target = new HttpHost("localhost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
@@ -121,7 +121,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test
     public void testReleaseRouteIncomplete() throws Exception {
-        final HttpHost target = new HttpHost("localhost");
+        final HttpHost target = new HttpHost("localhost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
@@ -149,7 +149,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test(expected=InterruptedException.class)
     public void testLeaseFutureCancelled() throws Exception {
-        final HttpHost target = new HttpHost("localhost");
+        final HttpHost target = new HttpHost("localhost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
@@ -166,7 +166,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test(expected=ConnectionPoolTimeoutException.class)
     public void testLeaseFutureTimeout() throws Exception {
-        final HttpHost target = new HttpHost("localhost");
+        final HttpHost target = new HttpHost("localhost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
@@ -179,7 +179,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test
     public void testReleaseReusable() throws Exception {
-        final HttpHost target = new HttpHost("localhost");
+        final HttpHost target = new HttpHost("localhost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         final CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
@@ -205,7 +205,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test
     public void testReleaseNonReusable() throws Exception {
-        final HttpHost target = new HttpHost("localhost");
+        final HttpHost target = new HttpHost("localhost", 80);
         final HttpRoute route = new HttpRoute(target);
 
         final CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
@@ -231,7 +231,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test
     public void testTargetConnect() throws Exception {
-        final HttpHost target = new HttpHost("somehost", -1, "https");
+        final HttpHost target = new HttpHost("somehost", 443, "https");
         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
         final InetAddress local = InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
         final HttpRoute route = new HttpRoute(target, local, true);
@@ -280,7 +280,7 @@ public class TestPoolingHttpClientConnectionManager {
 
     @Test
     public void testProxyConnectAndUpgrade() throws Exception {
-        final HttpHost target = new HttpHost("somehost", -1, "https");
+        final HttpHost target = new HttpHost("somehost", 443, "https");
         final HttpHost proxy = new HttpHost("someproxy", 8080);
         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
@@ -301,7 +301,7 @@ public class TestPoolingHttpClientConnectionManager {
 
         final ConnectionSocketFactory plainsf = Mockito.mock(ConnectionSocketFactory.class);
         final LayeredConnectionSocketFactory sslsf = Mockito.mock(LayeredConnectionSocketFactory.class);
-        final Socket socket = Mockito.mock(Socket.class);
+        final Socket mockSock = Mockito.mock(Socket.class);
         final HttpClientContext context = HttpClientContext.create();
         final SocketConfig sconfig = SocketConfig.custom().build();
         final ConnectionConfig cconfig = ConnectionConfig.custom().build();
@@ -314,31 +314,31 @@ public class TestPoolingHttpClientConnectionManager {
         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainsf);
         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslsf);
-        Mockito.when(plainsf.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
+        Mockito.when(plainsf.createSocket(Mockito.<HttpContext>any())).thenReturn(mockSock);
         Mockito.when(plainsf.connectSocket(
                 Mockito.anyInt(),
-                Mockito.eq(socket),
+                Mockito.eq(mockSock),
                 Mockito.<HttpHost>any(),
                 Mockito.<InetSocketAddress>any(),
                 Mockito.<InetSocketAddress>any(),
-                Mockito.<HttpContext>any())).thenReturn(socket);
+                Mockito.<HttpContext>any())).thenReturn(mockSock);
 
         mgr.connect(conn1, route, 123, context);
 
         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
         Mockito.verify(plainsf, Mockito.times(1)).createSocket(context);
-        Mockito.verify(plainsf, Mockito.times(1)).connectSocket(123, socket, proxy,
+        Mockito.verify(plainsf, Mockito.times(1)).connectSocket(123, mockSock, proxy,
                 new InetSocketAddress(remote, 8080),
                 new InetSocketAddress(local, 0), context);
 
-        Mockito.when(conn.getSocket()).thenReturn(socket);
+        Mockito.when(conn.getSocket()).thenReturn(mockSock);
 
         mgr.upgrade(conn1, route, context);
 
         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
         Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
-                socket, "somehost", 8443, context);
+                mockSock, "somehost", 8443, context);
 
         mgr.routeComplete(conn1, route, context);
     }
diff --git a/httpclient/src/test/java/org/apache/http/impl/conn/TestSystemDefaultRoutePlanner.java b/httpclient/src/test/java/org/apache/http/impl/conn/TestSystemDefaultRoutePlanner.java
index a7d6151..38920ba 100644
--- a/httpclient/src/test/java/org/apache/http/impl/conn/TestSystemDefaultRoutePlanner.java
+++ b/httpclient/src/test/java/org/apache/http/impl/conn/TestSystemDefaultRoutePlanner.java
@@ -46,12 +46,13 @@ import org.apache.http.protocol.HttpContext;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Matchers;
 import org.mockito.Mockito;
 
 /**
  * Tests for {@link SystemDefaultRoutePlanner}.
  */
- at SuppressWarnings({"boxing","static-access"}) // test code
+ at SuppressWarnings("boxing") // test code
 public class TestSystemDefaultRoutePlanner {
 
     private SchemePortResolver schemePortResolver;
@@ -76,7 +77,7 @@ public class TestSystemDefaultRoutePlanner {
         Assert.assertEquals(target, route.getTargetHost());
         Assert.assertEquals(1, route.getHopCount());
         Assert.assertFalse(route.isSecure());
-        Mockito.verify(schemePortResolver, Mockito.never()).resolve(Mockito.<HttpHost>any());
+        Mockito.verify(schemePortResolver, Mockito.never()).resolve(Matchers.<HttpHost>any());
     }
 
     @Test
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java
deleted file mode 100644
index d08eaa2..0000000
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.http.impl.cookie;
-
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.http.Header;
-import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieAttributeHandler;
-import org.apache.http.cookie.CookieOrigin;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.cookie.SetCookie;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class TestAbstractCookieSpec {
-
-    private static class DummyCookieSpec extends AbstractCookieSpec {
-
-        public List<Header> formatCookies(final List<Cookie> cookies) {
-            return null;
-        }
-
-        public boolean match(final Cookie cookie, final CookieOrigin origin) {
-            return true;
-        }
-
-        public List<Cookie> parse(final Header header, final CookieOrigin origin) throws MalformedCookieException {
-            return null;
-        }
-
-        public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
-        }
-
-        public int getVersion() {
-            return 0;
-        }
-
-        public Header getVersionHeader() {
-            return null;
-        }
-
-    }
-
-    private static class DummyCookieAttribHandler implements CookieAttributeHandler {
-
-        public boolean match(final Cookie cookie, final CookieOrigin origin) {
-            return true;
-        }
-
-        public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
-        }
-
-        public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
-        }
-
-    }
-
-    @Test
-    public void testSimpleRegisterAndGet() {
-        final CookieAttributeHandler h1 = new DummyCookieAttribHandler();
-        final CookieAttributeHandler h2 = new DummyCookieAttribHandler();
-
-        final AbstractCookieSpec cookiespec = new DummyCookieSpec();
-        cookiespec.registerAttribHandler("this", h1);
-        cookiespec.registerAttribHandler("that", h2);
-        cookiespec.registerAttribHandler("thistoo", h1);
-        cookiespec.registerAttribHandler("thattoo", h2);
-
-        Assert.assertTrue(h1 == cookiespec.getAttribHandler("this"));
-        Assert.assertTrue(h2 == cookiespec.getAttribHandler("that"));
-        Assert.assertTrue(h1 == cookiespec.getAttribHandler("thistoo"));
-        Assert.assertTrue(h2 == cookiespec.getAttribHandler("thattoo"));
-
-        final Iterator<CookieAttributeHandler> it = cookiespec.getAttribHandlers().iterator();
-        Assert.assertNotNull(it.next());
-        Assert.assertNotNull(it.next());
-        Assert.assertNotNull(it.next());
-        Assert.assertNotNull(it.next());
-        Assert.assertFalse(it.hasNext());
-    }
-
-    @Test(expected=IllegalStateException.class)
-    public void testInvalidHandler() {
-        final CookieAttributeHandler h1 = new DummyCookieAttribHandler();
-        final CookieAttributeHandler h2 = new DummyCookieAttribHandler();
-
-        final AbstractCookieSpec cookiespec = new DummyCookieSpec();
-        cookiespec.registerAttribHandler("this", h1);
-        cookiespec.registerAttribHandler("that", h2);
-
-        Assert.assertNull(cookiespec.findAttribHandler("whatever"));
-        cookiespec.getAttribHandler("whatever");
-    }
-
-    @Test(expected=IllegalArgumentException.class)
-    public void testBasicPathInvalidInput1() throws Exception {
-        final AbstractCookieSpec cookiespec = new DummyCookieSpec();
-        cookiespec.registerAttribHandler(null, null);
-    }
-
-    @Test(expected=IllegalArgumentException.class)
-    public void testBasicPathInvalidInput2() throws Exception {
-        final AbstractCookieSpec cookiespec = new DummyCookieSpec();
-        cookiespec.registerAttribHandler("whatever", null);
-    }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie.java
index f654a50..c807a2f 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie.java
@@ -40,6 +40,7 @@ import org.junit.Test;
  */
 public class TestBasicClientCookie {
 
+    @SuppressWarnings("unused")
     @Test
     public void testConstructor() {
         final BasicClientCookie cookie = new BasicClientCookie("name", "value");
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie2.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie2.java
index 407ab1f..9af1608 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie2.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicClientCookie2.java
@@ -40,6 +40,7 @@ import org.junit.Test;
  */
 public class TestBasicClientCookie2 {
 
+    @SuppressWarnings("unused")
     @Test
     public void testConstructor() {
         final BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java
index d1164f0..7b236fb 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java
@@ -34,6 +34,8 @@ import java.util.Date;
 import java.util.Locale;
 
 import org.apache.http.client.utils.DateUtils;
+import org.apache.http.conn.util.PublicSuffixMatcher;
+import org.apache.http.cookie.ClientCookie;
 import org.apache.http.cookie.CookieAttributeHandler;
 import org.apache.http.cookie.CookieOrigin;
 import org.apache.http.cookie.MalformedCookieException;
@@ -139,6 +141,7 @@ public class TestBasicCookieAttribHandlers {
         final CookieAttributeHandler h = new BasicDomainHandler();
 
         cookie.setDomain("somedomain.com");
+        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedomain.com");
         Assert.assertTrue(h.match(cookie, origin));
 
         cookie.setDomain(".somedomain.com");
@@ -152,6 +155,7 @@ public class TestBasicCookieAttribHandlers {
         final CookieAttributeHandler h = new BasicDomainHandler();
 
         cookie.setDomain("somedomain.com");
+        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedomain.com");
         Assert.assertTrue(h.match(cookie, origin));
 
         cookie.setDomain(".somedomain.com");
@@ -162,6 +166,28 @@ public class TestBasicCookieAttribHandlers {
     }
 
     @Test
+    public void testBasicDomainMatchOneLetterPrefix() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieOrigin origin = new CookieOrigin("a.somedomain.com", 80, "/", false);
+        final CookieAttributeHandler h = new BasicDomainHandler();
+
+        cookie.setDomain("somedomain.com");
+        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedomain.com");
+        Assert.assertTrue(h.match(cookie, origin));
+    }
+
+    @Test
+    public void testBasicDomainMatchMixedCase() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieOrigin origin = new CookieOrigin("a.SomeDomain.com", 80, "/", false);
+        final CookieAttributeHandler h = new BasicDomainHandler();
+
+        cookie.setDomain("somedoMain.Com");
+        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedoMain.Com");
+        Assert.assertTrue(h.match(cookie, origin));
+    }
+
+    @Test
     public void testBasicDomainInvalidInput() throws Exception {
         final CookieAttributeHandler h = new BasicDomainHandler();
         try {
@@ -450,6 +476,7 @@ public class TestBasicCookieAttribHandlers {
         }
     }
 
+    @SuppressWarnings("unused")
     @Test
     public void testBasicExpiresInvalidInput() throws Exception {
         try {
@@ -471,8 +498,8 @@ public class TestBasicCookieAttribHandlers {
     public void testPublicSuffixFilter() throws Exception {
         final BasicClientCookie cookie = new BasicClientCookie("name", "value");
 
-        final PublicSuffixFilter h = new PublicSuffixFilter(new RFC2109DomainHandler());
-        h.setPublicSuffixes(Arrays.asList(new String[] { "co.uk", "com" }));
+        final PublicSuffixMatcher matcher = new PublicSuffixMatcher(Arrays.asList("co.uk", "com"), null);
+        final PublicSuffixDomainFilter h = new PublicSuffixDomainFilter(new RFC2109DomainHandler(), matcher);
 
         cookie.setDomain(".co.uk");
         Assert.assertFalse(h.match(cookie, new CookieOrigin("apache.co.uk", 80, "/stuff", false)));
@@ -480,12 +507,24 @@ public class TestBasicCookieAttribHandlers {
         cookie.setDomain("co.uk");
         Assert.assertFalse(h.match(cookie, new CookieOrigin("apache.co.uk", 80, "/stuff", false)));
 
+        cookie.setDomain(".co.com");
+        Assert.assertTrue(h.match(cookie, new CookieOrigin("apache.co.com", 80, "/stuff", false)));
+
+        cookie.setDomain("co.com");
+        Assert.assertFalse(h.match(cookie, new CookieOrigin("apache.co.com", 80, "/stuff", false)));
+
         cookie.setDomain(".com");
         Assert.assertFalse(h.match(cookie, new CookieOrigin("apache.com", 80, "/stuff", false)));
 
         cookie.setDomain("com");
         Assert.assertFalse(h.match(cookie, new CookieOrigin("apache.com", 80, "/stuff", false)));
 
+        cookie.setDomain("apache.com");
+        Assert.assertTrue(h.match(cookie, new CookieOrigin("apache.com", 80, "/stuff", false)));
+
+        cookie.setDomain(".apache.com");
+        Assert.assertTrue(h.match(cookie, new CookieOrigin("www.apache.com", 80, "/stuff", false)));
+
         cookie.setDomain("localhost");
         Assert.assertTrue(h.match(cookie, new CookieOrigin("localhost", 80, "/stuff", false)));
     }
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBrowserCompatSpec.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestBrowserCompatSpec.java
deleted file mode 100644
index 3cb0c92..0000000
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestBrowserCompatSpec.java
+++ /dev/null
@@ -1,1072 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.http.impl.cookie;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.http.Header;
-import org.apache.http.client.utils.DateUtils;
-import org.apache.http.cookie.ClientCookie;
-import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieOrigin;
-import org.apache.http.cookie.CookieSpec;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.message.BasicHeader;
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * Test cases for BrowserCompatSpec
- *
- */
-public class TestBrowserCompatSpec {
-
-    @Test
-    public void testConstructor() throws Exception {
-        new BrowserCompatSpec();
-        new BrowserCompatSpec(null);
-        new BrowserCompatSpec(new String[] { DateUtils.PATTERN_RFC1036 });
-    }
-
-    /**
-     * Tests whether domain attribute check is case-insensitive.
-     */
-    @Test
-    public void testDomainCaseInsensitivity() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "name=value; path=/; domain=.whatever.com");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.WhatEver.com", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(1, cookies.size());
-        Assert.assertEquals(".whatever.com", cookies.get(0).getDomain());
-    }
-
-    /**
-     * Test basic parse (with various spacings
-     */
-    @Test
-    public void testParse1() throws Exception {
-        final String headerValue = "custno = 12345; comment=test; version=1," +
-            " name=John; version=1; max-age=600; secure; domain=.apache.org";
-
-        final Header header = new BasicHeader("set-cookie", headerValue);
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals(2, cookies.size());
-
-        Assert.assertEquals("custno", cookies.get(0).getName());
-        Assert.assertEquals("12345", cookies.get(0).getValue());
-        Assert.assertEquals("test", cookies.get(0).getComment());
-        Assert.assertEquals(1, cookies.get(0).getVersion());
-        Assert.assertEquals("www.apache.org", cookies.get(0).getDomain());
-        Assert.assertEquals("/", cookies.get(0).getPath());
-        Assert.assertFalse(cookies.get(0).isSecure());
-
-        Assert.assertEquals("name", cookies.get(1).getName());
-        Assert.assertEquals("John", cookies.get(1).getValue());
-        Assert.assertEquals(null, cookies.get(1).getComment());
-        Assert.assertEquals(1, cookies.get(1).getVersion());
-        Assert.assertEquals(".apache.org", cookies.get(1).getDomain());
-        Assert.assertEquals("/", cookies.get(1).getPath());
-        Assert.assertTrue(cookies.get(1).isSecure());
-    }
-
-    /**
-     * Test no spaces
-     */
-    @Test
-    public void testParse2() throws Exception {
-        final String headerValue = "custno=12345;comment=test; version=1," +
-            "name=John;version=1;max-age=600;secure;domain=.apache.org";
-
-        final Header header = new BasicHeader("set-cookie", headerValue);
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-
-        Assert.assertEquals(2, cookies.size());
-
-        Assert.assertEquals("custno", cookies.get(0).getName());
-        Assert.assertEquals("12345", cookies.get(0).getValue());
-        Assert.assertEquals("test", cookies.get(0).getComment());
-        Assert.assertEquals(1, cookies.get(0).getVersion());
-        Assert.assertEquals("www.apache.org", cookies.get(0).getDomain());
-        Assert.assertEquals("/", cookies.get(0).getPath());
-        Assert.assertFalse(cookies.get(0).isSecure());
-
-        Assert.assertEquals("name", cookies.get(1).getName());
-        Assert.assertEquals("John", cookies.get(1).getValue());
-        Assert.assertEquals(null, cookies.get(1).getComment());
-        Assert.assertEquals(1, cookies.get(1).getVersion());
-        Assert.assertEquals(".apache.org", cookies.get(1).getDomain());
-        Assert.assertEquals("/", cookies.get(1).getPath());
-        Assert.assertTrue(cookies.get(1).isSecure());
-    }
-
-
-    /**
-     * Test parse with quoted text
-     */
-    @Test
-    public void testParse3() throws Exception {
-        final String headerValue =
-            "name=\"Doe, John\";version=1;max-age=600;secure;domain=.apache.org";
-        final Header header = new BasicHeader("set-cookie", headerValue);
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-
-        Assert.assertEquals(1, cookies.size());
-
-        Assert.assertEquals("name", cookies.get(0).getName());
-        Assert.assertEquals("Doe, John", cookies.get(0).getValue());
-        Assert.assertEquals(null, cookies.get(0).getComment());
-        Assert.assertEquals(1, cookies.get(0).getVersion());
-        Assert.assertEquals(".apache.org", cookies.get(0).getDomain());
-        Assert.assertEquals("/", cookies.get(0).getPath());
-        Assert.assertTrue(cookies.get(0).isSecure());
-    }
-
-
-    // see issue #5279
-    @Test
-    public void testQuotedExpiresAttribute() throws Exception {
-        final String headerValue = "custno=12345;Expires='Thu, 01-Jan-2070 00:00:10 GMT'";
-
-        final Header header = new BasicHeader("set-cookie", headerValue);
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "/", true);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertNotNull("Expected some cookies",cookies);
-        Assert.assertEquals("Expected 1 cookie",1,cookies.size());
-        Assert.assertNotNull("Expected cookie to have getExpiryDate",cookies.get(0).getExpiryDate());
-    }
-
-    @Test
-    public void testSecurityError() throws Exception {
-        final String headerValue = "custno=12345;comment=test; version=1," +
-            "name=John;version=1;max-age=600;secure;domain=jakarta.apache.org";
-        final Header header = new BasicHeader("set-cookie", headerValue);
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "/", true);
-        try {
-            final List<Cookie> cookies = cookiespec.parse(header, origin);
-            for (int i = 0; i < cookies.size(); i++) {
-                cookiespec.validate(cookies.get(i), origin);
-            }
-            Assert.fail("MalformedCookieException exception should have been thrown");
-        } catch (final MalformedCookieException ex) {
-            // expected
-        }
-    }
-
-    @Test
-    public void testParseSimple() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie","cookie-name=cookie-value");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/path/path", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        //Assert.assertTrue("isToBeDiscarded",cookies.get(0).isToBeDiscarded());
-        Assert.assertTrue("isPersistent",!cookies.get(0).isPersistent());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/path",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertEquals("Version",0,cookies.get(0).getVersion());
-    }
-
-    @Test
-    public void testParseSimple2() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie", "cookie-name=cookie-value");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/path", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.", 1, cookies.size());
-        Assert.assertEquals("Name", "cookie-name", cookies.get(0).getName());
-        Assert.assertEquals("Value", "cookie-value", cookies.get(0).getValue());
-        Assert.assertTrue("Comment", null == cookies.get(0).getComment());
-        Assert.assertTrue("ExpiryDate", null == cookies.get(0).getExpiryDate());
-        //Assert.assertTrue("isToBeDiscarded",cookies.get(0).isToBeDiscarded());
-        Assert.assertTrue("isPersistent", !cookies.get(0).isPersistent());
-        Assert.assertEquals("Domain", "127.0.0.1", cookies.get(0).getDomain());
-        Assert.assertEquals("Path", "/", cookies.get(0).getPath());
-        Assert.assertTrue("Secure", !cookies.get(0).isSecure());
-        Assert.assertEquals("Version", 0, cookies.get(0).getVersion());
-    }
-
-    @Test
-    public void testParseNoName() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie","=stuff; path=/");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
-        try {
-            final List<Cookie> cookies = cookiespec.parse(header, origin);
-            for (int i = 0; i < cookies.size(); i++) {
-                cookiespec.validate(cookies.get(i), origin);
-            }
-            Assert.fail("MalformedCookieException should have been thrown");
-        } catch (final MalformedCookieException ex) {
-            // expected
-        }
-    }
-
-    @Test
-    public void testParseNoValue() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie","cookie-name=");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value", "", cookies.get(0).getValue());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        //Assert.assertTrue("isToBeDiscarded",cookies.get(0).isToBeDiscarded());
-        Assert.assertTrue("isPersistent",!cookies.get(0).isPersistent());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertEquals("Version",0,cookies.get(0).getVersion());
-    }
-
-    @Test
-    public void testParseWithWhiteSpace() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie"," cookie-name  =    cookie-value  ");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-    }
-
-    @Test
-    public void testParseWithQuotes() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie"," cookie-name  =  \" cookie-value \" ;path=/");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1",80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","\" cookie-value \"",cookies.get(0).getValue());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-    }
-
-    @Test
-    public void testParseWithPath() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie","cookie-name=cookie-value; Path=/path/");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/path/path", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/path/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-    }
-
-    @Test
-    public void testParseWithDomain() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie","cookie-name=cookie-value; Domain=127.0.0.1");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-    }
-
-    @Test
-    public void testParseWithSecure() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie","cookie-name=cookie-value; secure");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", true);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",cookies.get(0).isSecure());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-    }
-
-    @Test
-    public void testParseWithComment() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "cookie-name=cookie-value; comment=\"This is a comment.\"");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", true);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertTrue("ExpiryDate",null == cookies.get(0).getExpiryDate());
-        Assert.assertEquals("Comment","\"This is a comment.\"",cookies.get(0).getComment());
-    }
-
-    @Test
-    public void testParseWithExpires() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "cookie-name=cookie-value;Expires=Thu, 01-Jan-1970 00:00:10 GMT");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", true);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertEquals("Domain","127.0.0.1",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",!cookies.get(0).isSecure());
-        Assert.assertEquals(new Date(10000L),cookies.get(0).getExpiryDate());
-        Assert.assertTrue("Comment",null == cookies.get(0).getComment());
-    }
-
-    @Test
-    public void testParseWithAll() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "cookie-name=cookie-value;Version=1;Path=/commons;Domain=.apache.org;" +
-            "Comment=This is a comment.;secure;Expires=Thu, 01-Jan-1970 00:00:10 GMT");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "/commons/httpclient", true);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookie.",1,cookies.size());
-        Assert.assertEquals("Name","cookie-name",cookies.get(0).getName());
-        Assert.assertEquals("Value","cookie-value",cookies.get(0).getValue());
-        Assert.assertEquals("Domain",".apache.org",cookies.get(0).getDomain());
-        Assert.assertEquals("Path","/commons",cookies.get(0).getPath());
-        Assert.assertTrue("Secure",cookies.get(0).isSecure());
-        Assert.assertEquals(new Date(10000L),cookies.get(0).getExpiryDate());
-        Assert.assertEquals("Comment","This is a comment.",cookies.get(0).getComment());
-        Assert.assertEquals("Version",1,cookies.get(0).getVersion());
-    }
-
-    @Test
-    public void testParseMultipleDifferentPaths() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "name1=value1;Version=1;Path=/commons,name1=value2;Version=1;" +
-            "Path=/commons/httpclient;Version=1");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "/commons/httpclient", true);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Wrong number of cookies.",2,cookies.size());
-        Assert.assertEquals("Name","name1",cookies.get(0).getName());
-        Assert.assertEquals("Value","value1",cookies.get(0).getValue());
-        Assert.assertEquals("Name","name1",cookies.get(1).getName());
-        Assert.assertEquals("Value","value2",cookies.get(1).getValue());
-    }
-
-    @Test
-    public void testParseRelativePath() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie", "name1=value1;Path=whatever");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.apache.org", 80, "whatever", true);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertEquals("Found 1 cookies.",1,cookies.size());
-        Assert.assertEquals("Name","name1",cookies.get(0).getName());
-        Assert.assertEquals("Value","value1",cookies.get(0).getValue());
-        Assert.assertEquals("Path","whatever",cookies.get(0).getPath());
-    }
-
-    @Test
-    public void testParseWithWrongDomain() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "cookie-name=cookie-value; domain=127.0.0.1; version=1");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.2", 80, "/", false);
-        try {
-            final List<Cookie> cookies = cookiespec.parse(header, origin);
-            for (int i = 0; i < cookies.size(); i++) {
-                cookiespec.validate(cookies.get(i), origin);
-            }
-            Assert.fail("MalformedCookieException exception should have been thrown");
-        } catch (final MalformedCookieException ex) {
-            // expected
-        }
-    }
-
-    @Test
-    public void testParseWithPathMismatch() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "cookie-name=cookie-value; path=/path/path/path");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/path", false);
-        try {
-            final List<Cookie> cookies = cookiespec.parse(header, origin);
-            for (int i = 0; i < cookies.size(); i++) {
-                cookiespec.validate(cookies.get(i), origin);
-            }
-            Assert.fail("MalformedCookieException should have been thrown.");
-        } catch (final MalformedCookieException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void testParseWithPathMismatch2() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "cookie-name=cookie-value; path=/foobar");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/foo", false);
-        try {
-            final List<Cookie> cookies = cookiespec.parse(header, origin);
-            for (int i = 0; i < cookies.size(); i++) {
-                cookiespec.validate(cookies.get(i), origin);
-            }
-            Assert.fail("MalformedCookieException should have been thrown.");
-        } catch (final MalformedCookieException e) {
-            // expected
-        }
-    }
-
-    /**
-     * Tests if cookie constructor rejects cookie name containing blanks.
-     */
-    @Test
-    public void testCookieNameWithBlanks() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie", "invalid name=");
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(1, cookies.size());
-    }
-
-    /**
-     * Tests if cookie constructor rejects cookie name containing blanks.
-     */
-    @Test
-    public void testCookieNameBlank() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie", "=stuff");
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
-        try {
-            final List<Cookie> cookies = cookiespec.parse(header, origin);
-            for (int i = 0; i < cookies.size(); i++) {
-                cookiespec.validate(cookies.get(i), origin);
-            }
-            Assert.fail("MalformedCookieException should have been thrown");
-        } catch (final MalformedCookieException expected) {
-        }
-    }
-
-    /**
-     * Tests if cookie constructor rejects cookie name starting with $.
-     */
-    @Test
-    public void testCookieNameStartingWithDollarSign() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie", "$invalid_name=");
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(1, cookies.size());
-    }
-
-
-    /**
-     * Tests if malformatted expires attribute is cookies correctly.
-     */
-    @Test
-    public void testCookieWithComma() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie", "name=value; expires=\"Thu, 01-Jan-1970 00:00:00 GMT");
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("localhost", 80, "/", false);
-        try {
-            final List<Cookie> cookies = cookiespec.parse(header, origin);
-            for (int i = 0; i < cookies.size(); i++) {
-                cookiespec.validate(cookies.get(i), origin);
-            }
-            Assert.fail("MalformedCookieException should have been thrown");
-        } catch (final MalformedCookieException expected) {
-        }
-    }
-
-
-    /**
-     * Tests several date formats.
-     */
-    @Test
-    public void testDateFormats() throws Exception {
-        //comma, dashes
-        checkDate("Thu, 01-Jan-70 00:00:10 GMT");
-        checkDate("Thu, 01-Jan-2070 00:00:10 GMT");
-        //no comma, dashes
-        checkDate("Thu 01-Jan-70 00:00:10 GMT");
-        checkDate("Thu 01-Jan-2070 00:00:10 GMT");
-        //comma, spaces
-        checkDate("Thu, 01 Jan 70 00:00:10 GMT");
-        checkDate("Thu, 01 Jan 2070 00:00:10 GMT");
-        //no comma, spaces
-        checkDate("Thu 01 Jan 70 00:00:10 GMT");
-        checkDate("Thu 01 Jan 2070 00:00:10 GMT");
-        //weird stuff
-        checkDate("Wed, 20-Nov-2002 09-38-33 GMT");
-
-
-        try {
-            checkDate("this aint a date");
-            Assert.fail("Date check is bogus");
-        } catch(final Exception e) {
-        }
-    }
-
-    private void checkDate(final String date) throws Exception {
-        final Header header = new BasicHeader("Set-Cookie", "custno=12345;Expires='"+date+"';");
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("localhost", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        for (int i = 0; i < cookies.size(); i++) {
-            cookiespec.validate(cookies.get(i), origin);
-        }
-    }
-
-    /**
-     * Tests if invalid second domain level cookie gets accepted in the
-     * browser compatibility mode.
-     */
-    @Test
-    public void testSecondDomainLevelCookie() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain(".sourceforge.net");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("sourceforge.net", 80, "/", false);
-        cookiespec.validate(cookie, origin);
-    }
-
-    @Test
-    public void testSecondDomainLevelCookieMatch1() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain(".sourceforge.net");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("sourceforge.net", 80, "/", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testSecondDomainLevelCookieMatch2() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain("sourceforge.net");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("www.sourceforge.net", 80, "/", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testSecondDomainLevelCookieMatch3() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain(".sourceforge.net");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-         final CookieSpec cookiespec = new BrowserCompatSpec();
-         final CookieOrigin origin = new CookieOrigin("www.sourceforge.net", 80, "/", false);
-         Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testInvalidSecondDomainLevelCookieMatch1() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain(".sourceforge.net");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("antisourceforge.net", 80, "/", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testInvalidSecondDomainLevelCookieMatch2() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain("sourceforge.net");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("antisourceforge.net", 80, "/", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testMatchBlankPath() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "  ", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testMatchNullCookieDomain() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testMatchNullCookiePath() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMatch1() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMatch2() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain(".whatever.com");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin(".whatever.com", 80, "/", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMatch3() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain(".whatever.com");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin(".really.whatever.com", 80, "/", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMatch4() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/foobar", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMismatch1() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host1");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin("host2", 80, "/", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMismatch2() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain(".aaaaaaaaa.com");
-        cookie.setPath("/");
-        final CookieOrigin origin = new CookieOrigin(".bbbbbbbb.com", 80, "/", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMismatch3() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        cookie.setPath("/foobar");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/foo", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMismatch4() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        cookie.setPath("/foobar");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/foobar/", false);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMatch5() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        cookie.setPath("/foobar/r");
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/foobar/", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testCookieMismatch6() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain("host");
-        cookie.setPath("/foobar");
-        cookie.setSecure(true);
-        final CookieOrigin origin = new CookieOrigin("host", 80, "/foobar", false);
-        Assert.assertFalse(cookiespec.match(cookie, origin));
-    }
-
-    @Test
-    public void testInvalidMatchDomain() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain("beta.gamma.com");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("alpha.beta.gamma.com", 80, "/", false);
-        cookiespec.validate(cookie, origin);
-        Assert.assertTrue(cookiespec.match(cookie, origin));
-    }
-
-    /**
-     * Tests generic cookie formatting.
-     */
-    @Test
-    public void testGenericCookieFormatting() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "name=value; path=/; domain=.mydomain.com");
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        cookiespec.validate(cookies.get(0), origin);
-        final List<Header> headers = cookiespec.formatCookies(cookies);
-        Assert.assertNotNull(headers);
-        Assert.assertEquals(1, headers.size());
-        Assert.assertEquals("name=value", headers.get(0).getValue());
-    }
-
-    /**
-     * Tests if null cookie values are handled correctly.
-     */
-    @Test
-    public void testNullCookieValueFormatting() {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setDomain(".whatever.com");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final List<Cookie> cookies = new ArrayList<Cookie>(1);
-        cookies.add(cookie);
-        final List<Header> headers = cookiespec.formatCookies(cookies);
-        Assert.assertNotNull(headers);
-        Assert.assertEquals(1, headers.size());
-        Assert.assertEquals("name=", headers.get(0).getValue());
-    }
-
-    @Test
-    public void testNullCookieValueFormattingCookieVersion1() {
-        final BasicClientCookie cookie = new BasicClientCookie("name", null);
-        cookie.setVersion(1);
-        cookie.setDomain(".whatever.com");
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());
-        cookie.setPath("/");
-        cookie.setAttribute(ClientCookie.PATH_ATTR, cookie.getPath());
-
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final List<Cookie> cookies = new ArrayList<Cookie>(1);
-        cookies.add(cookie);
-        final List<Header> headers = cookiespec.formatCookies(cookies);
-        Assert.assertNotNull(headers);
-        Assert.assertEquals(1, headers.size());
-        Assert.assertEquals("name", headers.get(0).getValue());
-    }
-
-    /**
-     * Tests generic cookie formatting.
-     */
-    @Test
-    public void testFormatSeveralCookies() throws Exception {
-        final Header header = new BasicHeader("Set-Cookie",
-            "name1=value1; path=/; domain=.mydomain.com, name2 = value2 ; path=/; domain=.mydomain.com; version=0");
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
-        final List<Cookie> cookies = cookiespec.parse(header, origin);
-        final List<Header> headers = cookiespec.formatCookies(cookies);
-        Assert.assertNotNull(headers);
-        Assert.assertEquals(1, headers.size());
-        Assert.assertEquals("name1=value1; name2=value2", headers.get(0).getValue());
-    }
-
-    @Test
-    public void testKeepCloverHappy() throws Exception {
-        new MalformedCookieException();
-        new MalformedCookieException("whatever");
-        new MalformedCookieException("whatever", null);
-    }
-
-    @Test
-    public void testInvalidInput() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        try {
-            cookiespec.parse(null, null);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            cookiespec.parse(new BasicHeader("Set-Cookie", "name=value"), null);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            cookiespec.validate(null, null);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            cookiespec.validate(new BasicClientCookie("name", null), null);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            cookiespec.match(null, null);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            cookiespec.match(new BasicClientCookie("name", null), null);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            cookiespec.formatCookies(null);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            final List<Cookie> cookies = new ArrayList<Cookie>();
-            cookiespec.formatCookies(cookies);
-            Assert.fail("IllegalArgumentException must have been thrown");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-    }
-
-    /**
-     * Tests cookie version 1 with space in cookie value.
-     */
-    @Test
-    public void testFormatCookieWithSpaceInValue() throws Exception {
-        final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
-        final CookieSpec cookieSpec = new BrowserCompatSpec();
-        final Header setCookieHeader = new BasicHeader("Set-Cookie", "test=\"value 1\"; Version=1");
-        final Cookie cookie = cookieSpec.parse(setCookieHeader, origin).get(0);
-        final List<Cookie> cookies = new ArrayList<Cookie>();
-        cookies.add(cookie);
-        final List<Header> headers = cookieSpec.formatCookies(cookies);
-        Assert.assertNotNull(headers);
-        Assert.assertEquals(1, headers.size());
-        Assert.assertEquals("test=\"value 1\"", headers.get(0).getValue());
-    }
-
-    /**
-     * Tests Netscape cookie with space in cookie value.
-     */
-    @Test
-    public void testFormatCookieVersion0WithSpaceInValue() throws Exception {
-        final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
-        final CookieSpec cookieSpec = new BrowserCompatSpec();
-        final Header setCookieHeader = new BasicHeader("Set-Cookie", "test=value 1");
-        final Cookie cookie = cookieSpec.parse(setCookieHeader, origin).get(0);
-        final List<Cookie> cookies = new ArrayList<Cookie>();
-        cookies.add(cookie);
-        final List<Header> headers = cookieSpec.formatCookies(cookies);
-        Assert.assertNotNull(headers);
-        Assert.assertEquals(1, headers.size());
-        Assert.assertEquals("test=value 1", headers.get(0).getValue());
-    }
-
-    @Test
-    public void testVersion1CookieWithInvalidExpires() throws Exception {
-        final CookieSpec cookiespec = new BrowserCompatSpec();
-        final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
-
-        final Header origHeader = new BasicHeader("Set-Cookie",
-            "test=\"test\"; Version=1; Expires=Mon, 11-Feb-2013 10:39:19 GMT; Path=/");
-        final List<Cookie> cookies = cookiespec.parse(origHeader, origin);
-        Assert.assertNotNull(cookies);
-        Assert.assertEquals(1, cookies.size());
-
-        final List<Header> headers = cookiespec.formatCookies(cookies);
-        Assert.assertNotNull(headers);
-        Assert.assertEquals(1, headers.size());
-        final Header header1 = headers.get(0);
-        Assert.assertEquals("test=\"test\"", header1.getValue());
-    }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieNetscapeDraft.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieNetscapeDraft.java
index cd7c0f3..ec03d47 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieNetscapeDraft.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieNetscapeDraft.java
@@ -132,6 +132,25 @@ public class TestCookieNetscapeDraft {
         }
     }
 
+    @Test
+    public void testParseVersionIgnored() throws Exception {
+        final Header header = new BasicHeader("Set-Cookie", "name1=value1;Path=/path/;Version=1;");
+
+        final CookieSpec cookiespec = new NetscapeDraftSpec();
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final List<Cookie> cookies = cookiespec.parse(header, origin);
+        for (int i = 0; i < cookies.size(); i++) {
+            cookiespec.validate(cookies.get(i), origin);
+        }
+        Assert.assertEquals("Found 1 cookies.",1,cookies.size());
+        final Cookie cookie = cookies.get(0);
+        Assert.assertEquals("Name","name1", cookie.getName());
+        Assert.assertEquals("Value", "value1", cookie.getValue());
+        Assert.assertEquals("Domain", "host", cookie.getDomain());
+        Assert.assertEquals("Path","/path/", cookie.getPath());
+        Assert.assertEquals(0, cookie.getVersion());
+    }
+
     /**
      * Tests Netscape specific cookie formatting.
      */
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2109Spec.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2109Spec.java
index 8ee4a31..e4eff79 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2109Spec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2109Spec.java
@@ -46,6 +46,7 @@ import org.junit.Test;
  */
 public class TestCookieRFC2109Spec {
 
+    @SuppressWarnings("unused")
     @Test
     public void testConstructor() throws Exception {
         new RFC2109Spec();
@@ -398,8 +399,8 @@ public class TestCookieRFC2109Spec {
         Assert.assertEquals(1, headers.size());
         Assert.assertEquals("$Version=0; name=; $Path=/", headers.get(0).getValue());
 
-        cookie.setAttribute(ClientCookie.DOMAIN_ATTR, null);
-        cookie.setAttribute(ClientCookie.PATH_ATTR, null);
+        cookie.removeAttribute(ClientCookie.DOMAIN_ATTR);
+        cookie.removeAttribute(ClientCookie.PATH_ATTR);
         cookies = new ArrayList<Cookie>();
         cookies.add(cookie);
         headers = cookiespec.formatCookies(cookies);
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java
index 662b4cc..9720371 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java
@@ -46,7 +46,7 @@ import org.junit.Test;
 public class TestCookieRFC2965Spec {
 
     /**
-     * Test parsing cookie <tt>"Path"</tt> attribute.
+     * Test parsing cookie {@code "Path"} attribute.
      */
     @Test
     public void testParsePath() throws Exception {
@@ -103,7 +103,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test parsing cookie <tt>"Domain"</tt> attribute.
+     * Test parsing cookie {@code "Domain"} attribute.
      */
     @Test
     public void testParseDomain() throws Exception {
@@ -169,7 +169,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test parsing cookie <tt>"Port"</tt> attribute.
+     * Test parsing cookie {@code "Port"} attribute.
      */
     @Test
     public void testParsePort() throws Exception {
@@ -280,7 +280,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test parsing cookie <tt>"Version"</tt> attribute.
+     * test parsing cookie {@code "Version"} attribute.
      */
     @Test
     public void testParseVersion() throws Exception {
@@ -322,7 +322,7 @@ public class TestCookieRFC2965Spec {
         }
     }
     /**
-     * test parsing cookie <tt>"Max-age"</tt> attribute.
+     * test parsing cookie {@code "Max-age"} attribute.
      */
     @Test
     public void testParseMaxage() throws Exception {
@@ -377,7 +377,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test parsing <tt>"Secure"</tt> attribute.
+     * test parsing {@code "Secure"} attribute.
      */
     @Test
     public void testParseSecure() throws Exception {
@@ -392,7 +392,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test parsing <tt>"Discard"</tt> attribute.
+     * test parsing {@code "Discard"} attribute.
      */
     @Test
     public void testParseDiscard() throws Exception {
@@ -416,8 +416,8 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test parsing <tt>"Comment"</tt>, <tt>"CommentURL"</tt> and
-     * <tt>"Secure"</tt> attributes.
+     * test parsing {@code "Comment"}, {@code "CommentURL"} and
+     * {@code "Secure"} attributes.
      */
     @Test
     public void testParseOtherAttributes() throws Exception {
@@ -462,8 +462,8 @@ public class TestCookieRFC2965Spec {
     // ------------------------------------------------------- Test Cookie Validation
 
     /**
-     * Test <tt>Domain</tt> validation when domain is not specified
-     * in <tt>Set-Cookie2</tt> header.
+     * Test {@code Domain} validation when domain is not specified
+     * in {@code Set-Cookie2} header.
      */
     @Test
     public void testValidateNoDomain() throws Exception {
@@ -482,7 +482,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test <tt>Domain</tt> validation. Cookie domain attribute must have a
+     * Test {@code Domain} validation. Cookie domain attribute must have a
      * leading dot.
      */
     @Test
@@ -501,7 +501,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test <tt>Domain</tt> validation. Domain must have at least one embedded dot.
+     * Test {@code Domain} validation. Domain must have at least one embedded dot.
      */
     @Test
     public void testValidateDomainEmbeddedDot() throws Exception {
@@ -527,7 +527,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test local <tt>Domain</tt> validation. Simple host names
+     * Test local {@code Domain} validation. Simple host names
      * (without any dots) are valid only when cookie domain is specified
      * as ".local".
      */
@@ -574,7 +574,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test <tt>Domain</tt> validation. Effective host name
+     * Test {@code Domain} validation. Effective host name
      * must domain-match domain attribute.
      */
     @Test
@@ -604,7 +604,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test local <tt>Domain</tt> validation.
+     * Test local {@code Domain} validation.
      * Effective host name minus domain must not contain any dots.
      */
     @Test
@@ -622,7 +622,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test cookie <tt>Path</tt> validation. Cookie path attribute must path-match
+     * Test cookie {@code Path} validation. Cookie path attribute must path-match
      * request path.
      */
     @Test
@@ -698,7 +698,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test cookie <tt>Port</tt> validation. Request port must be in the
+     * Test cookie {@code Port} validation. Request port must be in the
      * port attribute list.
      */
     @Test
@@ -731,7 +731,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * Test cookie <tt>Version</tt> validation.
+     * Test cookie {@code Version} validation.
      */
     @Test
     public void testValidateVersion() throws Exception {
@@ -751,7 +751,7 @@ public class TestCookieRFC2965Spec {
     // ------------------------------------------------------- Test Cookie Matching
 
     /**
-     * test cookie <tt>Path</tt> matching. Cookie path attribute must path-match
+     * test cookie {@code Path} matching. Cookie path attribute must path-match
      * path of the request URI.
      */
     @Test
@@ -768,7 +768,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test cookie <tt>Domain</tt> matching.
+     * test cookie {@code Domain} matching.
      */
     @Test
     public void testMatchDomain() throws Exception {
@@ -789,7 +789,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test cookie local <tt>Domain</tt> matching.
+     * test cookie local {@code Domain} matching.
      */
     @Test
     public void testMatchDomainLocal() throws Exception {
@@ -805,7 +805,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test cookie <tt>Port</tt> matching.
+     * test cookie {@code Port} matching.
      */
     @Test
     public void testMatchPort() throws Exception {
@@ -865,7 +865,7 @@ public class TestCookieRFC2965Spec {
     }
 
     /**
-     * test cookie <tt>Secure</tt> attribute.
+     * test cookie {@code Secure} attribute.
      */
     @Test
     public void testCookieSecure() throws Exception {
@@ -996,7 +996,7 @@ public class TestCookieRFC2965Spec {
     // ------------------------------------------------------- Backward compatibility tests
 
     /**
-     * Test rejection of <tt>Set-Cookie</tt> header.
+     * Test rejection of {@code Set-Cookie} header.
      */
     @Test
     public void testRejectSetCookie() throws Exception {
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieBestMatchSpec.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestDefaultCookieSpec.java
similarity index 87%
rename from httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieBestMatchSpec.java
rename to httpclient/src/test/java/org/apache/http/impl/cookie/TestDefaultCookieSpec.java
index 12059f9..997789a 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestCookieBestMatchSpec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestDefaultCookieSpec.java
@@ -44,11 +44,11 @@ import org.junit.Test;
 /**
  * Test cases for 'best match' cookie policy
  */
-public class TestCookieBestMatchSpec {
+public class TestDefaultCookieSpec {
 
     @Test
     public void testCookieBrowserCompatParsing() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         final CookieOrigin origin = new CookieOrigin("a.b.domain.com", 80, "/", false);
 
         // Make sure the lenient (browser compatible) cookie parsing
@@ -63,7 +63,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testNetscapeCookieParsing() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
 
         Header header = new BasicHeader("Set-Cookie",
@@ -80,7 +80,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testCookieStandardCompliantParsing() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         final CookieOrigin origin = new CookieOrigin("a.b.domain.com", 80, "/", false);
 
         // Make sure the strict (RFC2965) cookie parsing
@@ -113,7 +113,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testCookieStandardCompliantParsingLocalHost() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         final CookieOrigin origin = new CookieOrigin("localhost", 80, "/", false);
 
         final Header header = new BasicHeader("Set-Cookie", "special=\"abcdigh\"; Version=1");
@@ -129,7 +129,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testCookieStandardCompliantParsingLocalHost2() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         final CookieOrigin origin = new CookieOrigin("localhost", 80, "/", false);
 
         final Header header = new BasicHeader("Set-Cookie2", "special=\"abcdigh\"; Version=1");
@@ -145,7 +145,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testCookieBrowserCompatMatch() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         final CookieOrigin origin = new CookieOrigin("a.b.domain.com", 80, "/", false);
 
         // Make sure the lenient (browser compatible) cookie matching
@@ -161,7 +161,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testCookieStandardCompliantMatch() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         final CookieOrigin origin = new CookieOrigin("a.b.domain.com", 80, "/", false);
 
         // Make sure the strict (RFC2965) cookie matching
@@ -182,7 +182,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testCookieBrowserCompatFormatting() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
 
         // Make sure the lenient (browser compatible) cookie formatting
         // is used for Netscape style cookies
@@ -214,7 +214,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testCookieStandardCompliantFormatting() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec(null, true);
+        final CookieSpec cookiespec = new DefaultCookieSpec(null, true);
 
         // Make sure the strict (RFC2965) cookie formatting
         // is used for Netscape style cookies
@@ -249,7 +249,7 @@ public class TestCookieBestMatchSpec {
 
     @Test
     public void testInvalidInput() throws Exception {
-        final CookieSpec cookiespec = new BestMatchSpec();
+        final CookieSpec cookiespec = new DefaultCookieSpec();
         try {
             cookiespec.parse(null, null);
             Assert.fail("IllegalArgumentException must have been thrown");
@@ -277,5 +277,23 @@ public class TestCookieBestMatchSpec {
         }
     }
 
+    @Test
+    public void testVersion1CookieWithInvalidExpires() throws Exception {
+        final CookieSpec cookiespec = new DefaultCookieSpec();
+        final CookieOrigin origin = new CookieOrigin("myhost.mydomain.com", 80, "/", false);
+
+        final Header origHeader = new BasicHeader("Set-Cookie",
+                "test=\"test\"; Version=1; Expires=Mon, 11-Feb-2013 10:39:19 GMT; Path=/");
+        final List<Cookie> cookies = cookiespec.parse(origHeader, origin);
+        Assert.assertNotNull(cookies);
+        Assert.assertEquals(1, cookies.size());
+
+        final List<Header> headers = cookiespec.formatCookies(cookies);
+        Assert.assertNotNull(headers);
+        Assert.assertEquals(1, headers.size());
+        final Header header1 = headers.get(0);
+        Assert.assertEquals("test=\"test\"", header1.getValue());
+    }
+
 }
 
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestLaxCookieAttribHandlers.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestLaxCookieAttribHandlers.java
new file mode 100644
index 0000000..d47d0ae
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestLaxCookieAttribHandlers.java
@@ -0,0 +1,317 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.MalformedCookieException;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestLaxCookieAttribHandlers {
+
+    @Test
+    public void testParseMaxAge() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxMaxAgeHandler();
+        h.parse(cookie, "2000");
+        Assert.assertNotNull(cookie.getExpiryDate());
+    }
+
+    @Test
+    public void testParseMaxNegative() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxMaxAgeHandler();
+        h.parse(cookie, "-2000");
+        Assert.assertNotNull(cookie.getExpiryDate());
+    }
+
+    @Test
+    public void testParseMaxZero() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxMaxAgeHandler();
+        h.parse(cookie, "0000");
+        Assert.assertNotNull(cookie.getExpiryDate());
+    }
+
+    @Test
+    public void testBasicMaxAgeParseEmpty() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxMaxAgeHandler();
+        h.parse(cookie, "  ");
+        Assert.assertNull(cookie.getExpiryDate());
+    }
+
+    @Test
+    public void testBasicMaxAgeParseInvalid() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxMaxAgeHandler();
+        h.parse(cookie, "garbage");
+        Assert.assertNull(cookie.getExpiryDate());
+    }
+
+    @Test
+    public void testBasicMaxAgeInvalidInput() throws Exception {
+        final CookieAttributeHandler h = new LaxMaxAgeHandler();
+        try {
+            h.parse(null, "stuff");
+            Assert.fail("IllegalArgumentException must have been thrown");
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testExpiryGarbage() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, ";;blah,blah;yada  ");
+    }
+
+    @Test
+    public void testParseExpiry() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "1:0:12 8-jan-2012");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(2012, c.get(Calendar.YEAR));
+        Assert.assertEquals(Calendar.JANUARY, c.get(Calendar.MONTH));
+        Assert.assertEquals(8, c.get(Calendar.DAY_OF_MONTH));
+        Assert.assertEquals(1, c.get(Calendar.HOUR_OF_DAY));
+        Assert.assertEquals(0, c.get(Calendar.MINUTE));
+        Assert.assertEquals(12, c.get(Calendar.SECOND));
+        Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidTime1() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "1:0:122 8 dec 1980");
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidTime2() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "24:00:00 8 dec 1980");
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidTime3() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "23:60:00 8 dec 1980");
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidTime4() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "23:00:60 8 dec 1980");
+    }
+
+    @Test
+    public void testParseExpiryFunnyTime() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "1:59:00blah; 8-feb-2000");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(2000, c.get(Calendar.YEAR));
+        Assert.assertEquals(Calendar.FEBRUARY, c.get(Calendar.MONTH));
+        Assert.assertEquals(8, c.get(Calendar.DAY_OF_MONTH));
+        Assert.assertEquals(1, c.get(Calendar.HOUR_OF_DAY));
+        Assert.assertEquals(59, c.get(Calendar.MINUTE));
+        Assert.assertEquals(0, c.get(Calendar.SECOND));
+        Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidDayOfMonth1() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "12:00:00 888 mar 1880");
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidDayOfMonth2() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "12:00:00 0 mar 1880");
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidDayOfMonth3() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "12:00:00 32 mar 1880");
+    }
+
+    @Test
+    public void testParseExpiryFunnyDayOfMonth() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "12:00:00 8blah;mar;1880");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(1880, c.get(Calendar.YEAR));
+        Assert.assertEquals(Calendar.MARCH, c.get(Calendar.MONTH));
+        Assert.assertEquals(8, c.get(Calendar.DAY_OF_MONTH));
+        Assert.assertEquals(12, c.get(Calendar.HOUR_OF_DAY));
+        Assert.assertEquals(0, c.get(Calendar.MINUTE));
+        Assert.assertEquals(0, c.get(Calendar.SECOND));
+        Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidMonth() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "1:00:00 8 dek 80");
+    }
+
+    @Test
+    public void testParseExpiryFunnyMonth() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "23:59:59; 1-ApriLLLLL-2008");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(2008, c.get(Calendar.YEAR));
+        Assert.assertEquals(Calendar.APRIL, c.get(Calendar.MONTH));
+        Assert.assertEquals(1, c.get(Calendar.DAY_OF_MONTH));
+        Assert.assertEquals(23, c.get(Calendar.HOUR_OF_DAY));
+        Assert.assertEquals(59, c.get(Calendar.MINUTE));
+        Assert.assertEquals(59, c.get(Calendar.SECOND));
+        Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidYearTooShort() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "1:00:00 8 dec 8");
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidYearTooLong() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "1:00:00 8 dec 88888");
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseExpiryInvalidYearTooLongAgo() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "1:00:00 8 dec 1600");
+    }
+
+    @Test
+    public void testParseExpiryFunnyYear() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "23:59:59; 1-Apr-2008blah");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(2008, c.get(Calendar.YEAR));
+        Assert.assertEquals(Calendar.APRIL, c.get(Calendar.MONTH));
+        Assert.assertEquals(1, c.get(Calendar.DAY_OF_MONTH));
+        Assert.assertEquals(23, c.get(Calendar.HOUR_OF_DAY));
+        Assert.assertEquals(59, c.get(Calendar.MINUTE));
+        Assert.assertEquals(59, c.get(Calendar.SECOND));
+        Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
+    }
+
+    @Test
+    public void testParseExpiryYearTwoDigit1() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "23:59:59; 1-Apr-70");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(1970, c.get(Calendar.YEAR));
+    }
+
+    @Test
+    public void testParseExpiryYearTwoDigit2() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "23:59:59; 1-Apr-99");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(1999, c.get(Calendar.YEAR));
+    }
+
+    @Test
+    public void testParseExpiryYearTwoDigit3() throws Exception {
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        final CookieAttributeHandler h = new LaxExpiresHandler();
+        h.parse(cookie, "23:59:59; 1-Apr-00");
+
+        final Date expiryDate = cookie.getExpiryDate();
+        Assert.assertNotNull(expiryDate);
+        final Calendar c = Calendar.getInstance();
+        c.setTimeZone(LaxExpiresHandler.UTC);
+        c.setTime(expiryDate);
+        Assert.assertEquals(2000, c.get(Calendar.YEAR));
+    }
+
+}
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestPublicSuffixListParser.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestPublicSuffixListParser.java
index d70ee25..86dded9 100644
--- a/httpclient/src/test/java/org/apache/http/impl/cookie/TestPublicSuffixListParser.java
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestPublicSuffixListParser.java
@@ -27,24 +27,37 @@
 
 package org.apache.http.impl.cookie;
 
+import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.Reader;
 
+import org.apache.http.Consts;
+import org.apache.http.conn.util.PublicSuffixList;
+import org.apache.http.conn.util.PublicSuffixMatcher;
 import org.apache.http.cookie.CookieOrigin;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
 public class TestPublicSuffixListParser {
-    private static final String LIST_FILE = "/suffixlist.txt";
-    private PublicSuffixFilter filter;
+
+    private static final String SOURCE_FILE = "suffixlist.txt";
+
+    private PublicSuffixDomainFilter filter;
 
     @Before
     public void setUp() throws Exception {
-        final Reader r = new InputStreamReader(getClass().getResourceAsStream(LIST_FILE), "UTF-8");
-        filter = new PublicSuffixFilter(new RFC2109DomainHandler());
-        final PublicSuffixListParser parser = new PublicSuffixListParser(filter);
-        parser.parse(r);
+        final ClassLoader classLoader = getClass().getClassLoader();
+        final InputStream in = classLoader.getResourceAsStream(SOURCE_FILE);
+        Assert.assertNotNull(in);
+        final PublicSuffixList suffixList;
+        try {
+            final org.apache.http.conn.util.PublicSuffixListParser parser = new org.apache.http.conn.util.PublicSuffixListParser();
+            suffixList = parser.parse(new InputStreamReader(in, Consts.UTF_8));
+        } finally {
+            in.close();
+        }
+        final PublicSuffixMatcher matcher = new PublicSuffixMatcher(suffixList.getRules(), suffixList.getExceptions());
+        this.filter = new PublicSuffixDomainFilter(new RFC2109DomainHandler(), matcher);
     }
 
     @Test
@@ -82,19 +95,4 @@ public class TestPublicSuffixListParser {
         Assert.assertFalse(filter.match(cookie, new CookieOrigin("apache.h\u00E5.no", 80, "/stuff", false)));
     }
 
-    @Test
-    public void testWhitespace() throws Exception {
-        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
-        cookie.setDomain(".xx");
-        Assert.assertFalse(filter.match(cookie, new CookieOrigin("apache.xx", 80, "/stuff", false)));
-
-        // yy appears after whitespace
-        cookie.setDomain(".yy");
-        Assert.assertTrue(filter.match(cookie, new CookieOrigin("apache.yy", 80, "/stuff", false)));
-
-        // zz is commented
-        cookie.setDomain(".zz");
-        Assert.assertTrue(filter.match(cookie, new CookieOrigin("apache.zz", 80, "/stuff", false)));
-    }
-
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/cookie/TestRFC6265CookieSpecBase.java b/httpclient/src/test/java/org/apache/http/impl/cookie/TestRFC6265CookieSpecBase.java
new file mode 100644
index 0000000..b8f595d
--- /dev/null
+++ b/httpclient/src/test/java/org/apache/http/impl/cookie/TestRFC6265CookieSpecBase.java
@@ -0,0 +1,337 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.http.Header;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.CommonCookieAttributeHandler;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SetCookie;
+import org.apache.http.message.BasicHeader;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestRFC6265CookieSpecBase {
+
+    @Test
+    public void testParseCookieBasics() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("that");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final Header header = new BasicHeader("Set-Cookie", "name = value ; this = stuff;");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final List<Cookie> cookies = cookiespec.parse(header, origin);
+
+        Assert.assertEquals(1, cookies.size());
+        final Cookie cookie = cookies.get(0);
+        Assert.assertEquals("name", cookie.getName());
+        Assert.assertEquals("value", cookie.getValue());
+        Assert.assertEquals("/path", cookie.getPath());
+        Assert.assertEquals("host", cookie.getDomain());
+        Assert.assertTrue(cookie instanceof ClientCookie);
+        final ClientCookie clientCookie = (ClientCookie) cookie;
+        Assert.assertEquals("stuff", clientCookie.getAttribute("this"));
+        Assert.assertEquals(null, clientCookie.getAttribute("that"));
+
+        Mockito.verify(h1).parse(Mockito.<SetCookie>any(), Mockito.eq("stuff"));
+        Mockito.verify(h2, Mockito.never()).parse(Mockito.<SetCookie>any(), Mockito.anyString());
+    }
+
+    @Test
+    public void testParseCookieQuotedValue() throws Exception {
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+
+        final Header header = new BasicHeader("Set-Cookie", "name = \" one, two, three; four \" ; this = stuff;");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final List<Cookie> cookies = cookiespec.parse(header, origin);
+
+        Assert.assertEquals(1, cookies.size());
+        final Cookie cookie = cookies.get(0);
+        Assert.assertEquals("name", cookie.getName());
+        Assert.assertEquals(" one, two, three; four ", cookie.getValue());
+        Assert.assertTrue(cookie instanceof ClientCookie);
+        final ClientCookie clientCookie = (ClientCookie) cookie;
+        Assert.assertEquals("stuff", clientCookie.getAttribute("this"));
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseCookieWrongHeader() throws Exception {
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+
+        final Header header = new BasicHeader("Set-Cookie2", "blah");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        cookiespec.parse(header, origin);
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseCookieMissingName() throws Exception {
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+
+        final Header header = new BasicHeader("Set-Cookie", "=blah ; this = stuff;");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        cookiespec.parse(header, origin);
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseCookieMissingValue1() throws Exception {
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+
+        final Header header = new BasicHeader("Set-Cookie", "blah");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        cookiespec.parse(header, origin);
+    }
+
+    @Test(expected = MalformedCookieException.class)
+    public void testParseCookieMissingValue2() throws Exception {
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+
+        final Header header = new BasicHeader("Set-Cookie", "blah;");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        cookiespec.parse(header, origin);
+    }
+
+    @Test
+    public void testParseCookieEmptyValue() throws Exception {
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+
+        final Header header = new BasicHeader("Set-Cookie", "blah=;");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final List<Cookie> cookies = cookiespec.parse(header, origin);
+        Assert.assertEquals(1, cookies.size());
+        final Cookie cookie = cookies.get(0);
+        Assert.assertEquals("blah", cookie.getName());
+        Assert.assertEquals("", cookie.getValue());
+    }
+
+    @Test
+    public void testParseCookieWithAttributes() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("that");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 = v ; p2 = v,0; p3 ; p4");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final List<Cookie> cookies = cookiespec.parse(header, origin);
+
+        Assert.assertEquals(1, cookies.size());
+        final Cookie cookie = cookies.get(0);
+        Assert.assertEquals("name", cookie.getName());
+        Assert.assertEquals("value", cookie.getValue());
+        Assert.assertTrue(cookie instanceof ClientCookie);
+        final ClientCookie clientCookie = (ClientCookie) cookie;
+        Assert.assertEquals("v", clientCookie.getAttribute("p1"));
+        Assert.assertEquals("v,0", clientCookie.getAttribute("p2"));
+        Assert.assertTrue(clientCookie.containsAttribute("p3"));
+        Assert.assertTrue(clientCookie.containsAttribute("p4"));
+        Assert.assertFalse(clientCookie.containsAttribute("p5"));
+    }
+
+    @Test
+    public void testParseCookieWithAttributes2() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("that");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 = v");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final List<Cookie> cookies = cookiespec.parse(header, origin);
+
+        Assert.assertEquals(1, cookies.size());
+        final Cookie cookie = cookies.get(0);
+        Assert.assertEquals("name", cookie.getName());
+        Assert.assertEquals("value", cookie.getValue());
+        Assert.assertTrue(cookie instanceof ClientCookie);
+        final ClientCookie clientCookie = (ClientCookie) cookie;
+        Assert.assertEquals("v", clientCookie.getAttribute("p1"));
+    }
+
+    @Test
+    public void testParseCookieWithAttributes3() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("that");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 =");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final List<Cookie> cookies = cookiespec.parse(header, origin);
+
+        Assert.assertEquals(1, cookies.size());
+        final Cookie cookie = cookies.get(0);
+        Assert.assertEquals("name", cookie.getName());
+        Assert.assertEquals("value", cookie.getValue());
+        Assert.assertTrue(cookie instanceof ClientCookie);
+        final ClientCookie clientCookie = (ClientCookie) cookie;
+        Assert.assertEquals("", clientCookie.getAttribute("p1"));
+    }
+
+    @Test
+    public void testValidateCookieBasics() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("that");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+        cookiespec.validate(cookie, origin);
+
+        Mockito.verify(h1).validate(cookie, origin);
+        Mockito.verify(h2).validate(cookie, origin);
+    }
+
+    @Test
+    public void testMatchCookie() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("that");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+
+        Mockito.when(h1.match(cookie, origin)).thenReturn(true);
+        Mockito.when(h2.match(cookie, origin)).thenReturn(true);
+
+        Assert.assertTrue(cookiespec.match(cookie, origin));
+
+        Mockito.verify(h1).match(cookie, origin);
+        Mockito.verify(h2).match(cookie, origin);
+    }
+
+    @Test
+    public void testMatchCookieNoMatch() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("that");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        final BasicClientCookie cookie = new BasicClientCookie("name", "value");
+
+        Mockito.when(h1.match(cookie, origin)).thenReturn(false);
+        Mockito.when(h2.match(cookie, origin)).thenReturn(false);
+
+        Assert.assertFalse(cookiespec.match(cookie, origin));
+
+        Mockito.verify(h1).match(cookie, origin);
+        Mockito.verify(h2, Mockito.never()).match(cookie, origin);
+    }
+
+    @Test
+    public void testLegacy() throws Exception {
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+
+        Assert.assertEquals(0, cookiespec.getVersion());
+        Assert.assertEquals(null, cookiespec.getVersionHeader());
+    }
+
+    @Test
+    public void testFormatCookiesBasics() throws Exception {
+        final Cookie cookie1 = new BasicClientCookie("name1", "value");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+        final List<Header> headers = cookiespec.formatCookies(Arrays.asList(cookie1));
+        Assert.assertNotNull(headers);
+        Assert.assertEquals(1, headers.size());
+        final Header header = headers.get(0);
+        Assert.assertEquals("Cookie", header.getName());
+        Assert.assertEquals("name1=value", header.getValue());
+    }
+
+    @Test
+    public void testFormatCookiesIllegalCharsInValue() throws Exception {
+        final Cookie cookie1 = new BasicClientCookie("name1", "value");
+        final Cookie cookie2 = new BasicClientCookie("name2", "some value");
+        final Cookie cookie3 = new BasicClientCookie("name3", "\"\\\"");
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
+        final List<Header> headers = cookiespec.formatCookies(Arrays.asList(cookie1, cookie2, cookie3));
+        Assert.assertNotNull(headers);
+        Assert.assertEquals(1, headers.size());
+        final Header header = headers.get(0);
+        Assert.assertEquals("Cookie", header.getName());
+        Assert.assertEquals("name1=value; name2=\"some value\"; name3=\"\\\"\\\\\\\"\"", header.getValue());
+    }
+
+    @Test
+    public void testParseCookieMultipleAttributes() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("this");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1);
+
+        final Header header = new BasicHeader("Set-Cookie", "name = value ; this = stuff; this = morestuff;");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        cookiespec.parse(header, origin);
+
+        Mockito.verify(h1).parse(Mockito.<SetCookie>any(), Mockito.eq("morestuff"));
+        Mockito.verify(h1, Mockito.times(1)).parse(Mockito.<SetCookie>any(), Mockito.anyString());
+    }
+
+    @Test
+    public void testParseCookieMaxAgeOverExpires() throws Exception {
+        final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h1.getAttributeName()).thenReturn("Expires");
+        final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
+        Mockito.when(h2.getAttributeName()).thenReturn("Max-Age");
+
+        final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
+
+        final Header header = new BasicHeader("Set-Cookie", "name = value ; expires = stuff; max-age = otherstuff;");
+        final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
+        cookiespec.parse(header, origin);
+
+        Mockito.verify(h1, Mockito.never()).parse(Mockito.<SetCookie>any(), Mockito.anyString());
+        Mockito.verify(h2).parse(Mockito.<SetCookie>any(), Mockito.eq("otherstuff"));
+    }
+
+}
diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestConnectionHolder.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestConnectionHolder.java
index a15593c..a908141 100644
--- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestConnectionHolder.java
+++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestConnectionHolder.java
@@ -37,6 +37,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 
+ at SuppressWarnings({"static-access"}) // test code
 public class TestConnectionHolder {
 
     private Log log;
diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java
index 663bdb9..70e23a8 100644
--- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java
@@ -77,8 +77,10 @@ import org.apache.http.impl.conn.ConnectionShutdownException;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
 import org.apache.http.protocol.HttpRequestExecutor;
 import org.apache.http.util.EntityUtils;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -88,8 +90,6 @@ import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import junit.framework.Assert;
-
 @SuppressWarnings({"boxing","static-access"}) // test code
 public class TestMainClientExec {
 
@@ -102,6 +102,8 @@ public class TestMainClientExec {
     @Mock
     private ConnectionKeepAliveStrategy keepAliveStrategy;
     @Mock
+    private HttpProcessor proxyHttpProcessor;
+    @Mock
     private AuthenticationStrategy targetAuthStrategy;
     @Mock
     private AuthenticationStrategy proxyAuthStrategy;
@@ -122,7 +124,7 @@ public class TestMainClientExec {
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
         mainClientExec = new MainClientExec(requestExecutor, connManager, reuseStrategy,
-            keepAliveStrategy, targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
+            keepAliveStrategy, proxyHttpProcessor, targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
         target = new HttpHost("foo", 80);
         proxy = new HttpHost("bar", 8888);
 
@@ -307,35 +309,6 @@ public class TestMainClientExec {
     }
 
     @Test
-    public void testExecRequestStaleConnectionCheck() throws Exception {
-        final HttpRoute route = new HttpRoute(target);
-        final HttpClientContext context = new HttpClientContext();
-        final RequestConfig config = RequestConfig.custom()
-                .setStaleConnectionCheckEnabled(true)
-                .build();
-        final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
-        context.setRequestConfig(config);
-        final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
-
-        Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
-        Mockito.when(managedConn.isStale()).thenReturn(Boolean.TRUE);
-        Mockito.when(requestExecutor.execute(
-                Mockito.same(request),
-                Mockito.<HttpClientConnection>any(),
-                Mockito.<HttpClientContext>any())).thenReturn(response);
-        Mockito.when(reuseStrategy.keepAlive(
-                Mockito.same(response),
-                Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
-
-        final CloseableHttpResponse finalResponse = mainClientExec.execute(
-                route, request, context, execAware);
-        Mockito.verify(managedConn, Mockito.times(1)).close();
-
-        Assert.assertNotNull(finalResponse);
-        Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
-    }
-
-    @Test
     public void testSocketTimeoutExistingConnection() throws Exception {
         final HttpRoute route = new HttpRoute(target);
         final HttpClientContext context = new HttpClientContext();
@@ -551,10 +524,11 @@ public class TestMainClientExec {
                 Mockito.<HttpClientConnection>any(),
                 Mockito.<HttpClientContext>any())).thenAnswer(new Answer<HttpResponse>() {
 
+            @Override
             public HttpResponse answer(final InvocationOnMock invocationOnMock) throws Throwable {
                 final Object[] args = invocationOnMock.getArguments();
-                final HttpEntityEnclosingRequest request = (HttpEntityEnclosingRequest) args[0];
-                request.getEntity().writeTo(new ByteArrayOutputStream());
+                final HttpEntityEnclosingRequest requestEE = (HttpEntityEnclosingRequest) args[0];
+                requestEE.getEntity().writeTo(new ByteArrayOutputStream());
                 return response1;
             }
 
diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java
index dc0906a..7c79f14 100644
--- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestMinimalClientExec.java
@@ -26,8 +26,6 @@
  */
 package org.apache.http.impl.execchain;
 
-import static org.junit.Assert.assertEquals;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InterruptedIOException;
@@ -56,6 +54,7 @@ import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.impl.conn.ConnectionShutdownException;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.protocol.HttpRequestExecutor;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -63,8 +62,6 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import junit.framework.Assert;
-
 @SuppressWarnings({"boxing","static-access"}) // test code
 public class TestMinimalClientExec {
 
@@ -360,6 +357,6 @@ public class TestMinimalClientExec {
         final ArgumentCaptor<HttpRequest> reqCaptor = ArgumentCaptor.forClass(HttpRequest.class);
         Mockito.verify(requestExecutor).execute(reqCaptor.capture(), Mockito.<HttpClientConnection>any(), Mockito.<HttpClientContext>any());
 
-        assertEquals("/test", reqCaptor.getValue().getRequestLine().getUri());
+        Assert.assertEquals("/test", reqCaptor.getValue().getRequestLine().getUri());
     }
 }
diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestProtocolExec.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestProtocolExec.java
index f2168ed..150393b 100644
--- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestProtocolExec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestProtocolExec.java
@@ -26,6 +26,9 @@
  */
 package org.apache.http.impl.execchain;
 
+import java.io.IOException;
+import java.net.URI;
+
 import org.apache.http.HttpException;
 import org.apache.http.HttpHost;
 import org.apache.http.auth.AuthScope;
@@ -47,9 +50,6 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.io.IOException;
-import java.net.URI;
-
 @SuppressWarnings({"static-access"}) // test code
 public class TestProtocolExec {
 
diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java
index 205a50d..ed1546c 100644
--- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java
@@ -26,7 +26,6 @@
  */
 package org.apache.http.impl.execchain;
 
-import junit.framework.Assert;
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpException;
@@ -51,6 +50,7 @@ import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.conn.routing.HttpRoutePlanner;
 import org.apache.http.impl.auth.BasicScheme;
 import org.apache.http.impl.auth.NTLMScheme;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -271,7 +271,7 @@ public class TestRedirectExec {
         Mockito.when(httpRoutePlanner.determineRoute(
                 Mockito.eq(target),
                 Mockito.<HttpRequestWrapper>any(),
-                Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(new HttpHost("otherhost")));
+                Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(new HttpHost("otherhost", 80)));
 
         redirectExec.execute(route, request, context, execAware);
 
diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java
index 841b6af..00c06d1 100644
--- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java
+++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestResponseEntityWrapper.java
@@ -38,7 +38,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 
- at SuppressWarnings({"boxing"}) // test code
+ at SuppressWarnings("boxing") // test code
 public class TestResponseEntityWrapper {
 
     private InputStream instream;
diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestRetryExec.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestRetryExec.java
index 5dd0534..e0cb016 100644
--- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestRetryExec.java
+++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestRetryExec.java
@@ -26,7 +26,6 @@
  */
 package org.apache.http.impl.execchain;
 
-import junit.framework.Assert;
 import org.apache.http.Header;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpHost;
@@ -40,6 +39,7 @@ import org.apache.http.client.methods.HttpRequestWrapper;
 import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.protocol.HttpContext;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -87,6 +87,7 @@ public class TestRetryExec {
                 Mockito.<HttpClientContext>any(),
                 Mockito.<HttpExecutionAware>any())).thenAnswer(new Answer<Object>() {
 
+            @Override
             public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
                 final Object[] args = invocationOnMock.getArguments();
                 final HttpRequestWrapper wrapper = (HttpRequestWrapper) args[1];
@@ -162,10 +163,11 @@ public class TestRetryExec {
                 Mockito.<HttpClientContext>any(),
                 Mockito.<HttpExecutionAware>any())).thenAnswer(new Answer<Object>() {
 
+            @Override
             public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
                 final Object[] args = invocationOnMock.getArguments();
-                final HttpEntityEnclosingRequest request = (HttpEntityEnclosingRequest) args[1];
-                request.getEntity().writeTo(new ByteArrayOutputStream());
+                final HttpEntityEnclosingRequest req = (HttpEntityEnclosingRequest) args[1];
+                req.getEntity().writeTo(new ByteArrayOutputStream());
                 throw new IOException("Ka-boom");
             }
 
diff --git a/httpclient/src/test/java/org/apache/http/localserver/EchoHandler.java b/httpclient/src/test/java/org/apache/http/localserver/EchoHandler.java
index c823357..380607e 100644
--- a/httpclient/src/test/java/org/apache/http/localserver/EchoHandler.java
+++ b/httpclient/src/test/java/org/apache/http/localserver/EchoHandler.java
@@ -67,12 +67,13 @@ public class EchoHandler
      * @throws HttpException    in case of a problem
      * @throws IOException      in case of an IO problem
      */
+    @Override
     public void handle(final HttpRequest request,
                        final HttpResponse response,
                        final HttpContext context)
         throws HttpException, IOException {
 
-        final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
+        final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
         if (!"GET".equals(method) &&
             !"POST".equals(method) &&
             !"PUT".equals(method)
diff --git a/httpclient/src/test/java/org/apache/http/localserver/LocalServerTestBase.java b/httpclient/src/test/java/org/apache/http/localserver/LocalServerTestBase.java
index b8e52b5..38833e2 100644
--- a/httpclient/src/test/java/org/apache/http/localserver/LocalServerTestBase.java
+++ b/httpclient/src/test/java/org/apache/http/localserver/LocalServerTestBase.java
@@ -27,10 +27,17 @@
 
 package org.apache.http.localserver;
 
-import java.net.InetSocketAddress;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.http.HttpHost;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.impl.bootstrap.HttpServer;
+import org.apache.http.impl.bootstrap.ServerBootstrap;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.junit.After;
+import org.junit.Before;
 
 /**
  * Base class for tests using {@link LocalTestServer}. The server will not be started
@@ -38,37 +45,69 @@ import org.junit.After;
  */
 public abstract class LocalServerTestBase {
 
-    /** The local server for testing. */
-    protected LocalTestServer localServer;
+    public enum ProtocolScheme { http, https };
 
-    @After
-    public void shutDownServer() throws Exception {
-        if (localServer != null) {
-            localServer.stop();
+    public static final String ORIGIN = "TEST/1.1";
+
+    protected final ProtocolScheme scheme;
+
+    protected ServerBootstrap serverBootstrap;
+    protected HttpServer server;
+    protected PoolingHttpClientConnectionManager connManager;
+    protected HttpClientBuilder clientBuilder;
+    protected CloseableHttpClient httpclient;
+
+    public LocalServerTestBase(final ProtocolScheme scheme) {
+        this.scheme = scheme;
+    }
+
+    public LocalServerTestBase() {
+        this(ProtocolScheme.http);
+    }
+
+    public String getSchemeName() {
+        return this.scheme.name();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        final SocketConfig socketConfig = SocketConfig.custom()
+                .setSoTimeout(15000)
+                .build();
+        this.serverBootstrap = ServerBootstrap.bootstrap()
+                .setSocketConfig(socketConfig)
+                .setServerInfo(ORIGIN)
+                .registerHandler("/echo/*", new EchoHandler())
+                .registerHandler("/random/*", new RandomHandler());
+        if (this.scheme.equals(ProtocolScheme.https)) {
+            this.serverBootstrap.setSslContext(SSLTestContexts.createServerSSLContext());
         }
-        localServer = null;
+
+        this.connManager = new PoolingHttpClientConnectionManager();
+        this.clientBuilder = HttpClientBuilder.create()
+                .setDefaultSocketConfig(socketConfig)
+                .setConnectionManager(this.connManager);
     }
 
-    protected void startServer() throws Exception {
-        if (localServer == null) {
-            localServer = new LocalTestServer(null, null);
-            localServer.registerDefaultHandlers();
+    @After
+    public void shutDown() throws Exception {
+        if (this.httpclient != null) {
+            this.httpclient.close();
+        }
+        if (this.server != null) {
+            this.server.shutdown(10, TimeUnit.SECONDS);
         }
-        localServer.setTimeout(5000);
-        localServer.start();
     }
 
-    /**
-     * Obtains the address of the local test server.
-     *
-     * @return  the test server host, with a scheme name of "http"
-     */
-    protected HttpHost getServerHttp() {
-        final InetSocketAddress address = localServer.getServiceAddress();
-        return new HttpHost(
-                address.getHostName(),
-                address.getPort(),
-                "http");
+    public HttpHost start() throws Exception {
+        this.server = this.serverBootstrap.create();
+        this.server.start();
+
+        if (this.httpclient == null) {
+            this.httpclient = this.clientBuilder.build();
+        }
+
+        return new HttpHost("localhost", this.server.getLocalPort(), this.scheme.name());
     }
 
 }
diff --git a/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java b/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java
deleted file mode 100644
index 40d0852..0000000
--- a/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.http.localserver;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-
-import org.apache.http.ConnectionReuseStrategy;
-import org.apache.http.HttpResponseFactory;
-import org.apache.http.HttpResponseInterceptor;
-import org.apache.http.HttpServerConnection;
-import org.apache.http.impl.DefaultBHttpServerConnection;
-import org.apache.http.impl.DefaultConnectionReuseStrategy;
-import org.apache.http.impl.DefaultHttpResponseFactory;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.protocol.HttpExpectationVerifier;
-import org.apache.http.protocol.HttpProcessor;
-import org.apache.http.protocol.HttpRequestHandler;
-import org.apache.http.protocol.HttpService;
-import org.apache.http.protocol.ImmutableHttpProcessor;
-import org.apache.http.protocol.ResponseConnControl;
-import org.apache.http.protocol.ResponseContent;
-import org.apache.http.protocol.ResponseDate;
-import org.apache.http.protocol.ResponseServer;
-import org.apache.http.protocol.UriHttpRequestHandlerMapper;
-import org.apache.http.util.Asserts;
-
-/**
- * Local HTTP server for tests that require one.
- * Based on the <code>ElementalHttpServer</code> example in HttpCore.
- */
-public class LocalTestServer {
-
-    public final static String ORIGIN = "LocalTestServer/1.1";
-
-    /**
-     * The local address to bind to.
-     * The host is an IP number rather than "localhost" to avoid surprises
-     * on hosts that map "localhost" to an IPv6 address or something else.
-     * The port is 0 to let the system pick one.
-     */
-    public final static InetSocketAddress TEST_SERVER_ADDR =
-        new InetSocketAddress("127.0.0.1", 0);
-
-    /** The request handler registry. */
-    private final UriHttpRequestHandlerMapper handlerRegistry;
-
-    private final HttpService httpservice;
-
-    /** Optional SSL context */
-    private final SSLContext sslcontext;
-
-    /** Optional flag whether to force SSL context */
-    private final boolean forceSSLAuth;
-
-    /** The server socket, while being served. */
-    private volatile ServerSocket servicedSocket;
-
-    /** The request listening thread, while listening. */
-    private volatile ListenerThread listenerThread;
-
-    /** Set of active worker threads */
-    private final Set<Worker> workers;
-
-    /** The number of connections this accepted. */
-    private final AtomicInteger acceptedConnections = new AtomicInteger(0);
-
-    private volatile int timeout;
-
-    /**
-     * Creates a new test server.
-     *
-     * @param proc      the HTTP processors to be used by the server, or
-     *                  <code>null</code> to use a
-     *                  {@link #newProcessor default} processor
-     * @param reuseStrat the connection reuse strategy to be used by the
-     *                  server, or <code>null</code> to use
-     *                  {@link #newConnectionReuseStrategy() default}
-     *                  strategy.
-     * @param responseFactory the response factory to be used by the
-     *                  server, or <code>null</code> to use
-     *                  {@link #newHttpResponseFactory() default} factory.
-     * @param expectationVerifier the expectation verifier. May be
-     *                  <code>null</code>.
-     * @param sslcontext optional SSL context if the server is to leverage
-     *                   SSL/TLS transport security
-     * @param forceSSLAuth whether or not the server needs to enforce client auth
-     */
-    public LocalTestServer(
-            final HttpProcessor proc,
-            final ConnectionReuseStrategy reuseStrat,
-            final HttpResponseFactory responseFactory,
-            final HttpExpectationVerifier expectationVerifier,
-            final SSLContext sslcontext,
-            final boolean forceSSLAuth) {
-        super();
-        this.handlerRegistry = new UriHttpRequestHandlerMapper();
-        this.workers = Collections.synchronizedSet(new HashSet<Worker>());
-        this.httpservice = new HttpService(
-            proc != null ? proc : newProcessor(),
-            reuseStrat != null ? reuseStrat: newConnectionReuseStrategy(),
-            responseFactory != null ? responseFactory: newHttpResponseFactory(),
-            handlerRegistry,
-            expectationVerifier);
-        this.sslcontext = sslcontext;
-        this.forceSSLAuth = forceSSLAuth;
-    }
-
-    public LocalTestServer(
-            final HttpProcessor proc,
-            final ConnectionReuseStrategy reuseStrat) {
-        this(proc, reuseStrat, null, null, null, false);
-    }
-
-    /**
-     * Creates a new test server with SSL/TLS encryption.
-     *
-     * @param sslcontext SSL context
-     * @param forceSSLAuth whether or not the server needs to enforce client auth
-     */
-    public LocalTestServer(final SSLContext sslcontext, final boolean forceSSLAuth) {
-        this(null, null, null, null, sslcontext, forceSSLAuth);
-    }
-
-    /**
-     * Creates a new test server with SSL/TLS encryption.
-     *
-     * @param sslcontext SSL context
-     */
-    public LocalTestServer(final SSLContext sslcontext) {
-        this(null, null, null, null, sslcontext, false);
-    }
-
-    /**
-     * Obtains an HTTP protocol processor with default interceptors.
-     *
-     * @return  a protocol processor for server-side use
-     */
-    protected HttpProcessor newProcessor() {
-        return new ImmutableHttpProcessor(
-                new HttpResponseInterceptor[] {
-                        new ResponseDate(),
-                        new ResponseServer(ORIGIN),
-                        new ResponseContent(),
-                        new ResponseConnControl()
-                });
-    }
-
-    protected ConnectionReuseStrategy newConnectionReuseStrategy() {
-        return DefaultConnectionReuseStrategy.INSTANCE;
-    }
-
-    protected HttpResponseFactory newHttpResponseFactory() {
-        return DefaultHttpResponseFactory.INSTANCE;
-    }
-
-    /**
-     * Returns the number of connections this test server has accepted.
-     */
-    public int getAcceptedConnectionCount() {
-        return acceptedConnections.get();
-    }
-
-    /**
-     * {@link #register Registers} a set of default request handlers.
-     * <pre>
-     * URI pattern      Handler
-     * -----------      -------
-     * /echo/*          {@link EchoHandler EchoHandler}
-     * /random/*        {@link RandomHandler RandomHandler}
-     * </pre>
-     */
-    public void registerDefaultHandlers() {
-        handlerRegistry.register("/echo/*", new EchoHandler());
-        handlerRegistry.register("/random/*", new RandomHandler());
-    }
-
-    /**
-     * Registers a handler with the local registry.
-     *
-     * @param pattern   the URL pattern to match
-     * @param handler   the handler to apply
-     */
-    public void register(final String pattern, final HttpRequestHandler handler) {
-        handlerRegistry.register(pattern, handler);
-    }
-
-    /**
-     * Unregisters a handler from the local registry.
-     *
-     * @param pattern   the URL pattern
-     */
-    public void unregister(final String pattern) {
-        handlerRegistry.unregister(pattern);
-    }
-
-    public int getTimeout() {
-        return timeout;
-    }
-
-    public void setTimeout(final int timeout) {
-        this.timeout = timeout;
-    }
-
-    /**
-     * Starts this test server.
-     */
-    public void start() throws Exception {
-        Asserts.check(servicedSocket == null, "Already running");
-        final ServerSocket ssock;
-        if (sslcontext != null) {
-            final SSLServerSocketFactory sf = sslcontext.getServerSocketFactory();
-            final SSLServerSocket sslsock = (SSLServerSocket) sf.createServerSocket();
-            if (forceSSLAuth) {
-                sslsock.setNeedClientAuth(true);
-            } else {
-                sslsock.setWantClientAuth(true);
-            }
-            ssock = sslsock;
-        } else {
-            ssock = new ServerSocket();
-        }
-
-        ssock.setReuseAddress(true); // probably pointless for port '0'
-        ssock.bind(TEST_SERVER_ADDR);
-        servicedSocket = ssock;
-
-        listenerThread = new ListenerThread();
-        listenerThread.setDaemon(false);
-        listenerThread.start();
-    }
-
-    /**
-     * Stops this test server.
-     */
-    public void stop() throws Exception {
-        if (servicedSocket == null) {
-            return; // not running
-        }
-        final ListenerThread t = listenerThread;
-        if (t != null) {
-            t.shutdown();
-        }
-        synchronized (workers) {
-            for (final Worker worker : workers) {
-                worker.shutdown();
-            }
-        }
-    }
-
-    public void awaitTermination(final long timeMs) throws InterruptedException {
-        if (listenerThread != null) {
-            listenerThread.join(timeMs);
-        }
-    }
-
-    @Override
-    public String toString() {
-        final ServerSocket ssock = servicedSocket; // avoid synchronization
-        final StringBuilder sb = new StringBuilder(80);
-        sb.append("LocalTestServer/");
-        if (ssock == null) {
-            sb.append("stopped");
-        } else {
-            sb.append(ssock.getLocalSocketAddress());
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Obtains the local address the server is listening on
-     *
-     * @return the service address
-     */
-    public InetSocketAddress getServiceAddress() {
-        final ServerSocket ssock = servicedSocket; // avoid synchronization
-        Asserts.notNull(ssock, "Not running");
-        return (InetSocketAddress) ssock.getLocalSocketAddress();
-    }
-
-    /**
-     * Creates an instance of {@link DefaultBHttpServerConnection} to be used
-     * in the Worker thread.
-     * <p>
-     * This method can be overridden in a super class in order to provide
-     * a different implementation of the {@link DefaultBHttpServerConnection}.
-     *
-     * @return DefaultBHttpServerConnection.
-     */
-    protected DefaultBHttpServerConnection createHttpServerConnection() {
-      return new DefaultBHttpServerConnection(8 * 1024);
-    }
-
-    /**
-     * The request listener.
-     * Accepts incoming connections and launches a service thread.
-     */
-    class ListenerThread extends Thread {
-
-        private volatile Exception exception;
-
-        ListenerThread() {
-            super();
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!interrupted()) {
-                    final Socket socket = servicedSocket.accept();
-                    acceptedConnections.incrementAndGet();
-                    final DefaultBHttpServerConnection conn = createHttpServerConnection();
-                    conn.bind(socket);
-                    conn.setSocketTimeout(timeout);
-                    // Start worker thread
-                    final Worker worker = new Worker(conn);
-                    workers.add(worker);
-                    worker.setDaemon(true);
-                    worker.start();
-                }
-            } catch (final Exception ex) {
-                this.exception = ex;
-            } finally {
-                try {
-                    servicedSocket.close();
-                } catch (final IOException ignore) {
-                }
-            }
-        }
-
-        public void shutdown() {
-            interrupt();
-            try {
-                servicedSocket.close();
-            } catch (final IOException ignore) {
-            }
-        }
-
-        public Exception getException() {
-            return this.exception;
-        }
-
-    }
-
-    class Worker extends Thread {
-
-        private final HttpServerConnection conn;
-
-        private volatile Exception exception;
-
-        public Worker(final HttpServerConnection conn) {
-            this.conn = conn;
-        }
-
-        @Override
-        public void run() {
-            final HttpContext context = new BasicHttpContext();
-            try {
-                while (this.conn.isOpen() && !Thread.interrupted()) {
-                    httpservice.handleRequest(this.conn, context);
-                }
-            } catch (final Exception ex) {
-                this.exception = ex;
-            } finally {
-                workers.remove(this);
-                try {
-                    this.conn.shutdown();
-                } catch (final IOException ignore) {
-                }
-            }
-        }
-
-        public void shutdown() {
-            interrupt();
-            try {
-                this.conn.shutdown();
-            } catch (final IOException ignore) {
-            }
-        }
-
-        public Exception getException() {
-            return this.exception;
-        }
-
-    }
-
-}
diff --git a/httpclient/src/test/java/org/apache/http/localserver/RandomHandler.java b/httpclient/src/test/java/org/apache/http/localserver/RandomHandler.java
index a003768..b1195ab 100644
--- a/httpclient/src/test/java/org/apache/http/localserver/RandomHandler.java
+++ b/httpclient/src/test/java/org/apache/http/localserver/RandomHandler.java
@@ -30,9 +30,9 @@ package org.apache.http.localserver;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.Locale;
 
+import org.apache.http.Consts;
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
@@ -42,19 +42,10 @@ import org.apache.http.entity.AbstractHttpEntity;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpRequestHandler;
 
-
-
 /**
  * A handler that generates random data.
- *
- *
- *
- * <!-- empty lines to avoid 'svn diff' problems -->
  */
-public class RandomHandler
-    implements HttpRequestHandler {
-
-    // public default constructor
+public class RandomHandler implements HttpRequestHandler {
 
     /**
      * Handles a request by generating random data.
@@ -71,12 +62,13 @@ public class RandomHandler
      * @throws HttpException    in case of a problem
      * @throws IOException      in case of an IO problem
      */
+    @Override
     public void handle(final HttpRequest request,
                        final HttpResponse response,
                        final HttpContext context)
         throws HttpException, IOException {
 
-        final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
+        final String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
         if (!"GET".equals(method) && !"HEAD".equals(method)) {
             throw new MethodNotSupportedException
                 (method + " not supported by " + getClass().getName());
@@ -130,19 +122,8 @@ public class RandomHandler
     public static class RandomEntity extends AbstractHttpEntity {
 
         /** The range from which to generate random data. */
-        private final static byte[] RANGE;
-        static {
-            byte[] range = null;
-            try {
-                range = ("abcdefghijklmnopqrstuvwxyz" +
-                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"
-                    ).getBytes("US-ASCII");
-            } catch (final UnsupportedEncodingException uex) {
-                // never, US-ASCII is guaranteed
-            }
-            RANGE = range;
-        }
-
+        private final static byte[] RANGE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+                .getBytes(Consts.ASCII);
 
         /** The length of the random data to generate. */
         protected final long length;
@@ -163,6 +144,7 @@ public class RandomHandler
          *
          * @return      false
          */
+        @Override
         public final boolean isStreaming() {
             return false;
         }
@@ -172,8 +154,9 @@ public class RandomHandler
          * Repetitions will generate different random data,
          * unless perchance the same random data is generated twice.
          *
-         * @return      <code>true</code>
+         * @return      {@code true}
          */
+        @Override
         public boolean isRepeatable() {
             return true;
         }
@@ -183,6 +166,7 @@ public class RandomHandler
          *
          * @return      the number of random bytes to generate
          */
+        @Override
         public long getContentLength() {
             return length;
         }
@@ -194,6 +178,7 @@ public class RandomHandler
          *
          * @return      never anything
          */
+        @Override
         public InputStream getContent() {
             throw new UnsupportedOperationException();
         }
@@ -204,6 +189,7 @@ public class RandomHandler
          *
          * @param out   where to write the content to
          */
+        @Override
         public void writeTo(final OutputStream out) throws IOException {
 
             final int blocksize = 2048;
diff --git a/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java b/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
index 5e5fca8..5723bd6 100644
--- a/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
+++ b/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
@@ -43,6 +43,7 @@ public class RequestBasicAuth implements HttpRequestInterceptor {
         this.authTokenExtractor = new BasicAuthTokenExtractor();
     }
 
+    @Override
     public void process(
             final HttpRequest request,
             final HttpContext context) throws HttpException, IOException {
diff --git a/httpclient/src/test/java/org/apache/http/localserver/ResponseBasicUnauthorized.java b/httpclient/src/test/java/org/apache/http/localserver/ResponseBasicUnauthorized.java
index 01cca6f..a6a92b5 100644
--- a/httpclient/src/test/java/org/apache/http/localserver/ResponseBasicUnauthorized.java
+++ b/httpclient/src/test/java/org/apache/http/localserver/ResponseBasicUnauthorized.java
@@ -38,11 +38,14 @@ import org.apache.http.protocol.HttpContext;
 
 public class ResponseBasicUnauthorized implements HttpResponseInterceptor {
 
+    @Override
     public void process(
             final HttpResponse response,
             final HttpContext context) throws HttpException, IOException {
         if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
-            response.addHeader(AUTH.WWW_AUTH, "Basic realm=\"test realm\"");
+            if (!response.containsHeader(AUTH.WWW_AUTH)) {
+                response.addHeader(AUTH.WWW_AUTH, "Basic realm=\"test realm\"");
+            }
         }
     }
 
diff --git a/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java b/httpclient/src/test/java/org/apache/http/localserver/SSLTestContexts.java
similarity index 60%
copy from httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
copy to httpclient/src/test/java/org/apache/http/localserver/SSLTestContexts.java
index 5e5fca8..2bfb5af 100644
--- a/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
+++ b/httpclient/src/test/java/org/apache/http/localserver/SSLTestContexts.java
@@ -27,26 +27,26 @@
 
 package org.apache.http.localserver;
 
-import java.io.IOException;
+import javax.net.ssl.SSLContext;
 
-import org.apache.http.HttpException;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.protocol.HttpContext;
+import org.apache.http.ssl.SSLContexts;
 
-public class RequestBasicAuth implements HttpRequestInterceptor {
+public class SSLTestContexts {
 
-    private final BasicAuthTokenExtractor authTokenExtractor;
-
-    public RequestBasicAuth() {
-        super();
-        this.authTokenExtractor = new BasicAuthTokenExtractor();
+    public static SSLContext createServerSSLContext() throws Exception {
+        return SSLContexts.custom()
+                .loadTrustMaterial(SSLTestContexts.class.getResource("/test.keystore"),
+                        "nopassword".toCharArray())
+                .loadKeyMaterial(SSLTestContexts.class.getResource("/test.keystore"),
+                        "nopassword".toCharArray(), "nopassword".toCharArray())
+                .build();
     }
 
-    public void process(
-            final HttpRequest request,
-            final HttpContext context) throws HttpException, IOException {
-        context.setAttribute("creds", this.authTokenExtractor.extract(request));
+    public static SSLContext createClientSSLContext() throws Exception {
+        return SSLContexts.custom()
+                .loadTrustMaterial(SSLTestContexts.class.getResource("/test.keystore"),
+                        "nopassword".toCharArray())
+                .build();
     }
 
 }
diff --git a/httpclient/src/test/resources/hc-test-1.truststore b/httpclient/src/test/resources/hc-test-1.truststore
deleted file mode 100644
index d8610f6..0000000
Binary files a/httpclient/src/test/resources/hc-test-1.truststore and /dev/null differ
diff --git a/httpclient/src/test/resources/hc-test-2.truststore b/httpclient/src/test/resources/hc-test-2.truststore
deleted file mode 100644
index 20c1964..0000000
Binary files a/httpclient/src/test/resources/hc-test-2.truststore and /dev/null differ
diff --git a/httpclient/src/test/resources/hc-test.keystore b/httpclient/src/test/resources/hc-test.keystore
deleted file mode 100644
index 72254e7..0000000
Binary files a/httpclient/src/test/resources/hc-test.keystore and /dev/null differ
diff --git a/httpclient/src/test/resources/test-keypasswd.keystore b/httpclient/src/test/resources/test-keypasswd.keystore
deleted file mode 100644
index 01dd1bb..0000000
Binary files a/httpclient/src/test/resources/test-keypasswd.keystore and /dev/null differ
diff --git a/httpclient/src/test/resources/test.keystore b/httpclient/src/test/resources/test.keystore
new file mode 100644
index 0000000..917f83e
Binary files /dev/null and b/httpclient/src/test/resources/test.keystore differ
diff --git a/httpmime/pom.xml b/httpmime/pom.xml
index 7050771..5c80b8d 100644
--- a/httpmime/pom.xml
+++ b/httpmime/pom.xml
@@ -28,12 +28,12 @@
   <parent>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpcomponents-client</artifactId>
-    <version>4.3.5</version>
+    <version>4.4.1</version>
   </parent>
   <artifactId>httpmime</artifactId>
   <name>Apache HttpClient Mime</name>
   <description>
-   HttpComponents HttpClient - MIME coded entities
+   Apache HttpComponents HttpClient - MIME coded entities
   </description>
   <url>http://hc.apache.org/httpcomponents-client</url>
   <packaging>jar</packaging>
@@ -97,13 +97,13 @@
 
       <plugin>
         <artifactId>maven-javadoc-plugin</artifactId>
-         <version>${hc.javadoc.version}</version>
+        <version>${hc.javadoc.version}</version>
         <configuration>
           <!-- reduce console output. Can override with -Dquiet=false -->
           <quiet>true</quiet>
           <source>${maven.compiler.source}</source>
           <links>
-            <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
+            <link>http://docs.oracle.com/javase/6/docs/api/</link>
             <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
           </links>
         </configuration>
@@ -133,12 +133,12 @@
 
       <plugin>
         <artifactId>maven-jxr-plugin</artifactId>
-         <version>${hc.jxr.version}</version>
+        <version>${hc.jxr.version}</version>
       </plugin>
 
       <plugin>
         <artifactId>maven-surefire-report-plugin</artifactId>
-         <version>${hc.surefire-report.version}</version>
+        <version>${hc.surefire-report.version}</version>
       </plugin>
 
     </plugins>
diff --git a/httpmime/src/main/java-deprecated/org/apache/http/entity/mime/HttpMultipart.java b/httpmime/src/main/java-deprecated/org/apache/http/entity/mime/HttpMultipart.java
index 0f7be7e..d756f03 100644
--- a/httpmime/src/main/java-deprecated/org/apache/http/entity/mime/HttpMultipart.java
+++ b/httpmime/src/main/java-deprecated/org/apache/http/entity/mime/HttpMultipart.java
@@ -48,6 +48,8 @@ public class HttpMultipart extends AbstractMultipartForm {
     private final HttpMultipartMode mode;
     private final List<FormBodyPart> parts;
 
+    private final String subType;
+
     /**
      * Creates an instance with the specified settings.
      *
@@ -61,7 +63,8 @@ public class HttpMultipart extends AbstractMultipartForm {
     public HttpMultipart(
             final String subType, final Charset charset, final String boundary,
             final HttpMultipartMode mode) {
-        super(subType, charset, boundary);
+        super(charset, boundary);
+        this.subType = subType;
         this.mode = mode;
         this.parts = new ArrayList<FormBodyPart>();
     }
@@ -123,4 +126,16 @@ public class HttpMultipart extends AbstractMultipartForm {
         this.parts.add(part);
     }
 
+    public String getSubType() {
+        return this.subType;
+    }
+
+    public Charset getCharset() {
+        return this.charset;
+    }
+
+    public String getBoundary() {
+        return this.boundary;
+    }
+
 }
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/AbstractMultipartForm.java b/httpmime/src/main/java/org/apache/http/entity/mime/AbstractMultipartForm.java
index 3f932cd..32249f6 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/AbstractMultipartForm.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/AbstractMultipartForm.java
@@ -93,53 +93,37 @@ abstract class AbstractMultipartForm {
     private static final ByteArrayBuffer CR_LF = encode(MIME.DEFAULT_CHARSET, "\r\n");
     private static final ByteArrayBuffer TWO_DASHES = encode(MIME.DEFAULT_CHARSET, "--");
 
-    private final String subType;
-    protected final Charset charset;
-    private final String boundary;
+    final Charset charset;
+    final String boundary;
 
     /**
      * Creates an instance with the specified settings.
      *
-     * @param subType MIME subtype - must not be {@code null}
      * @param charset the character set to use. May be {@code null}, in which case {@link MIME#DEFAULT_CHARSET} - i.e. US-ASCII - is used.
      * @param boundary to use  - must not be {@code null}
      * @throws IllegalArgumentException if charset is null or boundary is null
      */
-    public AbstractMultipartForm(final String subType, final Charset charset, final String boundary) {
+    public AbstractMultipartForm(final Charset charset, final String boundary) {
         super();
-        Args.notNull(subType, "Multipart subtype");
         Args.notNull(boundary, "Multipart boundary");
-        this.subType = subType;
         this.charset = charset != null ? charset : MIME.DEFAULT_CHARSET;
         this.boundary = boundary;
     }
 
-    public AbstractMultipartForm(final String subType, final String boundary) {
-        this(subType, null, boundary);
-    }
-
-    public String getSubType() {
-        return this.subType;
-    }
-
-    public Charset getCharset() {
-        return this.charset;
+    public AbstractMultipartForm(final String boundary) {
+        this(null, boundary);
     }
 
     public abstract List<FormBodyPart> getBodyParts();
 
-    public String getBoundary() {
-        return this.boundary;
-    }
-
     void doWriteTo(
         final OutputStream out,
         final boolean writeContent) throws IOException {
 
-        final ByteArrayBuffer boundary = encode(this.charset, getBoundary());
+        final ByteArrayBuffer boundaryEncoded = encode(this.charset, this.boundary);
         for (final FormBodyPart part: getBodyParts()) {
             writeBytes(TWO_DASHES, out);
-            writeBytes(boundary, out);
+            writeBytes(boundaryEncoded, out);
             writeBytes(CR_LF, out);
 
             formatMultipartHeader(part, out);
@@ -152,7 +136,7 @@ abstract class AbstractMultipartForm {
             writeBytes(CR_LF, out);
         }
         writeBytes(TWO_DASHES, out);
-        writeBytes(boundary, out);
+        writeBytes(boundaryEncoded, out);
         writeBytes(TWO_DASHES, out);
         writeBytes(CR_LF, out);
     }
@@ -178,12 +162,13 @@ abstract class AbstractMultipartForm {
      * individual parts plus that of extra elements required to delimit the parts
      * from one another). If any of the @{link BodyPart}s contained in this object
      * is of a streaming entity of unknown length the total length is also unknown.
-     * <p/>
+     * <p>
      * This method buffers only a small amount of data in order to determine the
      * total length of the entire entity. The content of individual parts is not
      * buffered.
+     * </p>
      *
-     * @return total length of the multipart entity if known, <code>-1</code>
+     * @return total length of the multipart entity if known, {@code -1}
      *   otherwise.
      */
     public long getTotalLength() {
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/FormBodyPart.java b/httpmime/src/main/java/org/apache/http/entity/mime/FormBodyPart.java
index b7cb7b6..fbf7a53 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/FormBodyPart.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/FormBodyPart.java
@@ -43,9 +43,21 @@ public class FormBodyPart {
 
     private final String name;
     private final Header header;
-
     private final ContentBody body;
 
+    FormBodyPart(final String name, final ContentBody body, final Header header) {
+        super();
+        Args.notNull(name, "Name");
+        Args.notNull(body, "Body");
+        this.name = name;
+        this.body = body;
+        this.header = header != null ? header : new Header();
+    }
+
+    /**
+     * @deprecated (4.4) use {@link org.apache.http.entity.mime.FormBodyPartBuilder}.
+     */
+    @Deprecated
     public FormBodyPart(final String name, final ContentBody body) {
         super();
         Args.notNull(name, "Name");
@@ -76,6 +88,10 @@ public class FormBodyPart {
         this.header.addField(new MinimalField(name, value));
     }
 
+    /**
+     * @deprecated (4.4) use {@link org.apache.http.entity.mime.FormBodyPartBuilder}.
+     */
+    @Deprecated
     protected void generateContentDisp(final ContentBody body) {
         final StringBuilder buffer = new StringBuilder();
         buffer.append("form-data; name=\"");
@@ -89,6 +105,10 @@ public class FormBodyPart {
         addField(MIME.CONTENT_DISPOSITION, buffer.toString());
     }
 
+    /**
+     * @deprecated (4.4) use {@link org.apache.http.entity.mime.FormBodyPartBuilder}.
+     */
+    @Deprecated
     protected void generateContentType(final ContentBody body) {
         final ContentType contentType;
         if (body instanceof AbstractContentBody) {
@@ -109,6 +129,10 @@ public class FormBodyPart {
         }
     }
 
+    /**
+     * @deprecated (4.4) use {@link org.apache.http.entity.mime.FormBodyPartBuilder}.
+     */
+    @Deprecated
     protected void generateTransferEncoding(final ContentBody body) {
         addField(MIME.CONTENT_TRANSFER_ENC, body.getTransferEncoding()); // TE cannot be null
     }
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/FormBodyPartBuilder.java b/httpmime/src/main/java/org/apache/http/entity/mime/FormBodyPartBuilder.java
new file mode 100644
index 0000000..3fd282a
--- /dev/null
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/FormBodyPartBuilder.java
@@ -0,0 +1,141 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity.mime;
+
+import java.util.List;
+
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.content.AbstractContentBody;
+import org.apache.http.entity.mime.content.ContentBody;
+import org.apache.http.util.Args;
+import org.apache.http.util.Asserts;
+
+/**
+ * Builder for individual {@link org.apache.http.entity.mime.FormBodyPart}s.
+ *
+ * @since 4.4
+ */
+public class FormBodyPartBuilder {
+
+    private String name;
+    private ContentBody body;
+    private final Header header;
+
+    public static FormBodyPartBuilder create(final String name, final ContentBody body) {
+        return new FormBodyPartBuilder(name, body);
+    }
+
+    public static FormBodyPartBuilder create() {
+        return new FormBodyPartBuilder();
+    }
+
+    FormBodyPartBuilder(final String name, final ContentBody body) {
+        this();
+        this.name = name;
+        this.body = body;
+    }
+
+    FormBodyPartBuilder() {
+        this.header = new Header();
+    }
+
+    public FormBodyPartBuilder setName(final String name) {
+        this.name = name;
+        return this;
+    }
+
+    public FormBodyPartBuilder setBody(final ContentBody body) {
+        this.body = body;
+        return this;
+    }
+
+    public FormBodyPartBuilder addField(final String name, final String value) {
+        Args.notNull(name, "Field name");
+        this.header.addField(new MinimalField(name, value));
+        return this;
+    }
+
+    public FormBodyPartBuilder setField(final String name, final String value) {
+        Args.notNull(name, "Field name");
+        this.header.setField(new MinimalField(name, value));
+        return this;
+    }
+
+    public FormBodyPartBuilder removeFields(final String name) {
+        Args.notNull(name, "Field name");
+        this.header.removeFields(name);
+        return this;
+    }
+
+    public FormBodyPart build() {
+        Asserts.notBlank(this.name, "Name");
+        Asserts.notNull(this.body, "Content body");
+        final Header headerCopy = new Header();
+        final List<MinimalField> fields = this.header.getFields();
+        for (MinimalField field: fields) {
+            headerCopy.addField(field);
+        }
+        if (headerCopy.getField(MIME.CONTENT_DISPOSITION) == null) {
+            final StringBuilder buffer = new StringBuilder();
+            buffer.append("form-data; name=\"");
+            buffer.append(this.name);
+            buffer.append("\"");
+            if (this.body.getFilename() != null) {
+                buffer.append("; filename=\"");
+                buffer.append(this.body.getFilename());
+                buffer.append("\"");
+            }
+            headerCopy.addField(new MinimalField(MIME.CONTENT_DISPOSITION, buffer.toString()));
+        }
+        if (headerCopy.getField(MIME.CONTENT_TYPE) == null) {
+            final ContentType contentType;
+            if (body instanceof AbstractContentBody) {
+                contentType = ((AbstractContentBody) body).getContentType();
+            } else {
+                contentType = null;
+            }
+            if (contentType != null) {
+                headerCopy.addField(new MinimalField(MIME.CONTENT_TYPE, contentType.toString()));
+            } else {
+                final StringBuilder buffer = new StringBuilder();
+                buffer.append(this.body.getMimeType()); // MimeType cannot be null
+                if (this.body.getCharset() != null) { // charset may legitimately be null
+                    buffer.append("; charset=");
+                    buffer.append(this.body.getCharset());
+                }
+                headerCopy.addField(new MinimalField(MIME.CONTENT_TYPE, buffer.toString()));
+            }
+        }
+        if (headerCopy.getField(MIME.CONTENT_TRANSFER_ENC) == null) {
+            // TE cannot be null
+            headerCopy.addField(new MinimalField(MIME.CONTENT_TRANSFER_ENC, body.getTransferEncoding()));
+        }
+        return new FormBodyPart(this.name, this.body, headerCopy);
+    }
+
+}
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/Header.java b/httpmime/src/main/java/org/apache/http/entity/mime/Header.java
index cebeb78..c39dff5 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/Header.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/Header.java
@@ -54,7 +54,7 @@ public class Header implements Iterable<MinimalField> {
         if (field == null) {
             return;
         }
-        final String key = field.getName().toLowerCase(Locale.ENGLISH);
+        final String key = field.getName().toLowerCase(Locale.ROOT);
         List<MinimalField> values = this.fieldMap.get(key);
         if (values == null) {
             values = new LinkedList<MinimalField>();
@@ -72,7 +72,7 @@ public class Header implements Iterable<MinimalField> {
         if (name == null) {
             return null;
         }
-        final String key = name.toLowerCase(Locale.ENGLISH);
+        final String key = name.toLowerCase(Locale.ROOT);
         final List<MinimalField> list = this.fieldMap.get(key);
         if (list != null && !list.isEmpty()) {
             return list.get(0);
@@ -84,7 +84,7 @@ public class Header implements Iterable<MinimalField> {
         if (name == null) {
             return null;
         }
-        final String key = name.toLowerCase(Locale.ENGLISH);
+        final String key = name.toLowerCase(Locale.ROOT);
         final List<MinimalField> list = this.fieldMap.get(key);
         if (list == null || list.isEmpty()) {
             return Collections.emptyList();
@@ -97,7 +97,7 @@ public class Header implements Iterable<MinimalField> {
         if (name == null) {
             return 0;
         }
-        final String key = name.toLowerCase(Locale.ENGLISH);
+        final String key = name.toLowerCase(Locale.ROOT);
         final List<MinimalField> removed = fieldMap.remove(key);
         if (removed == null || removed.isEmpty()) {
             return 0;
@@ -110,7 +110,7 @@ public class Header implements Iterable<MinimalField> {
         if (field == null) {
             return;
         }
-        final String key = field.getName().toLowerCase(Locale.ENGLISH);
+        final String key = field.getName().toLowerCase(Locale.ROOT);
         final List<MinimalField> list = fieldMap.get(key);
         if (list == null || list.isEmpty()) {
             addField(field);
@@ -132,6 +132,7 @@ public class Header implements Iterable<MinimalField> {
         this.fields.add(firstOccurrence, field);
     }
 
+    @Override
     public Iterator<MinimalField> iterator() {
         return Collections.unmodifiableList(fields).iterator();
     }
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/HttpBrowserCompatibleMultipart.java b/httpmime/src/main/java/org/apache/http/entity/mime/HttpBrowserCompatibleMultipart.java
index 5ac01fc..426b3da 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/HttpBrowserCompatibleMultipart.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/HttpBrowserCompatibleMultipart.java
@@ -43,11 +43,10 @@ class HttpBrowserCompatibleMultipart extends AbstractMultipartForm {
     private final List<FormBodyPart> parts;
 
     public HttpBrowserCompatibleMultipart(
-            final String subType,
             final Charset charset,
             final String boundary,
             final List<FormBodyPart> parts) {
-        super(subType, charset, boundary);
+        super(charset, boundary);
         this.parts = parts;
     }
 
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/HttpRFC6532Multipart.java b/httpmime/src/main/java/org/apache/http/entity/mime/HttpRFC6532Multipart.java
index a499151..a48b423 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/HttpRFC6532Multipart.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/HttpRFC6532Multipart.java
@@ -44,11 +44,10 @@ class HttpRFC6532Multipart extends AbstractMultipartForm {
     private final List<FormBodyPart> parts;
 
     public HttpRFC6532Multipart(
-            final String subType,
             final Charset charset,
             final String boundary,
             final List<FormBodyPart> parts) {
-        super(subType, charset, boundary);
+        super(charset, boundary);
         this.parts = parts;
     }
 
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/HttpStrictMultipart.java b/httpmime/src/main/java/org/apache/http/entity/mime/HttpStrictMultipart.java
index 5e9510e..6b07c66 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/HttpStrictMultipart.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/HttpStrictMultipart.java
@@ -44,11 +44,10 @@ class HttpStrictMultipart extends AbstractMultipartForm {
     private final List<FormBodyPart> parts;
 
     public HttpStrictMultipart(
-            final String subType,
             final Charset charset,
             final String boundary,
             final List<FormBodyPart> parts) {
-        super(subType, charset, boundary);
+        super(charset, boundary);
         this.parts = parts;
     }
 
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/MultipartEntityBuilder.java b/httpmime/src/main/java/org/apache/http/entity/mime/MultipartEntityBuilder.java
index b188e93..5bbb1db 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/MultipartEntityBuilder.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/MultipartEntityBuilder.java
@@ -36,12 +36,14 @@ import java.util.List;
 import java.util.Random;
 
 import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.content.ByteArrayBody;
 import org.apache.http.entity.mime.content.ContentBody;
 import org.apache.http.entity.mime.content.FileBody;
 import org.apache.http.entity.mime.content.InputStreamBody;
 import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.util.Args;
 
 /**
@@ -60,7 +62,7 @@ public class MultipartEntityBuilder {
 
     private final static String DEFAULT_SUBTYPE = "form-data";
 
-    private String subType = DEFAULT_SUBTYPE;
+    private ContentType contentType;
     private HttpMultipartMode mode = HttpMultipartMode.STRICT;
     private String boundary = null;
     private Charset charset = null;
@@ -71,7 +73,6 @@ public class MultipartEntityBuilder {
     }
 
     MultipartEntityBuilder() {
-        super();
     }
 
     public MultipartEntityBuilder setMode(final HttpMultipartMode mode) {
@@ -94,12 +95,33 @@ public class MultipartEntityBuilder {
         return this;
     }
 
+    /**
+     * @since 4.4
+     */
+    public MultipartEntityBuilder setMimeSubtype(final String subType) {
+        Args.notBlank(subType, "MIME subtype");
+        this.contentType = ContentType.create("multipart/" + subType);
+        return this;
+    }
+
+    /**
+     * @since 4.4
+     */
+    public MultipartEntityBuilder seContentType(final ContentType contentType) {
+        Args.notNull(contentType, "Content type");
+        this.contentType = contentType;
+        return this;
+    }
+
     public MultipartEntityBuilder setCharset(final Charset charset) {
         this.charset = charset;
         return this;
     }
 
-    MultipartEntityBuilder addPart(final FormBodyPart bodyPart) {
+    /**
+     * @since 4.4
+     */
+    public MultipartEntityBuilder addPart(final FormBodyPart bodyPart) {
         if (bodyPart == null) {
             return this;
         }
@@ -113,7 +135,7 @@ public class MultipartEntityBuilder {
     public MultipartEntityBuilder addPart(final String name, final ContentBody contentBody) {
         Args.notNull(name, "Name");
         Args.notNull(contentBody, "Content body");
-        return addPart(new FormBodyPart(name, contentBody));
+        return addPart(FormBodyPartBuilder.create(name, contentBody).build());
     }
 
     public MultipartEntityBuilder addTextBody(
@@ -156,19 +178,6 @@ public class MultipartEntityBuilder {
         return addBinaryBody(name, stream, ContentType.DEFAULT_BINARY, null);
     }
 
-    private String generateContentType(
-            final String boundary,
-            final Charset charset) {
-        final StringBuilder buffer = new StringBuilder();
-        buffer.append("multipart/form-data; boundary=");
-        buffer.append(boundary);
-        if (charset != null) {
-            buffer.append("; charset=");
-            buffer.append(charset.name());
-        }
-        return buffer.toString();
-    }
-
     private String generateBoundary() {
         final StringBuilder buffer = new StringBuilder();
         final Random rand = new Random();
@@ -180,24 +189,41 @@ public class MultipartEntityBuilder {
     }
 
     MultipartFormEntity buildEntity() {
-        final String st = subType != null ? subType : DEFAULT_SUBTYPE;
-        final Charset cs = charset;
-        final String b = boundary != null ? boundary : generateBoundary();
-        final List<FormBodyPart> bps = bodyParts != null ? new ArrayList<FormBodyPart>(bodyParts) :
+        String boundaryCopy = boundary;
+        if (boundaryCopy == null && contentType != null) {
+            boundaryCopy = contentType.getParameter("boundary");
+        }
+        if (boundaryCopy == null) {
+            boundaryCopy = generateBoundary();
+        }
+        Charset charsetCopy = charset;
+        if (charsetCopy == null && contentType != null) {
+            charsetCopy = contentType.getCharset();
+        }
+        final List<NameValuePair> paramsList = new ArrayList<NameValuePair>(2);
+        paramsList.add(new BasicNameValuePair("boundary", boundaryCopy));
+        if (charsetCopy != null) {
+            paramsList.add(new BasicNameValuePair("charset", charsetCopy.name()));
+        }
+        final NameValuePair[] params = paramsList.toArray(new NameValuePair[paramsList.size()]);
+        final ContentType contentTypeCopy = contentType != null ?
+                contentType.withParameters(params) :
+                ContentType.create("multipart/" + DEFAULT_SUBTYPE, params);
+        final List<FormBodyPart> bodyPartsCopy = bodyParts != null ? new ArrayList<FormBodyPart>(bodyParts) :
                 Collections.<FormBodyPart>emptyList();
-        final HttpMultipartMode m = mode != null ? mode : HttpMultipartMode.STRICT;
+        final HttpMultipartMode modeCopy = mode != null ? mode : HttpMultipartMode.STRICT;
         final AbstractMultipartForm form;
-        switch (m) {
+        switch (modeCopy) {
             case BROWSER_COMPATIBLE:
-                form = new HttpBrowserCompatibleMultipart(st, cs, b, bps);
+                form = new HttpBrowserCompatibleMultipart(charsetCopy, boundaryCopy, bodyPartsCopy);
                 break;
             case RFC6532:
-                form = new HttpRFC6532Multipart(st, cs, b, bps);
+                form = new HttpRFC6532Multipart(charsetCopy, boundaryCopy, bodyPartsCopy);
                 break;
             default:
-                form = new HttpStrictMultipart(st, cs, b, bps);
+                form = new HttpStrictMultipart(charsetCopy, boundaryCopy, bodyPartsCopy);
         }
-        return new MultipartFormEntity(form, generateContentType(b, cs), form.getTotalLength());
+        return new MultipartFormEntity(form, contentTypeCopy, form.getTotalLength());
     }
 
     public HttpEntity build() {
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/MultipartFormEntity.java b/httpmime/src/main/java/org/apache/http/entity/mime/MultipartFormEntity.java
index f71a43e..9c6158a 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/MultipartFormEntity.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/MultipartFormEntity.java
@@ -29,6 +29,7 @@ package org.apache.http.entity.mime;
 
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
+import org.apache.http.entity.ContentType;
 import org.apache.http.message.BasicHeader;
 import org.apache.http.protocol.HTTP;
 
@@ -44,11 +45,11 @@ class MultipartFormEntity implements HttpEntity {
 
     MultipartFormEntity(
             final AbstractMultipartForm multipart,
-            final String contentType,
+            final ContentType contentType,
             final long contentLength) {
         super();
         this.multipart = multipart;
-        this.contentType = new BasicHeader(HTTP.CONTENT_TYPE, contentType);
+        this.contentType = new BasicHeader(HTTP.CONTENT_TYPE, contentType.toString());
         this.contentLength = contentLength;
     }
 
@@ -56,30 +57,37 @@ class MultipartFormEntity implements HttpEntity {
         return this.multipart;
     }
 
+    @Override
     public boolean isRepeatable() {
         return this.contentLength != -1;
     }
 
+    @Override
     public boolean isChunked() {
         return !isRepeatable();
     }
 
+    @Override
     public boolean isStreaming() {
         return !isRepeatable();
     }
 
+    @Override
     public long getContentLength() {
         return this.contentLength;
     }
 
+    @Override
     public Header getContentType() {
         return this.contentType;
     }
 
+    @Override
     public Header getContentEncoding() {
         return null;
     }
 
+    @Override
     public void consumeContent()
         throws IOException, UnsupportedOperationException{
         if (isStreaming()) {
@@ -88,11 +96,13 @@ class MultipartFormEntity implements HttpEntity {
         }
     }
 
+    @Override
     public InputStream getContent() throws IOException {
         throw new UnsupportedOperationException(
                     "Multipart form entity does not implement #getContent()");
     }
 
+    @Override
     public void writeTo(final OutputStream outstream) throws IOException {
         this.multipart.writeTo(outstream);
     }
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/content/AbstractContentBody.java b/httpmime/src/main/java/org/apache/http/entity/mime/content/AbstractContentBody.java
index 642f841..9ac2b6e 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/content/AbstractContentBody.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/content/AbstractContentBody.java
@@ -64,10 +64,12 @@ public abstract class AbstractContentBody implements ContentBody {
         return this.contentType;
     }
 
+    @Override
     public String getMimeType() {
         return this.contentType.getMimeType();
     }
 
+    @Override
     public String getMediaType() {
         final String mimeType = this.contentType.getMimeType();
         final int i = mimeType.indexOf('/');
@@ -78,6 +80,7 @@ public abstract class AbstractContentBody implements ContentBody {
         }
     }
 
+    @Override
     public String getSubType() {
         final String mimeType = this.contentType.getMimeType();
         final int i = mimeType.indexOf('/');
@@ -88,6 +91,7 @@ public abstract class AbstractContentBody implements ContentBody {
         }
     }
 
+    @Override
     public String getCharset() {
         final Charset charset = this.contentType.getCharset();
         return charset != null ? charset.name() : null;
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/content/ByteArrayBody.java b/httpmime/src/main/java/org/apache/http/entity/mime/content/ByteArrayBody.java
index b40d7cd..d73e5ce 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/content/ByteArrayBody.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/content/ByteArrayBody.java
@@ -87,10 +87,12 @@ public class ByteArrayBody extends AbstractContentBody {
         this(data, "application/octet-stream", filename);
     }
 
+    @Override
     public String getFilename() {
         return filename;
     }
 
+    @Override
     public void writeTo(final OutputStream out) throws IOException {
         out.write(data);
     }
@@ -100,10 +102,12 @@ public class ByteArrayBody extends AbstractContentBody {
         return null;
     }
 
+    @Override
     public String getTransferEncoding() {
         return MIME.ENC_BINARY;
     }
 
+    @Override
     public long getContentLength() {
         return data.length;
     }
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/content/ContentDescriptor.java b/httpmime/src/main/java/org/apache/http/entity/mime/content/ContentDescriptor.java
index b7c58f1..6bbfdc9 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/content/ContentDescriptor.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/content/ContentDescriptor.java
@@ -44,10 +44,10 @@ public interface ContentDescriptor {
 
     /**
      * Gets the defaulted MIME media type for this content.
-     * For example <code>TEXT</code>, <code>IMAGE</code>, <code>MULTIPART</code>
+     * For example {@code TEXT}, {@code IMAGE}, {@code MULTIPART}
      * @see #getMimeType()
      * @return the MIME media type when content-type specified,
-     * otherwise the correct default (<code>TEXT</code>)
+     * otherwise the correct default ({@code TEXT})
      */
     String getMediaType();
 
@@ -55,19 +55,19 @@ public interface ContentDescriptor {
      * Gets the defaulted MIME sub type for this content.
      * @see #getMimeType()
      * @return the MIME media type when content-type is specified,
-     * otherwise the correct default (<code>PLAIN</code>)
+     * otherwise the correct default ({@code PLAIN})
      */
     String getSubType();
 
     /**
      * <p>The body descriptors character set, defaulted appropriately for the MIME type.</p>
      * <p>
-     * For <code>TEXT</code> types, this will be defaulted to <code>us-ascii</code>.
+     * For {@code TEXT} types, this will be defaulted to {@code us-ascii}.
      * For other types, when the charset parameter is missing this property will be null.
      * </p>
      * @return Character set, which has been parsed from the
-     *   content-type definition. Not null for <code>TEXT</code> types, when unset will
-     *   be set to default <code>us-ascii</code>. For other types, when unset,
+     *   content-type definition. Not null for {@code TEXT} types, when unset will
+     *   be set to default {@code us-ascii}. For other types, when unset,
      *   null will be returned.
      */
     String getCharset();
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/content/FileBody.java b/httpmime/src/main/java/org/apache/http/entity/mime/content/FileBody.java
index 16c915e..877dcc4 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/content/FileBody.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/content/FileBody.java
@@ -103,13 +103,14 @@ public class FileBody extends AbstractContentBody {
      * @since 4.3
      */
     public FileBody(final File file, final ContentType contentType) {
-        this(file, contentType, null);
+        this(file, contentType, file != null ? file.getName() : null);
     }
 
     public InputStream getInputStream() throws IOException {
         return new FileInputStream(this.file);
     }
 
+    @Override
     public void writeTo(final OutputStream out) throws IOException {
         Args.notNull(out, "Output stream");
         final InputStream in = new FileInputStream(this.file);
@@ -125,14 +126,17 @@ public class FileBody extends AbstractContentBody {
         }
     }
 
+    @Override
     public String getTransferEncoding() {
         return MIME.ENC_BINARY;
     }
 
+    @Override
     public long getContentLength() {
         return this.file.length();
     }
 
+    @Override
     public String getFilename() {
         return filename;
     }
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/content/InputStreamBody.java b/httpmime/src/main/java/org/apache/http/entity/mime/content/InputStreamBody.java
index 573aaa5..da4cbda 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/content/InputStreamBody.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/content/InputStreamBody.java
@@ -83,6 +83,7 @@ public class InputStreamBody extends AbstractContentBody {
         return this.in;
     }
 
+    @Override
     public void writeTo(final OutputStream out) throws IOException {
         Args.notNull(out, "Output stream");
         try {
@@ -97,14 +98,17 @@ public class InputStreamBody extends AbstractContentBody {
         }
     }
 
+    @Override
     public String getTransferEncoding() {
         return MIME.ENC_BINARY;
     }
 
+    @Override
     public long getContentLength() {
         return -1;
     }
 
+    @Override
     public String getFilename() {
         return this.filename;
     }
diff --git a/httpmime/src/main/java/org/apache/http/entity/mime/content/StringBody.java b/httpmime/src/main/java/org/apache/http/entity/mime/content/StringBody.java
index a9b319d..535ce4b 100644
--- a/httpmime/src/main/java/org/apache/http/entity/mime/content/StringBody.java
+++ b/httpmime/src/main/java/org/apache/http/entity/mime/content/StringBody.java
@@ -35,7 +35,6 @@ import java.io.OutputStream;
 import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
-import java.nio.charset.UnsupportedCharsetException;
 
 import org.apache.http.Consts;
 import org.apache.http.entity.ContentType;
@@ -155,13 +154,7 @@ public class StringBody extends AbstractContentBody {
         super(contentType);
         Args.notNull(text, "Text");
         final Charset charset = contentType.getCharset();
-        final String csname = charset != null ? charset.name() : Consts.ASCII.name();
-        try {
-            this.content = text.getBytes(csname);
-        } catch (final UnsupportedEncodingException ex) {
-            // Should never happen
-            throw new UnsupportedCharsetException(csname);
-        }
+        this.content = text.getBytes(charset != null ? charset : Consts.ASCII);
     }
 
     public Reader getReader() {
@@ -171,6 +164,7 @@ public class StringBody extends AbstractContentBody {
                 charset != null ? charset : Consts.ASCII);
     }
 
+    @Override
     public void writeTo(final OutputStream out) throws IOException {
         Args.notNull(out, "Output stream");
         final InputStream in = new ByteArrayInputStream(this.content);
@@ -182,14 +176,17 @@ public class StringBody extends AbstractContentBody {
         out.flush();
     }
 
+    @Override
     public String getTransferEncoding() {
         return MIME.ENC_8BIT;
     }
 
+    @Override
     public long getContentLength() {
         return this.content.length;
     }
 
+    @Override
     public String getFilename() {
         return null;
     }
diff --git a/httpmime/src/test/java/org/apache/http/entity/mime/TestFormBodyPartBuilder.java b/httpmime/src/test/java/org/apache/http/entity/mime/TestFormBodyPartBuilder.java
new file mode 100644
index 0000000..49a6bd8
--- /dev/null
+++ b/httpmime/src/test/java/org/apache/http/entity/mime/TestFormBodyPartBuilder.java
@@ -0,0 +1,175 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.entity.mime;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.entity.mime.content.StringBody;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestFormBodyPartBuilder {
+
+    @Test
+    public void testBuildBodyPartBasics() throws Exception {
+        final StringBody stringBody = new StringBody("stuff", ContentType.TEXT_PLAIN);
+        final FormBodyPart bodyPart = FormBodyPartBuilder.create()
+                .setName("blah")
+                .setBody(stringBody)
+                .build();
+        Assert.assertNotNull(bodyPart);
+        Assert.assertEquals("blah", bodyPart.getName());
+        Assert.assertEquals(stringBody, bodyPart.getBody());
+        final Header header = bodyPart.getHeader();
+        Assert.assertNotNull(header);
+        assertFields(Arrays.asList(
+                        new MinimalField("Content-Disposition", "form-data; name=\"blah\""),
+                        new MinimalField("Content-Type", "text/plain; charset=ISO-8859-1"),
+                        new MinimalField("Content-Transfer-Encoding", "8bit")),
+                header.getFields());
+    }
+
+    @Test
+    public void testBuildBodyPartMultipleBuilds() throws Exception {
+        final StringBody stringBody = new StringBody("stuff", ContentType.TEXT_PLAIN);
+        final FormBodyPartBuilder builder = FormBodyPartBuilder.create();
+        final FormBodyPart bodyPart1 = builder
+                .setName("blah")
+                .setBody(stringBody)
+                .build();
+        Assert.assertNotNull(bodyPart1);
+        Assert.assertEquals("blah", bodyPart1.getName());
+        Assert.assertEquals(stringBody, bodyPart1.getBody());
+        final Header header1 = bodyPart1.getHeader();
+        Assert.assertNotNull(header1);
+        assertFields(Arrays.asList(
+                        new MinimalField("Content-Disposition", "form-data; name=\"blah\""),
+                        new MinimalField("Content-Type", "text/plain; charset=ISO-8859-1"),
+                        new MinimalField("Content-Transfer-Encoding", "8bit")),
+                header1.getFields());
+        final FileBody fileBody = new FileBody(new File("/path/stuff.bin"), ContentType.DEFAULT_BINARY);
+        final FormBodyPart bodyPart2 = builder
+                .setName("yada")
+                .setBody(fileBody)
+                .build();
+
+        Assert.assertNotNull(bodyPart2);
+        Assert.assertEquals("yada", bodyPart2.getName());
+        Assert.assertEquals(fileBody, bodyPart2.getBody());
+        final Header header2 = bodyPart2.getHeader();
+        Assert.assertNotNull(header2);
+        assertFields(Arrays.asList(
+                        new MinimalField("Content-Disposition", "form-data; name=\"yada\"; filename=\"stuff.bin\""),
+                        new MinimalField("Content-Type", "application/octet-stream"),
+                        new MinimalField("Content-Transfer-Encoding", "binary")),
+                header2.getFields());
+    }
+
+    @Test
+    public void testBuildBodyPartCustomHeaders() throws Exception {
+        final StringBody stringBody = new StringBody("stuff", ContentType.TEXT_PLAIN);
+        final FormBodyPartBuilder builder = FormBodyPartBuilder.create("blah", stringBody);
+        final FormBodyPart bodyPart1 = builder
+                .addField("header1", "blah")
+                .addField("header3", "blah")
+                .addField("header3", "blah")
+                .addField("header3", "blah")
+                .addField("header3", "blah")
+                .addField("header3", "blah")
+                .build();
+
+        Assert.assertNotNull(bodyPart1);
+        final Header header1 = bodyPart1.getHeader();
+        Assert.assertNotNull(header1);
+
+        assertFields(Arrays.asList(
+                new MinimalField("header1", "blah"),
+                new MinimalField("header3", "blah"),
+                new MinimalField("header3", "blah"),
+                new MinimalField("header3", "blah"),
+                new MinimalField("header3", "blah"),
+                new MinimalField("header3", "blah"),
+                new MinimalField("Content-Disposition", "form-data; name=\"blah\""),
+                new MinimalField("Content-Type", "text/plain; charset=ISO-8859-1"),
+                new MinimalField("Content-Transfer-Encoding", "8bit")),
+                header1.getFields());
+
+        final FormBodyPart bodyPart2 = builder
+                .setField("header2", "yada")
+                .removeFields("header3")
+                .build();
+
+        Assert.assertNotNull(bodyPart2);
+        final Header header2 = bodyPart2.getHeader();
+        Assert.assertNotNull(header2);
+
+        assertFields(Arrays.asList(
+                        new MinimalField("header1", "blah"),
+                        new MinimalField("header2", "yada"),
+                        new MinimalField("Content-Disposition", "form-data; name=\"blah\""),
+                        new MinimalField("Content-Type", "text/plain; charset=ISO-8859-1"),
+                        new MinimalField("Content-Transfer-Encoding", "8bit")),
+                header2.getFields());
+
+        final FormBodyPart bodyPart3 = builder
+                .addField("Content-Disposition", "disposition stuff")
+                .addField("Content-Type", "type stuff")
+                .addField("Content-Transfer-Encoding", "encoding stuff")
+                .build();
+
+        Assert.assertNotNull(bodyPart3);
+        final Header header3 = bodyPart3.getHeader();
+        Assert.assertNotNull(header3);
+
+        assertFields(Arrays.asList(
+                        new MinimalField("header1", "blah"),
+                        new MinimalField("header2", "yada"),
+                        new MinimalField("Content-Disposition", "disposition stuff"),
+                        new MinimalField("Content-Type", "type stuff"),
+                        new MinimalField("Content-Transfer-Encoding", "encoding stuff")),
+                header3.getFields());
+
+    }
+
+    private static void assertFields(final List<MinimalField> expected, final List<MinimalField> result) {
+        Assert.assertNotNull(result);
+        Assert.assertEquals(expected.size(), result.size());
+        for (int i = 0; i < expected.size(); i++) {
+            final MinimalField expectedField = expected.get(i);
+            final MinimalField resultField = result.get(i);
+            Assert.assertNotNull(resultField);
+            Assert.assertEquals(expectedField.getName(), resultField.getName());
+            Assert.assertEquals(expectedField.getBody(), resultField.getBody());
+        }
+    }
+
+}
diff --git a/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartContentBody.java b/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartContentBody.java
index 3c50637..6c5a6e2 100644
--- a/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartContentBody.java
+++ b/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartContentBody.java
@@ -29,6 +29,7 @@ package org.apache.http.entity.mime;
 
 import java.io.ByteArrayInputStream;
 
+import org.apache.http.Consts;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.content.InputStreamBody;
 import org.apache.http.entity.mime.content.StringBody;
@@ -66,17 +67,17 @@ public class TestMultipartContentBody {
 
     @Test(expected=IllegalArgumentException.class)
     public void testStringBodyInvalidConstruction1() throws Exception {
-        new StringBody(null, ContentType.DEFAULT_TEXT);
+        Assert.assertNotNull(new StringBody(null, ContentType.DEFAULT_TEXT)); // avoid unused warning
     }
 
     @Test(expected=IllegalArgumentException.class)
     public void testStringBodyInvalidConstruction2() throws Exception {
-        new StringBody("stuff", (ContentType) null);
+        Assert.assertNotNull(new StringBody("stuff", (ContentType) null)); // avoid unused warning
     }
 
     @Test
     public void testInputStreamBody() throws Exception {
-        final byte[] stuff = "Stuff".getBytes("US-ASCII");
+        final byte[] stuff = "Stuff".getBytes(Consts.ASCII);
         final InputStreamBody b1 = new InputStreamBody(new ByteArrayInputStream(stuff), "stuff");
         Assert.assertEquals(-1, b1.getContentLength());
 
diff --git a/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartEntityBuilder.java b/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartEntityBuilder.java
index f355b5b..5a9e9a3 100644
--- a/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartEntityBuilder.java
+++ b/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartEntityBuilder.java
@@ -32,6 +32,9 @@ import java.io.File;
 import java.util.List;
 
 import org.apache.http.Consts;
+import org.apache.http.Header;
+import org.apache.http.entity.ContentType;
+import org.apache.http.message.BasicNameValuePair;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -54,8 +57,8 @@ public class TestMultipartEntityBuilder {
                 .buildEntity();
         Assert.assertNotNull(entity);
         Assert.assertTrue(entity.getMultipart() instanceof HttpBrowserCompatibleMultipart);
-        Assert.assertEquals("blah-blah", entity.getMultipart().getBoundary());
-        Assert.assertEquals(Consts.UTF_8, entity.getMultipart().getCharset());
+        Assert.assertEquals("blah-blah", entity.getMultipart().boundary);
+        Assert.assertEquals(Consts.UTF_8, entity.getMultipart().charset);
     }
 
     @Test
@@ -63,8 +66,8 @@ public class TestMultipartEntityBuilder {
         final MultipartFormEntity entity = MultipartEntityBuilder.create()
                 .addTextBody("p1", "stuff")
                 .addBinaryBody("p2", new File("stuff"))
-                .addBinaryBody("p3", new byte[] {})
-                .addBinaryBody("p4", new ByteArrayInputStream(new byte[] {}))
+                .addBinaryBody("p3", new byte[]{})
+                .addBinaryBody("p4", new ByteArrayInputStream(new byte[]{}))
                 .buildEntity();
         Assert.assertNotNull(entity);
         final List<FormBodyPart> bodyParts = entity.getMultipart().getBodyParts();
@@ -72,4 +75,52 @@ public class TestMultipartEntityBuilder {
         Assert.assertEquals(4, bodyParts.size());
     }
 
+    @Test
+    public void testMultipartCustomContentType() throws Exception {
+        final MultipartFormEntity entity = MultipartEntityBuilder.create()
+                .seContentType(ContentType.APPLICATION_XML)
+                .setBoundary("blah-blah")
+                .setCharset(Consts.UTF_8)
+                .setLaxMode()
+                .buildEntity();
+        Assert.assertNotNull(entity);
+        final Header contentType = entity.getContentType();
+        Assert.assertNotNull(contentType);
+        Assert.assertEquals("application/xml; boundary=blah-blah; charset=UTF-8", contentType.getValue());
+    }
+
+    @Test
+    public void testMultipartContentTypeParameter() throws Exception {
+        final MultipartFormEntity entity = MultipartEntityBuilder.create()
+                .seContentType(ContentType.MULTIPART_FORM_DATA.withParameters(
+                        new BasicNameValuePair("boundary", "yada-yada"),
+                        new BasicNameValuePair("charset", "ascii")))
+                .buildEntity();
+        Assert.assertNotNull(entity);
+        final Header contentType = entity.getContentType();
+        Assert.assertNotNull(contentType);
+        Assert.assertEquals("multipart/form-data; boundary=yada-yada; charset=US-ASCII",
+                contentType.getValue());
+        Assert.assertEquals("yada-yada", entity.getMultipart().boundary);
+        Assert.assertEquals(Consts.ASCII, entity.getMultipart().charset);
+    }
+
+    @Test
+    public void testMultipartCustomContentTypeParameterOverrides() throws Exception {
+        final MultipartFormEntity entity = MultipartEntityBuilder.create()
+                .seContentType(ContentType.MULTIPART_FORM_DATA.withParameters(
+                        new BasicNameValuePair("boundary", "yada-yada"),
+                        new BasicNameValuePair("charset", "ascii"),
+                        new BasicNameValuePair("my", "stuff")))
+                .setBoundary("blah-blah")
+                .setCharset(Consts.UTF_8)
+                .setLaxMode()
+                .buildEntity();
+        Assert.assertNotNull(entity);
+        final Header contentType = entity.getContentType();
+        Assert.assertNotNull(contentType);
+        Assert.assertEquals("multipart/form-data; boundary=blah-blah; charset=UTF-8; my=stuff",
+                contentType.getValue());
+    }
+
 }
diff --git a/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartForm.java b/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartForm.java
index 840a8c0..6ee3f39 100644
--- a/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartForm.java
+++ b/httpmime/src/test/java/org/apache/http/entity/mime/TestMultipartForm.java
@@ -57,17 +57,17 @@ public class TestMultipartForm {
 
     @Test
     public void testMultipartFormStringParts() throws Exception {
-        final FormBodyPart p1 = new FormBodyPart(
+        final FormBodyPart p1 = FormBodyPartBuilder.create(
                 "field1",
-                new StringBody("this stuff", ContentType.DEFAULT_TEXT));
-        final FormBodyPart p2 = new FormBodyPart(
+                new StringBody("this stuff", ContentType.DEFAULT_TEXT)).build();
+        final FormBodyPart p2 = FormBodyPartBuilder.create(
                 "field2",
                 new StringBody("that stuff", ContentType.create(
-                        ContentType.TEXT_PLAIN.getMimeType(), Consts.UTF_8)));
-        final FormBodyPart p3 = new FormBodyPart(
+                        ContentType.TEXT_PLAIN.getMimeType(), Consts.UTF_8))).build();
+        final FormBodyPart p3 = FormBodyPartBuilder.create(
                 "field3",
-                new StringBody("all kind of stuff", ContentType.DEFAULT_TEXT));
-        final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
+                new StringBody("all kind of stuff", ContentType.DEFAULT_TEXT)).build();
+        final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
                 Arrays.asList(p1, p2, p3));
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -101,13 +101,13 @@ public class TestMultipartForm {
 
     @Test
     public void testMultipartFormCustomContentType() throws Exception {
-        final FormBodyPart p1 = new FormBodyPart(
+        final FormBodyPart p1 = FormBodyPartBuilder.create(
                 "field1",
-                new StringBody("this stuff", ContentType.DEFAULT_TEXT));
-        final FormBodyPart p2 = new FormBodyPart(
+                new StringBody("this stuff", ContentType.DEFAULT_TEXT)).build();
+        final FormBodyPart p2 = FormBodyPartBuilder.create(
                 "field2",
-                new StringBody("that stuff", ContentType.parse("stuff/plain; param=value")));
-        final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
+                new StringBody("that stuff", ContentType.parse("stuff/plain; param=value"))).build();
+        final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
                 Arrays.asList(p1, p2));
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -143,13 +143,14 @@ public class TestMultipartForm {
             writer.close();
         }
 
-        final FormBodyPart p1 = new FormBodyPart(
+        final FormBodyPart p1 = FormBodyPartBuilder.create(
                 "field1",
-                new FileBody(tmpfile));
-        final FormBodyPart p2 = new FormBodyPart(
+                new FileBody(tmpfile)).build();
+        @SuppressWarnings("resource")
+        final FormBodyPart p2 = FormBodyPartBuilder.create(
                 "field2",
-                new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
-        final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
+                new InputStreamBody(new FileInputStream(tmpfile), "file.tmp")).build();
+        final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
                 Arrays.asList(p1, p2));
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -187,16 +188,17 @@ public class TestMultipartForm {
             writer.close();
         }
 
-        final FormBodyPart p1 = new FormBodyPart(
+        final FormBodyPart p1 = FormBodyPartBuilder.create(
                 "field1",
-                new FileBody(tmpfile));
-        final FormBodyPart p2 = new FormBodyPart(
+                new FileBody(tmpfile)).build();
+        final FormBodyPart p2 = FormBodyPartBuilder.create(
                 "field2",
-                new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file"));
-        final FormBodyPart p3 = new FormBodyPart(
+                new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file")).build();
+        @SuppressWarnings("resource")
+        final FormBodyPart p3 = FormBodyPartBuilder.create(
                 "field3",
-                new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
-        final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
+                new InputStreamBody(new FileInputStream(tmpfile), "file.tmp")).build();
+        final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
                 Arrays.asList(p1, p2, p3));
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -241,16 +243,17 @@ public class TestMultipartForm {
             writer.close();
         }
 
-        final FormBodyPart p1 = new FormBodyPart(
+        final FormBodyPart p1 = FormBodyPartBuilder.create(
                 "field1\u0414",
-                new FileBody(tmpfile));
-        final FormBodyPart p2 = new FormBodyPart(
+                new FileBody(tmpfile)).build();
+        final FormBodyPart p2 = FormBodyPartBuilder.create(
                 "field2",
-                new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file"));
-        final FormBodyPart p3 = new FormBodyPart(
+                new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file")).build();
+        @SuppressWarnings("resource")
+        final FormBodyPart p3 = FormBodyPartBuilder.create(
                 "field3",
-                new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
-        final HttpRFC6532Multipart multipart = new HttpRFC6532Multipart("form-data", null, "foo",
+                new InputStreamBody(new FileInputStream(tmpfile), "file.tmp")).build();
+        final HttpRFC6532Multipart multipart = new HttpRFC6532Multipart(null, "foo",
                 Arrays.asList(p1, p2, p3));
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -317,14 +320,16 @@ public class TestMultipartForm {
             writer.close();
         }
 
-        final FormBodyPart p1 = new FormBodyPart(
+        @SuppressWarnings("resource")
+        final FormBodyPart p1 = FormBodyPartBuilder.create(
                 "field1",
-                new InputStreamBody(new FileInputStream(tmpfile), s1 + ".tmp"));
-        final FormBodyPart p2 = new FormBodyPart(
+                new InputStreamBody(new FileInputStream(tmpfile), s1 + ".tmp")).build();
+        @SuppressWarnings("resource")
+        final FormBodyPart p2 = FormBodyPartBuilder.create(
                 "field2",
-                new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp"));
+                new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp")).build();
         final HttpBrowserCompatibleMultipart multipart = new HttpBrowserCompatibleMultipart(
-                "form-data", Consts.UTF_8, "foo",
+                Consts.UTF_8, "foo",
                 Arrays.asList(p1, p2));
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -355,13 +360,13 @@ public class TestMultipartForm {
         final String s1 = constructString(SWISS_GERMAN_HELLO);
         final String s2 = constructString(RUSSIAN_HELLO);
 
-        final FormBodyPart p1 = new FormBodyPart(
+        final FormBodyPart p1 = FormBodyPartBuilder.create(
                 "field1",
-                new StringBody(s1, ContentType.create("text/plain", Charset.forName("ISO-8859-1"))));
-        final FormBodyPart p2 = new FormBodyPart(
+                new StringBody(s1, ContentType.create("text/plain", Charset.forName("ISO-8859-1")))).build();
+        final FormBodyPart p2 = FormBodyPartBuilder.create(
                 "field2",
-                new StringBody(s2, ContentType.create("text/plain", Charset.forName("KOI8-R"))));
-        final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
+                new StringBody(s2, ContentType.create("text/plain", Charset.forName("KOI8-R")))).build();
+        final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
                 Arrays.asList(p1, p2));
 
         final ByteArrayOutputStream out1 = new ByteArrayOutputStream();
@@ -375,17 +380,17 @@ public class TestMultipartForm {
             "Content-Disposition: form-data; name=\"field1\"\r\n" +
             "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
             "Content-Transfer-Encoding: 8bit\r\n" +
-            "\r\n").getBytes("US-ASCII"));
-        out2.write(s1.getBytes("ISO-8859-1"));
+            "\r\n").getBytes(Consts.ASCII));
+        out2.write(s1.getBytes(Consts.ISO_8859_1));
         out2.write(("\r\n" +
             "--foo\r\n" +
             "Content-Disposition: form-data; name=\"field2\"\r\n" +
             "Content-Type: text/plain; charset=KOI8-R\r\n" +
             "Content-Transfer-Encoding: 8bit\r\n" +
-            "\r\n").getBytes("US-ASCII"));
-        out2.write(s2.getBytes("KOI8-R"));
+            "\r\n").getBytes(Consts.ASCII));
+        out2.write(s2.getBytes(Charset.forName("KOI8-R")));
         out2.write(("\r\n" +
-            "--foo--\r\n").getBytes("US-ASCII"));
+            "--foo--\r\n").getBytes(Consts.ASCII));
         out2.close();
 
         final byte[] actual = out1.toByteArray();
diff --git a/pom.xml b/pom.xml
index d30314d..031760e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,8 +32,8 @@
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>httpcomponents-client</artifactId>
-  <name>HttpComponents Client</name>
-  <version>4.3.5</version>
+  <name>Apache HttpComponents Client</name>
+  <version>4.4.1</version>
   <description>Apache HttpComponents Client is a library of components for building client side HTTP services</description>
   <url>http://hc.apache.org/httpcomponents-client</url>
   <inceptionYear>1999</inceptionYear>
@@ -58,40 +58,28 @@
   </issueManagement>
 
   <scm>
-    <connection>scm:svn:https://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.3.5</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.3.5</developerConnection>
-    <url>https://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.3.5</url>
+    <connection>scm:svn:https://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.4.1</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.4.1</developerConnection>
+    <url>https://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.4.1</url>
   </scm>
 
   <properties>
-    <maven.compiler.source>1.5</maven.compiler.source>
-    <maven.compiler.target>1.5</maven.compiler.target>
-    <httpcore.version>4.3.2</httpcore.version>
-    <commons-logging.version>1.1.3</commons-logging.version>
-    <commons-codec.version>1.6</commons-codec.version>
-    <ehcache.version>2.2.0</ehcache.version>
-    <memcached.version>2.6</memcached.version>
-    <slf4j.version>1.5.11</slf4j.version>
-    <junit.version>4.9</junit.version>
+    <maven.compiler.source>1.6</maven.compiler.source>
+    <maven.compiler.target>1.6</maven.compiler.target>
+    <httpcore.version>4.4.1</httpcore.version>
+    <commons-logging.version>1.2</commons-logging.version>
+    <commons-codec.version>1.9</commons-codec.version>
+    <ehcache.version>2.6.9</ehcache.version>
+    <memcached.version>2.11.4</memcached.version>
+    <slf4j.version>1.7.7</slf4j.version>
+    <junit.version>4.11</junit.version>
     <easymock.version>2.5.2</easymock.version>
     <mockito.version>1.8.5</mockito.version>
-    <jna.version>4.0.0</jna.version>
+    <jna.version>4.1.0</jna.version>
     <hc.stylecheck.version>1</hc.stylecheck.version>
-    <api.comparison.version>4.3</api.comparison.version>
+    <api.comparison.version>4.4</api.comparison.version>
   </properties>
 
-  <repositories>
-    <repository>
-      <id>spy</id>
-      <name>Spy Repository</name>
-      <layout>default</layout>
-      <url>http://files.couchbase.com/maven2/</url>
-      <snapshots>
-        <enabled>false</enabled>
-      </snapshots>
-    </repository>
-  </repositories>
-
   <dependencyManagement>
     <dependencies>
       <dependency>
@@ -120,7 +108,7 @@
         <version>${slf4j.version}</version>
       </dependency>
       <dependency>
-        <groupId>spy</groupId>
+        <groupId>net.spy</groupId>
         <artifactId>spymemcached</artifactId>
         <version>${memcached.version}</version>
       </dependency>
@@ -166,6 +154,7 @@
     <module>httpmime</module>
     <module>fluent-hc</module>
     <module>httpclient-cache</module>
+    <module>httpclient-win</module>
     <module>httpclient-osgi</module>
   </modules>
 
@@ -228,10 +217,9 @@
           <quiet>true</quiet>
           <source>${maven.compiler.source}</source>
           <links>
-            <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
+            <link>http://docs.oracle.com/javase/6/docs/api/</link>
             <link>http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/</link>
           </links>
-          <bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jsse.jar:${java.home}/lib/jce.jar</bootclasspath>
         </configuration>
       </plugin>
       <plugin>
@@ -308,13 +296,6 @@
           </executions>
         </plugin>
       <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>clirr-maven-plugin</artifactId>
-        <configuration>
-          <comparisonVersion>${api.comparison.version}</comparisonVersion>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
         <version>2.9.1</version>
@@ -376,33 +357,61 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>clirr-maven-plugin</artifactId>
+        <version>${hc.clirr.version}</version>
+        <configuration>
+          <comparisonVersion>${api.comparison.version}</comparisonVersion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <version>0.11</version>
+        <executions>
+          <execution>
+            <phase>verify</phase>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <excludes>
+            <exclude>src/docbkx/resources/**</exclude>
+            <exclude>src/test/resources/*.truststore</exclude>
+            <exclude>.checkstyle</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
   <reporting>
     <plugins>
 
-       <plugin>
-         <artifactId>maven-project-info-reports-plugin</artifactId>
-         <version>${hc.project-info.version}</version>
-         <inherited>false</inherited>
-         <reportSets>
-           <reportSet>
-             <reports>
-               <report>dependency-management</report>
-               <report>issue-tracking</report>
-               <report>license</report>
-               <report>scm</report>
-               <report>summary</report>
-             </reports>
-           </reportSet>
-         </reportSets>
+      <plugin>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+        <version>${hc.project-info.version}</version>
+        <inherited>false</inherited>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>dependency-management</report>
+              <report>issue-tracking</report>
+              <report>license</report>
+              <report>scm</report>
+              <report>summary</report>
+            </reports>
+          </reportSet>
+        </reportSets>
       </plugin>
 
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>clirr-maven-plugin</artifactId>
-         <version>${hc.clirr.version}</version>
+        <version>${hc.clirr.version}</version>
         <configuration>
           <comparisonVersion>${api.comparison.version}</comparisonVersion>
         </configuration>
diff --git a/src/docbkx/connmgmt.xml b/src/docbkx/connmgmt.xml
index 5a104f4..0f8f643 100644
--- a/src/docbkx/connmgmt.xml
+++ b/src/docbkx/connmgmt.xml
@@ -281,11 +281,11 @@ static class GetThread extends Thread {
         <para>HttpClient tries to mitigate the problem by testing whether the connection is 'stale',
             that is no longer valid because it was closed on the server side, prior to using the
             connection for executing an HTTP request. The stale connection check is not 100%
-            reliable and adds 10 to 30 ms overhead to each request execution. The only feasible
-            solution that does not involve a one thread per socket model for idle connections is a
-            dedicated monitor thread used to evict connections that are considered expired due to a
-            long period of inactivity. The monitor thread can periodically call
-                <methodname>ClientConnectionManager#closeExpiredConnections()</methodname> method to
+            reliable. The only feasible solution that does not involve a one thread per socket
+            model for idle connections is a dedicated monitor thread used to evict connections
+            that are considered expired due to a long period of inactivity. The monitor thread can
+            periodically call
+            <methodname>ClientConnectionManager#closeExpiredConnections()</methodname> method to
             close all expired connections and evict closed connections from the pool. It can also
             optionally call <methodname>ClientConnectionManager#closeIdleConnections()</methodname>
             method to close all connections that have been idle over a given period of time.</para>
@@ -445,8 +445,8 @@ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
                 a certain degree of familiarity with the concepts of the SSL/TLS protocol,
                 a detailed explanation of which is out of scope for this document. Please refer
                 to the <ulink
-                url="http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html">
-                Java Secure Socket Extension</ulink> for a detailed description of
+                url="http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+                Java&#x2122; Secure Socket Extension (JSSE) Reference Guide</ulink> for a detailed description of
                 <interfacename>javax.net.ssl.SSLContext</interfacename> and related
                 tools.</para>
         </section>
@@ -457,58 +457,66 @@ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
                 hostname matches the names stored inside the server's X.509 certificate, once the
                 connection has been established. This verification can provide additional guarantees
                 of authenticity of the server trust material.
-                The <interfacename>X509HostnameVerifier</interfacename> interface
-                represents a strategy for hostname verification. HttpClient ships with three
-                <interfacename>X509HostnameVerifier</interfacename> implementations.
+                The <interfacename>javax.net.ssl.HostnameVerifier</interfacename> interface
+                represents a strategy for hostname verification. HttpClient ships with two
+                <interfacename>javax.net.ssl.HostnameVerifier</interfacename> implementations.
                 Important: hostname verification should not be confused with
                 SSL trust verification.</para>
             <itemizedlist>
                 <listitem>
                     <formalpara>
-                        <title><classname>StrictHostnameVerifier</classname>:</title>
-                        <para>The strict hostname verifier works the same way as Sun Java 1.4, Sun
-                            Java 5, Sun Java 6. It's also pretty close to IE6. This implementation
-                            appears to be compliant with RFC 2818 for dealing with wildcards. The
-                            hostname must match either the first CN, or any of the subject-alts. A
+                        <title><classname>DefaultHostnameVerifier</classname>:</title>
+                        <para>The default implementation used by HttpClient is expected to be
+                            compliant with RFC 2818. The hostname must match any of alternative
+                            names specified by the certificate, or in case no alternative
+                            names are given the most specific CN of the certificate subject. A
                             wildcard can occur in the CN, and in any of the subject-alts.</para>
                     </formalpara>
                 </listitem>
                 <listitem>
                     <formalpara>
-                        <title><classname>BrowserCompatHostnameVerifier</classname>:</title>
-                        <para>This hostname verifier that works the same way as Curl and Firefox. The
-                            hostname must match either the first CN, or any of the subject-alts. A
-                            wildcard can occur in the CN, and in any of the subject-alts. The only
-                            difference between <classname>BrowserCompatHostnameVerifier</classname>
-                            and <classname>StrictHostnameVerifier</classname> is that a wildcard
-                            (such as "*.foo.com") with
-                            <classname>BrowserCompatHostnameVerifier</classname> matches all
-                            subdomains, including "a.b.foo.com".</para>
-                    </formalpara>
-                </listitem>
-                <listitem>
-                    <formalpara>
-                        <title><classname>AllowAllHostnameVerifier</classname>:</title>
+                        <title><classname>NoopHostnameVerifier</classname>:</title>
                         <para>This hostname verifier essentially turns hostname verification off.
-                            This implementation is a no-op, and never throws
-                            <exceptionname>javax.net.ssl.SSLException</exceptionname>.</para>
+                            It accepts any SSL session as valid and matching the target host.
+                        </para>
                     </formalpara>
                 </listitem>
             </itemizedlist>
-            <para>Per default HttpClient uses the <classname>BrowserCompatHostnameVerifier</classname>
+            <para>Per default HttpClient uses the <classname>DefaultHostnameVerifier</classname>
                 implementation. One can specify a different hostname verifier implementation if
                 desired</para>
             <programlisting><![CDATA[
 SSLContext sslContext = SSLContexts.createSystemDefault();
 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
         sslContext,
-        SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
+        NoopHostnameVerifier.INSTANCE);
+]]></programlisting>
+            <para>As of version 4.4 HttpClient uses the public suffix list kindly maintained
+                by Mozilla Foundation to make sure that wildcards in SSL certificates cannot be
+                misused to apply to multiple domains with a common top-level domain. HttpClient
+                ships with a copy of the list retrieved at the time of the release. The latest
+                revision of the list can found at
+                <ulink url="https://publicsuffix.org/list/effective_tld_names.dat">
+                    https://publicsuffix.org/list/</ulink>. It is highly adviseable to make a local
+                copy of the list and download the list no more than once per day from its original
+                location.
+            </para>
+            <programlisting><![CDATA[
+PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.load(
+    PublicSuffixMatcher.class.getResource("my-copy-effective_tld_names.dat"));
+DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
+]]></programlisting>
+            <para>One can disable verification against the public suffic list by using
+                <code>null</code> matcher.
+            </para>
+            <programlisting><![CDATA[
+DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(null);
 ]]></programlisting>
         </section>
     </section>
     <section>
         <title>HttpClient proxy configuration</title>
-        <para>Even though HttpClient is aware of complex routing scemes and proxy chaining, it
+        <para>Even though HttpClient is aware of complex routing schemes and proxy chaining, it
             supports only simple direct or one hop proxy connections out of the box.</para>
         <para>The simplest way to tell HttpClient to connect to the target host via a proxy is by
             setting the default proxy parameter:</para>
diff --git a/src/docbkx/fundamentals.xml b/src/docbkx/fundamentals.xml
index 7fd52d2..2d8eda2 100644
--- a/src/docbkx/fundamentals.xml
+++ b/src/docbkx/fundamentals.xml
@@ -657,14 +657,71 @@ try {
 }
 ]]></programlisting>
     </section>
+  <section id="protocol_interceptors">
+    <title>HTTP protocol interceptors</title>
+    <para>The HTTP protocol interceptor is a routine that implements a specific aspect of the HTTP
+      protocol. Usually protocol interceptors are expected to act upon one specific header or
+      a group of related headers of the incoming message, or populate the outgoing message with
+      one specific header or a group of related headers. Protocol interceptors can also
+      manipulate content entities enclosed with messages - transparent content compression /
+      decompression being a good example. Usually this is accomplished by using the
+      'Decorator' pattern where a wrapper entity class is used to decorate the original
+      entity. Several protocol interceptors can be combined to form one logical unit.</para>
+    <para>Protocol interceptors can collaborate by sharing information - such as a processing
+      state - through the HTTP execution context. Protocol interceptors can use HTTP context
+      to store a processing state for one request or several consecutive requests.</para>
+    <para>Usually the order in which interceptors are executed should not matter as long as they
+      do not depend on a particular state of the execution context. If protocol interceptors
+      have interdependencies and therefore must be executed in a particular order, they should
+      be added to the protocol processor in the same sequence as their expected execution
+      order.</para>
+    <para>Protocol interceptors must be implemented as thread-safe. Similarly to servlets,
+      protocol interceptors should not use instance variables unless access to those variables
+      is synchronized.</para>
+    <para>This is an example of how local context can be used to persist a processing state
+      between consecutive requests:</para>
+    <programlisting><![CDATA[
+CloseableHttpClient httpclient = HttpClients.custom()
+        .addInterceptorLast(new HttpRequestInterceptor() {
+
+            public void process(
+                    final HttpRequest request,
+                    final HttpContext context) throws HttpException, IOException {
+                AtomicInteger count = (AtomicInteger) context.getAttribute("count");
+                request.addHeader("Count", Integer.toString(count.getAndIncrement()));
+            }
+
+        })
+        .build();
+
+AtomicInteger count = new AtomicInteger(1);
+HttpClientContext localContext = HttpClientContext.create();
+localContext.setAttribute("count", count);
+
+HttpGet httpget = new HttpGet("http://localhost/");
+for (int i = 0; i < 10; i++) {
+    CloseableHttpResponse response = httpclient.execute(httpget, localContext);
+    try {
+        HttpEntity entity = response.getEntity();
+    } finally {
+        response.close();
+    }
+}
+]]></programlisting>
+  </section>
     <section>
         <title>Exception handling</title>
-        <para>HttpClient can throw two types of exceptions:
+        <para>HTTP protocol processors can throw two types of exceptions:
             <exceptionname>java.io.IOException</exceptionname> in case of an I/O failure such as
             socket timeout or an socket reset and <exceptionname>HttpException</exceptionname> that
             signals an HTTP failure such as a violation of the HTTP protocol. Usually I/O errors are
             considered non-fatal and recoverable, whereas HTTP protocol errors are considered fatal
-            and cannot be automatically recovered from.</para>
+            and cannot be automatically recovered from. Please note that <interfacename>HttpClient
+            </interfacename> implementations re-throw <exceptionname>HttpException</exceptionname>s
+            as <exceptionname>ClientProtocolException</exceptionname>, which is a subclass
+            of <exceptionname>java.io.IOException</exceptionname>. This enables the users
+            of <interfacename>HttpClient</interfacename> to handle both I/O errors and protocol
+            violations from a single catch clause.</para>
         <section>
             <title>HTTP transport safety</title>
             <para>It is important to understand that the HTTP protocol is not well suited to all
@@ -699,9 +756,10 @@ try {
             <para>Please note that this problem is not specific to HttpClient. Browser based
                 applications are subject to exactly the same issues related to HTTP methods
                 non-idempotency.</para>
-            <para>HttpClient assumes non-entity enclosing methods such as <literal>GET</literal> and
-                    <literal>HEAD</literal> to be idempotent and entity enclosing methods such as
-                    <literal>POST</literal> and <literal>PUT</literal> to be not.</para>
+            <para>By default HttpClient assumes only non-entity enclosing methods such as
+                <literal>GET</literal> and <literal>HEAD</literal> to be idempotent and entity
+                enclosing methods such as <literal>POST</literal> and <literal>PUT</literal> to be
+                not for compatibility reasons.</para>
         </section>
         <section>
             <title>Automatic exception recovery</title>
@@ -773,6 +831,11 @@ CloseableHttpClient httpclient = HttpClients.custom()
         .setRetryHandler(myRetryHandler)
         .build();
 ]]></programlisting>
+          <para>Please note that one can use <classname>StandardHttpRequestRetryHandler</classname>
+              instead of the one used by default in order to treat those request methods defined
+              as idempotent by RFC-2616 as safe to retry automatically: <literal>GET</literal>,
+              <literal>HEAD</literal>, <literal>PUT</literal>, <literal>DELETE</literal>, <literal>
+              OPTIONS</literal>, and <literal>TRACE</literal>.</para>
         </section>
     </section>
     <section>
@@ -787,58 +850,6 @@ CloseableHttpClient httpclient = HttpClients.custom()
             - even if currently blocked in an I/O operation - is guaranteed to unblock by throwing a
                 <exceptionname>InterruptedIOException</exceptionname></para>
     </section>
-    <section id="protocol_interceptors">
-        <title>HTTP protocol interceptors</title>
-        <para>The HTTP protocol interceptor is a routine that implements a specific aspect of the HTTP
-            protocol. Usually protocol interceptors are expected to act upon one specific header or
-            a group of related headers of the incoming message, or populate the outgoing message with
-            one specific header or a group of related headers. Protocol interceptors can also
-            manipulate content entities enclosed with messages - transparent content compression /
-            decompression being a good example. Usually this is accomplished by using the
-            'Decorator' pattern where a wrapper entity class is used to decorate the original
-            entity. Several protocol interceptors can be combined to form one logical unit.</para>
-        <para>Protocol interceptors can collaborate by sharing information - such as a processing
-            state - through the HTTP execution context. Protocol interceptors can use HTTP context
-            to store a processing state for one request or several consecutive requests.</para>
-        <para>Usually the order in which interceptors are executed should not matter as long as they
-            do not depend on a particular state of the execution context. If protocol interceptors
-            have interdependencies and therefore must be executed in a particular order, they should
-            be added to the protocol processor in the same sequence as their expected execution
-            order.</para>
-        <para>Protocol interceptors must be implemented as thread-safe. Similarly to servlets,
-            protocol interceptors should not use instance variables unless access to those variables
-            is synchronized.</para>
-        <para>This is an example of how local context can be used to persist a processing state
-            between consecutive requests:</para>
-        <programlisting><![CDATA[
-CloseableHttpClient httpclient = HttpClients.custom()
-        .addInterceptorLast(new HttpRequestInterceptor() {
-
-            public void process(
-                    final HttpRequest request,
-                    final HttpContext context) throws HttpException, IOException {
-                AtomicInteger count = (AtomicInteger) context.getAttribute("count");
-                request.addHeader("Count", Integer.toString(count.getAndIncrement()));
-            }
-
-        })
-        .build();
-
-AtomicInteger count = new AtomicInteger(1);
-HttpClientContext localContext = HttpClientContext.create();
-localContext.setAttribute("count", count);
-
-HttpGet httpget = new HttpGet("http://localhost/");
-for (int i = 0; i < 10; i++) {
-    CloseableHttpResponse response = httpclient.execute(httpget, localContext);
-    try {
-        HttpEntity entity = response.getEntity();
-    } finally {
-        response.close();
-    }
-}
-]]></programlisting>
-    </section>
     <section>
         <title>Redirect handling</title>
         <para>HttpClient handles all types of redirects automatically, except those explicitly
diff --git a/src/docbkx/preface.xml b/src/docbkx/preface.xml
index 8b7848b..b02e2ee 100644
--- a/src/docbkx/preface.xml
+++ b/src/docbkx/preface.xml
@@ -71,7 +71,7 @@
                 HttpClient is NOT a browser. It is a client side HTTP transport library. 
                 HttpClient's purpose is to transmit and receive HTTP messages. HttpClient will not 
                 attempt to process content, execute javascript embedded in HTML pages, try to guess
-                content type, if not explicitly set, or reformat request / redirect location URIs,
+                content type, if not explicitly set, or reformat request / rewrite location URIs,
                 or other functionality unrelated to the HTTP transport.
                 </para>
             </listitem>
diff --git a/src/docbkx/statemgmt.xml b/src/docbkx/statemgmt.xml
index b4da496..eb13511 100644
--- a/src/docbkx/statemgmt.xml
+++ b/src/docbkx/statemgmt.xml
@@ -45,63 +45,29 @@
             as a "magic cookie" and the name stuck.</para>
         <para>HttpClient uses the <interfacename>Cookie</interfacename> interface to represent an
             abstract cookie token. In its simplest form an HTTP cookie is merely a name / value pair.
-            Usually an HTTP cookie also contains a number of attributes such as version, a domain
-            for which is valid, a path that specifies the subset of URLs on the origin server to
-            which this cookie applies, and the maximum period of time for which the cookie is valid.</para>
+            Usually an HTTP cookie also contains a number of attributes such a domain for which is
+            valid, a path that specifies the subset of URLs on the origin server to which this
+            cookie applies, and the maximum period of time for which the cookie is valid.</para>
         <para>The <interfacename>SetCookie</interfacename> interface represents a
                 <literal>Set-Cookie</literal> response header sent by the origin server to the HTTP
-            agent in order to maintain a conversational state.
-            The <interfacename>SetCookie2</interfacename> interface extends SetCookie with
-                <literal>Set-Cookie2</literal> specific methods.</para>
-        <para>The <interfacename>ClientCookie</interfacename> interface extends
-                <interfacename>Cookie</interfacename> interface with additional client specific
-            functionality such as the ability to retrieve original cookie attributes exactly as they were
-            specified by the origin server. This is important for generating the
-                <literal>Cookie</literal> header because some cookie specifications require that the
-                <literal>Cookie</literal> header should include certain attributes only if they were
-            specified in the <literal>Set-Cookie</literal> or <literal>Set-Cookie2</literal>
-            header.</para>
-        <section>
-            <title>Cookie versions</title>
-            <para>Cookies compatible with Netscape draft specification but non-compliant with the
-                official specification are considered to be of version 0. Standard compliant cookies
-                are expected to have version 1. HttpClient may handle cookies differently depending
-                on the version.</para>
-            <para>Here is an example of re-creating a Netscape cookie:</para>
-            <programlisting><![CDATA[
-BasicClientCookie netscapeCookie = new BasicClientCookie("name", "value");
-netscapeCookie.setVersion(0);
-netscapeCookie.setDomain(".mycompany.com");
-netscapeCookie.setPath("/");
-]]></programlisting>
-            <para>Here is an example of re-creating a standard cookie. Please note that standard
-                compliant cookie must retain all attributes as sent by the origin server:</para>
-            <programlisting><![CDATA[
-BasicClientCookie stdCookie = new BasicClientCookie("name", "value");
-stdCookie.setVersion(1);
-stdCookie.setDomain(".mycompany.com");
-stdCookie.setPath("/");
-stdCookie.setSecure(true);
-// Set attributes EXACTLY as sent by the server 
-stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
-stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
-]]></programlisting>
-            <para>Here is an example of re-creating a <literal>Set-Cookie2</literal> compliant
-                cookie. Please note that standard compliant cookie must retain all attributes as
-                sent by the origin server:</para>
-            <programlisting><![CDATA[
-BasicClientCookie2 stdCookie = new BasicClientCookie2("name", "value");
-stdCookie.setVersion(1);
-stdCookie.setDomain(".mycompany.com");
-stdCookie.setPorts(new int[] {80,8080});
-stdCookie.setPath("/");
-stdCookie.setSecure(true);
-// Set attributes EXACTLY as sent by the server 
-stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
-stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
-stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
+            agent in order to maintain a conversational state.</para>
+        <para>The <interfacename>ClientCookie</interfacename> interface extends <interfacename>
+            Cookie</interfacename> interface with additional client specific functionality such
+            as the ability to retrieve original cookie attributes exactly as they were specified
+            by the origin server. This is important for generating the <literal>Cookie</literal>
+            header because some cookie specifications require that the  <literal>Cookie</literal>
+            header should include certain attributes only if they were specified in the
+            <literal>Set-Cookie</literal> header.</para>
+        <para>Here is an example of creating a client-side cookie object:</para>
+        <programlisting><![CDATA[
+BasicClientCookie cookie = new BasicClientCookie("name", "value");
+// Set effective domain and path attributes
+cookie.setDomain(".mycompany.com");
+cookie.setPath("/");
+// Set attributes exactly as sent by the server
+cookie.setAttribute(ClientCookie.PATH_ATTR, "/");
+cookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
 ]]></programlisting>
-        </section>
     </section>
     <section>
         <title>Cookie specifications</title>
@@ -109,8 +75,7 @@ stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
             specification. The cookie management specification is expected to enforce:</para>
         <itemizedlist>
             <listitem>
-                <para>rules of parsing <literal>Set-Cookie</literal> and optionally
-                        <literal>Set-Cookie2</literal> headers.</para>
+                <para>rules of parsing <literal>Set-Cookie</literal> headers.</para>
             </listitem>
             <listitem>
                 <para>rules of validation of parsed cookies.</para>
@@ -125,32 +90,60 @@ stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
         <itemizedlist>
             <listitem>
                 <formalpara>
-                    <title>Netscape draft:</title>
-                    <para>This specification conforms to the original draft specification published
+                    <title>Standard strict:</title>
+                    <para>State management policy compliant with the syntax and semantics of
+                        the well-behaved profile defined by RFC 6265, section 4.</para>
+                </formalpara>
+            </listitem>
+            <listitem>
+                <formalpara>
+                    <title>Standard:</title>
+                    <para>State management policy compliant with a more relaxed profile defined
+                        by RFC 6265, section 4 intended for interoperability with existing servers
+                        that do not conform to the well behaved profile.</para>
+                </formalpara>
+            </listitem>
+            <listitem>
+                <formalpara>
+                    <title>Netscape draft (obsolete):</title>
+                    <para>This policy conforms to the original draft specification published
                         by Netscape Communications. It should be avoided unless absolutely necessary
                         for compatibility with legacy code.</para>
                 </formalpara>
             </listitem>
             <listitem>
                 <formalpara>
-                    <title>Standard:</title>
-                    <para>RFC 2965 HTTP state management specification.</para>
+                    <title>RFC 2965 (obsolete):</title>
+                    <para>State management policy compliant with the obsolete state management
+                        specification defined by RFC 2965. Please do not use in new applications.
+                    </para>
                 </formalpara>
             </listitem>
             <listitem>
                 <formalpara>
-                    <title>Browser compatibility:</title>
-                    <para>This implementation strives to closely mimic the (mis)behavior of common web
-                        browser applications such as Microsoft Internet Explorer and Mozilla
-                        FireFox.</para>
+                    <title>RFC 2109 (obsolete):</title>
+                    <para>State management policy compliant with the obsolete state management
+                        specification defined by RFC 2109. Please do not use in new applications.
+                    </para>
                 </formalpara>
             </listitem>
             <listitem>
                 <formalpara>
-                    <title>Best match:</title>
-                    <para>'Meta' cookie specification that picks up a cookie policy based on the
-                        format of cookies sent with the HTTP response. It basically aggregates all
-                        above implementations into one class.</para>
+                    <title>Browser compatibility (obsolete):</title>
+                    <para>This policy strives to closely mimic the (mis)behavior of older versions
+                        of browser applications such as Microsoft Internet Explorer and Mozilla
+                        FireFox. Please do not use in new applications.</para>
+                </formalpara>
+            </listitem>
+            <listitem>
+                <formalpara>
+                    <title>Default:</title>
+                    <para>Default cookie policy is a synthetic policy that picks up either RFC 2965,
+                        RFC 2109 or Netscape draft compliant implementation based on properties of
+                        cookies sent with the HTTP response (such as version attribute,
+                        now obsolete). This policy will be deprecated in favor of the
+                        standard (RFC 6265 compliant) implementation in the next minor release
+                        of HttpClient.</para>
                 </formalpara>
             </listitem>
             <listitem>
@@ -160,9 +153,11 @@ stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
                 </formalpara>
             </listitem>
         </itemizedlist>
-        <para>It is strongly recommended to use the <literal>Best Match</literal> policy and let
-            HttpClient pick up an appropriate compliance level at runtime based on the execution
-            context.</para>
+        <para>It is strongly recommended to use either <literal>Standard</literal> or
+            <literal>Standard strict</literal> policy in new applications. Obsolete specifications
+            should be used for compatibility with legacy systems only. Support for obsolete
+            specifications will be removed in the next major release of HttpClient.
+        </para>
     </section>
     <section>
         <title>Choosing cookie policy</title>
@@ -170,13 +165,13 @@ stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
             if required.</para>
         <programlisting><![CDATA[
 RequestConfig globalConfig = RequestConfig.custom()
-        .setCookieSpec(CookieSpecs.BEST_MATCH)
+        .setCookieSpec(CookieSpecs.DEFAULT)
         .build();
 CloseableHttpClient httpclient = HttpClients.custom()
         .setDefaultRequestConfig(globalConfig)
         .build();
 RequestConfig localConfig = RequestConfig.copy(globalConfig)
-        .setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
+        .setCookieSpec(CookieSpecs.STANDARD_STRICT)
         .build();
 HttpGet httpGet = new HttpGet("/");
 httpGet.setConfig(localConfig);
@@ -191,26 +186,14 @@ httpGet.setConfig(localConfig);
             HttpClient. Once the custom specification has been registered, it can be activated the
             same way as a standard cookie specification.</para>
         <programlisting><![CDATA[
-CookieSpecProvider easySpecProvider = new CookieSpecProvider() {
-
-    public CookieSpec create(HttpContext context) {
-
-        return new BrowserCompatSpec() {
-            @Override
-            public void validate(Cookie cookie, CookieOrigin origin)
-                    throws MalformedCookieException {
-                // Oh, I am easy
-            }
-        };
-    }
+PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();
 
-};
 Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider>create()
-        .register(CookieSpecs.BEST_MATCH,
-            new BestMatchSpecFactory())
-        .register(CookieSpecs.BROWSER_COMPATIBILITY,
-            new BrowserCompatSpecFactory())
-        .register("easy", easySpecProvider)
+        .register(CookieSpecs.DEFAULT,
+                new DefaultCookieSpecProvider(publicSuffixMatcher))
+        .register(CookieSpecs.STANDARD,
+                new RFC6265CookieSpecProvider(publicSuffixMatcher))
+        .register("easy", new EasySpecProvider())
         .build();
 
 RequestConfig requestConfig = RequestConfig.custom()
@@ -238,7 +221,6 @@ CloseableHttpClient httpclient = HttpClients.custom()
 CookieStore cookieStore = new BasicCookieStore();
 // Populate cookies if needed
 BasicClientCookie cookie = new BasicClientCookie("name", "value");
-cookie.setVersion(0);
 cookie.setDomain(".mycompany.com");
 cookie.setPath("/");
 cookieStore.addCookie(cookie);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/httpcomponents-client.git



More information about the pkg-java-commits mailing list