playwright/api/
request.rs

1use crate::{
2    api::{Frame, Response},
3    imp::{core::*, prelude::*, request::Request as Impl, utils::ResponseTiming}
4};
5
6/// Whenever the page sends a request for a network resource the following sequence of events are emitted by `Page`:
7/// - [`event: Page.request`] emitted when the request is issued by the page.
8/// - [`event: Page.response`] emitted when/if the response status and headers are received for the request.
9/// - [`event: Page.requestFinished`] emitted when the response body is downloaded and the request is complete.
10///
11/// If request fails at some point, then instead of `'requestfinished'` event (and possibly instead of 'response' event),
12/// the  [`event: Page.requestFailed`] event is emitted.
13///
14/// > NOTE: HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will
15/// complete with `'requestfinished'` event.
16///
17/// If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new
18/// request is  issued to a redirected url.
19#[derive(Clone)]
20pub struct Request {
21    inner: Weak<Impl>
22}
23
24impl PartialEq for Request {
25    fn eq(&self, other: &Self) -> bool {
26        let a = self.inner.upgrade();
27        let b = other.inner.upgrade();
28        a.and_then(|a| b.map(|b| (a, b)))
29            .map(|(a, b)| a.guid() == b.guid())
30            .unwrap_or_default()
31    }
32}
33
34impl Request {
35    pub(crate) fn new(inner: Weak<Impl>) -> Self { Self { inner } }
36
37    /// Request's method (GET, POST, etc.)
38    pub fn method(&self) -> Result<String, Error> { Ok(upgrade(&self.inner)?.method().into()) }
39
40    /// Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
41    /// following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`,
42    /// `websocket`, `manifest`, `other`.
43    pub fn resource_type(&self) -> Result<String, Error> {
44        Ok(upgrade(&self.inner)?.resource_type().into())
45    }
46
47    pub fn url(&self) -> Result<String, Error> { Ok(upgrade(&self.inner)?.url().into()) }
48
49    /// Whether this request is driving frame's navigation.
50    pub fn is_navigation_request(&self) -> Result<bool, Error> {
51        Ok(upgrade(&self.inner)?.is_navigation_request())
52    }
53
54    /// Returns the `Frame` that initiated this request.
55    pub fn frame(&self) -> Frame {
56        let inner = weak_and_then(&self.inner, |rc| rc.frame());
57        Frame::new(inner)
58    }
59
60    pub fn post_data(&self) -> Result<Option<Vec<u8>>, Error> {
61        Ok(upgrade(&self.inner)?.post_data())
62    }
63
64    pub fn post_post_as_string(&self) -> Result<Option<String>, Error> {
65        Ok(upgrade(&self.inner)?.post_data_as_string())
66    }
67
68    /// An object with HTTP headers associated with the request. All header names are lower-case.
69    pub fn headers(&self) -> Result<HashMap<String, String>, Error> {
70        Ok(upgrade(&self.inner)?.headers().clone())
71    }
72
73    /// Request that was redirected by the server to this one, if any.
74    ///
75    /// When the server responds with a redirect, Playwright creates a new `Request` object. The two requests are connected by
76    /// `redirectedFrom()` and `redirectedTo()` methods. When multiple server redirects has happened, it is possible to
77    /// construct the whole redirect chain by repeatedly calling `redirectedFrom()`.
78    ///
79    /// For example, if the website `http://example.com` redirects to `https://example.com`:
80    ///
81    /// ```js
82    /// const response = await page.goto('http://example.com');
83    /// console.log(response.request().redirectedFrom().url()); // 'http://example.com'
84    /// ```
85    ///
86    /// If the website `https://google.com` has no redirects:
87    ///
88    /// ```js
89    /// const response = await page.goto('https://google.com');
90    /// console.log(response.request().redirectedFrom()); // null
91    /// ```
92    pub fn redirected_from(&self) -> Result<Option<Request>, Error> {
93        Ok(upgrade(&self.inner)?.redirected_from().map(Request::new))
94    }
95
96    pub async fn redirected_to(&self) -> Result<Option<Request>, Error> {
97        Ok(upgrade(&self.inner)?.redirected_to().map(Request::new))
98    }
99
100    /// Returns the matching `Response` object, or `null` if the response was not received due to error.
101    pub async fn response(&self) -> Result<Option<Response>, Arc<Error>> {
102        Ok(upgrade(&self.inner)?.response().await?.map(Response::new))
103    }
104
105    /// The method returns `null` unless this request has failed, as reported by `requestfailed` event.
106    ///
107    /// Example of logging of all the failed requests:
108    ///
109    /// ```js
110    /// page.on('requestfailed', request => {
111    ///  console.log(request.url() + ' ' + request.failure().errorText);
112    /// });
113    /// ```
114    pub fn failure(&self) -> Result<Option<String>, Error> { Ok(upgrade(&self.inner)?.failure()) }
115
116    /// Returns resource timing information for given request. Most of the timing values become available upon the response,
117    /// `responseEnd` becomes available when request finishes. Find more information at
118    /// [Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming).
119    ///
120    /// ```js
121    /// const [request] = await Promise.all([
122    ///  page.waitForEvent('requestfinished'),
123    ///  page.goto('http://example.com')
124    /// ]);
125    /// console.log(request.timing());
126    /// ```
127    pub fn timing(&self) -> Result<Option<ResponseTiming>, Error> {
128        Ok(upgrade(&self.inner)?.timing())
129    }
130
131    pub fn response_end(&self) -> Result<Option<f64>, Error> {
132        Ok(upgrade(&self.inner)?.response_end())
133    }
134}