Skip to content

Commit 874659b

Browse files
committed
Fix
1 parent fbd4a60 commit 874659b

2 files changed

Lines changed: 47 additions & 41 deletions

File tree

src/main/java/io/split/android/client/network/RawHttpResponseParser.java

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
import androidx.annotation.NonNull;
44
import androidx.annotation.Nullable;
55

6-
import java.io.BufferedReader;
76
import java.io.ByteArrayOutputStream;
87
import java.io.IOException;
98
import java.io.InputStream;
10-
import java.io.InputStreamReader;
119
import java.nio.charset.Charset;
1210
import java.nio.charset.StandardCharsets;
1311
import java.security.cert.Certificate;
@@ -33,44 +31,41 @@ class RawHttpResponseParser {
3331
*/
3432
@NonNull
3533
public HttpResponse parseHttpResponse(@NonNull InputStream inputStream, Certificate[] serverCertificates) throws IOException {
36-
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
37-
38-
// 1. Read and parse status line
39-
String statusLine = reader.readLine();
40-
if (statusLine == null) {
41-
throw new IOException("No HTTP response received from server");
42-
}
43-
44-
Logger.v("Parsing HTTP status line: " + statusLine);
45-
int statusCode = parseStatusCode(statusLine);
46-
47-
// 2. Read and parse response headers
48-
ParsedResponseHeaders responseHeaders = getParsedResponseHeaders(reader);
49-
50-
// 3. Determine charset from Content-Type header
51-
Charset bodyCharset = extractCharsetFromContentType(responseHeaders.mContentType);
52-
53-
// 4. Read response body based on encoding type
54-
String responseBody = readResponseBody(inputStream, responseHeaders.mIsChunked, bodyCharset, responseHeaders.mContentLength, responseHeaders.mConnectionClose);
55-
56-
// 5. Create and return HttpResponse
57-
if (responseBody != null && !responseBody.trim().isEmpty()) {
58-
return new HttpResponseImpl(statusCode, responseBody, serverCertificates);
59-
} else {
60-
return new HttpResponseImpl(statusCode, serverCertificates);
61-
}
34+
// 1. Read and parse status line
35+
String statusLine = readLineFromStream(inputStream);
36+
if (statusLine == null) {
37+
throw new IOException("No HTTP response received from server");
38+
}
39+
40+
Logger.v("Parsing HTTP status line: " + statusLine);
41+
int statusCode = parseStatusCode(statusLine);
42+
43+
// 2. Read and parse response headers directly (single-pass)
44+
ParsedResponseHeaders responseHeaders = parseHeadersDirectly(inputStream);
45+
46+
// 3. Determine charset from Content-Type header
47+
Charset bodyCharset = extractCharsetFromContentType(responseHeaders.mContentType);
48+
49+
// 4. Read response body using the same InputStream (correctly positioned after headers)
50+
String responseBody = readResponseBody(inputStream, responseHeaders.mIsChunked, bodyCharset, responseHeaders.mContentLength, responseHeaders.mConnectionClose);
51+
52+
// 5. Create and return HttpResponse
53+
if (responseBody != null && !responseBody.trim().isEmpty()) {
54+
return new HttpResponseImpl(statusCode, responseBody, serverCertificates);
55+
} else {
56+
return new HttpResponseImpl(statusCode, serverCertificates);
6257
}
6358
}
6459

6560
@NonNull
66-
private static ParsedResponseHeaders getParsedResponseHeaders(BufferedReader reader) throws IOException {
67-
int contentLength = 0;
61+
private ParsedResponseHeaders parseHeadersDirectly(@NonNull InputStream inputStream) throws IOException {
62+
int contentLength = -1;
6863
boolean isChunked = false;
6964
boolean connectionClose = false;
7065
String contentType = null;
7166
String headerLine;
72-
73-
while ((headerLine = reader.readLine()) != null && !headerLine.trim().isEmpty()) {
67+
68+
while ((headerLine = readLineFromStream(inputStream)) != null && !headerLine.trim().isEmpty()) {
7469
Logger.v("Parsing HTTP header: " + headerLine);
7570
int colonIndex = headerLine.indexOf(':');
7671
if (colonIndex > 0) {
@@ -96,6 +91,8 @@ private static ParsedResponseHeaders getParsedResponseHeaders(BufferedReader rea
9691
return new ParsedResponseHeaders(contentLength, isChunked, connectionClose, contentType);
9792
}
9893

94+
95+
9996
@Nullable
10097
private String readResponseBody(@NonNull InputStream inputStream, boolean isChunked, Charset bodyCharset, int contentLength, boolean connectionClose) throws IOException {
10198
String responseBody = null;
@@ -239,6 +236,10 @@ private String readUntilCloseWithCharset(InputStream inputStream, Charset charse
239236
return new String(bodyBytes.toByteArray(), charset);
240237
}
241238

239+
/**
240+
* Reads a line from the input stream for chunked transfer encoding.
241+
* This is only used for reading chunk size lines and trailers in chunked responses.
242+
*/
242243
private String readLineFromStream(InputStream inputStream) throws IOException {
243244
ByteArrayOutputStream lineBytes = new ByteArrayOutputStream();
244245
int b;

src/test/java/io/split/android/client/network/RawHttpResponseParserTest.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void httpResponseWithValidResponse() throws Exception {
2323
String rawHttpResponse =
2424
"HTTP/1.1 200 OK\r\n" +
2525
"Content-Type: application/json\r\n" +
26-
"Content-Length: 26\r\n" +
26+
"Content-Length: 25\r\n" +
2727
"\r\n" +
2828
"{\"message\":\"Hello World\"}";
2929

@@ -133,14 +133,19 @@ public void responseWithEmptyStreamThrowsException() throws Exception {
133133
@Test
134134
public void responseWithChunkedEncodingHandlesCorrectly() throws Exception {
135135
String rawHttpResponse =
136-
"HTTP/1.1 200 OK\r\n" +
137-
"Transfer-Encoding: chunked\r\n" +
138-
"\r\n" +
139-
"1a\r\n" +
140-
"This is chunked data!\r\n" +
141-
"\r\n" +
142-
"0\r\n" +
143-
"\r\n";
136+
// headers
137+
"HTTP/1.1 200 OK\r\n" +
138+
"Transfer-Encoding: chunked\r\n" +
139+
"\r\n" +
140+
// 1st chunk size
141+
"15\r\n" +
142+
// 1st chunk data
143+
"This is chunked data!" +
144+
"\r\n" +
145+
146+
// 2nd chunk size
147+
"0\r\n" +
148+
"\r\n";
144149

145150
InputStream inputStream = new ByteArrayInputStream(rawHttpResponse.getBytes("UTF-8"));
146151
RawHttpResponseParser parser = new RawHttpResponseParser();

0 commit comments

Comments
 (0)