wreq_util/
emulation.rs

1mod device;
2#[cfg(feature = "emulation-rand")]
3mod rand;
4
5use device::{chrome::*, firefox::*, okhttp::*, opera::*, safari::*};
6#[cfg(feature = "emulation-serde")]
7use serde::{Deserialize, Serialize};
8#[cfg(feature = "emulation-rand")]
9use strum_macros::VariantArray;
10use typed_builder::TypedBuilder;
11
12macro_rules! define_enum {
13    (
14        $(#[$meta:meta])*
15        with_dispatch,
16        $name:ident, $default_variant:ident,
17        $(
18            $variant:ident => ($rename:expr, $emulation_fn:path)
19        ),* $(,)?
20    ) => {
21        $(#[$meta])*
22        #[non_exhaustive]
23        #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
24        #[cfg_attr(feature = "emulation-rand", derive(VariantArray))]
25        #[cfg_attr(feature = "emulation-serde", derive(Deserialize, Serialize))]
26        pub enum $name {
27            $(
28                #[cfg_attr(feature = "emulation-serde", serde(rename = $rename))]
29                $variant,
30            )*
31        }
32
33        impl Default for $name {
34            fn default() -> Self {
35                $name::$default_variant
36            }
37        }
38
39        impl $name {
40            pub fn into_emulation(self, opt: EmulationOption) -> wreq::Emulation {
41                match self {
42                    $(
43                        $name::$variant => $emulation_fn(opt),
44                    )*
45                }
46            }
47        }
48    };
49
50    (
51        $(#[$meta:meta])*
52        plain,
53        $name:ident, $default_variant:ident,
54        $(
55            $variant:ident => $rename:expr
56        ),* $(,)?
57    ) => {
58        $(#[$meta])*
59        #[non_exhaustive]
60        #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
61        #[cfg_attr(feature = "emulation-rand", derive(VariantArray))]
62        #[cfg_attr(feature = "emulation-serde", derive(Deserialize, Serialize))]
63        pub enum $name {
64            $(
65                #[cfg_attr(feature = "emulation-serde", serde(rename = $rename))]
66                $variant,
67            )*
68        }
69
70        impl Default for $name {
71            fn default() -> Self {
72                $name::$default_variant
73            }
74        }
75    };
76}
77
78define_enum!(
79    /// Represents different browser versions for emulation.
80    ///
81    /// The `Emulation` enum provides variants for different browser versions that can be used
82    /// to emulation HTTP requests. Each variant corresponds to a specific browser version.
83    ///
84    /// # Naming Convention
85    ///
86    /// The naming convention for the variants follows the pattern `browser_version`, where
87    /// `browser` is the name of the browser (e.g., `chrome`, `firefox`, `safari`) and `version`
88    /// is the version number. For example, `Chrome100` represents Chrome version 100.
89    ///
90    /// The serialized names of the variants use underscores to separate the browser name and
91    /// version number, following the pattern `browser_version`. For example, `Chrome100` is
92    /// serialized as `"chrome_100"`.
93    with_dispatch,
94    Emulation, Chrome100,
95
96    // Chrome versions
97    Chrome100 => ("chrome_100", v100::emulation),
98    Chrome101 => ("chrome_101", v101::emulation),
99    Chrome104 => ("chrome_104", v104::emulation),
100    Chrome105 => ("chrome_105", v105::emulation),
101    Chrome106 => ("chrome_106", v106::emulation),
102    Chrome107 => ("chrome_107", v107::emulation),
103    Chrome108 => ("chrome_108", v108::emulation),
104    Chrome109 => ("chrome_109", v109::emulation),
105    Chrome110 => ("chrome_110", v110::emulation),
106    Chrome114 => ("chrome_114", v114::emulation),
107    Chrome116 => ("chrome_116", v116::emulation),
108    Chrome117 => ("chrome_117", v117::emulation),
109    Chrome118 => ("chrome_118", v118::emulation),
110    Chrome119 => ("chrome_119", v119::emulation),
111    Chrome120 => ("chrome_120", v120::emulation),
112    Chrome123 => ("chrome_123", v123::emulation),
113    Chrome124 => ("chrome_124", v124::emulation),
114    Chrome126 => ("chrome_126", v126::emulation),
115    Chrome127 => ("chrome_127", v127::emulation),
116    Chrome128 => ("chrome_128", v128::emulation),
117    Chrome129 => ("chrome_129", v129::emulation),
118    Chrome130 => ("chrome_130", v130::emulation),
119    Chrome131 => ("chrome_131", v131::emulation),
120    Chrome132 => ("chrome_132", v132::emulation),
121    Chrome133 => ("chrome_133", v133::emulation),
122    Chrome134 => ("chrome_134", v134::emulation),
123    Chrome135 => ("chrome_135", v135::emulation),
124    Chrome136 => ("chrome_136", v136::emulation),
125    Chrome137 => ("chrome_137", v137::emulation),
126    Chrome138 => ("chrome_138", v138::emulation),
127    Chrome139 => ("chrome_139", v139::emulation),
128    Chrome140 => ("chrome_140", v140::emulation),
129    Chrome141 => ("chrome_141", v141::emulation),
130    Chrome142 => ("chrome_142", v142::emulation),
131    Chrome143 => ("chrome_143", v143::emulation),
132
133    // Edge versions
134    Edge101 => ("edge_101", edge101::emulation),
135    Edge122 => ("edge_122", edge122::emulation),
136    Edge127 => ("edge_127", edge127::emulation),
137    Edge131 => ("edge_131", edge131::emulation),
138    Edge134 => ("edge_134", edge134::emulation),
139    Edge135 => ("edge_135", edge135::emulation),
140    Edge136 => ("edge_136", edge136::emulation),
141    Edge137 => ("edge_137", edge137::emulation),
142    Edge138 => ("edge_138", edge138::emulation),
143    Edge139 => ("edge_139", edge139::emulation),
144    Edge140 => ("edge_140", edge140::emulation),
145    Edge141 => ("edge_141", edge141::emulation),
146    Edge142 => ("edge_142", edge142::emulation),
147
148    // Opera versions
149    Opera116 => ("opera_116", opera116::emulation),
150    Opera117 => ("opera_117", opera117::emulation),
151    Opera118 => ("opera_118", opera118::emulation),
152    Opera119 => ("opera_119", opera119::emulation),
153
154    // Safari versions
155    SafariIos17_2 => ("safari_ios_17.2", safari_ios_17_2::emulation),
156    SafariIos17_4_1 => ("safari_ios_17.4.1", safari_ios_17_4_1::emulation),
157    SafariIos16_5 => ("safari_ios_16.5", safari_ios_16_5::emulation),
158    Safari15_3 => ("safari_15.3", safari15_3::emulation),
159    Safari15_5 => ("safari_15.5", safari15_5::emulation),
160    Safari15_6_1 => ("safari_15.6.1", safari15_6_1::emulation),
161    Safari16 => ("safari_16", safari16::emulation),
162    Safari16_5 => ("safari_16.5", safari16_5::emulation),
163    Safari17_0 => ("safari_17.0", safari17_0::emulation),
164    Safari17_2_1 => ("safari_17.2.1", safari17_2_1::emulation),
165    Safari17_4_1 => ("safari_17.4.1", safari17_4_1::emulation),
166    Safari17_5 => ("safari_17.5", safari17_5::emulation),
167    Safari17_6 => ("safari_17.6", safari17_6::emulation),
168    Safari18 => ("safari_18", safari18::emulation),
169    SafariIPad18 => ("safari_ipad_18", safari_ipad_18::emulation),
170    Safari18_2 => ("safari_18.2", safari18_2::emulation),
171    SafariIos18_1_1 => ("safari_ios_18.1.1", safari_ios_18_1_1::emulation),
172    Safari18_3 => ("safari_18.3", safari18_3::emulation),
173    Safari18_3_1 => ("safari_18.3.1", safari18_3_1::emulation),
174    Safari18_5 => ("safari_18.5", safari18_5::emulation),
175    Safari26 => ("safari_26", safari26::emulation),
176    Safari26_1 => ("safari_26.1", safari26_1::emulation),
177    Safari26_2 => ("safari_26.2", safari26_2::emulation),
178    SafariIPad26 => ("safari_ipad_26", safari_ipad_26::emulation),
179    SafariIpad26_2 => ("safari_ipad_26.2", safari_ipad_26_2::emulation),
180    SafariIos26 => ("safari_ios_26", safari_ios_26::emulation),
181    SafariIos26_2 => ("safari_ios_26.2", safari_ios_26_2::emulation),
182
183    // Firefox versions
184    Firefox109 => ("firefox_109", ff109::emulation),
185    Firefox117 => ("firefox_117", ff117::emulation),
186    Firefox128 => ("firefox_128", ff128::emulation),
187    Firefox133 => ("firefox_133", ff133::emulation),
188    Firefox135 => ("firefox_135", ff135::emulation),
189    FirefoxPrivate135 => ("firefox_private_135", ff_private_135::emulation),
190    FirefoxAndroid135 => ("firefox_android_135", ff_android_135::emulation),
191    Firefox136 => ("firefox_136", ff136::emulation),
192    FirefoxPrivate136 => ("firefox_private_136", ff_private_136::emulation),
193    Firefox139 => ("firefox_139", ff139::emulation),
194    Firefox142 => ("firefox_142", ff142::emulation),
195    Firefox143 => ("firefox_143", ff143::emulation),
196    Firefox144 => ("firefox_144", ff144::emulation),
197    Firefox145 => ("firefox_145", ff145::emulation),
198
199    // OkHttp versions
200    OkHttp3_9 => ("okhttp_3.9", okhttp3_9::emulation),
201    OkHttp3_11 => ("okhttp_3.11", okhttp3_11::emulation),
202    OkHttp3_13 => ("okhttp_3.13", okhttp3_13::emulation),
203    OkHttp3_14 => ("okhttp_3.14", okhttp3_14::emulation),
204    OkHttp4_9 => ("okhttp_4.9", okhttp4_9::emulation),
205    OkHttp4_10 => ("okhttp_4.10", okhttp4_10::emulation),
206    OkHttp4_12 => ("okhttp_4.12", okhttp4_12::emulation),
207    OkHttp5 => ("okhttp_5", okhttp5::emulation)
208
209);
210
211/// ======== Emulation impls ========
212impl wreq::EmulationFactory for Emulation {
213    #[inline]
214    fn emulation(self) -> wreq::Emulation {
215        EmulationOption::builder()
216            .emulation(self)
217            .build()
218            .emulation()
219    }
220}
221
222define_enum!(
223    /// Represents different operating systems for emulation.
224    ///
225    /// The `EmulationOS` enum provides variants for different operating systems that can be used
226    /// to emulation HTTP requests. Each variant corresponds to a specific operating system.
227    ///
228    /// # Naming Convention
229    ///
230    /// The naming convention for the variants follows the pattern `os_name`, where
231    /// `os_name` is the name of the operating system (e.g., `windows`, `macos`, `linux`, `android`, `ios`).
232    ///
233    /// The serialized names of the variants use lowercase letters to represent the operating system names.
234    /// For example, `Windows` is serialized as `"windows"`.
235    plain,
236    EmulationOS, MacOS,
237    Windows => "windows",
238    MacOS => "macos",
239    Linux => "linux",
240    Android => "android",
241    IOS => "ios"
242);
243
244/// ======== EmulationOS impls ========
245impl EmulationOS {
246    #[inline]
247    const fn platform(&self) -> &'static str {
248        match self {
249            EmulationOS::MacOS => "\"macOS\"",
250            EmulationOS::Linux => "\"Linux\"",
251            EmulationOS::Windows => "\"Windows\"",
252            EmulationOS::Android => "\"Android\"",
253            EmulationOS::IOS => "\"iOS\"",
254        }
255    }
256
257    #[inline]
258    const fn is_mobile(&self) -> bool {
259        matches!(self, EmulationOS::Android | EmulationOS::IOS)
260    }
261}
262
263/// Represents the configuration options for emulating a browser and operating system.
264///
265/// The `EmulationOption` struct allows you to configure various aspects of browser and OS
266/// emulation, including the browser version, operating system, and whether to skip certain features
267/// like HTTP/2 or headers.
268///
269/// This struct is typically used to build an `EmulationProvider` that can be applied to HTTP
270/// clients for making requests that mimic specific browser and OS configurations.
271///
272/// # Fields
273///
274/// - `emulation`: The browser version to emulate. Defaults to `Emulation::default()`.
275/// - `emulation_os`: The operating system to emulate. Defaults to `EmulationOS::default()`.
276/// - `skip_http2`: Whether to skip HTTP/2 support. Defaults to `false`.
277/// - `skip_headers`: Whether to skip adding default headers. Defaults to `false`.
278#[derive(Default, Clone, TypedBuilder)]
279pub struct EmulationOption {
280    /// The browser version to emulation.
281    #[builder(default)]
282    emulation: Emulation,
283
284    /// The operating system.
285    #[builder(default)]
286    emulation_os: EmulationOS,
287
288    /// Whether to skip HTTP/2.
289    #[builder(default = false)]
290    skip_http2: bool,
291
292    /// Whether to skip headers.
293    #[builder(default = false)]
294    skip_headers: bool,
295}
296
297/// ======== EmulationOption impls ========
298impl wreq::EmulationFactory for EmulationOption {
299    #[inline]
300    fn emulation(self) -> wreq::Emulation {
301        self.emulation.into_emulation(self)
302    }
303}