Skip to content

Commit 73447ee

Browse files
committed
Solves duplicate header issue
1 parent cc93f34 commit 73447ee

3 files changed

Lines changed: 56 additions & 14 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.example.http;
2+
3+
public class BinaryResponseBuilder {
4+
}

src/main/java/org/example/http/HttpResponseBuilder.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,34 @@ public void setContentTypeFromFilename(String filename) {
4141
404, "Not Found",
4242
500, "Internal Server Error");
4343

44-
public String build(){
44+
public String build() {
4545
StringBuilder sb = new StringBuilder();
4646
String reason = REASON_PHRASES.getOrDefault(statusCode, "OK");
47+
48+
// Status line
4749
sb.append(PROTOCOL).append(" ").append(statusCode).append(" ").append(reason).append(CRLF);
48-
headers.forEach((k,v) -> sb.append(k).append(": ").append(v).append(CRLF));
49-
sb.append("Content-Length: ")
50-
.append(body.getBytes(StandardCharsets.UTF_8).length);
51-
sb.append(CRLF);
52-
sb.append("Connection: close").append(CRLF);
50+
51+
// User-defined headers
52+
headers.forEach((k, v) -> sb.append(k).append(": ").append(v).append(CRLF));
53+
54+
// Only append Content-Length if not already set
55+
if (!headers.containsKey("Content-Length")) {
56+
sb.append("Content-Length: ")
57+
.append(body.getBytes(StandardCharsets.UTF_8).length)
58+
.append(CRLF);
59+
}
60+
61+
// Only append Connection if not already set
62+
if (!headers.containsKey("Connection")) {
63+
sb.append("Connection: close").append(CRLF);
64+
}
65+
66+
// Blank line before body
5367
sb.append(CRLF);
68+
69+
// Body
5470
sb.append(body);
71+
5572
return sb.toString();
5673
}
5774
}

src/test/java/org/example/http/HttpResponseBuilderTest.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import org.junit.jupiter.api.DisplayName;
44
import org.junit.jupiter.api.Test;
55
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.Arguments;
67
import org.junit.jupiter.params.provider.CsvSource;
8+
import org.junit.jupiter.params.provider.MethodSource;
9+
10+
import java.util.stream.Stream;
711

812
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
913

@@ -123,17 +127,34 @@ void setContentTypeFromFilename_allCases(String filename, String expectedContent
123127
assertThat(result).contains("Content-Type: " + expectedContentType);
124128
}
125129

126-
@Test
127-
@DisplayName("Should override previous Content-Type when set again")
128-
void setContentTypeFromFilename_overridesPrevious() {
130+
@ParameterizedTest
131+
@MethodSource("provideHeaderDuplicationScenarios")
132+
@DisplayName("Should not duplicate headers when manually set")
133+
void build_doesNotDuplicateHeaders(String headerName, String manualValue, String bodyContent) {
129134
HttpResponseBuilder builder = new HttpResponseBuilder();
130-
builder.setContentTypeFromFilename("file.txt");
131-
builder.setContentTypeFromFilename("file.html");
132-
builder.setBody("Test");
135+
builder.setHeader(headerName, manualValue);
136+
builder.setBody(bodyContent);
133137

134138
String result = builder.build();
135139

136-
assertThat(result).contains("Content-Type: text/html; charset=UTF-8");
137-
assertThat(result).doesNotContain("text/plain");
140+
// Count occurrences of the header
141+
long count = result.lines()
142+
.filter(line -> line.startsWith(headerName + ":"))
143+
.count();
144+
145+
assertThat(count).isEqualTo(1);
146+
assertThat(result).contains(headerName + ": " + manualValue);
147+
}
148+
149+
private static Stream<Arguments> provideHeaderDuplicationScenarios() {
150+
return Stream.of(
151+
Arguments.of("Content-Length", "999", "Hello"),
152+
Arguments.of("Content-Length", "0", ""),
153+
Arguments.of("Content-Length", "12345", "Test content"),
154+
Arguments.of("Connection", "keep-alive", "Hello"),
155+
Arguments.of("Connection", "upgrade", "WebSocket data"),
156+
Arguments.of("Connection", "close", "Goodbye")
157+
);
138158
}
159+
139160
}

0 commit comments

Comments
 (0)