use serde::{Deserialize, Serialize};
use super::network::{Request, ResourceType};
pub type RequestId = String;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HeaderEntry {
pub name: String,
pub value: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum RequestStage {
#[default]
Request,
Response,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct RequestPattern {
#[serde(skip_serializing_if = "Option::is_none")]
pub url_pattern: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_type: Option<ResourceType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request_stage: Option<RequestStage>,
}
impl RequestPattern {
pub fn all() -> Self {
Self::default()
}
pub fn url(pattern: impl Into<String>) -> Self {
Self {
url_pattern: Some(pattern.into()),
..Default::default()
}
}
#[must_use]
pub fn with_resource_type(mut self, resource_type: ResourceType) -> Self {
self.resource_type = Some(resource_type);
self
}
#[must_use]
pub fn with_stage(mut self, stage: RequestStage) -> Self {
self.request_stage = Some(stage);
self
}
}
#[derive(Debug, Clone, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct EnableParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub patterns: Option<Vec<RequestPattern>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle_auth_requests: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct DisableParams {}
#[derive(Debug, Clone, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ContinueRequestParams {
pub request_id: RequestId,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub post_data: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<Vec<HeaderEntry>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub intercept_response: Option<bool>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FulfillRequestParams {
pub request_id: RequestId,
pub response_code: i32,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_headers: Option<Vec<HeaderEntry>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub binary_response_headers: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_phrase: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FailRequestParams {
pub request_id: RequestId,
pub error_reason: ErrorReason,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetResponseBodyParams {
pub request_id: RequestId,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetResponseBodyResult {
pub body: String,
pub base64_encoded: bool,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ContinueWithAuthParams {
pub request_id: RequestId,
pub auth_challenge_response: AuthChallengeResponse,
}
#[derive(Debug, Clone, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ContinueResponseParams {
pub request_id: RequestId,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_code: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_phrase: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_headers: Option<Vec<HeaderEntry>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub binary_response_headers: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RequestPausedEvent {
pub request_id: RequestId,
pub request: Request,
pub frame_id: String,
pub resource_type: ResourceType,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_error_reason: Option<ErrorReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_status_code: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_status_text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_headers: Option<Vec<HeaderEntry>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub network_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub redirected_request_id: Option<RequestId>,
}
impl RequestPausedEvent {
pub fn is_response_stage(&self) -> bool {
self.response_error_reason.is_some() || self.response_status_code.is_some()
}
pub fn is_request_stage(&self) -> bool {
!self.is_response_stage()
}
pub fn is_redirect(&self) -> bool {
if let Some(code) = self.response_status_code {
matches!(code, 301 | 302 | 303 | 307 | 308)
&& self.response_headers.as_ref().is_some_and(|headers| {
headers
.iter()
.any(|h| h.name.eq_ignore_ascii_case("location"))
})
} else {
false
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthRequiredEvent {
pub request_id: RequestId,
pub request: Request,
pub frame_id: String,
pub resource_type: ResourceType,
pub auth_challenge: AuthChallenge,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum ErrorReason {
#[default]
Failed,
Aborted,
TimedOut,
AccessDenied,
ConnectionClosed,
ConnectionReset,
ConnectionRefused,
ConnectionAborted,
ConnectionFailed,
NameNotResolved,
InternetDisconnected,
AddressUnreachable,
BlockedByClient,
BlockedByResponse,
}
impl ErrorReason {
pub fn as_str(&self) -> &'static str {
match self {
Self::Failed => "Failed",
Self::Aborted => "Aborted",
Self::TimedOut => "TimedOut",
Self::AccessDenied => "AccessDenied",
Self::ConnectionClosed => "ConnectionClosed",
Self::ConnectionReset => "ConnectionReset",
Self::ConnectionRefused => "ConnectionRefused",
Self::ConnectionAborted => "ConnectionAborted",
Self::ConnectionFailed => "ConnectionFailed",
Self::NameNotResolved => "NameNotResolved",
Self::InternetDisconnected => "InternetDisconnected",
Self::AddressUnreachable => "AddressUnreachable",
Self::BlockedByClient => "BlockedByClient",
Self::BlockedByResponse => "BlockedByResponse",
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthChallenge {
pub source: AuthChallengeSource,
pub origin: String,
pub scheme: String,
pub realm: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AuthChallengeSource {
Server,
Proxy,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthChallengeResponse {
pub response: AuthChallengeResponseType,
#[serde(skip_serializing_if = "Option::is_none")]
pub username: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub password: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AuthChallengeResponseType {
Default,
CancelAuth,
ProvideCredentials,
}
impl AuthChallengeResponse {
pub fn default_response() -> Self {
Self {
response: AuthChallengeResponseType::Default,
username: None,
password: None,
}
}
pub fn cancel() -> Self {
Self {
response: AuthChallengeResponseType::CancelAuth,
username: None,
password: None,
}
}
pub fn provide_credentials(username: impl Into<String>, password: impl Into<String>) -> Self {
Self {
response: AuthChallengeResponseType::ProvideCredentials,
username: Some(username.into()),
password: Some(password.into()),
}
}
}