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}