From c6295e58a1d45f4973ce5e86fe950c0d5c9859f6 Mon Sep 17 00:00:00 2001 From: basavaraj-sm05 Date: Thu, 27 Aug 2026 16:46:57 +0530 Subject: [PATCH 1/2] require three ASCII digits for the response status code --- .../kotlin/okhttp3/internal/http/StatusLine.kt | 12 ++++++------ .../kotlin/okhttp3/internal/http/StatusLineTest.kt | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt index 354a7bce4ae9..ce1e120f7bb2 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt @@ -73,15 +73,15 @@ class StatusLine( throw ProtocolException("Unexpected status line: $statusLine") } - // Parse response code like "200". Always 3 digits. + // Parse response code like "200". Always 3 ASCII digits. if (statusLine.length < codeStart + 3) { throw ProtocolException("Unexpected status line: $statusLine") } - val code = - statusLine.substring(codeStart, codeStart + 3).toIntOrNull() - ?: throw ProtocolException( - "Unexpected status line: $statusLine", - ) + val codeString = statusLine.substring(codeStart, codeStart + 3) + if (!codeString.all { it in '0'..'9' }) { + throw ProtocolException("Unexpected status line: $statusLine") + } + val code = codeString.toInt() // Parse an optional response message like "OK" or "Not Modified". If it // exists, it is separated from the response code by a space. diff --git a/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/StatusLineTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/StatusLineTest.kt index 9ed49aac2b3a..52a9b5b431f9 100644 --- a/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/StatusLineTest.kt +++ b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/StatusLineTest.kt @@ -99,6 +99,16 @@ class StatusLineTest { assertInvalid("HTTP/1.1 two") } + @Test + fun nonAsciiDigitCode() { + // toIntOrNull() honors a sign prefix and any Unicode decimal digit, so a status code such + // as "+99", "-12" or the Arabic-Indic "٢٠٠" would otherwise be accepted even though + // RFC 9112 defines status-code as three ASCII DIGIT. + assertInvalid("HTTP/1.1 +99 OK") + assertInvalid("HTTP/1.1 -12 OK") + assertInvalid("HTTP/1.1 ٢٠٠ OK") + } + @Test fun truncated() { assertInvalid("") From 1c8e85104003a72d04b89a5d52fa61195eb9b7d5 Mon Sep 17 00:00:00 2001 From: basavaraj-sm05 Date: Fri, 28 Aug 2026 19:34:01 +0530 Subject: [PATCH 2/2] parse the status code chars in place without a substring --- .../kotlin/okhttp3/internal/http/StatusLine.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt index ce1e120f7bb2..724d5dd95280 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt @@ -77,11 +77,14 @@ class StatusLine( if (statusLine.length < codeStart + 3) { throw ProtocolException("Unexpected status line: $statusLine") } - val codeString = statusLine.substring(codeStart, codeStart + 3) - if (!codeString.all { it in '0'..'9' }) { - throw ProtocolException("Unexpected status line: $statusLine") + var code = 0 + for (i in codeStart until codeStart + 3) { + val digit = statusLine[i] + if (digit !in '0'..'9') { + throw ProtocolException("Unexpected status line: $statusLine") + } + code = code * 10 + (digit - '0') } - val code = codeString.toInt() // Parse an optional response message like "OK" or "Not Modified". If it // exists, it is separated from the response code by a space.