Skip to content
Commits on Source (5)
Apache HttpComponents Client
Copyright 1999-2019 The Apache Software Foundation
Copyright 1999-2020 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
......
Release 4.5.11
-------------------
This is a maintenance release that fixes a number defects discovered since 4.5.10
and upgrades HttpCore dependency to version 4.4.13.
Changelog:
-------------------
* Improved domain name normalization by DefaultHostnameVerifier.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* HTTPCLIENT-2033: Connection managers to immediately shut down all leased connection upon shutdown.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* HTTPCLIENT-2020: DefaultBackoffStrategy to support TOO_MANY_REQUESTS (429).
Contributed by Michael Osipov <michaelo at apache.org>
* HTTPCLIENT-2030: Fixed PublicSuffixMatcher#getDomainRoot behavior with invalid hostnames.
Contributed by Niels Basjes <niels at basjes.nl>
* HTTPCLIENT-2029: URIBuilder to support parsing of non-UTF8 URIs.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* HTTPCLIENT-2026: Fixed URIBuilder#isOpaque() logic.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* Updated text in pool stats description
Contributed by chao chang <chang-chao at users.noreply.github.com>
* HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer.
Contributed by Olof Larsson <olof at sylt.nu>
* Fixed fallback PublicSuffixMatcher instance.
Contributed by Ryan Schmitt <rschmitt at apache.org>
* Added family property #145.
Contributed by behrangsa
Release 4.5.10
-------------------
......
httpcomponents-client (4.5.10-3) UNRELEASED; urgency=medium
httpcomponents-client (4.5.11-1) unstable; urgency=medium
* Team upload.
[ Andrius Merkys ]
* Compiling sources depending on libspymemcached-java.
-- Andrius Merkys <merkys@debian.org> Tue, 12 Nov 2019 02:33:10 -0500
[ Emmanuel Bourg ]
* New upstream release
- Refreshed the patches
* Standards-Version updated to 4.5.0
-- Emmanuel Bourg <ebourg@apache.org> Sat, 25 Jan 2020 23:44:33 +0100
httpcomponents-client (4.5.10-2) unstable; urgency=medium
......
......@@ -21,7 +21,7 @@ Build-Depends:
libmockito-java,
maven-debian-helper,
libspymemcached-java
Standards-Version: 4.4.1
Standards-Version: 4.5.0
Vcs-Git: https://salsa.debian.org/java-team/httpcomponents-client.git
Vcs-Browser: https://salsa.debian.org/java-team/httpcomponents-client
Homepage: http://hc.apache.org/httpcomponents-client-ga/index.html
......
......@@ -4586,7 +4586,7 @@ Forwarded: not-needed
-}
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestHttpCacheEntrySerializers.java
+++ /dev/null
@@ -1,199 +0,0 @@
@@ -1,352 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
......@@ -4615,6 +4615,7 @@ Forwarded: not-needed
- */
-package org.apache.http.impl.client.cache;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
......@@ -4627,7 +4628,6 @@ Forwarded: not-needed
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.http.Header;
......@@ -4661,25 +4661,182 @@ Forwarded: not-needed
- readWriteVerify(makeCacheEntryWithVariantMap());
- }
-
- @Test(expected = HttpCacheEntrySerializationException.class)
- public void throwExceptionIfUnsafeDeserialization() throws IOException {
- impl.readFrom(new ByteArrayInputStream(serializeProhibitedObject()));
- @Test
- public void isAllowedClassNameStringTrue() {
- assertIsAllowedClassNameTrue(String.class.getName());
- }
-
- @Test(expected = HttpCacheEntrySerializationException.class)
- public void allowClassesToBeDeserialized() throws IOException {
- impl = new DefaultHttpCacheEntrySerializer(
- Pattern.compile("javax.sql.rowset.BaseRowSet"),
- Pattern.compile("com.sun.rowset.JdbcRowSetImpl"));
- readVerify(serializeProhibitedObject());
- @Test
- public void isAllowedClassNameStringArrayTrue() {
- assertIsAllowedClassNameTrue("[L" + String.class.getName());
- }
-
- @Test
- public void isAllowedClassNameStringArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[L" + String.class.getName());
- }
-
- @Test
- public void isAllowedClassNameDataTrue() {
- assertIsAllowedClassNameTrue(Date.class.getName());
- }
-
- @Test
- public void isAllowedClassNameStatusLineTrue() {
- assertIsAllowedClassNameTrue(StatusLine.class.getName());
- }
-
- @Test
- public void isAllowedClassNameResourceTrue() {
- assertIsAllowedClassNameTrue(Resource.class.getName());
- }
-
- @Test
- public void isAllowedClassNameByteArrayTrue() {
- assertIsAllowedClassNameTrue("[B");
- }
-
- @Test
- public void isAllowedClassNameByteArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[B");
- }
-
- @Test
- public void isAllowedClassNameCharArrayTrue() {
- assertIsAllowedClassNameTrue("[C");
- }
-
- @Test
- public void isAllowedClassNameCharArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[C");
- }
-
- @Test
- public void isAllowedClassNameDoubleArrayTrue() {
- assertIsAllowedClassNameTrue("[D");
- }
-
- @Test
- public void isAllowedClassNameDoubleArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[D");
- }
-
- @Test
- public void isAllowedClassNameFloatArrayTrue() {
- assertIsAllowedClassNameTrue("[F");
- }
-
- @Test
- public void isAllowedClassNameFloatArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[F");
- }
-
- @Test
- public void isAllowedClassNameIntArrayTrue() {
- assertIsAllowedClassNameTrue("[I");
- }
-
- @Test
- public void isAllowedClassNameIntArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[I");
- }
-
- @Test
- public void isAllowedClassNameLongArrayTrue() {
- assertIsAllowedClassNameTrue("[J");
- }
-
- @Test
- public void isAllowedClassNameLongArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[J");
- }
-
- @Test
- public void isAllowedClassNameShortArrayTrue() {
- assertIsAllowedClassNameTrue("[S");
- }
-
- @Test
- public void isAllowedClassNameShortArrayArrayTrue() {
- assertIsAllowedClassNameTrue("[[S");
- }
-
- @Test
- public void isAllowedClassNameCollectionsInvokerTransformerFalse() {
- assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InvokerTransformer");
- }
-
- @Test
- public void isAllowedClassNameCollections4InvokerTransformerFalse() {
- assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InvokerTransformer");
- }
-
- @Test
- public void isAllowedClassNameCollectionsInstantiateTransformerFalse() {
- assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InstantiateTransformer");
- }
-
- @Test
- public void isAllowedClassNameCollections4InstantiateTransformerFalse() {
- assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InstantiateTransformer");
- }
-
- @Test
- public void isAllowedClassNameGroovyConvertedClosureFalse() {
- assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.ConvertedClosure");
- }
-
- @Test
- public void isAllowedClassNameGroovyMethodClosureFalse() {
- assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.MethodClosure");
- }
-
- @Test
- public void isAllowedClassNameSpringObjectFactoryFalse() {
- assertIsAllowedClassNameFalse("org.springframework.beans.factory.ObjectFactory");
- }
-
- @Test
- public void isAllowedClassNameCalanTemplatesImplFalse() {
- assertIsAllowedClassNameFalse("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
- }
-
- @Test
- public void isAllowedClassNameCalanTemplatesImplArrayFalse() {
- assertIsAllowedClassNameFalse("[Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
- }
-
- @Test
- public void isAllowedClassNameJavaRmiRegistryFalse() {
- assertIsAllowedClassNameFalse("java.rmi.registry.Registry");
- }
-
- @Test
- public void isAllowedClassNameJavaRmiServerRemoteObjectInvocationHandlerFalse() {
- assertIsAllowedClassNameFalse("java.rmi.server.RemoteObjectInvocationHandler");
- }
-
- @Test
- public void isAllowedClassNameJavaxXmlTransformTemplatesFalse() {
- assertIsAllowedClassNameFalse("javax.xml.transform.Templates");
- }
-
- @Test
- public void isAllowedClassNameJavaxManagementMBeanServerInvocationHandlerFalse() {
- assertIsAllowedClassNameFalse("javax.management.MBeanServerInvocationHandler");
- }
-
- private static void assertIsAllowedClassNameTrue(final String className) {
- assertTrue(DefaultHttpCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
- }
-
- private static void assertIsAllowedClassNameFalse(final String className) {
- assertFalse(DefaultHttpCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
- }
-
- @Test(expected = HttpCacheEntrySerializationException.class)
- public void allowClassesToBeDeserializedByRegex() throws IOException {
- impl = new DefaultHttpCacheEntrySerializer(
- Pattern.compile(("^com\\.sun\\.rowset\\.(.*)")),
- Pattern.compile("^javax\\.sql\\.rowset\\.BaseRowSet$"));
- readVerify(serializeProhibitedObject());
- public void throwExceptionIfUnsafeDeserialization() throws IOException {
- impl.readFrom(new ByteArrayInputStream(serializeProhibitedObject()));
- }
-
- private byte[] serializeProhibitedObject() throws IOException {
......@@ -4694,11 +4851,7 @@ Forwarded: not-needed
- return baos.toByteArray();
- }
-
- private void readVerify(final byte[] data) throws IOException {
- impl.readFrom(new ByteArrayInputStream(data));
- }
-
- public void readWriteVerify(final HttpCacheEntry writeEntry) throws IOException {
- private void readWriteVerify(final HttpCacheEntry writeEntry) throws IOException {
- // write the entry
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- impl.writeTo(writeEntry, out);
......
......@@ -28,7 +28,7 @@
<parent>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcomponents-client</artifactId>
<version>4.5.10</version>
<version>4.5.11</version>
</parent>
<artifactId>fluent-hc</artifactId>
<name>Apache HttpClient Fluent API</name>
......
......@@ -28,7 +28,7 @@
<parent>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcomponents-client</artifactId>
<version>4.5.10</version>
<version>4.5.11</version>
</parent>
<artifactId>httpclient-cache</artifactId>
<name>Apache HttpClient Cache</name>
......
......@@ -37,7 +37,7 @@ public class HttpCacheEntrySerializationException extends IOException {
private static final long serialVersionUID = 9219188365878433519L;
public HttpCacheEntrySerializationException(final String message) {
super();
super(message);
}
public HttpCacheEntrySerializationException(final String message, final Throwable cause) {
......
......@@ -54,22 +54,6 @@ import org.apache.http.client.cache.HttpCacheEntrySerializer;
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer {
private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
Pattern.compile("^(\\[L)?org\\.apache\\.http\\.(.*)"),
Pattern.compile("^(\\[L)?java\\.util\\.(.*)"),
Pattern.compile("^(\\[L)?java\\.lang\\.(.*)$"),
Pattern.compile("^\\[B$")));
private final List<Pattern> allowedClassPatterns;
DefaultHttpCacheEntrySerializer(final Pattern... allowedClassPatterns) {
this.allowedClassPatterns = Collections.unmodifiableList(Arrays.asList(allowedClassPatterns));
}
public DefaultHttpCacheEntrySerializer() {
this.allowedClassPatterns = ALLOWED_CLASS_PATTERNS;
}
@Override
public void writeTo(final HttpCacheEntry cacheEntry, final OutputStream os) throws IOException {
final ObjectOutputStream oos = new ObjectOutputStream(os);
......@@ -82,7 +66,7 @@ public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer
@Override
public HttpCacheEntry readFrom(final InputStream is) throws IOException {
final ObjectInputStream ois = new RestrictedObjectInputStream(is, allowedClassPatterns);
final ObjectInputStream ois = new RestrictedObjectInputStream(is);
try {
return (HttpCacheEntry) ois.readObject();
} catch (final ClassNotFoundException ex) {
......@@ -92,32 +76,47 @@ public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer
}
}
private static class RestrictedObjectInputStream extends ObjectInputStream {
// visible for testing
static class RestrictedObjectInputStream extends ObjectInputStream {
private final List<Pattern> allowedClassPatterns;
private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
Pattern.compile("^(?:\\[+L)?org\\.apache\\.http\\..*$"),
Pattern.compile("^(?:\\[+L)?java\\.util\\..*$"),
Pattern.compile("^(?:\\[+L)?java\\.lang\\..*$"),
Pattern.compile("^\\[+Z$"), // boolean
Pattern.compile("^\\[+B$"), // byte
Pattern.compile("^\\[+C$"), // char
Pattern.compile("^\\[+D$"), // double
Pattern.compile("^\\[+F$"), // float
Pattern.compile("^\\[+I$"), // int
Pattern.compile("^\\[+J$"), // long
Pattern.compile("^\\[+S$") // short
));
private RestrictedObjectInputStream(final InputStream in, final List<Pattern> patterns) throws IOException {
private RestrictedObjectInputStream(final InputStream in) throws IOException {
super(in);
this.allowedClassPatterns = patterns;
}
@Override
protected Class<?> resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (isProhibited(desc)) {
throw new HttpCacheEntrySerializationException(String.format(
"Class %s is not allowed for deserialization", desc.getName()));
protected Class<?> resolveClass(final ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
final String className = objectStreamClass.getName();
if (!isAllowedClassName(className)) {
final String message = String.format("Class %s is not allowed for deserialization", className);
throw new HttpCacheEntrySerializationException(message);
}
return super.resolveClass(desc);
return super.resolveClass(objectStreamClass);
}
private boolean isProhibited(final ObjectStreamClass desc) {
for (final Pattern pattern : allowedClassPatterns) {
if (pattern.matcher(desc.getName()).matches()) {
return false;
// visible for testing
static boolean isAllowedClassName(final String className) {
for (final Pattern allowedClassPattern : ALLOWED_CLASS_PATTERNS) {
if (allowedClassPattern.matcher(className).matches()) {
return true;
}
}
return true;
return false;
}
}
}
......@@ -26,6 +26,7 @@
*/
package org.apache.http.impl.client.cache;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
......@@ -38,7 +39,6 @@ import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
......@@ -72,25 +72,182 @@ public class TestHttpCacheEntrySerializers {
readWriteVerify(makeCacheEntryWithVariantMap());
}
@Test(expected = HttpCacheEntrySerializationException.class)
public void throwExceptionIfUnsafeDeserialization() throws IOException {
impl.readFrom(new ByteArrayInputStream(serializeProhibitedObject()));
@Test
public void isAllowedClassNameStringTrue() {
assertIsAllowedClassNameTrue(String.class.getName());
}
@Test(expected = HttpCacheEntrySerializationException.class)
public void allowClassesToBeDeserialized() throws IOException {
impl = new DefaultHttpCacheEntrySerializer(
Pattern.compile("javax.sql.rowset.BaseRowSet"),
Pattern.compile("com.sun.rowset.JdbcRowSetImpl"));
readVerify(serializeProhibitedObject());
@Test
public void isAllowedClassNameStringArrayTrue() {
assertIsAllowedClassNameTrue("[L" + String.class.getName());
}
@Test
public void isAllowedClassNameStringArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[L" + String.class.getName());
}
@Test
public void isAllowedClassNameDataTrue() {
assertIsAllowedClassNameTrue(Date.class.getName());
}
@Test
public void isAllowedClassNameStatusLineTrue() {
assertIsAllowedClassNameTrue(StatusLine.class.getName());
}
@Test
public void isAllowedClassNameResourceTrue() {
assertIsAllowedClassNameTrue(Resource.class.getName());
}
@Test
public void isAllowedClassNameByteArrayTrue() {
assertIsAllowedClassNameTrue("[B");
}
@Test
public void isAllowedClassNameByteArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[B");
}
@Test
public void isAllowedClassNameCharArrayTrue() {
assertIsAllowedClassNameTrue("[C");
}
@Test
public void isAllowedClassNameCharArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[C");
}
@Test
public void isAllowedClassNameDoubleArrayTrue() {
assertIsAllowedClassNameTrue("[D");
}
@Test
public void isAllowedClassNameDoubleArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[D");
}
@Test
public void isAllowedClassNameFloatArrayTrue() {
assertIsAllowedClassNameTrue("[F");
}
@Test
public void isAllowedClassNameFloatArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[F");
}
@Test
public void isAllowedClassNameIntArrayTrue() {
assertIsAllowedClassNameTrue("[I");
}
@Test
public void isAllowedClassNameIntArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[I");
}
@Test
public void isAllowedClassNameLongArrayTrue() {
assertIsAllowedClassNameTrue("[J");
}
@Test
public void isAllowedClassNameLongArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[J");
}
@Test
public void isAllowedClassNameShortArrayTrue() {
assertIsAllowedClassNameTrue("[S");
}
@Test
public void isAllowedClassNameShortArrayArrayTrue() {
assertIsAllowedClassNameTrue("[[S");
}
@Test
public void isAllowedClassNameCollectionsInvokerTransformerFalse() {
assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InvokerTransformer");
}
@Test
public void isAllowedClassNameCollections4InvokerTransformerFalse() {
assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InvokerTransformer");
}
@Test
public void isAllowedClassNameCollectionsInstantiateTransformerFalse() {
assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InstantiateTransformer");
}
@Test
public void isAllowedClassNameCollections4InstantiateTransformerFalse() {
assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InstantiateTransformer");
}
@Test
public void isAllowedClassNameGroovyConvertedClosureFalse() {
assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.ConvertedClosure");
}
@Test
public void isAllowedClassNameGroovyMethodClosureFalse() {
assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.MethodClosure");
}
@Test
public void isAllowedClassNameSpringObjectFactoryFalse() {
assertIsAllowedClassNameFalse("org.springframework.beans.factory.ObjectFactory");
}
@Test
public void isAllowedClassNameCalanTemplatesImplFalse() {
assertIsAllowedClassNameFalse("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
}
@Test
public void isAllowedClassNameCalanTemplatesImplArrayFalse() {
assertIsAllowedClassNameFalse("[Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
}
@Test
public void isAllowedClassNameJavaRmiRegistryFalse() {
assertIsAllowedClassNameFalse("java.rmi.registry.Registry");
}
@Test
public void isAllowedClassNameJavaRmiServerRemoteObjectInvocationHandlerFalse() {
assertIsAllowedClassNameFalse("java.rmi.server.RemoteObjectInvocationHandler");
}
@Test
public void isAllowedClassNameJavaxXmlTransformTemplatesFalse() {
assertIsAllowedClassNameFalse("javax.xml.transform.Templates");
}
@Test
public void isAllowedClassNameJavaxManagementMBeanServerInvocationHandlerFalse() {
assertIsAllowedClassNameFalse("javax.management.MBeanServerInvocationHandler");
}
private static void assertIsAllowedClassNameTrue(final String className) {
assertTrue(DefaultHttpCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
}
private static void assertIsAllowedClassNameFalse(final String className) {
assertFalse(DefaultHttpCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
}
@Test(expected = HttpCacheEntrySerializationException.class)
public void allowClassesToBeDeserializedByRegex() throws IOException {
impl = new DefaultHttpCacheEntrySerializer(
Pattern.compile(("^com\\.sun\\.rowset\\.(.*)")),
Pattern.compile("^javax\\.sql\\.rowset\\.BaseRowSet$"));
readVerify(serializeProhibitedObject());
public void throwExceptionIfUnsafeDeserialization() throws IOException {
impl.readFrom(new ByteArrayInputStream(serializeProhibitedObject()));
}
private byte[] serializeProhibitedObject() throws IOException {
......@@ -105,11 +262,7 @@ public class TestHttpCacheEntrySerializers {
return baos.toByteArray();
}
private void readVerify(final byte[] data) throws IOException {
impl.readFrom(new ByteArrayInputStream(data));
}
public void readWriteVerify(final HttpCacheEntry writeEntry) throws IOException {
private void readWriteVerify(final HttpCacheEntry writeEntry) throws IOException {
// write the entry
final ByteArrayOutputStream out = new ByteArrayOutputStream();
impl.writeTo(writeEntry, out);
......
......@@ -28,7 +28,7 @@
<parent>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcomponents-client</artifactId>
<version>4.5.10</version>
<version>4.5.11</version>
</parent>
<artifactId>httpclient-osgi</artifactId>
<name>Apache HttpClient OSGi bundle</name>
......
......@@ -28,7 +28,7 @@
<parent>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcomponents-client</artifactId>
<version>4.5.10</version>
<version>4.5.11</version>
</parent>
<artifactId>httpclient-win</artifactId>
<name>Apache HttpClient Windows features</name>
......
......@@ -28,7 +28,7 @@
<parent>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcomponents-client</artifactId>
<version>4.5.10</version>
<version>4.5.11</version>
</parent>
<artifactId>httpclient</artifactId>
<name>Apache HttpClient</name>
......
......@@ -34,6 +34,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.http.Consts;
import org.apache.http.NameValuePair;
import org.apache.http.conn.util.InetAddressUtils;
......@@ -78,8 +79,7 @@ public class URIBuilder {
* @throws URISyntaxException if the input is not a valid URI
*/
public URIBuilder(final String string) throws URISyntaxException {
super();
digestURI(new URI(string));
this(new URI(string), null);
}
/**
......@@ -87,7 +87,26 @@ public class URIBuilder {
* @param uri
*/
public URIBuilder(final URI uri) {
this(uri, null);
}
/**
* Construct an instance from the string which must be a valid URI.
*
* @param string a valid URI in string form
* @throws URISyntaxException if the input is not a valid URI
*/
public URIBuilder(final String string, final Charset charset) throws URISyntaxException {
this(new URI(string), charset);
}
/**
* Construct an instance from the provided URI.
* @param uri
*/
public URIBuilder(final URI uri, final Charset charset) {
super();
setCharset(charset);
digestURI(uri);
}
......@@ -497,7 +516,7 @@ public class URIBuilder {
* @since 4.3
*/
public boolean isOpaque() {
return isPathEmpty();
return this.pathSegments == null && this.encodedPath == null;
}
public String getScheme() {
......
......@@ -36,7 +36,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
import javax.naming.InvalidNameException;
......@@ -55,6 +54,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.annotation.Contract;
import org.apache.http.annotation.ThreadingBehavior;
import org.apache.http.conn.util.DnsUtils;
import org.apache.http.conn.util.DomainType;
import org.apache.http.conn.util.InetAddressUtils;
import org.apache.http.conn.util.PublicSuffixMatcher;
......@@ -164,12 +164,12 @@ public final class DefaultHostnameVerifier implements HostnameVerifier {
static void matchDNSName(final String host, final List<SubjectName> subjectAlts,
final PublicSuffixMatcher publicSuffixMatcher) throws SSLException {
final String normalizedHost = host.toLowerCase(Locale.ROOT);
final String normalizedHost = DnsUtils.normalize(host);
for (int i = 0; i < subjectAlts.size(); i++) {
final SubjectName subjectAlt = subjectAlts.get(i);
if (subjectAlt.getType() == SubjectName.DNS) {
final String normalizedSubjectAlt = subjectAlt.getValue().toLowerCase(Locale.ROOT);
if (matchIdentityStrict(normalizedHost, normalizedSubjectAlt, publicSuffixMatcher)) {
final String normalizedSubjectAlt = DnsUtils.normalize(subjectAlt.getValue());
if (matchIdentityStrict(normalizedHost, normalizedSubjectAlt, publicSuffixMatcher, DomainType.ICANN)) {
return;
}
}
......@@ -180,9 +180,9 @@ public final class DefaultHostnameVerifier implements HostnameVerifier {
static void matchCN(final String host, final String cn,
final PublicSuffixMatcher publicSuffixMatcher) throws SSLException {
final String normalizedHost = host.toLowerCase(Locale.ROOT);
final String normalizedCn = cn.toLowerCase(Locale.ROOT);
if (!matchIdentityStrict(normalizedHost, normalizedCn, publicSuffixMatcher)) {
final String normalizedHost = DnsUtils.normalize(host);
final String normalizedCn = DnsUtils.normalize(cn);
if (!matchIdentityStrict(normalizedHost, normalizedCn, publicSuffixMatcher, DomainType.ICANN)) {
throw new SSLPeerUnverifiedException("Certificate for <" + host + "> doesn't match " +
"common name of the certificate subject: " + cn);
}
......@@ -198,9 +198,10 @@ public final class DefaultHostnameVerifier implements HostnameVerifier {
private static boolean matchIdentity(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher,
final DomainType domainType,
final boolean strict) {
if (publicSuffixMatcher != null && host.contains(".")) {
if (!matchDomainRoot(host, publicSuffixMatcher.getDomainRoot(identity, DomainType.ICANN))) {
if (!matchDomainRoot(host, publicSuffixMatcher.getDomainRoot(identity, domainType))) {
return false;
}
}
......@@ -235,20 +236,32 @@ public final class DefaultHostnameVerifier implements HostnameVerifier {
static boolean matchIdentity(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher) {
return matchIdentity(host, identity, publicSuffixMatcher, false);
return matchIdentity(host, identity, publicSuffixMatcher, null, false);
}
static boolean matchIdentity(final String host, final String identity) {
return matchIdentity(host, identity, null, false);
return matchIdentity(host, identity, null, null, false);
}
static boolean matchIdentityStrict(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher) {
return matchIdentity(host, identity, publicSuffixMatcher, true);
return matchIdentity(host, identity, publicSuffixMatcher, null, true);
}
static boolean matchIdentityStrict(final String host, final String identity) {
return matchIdentity(host, identity, null, true);
return matchIdentity(host, identity, null, null, true);
}
static boolean matchIdentity(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher,
final DomainType domainType) {
return matchIdentity(host, identity, publicSuffixMatcher, domainType, false);
}
static boolean matchIdentityStrict(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher,
final DomainType domainType) {
return matchIdentity(host, identity, publicSuffixMatcher, domainType, true);
}
static String extractCN(final String subjectPrincipal) throws SSLException {
......
/*
* ====================================================================
* 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;
/**
* A collection of utilities relating to Domain Name System.
*
* @since 4.5
*/
public class DnsUtils {
private DnsUtils() {
}
private static boolean isUpper(final char c) {
return c >= 'A' && c <= 'Z';
}
public static String normalize(final String s) {
if (s == null) {
return null;
}
int pos = 0;
int remaining = s.length();
while (remaining > 0) {
if (isUpper(s.charAt(pos))) {
break;
}
pos++;
remaining--;
}
if (remaining > 0) {
final StringBuilder buf = new StringBuilder(s.length());
buf.append(s, 0, pos);
while (remaining > 0) {
final char c = s.charAt(pos);
if (isUpper(c)) {
buf.append((char) (c + ('a' - 'A')));
} else {
buf.append(c);
}
pos++;
remaining--;
}
return buf.toString();
} else {
return s;
}
}
}
......@@ -29,7 +29,6 @@ package org.apache.http.conn.util;
import java.net.IDN;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
......@@ -142,7 +141,7 @@ public final class PublicSuffixMatcher {
if (domain.startsWith(".")) {
return null;
}
final String normalized = domain.toLowerCase(Locale.ROOT);
final String normalized = DnsUtils.normalize(domain);
String segment = normalized;
String result = null;
while (segment != null) {
......@@ -166,9 +165,15 @@ public final class PublicSuffixMatcher {
result = segment;
segment = nextSegment;
}
return result;
}
// If no expectations then this result is good.
if (expectedType == null || expectedType == DomainType.UNKNOWN) {
return result;
}
// If we did have expectations apparently there was no match
return null;
}
/**
* Tests whether the given domain matches any of entry from the public suffix list.
*/
......
......@@ -95,7 +95,7 @@ public final class PublicSuffixMatcherLoader {
}
}
} else {
DEFAULT_INSTANCE = new PublicSuffixMatcher(Arrays.asList("com"), null);
DEFAULT_INSTANCE = new PublicSuffixMatcher(DomainType.ICANN, Arrays.asList("com"), null);
}
}
}
......
......@@ -49,7 +49,8 @@ public class DefaultBackoffStrategy implements ConnectionBackoffStrategy {
@Override
public boolean shouldBackoff(final HttpResponse resp) {
return resp.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE;
return resp.getStatusLine().getStatusCode() == 429 ||
resp.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE;
}
}
......@@ -362,7 +362,19 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
@Override
public void shutdown() {
close();
if (this.isShutdown.compareAndSet(false, true)) {
if (this.conn != null) {
this.log.debug("Shutting down connection");
try {
this.conn.shutdown();
} catch (final IOException iox) {
if (this.log.isDebugEnabled()) {
this.log.debug("I/O exception shutting down connection", iox);
}
}
this.conn = null;
}
}
}
}