Skip to content

Commit 5e5eb0b

Browse files
HTTPCORE-769 - Add configurable behavior for handling 408 responses in DefaultConnectionReuseStrategy. (#489)
This change addresses scenarios where a server sends a 408 response without the "Connection: close" header, allowing clients to choose whether to close the connection as per RFC recommendations.
1 parent 077142a commit 5e5eb0b

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

httpcore5/src/main/java/org/apache/hc/core5/http/impl/DefaultConnectionReuseStrategy.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,44 @@ public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
7070

7171
public static final DefaultConnectionReuseStrategy INSTANCE = new DefaultConnectionReuseStrategy();
7272

73+
/**
74+
* Flag to determine whether the connection should be forcibly closed on receiving a 408 status code.
75+
* If {@code true}, the connection will be closed when a 408 (Request Timeout) response is encountered,
76+
* regardless of the "Connection" header's value.
77+
* @since 5.5
78+
*/
79+
private final boolean forceCloseOn408;
80+
81+
/**
82+
* Default constructor that initializes the strategy with the default behavior:
83+
* connections are not forcibly closed on a 408 status code unless explicitly signaled by the server.
84+
* <p>
85+
* This constructor maintains backward compatibility and adheres to the HTTP protocol as it is,
86+
* meaning that connections will be kept alive by default unless the server includes a "Connection: close"
87+
* header or other headers that imply the connection should be closed.
88+
*/
7389
public DefaultConnectionReuseStrategy() {
74-
super();
90+
this(false); // Default behavior: do not force-close on 408
91+
}
92+
93+
/**
94+
* Constructor to initialize the strategy with a customizable behavior for handling 408 responses.
95+
* <p>
96+
* When {@code forceCloseOn408} is set to {@code true}, the strategy will forcefully close connections
97+
* upon encountering a 408 (Request Timeout) response, regardless of the presence of the "Connection: close"
98+
* header in the response. This is particularly useful when interacting with servers that send 408 responses
99+
* without properly indicating that the connection should be closed.
100+
* <p>
101+
* If {@code forceCloseOn408} is set to {@code false}, the strategy will follow the standard HTTP protocol
102+
* behavior, only closing the connection if the server explicitly signals to do so (e.g., by including a
103+
* "Connection: close" header or other relevant headers).
104+
*
105+
* @param forceCloseOn408 {@code true} to force connection close on 408 responses;
106+
* {@code false} to use the default HTTP behavior.
107+
* @since 5.5
108+
*/
109+
public DefaultConnectionReuseStrategy(final boolean forceCloseOn408) {
110+
this.forceCloseOn408 = forceCloseOn408;
75111
}
76112

77113
// see interface ConnectionReuseStrategy
@@ -80,6 +116,10 @@ public boolean keepAlive(
80116
final HttpRequest request, final HttpResponse response, final HttpContext context) {
81117
Args.notNull(response, "HTTP response");
82118

119+
if (forceCloseOn408 && response.getCode() == HttpStatus.SC_REQUEST_TIMEOUT) {
120+
return false; // Force connection close on 408 if configured to do so
121+
}
122+
83123
if (request != null) {
84124
// Consider framing of a request message with both Content-Length and Content-Length headers faulty
85125
if (request.containsHeader(HttpHeaders.CONTENT_LENGTH) && request.containsHeader(HttpHeaders.TRANSFER_ENCODING)) {

httpcore5/src/test/java/org/apache/hc/core5/http/impl/TestDefaultConnectionReuseStrategy.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,5 +318,13 @@ void testResponseHTTP10TransferEncodingPresent() {
318318
Assertions.assertFalse(reuseStrategy.keepAlive(null, response, context));
319319
}
320320

321+
@Test
322+
void testRequestTimeout408Response() {
323+
final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_REQUEST_TIMEOUT, "Request Timeout");
324+
response.addHeader("Connection", "keep-alive");
325+
reuseStrategy = new DefaultConnectionReuseStrategy(true);
326+
Assertions.assertFalse(reuseStrategy.keepAlive(null, response, context));
327+
}
328+
321329
}
322330

0 commit comments

Comments
 (0)