use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct InterceptedRequest {
pub request_id: String,
pub url: String,
pub method: String,
pub headers: HashMap<String, String>,
pub resource_type: String,
pub tab_id: u32,
pub frame_id: u64,
pub body: Option<RequestBody>,
}
#[derive(Debug, Clone)]
pub enum RequestBody {
FormData(HashMap<String, Vec<String>>),
Raw(Vec<u8>),
Error(String),
}
#[derive(Debug, Clone)]
pub enum RequestAction {
Allow,
Block,
Redirect(String),
}
impl RequestAction {
#[inline]
#[must_use]
pub fn allow() -> Self {
Self::Allow
}
#[inline]
#[must_use]
pub fn block() -> Self {
Self::Block
}
#[inline]
#[must_use]
pub fn redirect(url: impl Into<String>) -> Self {
Self::Redirect(url.into())
}
}
#[derive(Debug, Clone)]
pub struct InterceptedRequestBody {
pub request_id: String,
pub url: String,
pub method: String,
pub resource_type: String,
pub tab_id: u32,
pub frame_id: u64,
pub body: Option<RequestBody>,
}
#[derive(Debug, Clone)]
pub struct InterceptedRequestHeaders {
pub request_id: String,
pub url: String,
pub method: String,
pub headers: HashMap<String, String>,
pub tab_id: u32,
pub frame_id: u64,
}
#[derive(Debug, Clone)]
pub enum HeadersAction {
Allow,
Modify {
headers: HashMap<String, String>,
status_code: Option<u16>,
},
Block,
}
impl HeadersAction {
#[inline]
#[must_use]
pub fn allow() -> Self {
Self::Allow
}
#[inline]
#[must_use]
pub fn block() -> Self {
Self::Block
}
#[inline]
#[must_use]
pub fn modify_headers(headers: HashMap<String, String>) -> Self {
Self::Modify {
headers,
status_code: None,
}
}
#[inline]
#[must_use]
pub fn modify_headers_with_status(
headers: HashMap<String, String>,
status_code: u16,
) -> Self {
Self::Modify {
headers,
status_code: Some(status_code),
}
}
}
#[derive(Debug, Clone)]
pub struct InterceptedResponse {
pub request_id: String,
pub url: String,
pub status: u16,
pub status_text: String,
pub headers: HashMap<String, String>,
pub tab_id: u32,
pub frame_id: u64,
}
#[derive(Debug, Clone)]
pub enum ResponseAction {
Allow,
Block,
Modify {
body: String,
},
Fulfill {
status: u16,
headers: HashMap<String, String>,
body: String,
},
}
impl ResponseAction {
#[inline]
#[must_use]
pub fn allow() -> Self {
Self::Allow
}
#[inline]
#[must_use]
pub fn block() -> Self {
Self::Block
}
#[inline]
#[must_use]
pub fn modify(body: impl Into<String>) -> Self {
Self::Modify { body: body.into() }
}
#[inline]
#[must_use]
pub fn fulfill(
status: u16,
headers: HashMap<String, String>,
body: impl Into<String>,
) -> Self {
Self::Fulfill {
status,
headers,
body: body.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct InterceptedResponseBody {
pub request_id: String,
pub url: String,
pub status: u16,
pub content_type: String,
pub body: ResponseBodyData,
pub tab_id: u32,
pub frame_id: u64,
pub content_length: usize,
}
#[derive(Debug, Clone)]
pub enum ResponseBodyData {
Text(String),
Binary(Vec<u8>),
}
impl ResponseBodyData {
#[inline]
#[must_use]
pub fn as_text(&self) -> Option<&str> {
match self {
Self::Text(s) => Some(s),
Self::Binary(_) => None,
}
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
Self::Text(_) => None,
Self::Binary(b) => Some(b),
}
}
#[inline]
#[must_use]
pub fn is_text(&self) -> bool {
matches!(self, Self::Text(_))
}
#[inline]
#[must_use]
pub fn is_binary(&self) -> bool {
matches!(self, Self::Binary(_))
}
}
#[derive(Debug, Clone)]
pub enum BodyAction {
Allow,
ModifyBody(String),
}
impl BodyAction {
#[inline]
#[must_use]
pub fn allow() -> Self {
Self::Allow
}
#[inline]
#[must_use]
pub fn modify_body(body: impl Into<String>) -> Self {
Self::ModifyBody(body.into())
}
}
#[cfg(test)]
mod tests {
use super::{BodyAction, HeadersAction, RequestAction, ResponseAction, ResponseBodyData};
use std::collections::HashMap;
#[test]
fn test_request_action_allow() {
let action = RequestAction::allow();
assert!(matches!(action, RequestAction::Allow));
}
#[test]
fn test_request_action_block() {
let action = RequestAction::block();
assert!(matches!(action, RequestAction::Block));
}
#[test]
fn test_request_action_redirect() {
let action = RequestAction::redirect("https://example.com");
if let RequestAction::Redirect(url) = action {
assert_eq!(url, "https://example.com");
} else {
panic!("Expected Redirect action");
}
}
#[test]
fn test_headers_action_allow() {
let action = HeadersAction::allow();
assert!(matches!(action, HeadersAction::Allow));
}
#[test]
fn test_headers_action_block() {
let action = HeadersAction::block();
assert!(matches!(action, HeadersAction::Block));
}
#[test]
fn test_headers_action_modify() {
let mut headers = HashMap::new();
headers.insert("X-Custom".to_string(), "value".to_string());
let action = HeadersAction::modify_headers(headers);
if let HeadersAction::Modify {
headers: h,
status_code,
} = action
{
assert_eq!(h.get("X-Custom"), Some(&"value".to_string()));
assert!(status_code.is_none());
} else {
panic!("Expected Modify action");
}
}
#[test]
fn test_headers_action_modify_with_status() {
let mut headers = HashMap::new();
headers.insert("X-Custom".to_string(), "value".to_string());
let action = HeadersAction::modify_headers_with_status(headers, 404);
if let HeadersAction::Modify {
headers: h,
status_code,
} = action
{
assert_eq!(h.get("X-Custom"), Some(&"value".to_string()));
assert_eq!(status_code, Some(404));
} else {
panic!("Expected Modify action with status");
}
}
#[test]
fn test_response_action_allow() {
let action = ResponseAction::allow();
assert!(matches!(action, ResponseAction::Allow));
}
#[test]
fn test_response_action_block() {
let action = ResponseAction::block();
assert!(matches!(action, ResponseAction::Block));
}
#[test]
fn test_response_action_modify() {
let action = ResponseAction::modify("new body");
if let ResponseAction::Modify { body } = action {
assert_eq!(body, "new body");
} else {
panic!("Expected Modify action");
}
}
#[test]
fn test_response_action_fulfill() {
let mut headers = HashMap::new();
headers.insert("Content-Type".to_string(), "application/json".to_string());
let action = ResponseAction::fulfill(200, headers, r#"{"ok": true}"#);
if let ResponseAction::Fulfill {
status,
headers: h,
body,
} = action
{
assert_eq!(status, 200);
assert_eq!(
h.get("Content-Type"),
Some(&"application/json".to_string())
);
assert_eq!(body, r#"{"ok": true}"#);
} else {
panic!("Expected Fulfill action");
}
}
#[test]
fn test_body_action_allow() {
let action = BodyAction::allow();
assert!(matches!(action, BodyAction::Allow));
}
#[test]
fn test_body_action_modify() {
let action = BodyAction::modify_body("new body");
if let BodyAction::ModifyBody(body) = action {
assert_eq!(body, "new body");
} else {
panic!("Expected ModifyBody action");
}
}
#[test]
fn test_response_body_data_text() {
let data = ResponseBodyData::Text("hello".to_string());
assert!(data.is_text());
assert!(!data.is_binary());
assert_eq!(data.as_text(), Some("hello"));
assert!(data.as_bytes().is_none());
}
#[test]
fn test_response_body_data_binary() {
let data = ResponseBodyData::Binary(vec![0x89, 0x50, 0x4E, 0x47]);
assert!(!data.is_text());
assert!(data.is_binary());
assert!(data.as_text().is_none());
assert_eq!(data.as_bytes(), Some(&[0x89, 0x50, 0x4E, 0x47][..]));
}
}