You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2021/02/18 18:20:00 UTC

[httpcomponents-core] branch master updated (3ec5a94 -> e6b09bf)

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git.


 discard 3ec5a94  * Add charset constant * Add Content Type
    omit e13186b  HTTPCORE-668 - W3C recommendation text/event-stream
    omit 8101bbf  Basic and classic message builders to support copy operation
    omit 81ecf9c  HTTPCORE-667 - Add new Content Type application/problem+json
    omit 42f79d4  Minor Improvements:
    omit e9e7b1a  BasicHttpRequest to support absolute request URI representation
    omit eddbc1a  RFC 3986 conformance: BasicHttpRequest to reject requests whose path component begins with multiple slashes
    omit 5af7cb5  RFC 3986 conformance: BasicHttpRequest to support parsing of valid URI authority components not recognized by java.net.URI
    omit d375a17  Improved message builder support
    omit 3587341  Removed references to deprecated Assert#assertThat
     new cb6cfd3  Removed references to deprecated Assert#assertThat
     new fcfdfd3  Improved message builder support
     new 870a5b3  RFC 3986 conformance: BasicHttpRequest to support parsing of valid URI authority components not recognized by java.net.URI
     new 1614d5d  RFC 3986 conformance: BasicHttpRequest to reject requests whose path component begins with multiple slashes
     new 373b680  BasicHttpRequest to support absolute request URI representation
     new 6d7debd  Minor Improvements:
     new b7d3e26  HTTPCORE-667 - Add new Content Type application/problem+json
     new 94e751c  Basic and classic message builders to support copy operation
     new 35c1541  HTTPCORE-668 - W3C recommendation text/event-stream
     new e6b09bf  * Add charset constant * Add Content Type

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (3ec5a94)
            \
             N -- N -- N   refs/heads/master (e6b09bf)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 10 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../hc/core5/http2/hpack/TestHPackCoding.java      | 12 ++--
 .../hc/core5/benchmark/ResultFormatterTest.java    |  8 +--
 .../testing/classic/ClassicAuthenticationTest.java | 10 ++--
 .../classic/ClassicServerAndRequesterTest.java     |  8 +--
 .../testing/classic/ClassicTLSIntegrationTest.java | 15 ++---
 .../testing/framework/TestTestingFramework.java    | 34 +++++------
 .../apache/hc/core5/testing/nio/H2AlpnTest.java    | 18 +++---
 .../hc/core5/testing/nio/H2IntegrationTest.java    | 66 +++++++++++-----------
 .../testing/nio/H2ProtocolNegotiationTest.java     | 10 ++--
 .../nio/H2ServerAndMultiplexingRequesterTest.java  | 18 +++---
 .../testing/nio/H2ServerAndRequesterTest.java      | 14 ++---
 .../hc/core5/testing/nio/H2TLSIntegrationTest.java | 21 +++----
 .../core5/testing/nio/Http1AuthenticationTest.java | 14 ++---
 .../testing/nio/Http1ServerAndRequesterTest.java   | 16 +++---
 .../hc/core5/concurrent/TestComplexFuture.java     |  4 +-
 .../core5/reactor/TestAbstractIOSessionPool.java   |  4 +-
 .../org/apache/hc/core5/util/TestTimeValue.java    |  6 +-
 17 files changed, 140 insertions(+), 138 deletions(-)


[httpcomponents-core] 03/10: RFC 3986 conformance: BasicHttpRequest to support parsing of valid URI authority components not recognized by java.net.URI

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 870a5b3cfc5613051b23eaa6f93fae1c139c3aa3
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue Feb 9 17:53:28 2021 +0100

    RFC 3986 conformance: BasicHttpRequest to support parsing of valid URI authority components not recognized by java.net.URI
---
 .../hc/core5/http/message/BasicHttpRequest.java    | 22 +++++++++++++++-------
 .../hc/core5/http/message/TestBasicMessages.java   | 13 +++++++++++--
 2 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
index 17742de..d83a83e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
@@ -27,9 +27,6 @@
 
 package org.apache.hc.core5.http.message;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Method;
@@ -39,6 +36,9 @@ import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TextUtils;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
 /**
  * Basic implementation of {@link HttpRequest}.
  *
@@ -223,10 +223,18 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
     @Override
     public void setUri(final URI requestUri) {
         this.scheme = requestUri.getScheme();
-        this.authority = requestUri.getHost() != null ? new URIAuthority(
-                requestUri.getRawUserInfo(),
-                requestUri.getHost(),
-                requestUri.getPort()) : null;
+        if (requestUri.getHost() != null) {
+            this.authority = new URIAuthority(
+                    requestUri.getRawUserInfo(), requestUri.getHost(), requestUri.getPort());
+        } else if (requestUri.getRawAuthority() != null) {
+            try {
+                this.authority = URIAuthority.create(requestUri.getRawAuthority());
+            } catch (final URISyntaxException ignore) {
+                this.authority = null;
+            }
+        } else {
+            this.authority = null;
+        }
         final StringBuilder buf = new StringBuilder();
         final String rawPath = requestUri.getRawPath();
         if (!TextUtils.isBlank(rawPath)) {
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
index 760bf8c..1b3937c 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
@@ -27,8 +27,6 @@
 
 package org.apache.hc.core5.http.message;
 
-import java.net.URI;
-
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
@@ -38,6 +36,8 @@ import org.apache.hc.core5.net.URIAuthority;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.net.URI;
+
 /**
  * Unit tests for {@link org.apache.hc.core5.http.HttpMessage}.
  *
@@ -205,5 +205,14 @@ public class TestBasicMessages {
         Assert.assertEquals(new URI("http://somehost/stuff"), request.getUri());
     }
 
+    @Test
+    public void testRequestHostWithReservedChars() throws Exception {
+        final HttpRequest request = new BasicHttpRequest(Method.GET, URI.create("http://someuser%21@%21example%21.com/stuff"));
+        Assert.assertEquals(Method.GET.name(), request.getMethod());
+        Assert.assertEquals("/stuff", request.getPath());
+        Assert.assertEquals(new URIAuthority("someuser%21", "%21example%21.com", -1), request.getAuthority());
+        Assert.assertEquals(new URI("http://%21example%21.com/stuff"), request.getUri());
+    }
+
 }
 


[httpcomponents-core] 04/10: RFC 3986 conformance: BasicHttpRequest to reject requests whose path component begins with multiple slashes

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 1614d5d5a5de6f4faadff9ecb566982d56b65179
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue Feb 9 17:53:34 2021 +0100

    RFC 3986 conformance: BasicHttpRequest to reject requests whose path component begins with multiple slashes
---
 .../org/apache/hc/core5/testing/framework/TestTestingFramework.java  | 2 +-
 .../main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java | 4 ++++
 .../java/org/apache/hc/core5/http/message/TestBasicMessages.java     | 5 +++++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java
index a3abfcd..1501bd5 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java
@@ -1029,7 +1029,7 @@ public class TestTestingFramework {
         final Map<String, Object> request = new HashMap<>();
         test.put(REQUEST, request);
 
-        request.put(PATH, "/stuff");
+        request.put(PATH, "stuff");
 
         final Map<String, Object> queryMap = new HashMap<>();
         request.put(QUERY, queryMap);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
index d83a83e..ac93392 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
@@ -189,6 +189,9 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
 
     @Override
     public void setPath(final String path) {
+        if (path != null) {
+            Args.check(!path.startsWith("//"), "URI path begins with multiple slashes");
+        }
         this.path = path;
         this.requestUri = null;
     }
@@ -238,6 +241,7 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
         final StringBuilder buf = new StringBuilder();
         final String rawPath = requestUri.getRawPath();
         if (!TextUtils.isBlank(rawPath)) {
+            Args.check(!rawPath.startsWith("//"), "URI path begins with multiple slashes");
             buf.append(rawPath);
         } else {
             buf.append("/");
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
index 1b3937c..86d3c96 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
@@ -214,5 +214,10 @@ public class TestBasicMessages {
         Assert.assertEquals(new URI("http://%21example%21.com/stuff"), request.getUri());
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testRequestPathWithMultipleLeadingSlashes() throws Exception {
+        new BasicHttpRequest(Method.GET, URI.create("http://host//stuff"));
+    }
+
 }
 


[httpcomponents-core] 10/10: * Add charset constant * Add Content Type

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit e6b09bf3291dcf4c56e0aec20ccb436140bc7768
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Sat Feb 13 19:37:07 2021 +0100

    * Add charset constant
    * Add Content Type
---
 .../java/org/apache/hc/core5/http/ContentType.java | 68 ++++++++++++++++++++--
 1 file changed, 63 insertions(+), 5 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
index dac2a58..08da33f 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
@@ -63,6 +63,11 @@ public final class ContentType implements Serializable {
 
     private static final long serialVersionUID = -7768694718232371896L;
 
+    /**
+     * Param that represent {@code charset} constant.
+     */
+    private static final String CHARSET = "charset";
+
     // constants
     public static final ContentType APPLICATION_ATOM_XML = create(
             "application/atom+xml", StandardCharsets.UTF_8);
@@ -70,8 +75,23 @@ public final class ContentType implements Serializable {
             "application/x-www-form-urlencoded", StandardCharsets.ISO_8859_1);
     public static final ContentType APPLICATION_JSON = create(
             "application/json", StandardCharsets.UTF_8);
+
+    /**
+     * Public constant media type for {@code application/x-ndjson}.
+     * @since 5.1
+     */
+    public static final ContentType APPLICATION_NDJSON = create(
+            "application/x-ndjson", StandardCharsets.UTF_8);
+
     public static final ContentType APPLICATION_OCTET_STREAM = create(
             "application/octet-stream", (Charset) null);
