diff --git a/pyrit/prompt_target/http_target/httpx_api_target.py b/pyrit/prompt_target/http_target/httpx_api_target.py index a5c90ae994..c2fa35a0bd 100644 --- a/pyrit/prompt_target/http_target/httpx_api_target.py +++ b/pyrit/prompt_target/http_target/httpx_api_target.py @@ -13,6 +13,7 @@ from pyrit.common.deprecation import print_deprecation_message from pyrit.models import ( + ComponentIdentifier, Message, MessagePiece, construct_response_from_request, @@ -117,6 +118,8 @@ def __init__( ) self.http_url = http_url + self._endpoint = http_url + self._destination_origin = self._get_destination_origin(http_url) self.method = method self.file_path = file_path self.allowed_upload_directory = self._resolve_allowed_upload_directory(allowed_upload_directory) @@ -130,6 +133,22 @@ def __init__( if self.method not in {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}: raise ValueError(f"Invalid HTTP method: {self.method}") + def _build_identifier(self) -> ComponentIdentifier: + """ + Build the identifier with HTTPX API target-specific parameters. + + Returns: + ComponentIdentifier: The identifier for this target instance. + """ + return self._create_identifier( + params={ + "method": self.method, + "follow_redirects": self.follow_redirects, + "callback_function": getattr(self.callback_function, "__name__", None), + "http2": self.http2, + }, + ) + @limit_requests_per_minute async def _send_prompt_to_target_async(self, *, normalized_conversation: list[Message]) -> list[Message]: """ diff --git a/tests/unit/prompt_target/target/test_http_api_target.py b/tests/unit/prompt_target/target/test_http_api_target.py index d9e4196d92..3b163940d3 100644 --- a/tests/unit/prompt_target/target/test_http_api_target.py +++ b/tests/unit/prompt_target/target/test_http_api_target.py @@ -363,3 +363,28 @@ async def test_send_prompt_async_validates_upload_method_after_path(mock_request await target.send_prompt_async(message=message) mock_request.assert_not_called() + + +def test_httpx_api_target_identifier_fields(patch_central_database): + target = HTTPXAPITarget( + http_url="https://example.com/api/v1", + method="POST", + http2=True, + follow_redirects=False, + ) + identifier = target.get_identifier() + + assert identifier.endpoint == "https://example.com/api/v1" + assert identifier.params["method"] == "POST" + assert identifier.params["follow_redirects"] is False + assert identifier.params["http2"] is True + assert target._destination_origin == ("https", "example.com", None) + + +def test_httpx_api_target_identifier_distinguishes_urls_and_methods(patch_central_database): + first = HTTPXAPITarget(http_url="https://example.com/api/v1", method="POST") + different_url = HTTPXAPITarget(http_url="https://different.org/api/v2", method="POST") + different_method = HTTPXAPITarget(http_url="https://example.com/api/v1", method="GET") + + assert first.get_identifier().hash != different_url.get_identifier().hash + assert first.get_identifier().hash != different_method.get_identifier().hash