Skip to content

Commit 4dbcdca

Browse files
authored
Merge pull request #1952 from ropalka/UNDERTOW-2763
[UNDERTOW-2763] As per RFC 9112 reason phrase is optional in HTTP responses
2 parents 12a2445 + a8bfac2 commit 4dbcdca

2 files changed

Lines changed: 52 additions & 19 deletions

File tree

core/src/main/java/io/undertow/client/http/ResponseParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,10 @@ private void parseReasonPhrase(final ByteBuffer buffer, final ResponseState stat
136136
if (state.previousByte == 0 && (isVisibleAsciiChar(nextByte) || isSpaceOrTabChar(nextByte) || isObsoleteChar(nextByte))) {
137137
// reason phrase data goes on
138138
sb.append(nextChar);
139-
} else if (state.previousByte == 0 && nextByte == CARRIAGE_RETURN && sb.length() > 0) {
139+
} else if (state.previousByte == 0 && nextByte == CARRIAGE_RETURN) {
140140
// reason phrase read complete - first separator
141141
state.previousByte = nextByte;
142-
} else if (state.previousByte == CARRIAGE_RETURN && nextByte == LINE_FEED && sb.length() > 0) {
142+
} else if (state.previousByte == CARRIAGE_RETURN && nextByte == LINE_FEED) {
143143
// reason phrase read complete - second separator
144144
final String reason = sb.toString().trim();
145145
if (!reason.isEmpty()) builder.setReasonPhrase(reason);

core/src/test/java/io/undertow/client/http/ResponseParserResumeTestCase.java

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package io.undertow.client.http;
2020

2121
import io.undertow.testutils.category.UnitTest;
22-
import io.undertow.util.BadRequestException;
2322
import io.undertow.util.HttpString;
2423
import io.undertow.util.Protocols;
2524
import io.undertow.util.StatusCodes;
@@ -37,23 +36,25 @@
3736
@Category(UnitTest.class)
3837
public class ResponseParserResumeTestCase {
3938

40-
public static final String DATA = "HTTP/1.1 200 OK\r\nHost: www.somehost.net\r\nOtherHeader: some\r\n \r\n value\r\nHostee:another\r\nAccept-garbage: a\r\n\r\ntttt";
39+
public static final String RESPONSE1 = "HTTP/1.1 200 OK\r\nHost: www.somehost.net\r\nOtherHeader: some\r\n \r\n value\r\nHostee:another\r\nAccept-garbage: a\r\n\r\ntttt";
40+
public static final String RESPONSE2 = "HTTP/1.1 200 \r\nHost: www.somehost.net\r\nOtherHeader: some\r\n \r\n value\r\nHostee:another\r\nAccept-garbage: a\r\n\r\ntttt";
41+
public static final String RESPONSE3 = "HTTP/1.1 200 \r\n\r\ntttt";
4142

4243
@Test
43-
public void testMethodSplit() {
44-
byte[] in = DATA.getBytes();
44+
public void testMethodSplit_response1() {
45+
byte[] in = RESPONSE1.getBytes();
4546
for (int i = 0; i < in.length - 4; ++i) {
4647
try {
47-
testResume(i, in);
48+
testResume(i, in, true, true);
4849
} catch (Throwable e) {
4950
throw new RuntimeException("Test failed at split " + i, e);
5051
}
5152
}
5253
}
5354

5455
@Test
55-
public void testOneCharacterAtATime() throws BadRequestException {
56-
byte[] in = DATA.getBytes();
56+
public void testOneCharacterAtATime_response1() {
57+
byte[] in = RESPONSE1.getBytes();
5758
final ResponseState context = new ResponseState();
5859
HttpResponseBuilder result = new HttpResponseBuilder();
5960
ByteBuffer buffer = ByteBuffer.wrap(in);
@@ -62,10 +63,38 @@ public void testOneCharacterAtATime() throws BadRequestException {
6263
ResponseParser.INSTANCE.handle(buffer, context, result);
6364
buffer.limit(buffer.limit() + 1);
6465
}
65-
runAssertions(result, context);
66+
runAssertions(result, context, true, true);
6667
}
6768

68-
private void testResume(final int split, byte[] in) throws BadRequestException {
69+
@Test
70+
public void testOneCharacterAtATime_response2() {
71+
byte[] in = RESPONSE2.getBytes();
72+
final ResponseState context = new ResponseState();
73+
HttpResponseBuilder result = new HttpResponseBuilder();
74+
ByteBuffer buffer = ByteBuffer.wrap(in);
75+
buffer.limit(1);
76+
while (!context.isComplete()) {
77+
ResponseParser.INSTANCE.handle(buffer, context, result);
78+
buffer.limit(buffer.limit() + 1);
79+
}
80+
runAssertions(result, context, false, true);
81+
}
82+
83+
@Test
84+
public void testOneCharacterAtATime_response3() {
85+
byte[] in = RESPONSE3.getBytes();
86+
final ResponseState context = new ResponseState();
87+
HttpResponseBuilder result = new HttpResponseBuilder();
88+
ByteBuffer buffer = ByteBuffer.wrap(in);
89+
buffer.limit(1);
90+
while (!context.isComplete()) {
91+
ResponseParser.INSTANCE.handle(buffer, context, result);
92+
buffer.limit(buffer.limit() + 1);
93+
}
94+
runAssertions(result, context, false, false);
95+
}
96+
97+
private void testResume(final int split, byte[] in, final boolean hasReasonPhrase, final boolean hasHeaders) {
6998
final ResponseState context = new ResponseState();
7099
HttpResponseBuilder result = new HttpResponseBuilder();
71100
ByteBuffer buffer = ByteBuffer.wrap(in);
@@ -74,20 +103,24 @@ private void testResume(final int split, byte[] in) throws BadRequestException {
74103
Assert.assertEquals(0, buffer.remaining());
75104
buffer.limit(buffer.capacity());
76105
ResponseParser.INSTANCE.handle(buffer,context, result);
77-
runAssertions(result, context);
106+
runAssertions(result, context, hasReasonPhrase, hasHeaders);
78107
Assert.assertEquals(4, buffer.remaining());
79108
}
80109

81-
private void runAssertions(final HttpResponseBuilder result, final ResponseState context) {
110+
private void runAssertions(final HttpResponseBuilder result, final ResponseState context, final boolean hasReasonPhrase, final boolean hasHeaders) {
82111
Assert.assertEquals(StatusCodes.OK, result.getStatusCode());
83-
Assert.assertEquals("OK", result.getReasonPhrase());
112+
Assert.assertEquals(hasReasonPhrase ? "OK" : null, result.getReasonPhrase());
84113
Assert.assertSame(Protocols.HTTP_1_1, result.getProtocol());
85114

86-
Assert.assertEquals("www.somehost.net", result.getResponseHeaders().getFirst(new HttpString("Host")));
87-
Assert.assertEquals("some value", result.getResponseHeaders().getFirst(new HttpString("OtherHeader")));
88-
Assert.assertEquals("another", result.getResponseHeaders().getFirst(new HttpString("Hostee")));
89-
Assert.assertEquals("a", result.getResponseHeaders().getFirst(new HttpString("Accept-garbage")));
90-
Assert.assertEquals(4, result.getResponseHeaders().getHeaderNames().size());
115+
if (hasHeaders) {
116+
Assert.assertEquals("www.somehost.net", result.getResponseHeaders().getFirst(new HttpString("Host")));
117+
Assert.assertEquals("some value", result.getResponseHeaders().getFirst(new HttpString("OtherHeader")));
118+
Assert.assertEquals("another", result.getResponseHeaders().getFirst(new HttpString("Hostee")));
119+
Assert.assertEquals("a", result.getResponseHeaders().getFirst(new HttpString("Accept-garbage")));
120+
Assert.assertEquals(4, result.getResponseHeaders().getHeaderNames().size());
121+
} else {
122+
Assert.assertEquals(0, result.getResponseHeaders().getHeaderNames().size());
123+
}
91124

92125
Assert.assertTrue(context.isComplete());
93126
}

0 commit comments

Comments
 (0)