+    /**
+     * Public constant media type for {@code application/pdf}.
+     * @since 5.1
+     */
+    public static final ContentType APPLICATION_PDF = create(
+            "application/pdf", StandardCharsets.UTF_8);
+
     public static final ContentType APPLICATION_SOAP_XML = create(
             "application/soap+xml", StandardCharsets.UTF_8);
     public static final ContentType APPLICATION_SVG_XML = create(
@@ -87,6 +107,21 @@ public final class ContentType implements Serializable {
      */
     public static final ContentType APPLICATION_PROBLEM_JSON = create(
             "application/problem+json", StandardCharsets.UTF_8);
+    /**
+     * Public constant media type for {@code application/problem+xml}.
+     * @see <a href="https://tools.ietf.org/html/rfc7807#section-6.2">Problem Details for HTTP APIs, 6.2. application/problem+xml</a>
+     * @since 5.1
+     */
+    public static final ContentType APPLICATION_PROBLEM_XML = create(
+            "application/problem+xml", StandardCharsets.UTF_8);
+
+    /**
+     * Public constant media type for {@code application/rss+xml}.
+     * @since 5.1
+     */
+    public static final ContentType APPLICATION_RSS_XML = create(
+            "application/rss+xml", StandardCharsets.UTF_8);
+
     public static final ContentType IMAGE_BMP = create(
             "image/bmp");
     public static final ContentType IMAGE_GIF = create(
@@ -103,8 +138,31 @@ public final class ContentType implements Serializable {
             "image/webp");
     public static final ContentType MULTIPART_FORM_DATA = create(
             "multipart/form-data", StandardCharsets.ISO_8859_1);
+
+    /**
+     * Public constant media type for {@code multipart/mixed}.
+     * @since 5.1
+     */
+    public static final ContentType MULTIPART_MIXED = create(
+            "multipart/mixed", StandardCharsets.ISO_8859_1);
+
+    /**
+     * Public constant media type for {@code multipart/related}.
+     * @since 5.1
+     */
+    public static final ContentType MULTIPART_RELATED = create(
+            "multipart/related", StandardCharsets.ISO_8859_1);
+
     public static final ContentType TEXT_HTML = create(
             "text/html", StandardCharsets.ISO_8859_1);
+
+    /**
+     * Public constant media type for {@code text/markdown}.
+     * @since 5.1
+     */
+    public static final ContentType TEXT_MARKDOWN = create(
+            "text/markdown", StandardCharsets.UTF_8);
+
     public static final ContentType TEXT_PLAIN = create(
             "text/plain", StandardCharsets.ISO_8859_1);
     public static final ContentType TEXT_XML = create(
@@ -114,7 +172,8 @@ public final class ContentType implements Serializable {
      * @see <a href="https://www.w3.org/TR/eventsource/">Server-Sent Events W3C recommendation</a>
      * @since 5.1
      */
-    public static final String TEXT_EVENT_STREAM = "text/event-stream";
+    public static final ContentType TEXT_EVENT_STREAM = create(
+            "text/event-stream", StandardCharsets.UTF_8);
 
     public static final ContentType WILDCARD = create(
             "*/*", (Charset) null);
@@ -124,7 +183,6 @@ public final class ContentType implements Serializable {
      */
     private static final NameValuePair[] EMPTY_NAME_VALUE_PAIR_ARRAY = new NameValuePair[0];
 
-
     /**
      * @deprecated To be removed in 6.0
      */
@@ -287,7 +345,7 @@ public final class ContentType implements Serializable {
         Charset charset = null;
         if (params != null) {
             for (final NameValuePair param : params) {
-                if (param.getName().equalsIgnoreCase("charset")) {
+                if (param.getName().equalsIgnoreCase(CHARSET)) {
                     final String s = param.getValue();
                     if (!TextUtils.isBlank(s)) {
                         try {
@@ -424,8 +482,8 @@ public final class ContentType implements Serializable {
             paramMap.put(param.getName(), param.getValue());
         }
         final List<NameValuePair> newParams = new ArrayList<>(paramMap.size() + 1);
-        if (this.charset != null && !paramMap.containsKey("charset")) {
-            newParams.add(new BasicNameValuePair("charset", this.charset.name()));
+        if (this.charset != null && !paramMap.containsKey(CHARSET)) {
+            newParams.add(new BasicNameValuePair(CHARSET, this.charset.name()));
         }
         for (final Map.Entry<String, String> entry: paramMap.entrySet()) {
             newParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));


[httpcomponents-core] 08/10: Basic and classic message builders to support copy operation

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 94e751caf3e8280bbff094b3096e513339017217
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue Feb 9 17:53:53 2021 +0100

    Basic and classic message builders to support copy operation
---
 .../http/io/support/ClassicRequestBuilder.java     |  56 ++++++++++--
 .../http/io/support/ClassicResponseBuilder.java    |  15 ++++
 .../http/message/BasicClassicHttpRequest.java      |  19 +++-
 .../hc/core5/http/message/BasicHttpRequest.java    |  18 ++++
 .../http/nio/support/AsyncRequestBuilder.java      |  41 +++++++--
 .../core5/http/support/AbstractMessageBuilder.java |  24 ++++-
 .../core5/http/support/AbstractRequestBuilder.java | 100 +++++++++++++++++++--
 .../hc/core5/http/support/BasicRequestBuilder.java |  42 +++++++--
 .../core5/http/support/BasicResponseBuilder.java   |   8 ++
 .../http/support/TestBasicMessageBuilders.java     |  46 +++++++++-
 10 files changed, 335 insertions(+), 34 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
index cd8835b..24873c9 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
@@ -39,8 +39,10 @@ import org.apache.hc.core5.http.io.entity.HttpEntities;
 import org.apache.hc.core5.http.io.entity.StringEntity;
 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
 import org.apache.hc.core5.http.support.AbstractRequestBuilder;
+import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.net.URIBuilder;
 import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.TextUtils;
 
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -189,6 +191,21 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
         return new ClassicRequestBuilder(Method.OPTIONS, uri);
     }
 
+    /**
+     * @since 5.1
+     */
+    public static ClassicRequestBuilder copy(final ClassicHttpRequest request) {
+        Args.notNull(request, "HTTP request");
+        final ClassicRequestBuilder builder = new ClassicRequestBuilder(request.getMethod());
+        builder.digest(request);
+        return builder;
+    }
+
+    protected void digest(final ClassicHttpRequest request) {
+        super.digest(request);
+        setEntity(request.getEntity());
+    }
+
     @Override
     public ClassicRequestBuilder setVersion(final ProtocolVersion version) {
         super.setVersion(version);
@@ -208,6 +225,24 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
     }
 
     @Override
+    public ClassicRequestBuilder setScheme(final String scheme) {
+        super.setScheme(scheme);
+        return this;
+    }
+
+    @Override
+    public ClassicRequestBuilder setAuthority(final URIAuthority authority) {
+        super.setAuthority(authority);
+        return this;
+    }
+
+    @Override
+    public ClassicRequestBuilder setPath(final String path) {
+        super.setPath(path);
+        return this;
+    }
+
+    @Override
     public ClassicRequestBuilder setHeaders(final Header... headers) {
         super.setHeaders(headers);
         return this;
@@ -304,9 +339,9 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
     }
 
     public ClassicHttpRequest build() {
-        URI uriCopy = getUri();
-        if (uriCopy == null) {
-            uriCopy = URI.create("/");
+        String path = getPath();
+        if (TextUtils.isEmpty(path)) {
+            path = "/";
         }
         HttpEntity entityCopy = this.entity;
         final String method = getMethod();
@@ -316,10 +351,11 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
                 entityCopy = HttpEntities.createUrlEncoded(parameters, getCharset());
             } else {
                 try {
-                    uriCopy = new URIBuilder(uriCopy)
+                    final URI uri = new URIBuilder(path)
                             .setCharset(getCharset())
                             .addParameters(parameters)
                             .build();
+                    path = uri.toASCIIString();
                 } catch (final URISyntaxException ex) {
                     // should never happen
                 }
@@ -330,7 +366,7 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
             throw new IllegalStateException(Method.TRACE + " requests may not include an entity");
         }
 
-        final BasicClassicHttpRequest result = new BasicClassicHttpRequest(method, uriCopy);
+        final BasicClassicHttpRequest result = new BasicClassicHttpRequest(method, getScheme(), getAuthority(), path);
         result.setVersion(getVersion());
         result.setHeaders(getHeaders());
         result.setEntity(entityCopy);
@@ -343,10 +379,12 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
         final StringBuilder builder = new StringBuilder();
         builder.append("ClassicRequestBuilder [method=");
         builder.append(getMethod());
-        builder.append(", version=");
-        builder.append(getVersion());
-        builder.append(", uri=");
-        builder.append(getUri());
+        builder.append(", scheme=");
+        builder.append(getScheme());
+        builder.append(", authority=");
+        builder.append(getAuthority());
+        builder.append(", path=");
+        builder.append(getPath());
         builder.append(", parameters=");
         builder.append(getParameters());
         builder.append(", headerGroup=");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
index ce6d7bf..9dd337a 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
@@ -58,6 +58,21 @@ public class ClassicResponseBuilder extends AbstractResponseBuilder<ClassicHttpR
         return new ClassicResponseBuilder(status);
     }
 
+    /**
+     * @since 5.1
+     */
+    public static ClassicResponseBuilder copy(final ClassicHttpResponse response) {
+        Args.notNull(response, "HTTP response");
+        final ClassicResponseBuilder builder = new ClassicResponseBuilder(response.getCode());
+        builder.digest(response);
+        return builder;
+    }
+
+    protected void digest(final ClassicHttpResponse response) {
+        super.digest(response);
+        setEntity(response.getEntity());
+    }
+
     @Override
     public ClassicResponseBuilder setVersion(final ProtocolVersion version) {
         super.setVersion(version);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicClassicHttpRequest.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicClassicHttpRequest.java
index 7038c17..deea4fd 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicClassicHttpRequest.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicClassicHttpRequest.java
@@ -27,12 +27,13 @@
 
 package org.apache.hc.core5.http.message;
 
-import java.net.URI;
-
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.Method;
+import org.apache.hc.core5.net.URIAuthority;
+
+import java.net.URI;
 
 /**
  * Basic implementation of {@link ClassicHttpRequest}.
@@ -46,6 +47,20 @@ public class BasicClassicHttpRequest extends BasicHttpRequest implements Classic
     private HttpEntity entity;
 
     /**
+     * Creates request message with the given method, host and request path.
+     *
+     * @param method request method.
+     * @param scheme request scheme.
+     * @param authority request authority.
+     * @param path request path.
+     *
+     * @since 5.1
+     */
+    public BasicClassicHttpRequest(final String method, final String scheme, final URIAuthority authority, final String path) {
+        super(method, scheme, authority, path);
+    }
+
+    /**
      * Creates request message with the given method and request path.
      *
      * @param method request method.
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
index ed94598..5b1db70 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
@@ -57,6 +57,24 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
     private boolean absoluteRequestUri;
 
     /**
+     * Creates request message with the given method, host and request path.
+     *
+     * @param method request method.
+     * @param scheme request scheme.
+     * @param authority request authority.
+     * @param path request path.
+     *
+     * @since 5.1
+     */
+    public BasicHttpRequest(final String method, final String scheme, final URIAuthority authority, final String path) {
+        super();
+        this.method = Args.notNull(method, "Method name");
+        this.scheme = scheme;
+        this.authority = authority;
+        this.path = path;
+    }
+
+    /**
      * Creates request message with the given method and request path.
      *
      * @param method request method.
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
index 52212b6..3093081 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
@@ -44,9 +44,11 @@ import org.apache.hc.core5.http.nio.AsyncRequestProducer;
 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
 import org.apache.hc.core5.http.support.AbstractRequestBuilder;
+import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.net.URIBuilder;
 import org.apache.hc.core5.net.WWWFormCodec;
 import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.TextUtils;
 
 /**
  * Builder for {@link AsyncRequestProducer} instances.
@@ -208,6 +210,24 @@ public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProd
     }
 
     @Override
+    public AsyncRequestBuilder setScheme(final String scheme) {
+        super.setScheme(scheme);
+        return this;
+    }
+
+    @Override
+    public AsyncRequestBuilder setAuthority(final URIAuthority authority) {
+        super.setAuthority(authority);
+        return this;
+    }
+
+    @Override
+    public AsyncRequestBuilder setPath(final String path) {
+        super.setPath(path);
+        return this;
+    }
+
+    @Override
     public AsyncRequestBuilder setHeaders(final Header... headers) {
         super.setHeaders(headers);
         return this;
@@ -304,9 +324,9 @@ public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProd
     }
 
     public AsyncRequestProducer build() {
-        URI uriCopy = getUri();
-        if (uriCopy == null) {
-            uriCopy = URI.create("/");
+        String path = getPath();
+        if (TextUtils.isEmpty(path)) {
+            path = "/";
         }
         AsyncEntityProducer entityProducerCopy = entityProducer;
         final String method = getMethod();
@@ -322,10 +342,11 @@ public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProd
                         ContentType.APPLICATION_FORM_URLENCODED);
             } else {
                 try {
-                    uriCopy = new URIBuilder(uriCopy)
+                    final URI uri = new URIBuilder(path)
                             .setCharset(charset)
                             .addParameters(parameters)
                             .build();
+                    path = uri.toASCIIString();
                 } catch (final URISyntaxException ex) {
                     // should never happen
                 }
@@ -336,7 +357,7 @@ public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProd
             throw new IllegalStateException(Method.TRACE + " requests may not include an entity");
         }
 
-        final BasicHttpRequest request = new BasicHttpRequest(method, uriCopy);
+        final BasicHttpRequest request = new BasicHttpRequest(method, getScheme(), getAuthority(), path);
         request.setVersion(getVersion());
         request.setHeaders(getHeaders());
         request.setAbsoluteRequestUri(isAbsoluteRequestUri());
@@ -348,10 +369,12 @@ public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProd
         final StringBuilder builder = new StringBuilder();
         builder.append("AsyncRequestBuilder [method=");
         builder.append(getMethod());
-        builder.append(", version=");
-        builder.append(getVersion());
-        builder.append(", uri=");
-        builder.append(getUri());
+        builder.append(", scheme=");
+        builder.append(getScheme());
+        builder.append(", authority=");
+        builder.append(getAuthority());
+        builder.append(", path=");
+        builder.append(getPath());
         builder.append(", parameters=");
         builder.append(getParameters());
         builder.append(", headerGroup=");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractMessageBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractMessageBuilder.java
index 143c30c..006e6b5 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractMessageBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractMessageBuilder.java
@@ -27,14 +27,14 @@
 
 package org.apache.hc.core5.http.support;
 
+import java.util.Iterator;
+
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpMessage;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.HeaderGroup;
 
-import java.util.Iterator;
-
 /**
  * Abstract {@link HttpMessage} builder.
  *
@@ -48,6 +48,14 @@ public abstract class AbstractMessageBuilder<T> {
     protected AbstractMessageBuilder() {
     }
 
+    protected void digest(final HttpMessage message) {
+        if (message == null) {
+            return;
+        }
+        setVersion(message.getVersion());
+        setHeaders(message.headerIterator());
+    }
+
     public ProtocolVersion getVersion() {
         return version;
     }
@@ -73,6 +81,18 @@ public abstract class AbstractMessageBuilder<T> {
         return this;
     }
 
+    public AbstractMessageBuilder<T> setHeaders(final Iterator<Header> it) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        } else {
+            headerGroup.clear();
+        }
+        while (it.hasNext()) {
+            headerGroup.addHeader(it.next());
+        }
+        return this;
+    }
+
     public Header[] getFirstHeaders() {
         return headerGroup != null ? headerGroup.getHeaders() : null;
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
index 1aeb36e..3c47362 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
@@ -28,13 +28,18 @@
 package org.apache.hc.core5.http.support;
 
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Method;
 import org.apache.hc.core5.http.NameValuePair;
 import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.message.BasicNameValuePair;
+import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.util.TextUtils;
 
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -48,7 +53,9 @@ import java.util.List;
 public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T> {
 
     final private String method;
-    private URI uri;
+    private String scheme;
+    private URIAuthority authority;
+    private String path;
     private Charset charset;
     private List<NameValuePair> parameters;
     private boolean absoluteRequestUri;
@@ -65,7 +72,7 @@ public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T
     protected AbstractRequestBuilder(final String method, final URI uri) {
         super();
         this.method = method;
-        this.uri = uri;
+        setUri(uri);
     }
 
     protected AbstractRequestBuilder(final Method method, final URI uri) {
@@ -80,6 +87,17 @@ public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T
         this(method, uri != null ? URI.create(uri) : null);
     }
 
+    protected void digest(final HttpRequest request) {
+        if (request == null) {
+            return;
+        }
+        setScheme(request.getScheme());
+        setAuthority(request.getAuthority());
+        setPath(request.getPath());
+        this.parameters = null;
+        super.digest(request);
+    }
+
     public String getMethod() {
         return method;
     }
@@ -90,17 +108,89 @@ public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T
         return this;
     }
 
+    public String getScheme() {
+        return scheme;
+    }
+
+    public AbstractRequestBuilder<T> setScheme(final String scheme) {
+        this.scheme = scheme;
+        return this;
+    }
+
+    public URIAuthority getAuthority() {
+        return authority;
+    }
+
+    public AbstractRequestBuilder<T> setAuthority(final URIAuthority authority) {
+        this.authority = authority;
+        return this;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public AbstractRequestBuilder<T> setPath(final String path) {
+        this.path = path;
+        return this;
+    }
+
     public URI getUri() {
-        return uri;
+        final StringBuilder buf = new StringBuilder();
+        if (this.authority != null) {
+            buf.append(this.scheme != null ? this.scheme : URIScheme.HTTP.id).append("://");
+            buf.append(this.authority.getHostName());
+            if (this.authority.getPort() >= 0) {
+                buf.append(":").append(this.authority.getPort());
+            }
+        }
+        if (this.path == null) {
+            buf.append("/");
+        } else {
+            if (buf.length() > 0 && !this.path.startsWith("/")) {
+                buf.append("/");
+            }
+            buf.append(this.path);
+        }
+        return URI.create(buf.toString());
     }
 
     public AbstractRequestBuilder<T> setUri(final URI uri) {
-        this.uri = uri;
+        if (uri == null) {
+            this.scheme = null;
+            this.authority = null;
+            this.path = null;
+        } else {
+            this.scheme = uri.getScheme();
+            if (uri.getHost() != null) {
+                this.authority = new URIAuthority(uri.getRawUserInfo(), uri.getHost(), uri.getPort());
+            } else if (uri.getRawAuthority() != null) {
+                try {
+                    this.authority = URIAuthority.create(uri.getRawAuthority());
+                } catch (final URISyntaxException ignore) {
+                    this.authority = null;
+                }
+            } else {
+                this.authority = null;
+            }
+            final StringBuilder buf = new StringBuilder();
+            final String rawPath = uri.getRawPath();
+            if (!TextUtils.isBlank(rawPath)) {
+                buf.append(rawPath);
+            } else {
+                buf.append("/");
+            }
+            final String query = uri.getRawQuery();
+            if (query != null) {
+                buf.append('?').append(query);
+            }
+            this.path = buf.toString();
+        }
         return this;
     }
 
     public AbstractRequestBuilder<T> setUri(final String uri) {
-        this.uri = uri != null ? URI.create(uri) : null;
+        setUri(uri != null ? URI.create(uri) : null);
         return this;
     }
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
index 74d3001..adc94b7 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
@@ -34,10 +34,12 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Method;
 import org.apache.hc.core5.http.NameValuePair;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.net.URIBuilder;
 import org.apache.hc.core5.util.Args;
 
@@ -173,6 +175,13 @@ public class BasicRequestBuilder extends AbstractRequestBuilder<BasicHttpRequest
         return new BasicRequestBuilder(Method.OPTIONS, uri);
     }
 
+    public static BasicRequestBuilder copy(final HttpRequest request) {
+        Args.notNull(request, "HTTP request");
+        final BasicRequestBuilder builder = new BasicRequestBuilder(request.getMethod());
+        builder.digest(request);
+        return builder;
+    }
+
     @Override
     public BasicRequestBuilder setVersion(final ProtocolVersion version) {
         super.setVersion(version);
@@ -192,6 +201,24 @@ public class BasicRequestBuilder extends AbstractRequestBuilder<BasicHttpRequest
     }
 
     @Override
+    public BasicRequestBuilder setScheme(final String scheme) {
+        super.setScheme(scheme);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setAuthority(final URIAuthority authority) {
+        super.setAuthority(authority);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setPath(final String path) {
+        super.setPath(path);
+        return this;
+    }
+
+    @Override
     public BasicRequestBuilder setHeaders(final Header... headers) {
         super.setHeaders(headers);
         return this;
@@ -265,19 +292,20 @@ public class BasicRequestBuilder extends AbstractRequestBuilder<BasicHttpRequest
 
     @Override
     public BasicHttpRequest build() {
-        URI uri = getUri();
+        String path = getPath();
         final List<NameValuePair> parameters = getParameters();
         if (parameters != null && !parameters.isEmpty()) {
             try {
-                uri = new URIBuilder(uri)
+                final URI uri = new URIBuilder(path)
                         .setCharset(getCharset())
                         .addParameters(parameters)
                         .build();
+                path = uri.toASCIIString();
             } catch (final URISyntaxException ex) {
                 // should never happen
             }
         }
-        final BasicHttpRequest result = new BasicHttpRequest(getMethod(), uri != null ? uri : URI.create("/"));
+        final BasicHttpRequest result = new BasicHttpRequest(getMethod(), getScheme(), getAuthority(), path);
         result.setVersion(getVersion());
         result.setHeaders(getHeaders());
         result.setAbsoluteRequestUri(isAbsoluteRequestUri());
@@ -289,8 +317,12 @@ public class BasicRequestBuilder extends AbstractRequestBuilder<BasicHttpRequest
         final StringBuilder builder = new StringBuilder();
         builder.append("BasicRequestBuilder [method=");
         builder.append(getMethod());
-        builder.append(", uri=");
-        builder.append(getUri());
+        builder.append(", scheme=");
+        builder.append(getScheme());
+        builder.append(", authority=");
+        builder.append(getAuthority());
+        builder.append(", path=");
+        builder.append(getPath());
         builder.append(", parameters=");
         builder.append(getParameters());
         builder.append(", headerGroup=");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicResponseBuilder.java
index de6baa3..39ebf65 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicResponseBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicResponseBuilder.java
@@ -28,6 +28,7 @@
 package org.apache.hc.core5.http.support;
 
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
 import org.apache.hc.core5.util.Args;
@@ -50,6 +51,13 @@ public class BasicResponseBuilder extends AbstractResponseBuilder<BasicHttpRespo
         return new BasicResponseBuilder(status);
     }
 
+    public static BasicResponseBuilder copy(final HttpResponse response) {
+        Args.notNull(response, "HTTP response");
+        final BasicResponseBuilder builder = new BasicResponseBuilder(response.getCode());
+        builder.digest(response);
+        return builder;
+    }
+
     @Override
     public BasicResponseBuilder setVersion(final ProtocolVersion version) {
         super.setVersion(version);
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/support/TestBasicMessageBuilders.java b/httpcore5/src/test/java/org/apache/hc/core5/http/support/TestBasicMessageBuilders.java
index b4f7923..152ad6e 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/support/TestBasicMessageBuilders.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/support/TestBasicMessageBuilders.java
@@ -29,7 +29,10 @@ package org.apache.hc.core5.http.support;
 
 import org.apache.hc.core5.http.HeaderMatcher;
 import org.apache.hc.core5.http.HeadersMatcher;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.Method;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
@@ -109,8 +112,11 @@ public class TestBasicMessageBuilders {
     @Test
     public void testRequestBasics() throws Exception {
         final BasicRequestBuilder builder = BasicRequestBuilder.get();
-        Assert.assertNull(builder.getUri());
+        Assert.assertEquals(URI.create("/"), builder.getUri());
         Assert.assertEquals("GET", builder.getMethod());
+        Assert.assertNull(builder.getScheme());
+        Assert.assertNull(builder.getAuthority());
+        Assert.assertNull(builder.getPath());
         Assert.assertNull(builder.getHeaders());
         Assert.assertNull(builder.getVersion());
         Assert.assertNull(builder.getCharset());
@@ -121,12 +127,15 @@ public class TestBasicMessageBuilders {
         Assert.assertEquals("GET", r1.getMethod());
         Assert.assertNull(r1.getScheme());
         Assert.assertNull(r1.getAuthority());
-        Assert.assertEquals("/", r1.getPath());
+        Assert.assertNull(r1.getPath());
         Assert.assertEquals(URI.create("/"), r1.getUri());
         Assert.assertNull(r1.getVersion());
 
         builder.setUri(URI.create("http://host:1234/blah?param=value"));
         builder.setVersion(HttpVersion.HTTP_1_1);
+        Assert.assertEquals("http", builder.getScheme());
+        Assert.assertEquals(new URIAuthority("host", 1234), builder.getAuthority());
+        Assert.assertEquals("/blah?param=value", builder.getPath());
         Assert.assertEquals(URI.create("http://host:1234/blah?param=value"), builder.getUri());
         Assert.assertEquals(HttpVersion.HTTP_1_1, builder.getVersion());
 
@@ -194,4 +203,37 @@ public class TestBasicMessageBuilders {
         MatcherAssert.assertThat(r6.getHeaders(), HeadersMatcher.same(new BasicHeader("h2", "v2")));
     }
 
+    @Test
+    public void testResponseCopy() throws Exception {
+        final HttpResponse response = new BasicHttpResponse(400);
+        response.addHeader("h1", "v1");
+        response.addHeader("h1", "v2");
+        response.addHeader("h2", "v2");
+        response.setVersion(HttpVersion.HTTP_2);
+
+        final BasicResponseBuilder builder = BasicResponseBuilder.copy(response);
+        Assert.assertEquals(400, builder.getStatus());
+        Assert.assertEquals(HttpVersion.HTTP_2, builder.getVersion());
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2"), new BasicHeader("h2", "v2")));
+    }
+
+    @Test
+    public void testRequestCopy() throws Exception {
+        final HttpRequest request = new BasicHttpRequest(Method.GET, URI.create("https://host:3456/stuff?blah")) ;
+        request.addHeader("h1", "v1");
+        request.addHeader("h1", "v2");
+        request.addHeader("h2", "v2");
+        request.setVersion(HttpVersion.HTTP_2);
+
+        final BasicRequestBuilder builder = BasicRequestBuilder.copy(request);
+        Assert.assertEquals("GET", builder.getMethod());
+        Assert.assertEquals("https", builder.getScheme());
+        Assert.assertEquals(new URIAuthority("host", 3456), builder.getAuthority());
+        Assert.assertEquals("/stuff?blah", builder.getPath());
+        Assert.assertEquals(HttpVersion.HTTP_2, builder.getVersion());
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2"), new BasicHeader("h2", "v2")));
+    }
+
 }


[httpcomponents-core] 09/10: HTTPCORE-668 - W3C recommendation text/event-stream

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 35c1541c098b30da5a0a37e73006db77c07dc022
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Fri Feb 12 20:41:21 2021 +0100

    HTTPCORE-668 - W3C recommendation text/event-stream
---
 httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
index 44419db..dac2a58 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
@@ -109,6 +109,13 @@ public final class ContentType implements Serializable {
             "text/plain", StandardCharsets.ISO_8859_1);
     public static final ContentType TEXT_XML = create(
             "text/xml", StandardCharsets.UTF_8);
+    /**
+     * Public constant media type for {@code text/event-stream}.
+     * @see <a href="https://www.w3.org/TR/eventsource/">Server-Sent Events W3C recommendation</a>
+     * @since 5.1
+     */
+    public static final String TEXT_EVENT_STREAM = "text/event-stream";
+
     public static final ContentType WILDCARD = create(
             "*/*", (Charset) null);
 


[httpcomponents-core] 07/10: HTTPCORE-667 - Add new Content Type application/problem+json

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit b7d3e2694ad7942ea8a50ff9465bed9f8deb4688
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Fri Feb 12 08:06:25 2021 +0100

    HTTPCORE-667 - Add new Content Type application/problem+json
---
 httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
index e2bd0f6..44419db 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
@@ -80,6 +80,13 @@ public final class ContentType implements Serializable {
             "application/xhtml+xml", StandardCharsets.UTF_8);
     public static final ContentType APPLICATION_XML = create(
             "application/xml", StandardCharsets.UTF_8);
+    /**
+     * Public constant media type for {@code application/problem+json}.
+     * @see <a href="https://tools.ietf.org/html/rfc7807#section-6.1">Problem Details for HTTP APIs, 6.1. application/problem+json</a>
+     * @since 5.1
+     */
+    public static final ContentType APPLICATION_PROBLEM_JSON = create(
+            "application/problem+json", StandardCharsets.UTF_8);
     public static final ContentType IMAGE_BMP = create(
             "image/bmp");
     public static final ContentType IMAGE_GIF = create(


[httpcomponents-core] 06/10: Minor Improvements:

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 6d7debde616235d81906b00d30601fe464eb8046
Author: Arturo Bernal <ar...@gmail.com>
AuthorDate: Wed Feb 10 08:07:23 2021 +0100

    Minor Improvements:
    
    * Unnecessary boxing
    * Unnecessary unboxing
    * inline variable
    * Change PosixParser to  DefaultParser
---
 .../hc/core5/http2/impl/nio/ClientHttpProtocolNegotiator.java     | 4 +---
 .../hc/core5/http2/impl/nio/H2OnlyClientProtocolNegotiator.java   | 4 +---
 .../main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java    | 4 ++--
 .../org/apache/hc/core5/http/support/AbstractRequestBuilder.java  | 2 +-
 .../src/main/java/org/apache/hc/core5/pool/StrictConnPool.java    | 4 ++--
 httpcore5/src/main/java/org/apache/hc/core5/util/Args.java        | 8 ++++----
 6 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttpProtocolNegotiator.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttpProtocolNegotiator.java
index 9e1cb7c..a1a7f4b 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttpProtocolNegotiator.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ClientHttpProtocolNegotiator.java
@@ -29,7 +29,6 @@ package org.apache.hc.core5.http2.impl.nio;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.channels.ByteChannel;
 import java.nio.channels.SelectionKey;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -133,8 +132,7 @@ public class ClientHttpProtocolNegotiator extends ProtocolNegotiatorBase {
 
     private void writeOutPreface(final IOSession session) throws IOException {
         if (preface.hasRemaining()) {
-            final ByteChannel channel = session;
-            channel.write(preface);
+            session.write(preface);
         }
         if (!preface.hasRemaining()) {
             session.clearEvent(SelectionKey.OP_WRITE);
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/H2OnlyClientProtocolNegotiator.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/H2OnlyClientProtocolNegotiator.java
index 1a14b3c..a4f7df5 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/H2OnlyClientProtocolNegotiator.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/H2OnlyClientProtocolNegotiator.java
@@ -29,7 +29,6 @@ package org.apache.hc.core5.http2.impl.nio;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.channels.ByteChannel;
 import java.nio.channels.SelectionKey;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -99,8 +98,7 @@ public class H2OnlyClientProtocolNegotiator extends ProtocolNegotiatorBase {
 
     private void writeOutPreface(final IOSession session) throws IOException  {
         if (preface.hasRemaining()) {
-            final ByteChannel channel = session;
-            channel.write(preface);
+            session.write(preface);
         }
         if (!preface.hasRemaining()) {
             session.clearEvent(SelectionKey.OP_WRITE);
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
index c3141b8..e968468 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
@@ -44,8 +44,8 @@ import javax.net.ssl.SSLContext;
 
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Options;
-import org.apache.commons.cli.PosixParser;
 import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpConnection;
@@ -92,7 +92,7 @@ public class HttpBenchmark {
     public static void main(final String[] args) throws Exception {
 
         final Options options = CommandLineUtils.getOptions();
-        final CommandLineParser parser = new PosixParser();
+        final CommandLineParser parser = new DefaultParser();
         final CommandLine cmd = parser.parse(options, args);
 
         if (args.length == 0 || cmd.hasOption('h') || cmd.getArgs().length != 1) {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
index e01e439..1aeb36e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
@@ -47,7 +47,7 @@ import java.util.List;
  */
 public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T> {
 
-    private String method;
+    final private String method;
     private URI uri;
     private Charset charset;
     private List<NameValuePair> parameters;
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java b/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java
index dfd5b36..a222bd8 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/pool/StrictConnPool.java
@@ -422,7 +422,7 @@ public class StrictConnPool<T, C extends ModalCloseable> implements ManagedConnP
     private int getMax(final T route) {
         final Integer v = this.maxPerRoute.get(route);
         if (v != null) {
-            return v.intValue();
+            return v;
         }
         return this.defaultMaxPerRoute;
     }
@@ -475,7 +475,7 @@ public class StrictConnPool<T, C extends ModalCloseable> implements ManagedConnP
         this.lock.lock();
         try {
             if (max > -1) {
-                this.maxPerRoute.put(route, Integer.valueOf(max));
+                this.maxPerRoute.put(route, max);
             } else {
                 this.maxPerRoute.remove(route);
             }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/util/Args.java b/httpcore5/src/main/java/org/apache/hc/core5/util/Args.java
index 5270a1e..25bc011 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/util/Args.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/util/Args.java
@@ -62,8 +62,8 @@ public class Args {
     public static int checkRange(final int value, final int lowInclusive, final int highInclusive,
                     final String message) {
         if (value < lowInclusive || value > highInclusive) {
-            throw illegalArgumentException("%s: %d is out of range [%d, %d]", message, Integer.valueOf(value),
-                            Integer.valueOf(lowInclusive), Integer.valueOf(highInclusive));
+            throw illegalArgumentException("%s: %d is out of range [%d, %d]", message, value,
+                    lowInclusive, highInclusive);
         }
         return value;
     }
@@ -71,8 +71,8 @@ public class Args {
     public static long checkRange(final long value, final long lowInclusive, final long highInclusive,
                     final String message) {
         if (value < lowInclusive || value > highInclusive) {
-            throw illegalArgumentException("%s: %d is out of range [%d, %d]", message, Long.valueOf(value),
-                            Long.valueOf(lowInclusive), Long.valueOf(highInclusive));
+            throw illegalArgumentException("%s: %d is out of range [%d, %d]", message, value,
+                    lowInclusive, highInclusive);
         }
         return value;
     }


[httpcomponents-core] 02/10: Improved message builder support

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit fcfdfd3574327784d66bc045616872b6fcfd07c3
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue Feb 9 17:53:22 2021 +0100

    Improved message builder support
---
 .../http/io/support/ClassicRequestBuilder.java     | 216 ++++++---------
 .../http/io/support/ClassicResponseBuilder.java    | 103 ++-----
 .../core5/http/nio/support/AsyncPushBuilder.java   |  94 +++----
 .../http/nio/support/AsyncRequestBuilder.java      | 182 ++++---------
 .../http/nio/support/AsyncResponseBuilder.java     | 103 ++-----
 .../core5/http/support/AbstractMessageBuilder.java | 143 ++++++++++
 .../core5/http/support/AbstractRequestBuilder.java | 183 +++++++++++++
 .../http/support/AbstractResponseBuilder.java      | 106 ++++++++
 .../hc/core5/http/support/BasicRequestBuilder.java | 295 +++++++++++++++++++++
 .../core5/http/support/BasicResponseBuilder.java   | 120 +++++++++
 .../org/apache/hc/core5/http/HeaderMatcher.java    |  66 +++++
 .../org/apache/hc/core5/http/HeadersMatcher.java   |  72 +++++
 .../http/support/TestBasicMessageBuilders.java     | 197 ++++++++++++++
 13 files changed, 1398 insertions(+), 482 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
index fd621ed..5c407f5 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
@@ -27,19 +27,10 @@
 
 package org.apache.hc.core5.http.io.support;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpEntity;
-import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.Method;
 import org.apache.hc.core5.http.NameValuePair;
 import org.apache.hc.core5.http.ProtocolVersion;
@@ -47,12 +38,16 @@ import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
 import org.apache.hc.core5.http.io.entity.HttpEntities;
 import org.apache.hc.core5.http.io.entity.StringEntity;
 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
-import org.apache.hc.core5.http.message.BasicHeader;
-import org.apache.hc.core5.http.message.BasicNameValuePair;
-import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.http.support.AbstractRequestBuilder;
 import org.apache.hc.core5.net.URIBuilder;
 import org.apache.hc.core5.util.Args;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Builder for {@link ClassicHttpRequest} instances.
  * <p>
@@ -65,44 +60,32 @@ import org.apache.hc.core5.util.Args;
  *
  * @since 5.0
  */
-public class ClassicRequestBuilder {
+public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpRequest> {
 
-    private String method;
-    private URI uri;
-    private Charset charset;
-    private ProtocolVersion version;
-    private HeaderGroup headerGroup;
     private HttpEntity entity;
-    private List<NameValuePair> parameters;
-
-    ClassicRequestBuilder() {
-    }
 
     ClassicRequestBuilder(final String method) {
-        super();
-        this.method = method;
+        super(method);
     }
 
     ClassicRequestBuilder(final Method method) {
-        this(method.name());
+        super(method);
     }
 
     ClassicRequestBuilder(final String method, final URI uri) {
-        super();
-        this.method = method;
-        this.uri = uri;
+        super(method, uri);
     }
 
     ClassicRequestBuilder(final Method method, final URI uri) {
-        this(method.name(), uri);
+        super(method, uri);
     }
 
     ClassicRequestBuilder(final Method method, final String uri) {
-        this(method.name(), uri != null ? URI.create(uri) : null);
+        super(method, uri);
     }
 
     ClassicRequestBuilder(final String method, final String uri) {
-        this(method, uri != null ? URI.create(uri) : null);
+        super(method, uri);
     }
 
     public static ClassicRequestBuilder create(final String method) {
@@ -206,112 +189,87 @@ public class ClassicRequestBuilder {
         return new ClassicRequestBuilder(Method.OPTIONS, uri);
     }
 
-    public ClassicRequestBuilder setCharset(final Charset charset) {
-        this.charset = charset;
-        return this;
-    }
-
-    public Charset getCharset() {
-        return charset;
-    }
-
-    public String getMethod() {
-        return method;
-    }
-
-    public ProtocolVersion getVersion() {
-        return version;
-    }
-
+    @Override
     public ClassicRequestBuilder setVersion(final ProtocolVersion version) {
-        this.version = version;
+        super.setVersion(version);
         return this;
     }
 
-    public URI getUri() {
-        return uri;
-    }
-
+    @Override
     public ClassicRequestBuilder setUri(final URI uri) {
-        this.uri = uri;
+        super.setUri(uri);
         return this;
     }
 
+    @Override
     public ClassicRequestBuilder setUri(final String uri) {
-        this.uri = uri != null ? URI.create(uri) : null;
+        super.setUri(uri);
         return this;
     }
 
-    public Header[] getHeaders(final String name) {
-        return headerGroup != null ? headerGroup.getHeaders(name) : null;
-    }
-
+    @Override
     public ClassicRequestBuilder setHeaders(final Header... headers) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.setHeaders(headers);
+        super.setHeaders(headers);
         return this;
     }
 
-    public Header getFirstHeader(final String name) {
-        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
-    }
-
-    public Header getLastHeader(final String name) {
-        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
-    }
-
+    @Override
     public ClassicRequestBuilder addHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.addHeader(header);
+        super.addHeader(header);
         return this;
     }
 
+    @Override
     public ClassicRequestBuilder addHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.addHeader(new BasicHeader(name, value));
+        super.addHeader(name, value);
         return this;
     }
 
+    @Override
     public ClassicRequestBuilder removeHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.removeHeader(header);
+        super.removeHeader(header);
         return this;
     }
 
+    @Override
     public ClassicRequestBuilder removeHeaders(final String name) {
-        if (name == null || headerGroup == null) {
-            return this;
-        }
-        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
-            final Header header = i.next();
-            if (name.equalsIgnoreCase(header.getName())) {
-                i.remove();
-            }
-        }
+        super.removeHeaders(name);
         return this;
     }
 
+    @Override
     public ClassicRequestBuilder setHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(header);
+        super.setHeader(header);
         return this;
     }
 
+    @Override
     public ClassicRequestBuilder setHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(new BasicHeader(name, value));
+        super.setHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public ClassicRequestBuilder setCharset(final Charset charset) {
+        super.setCharset(charset);
+        return this;
+    }
+
+    @Override
+    public ClassicRequestBuilder addParameter(final NameValuePair nvp) {
+        super.addParameter(nvp);
+        return this;
+    }
+
+    @Override
+    public ClassicRequestBuilder addParameter(final String name, final String value) {
+        super.addParameter(name, value);
+        return this;
+    }
+
+    @Override
+    public ClassicRequestBuilder addParameters(final NameValuePair... nvps) {
+        super.addParameters(nvps);
         return this;
     }
 
@@ -339,41 +297,21 @@ public class ClassicRequestBuilder {
         return this;
     }
 
-    public List<NameValuePair> getParameters() {
-        return parameters != null ? new ArrayList<>(parameters) :
-                new ArrayList<NameValuePair>();
-    }
-
-    public ClassicRequestBuilder addParameter(final NameValuePair nvp) {
-        Args.notNull(nvp, "Name value pair");
-        if (parameters == null) {
-            parameters = new LinkedList<>();
-        }
-        parameters.add(nvp);
-        return this;
-    }
-
-    public ClassicRequestBuilder addParameter(final String name, final String value) {
-        return addParameter(new BasicNameValuePair(name, value));
-    }
-
-    public ClassicRequestBuilder addParameters(final NameValuePair... nvps) {
-        for (final NameValuePair nvp : nvps) {
-            addParameter(nvp);
-        }
-        return this;
-    }
-
     public ClassicHttpRequest build() {
-        URI uriCopy = this.uri != null ? this.uri : URI.create("/");
+        URI uriCopy = getUri();
+        if (uriCopy == null) {
+            uriCopy = URI.create("/");
+        }
         HttpEntity entityCopy = this.entity;
+        final String method = getMethod();
+        final List<NameValuePair> parameters = getParameters();
         if (parameters != null && !parameters.isEmpty()) {
             if (entityCopy == null && (Method.POST.isSame(method) || Method.PUT.isSame(method))) {
-                entityCopy = HttpEntities.createUrlEncoded(parameters, charset);
+                entityCopy = HttpEntities.createUrlEncoded(parameters, getCharset());
             } else {
                 try {
                     uriCopy = new URIBuilder(uriCopy)
-                            .setCharset(this.charset)
+                            .setCharset(getCharset())
                             .addParameters(parameters)
                             .build();
                 } catch (final URISyntaxException ex) {
@@ -386,11 +324,9 @@ public class ClassicRequestBuilder {
             throw new IllegalStateException(Method.TRACE + " requests may not include an entity");
         }
 
-        final ClassicHttpRequest result = new BasicClassicHttpRequest(method, uriCopy);
-        result.setVersion(this.version != null ? this.version : HttpVersion.HTTP_1_1);
-        if (this.headerGroup != null) {
-            result.setHeaders(this.headerGroup.getHeaders());
-        }
+        final BasicClassicHttpRequest result = new BasicClassicHttpRequest(method, uriCopy);
+        result.setVersion(getVersion());
+        result.setHeaders(getHeaders());
         result.setEntity(entityCopy);
         return result;
     }
@@ -399,19 +335,17 @@ public class ClassicRequestBuilder {
     public String toString() {
         final StringBuilder builder = new StringBuilder();
         builder.append("ClassicRequestBuilder [method=");
-        builder.append(method);
-        builder.append(", charset=");
-        builder.append(charset);
+        builder.append(getMethod());
         builder.append(", version=");
-        builder.append(version);
+        builder.append(getVersion());
         builder.append(", uri=");
-        builder.append(uri);
+        builder.append(getUri());
+        builder.append(", parameters=");
+        builder.append(getParameters());
         builder.append(", headerGroup=");
-        builder.append(headerGroup);
+        builder.append(Arrays.toString(getHeaders()));
         builder.append(", entity=");
         builder.append(entity != null ? entity.getClass() : null);
-        builder.append(", parameters=");
-        builder.append(parameters);
         builder.append("]");
         return builder.toString();
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
index c8b583d..ce6d7bf 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicResponseBuilder.java
@@ -27,19 +27,17 @@
 
 package org.apache.hc.core5.http.io.support;
 
-import java.util.Iterator;
+import java.util.Arrays;
 
 import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpEntity;
-import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
 import org.apache.hc.core5.http.io.entity.StringEntity;
 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
-import org.apache.hc.core5.http.message.BasicHeader;
-import org.apache.hc.core5.http.message.HeaderGroup;
+import org.apache.hc.core5.http.support.AbstractResponseBuilder;
 import org.apache.hc.core5.util.Args;
 
 /**
@@ -47,19 +45,12 @@ import org.apache.hc.core5.util.Args;
  *
  * @since 5.0
  */
-public class ClassicResponseBuilder {
+public class ClassicResponseBuilder extends AbstractResponseBuilder<ClassicHttpResponse> {
 
-    private int status;
-    private ProtocolVersion version;
-    private HeaderGroup headerGroup;
     private HttpEntity entity;
 
-    ClassicResponseBuilder() {
-    }
-
     ClassicResponseBuilder(final int status) {
-        super();
-        this.status = status;
+        super(status);
     }
 
     public static ClassicResponseBuilder create(final int status) {
@@ -67,85 +58,51 @@ public class ClassicResponseBuilder {
         return new ClassicResponseBuilder(status);
     }
 
-    public ProtocolVersion getVersion() {
-        return version;
-    }
-
+    @Override
     public ClassicResponseBuilder setVersion(final ProtocolVersion version) {
-        this.version = version;
+        super.setVersion(version);
         return this;
     }
 
-    public Header[] getHeaders(final String name) {
-        return headerGroup != null ? headerGroup.getHeaders(name) : null;
-    }
-
+    @Override
     public ClassicResponseBuilder setHeaders(final Header... headers) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.setHeaders(headers);
+        super.setHeaders(headers);
         return this;
     }
 
-    public Header getFirstHeader(final String name) {
-        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
-    }
-
-    public Header getLastHeader(final String name) {
-        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
-    }
-
+    @Override
     public ClassicResponseBuilder addHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.addHeader(header);
+        super.addHeader(header);
         return this;
     }
 
-    public ClassicResponseBuilder addHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.addHeader(new BasicHeader(name, value));
+    @Override
+    public ClassicResponseBuilder addHeader(final String name, final    String value) {
+        super.addHeader(name, value);
         return this;
     }
 
+    @Override
     public ClassicResponseBuilder removeHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.removeHeader(header);
+        super.removeHeader(header);
         return this;
     }
 
+    @Override
     public ClassicResponseBuilder removeHeaders(final String name) {
-        if (name == null || headerGroup == null) {
-            return this;
-        }
-        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
-            final Header header = i.next();
-            if (name.equalsIgnoreCase(header.getName())) {
-                i.remove();
-            }
-        }
+        super.removeHeaders(name);
         return this;
     }
 
+    @Override
     public ClassicResponseBuilder setHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(header);
+        super.setHeader(header);
         return this;
     }
 
+    @Override
     public ClassicResponseBuilder setHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(new BasicHeader(name, value));
+        super.setHeader(name, value);
         return this;
     }
 
@@ -174,11 +131,9 @@ public class ClassicResponseBuilder {
     }
 
     public ClassicHttpResponse build() {
-        final ClassicHttpResponse result = new BasicClassicHttpResponse(status);
-        result.setVersion(this.version != null ? this.version : HttpVersion.HTTP_1_1);
-        if (this.headerGroup != null) {
-            result.setHeaders(this.headerGroup.getHeaders());
-        }
+        final BasicClassicHttpResponse result = new BasicClassicHttpResponse(getStatus());
+        result.setVersion(getVersion());
+        result.setHeaders(getHeaders());
         result.setEntity(entity);
         return result;
     }
@@ -186,14 +141,10 @@ public class ClassicResponseBuilder {
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append("ClassicResponseBuilder [method=");
-        builder.append(status);
-        builder.append(", status=");
-        builder.append(status);
-        builder.append(", version=");
-        builder.append(version);
+        builder.append("ClassicResponseBuilder [status=");
+        builder.append(getStatus());
         builder.append(", headerGroup=");
-        builder.append(headerGroup);
+        builder.append(Arrays.toString(getHeaders()));
         builder.append(", entity=");
         builder.append(entity != null ? entity.getClass() : null);
         builder.append("]");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java
index 66af20a..4155f61 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncPushBuilder.java
@@ -27,36 +27,30 @@
 
 package org.apache.hc.core5.http.nio.support;
 
-import java.util.Iterator;
-
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
-import org.apache.hc.core5.http.message.HeaderGroup;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.AsyncPushProducer;
 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.support.AbstractResponseBuilder;
 import org.apache.hc.core5.util.Args;
 
+import java.util.Arrays;
+
 /**
  * Builder for {@link AsyncPushProducer} instances.
  *
  * @since 5.0
  */
-public class AsyncPushBuilder {
+public class AsyncPushBuilder extends AbstractResponseBuilder<AsyncPushProducer> {
 
-    private int status;
-    private HeaderGroup headerGroup;
     private AsyncEntityProducer entityProducer;
 
-    AsyncPushBuilder() {
-    }
-
     AsyncPushBuilder(final int status) {
-        super();
-        this.status = status;
+        super(status);
     }
 
     public static AsyncPushBuilder create(final int status) {
@@ -64,76 +58,51 @@ public class AsyncPushBuilder {
         return new AsyncPushBuilder(status);
     }
 
-    public Header[] getHeaders(final String name) {
-        return headerGroup != null ? headerGroup.getHeaders(name) : null;
+    @Override
+    public AsyncPushBuilder setVersion(final ProtocolVersion version) {
+        super.setVersion(version);
+        return this;
     }
 
+    @Override
     public AsyncPushBuilder setHeaders(final Header... headers) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.setHeaders(headers);
+        super.setHeaders(headers);
         return this;
     }
 
-    public Header getFirstHeader(final String name) {
-        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
-    }
-
-    public Header getLastHeader(final String name) {
-        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
-    }
-
+    @Override
     public AsyncPushBuilder addHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.addHeader(header);
+        super.addHeader(header);
         return this;
     }
 
+    @Override
     public AsyncPushBuilder addHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.addHeader(new BasicHeader(name, value));
+        super.addHeader(name, value);
         return this;
     }
 
+    @Override
     public AsyncPushBuilder removeHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.removeHeader(header);
+        super.removeHeader(header);
         return this;
     }
 
+    @Override
     public AsyncPushBuilder removeHeaders(final String name) {
-        if (name == null || headerGroup == null) {
-            return this;
-        }
-        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
-            final Header header = i.next();
-            if (name.equalsIgnoreCase(header.getName())) {
-                i.remove();
-            }
-        }
+        super.removeHeaders(name);
         return this;
     }
 
+    @Override
     public AsyncPushBuilder setHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(header);
+        super.setHeader(header);
         return this;
     }
 
+    @Override
     public AsyncPushBuilder setHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(new BasicHeader(name, value));
+        super.setHeader(name, value);
         return this;
     }
 
@@ -162,22 +131,19 @@ public class AsyncPushBuilder {
     }
 
     public AsyncPushProducer build() {
-        final HttpResponse response = new BasicHttpResponse(status);
-        if (this.headerGroup != null) {
-            response.setHeaders(this.headerGroup.getHeaders());
-        }
+        final HttpResponse response = new BasicHttpResponse(getStatus());
+        response.setVersion(getVersion());
+        response.setHeaders(getHeaders());
         return new BasicPushProducer(response, entityProducer);
     }
 
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append("AsyncPushProducer [method=");
-        builder.append(status);
-        builder.append(", status=");
-        builder.append(status);
+        builder.append("AsyncPushProducer [status=");
+        builder.append(getStatus());
         builder.append(", headerGroup=");
-        builder.append(headerGroup);
+        builder.append(Arrays.toString(getHeaders()));
         builder.append(", entity=");
         builder.append(entityProducer != null ? entityProducer.getClass() : null);
         builder.append("]");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
index 720980e..a80737c 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
@@ -30,25 +30,20 @@ package org.apache.hc.core5.http.nio.support;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Method;
 import org.apache.hc.core5.http.NameValuePair;
 import org.apache.hc.core5.http.ProtocolVersion;
-import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
-import org.apache.hc.core5.http.message.BasicNameValuePair;
-import org.apache.hc.core5.http.message.HeaderGroup;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.AsyncRequestProducer;
 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
+import org.apache.hc.core5.http.support.AbstractRequestBuilder;
 import org.apache.hc.core5.net.URIBuilder;
 import org.apache.hc.core5.net.WWWFormCodec;
 import org.apache.hc.core5.util.Args;
@@ -65,32 +60,20 @@ import org.apache.hc.core5.util.Args;
  *
  * @since 5.0
  */
-public class AsyncRequestBuilder {
+public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProducer> {
 
-    private String method;
-    private URI uri;
-    private Charset charset;
-    private ProtocolVersion version;
-    private HeaderGroup headerGroup;
     private AsyncEntityProducer entityProducer;
-    private List<NameValuePair> parameters;
-
-    AsyncRequestBuilder() {
-    }
 
     AsyncRequestBuilder(final String method) {
-        super();
-        this.method = method;
+        super(method);
     }
 
     AsyncRequestBuilder(final Method method) {
-        this(method.name());
+        super(method);
     }
 
     AsyncRequestBuilder(final String method, final URI uri) {
-        super();
-        this.method = method;
-        this.uri = uri;
+        super(method, uri);
     }
 
     AsyncRequestBuilder(final Method method, final URI uri) {
@@ -206,136 +189,87 @@ public class AsyncRequestBuilder {
         return new AsyncRequestBuilder(Method.OPTIONS, uri);
     }
 
-    public AsyncRequestBuilder setCharset(final Charset charset) {
-        this.charset = charset;
+    @Override
+    public AsyncRequestBuilder setVersion(final ProtocolVersion version) {
+        super.setVersion(version);
         return this;
     }
 
-    public Charset getCharset() {
-        return charset;
-    }
-
-    public String getMethod() {
-        return method;
-    }
-
-    public URI getUri() {
-        return uri;
-    }
-
+    @Override
     public AsyncRequestBuilder setUri(final URI uri) {
-        this.uri = uri;
+        super.setUri(uri);
         return this;
     }
 
+    @Override
     public AsyncRequestBuilder setUri(final String uri) {
-        this.uri = uri != null ? URI.create(uri) : null;
-        return this;
-    }
-
-    public ProtocolVersion getVersion() {
-        return version;
-    }
-
-    public AsyncRequestBuilder setVersion(final ProtocolVersion version) {
-        this.version = version;
+        super.setUri(uri);
         return this;
     }
 
-    public Header[] getHeaders(final String name) {
-        return headerGroup != null ? headerGroup.getHeaders(name) : null;
-    }
-
+    @Override
     public AsyncRequestBuilder setHeaders(final Header... headers) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.setHeaders(headers);
+        super.setHeaders(headers);
         return this;
     }
 
-    public Header getFirstHeader(final String name) {
-        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
-    }
-
-    public Header getLastHeader(final String name) {
-        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
-    }
-
+    @Override
     public AsyncRequestBuilder addHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.addHeader(header);
+        super.addHeader(header);
         return this;
     }
 
+    @Override
     public AsyncRequestBuilder addHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.addHeader(new BasicHeader(name, value));
+        super.addHeader(name, value);
         return this;
     }
 
+    @Override
     public AsyncRequestBuilder removeHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.removeHeader(header);
+        super.removeHeader(header);
         return this;
     }
 
+    @Override
     public AsyncRequestBuilder removeHeaders(final String name) {
-        if (name == null || headerGroup == null) {
-            return this;
-        }
-        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
-            final Header header = i.next();
-            if (name.equalsIgnoreCase(header.getName())) {
-                i.remove();
-            }
-        }
+        super.removeHeaders(name);
         return this;
     }
 
+    @Override
     public AsyncRequestBuilder setHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(header);
+        super.setHeader(header);
         return this;
     }
 
+    @Override
     public AsyncRequestBuilder setHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(new BasicHeader(name, value));
+        super.setHeader(name, value);
         return this;
     }
 
-    public List<NameValuePair> getParameters() {
-        return parameters != null ? new ArrayList<>(parameters) : new ArrayList<NameValuePair>();
+    @Override
+    public AsyncRequestBuilder setCharset(final Charset charset) {
+        super.setCharset(charset);
+        return this;
     }
 
+    @Override
     public AsyncRequestBuilder addParameter(final NameValuePair nvp) {
-        Args.notNull(nvp, "Name value pair");
-        if (parameters == null) {
-            parameters = new LinkedList<>();
-        }
-        parameters.add(nvp);
+        super.addParameter(nvp);
         return this;
     }
 
+    @Override
     public AsyncRequestBuilder addParameter(final String name, final String value) {
-        return addParameter(new BasicNameValuePair(name, value));
+        super.addParameter(name, value);
+        return this;
     }
 
+    @Override
     public AsyncRequestBuilder addParameters(final NameValuePair... nvps) {
-        for (final NameValuePair nvp: nvps) {
-            addParameter(nvp);
-        }
+        super.addParameters(nvps);
         return this;
     }
 
@@ -364,9 +298,15 @@ public class AsyncRequestBuilder {
     }
 
     public AsyncRequestProducer build() {
-        URI uriCopy = uri != null ? uri : URI.create("/");
+        URI uriCopy = getUri();
+        if (uriCopy == null) {
+            uriCopy = URI.create("/");
+        }
         AsyncEntityProducer entityProducerCopy = entityProducer;
+        final String method = getMethod();
+        final List<NameValuePair> parameters = getParameters();
         if (parameters != null && !parameters.isEmpty()) {
+            final Charset charset = getCharset();
             if (entityProducerCopy == null && (Method.POST.isSame(method) || Method.PUT.isSame(method))) {
                 final String content = WWWFormCodec.format(
                         parameters,
@@ -377,9 +317,9 @@ public class AsyncRequestBuilder {
             } else {
                 try {
                     uriCopy = new URIBuilder(uriCopy)
-                      .setCharset(this.charset)
-                      .addParameters(parameters)
-                      .build();
+                            .setCharset(charset)
+                            .addParameters(parameters)
+                            .build();
                 } catch (final URISyntaxException ex) {
                     // should never happen
                 }
@@ -387,16 +327,12 @@ public class AsyncRequestBuilder {
         }
 
         if (entityProducerCopy != null && Method.TRACE.isSame(method)) {
-            throw new IllegalStateException(Method.TRACE + " requests may not include an entity.");
+            throw new IllegalStateException(Method.TRACE + " requests may not include an entity");
         }
 
-        final HttpRequest request = new BasicHttpRequest(method, uriCopy);
-        if (this.headerGroup != null) {
-            request.setHeaders(this.headerGroup.getHeaders());
-        }
-        if (version != null) {
-            request.setVersion(version);
-        }
+        final BasicHttpRequest request = new BasicHttpRequest(method, uriCopy);
+        request.setVersion(getVersion());
+        request.setHeaders(getHeaders());
         return new BasicRequestProducer(request, entityProducerCopy);
     }
 
@@ -404,19 +340,17 @@ public class AsyncRequestBuilder {
     public String toString() {
         final StringBuilder builder = new StringBuilder();
         builder.append("AsyncRequestBuilder [method=");
-        builder.append(method);
-        builder.append(", charset=");
-        builder.append(charset);
+        builder.append(getMethod());
         builder.append(", version=");
-        builder.append(version);
+        builder.append(getVersion());
         builder.append(", uri=");
-        builder.append(uri);
+        builder.append(getUri());
+        builder.append(", parameters=");
+        builder.append(getParameters());
         builder.append(", headerGroup=");
-        builder.append(headerGroup);
+        builder.append(Arrays.toString(getHeaders()));
         builder.append(", entity=");
         builder.append(entityProducer != null ? entityProducer.getClass() : null);
-        builder.append(", parameters=");
-        builder.append(parameters);
         builder.append("]");
         return builder.toString();
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java
index abb2294..42c6577 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncResponseBuilder.java
@@ -27,18 +27,16 @@
 
 package org.apache.hc.core5.http.nio.support;
 
-import java.util.Iterator;
+import java.util.Arrays;
 
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.ProtocolVersion;
-import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
-import org.apache.hc.core5.http.message.HeaderGroup;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 import org.apache.hc.core5.http.nio.AsyncResponseProducer;
 import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
+import org.apache.hc.core5.http.support.AbstractResponseBuilder;
 import org.apache.hc.core5.util.Args;
 
 /**
@@ -46,19 +44,12 @@ import org.apache.hc.core5.util.Args;
  *
  * @since 5.0
  */
-public class AsyncResponseBuilder {
+public class AsyncResponseBuilder extends AbstractResponseBuilder<AsyncResponseProducer>  {
 
-    private int status;
-    private ProtocolVersion version;
-    private HeaderGroup headerGroup;
     private AsyncEntityProducer entityProducer;
 
-    AsyncResponseBuilder() {
-    }
-
     AsyncResponseBuilder(final int status) {
-        super();
-        this.status = status;
+        super(status);
     }
 
     public static AsyncResponseBuilder create(final int status) {
@@ -66,85 +57,51 @@ public class AsyncResponseBuilder {
         return new AsyncResponseBuilder(status);
     }
 
-    public ProtocolVersion getVersion() {
-        return version;
-    }
-
+    @Override
     public AsyncResponseBuilder setVersion(final ProtocolVersion version) {
-        this.version = version;
+        super.setVersion(version);
         return this;
     }
 
-    public Header[] getHeaders(final String name) {
-        return headerGroup != null ? headerGroup.getHeaders(name) : null;
-    }
-
+    @Override
     public AsyncResponseBuilder setHeaders(final Header... headers) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.setHeaders(headers);
+        super.setHeaders(headers);
         return this;
     }
 
-    public Header getFirstHeader(final String name) {
-        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
-    }
-
-    public Header getLastHeader(final String name) {
-        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
-    }
-
+    @Override
     public AsyncResponseBuilder addHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.addHeader(header);
+        super.addHeader(header);
         return this;
     }
 
+    @Override
     public AsyncResponseBuilder addHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.addHeader(new BasicHeader(name, value));
+        super.addHeader(name, value);
         return this;
     }
 
+    @Override
     public AsyncResponseBuilder removeHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        headerGroup.removeHeader(header);
+        super.removeHeader(header);
         return this;
     }
 
+    @Override
     public AsyncResponseBuilder removeHeaders(final String name) {
-        if (name == null || headerGroup == null) {
-            return this;
-        }
-        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
-            final Header header = i.next();
-            if (name.equalsIgnoreCase(header.getName())) {
-                i.remove();
-            }
-        }
+        super.removeHeaders(name);
         return this;
     }
 
+    @Override
     public AsyncResponseBuilder setHeader(final Header header) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(header);
+        super.setHeader(header);
         return this;
     }
 
+    @Override
     public AsyncResponseBuilder setHeader(final String name, final String value) {
-        if (headerGroup == null) {
-            headerGroup = new HeaderGroup();
-        }
-        this.headerGroup.setHeader(new BasicHeader(name, value));
+        super.setHeader(name, value);
         return this;
     }
 
@@ -173,27 +130,19 @@ public class AsyncResponseBuilder {
     }
 
     public AsyncResponseProducer build() {
-        final HttpResponse response = new BasicHttpResponse(status);
-        if (this.headerGroup != null) {
-            response.setHeaders(this.headerGroup.getHeaders());
-        }
-        if (version != null) {
-            response.setVersion(version);
-        }
+        final BasicHttpResponse response = new BasicHttpResponse(getStatus());
+        response.setVersion(getVersion());
+        response.setHeaders(getHeaders());
         return new BasicResponseProducer(response, entityProducer);
     }
 
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append("AsyncResponseBuilder [method=");
-        builder.append(status);
-        builder.append(", status=");
-        builder.append(status);
-        builder.append(", version=");
-        builder.append(version);
+        builder.append("AsyncResponseBuilder [status=");
+        builder.append(getStatus());
         builder.append(", headerGroup=");
-        builder.append(headerGroup);
+        builder.append(Arrays.toString(getHeaders()));
         builder.append(", entity=");
         builder.append(entityProducer != null ? entityProducer.getClass() : null);
         builder.append("]");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractMessageBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractMessageBuilder.java
new file mode 100644
index 0000000..143c30c
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractMessageBuilder.java
@@ -0,0 +1,143 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http.support;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpMessage;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.HeaderGroup;
+
+import java.util.Iterator;
+
+/**
+ * Abstract {@link HttpMessage} builder.
+ *
+ * @since 5.1
+ */
+public abstract class AbstractMessageBuilder<T> {
+
+    private ProtocolVersion version;
+    private HeaderGroup headerGroup;
+
+    protected AbstractMessageBuilder() {
+    }
+
+    public ProtocolVersion getVersion() {
+        return version;
+    }
+
+    public AbstractMessageBuilder<T> setVersion(final ProtocolVersion version) {
+        this.version = version;
+        return this;
+    }
+
+    public Header[] getHeaders() {
+        return headerGroup != null ? headerGroup.getHeaders() : null;
+    }
+
+    public Header[] getHeaders(final String name) {
+        return headerGroup != null ? headerGroup.getHeaders(name) : null;
+    }
+
+    public AbstractMessageBuilder<T> setHeaders(final Header... headers) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeaders(headers);
+        return this;
+    }
+
+    public Header[] getFirstHeaders() {
+        return headerGroup != null ? headerGroup.getHeaders() : null;
+    }
+
+    public Header getFirstHeader(final String name) {
+        return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
+    }
+
+    public Header getLastHeader(final String name) {
+        return headerGroup != null ? headerGroup.getLastHeader(name) : null;
+    }
+
+    public AbstractMessageBuilder<T> addHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.addHeader(header);
+        return this;
+    }
+
+    public AbstractMessageBuilder<T> addHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.addHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    public AbstractMessageBuilder<T> removeHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.removeHeader(header);
+        return this;
+    }
+
+    public AbstractMessageBuilder<T> removeHeaders(final String name) {
+        if (name == null || headerGroup == null) {
+            return this;
+        }
+        for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
+            final Header header = i.next();
+            if (name.equalsIgnoreCase(header.getName())) {
+                i.remove();
+            }
+        }
+        return this;
+    }
+
+    public AbstractMessageBuilder<T> setHeader(final Header header) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeader(header);
+        return this;
+    }
+
+    public AbstractMessageBuilder<T> setHeader(final String name, final String value) {
+        if (headerGroup == null) {
+            headerGroup = new HeaderGroup();
+        }
+        headerGroup.setHeader(new BasicHeader(name, value));
+        return this;
+    }
+
+    protected abstract T build();
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
new file mode 100644
index 0000000..9c3c801
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
@@ -0,0 +1,183 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http.support;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.Method;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.http.message.BasicNameValuePair;
+
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Builder for {@link BasicHttpRequest} instances.
+ *
+ * @since 5.1
+ */
+public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T> {
+
+    private String method;
+    private URI uri;
+    private Charset charset;
+    private List<NameValuePair> parameters;
+
+    protected AbstractRequestBuilder(final String method) {
+        super();
+        this.method = method;
+    }
+
+    protected AbstractRequestBuilder(final Method method) {
+        this(method.name());
+    }
+
+    protected AbstractRequestBuilder(final String method, final URI uri) {
+        super();
+        this.method = method;
+        this.uri = uri;
+    }
+
+    protected AbstractRequestBuilder(final Method method, final URI uri) {
+        this(method.name(), uri);
+    }
+
+    protected AbstractRequestBuilder(final Method method, final String uri) {
+        this(method.name(), uri != null ? URI.create(uri) : null);
+    }
+
+    protected AbstractRequestBuilder(final String method, final String uri) {
+        this(method, uri != null ? URI.create(uri) : null);
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> setVersion(final ProtocolVersion version) {
+        super.setVersion(version);
+        return this;
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
+    public AbstractRequestBuilder<T> setUri(final URI uri) {
+        this.uri = uri;
+        return this;
+    }
+
+    public AbstractRequestBuilder<T> setUri(final String uri) {
+        this.uri = uri != null ? URI.create(uri) : null;
+        return this;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> setHeaders(final Header... headers) {
+        super.setHeaders(headers);
+        return this;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> addHeader(final Header header) {
+        super.addHeader(header);
+        return this;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> addHeader(final String name, final String value) {
+        super.addHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> removeHeader(final Header header) {
+        super.removeHeader(header);
+        return this;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> removeHeaders(final String name) {
+        super.removeHeaders(name);
+        return this;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> setHeader(final Header header) {
+        super.setHeader(header);
+        return this;
+    }
+
+    @Override
+    public AbstractRequestBuilder<T> setHeader(final String name, final String value) {
+        super.setHeader(name, value);
+        return this;
+    }
+
+    public Charset getCharset() {
+        return charset;
+    }
+
+    public AbstractRequestBuilder<T> setCharset(final Charset charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    public List<NameValuePair> getParameters() {
+        return parameters != null ? new ArrayList<>(parameters) : null;
+    }
+
+    public AbstractRequestBuilder<T> addParameter(final NameValuePair nvp) {
+        if (nvp == null) {
+            return this;
+        }
+        if (parameters == null) {
+            parameters = new LinkedList<>();
+        }
+        parameters.add(nvp);
+        return this;
+    }
+
+    public AbstractRequestBuilder<T> addParameter(final String name, final String value) {
+        return addParameter(new BasicNameValuePair(name, value));
+    }
+
+    public AbstractRequestBuilder<T> addParameters(final NameValuePair... nvps) {
+        for (final NameValuePair nvp : nvps) {
+            addParameter(nvp);
+        }
+        return this;
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractResponseBuilder.java
new file mode 100644
index 0000000..d371e8e
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractResponseBuilder.java
@@ -0,0 +1,106 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http.support;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+
+/**
+ * Builder for {@link BasicHttpRequest} instances.
+ *
+ * @since 5.1
+ */
+public abstract class AbstractResponseBuilder<T> extends AbstractMessageBuilder<T> {
+
+    private int status;
+
+    protected AbstractResponseBuilder(final int status) {
+        super();
+        this.status = status;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+    public void setStatus(final int status) {
+        this.status = status;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> setVersion(final ProtocolVersion version) {
+        super.setVersion(version);
+        return this;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> setHeaders(final Header... headers) {
+        super.setHeaders(headers);
+        return this;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> addHeader(final Header header) {
+        super.addHeader(header);
+        return this;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> addHeader(final String name, final String value) {
+        super.addHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> removeHeader(final Header header) {
+        super.removeHeader(header);
+        return this;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> removeHeaders(final String name) {
+        super.removeHeaders(name);
+        return this;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> setHeader(final Header header) {
+        super.setHeader(header);
+        return this;
+    }
+
+    @Override
+    public AbstractResponseBuilder<T> setHeader(final String name, final String value) {
+        super.setHeader(name, value);
+        return this;
+    }
+
+    protected abstract T build();
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
new file mode 100644
index 0000000..dab7bb7
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
@@ -0,0 +1,295 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http.support;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.Method;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.net.URIBuilder;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * Builder for {@link BasicHttpRequest} instances.
+ *
+ * @since 5.1
+ */
+public class BasicRequestBuilder extends AbstractRequestBuilder<BasicHttpRequest> {
+
+    BasicRequestBuilder(final String method) {
+        super(method);
+    }
+
+    BasicRequestBuilder(final Method method) {
+        super(method);
+    }
+
+    BasicRequestBuilder(final String method, final URI uri) {
+        super(method, uri);
+    }
+
+    BasicRequestBuilder(final Method method, final URI uri) {
+        super(method, uri);
+    }
+
+    BasicRequestBuilder(final Method method, final String uri) {
+        super(method, uri);
+    }
+
+    BasicRequestBuilder(final String method, final String uri) {
+        super(method, uri);
+    }
+
+    public static BasicRequestBuilder create(final String method) {
+        Args.notBlank(method, "HTTP method");
+        return new BasicRequestBuilder(method);
+    }
+
+    public static BasicRequestBuilder get() {
+        return new BasicRequestBuilder(Method.GET);
+    }
+
+    public static BasicRequestBuilder get(final URI uri) {
+        return new BasicRequestBuilder(Method.GET, uri);
+    }
+
+    public static BasicRequestBuilder get(final String uri) {
+        return new BasicRequestBuilder(Method.GET, uri);
+    }
+
+    public static BasicRequestBuilder head() {
+        return new BasicRequestBuilder(Method.HEAD);
+    }
+
+    public static BasicRequestBuilder head(final URI uri) {
+        return new BasicRequestBuilder(Method.HEAD, uri);
+    }
+
+    public static BasicRequestBuilder head(final String uri) {
+        return new BasicRequestBuilder(Method.HEAD, uri);
+    }
+
+    public static BasicRequestBuilder patch() {
+        return new BasicRequestBuilder(Method.PATCH);
+    }
+
+    public static BasicRequestBuilder patch(final URI uri) {
+        return new BasicRequestBuilder(Method.PATCH, uri);
+    }
+
+    public static BasicRequestBuilder patch(final String uri) {
+        return new BasicRequestBuilder(Method.PATCH, uri);
+    }
+
+    public static BasicRequestBuilder post() {
+        return new BasicRequestBuilder(Method.POST);
+    }
+
+    public static BasicRequestBuilder post(final URI uri) {
+        return new BasicRequestBuilder(Method.POST, uri);
+    }
+
+    public static BasicRequestBuilder post(final String uri) {
+        return new BasicRequestBuilder(Method.POST, uri);
+    }
+
+    public static BasicRequestBuilder put() {
+        return new BasicRequestBuilder(Method.PUT);
+    }
+
+    public static BasicRequestBuilder put(final URI uri) {
+        return new BasicRequestBuilder(Method.PUT, uri);
+    }
+
+    public static BasicRequestBuilder put(final String uri) {
+        return new BasicRequestBuilder(Method.PUT, uri);
+    }
+
+    public static BasicRequestBuilder delete() {
+        return new BasicRequestBuilder(Method.DELETE);
+    }
+
+    public static BasicRequestBuilder delete(final URI uri) {
+        return new BasicRequestBuilder(Method.DELETE, uri);
+    }
+
+    public static BasicRequestBuilder delete(final String uri) {
+        return new BasicRequestBuilder(Method.DELETE, uri);
+    }
+
+    public static BasicRequestBuilder trace() {
+        return new BasicRequestBuilder(Method.TRACE);
+    }
+
+    public static BasicRequestBuilder trace(final URI uri) {
+        return new BasicRequestBuilder(Method.TRACE, uri);
+    }
+
+    public static BasicRequestBuilder trace(final String uri) {
+        return new BasicRequestBuilder(Method.TRACE, uri);
+    }
+
+    public static BasicRequestBuilder options() {
+        return new BasicRequestBuilder(Method.OPTIONS);
+    }
+
+    public static BasicRequestBuilder options(final URI uri) {
+        return new BasicRequestBuilder(Method.OPTIONS, uri);
+    }
+
+    public static BasicRequestBuilder options(final String uri) {
+        return new BasicRequestBuilder(Method.OPTIONS, uri);
+    }
+
+    @Override
+    public BasicRequestBuilder setVersion(final ProtocolVersion version) {
+        super.setVersion(version);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setUri(final URI uri) {
+        super.setUri(uri);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setUri(final String uri) {
+        super.setUri(uri);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setHeaders(final Header... headers) {
+        super.setHeaders(headers);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder addHeader(final Header header) {
+        super.addHeader(header);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder addHeader(final String name, final String value) {
+        super.addHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder removeHeader(final Header header) {
+        super.removeHeader(header);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder removeHeaders(final String name) {
+        super.removeHeaders(name);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setHeader(final Header header) {
+        super.setHeader(header);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setHeader(final String name, final String value) {
+        super.setHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder setCharset(final Charset charset) {
+        super.setCharset(charset);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder addParameter(final NameValuePair nvp) {
+        super.addParameter(nvp);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder addParameter(final String name, final String value) {
+        super.addParameter(name, value);
+        return this;
+    }
+
+    @Override
+    public BasicRequestBuilder addParameters(final NameValuePair... nvps) {
+        super.addParameters(nvps);
+        return this;
+    }
+
+    @Override
+    public BasicHttpRequest build() {
+        URI uri = getUri();
+        final List<NameValuePair> parameters = getParameters();
+        if (parameters != null && !parameters.isEmpty()) {
+            try {
+                uri = new URIBuilder(uri)
+                        .setCharset(getCharset())
+                        .addParameters(parameters)
+                        .build();
+            } catch (final URISyntaxException ex) {
+                // should never happen
+            }
+        }
+        final BasicHttpRequest result = new BasicHttpRequest(getMethod(), uri != null ? uri : URI.create("/"));
+        result.setVersion(getVersion());
+        result.setHeaders(getHeaders());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("BasicRequestBuilder [method=");
+        builder.append(getMethod());
+        builder.append(", uri=");
+        builder.append(getUri());
+        builder.append(", parameters=");
+        builder.append(getParameters());
+        builder.append(", headerGroup=");
+        builder.append(Arrays.toString(getHeaders()));
+        builder.append("]");
+        return builder.toString();
+    }
+
+}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicResponseBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicResponseBuilder.java
new file mode 100644
index 0000000..de6baa3
--- /dev/null
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicResponseBuilder.java
@@ -0,0 +1,120 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http.support;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.message.BasicHttpResponse;
+import org.apache.hc.core5.util.Args;
+
+import java.util.Arrays;
+
+/**
+ * Builder for {@link BasicHttpResponse} instances.
+ *
+ * @since 5.1
+ */
+public class BasicResponseBuilder extends AbstractResponseBuilder<BasicHttpResponse> {
+
+    protected BasicResponseBuilder(final int status) {
+        super(status);
+    }
+
+    public static BasicResponseBuilder create(final int status) {
+        Args.checkRange(status, 100, 599, "HTTP status code");
+        return new BasicResponseBuilder(status);
+    }
+
+    @Override
+    public BasicResponseBuilder setVersion(final ProtocolVersion version) {
+        super.setVersion(version);
+        return this;
+    }
+
+    @Override
+    public BasicResponseBuilder setHeaders(final Header... headers) {
+        super.setHeaders(headers);
+        return this;
+    }
+
+    @Override
+    public BasicResponseBuilder addHeader(final Header header) {
+        super.addHeader(header);
+        return this;
+    }
+
+    @Override
+    public BasicResponseBuilder addHeader(final String name, final String value) {
+        super.addHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public BasicResponseBuilder removeHeader(final Header header) {
+        super.removeHeader(header);
+        return this;
+    }
+
+    @Override
+    public BasicResponseBuilder removeHeaders(final String name) {
+        super.removeHeaders(name);
+        return this;
+    }
+
+    @Override
+    public BasicResponseBuilder setHeader(final Header header) {
+        super.setHeader(header);
+        return this;
+    }
+
+    @Override
+    public BasicResponseBuilder setHeader(final String name, final String value) {
+        super.setHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public BasicHttpResponse build() {
+        final BasicHttpResponse result = new BasicHttpResponse(getStatus());
+        result.setVersion(getVersion());
+        result.setHeaders(getHeaders());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("BasicResponseBuilder [status=");
+        builder.append(getStatus());
+        builder.append(", headerGroup=");
+        builder.append(Arrays.toString(getHeaders()));
+        builder.append("]");
+        return builder.toString();
+    }
+
+}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/HeaderMatcher.java b/httpcore5/src/test/java/org/apache/hc/core5/http/HeaderMatcher.java
new file mode 100644
index 0000000..528cfb7
--- /dev/null
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/HeaderMatcher.java
@@ -0,0 +1,66 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http;
+
+import org.apache.hc.core5.util.LangUtils;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+
+public class HeaderMatcher extends BaseMatcher<Header> {
+
+    private final String headerName;
+    private final Object headerValue;
+
+    public HeaderMatcher(final String headerName, final Object headerValue) {
+        this.headerName = headerName;
+        this.headerValue = headerValue;
+    }
+
+    @Override
+    public boolean matches(final Object item) {
+        if (item instanceof Header) {
+            final Header header = (Header) item;
+            if (headerName.equalsIgnoreCase(header.getName()) && LangUtils.equals(headerValue, header.getValue())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void describeTo(final Description description) {
+        description.appendText("same header as ").appendValue(headerValue).appendText(": ").appendValue(headerValue);
+    }
+
+    @Factory
+    public static Matcher<Header> same(final String headerName, final Object headerValue) {
+        return new HeaderMatcher(headerName, headerValue);
+    }
+
+}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/HeadersMatcher.java b/httpcore5/src/test/java/org/apache/hc/core5/http/HeadersMatcher.java
new file mode 100644
index 0000000..5b6ae44
--- /dev/null
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/HeadersMatcher.java
@@ -0,0 +1,72 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http;
+
+import org.apache.hc.core5.util.LangUtils;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+
+public class HeadersMatcher extends BaseMatcher<Header[]> {
+
+    private final Header[] expectedHeaders;
+
+    public HeadersMatcher(final Header... headers) {
+        this.expectedHeaders = headers;
+    }
+
+    @Override
+    public boolean matches(final Object item) {
+        if (item instanceof Header[]) {
+            final Header[] headers = (Header[]) item;
+            if (headers.length == expectedHeaders.length) {
+                for (int i = 0; i < headers.length; i++) {
+                    final Header h1 = headers[i];
+                    final Header h2 = expectedHeaders[i];
+                    if (!h1.getName().equalsIgnoreCase(h2.getName())
+                            || !LangUtils.equals(h1.getValue(), h2.getValue())) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void describeTo(final Description description) {
+        description.appendText("same headers as ").appendValueList("[", "; ", "]", expectedHeaders);
+    }
+
+    @Factory
+    public static Matcher<Header[]> same(final Header... headers) {
+        return new HeadersMatcher(headers);
+    }
+
+}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/support/TestBasicMessageBuilders.java b/httpcore5/src/test/java/org/apache/hc/core5/http/support/TestBasicMessageBuilders.java
new file mode 100644
index 0000000..b4f7923
--- /dev/null
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/support/TestBasicMessageBuilders.java
@@ -0,0 +1,197 @@
+/*
+ * ====================================================================
+ * 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.hc.core5.http.support;
+
+import org.apache.hc.core5.http.HeaderMatcher;
+import org.apache.hc.core5.http.HeadersMatcher;
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.http.message.BasicHttpResponse;
+import org.apache.hc.core5.http.message.BasicNameValuePair;
+import org.apache.hc.core5.net.URIAuthority;
+import org.hamcrest.MatcherAssert;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * Simple tests for {@link BasicResponseBuilder} and {@link BasicRequestBuilder}.
+ */
+public class TestBasicMessageBuilders {
+
+    @Test
+    public void testResponseBasics() throws Exception {
+        final BasicResponseBuilder builder = BasicResponseBuilder.create(200);
+        Assert.assertEquals(200, builder.getStatus());
+        Assert.assertNull(builder.getHeaders());
+        Assert.assertNull(builder.getVersion());
+
+        final BasicHttpResponse r1 = builder.build();
+        Assert.assertNotNull(r1);
+        Assert.assertEquals(200, r1.getCode());
+        Assert.assertNull(r1.getVersion());
+
+        builder.setStatus(500);
+        builder.setVersion(HttpVersion.HTTP_1_0);
+        Assert.assertEquals(500, builder.getStatus());
+        Assert.assertEquals(HttpVersion.HTTP_1_0, builder.getVersion());
+
+        final BasicHttpResponse r2 = builder.build();
+        Assert.assertEquals(500, r2.getCode());
+        Assert.assertEquals(HttpVersion.HTTP_1_0, r2.getVersion());
+
+        builder.addHeader("h1", "v1");
+        builder.addHeader("h1", "v2");
+        builder.addHeader("h2", "v2");
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2"), new BasicHeader("h2", "v2")));
+        MatcherAssert.assertThat(builder.getHeaders("h1"), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2")));
+        MatcherAssert.assertThat(builder.getFirstHeader("h1"), HeaderMatcher.same("h1", "v1"));
+        MatcherAssert.assertThat(builder.getLastHeader("h1"), HeaderMatcher.same("h1", "v2"));
+
+        final BasicHttpResponse r3 = builder.build();
+        MatcherAssert.assertThat(r3.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2"), new BasicHeader("h2", "v2")));
+        MatcherAssert.assertThat(r3.getHeaders("h1"), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2")));
+        MatcherAssert.assertThat(r3.getFirstHeader("h1"), HeaderMatcher.same("h1", "v1"));
+        MatcherAssert.assertThat(r3.getLastHeader("h1"), HeaderMatcher.same("h1", "v2"));
+
+        builder.removeHeader(new BasicHeader("h1", "v2"));
+        MatcherAssert.assertThat(builder.getHeaders("h1"), HeadersMatcher.same(new BasicHeader("h1", "v1")));
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h2", "v2")));
+
+        final BasicHttpResponse r4 = builder.build();
+        MatcherAssert.assertThat(r4.getHeaders("h1"), HeadersMatcher.same(new BasicHeader("h1", "v1")));
+        MatcherAssert.assertThat(r4.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h2", "v2")));
+
+        builder.removeHeaders("h1");
+        MatcherAssert.assertThat(builder.getHeaders("h1"), HeadersMatcher.same());
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(new BasicHeader("h2", "v2")));
+
+        final BasicHttpResponse r5 = builder.build();
+        MatcherAssert.assertThat(r5.getHeaders("h1"), HeadersMatcher.same());
+        MatcherAssert.assertThat(r5.getHeaders(), HeadersMatcher.same(new BasicHeader("h2", "v2")));
+    }
+
+    @Test
+    public void testRequestBasics() throws Exception {
+        final BasicRequestBuilder builder = BasicRequestBuilder.get();
+        Assert.assertNull(builder.getUri());
+        Assert.assertEquals("GET", builder.getMethod());
+        Assert.assertNull(builder.getHeaders());
+        Assert.assertNull(builder.getVersion());
+        Assert.assertNull(builder.getCharset());
+        Assert.assertNull(builder.getParameters());
+
+        final BasicHttpRequest r1 = builder.build();
+        Assert.assertNotNull(r1);
+        Assert.assertEquals("GET", r1.getMethod());
+        Assert.assertNull(r1.getScheme());
+        Assert.assertNull(r1.getAuthority());
+        Assert.assertEquals("/", r1.getPath());
+        Assert.assertEquals(URI.create("/"), r1.getUri());
+        Assert.assertNull(r1.getVersion());
+
+        builder.setUri(URI.create("http://host:1234/blah?param=value"));
+        builder.setVersion(HttpVersion.HTTP_1_1);
+        Assert.assertEquals(URI.create("http://host:1234/blah?param=value"), builder.getUri());
+        Assert.assertEquals(HttpVersion.HTTP_1_1, builder.getVersion());
+
+        final BasicHttpRequest r2 = builder.build();
+        Assert.assertEquals("GET", r2.getMethod());
+        Assert.assertEquals("http", r2.getScheme());
+        Assert.assertEquals(new URIAuthority("host", 1234), r2.getAuthority());
+        Assert.assertEquals("/blah?param=value", r2.getPath());
+        Assert.assertEquals(URI.create("http://host:1234/blah?param=value"), r2.getUri());
+        Assert.assertEquals(HttpVersion.HTTP_1_1, builder.getVersion());
+
+        builder.setCharset(StandardCharsets.US_ASCII);
+        builder.addParameter("param1", "value1");
+        builder.addParameter("param2", null);
+        builder.addParameters(new BasicNameValuePair("param3", "value3"), new BasicNameValuePair("param4", null));
+
+        Assert.assertEquals(builder.getParameters(), Arrays.asList(
+                new BasicNameValuePair("param1", "value1"), new BasicNameValuePair("param2", null),
+                new BasicNameValuePair("param3", "value3"), new BasicNameValuePair("param4", null)
+        ));
+        Assert.assertEquals(URI.create("http://host:1234/blah?param=value"), builder.getUri());
+
+        final BasicHttpRequest r3 = builder.build();
+        Assert.assertEquals("GET", r3.getMethod());
+        Assert.assertEquals("http", r3.getScheme());
+        Assert.assertEquals(new URIAuthority("host", 1234), r3.getAuthority());
+        Assert.assertEquals("/blah?param=value&param1=value1&param2&param3=value3&param4", r3.getPath());
+        Assert.assertEquals(URI.create("http://host:1234/blah?param=value&param1=value1&param2&param3=value3&param4"),
+                r3.getUri());
+
+        builder.addHeader("h1", "v1");
+        builder.addHeader("h1", "v2");
+        builder.addHeader("h2", "v2");
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2"), new BasicHeader("h2", "v2")));
+        MatcherAssert.assertThat(builder.getHeaders("h1"), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2")));
+        MatcherAssert.assertThat(builder.getFirstHeader("h1"), HeaderMatcher.same("h1", "v1"));
+        MatcherAssert.assertThat(builder.getLastHeader("h1"), HeaderMatcher.same("h1", "v2"));
+
+        final BasicHttpRequest r4 = builder.build();
+        MatcherAssert.assertThat(r4.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2"), new BasicHeader("h2", "v2")));
+        MatcherAssert.assertThat(r4.getHeaders("h1"), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h1", "v2")));
+        MatcherAssert.assertThat(r4.getFirstHeader("h1"), HeaderMatcher.same("h1", "v1"));
+        MatcherAssert.assertThat(r4.getLastHeader("h1"), HeaderMatcher.same("h1", "v2"));
+
+        builder.removeHeader(new BasicHeader("h1", "v2"));
+        MatcherAssert.assertThat(builder.getHeaders("h1"), HeadersMatcher.same(new BasicHeader("h1", "v1")));
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h2", "v2")));
+
+        final BasicHttpRequest r5 = builder.build();
+        MatcherAssert.assertThat(r5.getHeaders("h1"), HeadersMatcher.same(new BasicHeader("h1", "v1")));
+        MatcherAssert.assertThat(r5.getHeaders(), HeadersMatcher.same(
+                new BasicHeader("h1", "v1"), new BasicHeader("h2", "v2")));
+
+        builder.removeHeaders("h1");
+        MatcherAssert.assertThat(builder.getHeaders("h1"), HeadersMatcher.same());
+        MatcherAssert.assertThat(builder.getHeaders(), HeadersMatcher.same(new BasicHeader("h2", "v2")));
+
+        final BasicHttpRequest r6 = builder.build();
+        MatcherAssert.assertThat(r6.getHeaders("h1"), HeadersMatcher.same());
+        MatcherAssert.assertThat(r6.getHeaders(), HeadersMatcher.same(new BasicHeader("h2", "v2")));
+    }
+
+}


[httpcomponents-core] 01/10: Removed references to deprecated Assert#assertThat

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit cb6cfd3202d203123f84b733ca61119041c6c364
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Thu Feb 18 19:13:41 2021 +0100

    Removed references to deprecated Assert#assertThat
---
 .../hc/core5/http2/hpack/TestHPackCoding.java      |  5 +-
 .../hc/core5/benchmark/ResultFormatterTest.java    |  4 +-
 .../testing/classic/ClassicAuthenticationTest.java | 26 +++----
 .../classic/ClassicServerAndRequesterTest.java     | 26 +++----
 .../testing/classic/ClassicTLSIntegrationTest.java |  9 +--
 .../testing/framework/TestTestingFramework.java    |  3 +-
 .../apache/hc/core5/testing/nio/H2AlpnTest.java    |  8 +--
 .../hc/core5/testing/nio/H2IntegrationTest.java    |  5 +-
 .../testing/nio/H2ProtocolNegotiationTest.java     | 22 +++---
 .../nio/H2ServerAndMultiplexingRequesterTest.java  | 46 ++++++-------
 .../testing/nio/H2ServerAndRequesterTest.java      | 44 ++++++------
 .../hc/core5/testing/nio/H2TLSIntegrationTest.java | 19 ++---
 .../core5/testing/nio/Http1AuthenticationTest.java | 38 +++++-----
 .../testing/nio/Http1ServerAndRequesterTest.java   | 68 +++++++++---------
 .../core5/concurrent/TestComplexCancellable.java   |  7 +-
 .../hc/core5/concurrent/TestComplexFuture.java     | 19 ++---
 .../core5/http/config/TestNamedElementChain.java   | 80 +++++++++++-----------
 .../core5/http/impl/nio/TestExpandableBuffer.java  | 42 ++++++------
 .../hc/core5/http/ssl/TestTlsVersionParser.java    | 16 ++---
 .../core5/reactor/TestAbstractIOSessionPool.java   | 64 ++++++++---------
 .../org/apache/hc/core5/util/TestTimeValue.java    | 41 +++++------
 21 files changed, 300 insertions(+), 292 deletions(-)

diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestHPackCoding.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestHPackCoding.java
index 8e71d5f..57ab798 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestHPackCoding.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/hpack/TestHPackCoding.java
@@ -37,6 +37,7 @@ import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.util.ByteArrayBuffer;
 import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -1053,10 +1054,10 @@ public class TestHPackCoding {
                                 "123456789012345678901234567890123456789012345678901234567890")),
                 false);
 
-        Assert.assertThat(decoder.decodeHeaders(wrap(buf)).size(), CoreMatchers.equalTo(2));
+        MatcherAssert.assertThat(decoder.decodeHeaders(wrap(buf)).size(), CoreMatchers.equalTo(2));
 
         decoder.setMaxListSize(1000000);
-        Assert.assertThat(decoder.decodeHeaders(wrap(buf)).size(), CoreMatchers.equalTo(2));
+        MatcherAssert.assertThat(decoder.decodeHeaders(wrap(buf)).size(), CoreMatchers.equalTo(2));
 
         decoder.setMaxListSize(200);
         decoder.decodeHeaders(wrap(buf));
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/ResultFormatterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/ResultFormatterTest.java
index 023f81b..33e7185 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/ResultFormatterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/ResultFormatterTest.java
@@ -32,7 +32,7 @@ import java.nio.charset.StandardCharsets;
 
 import org.apache.hc.core5.http.HttpVersion;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Test;
 
 public class ResultFormatterTest {
@@ -56,7 +56,7 @@ public class ResultFormatterTest {
                 50000000);
         final ByteArrayOutputStream buf = new ByteArrayOutputStream();
         ResultFormatter.print(new PrintStream(buf, true, StandardCharsets.US_ASCII.name()), results);
-        Assert.assertThat(new String(buf.toByteArray(), StandardCharsets.US_ASCII).replace("\r\n", "\n"),
+        MatcherAssert.assertThat(new String(buf.toByteArray(), StandardCharsets.US_ASCII).replace("\r\n", "\n"),
                 CoreMatchers.equalTo(
                 "Server Software:\t\tTestServer/1.1\n" +
                         "Protocol version:\t\tHTTP/1.1\n" +
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicAuthenticationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicAuthenticationTest.java
index c14254d..ce1b332 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicAuthenticationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicAuthenticationTest.java
@@ -60,7 +60,7 @@ import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExternalResource;
@@ -193,16 +193,16 @@ public class ClassicAuthenticationTest {
         final HttpCoreContext context = HttpCoreContext.create();
         final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.GET, "/stuff");
         try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
             final String body1 = EntityUtils.toString(response1.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
         }
         final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.GET, "/stuff");
         request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
         try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
-            Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = EntityUtils.toString(response2.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo(""));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo(""));
         }
     }
 
@@ -219,17 +219,17 @@ public class ClassicAuthenticationTest {
         final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/stuff");
         request1.setEntity(new ByteArrayEntity(stuff, ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
             final String body1 = EntityUtils.toString(response1.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
         }
         final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/stuff");
         request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
         request2.setEntity(new ByteArrayEntity(stuff, ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
-            Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = EntityUtils.toString(response2.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
         }
     }
 
@@ -247,18 +247,18 @@ public class ClassicAuthenticationTest {
         request1.setVersion(HttpVersion.HTTP_1_0);
         request1.setEntity(new ByteArrayEntity(stuff, ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
             final String body1 = EntityUtils.toString(response1.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
         }
         final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/stuff");
         request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
         request2.setVersion(HttpVersion.HTTP_1_0);
         request2.setEntity(new ByteArrayEntity(stuff, ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
-            Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = EntityUtils.toString(response2.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
         }
     }
 
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicServerAndRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicServerAndRequesterTest.java
index 462cd8d..83377b3 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicServerAndRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicServerAndRequesterTest.java
@@ -58,7 +58,7 @@ import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.testing.SSLTestContexts;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExternalResource;
@@ -189,23 +189,23 @@ public class ClassicServerAndRequesterTest {
         final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/stuff");
         request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = EntityUtils.toString(response1.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
         }
         final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/other-stuff");
         request2.setEntity(new StringEntity("some other stuff", ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
-            Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body2 = EntityUtils.toString(response2.getEntity());
-            Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+            MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
         }
         final ClassicHttpRequest request3 = new BasicClassicHttpRequest(Method.POST, "/more-stuff");
         request3.setEntity(new StringEntity("some more stuff", ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response3 = requester.execute(target, request3, TIMEOUT, context)) {
-            Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body3 = EntityUtils.toString(response3.getEntity());
-            Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+            MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
         }
     }
 
@@ -217,23 +217,23 @@ public class ClassicServerAndRequesterTest {
         final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/stuff");
         request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = EntityUtils.toString(response1.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
         }
         final ClassicHttpRequest request2 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/other-stuff");
         request2.setEntity(new StringEntity("some other stuff", ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response2 = requester.execute(target, request2, TIMEOUT, context)) {
-            Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body2 = EntityUtils.toString(response2.getEntity());
-            Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+            MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
         }
         final ClassicHttpRequest request3 = new BasicClassicHttpRequest(Method.POST, "/no-keep-alive/more-stuff");
         request3.setEntity(new StringEntity("some more stuff", ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response3 = requester.execute(target, request3, TIMEOUT, context)) {
-            Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body3 = EntityUtils.toString(response3.getEntity());
-            Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+            MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
         }
     }
 
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicTLSIntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicTLSIntegrationTest.java
index bd344b0..c839f01 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicTLSIntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicTLSIntegrationTest.java
@@ -60,6 +60,7 @@ import org.apache.hc.core5.ssl.SSLContexts;
 import org.apache.hc.core5.testing.SSLTestContexts;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
@@ -140,15 +141,15 @@ public class ClassicTLSIntegrationTest {
         final ClassicHttpRequest request1 = new BasicClassicHttpRequest(Method.POST, "/stuff");
         request1.setEntity(new StringEntity("some stuff", ContentType.TEXT_PLAIN));
         try (final ClassicHttpResponse response1 = requester.execute(target, request1, TIMEOUT, context)) {
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = EntityUtils.toString(response1.getEntity());
-            Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
         }
 
         final SSLSession sslSession = sslSessionRef.getAndSet(null);
         final ProtocolVersion tlsVersion = TLS.parse(sslSession.getProtocol());
-        Assert.assertThat(tlsVersion.greaterEquals(TLS.V_1_2.version), CoreMatchers.equalTo(true));
-        Assert.assertThat(sslSession.getPeerPrincipal().getName(),
+        MatcherAssert.assertThat(tlsVersion.greaterEquals(TLS.V_1_2.version), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(sslSession.getPeerPrincipal().getName(),
                 CoreMatchers.equalTo("CN=localhost,OU=Apache HttpComponents,O=Apache Software Foundation"));
     }
 
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java
index c9b7980..a3abfcd 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java
@@ -50,6 +50,7 @@ import org.apache.hc.core5.http.ProtocolVersion;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.ArgumentMatchers;
@@ -179,7 +180,7 @@ public class TestTestingFramework {
                                    final Map<String, Object> request,
                                    final TestingFrameworkRequestHandler requestHandler,
                                    final Map<String, Object> responseExpectations) throws TestingFrameworkException {
-                Assert.assertThat(defaultURI, matchesDefaultURI());
+                MatcherAssert.assertThat(defaultURI, matchesDefaultURI());
 
                 Assert.assertNotNull("request should not be null", request);
 
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2AlpnTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2AlpnTest.java
index 76e8d9a..b9b7cb6 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2AlpnTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2AlpnTest.java
@@ -65,7 +65,7 @@ import org.apache.hc.core5.testing.SSLTestContexts;
 import org.apache.hc.core5.util.ReflectionUtils;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assume;
 import org.junit.BeforeClass;
 import org.junit.Rule;
@@ -204,10 +204,10 @@ public class H2AlpnTest {
         }
 
         assertTrue("h2 negotiation was disabled, but h2 was negotiated", h2Allowed);
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
     }
 }
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2IntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2IntegrationTest.java
index 35b1a66..8493256 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2IntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2IntegrationTest.java
@@ -125,6 +125,7 @@ import org.apache.hc.core5.util.TextUtils;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -1048,11 +1049,11 @@ public class H2IntegrationTest extends InternalH2ServerTestBase {
             future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
             Assert.fail("ExecutionException is expected");
         } catch (final ExecutionException ex) {
-            Assert.assertThat(ex.getCause(), CoreMatchers.instanceOf(ProtocolException.class));
+            MatcherAssert.assertThat(ex.getCause(), CoreMatchers.instanceOf(ProtocolException.class));
         }
 
         final EndpointDetails endpointDetails = coreContext.getEndpointDetails();
-        Assert.assertThat(endpointDetails.getRequestCount(), CoreMatchers.equalTo(0L));
+        MatcherAssert.assertThat(endpointDetails.getRequestCount(), CoreMatchers.equalTo(0L));
     }
 
     @Test
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ProtocolNegotiationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ProtocolNegotiationTest.java
index b77d390..d97b8f5 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ProtocolNegotiationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ProtocolNegotiationTest.java
@@ -63,7 +63,7 @@ import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
 import org.apache.hc.core5.util.ReflectionUtils;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -184,10 +184,10 @@ public class H2ProtocolNegotiationTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
-        Assert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_1_1));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_1_1));
     }
 
     @Test
@@ -207,10 +207,10 @@ public class H2ProtocolNegotiationTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
-        Assert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_2));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_2));
     }
 
     @Test
@@ -230,14 +230,14 @@ public class H2ProtocolNegotiationTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
 
         if (isAlpnSupported()) {
-            Assert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_2));
+            MatcherAssert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_2));
         } else {
-            Assert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_1_1));
+            MatcherAssert.assertThat(response1.getVersion(), CoreMatchers.<ProtocolVersion>equalTo(HttpVersion.HTTP_1_1));
         }
     }
 
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndMultiplexingRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndMultiplexingRequesterTest.java
index 6a60017..325e6ea 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndMultiplexingRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndMultiplexingRequesterTest.java
@@ -67,7 +67,7 @@ import org.apache.hc.core5.util.ReflectionUtils;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -197,33 +197,33 @@ public class H2ServerAndMultiplexingRequesterTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/other-stuff",
                         new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture3 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/more-stuff",
                         new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message3, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message3, CoreMatchers.notNullValue());
         final HttpResponse response3 = message3.getHead();
-        Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body3 = message3.getBody();
-        Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+        MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
     }
 
     @Test
@@ -253,11 +253,11 @@ public class H2ServerAndMultiplexingRequesterTest {
         while (!queue.isEmpty()) {
             final Future<Message<HttpResponse, String>> resultFuture = queue.remove();
             final Message<HttpResponse, String> message = resultFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message, CoreMatchers.notNullValue());
             final HttpResponse response = message.getHead();
-            Assert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body = message.getBody();
-            Assert.assertThat(body, CoreMatchers.containsString("stuff"));
+            MatcherAssert.assertThat(body, CoreMatchers.containsString("stuff"));
         }
     }
 
@@ -276,11 +276,11 @@ public class H2ServerAndMultiplexingRequesterTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
         Thread.sleep(100);
 
@@ -289,11 +289,11 @@ public class H2ServerAndMultiplexingRequesterTest {
                         new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
 
         Thread.sleep(100);
 
@@ -302,11 +302,11 @@ public class H2ServerAndMultiplexingRequesterTest {
                         new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message3, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message3, CoreMatchers.notNullValue());
         final HttpResponse response3 = message3.getHead();
-        Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body3 = message3.getBody();
-        Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+        MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
     }
 
     @Test
@@ -350,7 +350,7 @@ public class H2ServerAndMultiplexingRequesterTest {
             Thread.sleep(random.nextInt(10));
             cancellable.cancel();
         }
-        Assert.assertThat(countDownLatch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(countDownLatch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()), CoreMatchers.equalTo(true));
     }
 
 }
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndRequesterTest.java
index fc8a0d0..f0e789d 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ServerAndRequesterTest.java
@@ -64,7 +64,7 @@ import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
 import org.apache.hc.core5.util.ReflectionUtils;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -200,33 +200,33 @@ public class H2ServerAndRequesterTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/other-stuff",
                         new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture3 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/more-stuff",
                         new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message3, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message3, CoreMatchers.notNullValue());
         final HttpResponse response3 = message3.getHead();
-        Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body3 = message3.getBody();
-        Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+        MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
     }
 
     @Test
@@ -247,33 +247,33 @@ public class H2ServerAndRequesterTest {
                             new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message1, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
             final HttpResponse response1 = message1.getHead();
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = message1.getBody();
-            Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
             final Future<Message<HttpResponse, String>> resultFuture2 = endpoint.execute(
                     new BasicRequestProducer(Method.POST, target, "/other-stuff",
                             new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message2, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
             final HttpResponse response2 = message2.getHead();
-            Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body2 = message2.getBody();
-            Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+            MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
 
             final Future<Message<HttpResponse, String>> resultFuture3 = endpoint.execute(
                     new BasicRequestProducer(Method.POST, target, "/more-stuff",
                             new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message3, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message3, CoreMatchers.notNullValue());
             final HttpResponse response3 = message3.getHead();
-            Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body3 = message3.getBody();
-            Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+            MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
 
         } finally {
             endpoint.releaseAndReuse();
@@ -311,11 +311,11 @@ public class H2ServerAndRequesterTest {
             while (!queue.isEmpty()) {
                 final Future<Message<HttpResponse, String>> resultFuture = queue.remove();
                 final Message<HttpResponse, String> message = resultFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-                Assert.assertThat(message, CoreMatchers.notNullValue());
+                MatcherAssert.assertThat(message, CoreMatchers.notNullValue());
                 final HttpResponse response = message.getHead();
-                Assert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+                MatcherAssert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
                 final String body = message.getBody();
-                Assert.assertThat(body, CoreMatchers.containsString("stuff"));
+                MatcherAssert.assertThat(body, CoreMatchers.containsString("stuff"));
             }
 
         } finally {
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java
index 0833c57..e95c460 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java
@@ -72,6 +72,7 @@ import org.apache.hc.core5.testing.SSLTestContexts;
 import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
@@ -176,16 +177,16 @@ public class H2TLSIntegrationTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
         final SSLSession sslSession = sslSessionRef.getAndSet(null);
         final ProtocolVersion tlsVersion = TLS.parse(sslSession.getProtocol());
-        Assert.assertThat(tlsVersion.greaterEquals(TLS.V_1_2.version), CoreMatchers.equalTo(true));
-        Assert.assertThat(sslSession.getPeerPrincipal().getName(),
+        MatcherAssert.assertThat(tlsVersion.greaterEquals(TLS.V_1_2.version), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(sslSession.getPeerPrincipal().getName(),
                 CoreMatchers.equalTo("CN=localhost,OU=Apache HttpComponents,O=Apache Software Foundation"));
     }
 
@@ -241,7 +242,7 @@ public class H2TLSIntegrationTest {
             Assert.fail("ExecutionException expected");
         } catch (final ExecutionException ex) {
             final Throwable cause = ex.getCause();
-            Assert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(SSLHandshakeException.class));
+            MatcherAssert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(SSLHandshakeException.class));
         }
     }
 
@@ -306,7 +307,7 @@ public class H2TLSIntegrationTest {
             Assert.fail("ExecutionException expected");
         } catch (final ExecutionException ex) {
             final Throwable cause = ex.getCause();
-            Assert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(IOException.class));
+            MatcherAssert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(IOException.class));
         }
     }
 
@@ -371,7 +372,7 @@ public class H2TLSIntegrationTest {
             Assert.fail("ExecutionException expected");
         } catch (final ExecutionException ex) {
             final Throwable cause = ex.getCause();
-            Assert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(IOException.class));
+            MatcherAssert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(IOException.class));
         }
     }
 
@@ -454,7 +455,7 @@ public class H2TLSIntegrationTest {
                     Assert.fail("ExecutionException expected");
                 } catch (final ExecutionException ex) {
                     final Throwable cause = ex.getCause();
-                    Assert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(IOException.class));
+                    MatcherAssert.assertThat(cause, CoreMatchers.<Throwable>instanceOf(IOException.class));
                 }
             } finally {
                 server.close(CloseMode.IMMEDIATE);
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java
index 8d12aa1..9b779cc 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1AuthenticationTest.java
@@ -67,7 +67,7 @@ import org.apache.hc.core5.reactor.ListenerEndpoint;
 import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExternalResource;
@@ -217,11 +217,11 @@ public class Http1AuthenticationTest {
                 new BasicRequestProducer(request1, null),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
 
         final HttpRequest request2 = new BasicHttpRequest(Method.GET, target, "/stuff");
         request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
@@ -229,11 +229,11 @@ public class Http1AuthenticationTest {
                 new BasicRequestProducer(request2, null),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo(""));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo(""));
     }
 
     @Test
@@ -255,11 +255,11 @@ public class Http1AuthenticationTest {
                 new BasicRequestProducer(request1, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
 
         final HttpRequest request2 = new BasicHttpRequest(Method.POST, target, "/stuff");
         request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
@@ -267,11 +267,11 @@ public class Http1AuthenticationTest {
                 new BasicRequestProducer(request2, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
     }
 
     @Test
@@ -295,11 +295,11 @@ public class Http1AuthenticationTest {
                 new BasicRequestProducer(request1, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
 
         final HttpRequest request2 = new BasicHttpRequest(Method.POST, target, "/stuff");
         request2.setVersion(HttpVersion.HTTP_1_0);
@@ -308,11 +308,11 @@ public class Http1AuthenticationTest {
                 new BasicRequestProducer(request2, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
     }
 
 }
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
index 2d961d7..4fd8002 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
@@ -76,7 +76,7 @@ import org.apache.hc.core5.testing.SSLTestContexts;
 import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExternalResource;
@@ -228,33 +228,33 @@ public class Http1ServerAndRequesterTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/other-stuff",
                         new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture3 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/more-stuff",
                         new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message3, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message3, CoreMatchers.notNullValue());
         final HttpResponse response3 = message3.getHead();
-        Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body3 = message3.getBody();
-        Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+        MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
     }
 
     @Test
@@ -271,33 +271,33 @@ public class Http1ServerAndRequesterTest {
                         new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
         final HttpResponse response1 = message1.getHead();
-        Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body1 = message1.getBody();
-        Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+        MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/no-keep-alive/other-stuff",
                         new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
         final HttpResponse response2 = message2.getHead();
-        Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body2 = message2.getBody();
-        Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+        MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
 
         final Future<Message<HttpResponse, String>> resultFuture3 = requester.execute(
                 new BasicRequestProducer(Method.POST, target, "/no-keep-alive/more-stuff",
                         new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
                 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
         final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assert.assertThat(message3, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(message3, CoreMatchers.notNullValue());
         final HttpResponse response3 = message3.getHead();
-        Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+        MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
         final String body3 = message3.getBody();
-        Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+        MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
     }
 
     @Test
@@ -318,33 +318,33 @@ public class Http1ServerAndRequesterTest {
                             new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message1, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message1, CoreMatchers.notNullValue());
             final HttpResponse response1 = message1.getHead();
-            Assert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body1 = message1.getBody();
-            Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
+            MatcherAssert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
 
             final Future<Message<HttpResponse, String>> resultFuture2 = endpoint.execute(
                     new BasicRequestProducer(Method.POST, target, "/other-stuff",
                             new StringAsyncEntityProducer("some other stuff", ContentType.TEXT_PLAIN)),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message2, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message2, CoreMatchers.notNullValue());
             final HttpResponse response2 = message2.getHead();
-            Assert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body2 = message2.getBody();
-            Assert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
+            MatcherAssert.assertThat(body2, CoreMatchers.equalTo("some other stuff"));
 
             final Future<Message<HttpResponse, String>> resultFuture3 = endpoint.execute(
                     new BasicRequestProducer(Method.POST, target, "/more-stuff",
                             new StringAsyncEntityProducer("some more stuff", ContentType.TEXT_PLAIN)),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
             final Message<HttpResponse, String> message3 = resultFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message3, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message3, CoreMatchers.notNullValue());
             final HttpResponse response3 = message3.getHead();
-            Assert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(response3.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
             final String body3 = message3.getBody();
-            Assert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
+            MatcherAssert.assertThat(body3, CoreMatchers.equalTo("some more stuff"));
 
         } finally {
             endpoint.releaseAndReuse();
@@ -382,11 +382,11 @@ public class Http1ServerAndRequesterTest {
             while (!queue.isEmpty()) {
                 final Future<Message<HttpResponse, String>> resultFuture = queue.remove();
                 final Message<HttpResponse, String> message = resultFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-                Assert.assertThat(message, CoreMatchers.notNullValue());
+                MatcherAssert.assertThat(message, CoreMatchers.notNullValue());
                 final HttpResponse response = message.getHead();
-                Assert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+                MatcherAssert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
                 final String body = message.getBody();
-                Assert.assertThat(body, CoreMatchers.containsString("stuff"));
+                MatcherAssert.assertThat(body, CoreMatchers.containsString("stuff"));
             }
 
         } finally {
@@ -415,10 +415,10 @@ public class Http1ServerAndRequesterTest {
         while (!queue.isEmpty()) {
             final Future<Message<HttpResponse, String>> resultFuture = queue.remove();
             final Message<HttpResponse, String> message = resultFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-            Assert.assertThat(message, CoreMatchers.notNullValue());
+            MatcherAssert.assertThat(message, CoreMatchers.notNullValue());
             final HttpResponse response = message.getHead();
-            Assert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
-            Assert.assertThat(message.getBody(), CoreMatchers.nullValue());
+            MatcherAssert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+            MatcherAssert.assertThat(message.getBody(), CoreMatchers.nullValue());
         }
     }
 
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexCancellable.java b/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexCancellable.java
index 8013dd9..9904576 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexCancellable.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexCancellable.java
@@ -27,6 +27,7 @@
 package org.apache.hc.core5.concurrent;
 
 import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -42,12 +43,12 @@ public class TestComplexCancellable {
         Assert.assertFalse(cancellable.isCancelled());
 
         cancellable.cancel();
-        Assert.assertThat(cancellable.isCancelled(), CoreMatchers.is(true));
-        Assert.assertThat(dependency1.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(cancellable.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(dependency1.isCancelled(), CoreMatchers.is(true));
 
         final BasicFuture<Object> dependency2 = new BasicFuture<>(null);
         cancellable.setDependency(dependency2);
-        Assert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
     }
 
 }
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexFuture.java b/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexFuture.java
index ed04a82..7653260 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexFuture.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/concurrent/TestComplexFuture.java
@@ -29,6 +29,7 @@ package org.apache.hc.core5.concurrent;
 import java.util.concurrent.Future;
 
 import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -44,12 +45,12 @@ public class TestComplexFuture {
         Assert.assertFalse(future.isDone());
 
         future.cancel();
-        Assert.assertThat(future.isCancelled(), CoreMatchers.is(true));
-        Assert.assertThat(dependency1.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(future.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(dependency1.isCancelled(), CoreMatchers.is(true));
 
         final Future<Object> dependency2 = new BasicFuture<>(null);
         future.setDependency(dependency2);
-        Assert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
     }
 
     @Test
@@ -62,12 +63,12 @@ public class TestComplexFuture {
         Assert.assertFalse(future.isDone());
 
         future.completed(Boolean.TRUE);
-        Assert.assertThat(future.isCancelled(), CoreMatchers.is(false));
-        Assert.assertThat(dependency1.isCancelled(), CoreMatchers.is(false));
+        MatcherAssert.assertThat(future.isCancelled(), CoreMatchers.is(false));
+        MatcherAssert.assertThat(dependency1.isCancelled(), CoreMatchers.is(false));
 
         final Future<Object> dependency2 = new BasicFuture<>(null);
         future.setDependency(dependency2);
-        Assert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
     }
 
     @Test
@@ -86,12 +87,12 @@ public class TestComplexFuture {
         Assert.assertFalse(future.isDone());
 
         future.cancel();
-        Assert.assertThat(future.isCancelled(), CoreMatchers.is(true));
-        Assert.assertThat(dependency1.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(future.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(dependency1.isCancelled(), CoreMatchers.is(true));
 
         final Future<Object> dependency2 = new BasicFuture<>(null);
         future.setDependency(dependency2);
-        Assert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(dependency2.isCancelled(), CoreMatchers.is(true));
     }
 
 }
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/config/TestNamedElementChain.java b/httpcore5/src/test/java/org/apache/hc/core5/http/config/TestNamedElementChain.java
index 203d54d..67c2ad1 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/config/TestNamedElementChain.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/config/TestNamedElementChain.java
@@ -28,7 +28,7 @@
 package org.apache.hc.core5.http.config;
 
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Test;
 
 /**
@@ -39,59 +39,59 @@ public class TestNamedElementChain {
     @Test
     public void testBasics() {
         final NamedElementChain<Character> list = new NamedElementChain<>();
-        Assert.assertThat(list.getFirst(), CoreMatchers.nullValue());
-        Assert.assertThat(list.getLast(), CoreMatchers.nullValue());
+        MatcherAssert.assertThat(list.getFirst(), CoreMatchers.nullValue());
+        MatcherAssert.assertThat(list.getLast(), CoreMatchers.nullValue());
 
         final NamedElementChain<Character>.Node nodeA = list.addFirst('a', "a");
 
-        Assert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeA));
-        Assert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeA));
+        MatcherAssert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeA));
+        MatcherAssert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeA));
 
         final NamedElementChain<Character>.Node nodeB = list.addLast('b', "b");
 
-        Assert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeA));
-        Assert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeB));
+        MatcherAssert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeA));
+        MatcherAssert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeB));
 
         final NamedElementChain<Character>.Node nodeZ = list.addLast('z', "z");
 
-        Assert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeA));
-        Assert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeZ));
+        MatcherAssert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeA));
+        MatcherAssert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeZ));
 
-        Assert.assertThat(nodeA.getPrevious(), CoreMatchers.nullValue());
-        Assert.assertThat(nodeA.getNext(), CoreMatchers.sameInstance(nodeB));
-        Assert.assertThat(nodeB.getPrevious(), CoreMatchers.sameInstance(nodeA));
-        Assert.assertThat(nodeB.getNext(), CoreMatchers.sameInstance(nodeZ));
-        Assert.assertThat(nodeZ.getPrevious(), CoreMatchers.sameInstance(nodeB));
-        Assert.assertThat(nodeZ.getNext(), CoreMatchers.nullValue());
+        MatcherAssert.assertThat(nodeA.getPrevious(), CoreMatchers.nullValue());
+        MatcherAssert.assertThat(nodeA.getNext(), CoreMatchers.sameInstance(nodeB));
+        MatcherAssert.assertThat(nodeB.getPrevious(), CoreMatchers.sameInstance(nodeA));
+        MatcherAssert.assertThat(nodeB.getNext(), CoreMatchers.sameInstance(nodeZ));
+        MatcherAssert.assertThat(nodeZ.getPrevious(), CoreMatchers.sameInstance(nodeB));
+        MatcherAssert.assertThat(nodeZ.getNext(), CoreMatchers.nullValue());
 
         final NamedElementChain<Character>.Node nodeD = list.addAfter("b", 'd', "d");
-        Assert.assertThat(nodeD.getPrevious(), CoreMatchers.sameInstance(nodeB));
-        Assert.assertThat(nodeD.getNext(), CoreMatchers.sameInstance(nodeZ));
-        Assert.assertThat(nodeB.getNext(), CoreMatchers.sameInstance(nodeD));
-        Assert.assertThat(nodeZ.getPrevious(), CoreMatchers.sameInstance(nodeD));
+        MatcherAssert.assertThat(nodeD.getPrevious(), CoreMatchers.sameInstance(nodeB));
+        MatcherAssert.assertThat(nodeD.getNext(), CoreMatchers.sameInstance(nodeZ));
+        MatcherAssert.assertThat(nodeB.getNext(), CoreMatchers.sameInstance(nodeD));
+        MatcherAssert.assertThat(nodeZ.getPrevious(), CoreMatchers.sameInstance(nodeD));
 
         final NamedElementChain<Character>.Node nodeC = list.addBefore("d", 'c', "c");
-        Assert.assertThat(nodeC.getPrevious(), CoreMatchers.sameInstance(nodeB));
-        Assert.assertThat(nodeC.getNext(), CoreMatchers.sameInstance(nodeD));
-        Assert.assertThat(nodeB.getNext(), CoreMatchers.sameInstance(nodeC));
-        Assert.assertThat(nodeD.getPrevious(), CoreMatchers.sameInstance(nodeC));
-        Assert.assertThat(list.getSize(), CoreMatchers.equalTo(5));
-
-        Assert.assertThat(list.remove("a"), CoreMatchers.is(true));
-        Assert.assertThat(list.remove("z"), CoreMatchers.is(true));
-        Assert.assertThat(list.remove("c"), CoreMatchers.is(true));
-        Assert.assertThat(list.remove("c"), CoreMatchers.is(false));
-        Assert.assertThat(list.remove("blah"), CoreMatchers.is(false));
-
-        Assert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeB));
-        Assert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeD));
-
-        Assert.assertThat(list.getSize(), CoreMatchers.equalTo(2));
-        Assert.assertThat(list.addBefore("blah", 'e', "e"), CoreMatchers.nullValue());
-        Assert.assertThat(list.getSize(), CoreMatchers.equalTo(2));
-
-        Assert.assertThat(list.addAfter("yada", 'e', "e"), CoreMatchers.nullValue());
-        Assert.assertThat(list.getSize(), CoreMatchers.equalTo(2));
+        MatcherAssert.assertThat(nodeC.getPrevious(), CoreMatchers.sameInstance(nodeB));
+        MatcherAssert.assertThat(nodeC.getNext(), CoreMatchers.sameInstance(nodeD));
+        MatcherAssert.assertThat(nodeB.getNext(), CoreMatchers.sameInstance(nodeC));
+        MatcherAssert.assertThat(nodeD.getPrevious(), CoreMatchers.sameInstance(nodeC));
+        MatcherAssert.assertThat(list.getSize(), CoreMatchers.equalTo(5));
+
+        MatcherAssert.assertThat(list.remove("a"), CoreMatchers.is(true));
+        MatcherAssert.assertThat(list.remove("z"), CoreMatchers.is(true));
+        MatcherAssert.assertThat(list.remove("c"), CoreMatchers.is(true));
+        MatcherAssert.assertThat(list.remove("c"), CoreMatchers.is(false));
+        MatcherAssert.assertThat(list.remove("blah"), CoreMatchers.is(false));
+
+        MatcherAssert.assertThat(list.getFirst(), CoreMatchers.sameInstance(nodeB));
+        MatcherAssert.assertThat(list.getLast(), CoreMatchers.sameInstance(nodeD));
+
+        MatcherAssert.assertThat(list.getSize(), CoreMatchers.equalTo(2));
+        MatcherAssert.assertThat(list.addBefore("blah", 'e', "e"), CoreMatchers.nullValue());
+        MatcherAssert.assertThat(list.getSize(), CoreMatchers.equalTo(2));
+
+        MatcherAssert.assertThat(list.addAfter("yada", 'e', "e"), CoreMatchers.nullValue());
+        MatcherAssert.assertThat(list.getSize(), CoreMatchers.equalTo(2));
     }
 
 }
\ No newline at end of file
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestExpandableBuffer.java b/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestExpandableBuffer.java
index 4f0dfe7..d98d3fc 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestExpandableBuffer.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestExpandableBuffer.java
@@ -28,7 +28,7 @@
 package org.apache.hc.core5.http.impl.nio;
 
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Test;
 
 public class TestExpandableBuffer {
@@ -36,47 +36,47 @@ public class TestExpandableBuffer {
     @Test
     public void testBasics() throws Exception {
         final ExpandableBuffer buffer = new ExpandableBuffer(16);
-        Assert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.INPUT));
-        Assert.assertThat(buffer.hasData(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.INPUT));
+        MatcherAssert.assertThat(buffer.hasData(), CoreMatchers.equalTo(false));
 
         buffer.setInputMode();
         buffer.buffer().put(new byte[] { 0, 1, 2, 3, 4, 5});
-        Assert.assertThat(buffer.hasData(), CoreMatchers.equalTo(true));
-        Assert.assertThat(buffer.length(), CoreMatchers.equalTo(6));
-        Assert.assertThat(buffer.buffer().capacity(), CoreMatchers.equalTo(16));
-        Assert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.OUTPUT));
+        MatcherAssert.assertThat(buffer.hasData(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(buffer.length(), CoreMatchers.equalTo(6));
+        MatcherAssert.assertThat(buffer.buffer().capacity(), CoreMatchers.equalTo(16));
+        MatcherAssert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.OUTPUT));
 
         buffer.setInputMode();
         buffer.buffer().put(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
-        Assert.assertThat(buffer.length(), CoreMatchers.equalTo(16));
-        Assert.assertThat(buffer.buffer().capacity(), CoreMatchers.equalTo(16));
-        Assert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.OUTPUT));
+        MatcherAssert.assertThat(buffer.length(), CoreMatchers.equalTo(16));
+        MatcherAssert.assertThat(buffer.buffer().capacity(), CoreMatchers.equalTo(16));
+        MatcherAssert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.OUTPUT));
 
         buffer.setInputMode();
         buffer.ensureCapacity(22);
         buffer.buffer().put(new byte[] { 0, 1, 2, 3, 4, 5});
-        Assert.assertThat(buffer.length(), CoreMatchers.equalTo(22));
-        Assert.assertThat(buffer.buffer().capacity(), CoreMatchers.equalTo(22));
-        Assert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.OUTPUT));
+        MatcherAssert.assertThat(buffer.length(), CoreMatchers.equalTo(22));
+        MatcherAssert.assertThat(buffer.buffer().capacity(), CoreMatchers.equalTo(22));
+        MatcherAssert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.OUTPUT));
 
         buffer.clear();
-        Assert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.INPUT));
-        Assert.assertThat(buffer.hasData(), CoreMatchers.equalTo(false));
-        Assert.assertThat(buffer.capacity(), CoreMatchers.equalTo(22));
+        MatcherAssert.assertThat(buffer.mode(), CoreMatchers.equalTo(ExpandableBuffer.Mode.INPUT));
+        MatcherAssert.assertThat(buffer.hasData(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(buffer.capacity(), CoreMatchers.equalTo(22));
     }
 
     @Test
     public void testAdjustCapacity() throws Exception {
         final ExpandableBuffer buffer = new ExpandableBuffer(16);
-        Assert.assertThat(buffer.capacity(), CoreMatchers.equalTo(16));
+        MatcherAssert.assertThat(buffer.capacity(), CoreMatchers.equalTo(16));
 
         buffer.ensureCapacity(21);
-        Assert.assertThat(buffer.capacity(), CoreMatchers.equalTo(21));
+        MatcherAssert.assertThat(buffer.capacity(), CoreMatchers.equalTo(21));
         buffer.ensureAdjustedCapacity(22);
-        Assert.assertThat(buffer.capacity(), CoreMatchers.equalTo(1024));
+        MatcherAssert.assertThat(buffer.capacity(), CoreMatchers.equalTo(1024));
         buffer.ensureAdjustedCapacity(1024);
-        Assert.assertThat(buffer.capacity(), CoreMatchers.equalTo(1024));
+        MatcherAssert.assertThat(buffer.capacity(), CoreMatchers.equalTo(1024));
         buffer.ensureAdjustedCapacity(1025);
-        Assert.assertThat(buffer.capacity(), CoreMatchers.equalTo(2048));
+        MatcherAssert.assertThat(buffer.capacity(), CoreMatchers.equalTo(2048));
     }
 }
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/ssl/TestTlsVersionParser.java b/httpcore5/src/test/java/org/apache/hc/core5/http/ssl/TestTlsVersionParser.java
index 221f49d..7966ae2 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/ssl/TestTlsVersionParser.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/ssl/TestTlsVersionParser.java
@@ -31,7 +31,7 @@ import org.apache.hc.core5.http.ParseException;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.util.Tokenizer;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -49,19 +49,19 @@ public class TestTlsVersionParser {
 
     @Test
     public void testParseBasic() throws Exception {
-        Assert.assertThat(impl.parse("TLSv1"), CoreMatchers.equalTo(TLS.V_1_0.version));
-        Assert.assertThat(impl.parse("TLSv1.1"), CoreMatchers.equalTo(TLS.V_1_1.version));
-        Assert.assertThat(impl.parse("TLSv1.2"), CoreMatchers.equalTo(TLS.V_1_2.version));
-        Assert.assertThat(impl.parse("TLSv1.3"), CoreMatchers.equalTo(TLS.V_1_3.version));
-        Assert.assertThat(impl.parse("TLSv22.356"), CoreMatchers.equalTo(new ProtocolVersion("TLS", 22, 356)));
+        MatcherAssert.assertThat(impl.parse("TLSv1"), CoreMatchers.equalTo(TLS.V_1_0.version));
+        MatcherAssert.assertThat(impl.parse("TLSv1.1"), CoreMatchers.equalTo(TLS.V_1_1.version));
+        MatcherAssert.assertThat(impl.parse("TLSv1.2"), CoreMatchers.equalTo(TLS.V_1_2.version));
+        MatcherAssert.assertThat(impl.parse("TLSv1.3"), CoreMatchers.equalTo(TLS.V_1_3.version));
+        MatcherAssert.assertThat(impl.parse("TLSv22.356"), CoreMatchers.equalTo(new ProtocolVersion("TLS", 22, 356)));
     }
 
     @Test
     public void testParseBuffer() throws Exception {
         final Tokenizer.Cursor cursor = new Tokenizer.Cursor(1, 13);
-        Assert.assertThat(impl.parse(" TLSv1.2,0000", cursor, Tokenizer.INIT_BITSET(',')),
+        MatcherAssert.assertThat(impl.parse(" TLSv1.2,0000", cursor, Tokenizer.INIT_BITSET(',')),
                 CoreMatchers.equalTo(TLS.V_1_2.version));
-        Assert.assertThat(cursor.getPos(), CoreMatchers.equalTo(8));
+        MatcherAssert.assertThat(cursor.getPos(), CoreMatchers.equalTo(8));
     }
 
     @Test(expected = ParseException.class)
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/reactor/TestAbstractIOSessionPool.java b/httpcore5/src/test/java/org/apache/hc/core5/reactor/TestAbstractIOSessionPool.java
index fe87e61..83febce 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/reactor/TestAbstractIOSessionPool.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/reactor/TestAbstractIOSessionPool.java
@@ -34,7 +34,7 @@ import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
+import org.hamcrest.MatcherAssert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -92,9 +92,9 @@ public class TestAbstractIOSessionPool {
         Mockito.when(ioSession1.isOpen()).thenReturn(true);
 
         final Future<IOSession> future1 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
-        Assert.assertThat(future1, CoreMatchers.notNullValue());
-        Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
-        Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
+        MatcherAssert.assertThat(future1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
 
         Mockito.verify(impl).connectSession(
                 ArgumentMatchers.eq("somehost"),
@@ -102,9 +102,9 @@ public class TestAbstractIOSessionPool {
                 ArgumentMatchers.<FutureCallback<IOSession>>any());
 
         final Future<IOSession> future2 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
-        Assert.assertThat(future2, CoreMatchers.notNullValue());
-        Assert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
-        Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
+        MatcherAssert.assertThat(future2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
 
         Mockito.verify(impl, Mockito.times(1)).connectSession(
                 ArgumentMatchers.eq("somehost"),
@@ -119,11 +119,11 @@ public class TestAbstractIOSessionPool {
 
                 }));
 
-        Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
-        Assert.assertThat(future1.get(), CoreMatchers.sameInstance(ioSession1));
+        MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(future1.get(), CoreMatchers.sameInstance(ioSession1));
 
-        Assert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
-        Assert.assertThat(future2.get(), CoreMatchers.sameInstance(ioSession1));
+        MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(future2.get(), CoreMatchers.sameInstance(ioSession1));
 
         Mockito.verify(impl, Mockito.times(2)).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
 
@@ -136,8 +136,8 @@ public class TestAbstractIOSessionPool {
 
         Mockito.verify(impl, Mockito.times(3)).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
 
-        Assert.assertThat(future3.isDone(), CoreMatchers.equalTo(true));
-        Assert.assertThat(future3.get(), CoreMatchers.sameInstance(ioSession1));
+        MatcherAssert.assertThat(future3.isDone(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(future3.get(), CoreMatchers.sameInstance(ioSession1));
     }
 
     @Test
@@ -149,9 +149,9 @@ public class TestAbstractIOSessionPool {
                 ArgumentMatchers.<FutureCallback<IOSession>>any())).thenReturn(connectFuture);
 
         final Future<IOSession> future1 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
-        Assert.assertThat(future1, CoreMatchers.notNullValue());
-        Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
-        Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
+        MatcherAssert.assertThat(future1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
 
         Mockito.verify(impl).connectSession(
                 ArgumentMatchers.eq("somehost"),
@@ -159,9 +159,9 @@ public class TestAbstractIOSessionPool {
                 ArgumentMatchers.<FutureCallback<IOSession>>any());
 
         final Future<IOSession> future2 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
-        Assert.assertThat(future2, CoreMatchers.notNullValue());
-        Assert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
-        Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
+        MatcherAssert.assertThat(future2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
 
         Mockito.verify(impl, Mockito.times(1)).connectSession(
                 ArgumentMatchers.eq("somehost"),
@@ -176,22 +176,22 @@ public class TestAbstractIOSessionPool {
 
                 }));
 
-        Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
-        Assert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
     }
 
     @Test
     public void testShutdownPool() throws Exception {
         final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("host1");
-        Assert.assertThat(entry1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
         entry1.session = ioSession1;
 
         final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
-        Assert.assertThat(entry2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry2, CoreMatchers.notNullValue());
         entry2.session = ioSession2;
 
         final AbstractIOSessionPool.PoolEntry entry3 = impl.getPoolEntry("host3");
-        Assert.assertThat(entry3, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry3, CoreMatchers.notNullValue());
         entry3.sessionFuture = connectFuture;
         entry3.requestQueue.add(callback1);
         entry3.requestQueue.add(callback2);
@@ -208,11 +208,11 @@ public class TestAbstractIOSessionPool {
     @Test
     public void testCloseIdleSessions() throws Exception {
         final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("host1");
-        Assert.assertThat(entry1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
         entry1.session = ioSession1;
 
         final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
-        Assert.assertThat(entry2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry2, CoreMatchers.notNullValue());
         entry2.session = ioSession2;
 
         impl.closeIdle(TimeValue.ZERO_MILLISECONDS);
@@ -220,18 +220,18 @@ public class TestAbstractIOSessionPool {
         Mockito.verify(impl).closeSession(ioSession1, CloseMode.GRACEFUL);
         Mockito.verify(impl).closeSession(ioSession2, CloseMode.GRACEFUL);
 
-        Assert.assertThat(entry1.session, CoreMatchers.nullValue());
-        Assert.assertThat(entry2.session, CoreMatchers.nullValue());
+        MatcherAssert.assertThat(entry1.session, CoreMatchers.nullValue());
+        MatcherAssert.assertThat(entry2.session, CoreMatchers.nullValue());
     }
 
     @Test
     public void testEnumSessions() throws Exception {
         final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("host1");
-        Assert.assertThat(entry1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
         entry1.session = ioSession1;
 
         final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
-        Assert.assertThat(entry2, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry2, CoreMatchers.notNullValue());
         entry2.session = ioSession2;
 
         impl.enumAvailable(new Callback<IOSession>() {
@@ -249,7 +249,7 @@ public class TestAbstractIOSessionPool {
     @Test
     public void testGetSessionReconnectAfterValidate() throws Exception {
         final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("somehost");
-        Assert.assertThat(entry1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
         entry1.session = ioSession1;
 
         Mockito.when(ioSession1.isOpen()).thenReturn(true);
@@ -275,7 +275,7 @@ public class TestAbstractIOSessionPool {
     @Test
     public void testGetSessionReconnectIfClosed() throws Exception {
         final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("somehost");
-        Assert.assertThat(entry1, CoreMatchers.notNullValue());
+        MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
         entry1.session = ioSession1;
 
         Mockito.when(ioSession1.isOpen()).thenReturn(false);
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/util/TestTimeValue.java b/httpcore5/src/test/java/org/apache/hc/core5/util/TestTimeValue.java
index 18bc451..89ee793 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/util/TestTimeValue.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/util/TestTimeValue.java
@@ -31,6 +31,7 @@ import java.text.ParseException;
 import java.util.concurrent.TimeUnit;
 
 import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -271,19 +272,19 @@ public class TestTimeValue {
         final TimeValue tv4 = TimeValue.ofSeconds(1L);
         final TimeValue tv5 = TimeValue.ofSeconds(1000L);
 
-        Assert.assertThat(tv1.equals(tv1), CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.equals(null), CoreMatchers.equalTo(false));
-        Assert.assertThat(tv1.equals(tv2), CoreMatchers.equalTo(false));
-        Assert.assertThat(tv1.equals(tv3), CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.equals(tv4), CoreMatchers.equalTo(true));
-        Assert.assertThat(tv4.equals(tv1), CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.equals(tv5), CoreMatchers.equalTo(false));
-
-        Assert.assertThat(tv1.hashCode() == tv2.hashCode(), CoreMatchers.equalTo(false));
-        Assert.assertThat(tv1.hashCode() == tv3.hashCode(), CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.hashCode() == tv4.hashCode(), CoreMatchers.equalTo(true));
-        Assert.assertThat(tv4.hashCode() == tv1.hashCode(), CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.hashCode() == tv5.hashCode(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(tv1.equals(tv1), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.equals(null), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(tv1.equals(tv2), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(tv1.equals(tv3), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.equals(tv4), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv4.equals(tv1), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.equals(tv5), CoreMatchers.equalTo(false));
+
+        MatcherAssert.assertThat(tv1.hashCode() == tv2.hashCode(), CoreMatchers.equalTo(false));
+        MatcherAssert.assertThat(tv1.hashCode() == tv3.hashCode(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.hashCode() == tv4.hashCode(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv4.hashCode() == tv1.hashCode(), CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.hashCode() == tv5.hashCode(), CoreMatchers.equalTo(false));
     }
 
     @Test
@@ -295,13 +296,13 @@ public class TestTimeValue {
         final TimeValue tv5 = TimeValue.ofSeconds(60L);
         final TimeValue tv6 = TimeValue.ofMinutes(1L);
 
-        Assert.assertThat(tv1.compareTo(tv1) == 0, CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.compareTo(tv2) < 0, CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.compareTo(tv3) == 0, CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.compareTo(tv4) == 0, CoreMatchers.equalTo(true));
-        Assert.assertThat(tv1.compareTo(tv5) < 0, CoreMatchers.equalTo(true));
-        Assert.assertThat(tv6.compareTo(tv5) == 0, CoreMatchers.equalTo(true));
-        Assert.assertThat(tv6.compareTo(tv4) > 0, CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.compareTo(tv1) == 0, CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.compareTo(tv2) < 0, CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.compareTo(tv3) == 0, CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.compareTo(tv4) == 0, CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv1.compareTo(tv5) < 0, CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv6.compareTo(tv5) == 0, CoreMatchers.equalTo(true));
+        MatcherAssert.assertThat(tv6.compareTo(tv4) > 0, CoreMatchers.equalTo(true));
         try {
             tv1.compareTo(null);
             Assert.fail("NullPointerException expected");


[httpcomponents-core] 05/10: BasicHttpRequest to support absolute request URI representation

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 373b6800d837d29b7538c08665c33e61659880d5
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue Feb 9 17:53:42 2021 +0100

    BasicHttpRequest to support absolute request URI representation
---
 .../http/io/support/ClassicRequestBuilder.java     |  7 +++
 .../hc/core5/http/message/BasicHttpRequest.java    | 62 +++++++++++++++-------
 .../http/nio/support/AsyncRequestBuilder.java      |  7 +++
 .../core5/http/support/AbstractRequestBuilder.java | 10 ++++
 .../hc/core5/http/support/BasicRequestBuilder.java |  7 +++
 .../hc/core5/http/message/TestBasicMessages.java   |  8 +++
 6 files changed, 82 insertions(+), 19 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
index 5c407f5..cd8835b 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/support/ClassicRequestBuilder.java
@@ -273,6 +273,12 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
         return this;
     }
 
+    @Override
+    public ClassicRequestBuilder setAbsoluteRequestUri(final boolean absoluteRequestUri) {
+        super.setAbsoluteRequestUri(absoluteRequestUri);
+        return this;
+    }
+
     public HttpEntity getEntity() {
         return entity;
     }
@@ -328,6 +334,7 @@ public class ClassicRequestBuilder extends AbstractRequestBuilder<ClassicHttpReq
         result.setVersion(getVersion());
         result.setHeaders(getHeaders());
         result.setEntity(entityCopy);
+        result.setAbsoluteRequestUri(isAbsoluteRequestUri());
         return result;
     }
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
index ac93392..ed94598 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
@@ -54,6 +54,7 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
     private URIAuthority authority;
     private ProtocolVersion version;
     private URI requestUri;
+    private boolean absoluteRequestUri;
 
     /**
      * Creates request message with the given method and request path.
@@ -218,9 +219,27 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
         this.requestUri = null;
     }
 
+    /**
+     * Sets a flag that the {@link #getRequestUri()} method should return the request URI
+     * in an absolute form.
+     * <p>
+     * This flag can used when the request is going to be transmitted via an HTTP/1.1 proxy.
+     *
+     * @since 5.1
+     */
+    public void setAbsoluteRequestUri(final boolean absoluteRequestUri) {
+        this.absoluteRequestUri = absoluteRequestUri;
+    }
+
     @Override
     public String getRequestUri() {
-        return getPath();
+        if (absoluteRequestUri) {
+            final StringBuilder buf = new StringBuilder();
+            assembleRequestUri(buf);
+            return buf.toString();
+        } else {
+            return getPath();
+        }
     }
 
     @Override
@@ -253,25 +272,29 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
         this.path = buf.toString();
     }
 
+    private void assembleRequestUri(final StringBuilder buf) {
+        if (this.authority != null) {
+            buf.append(this.scheme != null ? this.scheme : URIScheme.HTTP.id).append("://");
+            buf.append(this.authority.getHostName());
+            if (this.authority.getPort() >= 0) {
+                buf.append(":").append(this.authority.getPort());
+            }
+        }
+        if (this.path == null) {
+            buf.append("/");
+        } else {
+            if (buf.length() > 0 && !this.path.startsWith("/")) {
+                buf.append("/");
+            }
+            buf.append(this.path);
+        }
+    }
+
     @Override
     public URI getUri() throws URISyntaxException {
         if (this.requestUri == null) {
             final StringBuilder buf = new StringBuilder();
-            if (this.authority != null) {
-                buf.append(this.scheme != null ? this.scheme : URIScheme.HTTP.id).append("://");
-                buf.append(this.authority.getHostName());
-                if (this.authority.getPort() >= 0) {
-                    buf.append(":").append(this.authority.getPort());
-                }
-            }
-            if (this.path == null) {
-                buf.append("/");
-            } else {
-                if (buf.length() > 0 && !this.path.startsWith("/")) {
-                    buf.append("/");
-                }
-                buf.append(this.path);
-            }
+            assembleRequestUri(buf);
             this.requestUri = new URI(buf.toString());
         }
         return this.requestUri;
@@ -279,9 +302,10 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
 
     @Override
     public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append(this.method).append(" ").append(this.scheme).append("://").append(this.authority).append(this.path);
-        return sb.toString();
+        final StringBuilder buf = new StringBuilder();
+        buf.append(method).append(" ");
+        assembleRequestUri(buf);
+        return buf.toString();
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
index a80737c..52212b6 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/support/AsyncRequestBuilder.java
@@ -273,6 +273,12 @@ public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProd
         return this;
     }
 
+    @Override
+    public AsyncRequestBuilder setAbsoluteRequestUri(final boolean absoluteRequestUri) {
+        super.setAbsoluteRequestUri(absoluteRequestUri);
+        return this;
+    }
+
     public AsyncEntityProducer getEntity() {
         return entityProducer;
     }
@@ -333,6 +339,7 @@ public class AsyncRequestBuilder extends AbstractRequestBuilder<AsyncRequestProd
         final BasicHttpRequest request = new BasicHttpRequest(method, uriCopy);
         request.setVersion(getVersion());
         request.setHeaders(getHeaders());
+        request.setAbsoluteRequestUri(isAbsoluteRequestUri());
         return new BasicRequestProducer(request, entityProducerCopy);
     }
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
index 9c3c801..e01e439 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/AbstractRequestBuilder.java
@@ -51,6 +51,7 @@ public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T
     private URI uri;
     private Charset charset;
     private List<NameValuePair> parameters;
+    private boolean absoluteRequestUri;
 
     protected AbstractRequestBuilder(final String method) {
         super();
@@ -180,4 +181,13 @@ public abstract class AbstractRequestBuilder<T> extends AbstractMessageBuilder<T
         return this;
     }
 
+    public boolean isAbsoluteRequestUri() {
+        return absoluteRequestUri;
+    }
+
+    public AbstractRequestBuilder<T> setAbsoluteRequestUri(final boolean absoluteRequestUri) {
+        this.absoluteRequestUri = absoluteRequestUri;
+        return this;
+    }
+
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
index dab7bb7..74d3001 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/support/BasicRequestBuilder.java
@@ -258,6 +258,12 @@ public class BasicRequestBuilder extends AbstractRequestBuilder<BasicHttpRequest
     }
 
     @Override
+    public BasicRequestBuilder setAbsoluteRequestUri(final boolean absoluteRequestUri) {
+        super.setAbsoluteRequestUri(absoluteRequestUri);
+        return this;
+    }
+
+    @Override
     public BasicHttpRequest build() {
         URI uri = getUri();
         final List<NameValuePair> parameters = getParameters();
@@ -274,6 +280,7 @@ public class BasicRequestBuilder extends AbstractRequestBuilder<BasicHttpRequest
         final BasicHttpRequest result = new BasicHttpRequest(getMethod(), uri != null ? uri : URI.create("/"));
         result.setVersion(getVersion());
         result.setHeaders(getHeaders());
+        result.setAbsoluteRequestUri(isAbsoluteRequestUri());
         return result;
     }
 
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
index 86d3c96..020d6a3 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
@@ -219,5 +219,13 @@ public class TestBasicMessages {
         new BasicHttpRequest(Method.GET, URI.create("http://host//stuff"));
     }
 
+    @Test
+    public void testRequestAbsoluteRequestUri() throws Exception {
+        final BasicHttpRequest request = new BasicHttpRequest(Method.GET, new HttpHost("http", "somehost", -1), "stuff");
+        Assert.assertEquals("stuff", request.getRequestUri());
+        request.setAbsoluteRequestUri(true);
+        Assert.assertEquals("http://somehost/stuff", request.getRequestUri());
+    }
+
 }