"""Data models for HTTP entries.""" from dataclasses import dataclass, field from datetime import datetime from typing import Any @dataclass class Request: """Represents an HTTP request.""" method: str url: str http_version: str = "HTTP/1.1" headers: dict[str, str] = field(default_factory=dict) body: str | None = None query_params: dict[str, str] = field(default_factory=dict) def __post_init__(self) -> None: if isinstance(self.headers, list): self.headers = {h.get("name", ""): h.get("value", "") for h in self.headers} @dataclass class Response: """Represents an HTTP response.""" status: int status_text: str http_version: str = "HTTP/1.1" headers: dict[str, str] = field(default_factory=dict) body: str | None = None content_type: str | None = None response_time_ms: float | None = None def __post_init__(self) -> None: if isinstance(self.headers, list): self.headers = {h.get("name", ""): h.get("value", "") for h in self.headers} @dataclass class HTTPEntry: """Represents a complete HTTP request/response pair.""" id: str request: Request response: Response timestamp: datetime | None = None server_ip: str | None = None connection: str | None = None raw_size: int | None = None source_file: str | None = None @property def duration_ms(self) -> float | None: """Get response time in milliseconds.""" return self.response.response_time_ms @property def content_type(self) -> str | None: """Get content type from response headers.""" if self.response.content_type: return self.response.content_type for key, value in self.response.headers.items(): if key.lower() == "content-type": return value return None @property def endpoint(self) -> str: """Extract endpoint path from URL.""" from urllib.parse import urlparse parsed = urlparse(self.request.url) return parsed.path or "/" @property def host(self) -> str: """Extract host from URL.""" from urllib.parse import urlparse parsed = urlparse(self.request.url) return parsed.netloc def to_dict(self) -> dict[str, Any]: """Convert to dictionary representation.""" return { "id": self.id, "request": { "method": self.request.method, "url": self.request.url, "http_version": self.request.http_version, "headers": self.request.headers, "body": self.request.body, "query_params": self.request.query_params, }, "response": { "status": self.response.status, "status_text": self.response.status_text, "http_version": self.response.http_version, "headers": self.response.headers, "body": self.response.body, "content_type": self.response.content_type, "response_time_ms": self.response.response_time_ms, }, "timestamp": self.timestamp.isoformat() if self.timestamp else None, "server_ip": self.server_ip, "connection": self.connection, "raw_size": self.raw_size, } @dataclass class FilterCriteria: """Criteria for filtering HTTP entries.""" methods: list[str] | None = None status_codes: list[int] | None = None url_pattern: str | None = None content_types: list[str] | None = None start_time: datetime | None = None end_time: datetime | None = None min_response_time_ms: float | None = None max_response_time_ms: float | None = None request_body_contains: str | None = None response_body_contains: str | None = None @dataclass class DiffResult: """Represents the result of comparing two HTTP entries.""" entry1_id: str entry2_id: str request_headers_diff: list[str] = field(default_factory=list) request_body_diff: list[str] = field(default_factory=list) response_headers_diff: list[str] = field(default_factory=list) response_body_diff: list[str] = field(default_factory=list) status_changed: bool = False status1: int = 0 status2: int = 0 url_changed: bool = False