Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions pyrit/prompt_target/http_target/httpx_api_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from pyrit.common.deprecation import print_deprecation_message
from pyrit.models import (
ComponentIdentifier,
Message,
MessagePiece,
construct_response_from_request,
Expand Down Expand Up @@ -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)
Expand All @@ -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]:
"""
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/prompt_target/target/test_http_api_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -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