From 08abd021f644125288f921c369b78413c2d66588 Mon Sep 17 00:00:00 2001 From: hannahwestra25 Date: Tue, 24 Mar 2026 12:53:22 -0400 Subject: [PATCH 1/3] fix pre-commit error --- pyrit/prompt_target/http_target/http_target.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrit/prompt_target/http_target/http_target.py b/pyrit/prompt_target/http_target/http_target.py index 1aeee2b6e..71dd5c716 100644 --- a/pyrit/prompt_target/http_target/http_target.py +++ b/pyrit/prompt_target/http_target/http_target.py @@ -240,7 +240,7 @@ def parse_raw_http_request(self, http_request: str) -> tuple[dict[str, str], Req body = "" # Support both LF and CRLF raw HTTP requests (e.g. copied from Burp). - request_parts = re.split(r"\r?\n\r?\n", http_request.strip(), maxsplit=1) + request_parts = re.split(r"\r?\n\r?\n", http_request.strip(), 1) # Parse out the header components header_lines = request_parts[0].strip().splitlines() From 4faf67312edf83cf894a78f0653fe06dac1293c5 Mon Sep 17 00:00:00 2001 From: hannahwestra25 Date: Tue, 24 Mar 2026 13:09:05 -0400 Subject: [PATCH 2/3] revert --- .../prompt_target/http_target/http_target.py | 6 +++--- tests/unit/target/test_http_target_parsing.py | 19 ------------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/pyrit/prompt_target/http_target/http_target.py b/pyrit/prompt_target/http_target/http_target.py index 71dd5c716..2a045de51 100644 --- a/pyrit/prompt_target/http_target/http_target.py +++ b/pyrit/prompt_target/http_target/http_target.py @@ -239,11 +239,11 @@ def parse_raw_http_request(self, http_request: str) -> tuple[dict[str, str], Req body = "" - # Support both LF and CRLF raw HTTP requests (e.g. copied from Burp). - request_parts = re.split(r"\r?\n\r?\n", http_request.strip(), 1) + # Split the request into headers and body by finding the double newlines (\n\n) + request_parts = http_request.strip().split("\n\n", 1) # Parse out the header components - header_lines = request_parts[0].strip().splitlines() + header_lines = request_parts[0].strip().split("\n") http_req_info_line = header_lines[0].split(" ") # get 1st line like POST /url_ending HTTP_VSN header_lines = header_lines[1:] # rest of the raw request is the headers info diff --git a/tests/unit/target/test_http_target_parsing.py b/tests/unit/target/test_http_target_parsing.py index c0c64904c..d69e79acd 100644 --- a/tests/unit/target/test_http_target_parsing.py +++ b/tests/unit/target/test_http_target_parsing.py @@ -59,25 +59,6 @@ def test_parse_raw_http_request(mock_http_target): assert version == "HTTP/1.1" -def test_parse_raw_http_request_with_crlf_line_endings(sqlite_instance): - request = ( - "POST /submit HTTP/1.1\r\n" - "Host: example.com\r\n" - "Content-Type: application/json\r\n" - "\r\n" - '{"prompt": "{PLACEHOLDER_PROMPT}"}' - ) - target = HTTPTarget(http_request=request) - - headers, body, url, method, version = target.parse_raw_http_request(request) - - assert url == "https://example.com/submit" - assert method == "POST" - assert headers == {"host": "example.com", "content-type": "application/json"} - assert body == '{"prompt": "{PLACEHOLDER_PROMPT}"}' - assert version == "HTTP/1.1" - - def test_parse_raw_http_request_preserves_relative_url_case(sqlite_instance): request = "GET /CaseSensitive/Run?token=AbC123&Mode=Keep HTTP/1.1\nHost: Example.COM\n\n" target = HTTPTarget(http_request=request) From d80ac8106bb57b3878bc76c55147c4d98bb24dbf Mon Sep 17 00:00:00 2001 From: hannahwestra25 Date: Tue, 24 Mar 2026 13:30:42 -0400 Subject: [PATCH 3/3] restore func --- .../prompt_target/http_target/http_target.py | 5 +++-- tests/unit/target/test_http_target_parsing.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/pyrit/prompt_target/http_target/http_target.py b/pyrit/prompt_target/http_target/http_target.py index 2a045de51..48e6a24c1 100644 --- a/pyrit/prompt_target/http_target/http_target.py +++ b/pyrit/prompt_target/http_target/http_target.py @@ -239,8 +239,9 @@ def parse_raw_http_request(self, http_request: str) -> tuple[dict[str, str], Req body = "" - # Split the request into headers and body by finding the double newlines (\n\n) - request_parts = http_request.strip().split("\n\n", 1) + # Support both LF and CRLF raw HTTP requests (e.g. copied from Burp). + normalized = http_request.strip().replace("\r\n", "\n") + request_parts = normalized.split("\n\n", 1) # Parse out the header components header_lines = request_parts[0].strip().split("\n") diff --git a/tests/unit/target/test_http_target_parsing.py b/tests/unit/target/test_http_target_parsing.py index d69e79acd..c0c64904c 100644 --- a/tests/unit/target/test_http_target_parsing.py +++ b/tests/unit/target/test_http_target_parsing.py @@ -59,6 +59,25 @@ def test_parse_raw_http_request(mock_http_target): assert version == "HTTP/1.1" +def test_parse_raw_http_request_with_crlf_line_endings(sqlite_instance): + request = ( + "POST /submit HTTP/1.1\r\n" + "Host: example.com\r\n" + "Content-Type: application/json\r\n" + "\r\n" + '{"prompt": "{PLACEHOLDER_PROMPT}"}' + ) + target = HTTPTarget(http_request=request) + + headers, body, url, method, version = target.parse_raw_http_request(request) + + assert url == "https://example.com/submit" + assert method == "POST" + assert headers == {"host": "example.com", "content-type": "application/json"} + assert body == '{"prompt": "{PLACEHOLDER_PROMPT}"}' + assert version == "HTTP/1.1" + + def test_parse_raw_http_request_preserves_relative_url_case(sqlite_instance): request = "GET /CaseSensitive/Run?token=AbC123&Mode=Keep HTTP/1.1\nHost: Example.COM\n\n" target = HTTPTarget(http_request=request)