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 2023/12/13 08:24:00 UTC

(httpcomponents-core) 33/37: HTTPCORE-756: Support for the effective HTTP/1.x protocol level config parameter; HTTP/1.1 endpoints to signal their actual supported protocol level (the minor version in HTTP/1.x) in the message control data as per RFC 9110 section 6.2

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 51f3be8b9e203f5b923733d44909fd9b15179a31
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Tue Oct 10 11:38:42 2023 +0200

    HTTPCORE-756: Support for the effective HTTP/1.x protocol level config parameter; HTTP/1.1 endpoints to signal their actual supported protocol level (the minor version in HTTP/1.x) in the message control data as per RFC 9110 section 6.2
---
 .../impl/nio/bootstrap/H2ServerBootstrap.java      |  4 +-
 .../core5/testing/classic/ClassicTestClient.java   |  2 +-
 .../InternalServerHttp1EventHandlerFactory.java    |  2 +-
 .../testing/classic/ClassicIntegrationTest.java    | 62 ++++++++++------------
 .../testing/framework/TestTestingFramework.java    | 27 ----------
 .../hc/core5/testing/nio/Http1IntegrationTest.java | 62 ++++++++--------------
 .../apache/hc/core5/http/config/Http1Config.java   | 39 ++++++++++++--
 .../http/impl/bootstrap/AsyncServerBootstrap.java  |  6 +--
 .../http/impl/bootstrap/RequesterBootstrap.java    | 13 ++++-
 .../core5/http/impl/bootstrap/ServerBootstrap.java |  3 +-
 .../core5/http/impl/io/AbstractMessageParser.java  | 21 ++++----
 .../http/impl/io/DefaultBHttpClientConnection.java |  2 +-
 .../io/DefaultBHttpClientConnectionFactory.java    |  6 ++-
 .../http/impl/io/DefaultBHttpServerConnection.java |  2 +-
 .../io/DefaultBHttpServerConnectionFactory.java    |  6 ++-
 .../http/impl/io/DefaultHttpRequestParser.java     | 30 ++++++-----
 .../impl/io/DefaultHttpRequestParserFactory.java   | 32 ++++++++++-
 .../http/impl/io/DefaultHttpRequestWriter.java     | 33 ++++++++----
 .../impl/io/DefaultHttpRequestWriterFactory.java   | 23 ++++++--
 .../http/impl/io/DefaultHttpResponseParser.java    | 28 +++++-----
 .../impl/io/DefaultHttpResponseParserFactory.java  | 32 ++++++++++-
 .../http/impl/io/DefaultHttpResponseWriter.java    | 33 ++++++++----
 .../impl/io/DefaultHttpResponseWriterFactory.java  | 23 ++++++--
 .../hc/core5/http/impl/io/HttpRequestExecutor.java | 42 +++++++++++----
 .../apache/hc/core5/http/impl/io/HttpService.java  | 49 ++++++++++++++---
 .../core5/http/impl/nio/AbstractMessageParser.java | 37 ++++++-------
 .../impl/nio/ClientHttp1StreamDuplexerFactory.java |  4 +-
 .../http/impl/nio/ClientHttp1StreamHandler.java    | 16 ++++--
 .../http/impl/nio/DefaultHttpRequestParser.java    | 45 ++++++++++------
 .../impl/nio/DefaultHttpRequestParserFactory.java  |  2 +-
 .../http/impl/nio/DefaultHttpRequestWriter.java    | 29 ++++++++--
 .../impl/nio/DefaultHttpRequestWriterFactory.java  | 23 ++++++--
 .../http/impl/nio/DefaultHttpResponseParser.java   | 39 +++++++++-----
 .../impl/nio/DefaultHttpResponseParserFactory.java |  2 +-
 .../http/impl/nio/DefaultHttpResponseWriter.java   | 29 ++++++++--
 .../impl/nio/DefaultHttpResponseWriterFactory.java | 23 ++++++--
 .../http/impl/nio/ServerHttp1StreamDuplexer.java   |  4 ++
 .../impl/nio/ServerHttp1StreamDuplexerFactory.java |  4 +-
 .../http/impl/nio/ServerHttp1StreamHandler.java    | 14 +++--
 .../hc/core5/http/io/HttpMessageParserFactory.java |  8 +++
 40 files changed, 578 insertions(+), 283 deletions(-)

diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
index d60f84276..c7486c318 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
@@ -409,8 +409,8 @@ public class H2ServerBootstrap {
                 http1Config != null ? http1Config : Http1Config.DEFAULT,
                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
                 DefaultConnectionReuseStrategy.INSTANCE,
-                DefaultHttpRequestParserFactory.INSTANCE,
-                DefaultHttpResponseWriterFactory.INSTANCE,
+                new DefaultHttpRequestParserFactory(http1Config),
+                new DefaultHttpResponseWriterFactory(http1Config),
                 DefaultContentLengthStrategy.INSTANCE,
                 DefaultContentLengthStrategy.INSTANCE,
                 http1StreamListener);
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestClient.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestClient.java
index efb1730cd..d2951a73d 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestClient.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestClient.java
@@ -82,7 +82,7 @@ public class ClassicTestClient {
     public void start(final HttpProcessor httpProcessor) {
         if (requesterRef.get() == null) {
             final HttpRequestExecutor requestExecutor = new HttpRequestExecutor(
-                    HttpRequestExecutor.DEFAULT_WAIT_FOR_CONTINUE,
+                    Http1Config.DEFAULT,
                     DefaultConnectionReuseStrategy.INSTANCE,
                     LoggingHttp1StreamListener.INSTANCE);
             final StrictConnPool<HttpHost, HttpClientConnection> connPool = new StrictConnPool<>(
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java
index de55f629e..c7487ec62 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java
@@ -95,7 +95,7 @@ class InternalServerHttp1EventHandlerFactory implements IOEventHandlerFactory {
         this.sslSessionInitializer = sslSessionInitializer;
         this.sslSessionVerifier = sslSessionVerifier;
         this.requestParserFactory = new DefaultHttpRequestParserFactory(this.http1Config);
-        this.responseWriterFactory = DefaultHttpResponseWriterFactory.INSTANCE;
+        this.responseWriterFactory = new DefaultHttpResponseWriterFactory(this.http1Config);
     }
 
     protected ServerHttp1StreamDuplexer createServerHttp1StreamDuplexer(
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java
index fcfa8f389..f6f83bcfa 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java
@@ -49,6 +49,7 @@ import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.Method;
+import org.apache.hc.core5.http.ProtocolException;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
@@ -279,9 +280,6 @@ public abstract class ClassicIntegrationTest {
                 final byte[] data = EntityUtils.toByteArray(entity);
                 response.setEntity(new ByteArrayEntity(data, null));
             }
-            if (HttpVersion.HTTP_1_0.equals(request.getVersion())) {
-                response.addHeader("Version", "1.0");
-            }
         });
 
         server.start();
@@ -298,10 +296,6 @@ public abstract class ClassicIntegrationTest {
             post.setEntity(new ByteArrayEntity(data, null));
 
             try (final ClassicHttpResponse response = client.execute(host, post, context)) {
-                Assertions.assertEquals(HttpVersion.HTTP_1_1, response.getVersion());
-                final Header h1 = response.getFirstHeader("Version");
-                Assertions.assertNotNull(h1);
-                Assertions.assertEquals("1.0", h1.getValue());
                 final byte[] received = EntityUtils.toByteArray(response.getEntity());
                 final byte[] expected = testData.get(r);
 
@@ -313,6 +307,32 @@ public abstract class ClassicIntegrationTest {
         }
     }
 
+    /**
+     * This test case ensures that HTTP/1.1 features are disabled when executing
+     * HTTP/1.0 compatible requests.
+     */
+    @Test
+    public void testHTTP11FeaturesDisabledWithHTTP10Requests() throws Exception {
+        final ClassicTestServer server = testResources.server();
+        final ClassicTestClient client = testResources.client();
+
+        server.start();
+        client.start();
+
+        final HttpCoreContext context = HttpCoreContext.create();
+        final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
+
+        final BasicClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
+        post.setVersion(HttpVersion.HTTP_1_0);
+        post.setEntity(new ByteArrayEntity(new byte[] {'a', 'b', 'c'}, null, true));
+
+        Assertions.assertThrows(ProtocolException.class, () -> {
+            try (final ClassicHttpResponse response = client.execute(host, post, context)) {
+                EntityUtils.consume(response.getEntity());
+            }
+        });
+    }
+
     /**
      * This test case executes a series of simple POST requests using
      * the 'expect: continue' handshake.
@@ -690,34 +710,6 @@ public abstract class ClassicIntegrationTest {
         }
     }
 
-    @Test
-    public void testAbsentHostHeader() throws Exception {
-        final ClassicTestServer server = testResources.server();
-        final ClassicTestClient client = testResources.client();
-
-        // Initialize the server-side request handler
-        server.registerHandler("*", (request, response, context) -> response.setEntity(new StringEntity("All is well", StandardCharsets.US_ASCII)));
-
-        server.start();
-        client.start(new DefaultHttpProcessor(RequestContent.INSTANCE, new RequestConnControl()));
-
-        final HttpCoreContext context = HttpCoreContext.create();
-        final HttpHost host = new HttpHost(scheme.id, "localhost", server.getPort());
-
-        final BasicClassicHttpRequest get1 = new BasicClassicHttpRequest(Method.GET, "/");
-        get1.setVersion(HttpVersion.HTTP_1_0);
-        try (final ClassicHttpResponse response1 = client.execute(host, get1, context)) {
-            Assertions.assertEquals(200, response1.getCode());
-            EntityUtils.consume(response1.getEntity());
-        }
-
-        final BasicClassicHttpRequest get2 = new BasicClassicHttpRequest(Method.GET, "/");
-        try (final ClassicHttpResponse response2 = client.execute(host, get2, context)) {
-            Assertions.assertEquals(400, response2.getCode());
-            EntityUtils.consume(response2.getEntity());
-        }
-    }
-
     @Test
     public void testHeaderTooLarge() throws Exception {
         final ClassicTestServer server = testResources.server();
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 dfb09be96..533b5644d 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
@@ -33,7 +33,6 @@ import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.HEADERS;
 import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.METHOD;
 import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.NAME;
 import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.PATH;
-import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.PROTOCOL_VERSION;
 import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.QUERY;
 import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.REQUEST;
 import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.RESPONSE;
@@ -46,8 +45,6 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.hc.core5.http.ContentType;
-import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolVersion;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
@@ -665,30 +662,6 @@ public class TestTestingFramework {
         Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
     }
 
-    @Test
-    public void changeProtocolVersion() throws Exception {
-        final ClientTestingAdapter adapter = new ClassicTestClientTestingAdapter() {
-            @Override
-            public Map<String, Object> execute(
-                    final String defaultURI,
-                    final Map<String, Object> request,
-                    final TestingFrameworkRequestHandler requestHandler,
-                    final Map<String, Object> responseExpectations) throws TestingFrameworkException {
-                // change the request from what is expected.
-                final ProtocolVersion protocolVersion = (ProtocolVersion) request.get(PROTOCOL_VERSION);
-                Assertions.assertNotNull(protocolVersion);
-                request.put(PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
-                return super.execute(defaultURI, request, requestHandler, responseExpectations);
-            }
-        };
-
-        final TestingFramework framework = newFrameworkAndSetAdapter(adapter);
-
-        framework.addTest();
-
-        Assertions.assertThrows(TestingFrameworkException.class, () -> framework.runTests());
-    }
-
     @Test
     public void changeResponseExpectationsFails() throws Exception {
         final ClientTestingAdapter adapter = new ClientTestingAdapter() {
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
index 46951ffd1..03459ee13 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
@@ -101,6 +101,7 @@ import org.apache.hc.core5.http.nio.NHttpMessageWriter;
 import org.apache.hc.core5.http.nio.ResponseChannel;
 import org.apache.hc.core5.http.nio.SessionOutputBuffer;
 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
+import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
 import org.apache.hc.core5.http.nio.entity.DigestingEntityConsumer;
 import org.apache.hc.core5.http.nio.entity.DigestingEntityProducer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
@@ -522,6 +523,28 @@ public abstract class Http1IntegrationTest {
         }
     }
 
+    @Test
+    public void testHTTP11FeaturesDisabledWithHTTP10Requests() throws Exception {
+        final Http1TestServer server = resources.server();
+        final Http1TestClient client = resources.client();
+
+        server.register("/hello", () -> new SingleLineResponseHandler("Hi back"));
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start();
+        final Future<ClientSessionEndpoint> connectFuture = client.connect(
+                "localhost", serverEndpoint.getPort(), TIMEOUT);
+        final ClientSessionEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request = new BasicHttpRequest(Method.POST, createRequestURI(serverEndpoint, "/hello"));
+        request.setVersion(HttpVersion.HTTP_1_0);
+        final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
+                new BasicRequestProducer(request, new BasicAsyncEntityProducer(new byte[] {'a', 'b', 'c'}, null, true)),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final ExecutionException exception = Assertions.assertThrows(ExecutionException.class, future::get);
+        Assertions.assertInstanceOf(ProtocolException.class, exception.getCause());
+    }
+
     @Test
     public void testNoEntityPost() throws Exception {
         final Http1TestServer server = resources.server();
@@ -1604,45 +1627,6 @@ public abstract class Http1IntegrationTest {
         Assertions.assertNull(result.getBody());
     }
 
-    @Test
-    public void testAbsentHostHeader() throws Exception {
-        final Http1TestServer server = resources.server();
-        final Http1TestClient client = resources.client();
-
-        server.register("/hello", () -> new SingleLineResponseHandler("Hi there"));
-        final InetSocketAddress serverEndpoint = server.start();
-
-        client.start(new DefaultHttpProcessor(RequestContent.INSTANCE, RequestConnControl.INSTANCE), Http1Config.DEFAULT);
-
-        final Future<ClientSessionEndpoint> connectFuture = client.connect(
-                "localhost", serverEndpoint.getPort(), TIMEOUT);
-        final ClientSessionEndpoint streamEndpoint = connectFuture.get();
-
-        final HttpRequest request1 = new BasicHttpRequest(Method.GET, createRequestURI(serverEndpoint, "/hello"));
-        request1.setVersion(HttpVersion.HTTP_1_0);
-        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
-                new BasicRequestProducer(request1, null),
-                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
-        final Message<HttpResponse, String> result1 = future1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assertions.assertNotNull(result1);
-        final HttpResponse response1 = result1.getHead();
-        Assertions.assertNotNull(response1);
-        Assertions.assertEquals(200, response1.getCode());
-        Assertions.assertEquals("Hi there", result1.getBody());
-
-        final HttpRequest request2 = new BasicHttpRequest(Method.GET, createRequestURI(serverEndpoint, "/hello"));
-        request2.setVersion(HttpVersion.HTTP_1_1);
-        final Future<Message<HttpResponse, String>> future2 = streamEndpoint.execute(
-                new BasicRequestProducer(request2, null),
-                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
-        final Message<HttpResponse, String> result2 = future2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
-        Assertions.assertNotNull(result2);
-        final HttpResponse response2 = result2.getHead();
-        Assertions.assertNotNull(response2);
-        Assertions.assertEquals(400, response2.getCode());
-        Assertions.assertEquals("Host header is absent", result2.getBody());
-    }
-
     @Test
     public void testMessageWithTrailers() throws Exception {
         final Http1TestServer server = resources.server();
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/config/Http1Config.java b/httpcore5/src/main/java/org/apache/hc/core5/http/config/Http1Config.java
index 54e26e814..f8817469b 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/config/Http1Config.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/config/Http1Config.java
@@ -29,6 +29,7 @@ package org.apache.hc.core5.http.config;
 
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.Timeout;
 
@@ -47,6 +48,7 @@ public class Http1Config {
 
     public static final Http1Config DEFAULT = new Builder().build();
 
+    private final HttpVersion version;
     private final int bufferSize;
     private final int chunkSizeHint;
     private final Timeout waitForContinueTimeout;
@@ -55,10 +57,11 @@ public class Http1Config {
     private final int maxEmptyLineCount;
     private final int initialWindowSize;
 
-    Http1Config(final int bufferSize, final int chunkSizeHint, final Timeout waitForContinueTimeout,
-                final int maxLineLength, final int maxHeaderCount, final int maxEmptyLineCount,
-                final int initialWindowSize) {
+    Http1Config(final HttpVersion version, final int bufferSize, final int chunkSizeHint,
+                final Timeout waitForContinueTimeout, final int maxLineLength, final int maxHeaderCount,
+                final int maxEmptyLineCount, final int initialWindowSize) {
         super();
+        this.version = version;
         this.bufferSize = bufferSize;
         this.chunkSizeHint = chunkSizeHint;
         this.waitForContinueTimeout = waitForContinueTimeout;
@@ -68,6 +71,15 @@ public class Http1Config {
         this.initialWindowSize = initialWindowSize;
     }
 
+    /**
+     * The effective protocol level expressed by the minor version of HTTP/1.x.
+     *
+     * @since 5.3
+     */
+    public HttpVersion getVersion() {
+        return version;
+    }
+
     public int getBufferSize() {
         return bufferSize;
     }
@@ -99,7 +111,8 @@ public class Http1Config {
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append("[bufferSize=").append(bufferSize)
+        builder.append("[version=").append(version)
+                .append(", bufferSize=").append(bufferSize)
                 .append(", chunkSizeHint=").append(chunkSizeHint)
                 .append(", waitForContinueTimeout=").append(waitForContinueTimeout)
                 .append(", maxLineLength=").append(maxLineLength)
@@ -116,6 +129,7 @@ public class Http1Config {
     public static Http1Config.Builder copy(final Http1Config config) {
         Args.notNull(config, "Config");
         return new Builder()
+                .setVersion(config.getVersion())
                 .setBufferSize(config.getBufferSize())
                 .setChunkSizeHint(config.getChunkSizeHint())
                 .setWaitForContinueTimeout(config.getWaitForContinueTimeout())
@@ -135,6 +149,7 @@ public class Http1Config {
 
     public static class Builder {
 
+        private HttpVersion version;
         private int bufferSize;
         private int chunkSizeHint;
         private Timeout waitForContinueTimeout;
@@ -144,6 +159,7 @@ public class Http1Config {
         private int initialWindowSize;
 
         Builder() {
+            this.version = HttpVersion.HTTP_1_1;
             this.bufferSize = INIT_BUF_SIZE;
             this.chunkSizeHint = INIT_BUF_CHUNK;
             this.waitForContinueTimeout = INIT_WAIT_FOR_CONTINUE;
@@ -153,6 +169,20 @@ public class Http1Config {
             this.initialWindowSize = INIT_WINDOW_SIZE;
         }
 
+        /**
+         * Sets the effective HTTP/1.x protocol level (as expressed by the minor version).
+         * Presently only {@link HttpVersion#HTTP_1_0} and {@link HttpVersion#HTTP_1_1} are
+         * supported.
+         *
+         * @since 5.3
+         */
+        public Builder setVersion(final HttpVersion version) {
+            Args.notNull(version, "HTTP/1 protocol version");
+            Args.check(version.getMajor() == 1, "HTTP/1 protocol version is required");
+            this.version = version;
+            return this;
+        }
+
         public Builder setBufferSize(final int bufferSize) {
             this.bufferSize = bufferSize;
             return this;
@@ -191,6 +221,7 @@ public class Http1Config {
 
         public Http1Config build() {
             return new Http1Config(
+                    version,
                     bufferSize,
                     chunkSizeHint,
                     waitForContinueTimeout,
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java
index dfbe1fabe..cb68c25f8 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java
@@ -374,11 +374,11 @@ public class AsyncServerBootstrap {
         final ServerHttp1StreamDuplexerFactory streamHandlerFactory = new ServerHttp1StreamDuplexerFactory(
                 httpProcessor != null ? httpProcessor : HttpProcessors.server(),
                 handlerFactory,
-                http1Config != null ? http1Config : Http1Config.DEFAULT,
+                http1Config,
                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
                 connStrategy != null ? connStrategy : DefaultConnectionReuseStrategy.INSTANCE,
-                DefaultHttpRequestParserFactory.INSTANCE,
-                DefaultHttpResponseWriterFactory.INSTANCE,
+                new DefaultHttpRequestParserFactory(http1Config),
+                new DefaultHttpResponseWriterFactory(http1Config),
                 DefaultContentLengthStrategy.INSTANCE,
                 DefaultContentLengthStrategy.INSTANCE,
                 streamListener);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/RequesterBootstrap.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/RequesterBootstrap.java
index 15791af2d..a239f2032 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/RequesterBootstrap.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/RequesterBootstrap.java
@@ -65,6 +65,7 @@ import org.apache.hc.core5.util.Timeout;
 public class RequesterBootstrap {
 
     private HttpProcessor httpProcessor;
+    private Http1Config http1Config;
     private ConnectionReuseStrategy connReuseStrategy;
     private SocketConfig socketConfig;
     private HttpConnectionFactory<? extends HttpClientConnection> connectFactory;
@@ -94,6 +95,14 @@ public class RequesterBootstrap {
         return this;
     }
 
+    /**
+     * Sets HTTP/1 protocol configuration.
+     */
+    public final RequesterBootstrap setHttp1Config(final Http1Config http1Config) {
+        this.http1Config = http1Config;
+        return this;
+    }
+
     /**
      * Assigns {@link ConnectionReuseStrategy} instance.
      */
@@ -179,7 +188,7 @@ public class RequesterBootstrap {
 
     public HttpRequester create() {
         final HttpRequestExecutor requestExecutor = new HttpRequestExecutor(
-                HttpRequestExecutor.DEFAULT_WAIT_FOR_CONTINUE,
+                http1Config,
                 connReuseStrategy != null ? connReuseStrategy : DefaultConnectionReuseStrategy.INSTANCE,
                 streamListener);
         final ManagedConnPool<HttpHost, HttpClientConnection> connPool;
@@ -209,7 +218,7 @@ public class RequesterBootstrap {
                 connPool,
                 socketConfig != null ? socketConfig : SocketConfig.DEFAULT,
                 connectFactory != null ? connectFactory : new DefaultBHttpClientConnectionFactory(
-                        Http1Config.DEFAULT, CharCodingConfig.DEFAULT),
+                        http1Config, CharCodingConfig.DEFAULT),
                 sslSocketFactory,
                 sslSetupHandler != null ? sslSetupHandler : new DefaultTlsSetupHandler(),
                 sslSessionVerifier,
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/ServerBootstrap.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/ServerBootstrap.java
index d2b16d847..f52741c4a 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/ServerBootstrap.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/ServerBootstrap.java
@@ -140,7 +140,7 @@ public class ServerBootstrap {
     }
 
     /**
-     * Sets connection configuration.
+     * Sets HTTP/1 protocol configuration.
      */
     public final ServerBootstrap setHttp1Config(final Http1Config http1Config) {
         this.http1Config = http1Config;
@@ -380,6 +380,7 @@ public class ServerBootstrap {
         final HttpService httpService = new HttpService(
                 this.httpProcessor != null ? this.httpProcessor : HttpProcessors.server(),
                 requestHandler,
+                this.http1Config,
                 this.connStrategy != null ? this.connStrategy : DefaultConnectionReuseStrategy.INSTANCE,
                 this.streamListener);
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/AbstractMessageParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/AbstractMessageParser.java
index 43329b2ce..cd3482bd5 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/AbstractMessageParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/AbstractMessageParser.java
@@ -65,24 +65,25 @@ public abstract class AbstractMessageParser<T extends HttpMessage> implements Ht
     private T message;
 
     /**
-     * Creates new instance of AbstractMessageParser.
-     *
-     * @param lineParser the line parser. If {@code null}
-     *   {@link org.apache.hc.core5.http.message.LazyLineParser#INSTANCE} will be used.
-     * @param http1Config the message http1Config. If {@code null}
-     *   {@link Http1Config#DEFAULT} will be used.
-     *
-     * @since 4.3
+     * @since 5.3
      */
-    public AbstractMessageParser(final LineParser lineParser, final Http1Config http1Config) {
+    public AbstractMessageParser(final Http1Config http1Config, final LineParser lineParser) {
         super();
-        this.lineParser = lineParser != null ? lineParser : LazyLineParser.INSTANCE;
         this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
+        this.lineParser = lineParser != null ? lineParser : LazyLineParser.INSTANCE;
         this.headerLines = new ArrayList<>();
         this.headLine = new CharArrayBuffer(128);
         this.state = HEAD_LINE;
     }
 
+    /**
+     * @deprecated Use {@link #AbstractMessageParser(Http1Config, LineParser)}
+     */
+    @Deprecated
+    public AbstractMessageParser(final LineParser lineParser, final Http1Config http1Config) {
+        this(http1Config, lineParser);
+    }
+
     LineParser getLineParser() {
         return this.lineParser;
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnection.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnection.java
index 9fd4cec94..34e087e2a 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnection.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnection.java
@@ -108,7 +108,7 @@ public class DefaultBHttpClientConnection extends BHttpConnectionBase
         this.requestWriter = (requestWriterFactory != null ? requestWriterFactory :
             DefaultHttpRequestWriterFactory.INSTANCE).create();
         this.responseParser = (responseParserFactory != null ? responseParserFactory :
-            DefaultHttpResponseParserFactory.INSTANCE).create(http1Config);
+            DefaultHttpResponseParserFactory.INSTANCE).create();
         this.incomingContentStrategy = incomingContentStrategy != null ? incomingContentStrategy :
             DefaultContentLengthStrategy.INSTANCE;
         this.outgoingContentStrategy = outgoingContentStrategy != null ? outgoingContentStrategy :
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnectionFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnectionFactory.java
index c2becd2a0..85d02b267 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnectionFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpClientConnectionFactory.java
@@ -73,8 +73,10 @@ public class DefaultBHttpClientConnectionFactory
         this.incomingContentStrategy = incomingContentStrategy;
         this.outgoingContentStrategy = outgoingContentStrategy;
         this.responseOutOfOrderStrategy = responseOutOfOrderStrategy;
-        this.requestWriterFactory = requestWriterFactory;
-        this.responseParserFactory = responseParserFactory;
+        this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
+                new DefaultHttpRequestWriterFactory(this.http1Config) ;
+        this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
+                new DefaultHttpResponseParserFactory(this.http1Config);
     }
 
     public DefaultBHttpClientConnectionFactory(
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnection.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnection.java
index 8fe324f8b..aa01055e3 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnection.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnection.java
@@ -95,7 +95,7 @@ public class DefaultBHttpServerConnection extends BHttpConnectionBase implements
         super(http1Config, charDecoder, charEncoder);
         this.scheme = scheme;
         this.requestParser = (requestParserFactory != null ? requestParserFactory :
-            DefaultHttpRequestParserFactory.INSTANCE).create(http1Config);
+            DefaultHttpRequestParserFactory.INSTANCE).create();
         this.responseWriter = (responseWriterFactory != null ? responseWriterFactory :
             DefaultHttpResponseWriterFactory.INSTANCE).create();
         this.incomingContentStrategy = incomingContentStrategy != null ? incomingContentStrategy :
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnectionFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnectionFactory.java
index 8a67f1ed1..56d5c8ece 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnectionFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultBHttpServerConnectionFactory.java
@@ -72,8 +72,10 @@ public class DefaultBHttpServerConnectionFactory implements HttpConnectionFactor
         this.charCodingConfig = charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT;
         this.incomingContentStrategy = incomingContentStrategy;
         this.outgoingContentStrategy = outgoingContentStrategy;
-        this.requestParserFactory = requestParserFactory;
-        this.responseWriterFactory = responseWriterFactory;
+        this.requestParserFactory = requestParserFactory != null ? requestParserFactory :
+            new DefaultHttpRequestParserFactory(this.http1Config);
+        this.responseWriterFactory = responseWriterFactory != null ? responseWriterFactory :
+            new DefaultHttpResponseWriterFactory(this.http1Config);
     }
 
     public DefaultBHttpServerConnectionFactory(
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java
index b5acd53cd..19a1ecedb 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java
@@ -52,37 +52,39 @@ public class DefaultHttpRequestParser extends AbstractMessageParser<ClassicHttpR
     private final HttpRequestFactory<ClassicHttpRequest> requestFactory;
 
     /**
-     * Creates new instance of DefaultHttpRequestParser.
-     *
-     * @param lineParser the line parser. If {@code null}
-     *   {@link org.apache.hc.core5.http.message.LazyLineParser#INSTANCE} will be used.
-     * @param requestFactory the response factory. If {@code null}
-     *   {@link DefaultClassicHttpRequestFactory#INSTANCE} will be used.
-     * @param http1Config the message http1Config. If {@code null}
-     *   {@link Http1Config#DEFAULT} will be used.
-     *
-     * @since 4.3
+     * @since 5.3
      */
+    public DefaultHttpRequestParser(
+            final Http1Config http1Config,
+            final LineParser lineParser,
+            final HttpRequestFactory<ClassicHttpRequest> requestFactory) {
+        super(http1Config, lineParser);
+        this.requestFactory = requestFactory != null ? requestFactory : DefaultClassicHttpRequestFactory.INSTANCE;
+    }
+
+    /**
+     * @deprecated Use {@link #DefaultHttpRequestParser(Http1Config, LineParser, HttpRequestFactory)}
+     */
+    @Deprecated
     public DefaultHttpRequestParser(
             final LineParser lineParser,
             final HttpRequestFactory<ClassicHttpRequest> requestFactory,
             final Http1Config http1Config) {
-        super(lineParser, http1Config);
-        this.requestFactory = requestFactory != null ? requestFactory : DefaultClassicHttpRequestFactory.INSTANCE;
+        this(http1Config, lineParser, requestFactory);
     }
 
     /**
      * @since 4.3
      */
     public DefaultHttpRequestParser(final Http1Config http1Config) {
-        this(null, null, http1Config);
+        this(http1Config, null, null);
     }
 
     /**
      * @since 4.3
      */
     public DefaultHttpRequestParser() {
-        this(Http1Config.DEFAULT);
+        this(Http1Config.DEFAULT, null, null);
     }
 
     @Override
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParserFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParserFactory.java
index a2cbb983e..ebace6063 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParserFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParserFactory.java
@@ -47,23 +47,51 @@ public class DefaultHttpRequestParserFactory implements HttpMessageParserFactory
 
     public static final DefaultHttpRequestParserFactory INSTANCE = new DefaultHttpRequestParserFactory();
 
+    private final Http1Config http1Config;
     private final LineParser lineParser;
     private final HttpRequestFactory<ClassicHttpRequest> requestFactory;
 
-    public DefaultHttpRequestParserFactory(final LineParser lineParser,
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpRequestParserFactory(
+            final Http1Config http1Config,
+            final LineParser lineParser,
             final HttpRequestFactory<ClassicHttpRequest> requestFactory) {
         super();
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.lineParser = lineParser != null ? lineParser : LazyLineParser.INSTANCE;
         this.requestFactory = requestFactory != null ? requestFactory : DefaultClassicHttpRequestFactory.INSTANCE;
     }
 
+    public DefaultHttpRequestParserFactory(final LineParser lineParser,
+            final HttpRequestFactory<ClassicHttpRequest> requestFactory) {
+        this(null, lineParser, requestFactory);
+    }
+
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpRequestParserFactory(final Http1Config http1Config) {
+        this(http1Config, null, null);
+    }
+
     public DefaultHttpRequestParserFactory() {
         this(null, null);
     }
 
+    /**
+     * @deprecated Use {@link #create()}
+     */
+    @Deprecated
     @Override
     public HttpMessageParser<ClassicHttpRequest> create(final Http1Config http1Config) {
-        return new DefaultHttpRequestParser(this.lineParser, this.requestFactory, http1Config);
+        return new DefaultHttpRequestParser(http1Config, this.lineParser, this.requestFactory);
+    }
+
+    @Override
+    public HttpMessageParser<ClassicHttpRequest> create() {
+        return new DefaultHttpRequestParser(this.http1Config, this.lineParser, this.requestFactory);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriter.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriter.java
index 5aac8da08..c5afc4fd0 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriter.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriter.java
@@ -30,8 +30,9 @@ package org.apache.hc.core5.http.impl.io;
 import java.io.IOException;
 
 import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.LineFormatter;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.util.CharArrayBuffer;
@@ -44,29 +45,41 @@ import org.apache.hc.core5.util.CharArrayBuffer;
  */
 public class DefaultHttpRequestWriter extends AbstractMessageWriter<ClassicHttpRequest> {
 
+    private final Http1Config http1Config;
+
     /**
-     * Creates an instance of DefaultHttpRequestWriter.
-     *
-     * @param formatter the line formatter If {@code null}
-     *   {@link org.apache.hc.core5.http.message.BasicLineFormatter#INSTANCE}
-     *   will be used.
+     * @since 5.3
      */
-    public DefaultHttpRequestWriter(final LineFormatter formatter) {
+    public DefaultHttpRequestWriter(final Http1Config http1Config, final LineFormatter formatter) {
         super(formatter);
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
+    }
+
+    public DefaultHttpRequestWriter(final LineFormatter formatter) {
+        this(null, formatter);
     }
 
     public DefaultHttpRequestWriter() {
-        this(null);
+        this(null, null);
+    }
+
+    /**
+     * Determines the HTTP protocol version to be communicated to the opposite
+     * endpoint in the message header.
+     *
+     * @since 5.3
+     */
+    protected HttpVersion protocolVersion(final HttpRequest message) {
+        return http1Config.getVersion();
     }
 
     @Override
     protected void writeHeadLine(
             final ClassicHttpRequest message, final CharArrayBuffer lineBuf) throws IOException {
-        final ProtocolVersion transportVersion = message.getVersion();
         getLineFormatter().formatRequestLine(lineBuf, new RequestLine(
                 message.getMethod(),
                 message.getRequestUri(),
-                transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1));
+                protocolVersion(message)));
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriterFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriterFactory.java
index b377ccc28..c38d4b377 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriterFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriterFactory.java
@@ -30,6 +30,7 @@ package org.apache.hc.core5.http.impl.io;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.io.HttpMessageWriter;
 import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
 import org.apache.hc.core5.http.message.BasicLineFormatter;
@@ -45,20 +46,36 @@ public class DefaultHttpRequestWriterFactory implements HttpMessageWriterFactory
 
     public static final DefaultHttpRequestWriterFactory INSTANCE = new DefaultHttpRequestWriterFactory();
 
+    private final Http1Config http1Config;
     private final LineFormatter lineFormatter;
 
-    public DefaultHttpRequestWriterFactory(final LineFormatter lineFormatter) {
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpRequestWriterFactory(final Http1Config http1Config, final LineFormatter lineFormatter) {
         super();
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.lineFormatter = lineFormatter != null ? lineFormatter : BasicLineFormatter.INSTANCE;
     }
 
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpRequestWriterFactory(final Http1Config http1Config) {
+        this(http1Config, null);
+    }
+
+    public DefaultHttpRequestWriterFactory(final LineFormatter lineFormatter) {
+        this(null, lineFormatter);
+    }
+
     public DefaultHttpRequestWriterFactory() {
-        this(null);
+        this(null, null);
     }
 
     @Override
     public HttpMessageWriter<ClassicHttpRequest> create() {
-        return new DefaultHttpRequestWriter(this.lineFormatter);
+        return new DefaultHttpRequestWriter(http1Config, lineFormatter);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParser.java
index c2c4352f5..32d7810c0 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParser.java
@@ -48,30 +48,32 @@ public class DefaultHttpResponseParser extends AbstractMessageParser<ClassicHttp
     private final HttpResponseFactory<ClassicHttpResponse> responseFactory;
 
     /**
-     * Creates new instance of DefaultHttpResponseParser.
-     *
-     * @param lineParser the line parser. If {@code null}
-     *   {@link org.apache.hc.core5.http.message.LazyLineParser#INSTANCE} will be used
-     * @param responseFactory the response factory. If {@code null}
-     *   {@link DefaultClassicHttpResponseFactory#INSTANCE} will be used.
-     * @param http1Config the message http1Config. If {@code null}
-     *   {@link Http1Config#DEFAULT} will be used.
-     *
-     * @since 4.3
+     * @since 5.3
      */
+    public DefaultHttpResponseParser(
+            final Http1Config http1Config,
+            final LineParser lineParser,
+            final HttpResponseFactory<ClassicHttpResponse> responseFactory) {
+        super(http1Config, lineParser);
+        this.responseFactory = responseFactory != null ? responseFactory : DefaultClassicHttpResponseFactory.INSTANCE;
+    }
+
+    /**
+     * @deprecated Use {@link #DefaultHttpResponseParser(Http1Config, LineParser, HttpResponseFactory)}
+     */
+    @Deprecated
     public DefaultHttpResponseParser(
             final LineParser lineParser,
             final HttpResponseFactory<ClassicHttpResponse> responseFactory,
             final Http1Config http1Config) {
-        super(lineParser, http1Config);
-        this.responseFactory = responseFactory != null ? responseFactory : DefaultClassicHttpResponseFactory.INSTANCE;
+        this(http1Config, lineParser, responseFactory);
     }
 
     /**
      * @since 4.3
      */
     public DefaultHttpResponseParser(final Http1Config http1Config) {
-        this(null, null, http1Config);
+        this(http1Config, null, null);
     }
 
     /**
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParserFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParserFactory.java
index 9e602f789..59422fb7b 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParserFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseParserFactory.java
@@ -47,23 +47,51 @@ public class DefaultHttpResponseParserFactory implements HttpMessageParserFactor
 
     public static final DefaultHttpResponseParserFactory INSTANCE = new DefaultHttpResponseParserFactory();
 
+    private final Http1Config http1Config;
     private final LineParser lineParser;
     private final HttpResponseFactory<ClassicHttpResponse> responseFactory;
 
-    public DefaultHttpResponseParserFactory(final LineParser lineParser,
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpResponseParserFactory(
+            final Http1Config http1Config,
+            final LineParser lineParser,
             final HttpResponseFactory<ClassicHttpResponse> responseFactory) {
         super();
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.lineParser = lineParser != null ? lineParser : LazyLaxLineParser.INSTANCE;
         this.responseFactory = responseFactory != null ? responseFactory : DefaultClassicHttpResponseFactory.INSTANCE;
     }
 
+    public DefaultHttpResponseParserFactory(final LineParser lineParser,
+            final HttpResponseFactory<ClassicHttpResponse> responseFactory) {
+        this(null, lineParser, responseFactory);
+    }
+
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpResponseParserFactory(final Http1Config http1Config) {
+        this(http1Config, null, null);
+    }
+
     public DefaultHttpResponseParserFactory() {
         this(null, null);
     }
 
+    /**
+     * @deprecated Use {@link #create()}
+     */
+    @Deprecated
     @Override
     public HttpMessageParser<ClassicHttpResponse> create(final Http1Config http1Config) {
-        return new DefaultHttpResponseParser(this.lineParser, this.responseFactory, http1Config);
+        return new DefaultHttpResponseParser(http1Config, this.lineParser, this.responseFactory);
+    }
+
+    @Override
+    public HttpMessageParser<ClassicHttpResponse> create() {
+        return new DefaultHttpResponseParser(this.http1Config, this.lineParser, this.responseFactory);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriter.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriter.java
index 478a4aa48..8f5667104 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriter.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriter.java
@@ -30,8 +30,9 @@ package org.apache.hc.core5.http.impl.io;
 import java.io.IOException;
 
 import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.LineFormatter;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.util.CharArrayBuffer;
@@ -44,27 +45,39 @@ import org.apache.hc.core5.util.CharArrayBuffer;
  */
 public class DefaultHttpResponseWriter extends AbstractMessageWriter<ClassicHttpResponse> {
 
+    private final Http1Config http1Config;
+
     /**
-     * Creates an instance of DefaultHttpResponseWriter.
-     *
-     * @param formatter the line formatter If {@code null}
-     *  {@link org.apache.hc.core5.http.message.BasicLineFormatter#INSTANCE}
-     *   will be used.
+     * @since 5.3
      */
-    public DefaultHttpResponseWriter(final LineFormatter formatter) {
+    public DefaultHttpResponseWriter(final Http1Config http1Config, final LineFormatter formatter) {
         super(formatter);
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
+    }
+
+    public DefaultHttpResponseWriter(final LineFormatter formatter) {
+        this(null, formatter);
     }
 
     public DefaultHttpResponseWriter() {
-        super(null);
+        this(null, null);
+    }
+
+    /**
+     * Determines the HTTP protocol version to be communicated to the opposite
+     * endpoint in the message header.
+     *
+     * @since 5.3
+     */
+    protected HttpVersion protocolVersion(final HttpResponse message) {
+        return http1Config.getVersion();
     }
 
     @Override
     protected void writeHeadLine(
             final ClassicHttpResponse message, final CharArrayBuffer lineBuf) throws IOException {
-        final ProtocolVersion transportVersion = message.getVersion();
         getLineFormatter().formatStatusLine(lineBuf, new StatusLine(
-                transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1,
+                protocolVersion(message),
                 message.getCode(),
                 message.getReasonPhrase()));
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriterFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriterFactory.java
index beac2f565..75ae97a16 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriterFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpResponseWriterFactory.java
@@ -30,6 +30,7 @@ package org.apache.hc.core5.http.impl.io;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.io.HttpMessageWriter;
 import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
 import org.apache.hc.core5.http.message.BasicLineFormatter;
@@ -45,20 +46,36 @@ public class DefaultHttpResponseWriterFactory implements HttpMessageWriterFactor
 
     public static final DefaultHttpResponseWriterFactory INSTANCE = new DefaultHttpResponseWriterFactory();
 
+    private final Http1Config http1Config;
     private final LineFormatter lineFormatter;
 
-    public DefaultHttpResponseWriterFactory(final LineFormatter lineFormatter) {
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpResponseWriterFactory(final Http1Config http1Config, final LineFormatter lineFormatter) {
         super();
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.lineFormatter = lineFormatter != null ? lineFormatter : BasicLineFormatter.INSTANCE;
     }
 
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpResponseWriterFactory(final Http1Config http1Config) {
+        this(http1Config, null);
+    }
+
+    public DefaultHttpResponseWriterFactory(final LineFormatter lineFormatter) {
+        this(null, lineFormatter);
+    }
+
     public DefaultHttpResponseWriterFactory() {
-        this(null);
+        this(null, null);
     }
 
     @Override
     public HttpMessageWriter<ClassicHttpResponse> create() {
-        return new DefaultHttpResponseWriter(this.lineFormatter);
+        return new DefaultHttpResponseWriter(http1Config, lineFormatter);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java
index 7f6ad6796..ed52cebba 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpRequestExecutor.java
@@ -44,6 +44,7 @@ import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.ProtocolException;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.UnsupportedHttpVersionException;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
 import org.apache.hc.core5.http.impl.Http1StreamListener;
 import org.apache.hc.core5.http.io.HttpClientConnection;
@@ -75,31 +76,46 @@ public class HttpRequestExecutor {
 
     public static final Timeout DEFAULT_WAIT_FOR_CONTINUE = Timeout.ofSeconds(3);
 
-    private final Timeout waitForContinue;
+    private final Http1Config http1Config;
     private final ConnectionReuseStrategy connReuseStrategy;
     private final Http1StreamListener streamListener;
 
     /**
      * Creates new instance of HttpRequestExecutor.
      *
-     * @since 4.3
+     * @since 5.3
      */
     public HttpRequestExecutor(
-            final Timeout waitForContinue,
+            final Http1Config http1Config,
             final ConnectionReuseStrategy connReuseStrategy,
             final Http1StreamListener streamListener) {
         super();
-        this.waitForContinue = Args.positive(waitForContinue, "Wait for continue time");
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.connReuseStrategy = connReuseStrategy != null ? connReuseStrategy : DefaultConnectionReuseStrategy.INSTANCE;
         this.streamListener = streamListener;
     }
 
+    /**
+     * @deprecated Use {@link #HttpRequestExecutor(Http1Config, ConnectionReuseStrategy, Http1StreamListener)}
+     */
+    @Deprecated
+    public HttpRequestExecutor(
+            final Timeout waitForContinue,
+            final ConnectionReuseStrategy connReuseStrategy,
+            final Http1StreamListener streamListener) {
+        this(Http1Config.custom()
+                .setWaitForContinueTimeout(waitForContinue)
+                .build(),
+                connReuseStrategy,
+                streamListener);
+    }
+
     public HttpRequestExecutor(final ConnectionReuseStrategy connReuseStrategy) {
-        this(DEFAULT_WAIT_FOR_CONTINUE, connReuseStrategy, null);
+        this(Http1Config.DEFAULT, connReuseStrategy, null);
     }
 
     public HttpRequestExecutor() {
-        this(DEFAULT_WAIT_FOR_CONTINUE, null, null);
+        this(Http1Config.DEFAULT, null, null);
     }
 
     /**
@@ -145,7 +161,8 @@ public class HttpRequestExecutor {
             ClassicHttpResponse response = null;
             while (response == null) {
                 if (expectContinue) {
-                    if (conn.isDataAvailable(this.waitForContinue)) {
+                    final Timeout timeout = http1Config.getWaitForContinueTimeout() != null ? http1Config.getWaitForContinueTimeout() : DEFAULT_WAIT_FOR_CONTINUE;
+                    if (conn.isDataAvailable(timeout)) {
                         response = conn.receiveResponseHeader();
                         if (streamListener != null) {
                             streamListener.onResponseHead(conn, response);
@@ -238,10 +255,10 @@ public class HttpRequestExecutor {
         Args.notNull(processor, "HTTP processor");
         Args.notNull(context, "HTTP context");
         final ProtocolVersion transportVersion = request.getVersion();
-        if (transportVersion != null && transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
+        if (transportVersion != null && !transportVersion.lessEquals(http1Config.getVersion())) {
             throw new UnsupportedHttpVersionException(transportVersion);
         }
-        context.setProtocolVersion(transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1);
+        context.setProtocolVersion(transportVersion != null ? transportVersion : http1Config.getVersion());
         context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
         processor.process(request, request.getEntity(), context);
     }
@@ -271,7 +288,12 @@ public class HttpRequestExecutor {
         Args.notNull(processor, "HTTP processor");
         Args.notNull(context, "HTTP context");
         final ProtocolVersion transportVersion = response.getVersion();
-        context.setProtocolVersion(transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1);
+        if (transportVersion != null) {
+            if (transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
+                throw new UnsupportedHttpVersionException(transportVersion);
+            }
+            context.setProtocolVersion(transportVersion);
+        }
         context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
         processor.process(response, response.getEntity(), context);
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java
index 7ae6c0cca..6d0bb8f43 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java
@@ -45,6 +45,7 @@ import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.UnsupportedHttpVersionException;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
 import org.apache.hc.core5.http.impl.Http1StreamListener;
 import org.apache.hc.core5.http.impl.ServerSupport;
@@ -82,13 +83,13 @@ import org.apache.hc.core5.util.Args;
 public class HttpService {
 
     private final HttpProcessor processor;
+    private final Http1Config http1Config;
     private final HttpServerRequestHandler requestHandler;
     private final ConnectionReuseStrategy connReuseStrategy;
     private final Http1StreamListener streamListener;
 
     /**
      * Create a new HTTP service.
-     *
      * @param processor the processor to use on requests and responses
      * @param handlerMapper  the handler mapper
      * @param responseFactory  the response factory. If {@code null}
@@ -105,6 +106,7 @@ public class HttpService {
             final Http1StreamListener streamListener) {
         this(processor,
                 new BasicHttpServerExpectationDecorator(new BasicHttpServerRequestHandler(handlerMapper, responseFactory)),
+                Http1Config.DEFAULT,
                 connReuseStrategy,
                 streamListener);
     }
@@ -141,9 +143,31 @@ public class HttpService {
             final HttpServerRequestHandler requestHandler,
             final ConnectionReuseStrategy connReuseStrategy,
             final Http1StreamListener streamListener) {
+        this(processor, requestHandler, Http1Config.DEFAULT, connReuseStrategy, streamListener);
+    }
+
+    /**
+     * Create a new HTTP service.
+     *
+     * @param processor the processor to use on requests and responses
+     * @param requestHandler  the request handler.
+     * @param http1Config HTTP/1 protocol configuration.
+     * @param connReuseStrategy the connection reuse strategy. If {@code null}
+     *   {@link DefaultConnectionReuseStrategy#INSTANCE} will be used.
+     * @param streamListener message stream listener.
+     *
+     * @since 5.3
+     */
+    public HttpService(
+            final HttpProcessor processor,
+            final HttpServerRequestHandler requestHandler,
+            final Http1Config http1Config,
+            final ConnectionReuseStrategy connReuseStrategy,
+            final Http1StreamListener streamListener) {
         super();
         this.processor =  Args.notNull(processor, "HTTP processor");
         this.requestHandler =  Args.notNull(requestHandler, "Request handler");
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.connReuseStrategy = connReuseStrategy != null ? connReuseStrategy : DefaultConnectionReuseStrategy.INSTANCE;
         this.streamListener = streamListener;
     }
@@ -156,7 +180,7 @@ public class HttpService {
      */
     public HttpService(
             final HttpProcessor processor, final HttpServerRequestHandler requestHandler) {
-        this(processor, requestHandler, null, null);
+        this(processor, requestHandler, Http1Config.DEFAULT, null, null);
     }
 
     /**
@@ -185,7 +209,10 @@ public class HttpService {
             }
             conn.receiveRequestEntity(request);
             final ProtocolVersion transportVersion = request.getVersion();
-            context.setProtocolVersion(transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1);
+            if (transportVersion != null && transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
+                throw new UnsupportedHttpVersionException(transportVersion);
+            }
+            context.setProtocolVersion(transportVersion != null ? transportVersion : http1Config.getVersion());
             context.setAttribute(HttpCoreContext.SSL_SESSION, conn.getSSLSession());
             context.setAttribute(HttpCoreContext.CONNECTION_ENDPOINT, conn.getEndpointDetails());
             context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
@@ -212,10 +239,12 @@ public class HttpService {
                 public void submitResponse(final ClassicHttpResponse response) throws HttpException, IOException {
                     try {
                         final ProtocolVersion transportVersion = response.getVersion();
-                        if (transportVersion != null && transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
-                            throw new UnsupportedHttpVersionException(transportVersion);
+                        if (transportVersion != null) {
+                            if (!transportVersion.lessEquals(http1Config.getVersion())) {
+                                throw new UnsupportedHttpVersionException(transportVersion);
+                            }
+                            context.setProtocolVersion(transportVersion);
                         }
-                        context.setProtocolVersion(transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1);
                         context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
                         processor.process(response, response.getEntity(), context);
 
@@ -300,6 +329,7 @@ public class HttpService {
 
         private HttpProcessor processor;
         private HttpServerRequestHandler requestHandler;
+        private Http1Config http1Config;
         private ConnectionReuseStrategy connReuseStrategy;
         private Http1StreamListener streamListener;
 
@@ -315,6 +345,11 @@ public class HttpService {
             return this;
         }
 
+        public Builder withHttp1Config(final Http1Config http1Config) {
+            this.http1Config = http1Config;
+            return this;
+        }
+
         public Builder withConnectionReuseStrategy(final ConnectionReuseStrategy connReuseStrategy) {
             this.connReuseStrategy = connReuseStrategy;
             return this;
@@ -324,6 +359,7 @@ public class HttpService {
             this.streamListener = streamListener;
             return this;
         }
+
         /**
          * Create a new HTTP service.
          *
@@ -333,6 +369,7 @@ public class HttpService {
             return new HttpService(
                     processor,
                     requestHandler,
+                    http1Config,
                     connReuseStrategy,
                     streamListener);
         }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractMessageParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractMessageParser.java
index 9c6dc65fa..17fe3a296 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractMessageParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractMessageParser.java
@@ -37,8 +37,8 @@ import org.apache.hc.core5.http.MessageConstraintException;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.LazyLineParser;
 import org.apache.hc.core5.http.message.LineParser;
-import org.apache.hc.core5.http.nio.SessionInputBuffer;
 import org.apache.hc.core5.http.nio.NHttpMessageParser;
+import org.apache.hc.core5.http.nio.SessionInputBuffer;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.CharArrayBuffer;
 
@@ -54,6 +54,9 @@ public abstract class AbstractMessageParser<T extends HttpMessage> implements NH
         READ_HEAD_LINE, READ_HEADERS, COMPLETED
     }
 
+    private final Http1Config http1Config;
+    private final LineParser lineParser;
+
     private State state;
 
     private T message;
@@ -61,27 +64,25 @@ public abstract class AbstractMessageParser<T extends HttpMessage> implements NH
     private final List<CharArrayBuffer> headerBufs;
     private int emptyLineCount;
 
-    private final LineParser lineParser;
-    private final Http1Config messageConstraints;
-
     /**
-     * Creates an instance of AbstractMessageParser.
-     *
-     * @param lineParser the line parser. If {@code null}
-     *   {@link org.apache.hc.core5.http.message.LazyLineParser#INSTANCE} will be used.
-     * @param messageConstraints Message constraints. If {@code null}
-     *   {@link Http1Config#DEFAULT} will be used.
-     *
-     * @since 4.3
+     * @since 5.3
      */
-    public AbstractMessageParser(final LineParser lineParser, final Http1Config messageConstraints) {
+    public AbstractMessageParser(final Http1Config http1Config, final LineParser lineParser) {
         super();
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.lineParser = lineParser != null ? lineParser : LazyLineParser.INSTANCE;
-        this.messageConstraints = messageConstraints != null ? messageConstraints : Http1Config.DEFAULT;
         this.headerBufs = new ArrayList<>();
         this.state = State.READ_HEAD_LINE;
     }
 
+    /**
+     * @deprecated Use {@link #AbstractMessageParser(Http1Config, LineParser)}
+     */
+    @Deprecated
+    public AbstractMessageParser(final LineParser lineParser, final Http1Config messageConstraints) {
+        this(messageConstraints, lineParser);
+    }
+
     LineParser getLineParser() {
         return this.lineParser;
     }
@@ -107,7 +108,7 @@ public abstract class AbstractMessageParser<T extends HttpMessage> implements NH
     private T parseHeadLine() throws IOException, HttpException {
         if (this.lineBuf.isEmpty()) {
             this.emptyLineCount++;
-            if (this.emptyLineCount >= this.messageConstraints.getMaxEmptyLineCount()) {
+            if (this.emptyLineCount >= this.http1Config.getMaxEmptyLineCount()) {
                 throw new MessageConstraintException("Maximum empty line limit exceeded");
             }
             return null;
@@ -129,7 +130,7 @@ public abstract class AbstractMessageParser<T extends HttpMessage> implements NH
                 }
                 i++;
             }
-            final int maxLineLen = this.messageConstraints.getMaxLineLength();
+            final int maxLineLen = this.http1Config.getMaxLineLength();
             if (maxLineLen > 0 && previous.length() + 1 + current.length() - i > maxLineLen) {
                 throw new MessageConstraintException("Maximum line length limit exceeded");
             }
@@ -152,7 +153,7 @@ public abstract class AbstractMessageParser<T extends HttpMessage> implements NH
                 this.lineBuf.clear();
             }
             final boolean lineComplete = sessionBuffer.readLine(this.lineBuf, endOfStream);
-            final int maxLineLen = this.messageConstraints.getMaxLineLength();
+            final int maxLineLen = this.http1Config.getMaxLineLength();
             if (maxLineLen > 0 &&
                     (this.lineBuf.length() > maxLineLen ||
                             (!lineComplete && sessionBuffer.length() > maxLineLen))) {
@@ -171,7 +172,7 @@ public abstract class AbstractMessageParser<T extends HttpMessage> implements NH
                 break;
             case READ_HEADERS:
                 if (this.lineBuf.length() > 0) {
-                    final int maxHeaderCount = this.messageConstraints.getMaxHeaderCount();
+                    final int maxHeaderCount = this.http1Config.getMaxHeaderCount();
                     if (maxHeaderCount > 0 && headerBufs.size() >= maxHeaderCount) {
                         throw new MessageConstraintException("Maximum header count exceeded");
                     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexerFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexerFactory.java
index 12544e8bc..54691487e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexerFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexerFactory.java
@@ -80,9 +80,9 @@ public final class ClientHttp1StreamDuplexerFactory {
         this.connectionReuseStrategy = connectionReuseStrategy != null ? connectionReuseStrategy :
                 DefaultConnectionReuseStrategy.INSTANCE;
         this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
-                new DefaultHttpResponseParserFactory(http1Config);
+                new DefaultHttpResponseParserFactory(this.http1Config);
         this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
-                DefaultHttpRequestWriterFactory.INSTANCE;
+                new DefaultHttpRequestWriterFactory(this.http1Config);
         this.incomingContentStrategy = incomingContentStrategy != null ? incomingContentStrategy :
                 DefaultContentLengthStrategy.INSTANCE;
         this.outgoingContentStrategy = outgoingContentStrategy != null ? outgoingContentStrategy :
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
index 244a696e9..11fc5b9be 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
@@ -56,6 +56,8 @@ import org.apache.hc.core5.util.Timeout;
 
 class ClientHttp1StreamHandler implements ResourceHolder {
 
+    public static final Timeout DEFAULT_WAIT_FOR_CONTINUE = Timeout.ofSeconds(3);
+
     private final Http1StreamChannel<HttpRequest> outputChannel;
     private final DataStreamChannel internalDataChannel;
     private final HttpProcessor httpProcessor;
@@ -144,10 +146,10 @@ class ClientHttp1StreamHandler implements ResourceHolder {
     private void commitRequest(final HttpRequest request, final EntityDetails entityDetails) throws IOException, HttpException {
         if (requestCommitted.compareAndSet(false, true)) {
             final ProtocolVersion transportVersion = request.getVersion();
-            if (transportVersion != null && transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
+            if (transportVersion != null && !transportVersion.lessEquals(http1Config.getVersion())) {
                 throw new UnsupportedHttpVersionException(transportVersion);
             }
-            context.setProtocolVersion(transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1);
+            context.setProtocolVersion(transportVersion != null ? transportVersion : http1Config.getVersion());
             context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
 
             httpProcessor.process(request, entityDetails, context);
@@ -165,7 +167,8 @@ class ClientHttp1StreamHandler implements ResourceHolder {
                 if (expectContinue) {
                     requestState = MessageState.ACK;
                     timeout = outputChannel.getSocketTimeout();
-                    outputChannel.setSocketTimeout(http1Config.getWaitForContinueTimeout());
+                    final Timeout timeout = http1Config.getWaitForContinueTimeout() != null ? http1Config.getWaitForContinueTimeout() : DEFAULT_WAIT_FOR_CONTINUE;
+                    outputChannel.setSocketTimeout(timeout);
                 } else {
                     requestState = MessageState.BODY;
                     exchangeHandler.produce(internalDataChannel);
@@ -196,8 +199,11 @@ class ClientHttp1StreamHandler implements ResourceHolder {
             throw new ProtocolException("Unexpected message head");
         }
         final ProtocolVersion transportVersion = response.getVersion();
-        if (transportVersion != null && transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
-            throw new UnsupportedHttpVersionException(transportVersion);
+        if (transportVersion != null) {
+            if (transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
+                throw new UnsupportedHttpVersionException(transportVersion);
+            }
+            context.setProtocolVersion(transportVersion);
         }
 
         final int status = response.getCode();
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java
index 67724df13..67f5cffc8 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java
@@ -51,36 +51,47 @@ public class DefaultHttpRequestParser<T extends HttpRequest> extends AbstractMes
     private final HttpRequestFactory<T> requestFactory;
 
     /**
-     * Creates an instance of DefaultHttpRequestParser.
-     *
-     * @param requestFactory the request factory.
-     * @param parser the line parser. If {@code null}
-     *   {@link org.apache.hc.core5.http.message.LazyLineParser#INSTANCE} will be used.
-     * @param http1Config Message http1Config. If {@code null}
-     *   {@link Http1Config#DEFAULT} will be used.
-     *
-     * @since 4.3
+     * @since 5.3
      */
     public DefaultHttpRequestParser(
-            final HttpRequestFactory<T> requestFactory,
+            final Http1Config http1Config,
             final LineParser parser,
-            final Http1Config http1Config) {
-        super(parser, http1Config);
+            final HttpRequestFactory<T> requestFactory) {
+        super(http1Config, parser);
         this.requestFactory = Args.notNull(requestFactory, "Request factory");
     }
 
     /**
-    * @since 4.3
-    */
+     * @since 5.3
+     */
+    public DefaultHttpRequestParser(final Http1Config http1Config, final HttpRequestFactory<T> requestFactory) {
+        this(http1Config, null, requestFactory);
+    }
+
+    /**
+     * @deprecated Use {@link #DefaultHttpRequestParser(Http1Config, HttpRequestFactory)}  }
+     */
+    @Deprecated
     public DefaultHttpRequestParser(final HttpRequestFactory<T> requestFactory, final Http1Config http1Config) {
         this(requestFactory, null, http1Config);
     }
 
     /**
-    * @since 4.3
-    */
+     * @deprecated Use {@link #DefaultHttpRequestParser(Http1Config, LineParser, HttpRequestFactory)}  }
+     */
+    @Deprecated
+    public DefaultHttpRequestParser(
+            final HttpRequestFactory<T> requestFactory,
+            final LineParser parser,
+            final Http1Config http1Config) {
+        this(http1Config, parser, requestFactory);
+    }
+
+    /**
+     * @since 4.3
+     */
     public DefaultHttpRequestParser(final HttpRequestFactory<T> requestFactory) {
-        this(requestFactory, null);
+        this(null, null, requestFactory);
     }
 
     @Override
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParserFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParserFactory.java
index e0db9ab3b..d3ba90f81 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParserFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParserFactory.java
@@ -71,7 +71,7 @@ public class DefaultHttpRequestParserFactory implements NHttpMessageParserFactor
 
     @Override
     public NHttpMessageParser<HttpRequest> create() {
-        return new DefaultHttpRequestParser<>(requestFactory, lineParser, http1Config);
+        return new DefaultHttpRequestParser<>(http1Config, lineParser, requestFactory);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriter.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriter.java
index 480d4a32e..b79a02ae1 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriter.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriter.java
@@ -31,7 +31,7 @@ import java.io.IOException;
 
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.LineFormatter;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.util.CharArrayBuffer;
@@ -43,6 +43,16 @@ import org.apache.hc.core5.util.CharArrayBuffer;
  */
 public class DefaultHttpRequestWriter<T extends HttpRequest> extends AbstractMessageWriter<T> {
 
+    private final Http1Config http1Config;
+
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpRequestWriter(final Http1Config http1Config, final LineFormatter formatter) {
+        super(formatter);
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
+    }
+
     /**
      * Creates an instance of DefaultHttpRequestWriter.
      *
@@ -52,24 +62,33 @@ public class DefaultHttpRequestWriter<T extends HttpRequest> extends AbstractMes
      * @since 4.3
      */
     public DefaultHttpRequestWriter(final LineFormatter formatter) {
-        super(formatter);
+        this(null, formatter);
     }
 
     /**
      * @since 4.3
      */
     public DefaultHttpRequestWriter() {
-        super(null);
+        this(null, null);
+    }
+
+    /**
+     * Determines the HTTP protocol version to be communicated to the opposite
+     * endpoint in the message header.
+     *
+     * @since 5.3
+     */
+    protected HttpVersion protocolVersion(final T request) {
+        return http1Config.getVersion();
     }
 
     @Override
     protected void writeHeadLine(final T message, final CharArrayBuffer lineBuf) throws IOException {
         lineBuf.clear();
-        final ProtocolVersion transportVersion = message.getVersion();
         getLineFormatter().formatRequestLine(lineBuf, new RequestLine(
                 message.getMethod(),
                 message.getRequestUri(),
-                transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1));
+                protocolVersion(message)));
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriterFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriterFactory.java
index 013b16adf..c71a557b0 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriterFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriterFactory.java
@@ -30,6 +30,7 @@ package org.apache.hc.core5.http.impl.nio;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.BasicLineFormatter;
 import org.apache.hc.core5.http.message.LineFormatter;
 import org.apache.hc.core5.http.nio.NHttpMessageWriter;
@@ -45,20 +46,36 @@ public class DefaultHttpRequestWriterFactory implements NHttpMessageWriterFactor
 
     public static final DefaultHttpRequestWriterFactory INSTANCE = new DefaultHttpRequestWriterFactory();
 
+    private final Http1Config http1Config;
     private final LineFormatter lineFormatter;
 
-    public DefaultHttpRequestWriterFactory(final LineFormatter lineFormatter) {
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpRequestWriterFactory(final Http1Config http1Config, final LineFormatter lineFormatter) {
         super();
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.lineFormatter = lineFormatter != null ? lineFormatter : BasicLineFormatter.INSTANCE;
     }
 
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpRequestWriterFactory(final Http1Config http1Config) {
+        this(http1Config, null);
+    }
+
+    public DefaultHttpRequestWriterFactory(final LineFormatter lineFormatter) {
+        this(null, lineFormatter);
+    }
+
     public DefaultHttpRequestWriterFactory() {
-        this(null);
+        this(null, null);
     }
 
     @Override
     public NHttpMessageWriter<HttpRequest> create() {
-        return new DefaultHttpRequestWriter<>(this.lineFormatter);
+        return new DefaultHttpRequestWriter<>(http1Config, lineFormatter);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParser.java
index ec05fad04..66a7b3528 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParser.java
@@ -46,27 +46,40 @@ public class DefaultHttpResponseParser<T extends HttpResponse> extends AbstractM
     private final HttpResponseFactory<T> responseFactory;
 
     /**
-     * Creates an instance of DefaultHttpResponseParser.
-     *
-     * @param responseFactory the response factory.
-     * @param parser the line parser. If {@code null}
-     *   {@link org.apache.hc.core5.http.message.LazyLineParser#INSTANCE} will be used.
-     * @param http1Config Message http1Config. If {@code null}
-     *   {@link Http1Config#DEFAULT} will be used.
-     *
-     * @since 4.3
+     * @since 5.3
+     */
+    public DefaultHttpResponseParser(
+            final Http1Config http1Config,
+            final LineParser parser,
+            final HttpResponseFactory<T> responseFactory) {
+        super(http1Config, parser);
+        this.responseFactory = Args.notNull(responseFactory, "Response factory");
+    }
+
+    /**
+     * @since 5.3
      */
+    public DefaultHttpResponseParser(
+            final Http1Config http1Config,
+            final HttpResponseFactory<T> responseFactory) {
+        this(http1Config, null, responseFactory);
+    }
+
+    /**
+     * @deprecated Use {@link #DefaultHttpResponseParser(Http1Config, LineParser, HttpResponseFactory)}
+     */
+    @Deprecated
     public DefaultHttpResponseParser(
             final HttpResponseFactory<T> responseFactory,
             final LineParser parser,
             final Http1Config http1Config) {
-        super(parser, http1Config);
-        this.responseFactory = Args.notNull(responseFactory, "Response factory");
+        this(http1Config, parser, responseFactory);
     }
 
     /**
-     * @since 4.3
+     * @deprecated Use {@link #DefaultHttpResponseParser(Http1Config, HttpResponseFactory)}
      */
+    @Deprecated
     public DefaultHttpResponseParser(final HttpResponseFactory<T> responseFactory, final Http1Config http1Config) {
         this(responseFactory, null, http1Config);
     }
@@ -75,7 +88,7 @@ public class DefaultHttpResponseParser<T extends HttpResponse> extends AbstractM
      * @since 4.3
      */
     public DefaultHttpResponseParser(final HttpResponseFactory<T> responseFactory) {
-        this(responseFactory, null);
+        this(null, null, responseFactory);
     }
 
     @Override
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParserFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParserFactory.java
index a6c8b3d31..01fcb03ef 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParserFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseParserFactory.java
@@ -71,7 +71,7 @@ public class DefaultHttpResponseParserFactory implements NHttpMessageParserFacto
 
     @Override
     public NHttpMessageParser<HttpResponse> create() {
-        return new DefaultHttpResponseParser<>(responseFactory, lineParser, http1Config);
+        return new DefaultHttpResponseParser<>(http1Config, lineParser, responseFactory);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriter.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriter.java
index ea9922bca..80e3359ef 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriter.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriter.java
@@ -31,7 +31,7 @@ import java.io.IOException;
 
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.LineFormatter;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.util.CharArrayBuffer;
@@ -43,6 +43,16 @@ import org.apache.hc.core5.util.CharArrayBuffer;
  */
 public class DefaultHttpResponseWriter<T extends HttpResponse> extends AbstractMessageWriter<T> {
 
+    private final Http1Config http1Config;
+
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpResponseWriter(final LineFormatter formatter, final Http1Config http1Config) {
+        super(formatter);
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
+    }
+
     /**
      * Creates an instance of DefaultHttpResponseWriter.
      *
@@ -52,22 +62,31 @@ public class DefaultHttpResponseWriter<T extends HttpResponse> extends AbstractM
      * @since 4.3
      */
     public DefaultHttpResponseWriter(final LineFormatter formatter) {
-        super(formatter);
+        this(formatter, null);
     }
 
     /**
      * @since 4.3
      */
     public DefaultHttpResponseWriter() {
-        super(null);
+        this(null, null);
+    }
+
+    /**
+     * Determines the HTTP protocol version to be communicated to the opposite
+     * endpoint in the message header.
+     *
+     * @since 5.3
+     */
+    protected HttpVersion protocolVersion(final T request) {
+        return http1Config.getVersion();
     }
 
     @Override
     protected void writeHeadLine(final T message, final CharArrayBuffer lineBuf) throws IOException {
         lineBuf.clear();
-        final ProtocolVersion transportVersion = message.getVersion();
         getLineFormatter().formatStatusLine(lineBuf, new StatusLine(
-                transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1,
+                protocolVersion(message),
                 message.getCode(),
                 message.getReasonPhrase()));
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriterFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriterFactory.java
index 6c08c655f..9cd5d63f4 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriterFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpResponseWriterFactory.java
@@ -30,6 +30,7 @@ package org.apache.hc.core5.http.impl.nio;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.BasicLineFormatter;
 import org.apache.hc.core5.http.message.LineFormatter;
 import org.apache.hc.core5.http.nio.NHttpMessageWriter;
@@ -45,20 +46,36 @@ public class DefaultHttpResponseWriterFactory implements NHttpMessageWriterFacto
 
     public static final DefaultHttpResponseWriterFactory INSTANCE = new DefaultHttpResponseWriterFactory();
 
+    private final Http1Config http1Config;
     private final LineFormatter lineFormatter;
 
-    public DefaultHttpResponseWriterFactory(final LineFormatter lineFormatter) {
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpResponseWriterFactory(final Http1Config http1Config, final LineFormatter lineFormatter) {
         super();
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.lineFormatter = lineFormatter != null ? lineFormatter : BasicLineFormatter.INSTANCE;
     }
 
+    /**
+     * @since 5.3
+     */
+    public DefaultHttpResponseWriterFactory(final Http1Config http1Config) {
+        this(http1Config, null);
+    }
+
+    public DefaultHttpResponseWriterFactory(final LineFormatter lineFormatter) {
+        this(null, lineFormatter);
+    }
+
     public DefaultHttpResponseWriterFactory() {
-        this(null);
+        this(null, null);
     }
 
     @Override
     public NHttpMessageWriter<HttpResponse> create() {
-        return new DefaultHttpResponseWriter<>(this.lineFormatter);
+        return new DefaultHttpResponseWriter<>(lineFormatter, http1Config);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java
index 4a886d7d5..43f4f7fb7 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java
@@ -320,6 +320,7 @@ public class ServerHttp1StreamDuplexer extends AbstractHttp1StreamDuplexer<HttpR
             streamHandler = new ServerHttp1StreamHandler(
                     outputChannel,
                     httpProcessor,
+                    http1Config,
                     connectionReuseStrategy,
                     exchangeHandlerFactory,
                     context);
@@ -328,6 +329,7 @@ public class ServerHttp1StreamDuplexer extends AbstractHttp1StreamDuplexer<HttpR
             streamHandler = new ServerHttp1StreamHandler(
                     new DelayedOutputChannel(outputChannel),
                     httpProcessor,
+                    http1Config,
                     connectionReuseStrategy,
                     exchangeHandlerFactory,
                     context);
@@ -350,6 +352,7 @@ public class ServerHttp1StreamDuplexer extends AbstractHttp1StreamDuplexer<HttpR
             streamHandler = new ServerHttp1StreamHandler(
                     outputChannel,
                     httpProcessor,
+                    http1Config,
                     connectionReuseStrategy,
                     exchangeHandlerFactory,
                     context);
@@ -358,6 +361,7 @@ public class ServerHttp1StreamDuplexer extends AbstractHttp1StreamDuplexer<HttpR
             streamHandler = new ServerHttp1StreamHandler(
                     new DelayedOutputChannel(outputChannel),
                     httpProcessor,
+                    http1Config,
                     connectionReuseStrategy,
                     exchangeHandlerFactory,
                     context);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexerFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexerFactory.java
index 5d1c6464e..7c078b6e7 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexerFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexerFactory.java
@@ -85,9 +85,9 @@ public final class ServerHttp1StreamDuplexerFactory {
         this.connectionReuseStrategy = connectionReuseStrategy != null ? connectionReuseStrategy :
                 DefaultConnectionReuseStrategy.INSTANCE;
         this.requestParserFactory = requestParserFactory != null ? requestParserFactory :
-                new DefaultHttpRequestParserFactory(http1Config);
+                new DefaultHttpRequestParserFactory(this.http1Config);
         this.responseWriterFactory = responseWriterFactory != null ? responseWriterFactory :
-                DefaultHttpResponseWriterFactory.INSTANCE;
+                new DefaultHttpResponseWriterFactory(this.http1Config);
         this.incomingContentStrategy = incomingContentStrategy != null ? incomingContentStrategy :
                 DefaultContentLengthStrategy.INSTANCE;
         this.outgoingContentStrategy = outgoingContentStrategy != null ? outgoingContentStrategy :
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
index 0bc6b0112..721d0ae8b 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
@@ -46,6 +46,7 @@ import org.apache.hc.core5.http.MisdirectedRequestException;
 import org.apache.hc.core5.http.ProtocolException;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.UnsupportedHttpVersionException;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.impl.ServerSupport;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
 import org.apache.hc.core5.http.nio.AsyncPushProducer;
@@ -68,6 +69,7 @@ class ServerHttp1StreamHandler implements ResourceHolder {
     private final DataStreamChannel internalDataChannel;
     private final ResponseChannel responseChannel;
     private final HttpProcessor httpProcessor;
+    private final Http1Config http1Config;
     private final HandlerFactory<AsyncServerExchangeHandler> exchangeHandlerFactory;
     private final ConnectionReuseStrategy connectionReuseStrategy;
     private final HttpCoreContext context;
@@ -83,6 +85,7 @@ class ServerHttp1StreamHandler implements ResourceHolder {
     ServerHttp1StreamHandler(
             final Http1StreamChannel<HttpResponse> outputChannel,
             final HttpProcessor httpProcessor,
+            final Http1Config http1Config,
             final ConnectionReuseStrategy connectionReuseStrategy,
             final HandlerFactory<AsyncServerExchangeHandler> exchangeHandlerFactory,
             final HttpCoreContext context) {
@@ -142,6 +145,7 @@ class ServerHttp1StreamHandler implements ResourceHolder {
         };
 
         this.httpProcessor = httpProcessor;
+        this.http1Config = http1Config != null ? http1Config : Http1Config.DEFAULT;
         this.connectionReuseStrategy = connectionReuseStrategy;
         this.exchangeHandlerFactory = exchangeHandlerFactory;
         this.context = context;
@@ -158,8 +162,11 @@ class ServerHttp1StreamHandler implements ResourceHolder {
         if (responseCommitted.compareAndSet(false, true)) {
 
             final ProtocolVersion transportVersion = response.getVersion();
-            if (transportVersion != null && transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
-                throw new UnsupportedHttpVersionException(transportVersion);
+            if (transportVersion != null) {
+                if (!transportVersion.lessEquals(http1Config.getVersion())) {
+                    throw new UnsupportedHttpVersionException(transportVersion);
+                }
+                context.setProtocolVersion(transportVersion);
             }
 
             final int status = response.getCode();
@@ -167,7 +174,6 @@ class ServerHttp1StreamHandler implements ResourceHolder {
                 throw new HttpException("Invalid response: " + status);
             }
 
-            context.setProtocolVersion(transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1);
             context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
             httpProcessor.process(response, responseEntityDetails, context);
 
@@ -262,7 +268,7 @@ class ServerHttp1StreamHandler implements ResourceHolder {
         if (transportVersion != null && transportVersion.greaterEquals(HttpVersion.HTTP_2)) {
             throw new UnsupportedHttpVersionException(transportVersion);
         }
-        context.setProtocolVersion(transportVersion != null ? transportVersion : HttpVersion.HTTP_1_1);
+        context.setProtocolVersion(transportVersion != null ? transportVersion : http1Config.getVersion());
         context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
 
         try {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageParserFactory.java b/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageParserFactory.java
index 9522cea28..676368f49 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageParserFactory.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageParserFactory.java
@@ -37,6 +37,14 @@ import org.apache.hc.core5.http.config.Http1Config;
  */
 public interface HttpMessageParserFactory<T extends MessageHeaders> {
 
+    /**
+     * @deprecated Use {@link #create()}
+     */
+    @Deprecated
     HttpMessageParser<T> create(Http1Config http1Config);
 
+    default HttpMessageParser<T> create() {
+        return create(Http1Config.DEFAULT);
+    }
+
 }