From 27480146d9da472dc81c48bc0543a05dcb38592e Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Mon, 19 Jan 2026 09:47:35 +0100 Subject: [PATCH] fix: handle non-standard decimal status codes (#697) Some IIS servers return status codes like 401.1 or 403.14 (see Microsoft IIS HTTP status codes documentation). These are non-standard but do exist in the wild. The fix truncates at the decimal point since HTTP status codes are defined as 3-digit integers per RFC 7231. --- src/hackney_http.erl | 7 ++++++- test/hackney_http_tests.erl | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/hackney_http.erl b/src/hackney_http.erl index d37b5f93..d2d19931 100644 --- a/src/hackney_http.erl +++ b/src/hackney_http.erl @@ -232,7 +232,12 @@ parse_status(<< C, Rest/bits >>, St, Version, Acc) -> end. parse_reason(Reason, St, Version, StatusCode) -> - StatusInt = list_to_integer(binary_to_list(StatusCode)), + %% Handle non-standard decimal status codes (e.g., 401.1 from IIS) by truncating + StatusCodeInt = case binary:split(StatusCode, <<".">>) of + [IntPart, _DecPart] -> IntPart; + [IntPart] -> IntPart + end, + StatusInt = list_to_integer(binary_to_list(StatusCodeInt)), NState = St#hparser{type=response, version=Version, diff --git a/test/hackney_http_tests.erl b/test/hackney_http_tests.erl index 4b7e7315..a1fed2e4 100644 --- a/test/hackney_http_tests.erl +++ b/test/hackney_http_tests.erl @@ -66,3 +66,18 @@ parse_chunked_response_trailers_test() -> {_, P3} = hackney_http:execute(P2, <<"\r\n">>), {more, P4} = hackney_http:execute(P3, <<"0\r\nFoo: ">>), ?assertEqual({done, <<>>}, hackney_http:execute(P4, <<"Bar\r\n\r\n">>)). + +%% Issue #697: Handle non-standard decimal status codes (e.g., 401.1 from IIS) +parse_response_decimal_status_code_test() -> + Response = <<"HTTP/1.1 401.1 Access Denied">>, + St = #hparser{}, + {response, _Version, StatusInt, Reason, _NState} = hackney_http:parse_response_version(Response, St), + ?assertEqual(401, StatusInt), + ?assertEqual(<<"Access Denied">>, Reason). + +parse_response_decimal_status_code_two_digits_test() -> + Response = <<"HTTP/1.1 403.14 Forbidden">>, + St = #hparser{}, + {response, _Version, StatusInt, Reason, _NState} = hackney_http:parse_response_version(Response, St), + ?assertEqual(403, StatusInt), + ?assertEqual(<<"Forbidden">>, Reason).