Skip to main content

scrapr_core/
request.rs

1use std::collections::HashMap;
2
3/// Options for customizing an HTTP request.
4///
5/// Includes optional headers, cookies, and query parameters.
6#[derive(Clone, Debug, Default)]
7pub struct RequestOptions {
8    /// Custom HTTP headers to send with the request.
9    pub headers: HashMap<String, String>,
10
11    /// Key-value pairs representing cookies.
12    pub cookies: HashMap<String, String>,
13
14    /// Query string parameters to include in the URL.
15    pub query: HashMap<String, String>,
16}
17
18
19
20impl RequestOptions {
21    /// Creates a new `RequestOptions` instance from optional headers, cookies, and query params.
22    ///
23    /// # Arguments
24    ///
25    /// * `headers` - Optional map of header names to values.
26    /// * `cookies` - Optional map of cookie names to values.
27    /// * `query` - Optional map of query parameter names to values.
28    pub fn new(
29        headers: Option<HashMap<String, String>>,
30        cookies: Option<HashMap<String, String>>,
31        query: Option<HashMap<String, String>>,
32    ) -> Self {
33        RequestOptions {
34            headers: headers.unwrap_or_default(),
35            cookies: cookies.unwrap_or_default(),
36            query: query.unwrap_or_default(),
37        }
38    }
39}
40
41/// Constructs a URL string with an optional base, path, and query parameters.
42///
43/// # Arguments
44///
45/// * `base` - Optional base URL prefix (can be empty).
46/// * `path` - The resource path (e.g., `/index.html`).
47/// * `query` - A map of query parameters to append to the URL.
48///
49/// # Returns
50///
51/// A full URL with query string if applicable.
52pub fn build_url(base: &str, path: &str, query: &HashMap<String, String>) -> String {
53    let mut url = format!("{base}{path}");
54    if !query.is_empty() {
55        let query_string = query
56            .iter()
57            .map(|(k, v)| format!("{}={}", k, v))
58            .collect::<Vec<_>>()
59            .join("&");
60        url.push('?');
61        url.push_str(&query_string);
62    }
63    url
64}
65
66/// Formats HTTP headers into a request-ready string.
67///
68/// # Arguments
69///
70/// * `host` - The host name to include in the `Host` header.
71/// * `options` - The `RequestOptions` containing custom headers and cookies.
72///
73/// # Returns
74///
75/// A formatted string of HTTP headers.
76pub fn format_headers(host: &str, options: &RequestOptions) -> String {
77    let mut headers = vec![
78        format!("Host: {host}"),
79        "Connection: close".to_string(),
80        "User-Agent: Scraper/0.1".to_string(),
81    ];
82
83    for (k, v) in &options.headers {
84        headers.push(format!("{k}: {v}"));
85    }
86
87    if !options.cookies.is_empty() {
88        // Cookies should be formatted as `key=value` pairs separated by "; "
89        let cookie_string = options
90            .cookies
91            .iter()
92            .map(|(k, v)| format!("{k}={v}"))
93            .collect::<Vec<_>>()
94            .join("; ");
95        headers.push(format!("Cookie: {cookie_string}"));
96    }
97
98    headers.join("\r\n")
99}