test: avoid http.client for malformed header checks #35647

pull alerodriargui wants to merge 1 commits into bitcoin:master from alerodriargui:fix-interface-http-whitespace-headers changing 1 files +21 −9
  1. alerodriargui commented at 10:39 AM on July 3, 2026: none

    Fixes #35632.

    This updates the malformed whitespace header checks in interface_http.py to send exact raw HTTP requests instead of using http.client to construct and parse deliberately invalid requests.

    The failing case is platform-sensitive: the server can correctly send HTTP/1.1 400 and close the connection, while Python on Windows may surface the close as ConnectionAbortedError before http.client returns an HTTPResponse. Sending raw bytes and checking the raw status line matches the pattern already used by nearby malformed-request tests and keeps the assertion focused on the server behavior.

  2. DrahtBot added the label Tests on Jul 3, 2026
  3. DrahtBot commented at 10:39 AM on July 3, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35647.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Stale ACK pablomartin4btc, ViniciusCestarii

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. pablomartin4btc commented at 2:00 PM on July 3, 2026: member

    ACK 084095a7ac379c1617a410127e7eb63b986ec034

    Good fix — bypassing http.client for these two cases eliminates the Windows-specific race where getresponse() throws ConnectionAbortedError before reading the 400 response. This matches the pattern already used in nearby tests (e.g. check_idle_timeout).

    <details> <summary>I'd suggest refactoring the two cases into a local <code>assert_rejects_bad_header</code> helper — if more whitespace variants are added in the future, each one becomes a two-liner. Also, RFC 7230 §3.2.6 defines field-names as tokens excluding all whitespace (both <code>SP</code> and <code>HTAB</code>); the refactor makes it trivial to add the <code>HTAB</code> case for completeness.</summary>

    Suggested diff at 669c2dcab0 (on top of 084095a7ac).

    --- a/test/functional/interface_http.py
    +++ b/test/functional/interface_http.py
    @@ -552,20 +552,27 @@ class HTTPBasicsTest (BitcoinTestFramework):
     
         def check_whitespace_in_headers(self):
             self.log.info("Check that requests with whitespace in headers are rejected")
    -        # Extra whitespace before colon in header.
    -        conn = BitcoinHTTPConnection(self.node)
             body = '{"method": "getbestblockhash"}'
    -        raw = (
    -            f"POST / HTTP/1.1\r\n"
    -            f"Host: {conn.url.hostname}\r\n"
    -            f"Authorization : Basic {str_to_b64str(conn.authpair)}\r\n"
    -            f"Content-Length: {len(body)}\r\n"
    -            f"\r\n"
    -            f"{body}"
    -        ).encode("ascii")
    -        conn.send_raw(raw)
    -        response = conn.recv_raw().decode()
    -        assert response.startswith("HTTP/1.1 400")
    +
    +        def assert_rejects_bad_header(conn, header_line):
    +            raw = (
    +                f"POST / HTTP/1.1\r\n"
    +                f"Host: {conn.url.hostname}\r\n"
    +                f"{header_line}\r\n"
    +                f"Content-Length: {len(body)}\r\n"
    +                f"\r\n"
    +                f"{body}"
    +            ).encode("ascii")
    +            conn.send_raw(raw)
    +            assert conn.recv_raw().decode().startswith("HTTP/1.1 400")
    +
    +        # Extra whitespace (space) before colon in header field-name.
    +        conn = BitcoinHTTPConnection(self.node)
    +        assert_rejects_bad_header(conn, f"Authorization : Basic {str_to_b64str(conn.authpair)}")
    +
    +        # Extra whitespace (tab) before colon in header field-name.
    +        conn = BitcoinHTTPConnection(self.node)
    +        assert_rejects_bad_header(conn, f"Authorization\t: Basic {str_to_b64str(conn.authpair)}")
     
             # Extra whitespace at start of new line.
             # "line folding" as defined in
    @@ -573,17 +580,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
             # is considered unsafe and is explicitly deprecated in
             # https://www.rfc-editor.org/rfc/rfc7230#section-3.2.4
             conn = BitcoinHTTPConnection(self.node)
    -        raw = (
    -            f"POST / HTTP/1.1\r\n"
    -            f"Host: {conn.url.hostname}\r\n"
    -            f"Authorization: Basic \r\n {str_to_b64str(conn.authpair)}\r\n"
    -            f"Content-Length: {len(body)}\r\n"
    -            f"\r\n"
    -            f"{body}"
    -        ).encode("ascii")
    -        conn.send_raw(raw)
    -        response = conn.recv_raw().decode()
    -        assert response.startswith("HTTP/1.1 400")
    +        assert_rejects_bad_header(conn, f"Authorization: Basic \r\n {str_to_b64str(conn.authpair)}")
     
     
     if __name__ == '__main__':
    

    </details>

  5. alerodriargui commented at 3:37 PM on July 3, 2026: none

    Thanks, good point. I refactored the repeated raw-request/assertion pattern into a local helper and added the HTAB-before-colon case for completeness.

  6. pablomartin4btc commented at 3:41 PM on July 3, 2026: member

    ACK 8d29ace9f2d5d3b12e73e061ac576577245b56c9

  7. in test/functional/interface_http.py:580 in 8d29ace9f2 outdated
     600 | -            f"{body}"
     601 | -        ).encode("ascii")
     602 | -        conn.send_raw(raw)
     603 | -        response = conn.recv_raw().decode()
     604 | -        assert response.startswith("HTTP/1.1 400")
     605 | +        assert_rejects_bad_header("Authorization: Basic \r\n ")
    


    ViniciusCestarii commented at 6:45 PM on July 3, 2026:

    In "Update interface_http.py" 8d29ace9f2d5d3b12e73e061ac576577245b56c9\

    nit: to mirror the new variant extra whitespace before colon in header testing "\t"code there could be here:

    assert_rejects_bad_header("Authorization: Basic \r\n\t")
    

    alerodriargui commented at 7:13 PM on July 3, 2026:

    Thanks, added the folded HTAB case as suggested and squashed the branch back to a single commit.

  8. ViniciusCestarii commented at 6:54 PM on July 3, 2026: contributor

    utACK 8d29ace9f2d5d3b12e73e061ac576577245b56c9 (I couldn't verify the Windows flake myself.)

    nit: the commits could be squashed into a single one.

  9. alerodriargui force-pushed on Jul 3, 2026
  10. alerodriargui force-pushed on Jul 3, 2026
  11. alerodriargui force-pushed on Jul 3, 2026
  12. DrahtBot added the label CI failed on Jul 3, 2026
  13. DrahtBot removed the label CI failed on Jul 3, 2026
  14. test: avoid http.client for malformed header checks 116b68e026
  15. alerodriargui force-pushed on Jul 4, 2026
  16. alerodriargui commented at 8:18 PM on July 4, 2026: none

    Force-pushed a clean single-commit branch on top of current master.

    The diff is still limited to test/functional/interface_http.py and keeps the previously requested helper refactor plus both HTAB cases:

    • whitespace before :: Authorization\t: Basic ...
    • folded whitespace: Authorization: Basic \r\n\t...

    Verified compare state after the push: ahead_by: 1, behind_by: 0, total_commits: 1.

  17. DrahtBot added the label CI failed on Jul 5, 2026
  18. DrahtBot commented at 5:36 PM on July 5, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/actions/runs/28718398451/job/85241060956</sub> <sub>LLM reason (✨ experimental): CI failed due to Python lint errors in test/functional/interface_http.py (missing trailing newline; also incorrect executable permission for the shebang file).</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-07-09 06:47 UTC