standard_plugin/testing/
http.rs1use alloc::collections::VecDeque;
7use alloc::string::{String, ToString};
8use alloc::vec::Vec;
9
10use super::MockHost;
11use crate::daemon::http::{Request, Response, Target, too_long};
12use crate::error::{Error, Result};
13
14#[derive(Clone, Debug)]
17struct Scripted {
18 method: String,
19 prefix: String,
20 answer: Result<Response>,
21}
22
23#[derive(Clone, Debug, Default)]
25pub(crate) struct MockHttp {
26 queue: VecDeque<Scripted>,
27 requests: Vec<Request>,
28}
29
30impl MockHost {
31 pub fn http(mut self, method: &str, url_prefix: &str, response: Response) -> Self {
36 self.queue_http(method, url_prefix, Ok(response));
37 self
38 }
39
40 pub fn queue_http(&mut self, method: &str, url_prefix: &str, answer: Result<Response>) {
44 self.http.queue.push_back(Scripted {
45 method: method.to_ascii_uppercase(),
46 prefix: url_prefix.to_string(),
47 answer,
48 });
49 }
50
51 pub fn http_requests(&self) -> &[Request] {
54 &self.http.requests
55 }
56
57 pub fn http_pending(&self) -> usize {
59 self.http.queue.len()
60 }
61
62 fn send_http(&mut self, request: &Request, target: &Target<'_>) -> Result<Response> {
63 if !self
64 .grants
65 .allows_fetch(target.scheme, &target.host(), target.port())
66 {
67 let Error::GrantDenied { grant } = target.denied() else {
68 unreachable!("a fetch refusal names its grant")
69 };
70 self.denials.push(grant.clone());
71 return Err(Error::GrantDenied { grant });
72 }
73 self.http.requests.push(request.clone());
74 let method = request.method.to_ascii_uppercase();
75 let index = self.http.queue.iter().position(|scripted| {
76 (scripted.method == "*" || scripted.method == method)
77 && request.url.starts_with(&scripted.prefix)
78 });
79 let Some(scripted) = index.and_then(|index| self.http.queue.remove(index)) else {
80 return Err(Error::Unavailable(alloc::format!(
81 "no response queued for {method} {}",
82 request.url
83 )));
84 };
85 let response = scripted.answer?;
86 if response.body.len() > request.max_body {
87 return Err(too_long(request.max_body));
88 }
89 Ok(response)
90 }
91}
92
93pub(crate) fn send(request: &Request, target: &Target<'_>) -> Result<Response> {
95 super::with_host(|host| host.send_http(request, target))
96}