crawlberg 1.7.1 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/crawlberg_rb/native/Cargo.lock +433 -160
- data/ext/crawlberg_rb/native/Cargo.toml +4 -4
- data/ext/crawlberg_rb/src/lib.rs +687 -47
- data/lib/crawlberg/native.rb +24 -47
- data/lib/crawlberg/version.rb +2 -2
- data/sig/types.rbs +55 -56
- metadata +2 -2
data/ext/crawlberg_rb/src/lib.rs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// This file is auto-generated by alef. DO NOT EDIT.
|
|
2
|
-
// alef:hash:
|
|
2
|
+
// alef:hash:51d55e2247bdc2514829f3eaafb5c8524624f269469856210cf0950e6c206e7f
|
|
3
3
|
// Re-generate with: alef generate
|
|
4
4
|
#![allow(dead_code, unused_imports, unused_variables)]
|
|
5
5
|
#![allow(
|
|
@@ -821,7 +821,7 @@ impl BatchScrapeResults {
|
|
|
821
821
|
}
|
|
822
822
|
}
|
|
823
823
|
|
|
824
|
-
#[derive(Clone,
|
|
824
|
+
#[derive(Clone, serde::Serialize)]
|
|
825
825
|
#[serde(default)]
|
|
826
826
|
#[magnus::wrap(class = "Crawlberg::BrowserConfig")]
|
|
827
827
|
pub struct BrowserConfig {
|
|
@@ -830,6 +830,8 @@ pub struct BrowserConfig {
|
|
|
830
830
|
endpoint: Option<String>,
|
|
831
831
|
#[serde(default = "default_timeout")]
|
|
832
832
|
timeout: u64,
|
|
833
|
+
overall_timeout: u64,
|
|
834
|
+
shutdown_timeout: u64,
|
|
833
835
|
wait: BrowserWait,
|
|
834
836
|
wait_selector: Option<String>,
|
|
835
837
|
extra_wait: Option<u64>,
|
|
@@ -839,6 +841,8 @@ pub struct BrowserConfig {
|
|
|
839
841
|
robots_user_agent: Option<String>,
|
|
840
842
|
capture_network_events: bool,
|
|
841
843
|
session_affinity: bool,
|
|
844
|
+
chrome_path: Option<String>,
|
|
845
|
+
chrome_args: Vec<String>,
|
|
842
846
|
}
|
|
843
847
|
|
|
844
848
|
unsafe impl IntoValueFromNative for BrowserConfig {}
|
|
@@ -868,6 +872,29 @@ impl magnus::TryConvert for BrowserConfig {
|
|
|
868
872
|
}
|
|
869
873
|
|
|
870
874
|
unsafe impl TryConvertOwned for BrowserConfig {}
|
|
875
|
+
impl std::fmt::Debug for BrowserConfig {
|
|
876
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
877
|
+
let mut debug = f.debug_struct("BrowserConfig");
|
|
878
|
+
debug.field("mode", &self.mode);
|
|
879
|
+
debug.field("backend", &self.backend);
|
|
880
|
+
debug.field("endpoint", &"<redacted>");
|
|
881
|
+
debug.field("timeout", &self.timeout);
|
|
882
|
+
debug.field("overall_timeout", &self.overall_timeout);
|
|
883
|
+
debug.field("shutdown_timeout", &self.shutdown_timeout);
|
|
884
|
+
debug.field("wait", &self.wait);
|
|
885
|
+
debug.field("wait_selector", &self.wait_selector);
|
|
886
|
+
debug.field("extra_wait", &self.extra_wait);
|
|
887
|
+
debug.field("proxy", &self.proxy);
|
|
888
|
+
debug.field("block_url_patterns", &self.block_url_patterns);
|
|
889
|
+
debug.field("eval_script", &"<redacted>");
|
|
890
|
+
debug.field("robots_user_agent", &self.robots_user_agent);
|
|
891
|
+
debug.field("capture_network_events", &self.capture_network_events);
|
|
892
|
+
debug.field("session_affinity", &self.session_affinity);
|
|
893
|
+
debug.field("chrome_path", &self.chrome_path);
|
|
894
|
+
debug.field("chrome_args", &"<redacted>");
|
|
895
|
+
debug.finish()
|
|
896
|
+
}
|
|
897
|
+
}
|
|
871
898
|
impl<'de> serde::Deserialize<'de> for BrowserConfig {
|
|
872
899
|
fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
|
|
873
900
|
where
|
|
@@ -926,6 +953,24 @@ impl BrowserConfig {
|
|
|
926
953
|
})?,
|
|
927
954
|
None => 30000,
|
|
928
955
|
},
|
|
956
|
+
overall_timeout: match kwargs.get(ruby.to_symbol("overall_timeout")) {
|
|
957
|
+
Some(v) => u64::try_convert(v).map_err(|e| {
|
|
958
|
+
magnus::Error::new(
|
|
959
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
960
|
+
format!("invalid value for `overall_timeout`: {}", e),
|
|
961
|
+
)
|
|
962
|
+
})?,
|
|
963
|
+
None => 60000,
|
|
964
|
+
},
|
|
965
|
+
shutdown_timeout: match kwargs.get(ruby.to_symbol("shutdown_timeout")) {
|
|
966
|
+
Some(v) => u64::try_convert(v).map_err(|e| {
|
|
967
|
+
magnus::Error::new(
|
|
968
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
969
|
+
format!("invalid value for `shutdown_timeout`: {}", e),
|
|
970
|
+
)
|
|
971
|
+
})?,
|
|
972
|
+
None => 5000,
|
|
973
|
+
},
|
|
929
974
|
wait: match kwargs.get(ruby.to_symbol("wait")) {
|
|
930
975
|
Some(v) => BrowserWait::try_convert(v).map_err(|e| {
|
|
931
976
|
magnus::Error::new(
|
|
@@ -1007,6 +1052,24 @@ impl BrowserConfig {
|
|
|
1007
1052
|
})?,
|
|
1008
1053
|
None => true,
|
|
1009
1054
|
},
|
|
1055
|
+
chrome_path: match kwargs.get(ruby.to_symbol("chrome_path")).filter(|v| !v.is_nil()) {
|
|
1056
|
+
Some(v) => Some(String::try_convert(v).map_err(|e| {
|
|
1057
|
+
magnus::Error::new(
|
|
1058
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
1059
|
+
format!("invalid value for `chrome_path`: {}", e),
|
|
1060
|
+
)
|
|
1061
|
+
})?),
|
|
1062
|
+
None => None,
|
|
1063
|
+
},
|
|
1064
|
+
chrome_args: match kwargs.get(ruby.to_symbol("chrome_args")) {
|
|
1065
|
+
Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
|
|
1066
|
+
magnus::Error::new(
|
|
1067
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
1068
|
+
format!("invalid value for `chrome_args`: {}", e),
|
|
1069
|
+
)
|
|
1070
|
+
})?,
|
|
1071
|
+
None => Default::default(),
|
|
1072
|
+
},
|
|
1010
1073
|
})
|
|
1011
1074
|
}
|
|
1012
1075
|
|
|
@@ -1026,6 +1089,14 @@ impl BrowserConfig {
|
|
|
1026
1089
|
self.timeout.clone()
|
|
1027
1090
|
}
|
|
1028
1091
|
|
|
1092
|
+
fn overall_timeout(&self) -> u64 {
|
|
1093
|
+
self.overall_timeout.clone()
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
fn shutdown_timeout(&self) -> u64 {
|
|
1097
|
+
self.shutdown_timeout.clone()
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1029
1100
|
fn wait(&self) -> BrowserWait {
|
|
1030
1101
|
self.wait.clone()
|
|
1031
1102
|
}
|
|
@@ -1061,6 +1132,14 @@ impl BrowserConfig {
|
|
|
1061
1132
|
fn session_affinity(&self) -> bool {
|
|
1062
1133
|
self.session_affinity
|
|
1063
1134
|
}
|
|
1135
|
+
|
|
1136
|
+
fn chrome_path(&self) -> Option<String> {
|
|
1137
|
+
self.chrome_path.clone()
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
fn chrome_args(&self) -> Vec<String> {
|
|
1141
|
+
self.chrome_args.clone()
|
|
1142
|
+
}
|
|
1064
1143
|
}
|
|
1065
1144
|
|
|
1066
1145
|
#[derive(Clone, Debug, serde::Serialize)]
|
|
@@ -1357,6 +1436,7 @@ pub struct ContentConfig {
|
|
|
1357
1436
|
wrap: bool,
|
|
1358
1437
|
wrap_width: usize,
|
|
1359
1438
|
include_document_structure: bool,
|
|
1439
|
+
extract_metadata: bool,
|
|
1360
1440
|
}
|
|
1361
1441
|
|
|
1362
1442
|
unsafe impl IntoValueFromNative for ContentConfig {}
|
|
@@ -1516,6 +1596,15 @@ impl ContentConfig {
|
|
|
1516
1596
|
})?,
|
|
1517
1597
|
None => true,
|
|
1518
1598
|
},
|
|
1599
|
+
extract_metadata: match kwargs.get(ruby.to_symbol("extract_metadata")) {
|
|
1600
|
+
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
1601
|
+
magnus::Error::new(
|
|
1602
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
1603
|
+
format!("invalid value for `extract_metadata`: {}", e),
|
|
1604
|
+
)
|
|
1605
|
+
})?,
|
|
1606
|
+
None => true,
|
|
1607
|
+
},
|
|
1519
1608
|
})
|
|
1520
1609
|
}
|
|
1521
1610
|
|
|
@@ -1566,9 +1655,13 @@ impl ContentConfig {
|
|
|
1566
1655
|
fn include_document_structure(&self) -> bool {
|
|
1567
1656
|
self.include_document_structure
|
|
1568
1657
|
}
|
|
1658
|
+
|
|
1659
|
+
fn extract_metadata(&self) -> bool {
|
|
1660
|
+
self.extract_metadata
|
|
1661
|
+
}
|
|
1569
1662
|
}
|
|
1570
1663
|
|
|
1571
|
-
#[derive(Clone,
|
|
1664
|
+
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
1572
1665
|
#[serde(default)]
|
|
1573
1666
|
#[magnus::wrap(class = "Crawlberg::CookieInfo")]
|
|
1574
1667
|
pub struct CookieInfo {
|
|
@@ -1605,6 +1698,16 @@ impl magnus::TryConvert for CookieInfo {
|
|
|
1605
1698
|
}
|
|
1606
1699
|
|
|
1607
1700
|
unsafe impl TryConvertOwned for CookieInfo {}
|
|
1701
|
+
impl std::fmt::Debug for CookieInfo {
|
|
1702
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
1703
|
+
let mut debug = f.debug_struct("CookieInfo");
|
|
1704
|
+
debug.field("name", &self.name);
|
|
1705
|
+
debug.field("value", &"<redacted>");
|
|
1706
|
+
debug.field("domain", &self.domain);
|
|
1707
|
+
debug.field("path", &self.path);
|
|
1708
|
+
debug.finish()
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1608
1711
|
|
|
1609
1712
|
impl Default for CookieInfo {
|
|
1610
1713
|
fn default() -> Self {
|
|
@@ -1675,7 +1778,7 @@ impl CookieInfo {
|
|
|
1675
1778
|
}
|
|
1676
1779
|
}
|
|
1677
1780
|
|
|
1678
|
-
#[derive(Clone,
|
|
1781
|
+
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
1679
1782
|
#[serde(default)]
|
|
1680
1783
|
#[magnus::wrap(class = "Crawlberg::CrawlConfig")]
|
|
1681
1784
|
pub struct CrawlConfig {
|
|
@@ -1694,6 +1797,11 @@ pub struct CrawlConfig {
|
|
|
1694
1797
|
allow_subdomains: bool,
|
|
1695
1798
|
include_paths: Vec<String>,
|
|
1696
1799
|
exclude_paths: Vec<String>,
|
|
1800
|
+
path_patterns_match_query: bool,
|
|
1801
|
+
path_patterns_match_url: bool,
|
|
1802
|
+
dedup_include_query: bool,
|
|
1803
|
+
strip_tracking_params: bool,
|
|
1804
|
+
tracking_params: Vec<String>,
|
|
1697
1805
|
custom_headers: HashMap<String, String>,
|
|
1698
1806
|
#[serde(default = "default_timeout")]
|
|
1699
1807
|
request_timeout: u64,
|
|
@@ -1701,6 +1809,9 @@ pub struct CrawlConfig {
|
|
|
1701
1809
|
max_redirects: usize,
|
|
1702
1810
|
retry_count: usize,
|
|
1703
1811
|
retry_codes: Vec<u16>,
|
|
1812
|
+
retry_initial_delay_ms: u64,
|
|
1813
|
+
retry_max_delay_ms: u64,
|
|
1814
|
+
rate_limit_jitter_ratio: f64,
|
|
1704
1815
|
cookies_enabled: bool,
|
|
1705
1816
|
auth: Option<AuthConfig>,
|
|
1706
1817
|
max_body_size: Option<usize>,
|
|
@@ -1756,6 +1867,67 @@ impl magnus::TryConvert for CrawlConfig {
|
|
|
1756
1867
|
}
|
|
1757
1868
|
|
|
1758
1869
|
unsafe impl TryConvertOwned for CrawlConfig {}
|
|
1870
|
+
impl std::fmt::Debug for CrawlConfig {
|
|
1871
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
1872
|
+
let mut debug = f.debug_struct("CrawlConfig");
|
|
1873
|
+
debug.field("max_depth", &self.max_depth);
|
|
1874
|
+
debug.field("max_pages", &self.max_pages);
|
|
1875
|
+
debug.field("max_links_per_page", &self.max_links_per_page);
|
|
1876
|
+
debug.field("max_concurrent", &self.max_concurrent);
|
|
1877
|
+
debug.field("crawl_strategy", &self.crawl_strategy);
|
|
1878
|
+
debug.field("content_filter", &self.content_filter);
|
|
1879
|
+
debug.field("bm25_query", &self.bm25_query);
|
|
1880
|
+
debug.field("bm25_threshold", &self.bm25_threshold);
|
|
1881
|
+
debug.field("respect_robots_txt", &self.respect_robots_txt);
|
|
1882
|
+
debug.field("soft_http_errors", &self.soft_http_errors);
|
|
1883
|
+
debug.field("user_agent", &self.user_agent);
|
|
1884
|
+
debug.field("stay_on_domain", &self.stay_on_domain);
|
|
1885
|
+
debug.field("allow_subdomains", &self.allow_subdomains);
|
|
1886
|
+
debug.field("include_paths", &self.include_paths);
|
|
1887
|
+
debug.field("exclude_paths", &self.exclude_paths);
|
|
1888
|
+
debug.field("path_patterns_match_query", &self.path_patterns_match_query);
|
|
1889
|
+
debug.field("path_patterns_match_url", &self.path_patterns_match_url);
|
|
1890
|
+
debug.field("dedup_include_query", &self.dedup_include_query);
|
|
1891
|
+
debug.field("strip_tracking_params", &self.strip_tracking_params);
|
|
1892
|
+
debug.field("tracking_params", &self.tracking_params);
|
|
1893
|
+
debug.field("custom_headers", &"<redacted>");
|
|
1894
|
+
debug.field("request_timeout", &self.request_timeout);
|
|
1895
|
+
debug.field("rate_limit_ms", &self.rate_limit_ms);
|
|
1896
|
+
debug.field("max_redirects", &self.max_redirects);
|
|
1897
|
+
debug.field("retry_count", &self.retry_count);
|
|
1898
|
+
debug.field("retry_codes", &self.retry_codes);
|
|
1899
|
+
debug.field("retry_initial_delay_ms", &self.retry_initial_delay_ms);
|
|
1900
|
+
debug.field("retry_max_delay_ms", &self.retry_max_delay_ms);
|
|
1901
|
+
debug.field("rate_limit_jitter_ratio", &self.rate_limit_jitter_ratio);
|
|
1902
|
+
debug.field("cookies_enabled", &self.cookies_enabled);
|
|
1903
|
+
debug.field("auth", &self.auth);
|
|
1904
|
+
debug.field("max_body_size", &self.max_body_size);
|
|
1905
|
+
debug.field("remove_tags", &self.remove_tags);
|
|
1906
|
+
debug.field("content", &self.content);
|
|
1907
|
+
debug.field("map_limit", &self.map_limit);
|
|
1908
|
+
debug.field("map_search", &self.map_search);
|
|
1909
|
+
debug.field("download_assets", &self.download_assets);
|
|
1910
|
+
debug.field("asset_types", &self.asset_types);
|
|
1911
|
+
debug.field("max_asset_size", &self.max_asset_size);
|
|
1912
|
+
debug.field("browser", &self.browser);
|
|
1913
|
+
debug.field("proxy", &self.proxy);
|
|
1914
|
+
debug.field("user_agents", &self.user_agents);
|
|
1915
|
+
debug.field("capture_screenshot", &self.capture_screenshot);
|
|
1916
|
+
debug.field("follow_document_urls", &self.follow_document_urls);
|
|
1917
|
+
debug.field("document_url_depth", &self.document_url_depth);
|
|
1918
|
+
debug.field("download_documents", &self.download_documents);
|
|
1919
|
+
debug.field("document_max_size", &self.document_max_size);
|
|
1920
|
+
debug.field("document_mime_types", &self.document_mime_types);
|
|
1921
|
+
debug.field("document_output_dir", &self.document_output_dir);
|
|
1922
|
+
debug.field("document_content_encoding", &self.document_content_encoding);
|
|
1923
|
+
debug.field("warc_output", &self.warc_output);
|
|
1924
|
+
debug.field("browser_profile", &self.browser_profile);
|
|
1925
|
+
debug.field("save_browser_profile", &self.save_browser_profile);
|
|
1926
|
+
debug.field("ssrf", &self.ssrf);
|
|
1927
|
+
debug.field("ssrf_deny_private_explicit", &self.ssrf_deny_private_explicit);
|
|
1928
|
+
debug.finish()
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1759
1931
|
|
|
1760
1932
|
impl Default for CrawlConfig {
|
|
1761
1933
|
fn default() -> Self {
|
|
@@ -1905,6 +2077,56 @@ impl CrawlConfig {
|
|
|
1905
2077
|
})?,
|
|
1906
2078
|
None => Default::default(),
|
|
1907
2079
|
},
|
|
2080
|
+
path_patterns_match_query: match kwargs.get(ruby.to_symbol("path_patterns_match_query")) {
|
|
2081
|
+
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
2082
|
+
magnus::Error::new(
|
|
2083
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2084
|
+
format!("invalid value for `path_patterns_match_query`: {}", e),
|
|
2085
|
+
)
|
|
2086
|
+
})?,
|
|
2087
|
+
None => false,
|
|
2088
|
+
},
|
|
2089
|
+
path_patterns_match_url: match kwargs.get(ruby.to_symbol("path_patterns_match_url")) {
|
|
2090
|
+
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
2091
|
+
magnus::Error::new(
|
|
2092
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2093
|
+
format!("invalid value for `path_patterns_match_url`: {}", e),
|
|
2094
|
+
)
|
|
2095
|
+
})?,
|
|
2096
|
+
None => false,
|
|
2097
|
+
},
|
|
2098
|
+
dedup_include_query: match kwargs.get(ruby.to_symbol("dedup_include_query")) {
|
|
2099
|
+
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
2100
|
+
magnus::Error::new(
|
|
2101
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2102
|
+
format!("invalid value for `dedup_include_query`: {}", e),
|
|
2103
|
+
)
|
|
2104
|
+
})?,
|
|
2105
|
+
None => false,
|
|
2106
|
+
},
|
|
2107
|
+
strip_tracking_params: match kwargs.get(ruby.to_symbol("strip_tracking_params")) {
|
|
2108
|
+
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
2109
|
+
magnus::Error::new(
|
|
2110
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2111
|
+
format!("invalid value for `strip_tracking_params`: {}", e),
|
|
2112
|
+
)
|
|
2113
|
+
})?,
|
|
2114
|
+
None => false,
|
|
2115
|
+
},
|
|
2116
|
+
tracking_params: match kwargs.get(ruby.to_symbol("tracking_params")) {
|
|
2117
|
+
Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
|
|
2118
|
+
magnus::Error::new(
|
|
2119
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2120
|
+
format!("invalid value for `tracking_params`: {}", e),
|
|
2121
|
+
)
|
|
2122
|
+
})?,
|
|
2123
|
+
None => vec![
|
|
2124
|
+
"utm_*".to_string(),
|
|
2125
|
+
"fbclid".to_string(),
|
|
2126
|
+
"gclid".to_string(),
|
|
2127
|
+
"ref".to_string(),
|
|
2128
|
+
],
|
|
2129
|
+
},
|
|
1908
2130
|
custom_headers: match kwargs.get(ruby.to_symbol("custom_headers")) {
|
|
1909
2131
|
Some(v) => <HashMap<String, String>>::try_convert(v).map_err(|e| {
|
|
1910
2132
|
magnus::Error::new(
|
|
@@ -1959,6 +2181,33 @@ impl CrawlConfig {
|
|
|
1959
2181
|
})?,
|
|
1960
2182
|
None => Default::default(),
|
|
1961
2183
|
},
|
|
2184
|
+
retry_initial_delay_ms: match kwargs.get(ruby.to_symbol("retry_initial_delay_ms")) {
|
|
2185
|
+
Some(v) => u64::try_convert(v).map_err(|e| {
|
|
2186
|
+
magnus::Error::new(
|
|
2187
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2188
|
+
format!("invalid value for `retry_initial_delay_ms`: {}", e),
|
|
2189
|
+
)
|
|
2190
|
+
})?,
|
|
2191
|
+
None => 100,
|
|
2192
|
+
},
|
|
2193
|
+
retry_max_delay_ms: match kwargs.get(ruby.to_symbol("retry_max_delay_ms")) {
|
|
2194
|
+
Some(v) => u64::try_convert(v).map_err(|e| {
|
|
2195
|
+
magnus::Error::new(
|
|
2196
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2197
|
+
format!("invalid value for `retry_max_delay_ms`: {}", e),
|
|
2198
|
+
)
|
|
2199
|
+
})?,
|
|
2200
|
+
None => 60000,
|
|
2201
|
+
},
|
|
2202
|
+
rate_limit_jitter_ratio: match kwargs.get(ruby.to_symbol("rate_limit_jitter_ratio")) {
|
|
2203
|
+
Some(v) => f64::try_convert(v).map_err(|e| {
|
|
2204
|
+
magnus::Error::new(
|
|
2205
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
2206
|
+
format!("invalid value for `rate_limit_jitter_ratio`: {}", e),
|
|
2207
|
+
)
|
|
2208
|
+
})?,
|
|
2209
|
+
None => 0.0,
|
|
2210
|
+
},
|
|
1962
2211
|
cookies_enabled: match kwargs.get(ruby.to_symbol("cookies_enabled")) {
|
|
1963
2212
|
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
1964
2213
|
magnus::Error::new(
|
|
@@ -2265,6 +2514,26 @@ impl CrawlConfig {
|
|
|
2265
2514
|
self.exclude_paths.clone()
|
|
2266
2515
|
}
|
|
2267
2516
|
|
|
2517
|
+
fn path_patterns_match_query(&self) -> bool {
|
|
2518
|
+
self.path_patterns_match_query
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
fn path_patterns_match_url(&self) -> bool {
|
|
2522
|
+
self.path_patterns_match_url
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
fn dedup_include_query(&self) -> bool {
|
|
2526
|
+
self.dedup_include_query
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
fn strip_tracking_params(&self) -> bool {
|
|
2530
|
+
self.strip_tracking_params
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
fn tracking_params(&self) -> Vec<String> {
|
|
2534
|
+
self.tracking_params.clone()
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2268
2537
|
fn custom_headers(&self) -> HashMap<String, String> {
|
|
2269
2538
|
self.custom_headers.clone()
|
|
2270
2539
|
}
|
|
@@ -2289,6 +2558,18 @@ impl CrawlConfig {
|
|
|
2289
2558
|
self.retry_codes.clone()
|
|
2290
2559
|
}
|
|
2291
2560
|
|
|
2561
|
+
fn retry_initial_delay_ms(&self) -> u64 {
|
|
2562
|
+
self.retry_initial_delay_ms
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
fn retry_max_delay_ms(&self) -> u64 {
|
|
2566
|
+
self.retry_max_delay_ms
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
fn rate_limit_jitter_ratio(&self) -> f64 {
|
|
2570
|
+
self.rate_limit_jitter_ratio
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2292
2573
|
fn cookies_enabled(&self) -> bool {
|
|
2293
2574
|
self.cookies_enabled
|
|
2294
2575
|
}
|
|
@@ -2426,6 +2707,16 @@ impl CrawlConfig {
|
|
|
2426
2707
|
|
|
2427
2708
|
exclude_paths: self.exclude_paths.clone(),
|
|
2428
2709
|
|
|
2710
|
+
path_patterns_match_query: self.path_patterns_match_query,
|
|
2711
|
+
|
|
2712
|
+
path_patterns_match_url: self.path_patterns_match_url,
|
|
2713
|
+
|
|
2714
|
+
dedup_include_query: self.dedup_include_query,
|
|
2715
|
+
|
|
2716
|
+
strip_tracking_params: self.strip_tracking_params,
|
|
2717
|
+
|
|
2718
|
+
tracking_params: self.tracking_params.clone(),
|
|
2719
|
+
|
|
2429
2720
|
custom_headers: self
|
|
2430
2721
|
.custom_headers
|
|
2431
2722
|
.clone()
|
|
@@ -2443,6 +2734,12 @@ impl CrawlConfig {
|
|
|
2443
2734
|
|
|
2444
2735
|
retry_codes: self.retry_codes.clone(),
|
|
2445
2736
|
|
|
2737
|
+
retry_initial_delay_ms: self.retry_initial_delay_ms,
|
|
2738
|
+
|
|
2739
|
+
retry_max_delay_ms: self.retry_max_delay_ms,
|
|
2740
|
+
|
|
2741
|
+
rate_limit_jitter_ratio: self.rate_limit_jitter_ratio,
|
|
2742
|
+
|
|
2446
2743
|
cookies_enabled: self.cookies_enabled,
|
|
2447
2744
|
|
|
2448
2745
|
auth: self.auth.clone().map(Into::into),
|
|
@@ -2619,7 +2916,7 @@ impl CrawlEngineHandle {
|
|
|
2619
2916
|
}
|
|
2620
2917
|
}
|
|
2621
2918
|
|
|
2622
|
-
#[derive(Clone, Debug, serde::Serialize
|
|
2919
|
+
#[derive(Clone, Debug, serde::Serialize)]
|
|
2623
2920
|
#[serde(default)]
|
|
2624
2921
|
#[magnus::wrap(class = "Crawlberg::CrawlPageResult")]
|
|
2625
2922
|
pub struct CrawlPageResult {
|
|
@@ -2644,6 +2941,11 @@ pub struct CrawlPageResult {
|
|
|
2644
2941
|
extraction_meta: Option<ExtractionMeta>,
|
|
2645
2942
|
downloaded_document: Option<DownloadedDocument>,
|
|
2646
2943
|
browser_used: bool,
|
|
2944
|
+
final_url: String,
|
|
2945
|
+
redirect_count: usize,
|
|
2946
|
+
noindex_detected: bool,
|
|
2947
|
+
nofollow_detected: bool,
|
|
2948
|
+
ssrf_refused_urls: Vec<String>,
|
|
2647
2949
|
}
|
|
2648
2950
|
|
|
2649
2951
|
unsafe impl IntoValueFromNative for CrawlPageResult {}
|
|
@@ -2673,6 +2975,14 @@ impl magnus::TryConvert for CrawlPageResult {
|
|
|
2673
2975
|
}
|
|
2674
2976
|
|
|
2675
2977
|
unsafe impl TryConvertOwned for CrawlPageResult {}
|
|
2978
|
+
impl<'de> serde::Deserialize<'de> for CrawlPageResult {
|
|
2979
|
+
fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
|
|
2980
|
+
where
|
|
2981
|
+
D: serde::Deserializer<'de>,
|
|
2982
|
+
{
|
|
2983
|
+
<crawlberg::CrawlPageResult as serde::Deserialize>::deserialize(deserializer).map(Into::into)
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2676
2986
|
|
|
2677
2987
|
impl Default for CrawlPageResult {
|
|
2678
2988
|
fn default() -> Self {
|
|
@@ -2879,6 +3189,51 @@ impl CrawlPageResult {
|
|
|
2879
3189
|
})?,
|
|
2880
3190
|
None => Default::default(),
|
|
2881
3191
|
},
|
|
3192
|
+
final_url: match kwargs.get(ruby.to_symbol("final_url")) {
|
|
3193
|
+
Some(v) => String::try_convert(v).map_err(|e| {
|
|
3194
|
+
magnus::Error::new(
|
|
3195
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
3196
|
+
format!("invalid value for `final_url`: {}", e),
|
|
3197
|
+
)
|
|
3198
|
+
})?,
|
|
3199
|
+
None => Default::default(),
|
|
3200
|
+
},
|
|
3201
|
+
redirect_count: match kwargs.get(ruby.to_symbol("redirect_count")) {
|
|
3202
|
+
Some(v) => usize::try_convert(v).map_err(|e| {
|
|
3203
|
+
magnus::Error::new(
|
|
3204
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
3205
|
+
format!("invalid value for `redirect_count`: {}", e),
|
|
3206
|
+
)
|
|
3207
|
+
})?,
|
|
3208
|
+
None => Default::default(),
|
|
3209
|
+
},
|
|
3210
|
+
noindex_detected: match kwargs.get(ruby.to_symbol("noindex_detected")) {
|
|
3211
|
+
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
3212
|
+
magnus::Error::new(
|
|
3213
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
3214
|
+
format!("invalid value for `noindex_detected`: {}", e),
|
|
3215
|
+
)
|
|
3216
|
+
})?,
|
|
3217
|
+
None => Default::default(),
|
|
3218
|
+
},
|
|
3219
|
+
nofollow_detected: match kwargs.get(ruby.to_symbol("nofollow_detected")) {
|
|
3220
|
+
Some(v) => bool::try_convert(v).map_err(|e| {
|
|
3221
|
+
magnus::Error::new(
|
|
3222
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
3223
|
+
format!("invalid value for `nofollow_detected`: {}", e),
|
|
3224
|
+
)
|
|
3225
|
+
})?,
|
|
3226
|
+
None => Default::default(),
|
|
3227
|
+
},
|
|
3228
|
+
ssrf_refused_urls: match kwargs.get(ruby.to_symbol("ssrf_refused_urls")) {
|
|
3229
|
+
Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
|
|
3230
|
+
magnus::Error::new(
|
|
3231
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
3232
|
+
format!("invalid value for `ssrf_refused_urls`: {}", e),
|
|
3233
|
+
)
|
|
3234
|
+
})?,
|
|
3235
|
+
None => Default::default(),
|
|
3236
|
+
},
|
|
2882
3237
|
})
|
|
2883
3238
|
}
|
|
2884
3239
|
|
|
@@ -2965,6 +3320,26 @@ impl CrawlPageResult {
|
|
|
2965
3320
|
fn browser_used(&self) -> bool {
|
|
2966
3321
|
self.browser_used
|
|
2967
3322
|
}
|
|
3323
|
+
|
|
3324
|
+
fn final_url(&self) -> String {
|
|
3325
|
+
self.final_url.clone()
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
fn redirect_count(&self) -> usize {
|
|
3329
|
+
self.redirect_count
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
fn noindex_detected(&self) -> bool {
|
|
3333
|
+
self.noindex_detected
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
fn nofollow_detected(&self) -> bool {
|
|
3337
|
+
self.nofollow_detected
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
fn ssrf_refused_urls(&self) -> Vec<String> {
|
|
3341
|
+
self.ssrf_refused_urls.clone()
|
|
3342
|
+
}
|
|
2968
3343
|
}
|
|
2969
3344
|
|
|
2970
3345
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
|
@@ -3360,7 +3735,7 @@ impl DownloadedAsset {
|
|
|
3360
3735
|
}
|
|
3361
3736
|
}
|
|
3362
3737
|
|
|
3363
|
-
#[derive(Clone,
|
|
3738
|
+
#[derive(Clone, serde::Serialize)]
|
|
3364
3739
|
#[serde(default)]
|
|
3365
3740
|
#[magnus::wrap(class = "Crawlberg::DownloadedDocument")]
|
|
3366
3741
|
pub struct DownloadedDocument {
|
|
@@ -3402,6 +3777,21 @@ impl magnus::TryConvert for DownloadedDocument {
|
|
|
3402
3777
|
}
|
|
3403
3778
|
|
|
3404
3779
|
unsafe impl TryConvertOwned for DownloadedDocument {}
|
|
3780
|
+
impl std::fmt::Debug for DownloadedDocument {
|
|
3781
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
3782
|
+
let mut debug = f.debug_struct("DownloadedDocument");
|
|
3783
|
+
debug.field("url", &self.url);
|
|
3784
|
+
debug.field("mime_type", &self.mime_type);
|
|
3785
|
+
debug.field("size", &self.size);
|
|
3786
|
+
debug.field("filename", &self.filename);
|
|
3787
|
+
debug.field("content_hash", &self.content_hash);
|
|
3788
|
+
debug.field("headers", &"<redacted>");
|
|
3789
|
+
debug.field("truncated", &self.truncated);
|
|
3790
|
+
debug.field("content_path", &self.content_path);
|
|
3791
|
+
debug.field("content_base64", &self.content_base64);
|
|
3792
|
+
debug.finish()
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3405
3795
|
impl<'de> serde::Deserialize<'de> for DownloadedDocument {
|
|
3406
3796
|
fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
|
|
3407
3797
|
where
|
|
@@ -4145,7 +4535,7 @@ impl ImageInfo {
|
|
|
4145
4535
|
}
|
|
4146
4536
|
}
|
|
4147
4537
|
|
|
4148
|
-
#[derive(Clone, Debug, serde::Serialize
|
|
4538
|
+
#[derive(Clone, Debug, serde::Serialize)]
|
|
4149
4539
|
#[serde(default)]
|
|
4150
4540
|
#[magnus::wrap(class = "Crawlberg::InteractionResult")]
|
|
4151
4541
|
pub struct InteractionResult {
|
|
@@ -4153,6 +4543,7 @@ pub struct InteractionResult {
|
|
|
4153
4543
|
final_html: String,
|
|
4154
4544
|
final_url: String,
|
|
4155
4545
|
screenshot_base64: Option<String>,
|
|
4546
|
+
ssrf_refused_urls: Vec<String>,
|
|
4156
4547
|
}
|
|
4157
4548
|
|
|
4158
4549
|
unsafe impl IntoValueFromNative for InteractionResult {}
|
|
@@ -4182,6 +4573,14 @@ impl magnus::TryConvert for InteractionResult {
|
|
|
4182
4573
|
}
|
|
4183
4574
|
|
|
4184
4575
|
unsafe impl TryConvertOwned for InteractionResult {}
|
|
4576
|
+
impl<'de> serde::Deserialize<'de> for InteractionResult {
|
|
4577
|
+
fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
|
|
4578
|
+
where
|
|
4579
|
+
D: serde::Deserializer<'de>,
|
|
4580
|
+
{
|
|
4581
|
+
<crawlberg::InteractionResult as serde::Deserialize>::deserialize(deserializer).map(Into::into)
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4185
4584
|
|
|
4186
4585
|
impl Default for InteractionResult {
|
|
4187
4586
|
fn default() -> Self {
|
|
@@ -4232,6 +4631,15 @@ impl InteractionResult {
|
|
|
4232
4631
|
})?),
|
|
4233
4632
|
None => None,
|
|
4234
4633
|
},
|
|
4634
|
+
ssrf_refused_urls: match kwargs.get(ruby.to_symbol("ssrf_refused_urls")) {
|
|
4635
|
+
Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
|
|
4636
|
+
magnus::Error::new(
|
|
4637
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
4638
|
+
format!("invalid value for `ssrf_refused_urls`: {}", e),
|
|
4639
|
+
)
|
|
4640
|
+
})?,
|
|
4641
|
+
None => Default::default(),
|
|
4642
|
+
},
|
|
4235
4643
|
})
|
|
4236
4644
|
}
|
|
4237
4645
|
|
|
@@ -4250,6 +4658,10 @@ impl InteractionResult {
|
|
|
4250
4658
|
fn screenshot_base64(&self) -> Option<String> {
|
|
4251
4659
|
self.screenshot_base64.clone()
|
|
4252
4660
|
}
|
|
4661
|
+
|
|
4662
|
+
fn ssrf_refused_urls(&self) -> Vec<String> {
|
|
4663
|
+
self.ssrf_refused_urls.clone()
|
|
4664
|
+
}
|
|
4253
4665
|
}
|
|
4254
4666
|
|
|
4255
4667
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
|
@@ -5330,7 +5742,7 @@ impl PageMetadata {
|
|
|
5330
5742
|
}
|
|
5331
5743
|
}
|
|
5332
5744
|
|
|
5333
|
-
#[derive(Clone,
|
|
5745
|
+
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
5334
5746
|
#[serde(default)]
|
|
5335
5747
|
#[magnus::wrap(class = "Crawlberg::ProxyConfig")]
|
|
5336
5748
|
pub struct ProxyConfig {
|
|
@@ -5366,6 +5778,15 @@ impl magnus::TryConvert for ProxyConfig {
|
|
|
5366
5778
|
}
|
|
5367
5779
|
|
|
5368
5780
|
unsafe impl TryConvertOwned for ProxyConfig {}
|
|
5781
|
+
impl std::fmt::Debug for ProxyConfig {
|
|
5782
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
5783
|
+
let mut debug = f.debug_struct("ProxyConfig");
|
|
5784
|
+
debug.field("url", &"<redacted>");
|
|
5785
|
+
debug.field("username", &self.username);
|
|
5786
|
+
debug.field("password", &"<redacted>");
|
|
5787
|
+
debug.finish()
|
|
5788
|
+
}
|
|
5789
|
+
}
|
|
5369
5790
|
|
|
5370
5791
|
impl Default for ProxyConfig {
|
|
5371
5792
|
fn default() -> Self {
|
|
@@ -5572,7 +5993,7 @@ impl ResponseMeta {
|
|
|
5572
5993
|
}
|
|
5573
5994
|
}
|
|
5574
5995
|
|
|
5575
|
-
#[derive(Clone, Debug, serde::Serialize
|
|
5996
|
+
#[derive(Clone, Debug, serde::Serialize)]
|
|
5576
5997
|
#[serde(default)]
|
|
5577
5998
|
#[magnus::wrap(class = "Crawlberg::ScrapeResult")]
|
|
5578
5999
|
pub struct ScrapeResult {
|
|
@@ -5605,6 +6026,7 @@ pub struct ScrapeResult {
|
|
|
5605
6026
|
screenshot_base64: Option<String>,
|
|
5606
6027
|
downloaded_document: Option<DownloadedDocument>,
|
|
5607
6028
|
browser: Option<BrowserExtras>,
|
|
6029
|
+
ssrf_refused_urls: Vec<String>,
|
|
5608
6030
|
}
|
|
5609
6031
|
|
|
5610
6032
|
unsafe impl IntoValueFromNative for ScrapeResult {}
|
|
@@ -5634,6 +6056,14 @@ impl magnus::TryConvert for ScrapeResult {
|
|
|
5634
6056
|
}
|
|
5635
6057
|
|
|
5636
6058
|
unsafe impl TryConvertOwned for ScrapeResult {}
|
|
6059
|
+
impl<'de> serde::Deserialize<'de> for ScrapeResult {
|
|
6060
|
+
fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
|
|
6061
|
+
where
|
|
6062
|
+
D: serde::Deserializer<'de>,
|
|
6063
|
+
{
|
|
6064
|
+
<crawlberg::ScrapeResult as serde::Deserialize>::deserialize(deserializer).map(Into::into)
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
5637
6067
|
|
|
5638
6068
|
impl Default for ScrapeResult {
|
|
5639
6069
|
fn default() -> Self {
|
|
@@ -5912,6 +6342,15 @@ impl ScrapeResult {
|
|
|
5912
6342
|
})?),
|
|
5913
6343
|
None => None,
|
|
5914
6344
|
},
|
|
6345
|
+
ssrf_refused_urls: match kwargs.get(ruby.to_symbol("ssrf_refused_urls")) {
|
|
6346
|
+
Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
|
|
6347
|
+
magnus::Error::new(
|
|
6348
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
6349
|
+
format!("invalid value for `ssrf_refused_urls`: {}", e),
|
|
6350
|
+
)
|
|
6351
|
+
})?,
|
|
6352
|
+
None => Default::default(),
|
|
6353
|
+
},
|
|
5915
6354
|
})
|
|
5916
6355
|
}
|
|
5917
6356
|
|
|
@@ -6030,6 +6469,10 @@ impl ScrapeResult {
|
|
|
6030
6469
|
fn browser(&self) -> Option<BrowserExtras> {
|
|
6031
6470
|
self.browser.clone()
|
|
6032
6471
|
}
|
|
6472
|
+
|
|
6473
|
+
fn ssrf_refused_urls(&self) -> Vec<String> {
|
|
6474
|
+
self.ssrf_refused_urls.clone()
|
|
6475
|
+
}
|
|
6033
6476
|
}
|
|
6034
6477
|
|
|
6035
6478
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
|
@@ -6145,6 +6588,7 @@ impl SitemapUrl {
|
|
|
6145
6588
|
pub struct SsrfPolicy {
|
|
6146
6589
|
deny_private: bool,
|
|
6147
6590
|
allowlist: Vec<HostMatcher>,
|
|
6591
|
+
denylist: Vec<HostMatcher>,
|
|
6148
6592
|
max_redirects: u8,
|
|
6149
6593
|
scheme_allowlist: Vec<String>,
|
|
6150
6594
|
}
|
|
@@ -6216,6 +6660,15 @@ impl SsrfPolicy {
|
|
|
6216
6660
|
})?,
|
|
6217
6661
|
None => Default::default(),
|
|
6218
6662
|
},
|
|
6663
|
+
denylist: match kwargs.get(ruby.to_symbol("denylist")) {
|
|
6664
|
+
Some(v) => <Vec<HostMatcher>>::try_convert(v).map_err(|e| {
|
|
6665
|
+
magnus::Error::new(
|
|
6666
|
+
unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
|
|
6667
|
+
format!("invalid value for `denylist`: {}", e),
|
|
6668
|
+
)
|
|
6669
|
+
})?,
|
|
6670
|
+
None => Default::default(),
|
|
6671
|
+
},
|
|
6219
6672
|
max_redirects: match kwargs.get(ruby.to_symbol("max_redirects")) {
|
|
6220
6673
|
Some(v) => u8::try_convert(v).map_err(|e| {
|
|
6221
6674
|
magnus::Error::new(
|
|
@@ -6245,6 +6698,10 @@ impl SsrfPolicy {
|
|
|
6245
6698
|
self.allowlist.clone()
|
|
6246
6699
|
}
|
|
6247
6700
|
|
|
6701
|
+
fn denylist(&self) -> Vec<HostMatcher> {
|
|
6702
|
+
self.denylist.clone()
|
|
6703
|
+
}
|
|
6704
|
+
|
|
6248
6705
|
fn max_redirects(&self) -> u8 {
|
|
6249
6706
|
self.max_redirects
|
|
6250
6707
|
}
|
|
@@ -6254,7 +6711,7 @@ impl SsrfPolicy {
|
|
|
6254
6711
|
}
|
|
6255
6712
|
}
|
|
6256
6713
|
|
|
6257
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
6714
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6258
6715
|
#[serde(rename_all = "snake_case")]
|
|
6259
6716
|
pub enum AssetCategory {
|
|
6260
6717
|
Document,
|
|
@@ -6295,7 +6752,14 @@ impl magnus::IntoValue for AssetCategory {
|
|
|
6295
6752
|
|
|
6296
6753
|
impl magnus::TryConvert for AssetCategory {
|
|
6297
6754
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6298
|
-
|
|
6755
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
6756
|
+
// Accept that exact representation as well as String inputs; do not
|
|
6757
|
+
// coerce arbitrary objects through to_s.
|
|
6758
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
6759
|
+
symbol.name()?.into_owned()
|
|
6760
|
+
} else {
|
|
6761
|
+
magnus::TryConvert::try_convert(val)?
|
|
6762
|
+
};
|
|
6299
6763
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6300
6764
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6301
6765
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6321,7 +6785,7 @@ impl magnus::TryConvert for AssetCategory {
|
|
|
6321
6785
|
unsafe impl IntoValueFromNative for AssetCategory {}
|
|
6322
6786
|
unsafe impl TryConvertOwned for AssetCategory {}
|
|
6323
6787
|
|
|
6324
|
-
#[derive(Clone,
|
|
6788
|
+
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
6325
6789
|
#[serde(tag = "type")]
|
|
6326
6790
|
pub enum AuthConfig {
|
|
6327
6791
|
#[serde(rename = "basic")]
|
|
@@ -6352,7 +6816,8 @@ impl magnus::IntoValue for AuthConfig {
|
|
|
6352
6816
|
|
|
6353
6817
|
impl magnus::TryConvert for AuthConfig {
|
|
6354
6818
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6355
|
-
//
|
|
6819
|
+
// Generated Data variants carry native DTOs, not JSON-compatible display strings.
|
|
6820
|
+
let class_name: Option<String> = val.class().funcall("name", ())?; // For data enums with fields (e.g., PageAction), try to deserialize from JSON first.
|
|
6356
6821
|
// For unit enums or when passed as a string, fall back to string-based conversion.
|
|
6357
6822
|
let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
|
|
6358
6823
|
s
|
|
@@ -6384,9 +6849,15 @@ impl magnus::TryConvert for AuthConfig {
|
|
|
6384
6849
|
|
|
6385
6850
|
unsafe impl IntoValueFromNative for AuthConfig {}
|
|
6386
6851
|
unsafe impl TryConvertOwned for AuthConfig {}
|
|
6852
|
+
|
|
6387
6853
|
impl AuthConfig {}
|
|
6854
|
+
impl std::fmt::Debug for AuthConfig {
|
|
6855
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
6856
|
+
f.write_str("AuthConfig(<redacted>)")
|
|
6857
|
+
}
|
|
6858
|
+
}
|
|
6388
6859
|
|
|
6389
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
6860
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6390
6861
|
#[serde(rename_all = "snake_case")]
|
|
6391
6862
|
pub enum BrowserBackend {
|
|
6392
6863
|
Chromiumoxide,
|
|
@@ -6411,7 +6882,14 @@ impl magnus::IntoValue for BrowserBackend {
|
|
|
6411
6882
|
|
|
6412
6883
|
impl magnus::TryConvert for BrowserBackend {
|
|
6413
6884
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6414
|
-
|
|
6885
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
6886
|
+
// Accept that exact representation as well as String inputs; do not
|
|
6887
|
+
// coerce arbitrary objects through to_s.
|
|
6888
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
6889
|
+
symbol.name()?.into_owned()
|
|
6890
|
+
} else {
|
|
6891
|
+
magnus::TryConvert::try_convert(val)?
|
|
6892
|
+
};
|
|
6415
6893
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6416
6894
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6417
6895
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6429,7 +6907,7 @@ impl magnus::TryConvert for BrowserBackend {
|
|
|
6429
6907
|
unsafe impl IntoValueFromNative for BrowserBackend {}
|
|
6430
6908
|
unsafe impl TryConvertOwned for BrowserBackend {}
|
|
6431
6909
|
|
|
6432
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
6910
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6433
6911
|
#[serde(rename_all = "snake_case")]
|
|
6434
6912
|
pub enum BrowserMode {
|
|
6435
6913
|
Auto,
|
|
@@ -6458,7 +6936,14 @@ impl magnus::IntoValue for BrowserMode {
|
|
|
6458
6936
|
|
|
6459
6937
|
impl magnus::TryConvert for BrowserMode {
|
|
6460
6938
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6461
|
-
|
|
6939
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
6940
|
+
// Accept that exact representation as well as String inputs; do not
|
|
6941
|
+
// coerce arbitrary objects through to_s.
|
|
6942
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
6943
|
+
symbol.name()?.into_owned()
|
|
6944
|
+
} else {
|
|
6945
|
+
magnus::TryConvert::try_convert(val)?
|
|
6946
|
+
};
|
|
6462
6947
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6463
6948
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6464
6949
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6478,7 +6963,7 @@ impl magnus::TryConvert for BrowserMode {
|
|
|
6478
6963
|
unsafe impl IntoValueFromNative for BrowserMode {}
|
|
6479
6964
|
unsafe impl TryConvertOwned for BrowserMode {}
|
|
6480
6965
|
|
|
6481
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
6966
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6482
6967
|
#[serde(rename_all = "snake_case")]
|
|
6483
6968
|
pub enum BrowserWait {
|
|
6484
6969
|
NetworkIdle,
|
|
@@ -6505,7 +6990,14 @@ impl magnus::IntoValue for BrowserWait {
|
|
|
6505
6990
|
|
|
6506
6991
|
impl magnus::TryConvert for BrowserWait {
|
|
6507
6992
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6508
|
-
|
|
6993
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
6994
|
+
// Accept that exact representation as well as String inputs; do not
|
|
6995
|
+
// coerce arbitrary objects through to_s.
|
|
6996
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
6997
|
+
symbol.name()?.into_owned()
|
|
6998
|
+
} else {
|
|
6999
|
+
magnus::TryConvert::try_convert(val)?
|
|
7000
|
+
};
|
|
6509
7001
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6510
7002
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6511
7003
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6524,7 +7016,7 @@ impl magnus::TryConvert for BrowserWait {
|
|
|
6524
7016
|
unsafe impl IntoValueFromNative for BrowserWait {}
|
|
6525
7017
|
unsafe impl TryConvertOwned for BrowserWait {}
|
|
6526
7018
|
|
|
6527
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
7019
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6528
7020
|
#[serde(rename_all = "snake_case")]
|
|
6529
7021
|
pub enum ContentFilterKind {
|
|
6530
7022
|
Bm25,
|
|
@@ -6547,7 +7039,14 @@ impl magnus::IntoValue for ContentFilterKind {
|
|
|
6547
7039
|
|
|
6548
7040
|
impl magnus::TryConvert for ContentFilterKind {
|
|
6549
7041
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6550
|
-
|
|
7042
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
7043
|
+
// Accept that exact representation as well as String inputs; do not
|
|
7044
|
+
// coerce arbitrary objects through to_s.
|
|
7045
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
7046
|
+
symbol.name()?.into_owned()
|
|
7047
|
+
} else {
|
|
7048
|
+
magnus::TryConvert::try_convert(val)?
|
|
7049
|
+
};
|
|
6551
7050
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6552
7051
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6553
7052
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6568,7 +7067,7 @@ unsafe impl TryConvertOwned for ContentFilterKind {}
|
|
|
6568
7067
|
#[serde(tag = "type")]
|
|
6569
7068
|
#[serde(rename_all = "snake_case")]
|
|
6570
7069
|
pub enum CrawlEvent {
|
|
6571
|
-
Page { result: CrawlPageResult },
|
|
7070
|
+
Page { result: Box<CrawlPageResult> },
|
|
6572
7071
|
Error { url: String, error: String },
|
|
6573
7072
|
Complete { pages_crawled: usize },
|
|
6574
7073
|
}
|
|
@@ -6592,7 +7091,8 @@ impl magnus::IntoValue for CrawlEvent {
|
|
|
6592
7091
|
|
|
6593
7092
|
impl magnus::TryConvert for CrawlEvent {
|
|
6594
7093
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6595
|
-
//
|
|
7094
|
+
// Generated Data variants carry native DTOs, not JSON-compatible display strings.
|
|
7095
|
+
let class_name: Option<String> = val.class().funcall("name", ())?; // For data enums with fields (e.g., PageAction), try to deserialize from JSON first.
|
|
6596
7096
|
// For unit enums or when passed as a string, fall back to string-based conversion.
|
|
6597
7097
|
let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
|
|
6598
7098
|
s
|
|
@@ -6624,9 +7124,10 @@ impl magnus::TryConvert for CrawlEvent {
|
|
|
6624
7124
|
|
|
6625
7125
|
unsafe impl IntoValueFromNative for CrawlEvent {}
|
|
6626
7126
|
unsafe impl TryConvertOwned for CrawlEvent {}
|
|
7127
|
+
|
|
6627
7128
|
impl CrawlEvent {}
|
|
6628
7129
|
|
|
6629
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
7130
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6630
7131
|
#[serde(rename_all = "snake_case")]
|
|
6631
7132
|
pub enum CrawlStrategyKind {
|
|
6632
7133
|
Bfs,
|
|
@@ -6655,7 +7156,14 @@ impl magnus::IntoValue for CrawlStrategyKind {
|
|
|
6655
7156
|
|
|
6656
7157
|
impl magnus::TryConvert for CrawlStrategyKind {
|
|
6657
7158
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6658
|
-
|
|
7159
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
7160
|
+
// Accept that exact representation as well as String inputs; do not
|
|
7161
|
+
// coerce arbitrary objects through to_s.
|
|
7162
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
7163
|
+
symbol.name()?.into_owned()
|
|
7164
|
+
} else {
|
|
7165
|
+
magnus::TryConvert::try_convert(val)?
|
|
7166
|
+
};
|
|
6659
7167
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6660
7168
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6661
7169
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6675,7 +7183,7 @@ impl magnus::TryConvert for CrawlStrategyKind {
|
|
|
6675
7183
|
unsafe impl IntoValueFromNative for CrawlStrategyKind {}
|
|
6676
7184
|
unsafe impl TryConvertOwned for CrawlStrategyKind {}
|
|
6677
7185
|
|
|
6678
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
7186
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6679
7187
|
#[serde(rename_all = "snake_case")]
|
|
6680
7188
|
pub enum DocumentContentEncoding {
|
|
6681
7189
|
Base64,
|
|
@@ -6698,7 +7206,14 @@ impl magnus::IntoValue for DocumentContentEncoding {
|
|
|
6698
7206
|
|
|
6699
7207
|
impl magnus::TryConvert for DocumentContentEncoding {
|
|
6700
7208
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6701
|
-
|
|
7209
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
7210
|
+
// Accept that exact representation as well as String inputs; do not
|
|
7211
|
+
// coerce arbitrary objects through to_s.
|
|
7212
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
7213
|
+
symbol.name()?.into_owned()
|
|
7214
|
+
} else {
|
|
7215
|
+
magnus::TryConvert::try_convert(val)?
|
|
7216
|
+
};
|
|
6702
7217
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6703
7218
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6704
7219
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6715,7 +7230,7 @@ impl magnus::TryConvert for DocumentContentEncoding {
|
|
|
6715
7230
|
unsafe impl IntoValueFromNative for DocumentContentEncoding {}
|
|
6716
7231
|
unsafe impl TryConvertOwned for DocumentContentEncoding {}
|
|
6717
7232
|
|
|
6718
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
7233
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6719
7234
|
#[serde(rename_all = "snake_case")]
|
|
6720
7235
|
pub enum FeedType {
|
|
6721
7236
|
Rss,
|
|
@@ -6742,7 +7257,14 @@ impl magnus::IntoValue for FeedType {
|
|
|
6742
7257
|
|
|
6743
7258
|
impl magnus::TryConvert for FeedType {
|
|
6744
7259
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6745
|
-
|
|
7260
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
7261
|
+
// Accept that exact representation as well as String inputs; do not
|
|
7262
|
+
// coerce arbitrary objects through to_s.
|
|
7263
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
7264
|
+
symbol.name()?.into_owned()
|
|
7265
|
+
} else {
|
|
7266
|
+
magnus::TryConvert::try_convert(val)?
|
|
7267
|
+
};
|
|
6746
7268
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6747
7269
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6748
7270
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6770,14 +7292,6 @@ pub enum HostMatcher {
|
|
|
6770
7292
|
Cidr { value: String },
|
|
6771
7293
|
}
|
|
6772
7294
|
|
|
6773
|
-
impl Default for HostMatcher {
|
|
6774
|
-
fn default() -> Self {
|
|
6775
|
-
Self::Exact {
|
|
6776
|
-
value: Default::default(),
|
|
6777
|
-
}
|
|
6778
|
-
}
|
|
6779
|
-
}
|
|
6780
|
-
|
|
6781
7295
|
impl magnus::IntoValue for HostMatcher {
|
|
6782
7296
|
fn into_value_with(self, handle: &Ruby) -> magnus::Value {
|
|
6783
7297
|
match serde_json::to_value(&self) {
|
|
@@ -6789,7 +7303,8 @@ impl magnus::IntoValue for HostMatcher {
|
|
|
6789
7303
|
|
|
6790
7304
|
impl magnus::TryConvert for HostMatcher {
|
|
6791
7305
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6792
|
-
//
|
|
7306
|
+
// Generated Data variants carry native DTOs, not JSON-compatible display strings.
|
|
7307
|
+
let class_name: Option<String> = val.class().funcall("name", ())?; // For data enums with fields (e.g., PageAction), try to deserialize from JSON first.
|
|
6793
7308
|
// For unit enums or when passed as a string, fall back to string-based conversion.
|
|
6794
7309
|
let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
|
|
6795
7310
|
s
|
|
@@ -6821,9 +7336,10 @@ impl magnus::TryConvert for HostMatcher {
|
|
|
6821
7336
|
|
|
6822
7337
|
unsafe impl IntoValueFromNative for HostMatcher {}
|
|
6823
7338
|
unsafe impl TryConvertOwned for HostMatcher {}
|
|
7339
|
+
|
|
6824
7340
|
impl HostMatcher {}
|
|
6825
7341
|
|
|
6826
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
7342
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6827
7343
|
#[serde(rename_all = "snake_case")]
|
|
6828
7344
|
pub enum ImageSource {
|
|
6829
7345
|
Img,
|
|
@@ -6854,7 +7370,14 @@ impl magnus::IntoValue for ImageSource {
|
|
|
6854
7370
|
|
|
6855
7371
|
impl magnus::TryConvert for ImageSource {
|
|
6856
7372
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6857
|
-
|
|
7373
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
7374
|
+
// Accept that exact representation as well as String inputs; do not
|
|
7375
|
+
// coerce arbitrary objects through to_s.
|
|
7376
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
7377
|
+
symbol.name()?.into_owned()
|
|
7378
|
+
} else {
|
|
7379
|
+
magnus::TryConvert::try_convert(val)?
|
|
7380
|
+
};
|
|
6858
7381
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6859
7382
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6860
7383
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6874,7 +7397,7 @@ impl magnus::TryConvert for ImageSource {
|
|
|
6874
7397
|
unsafe impl IntoValueFromNative for ImageSource {}
|
|
6875
7398
|
unsafe impl TryConvertOwned for ImageSource {}
|
|
6876
7399
|
|
|
6877
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
7400
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
6878
7401
|
#[serde(rename_all = "snake_case")]
|
|
6879
7402
|
pub enum LinkType {
|
|
6880
7403
|
Internal,
|
|
@@ -6903,7 +7426,14 @@ impl magnus::IntoValue for LinkType {
|
|
|
6903
7426
|
|
|
6904
7427
|
impl magnus::TryConvert for LinkType {
|
|
6905
7428
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6906
|
-
|
|
7429
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
7430
|
+
// Accept that exact representation as well as String inputs; do not
|
|
7431
|
+
// coerce arbitrary objects through to_s.
|
|
7432
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
7433
|
+
symbol.name()?.into_owned()
|
|
7434
|
+
} else {
|
|
7435
|
+
magnus::TryConvert::try_convert(val)?
|
|
7436
|
+
};
|
|
6907
7437
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
6908
7438
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
6909
7439
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -6923,7 +7453,7 @@ impl magnus::TryConvert for LinkType {
|
|
|
6923
7453
|
unsafe impl IntoValueFromNative for LinkType {}
|
|
6924
7454
|
unsafe impl TryConvertOwned for LinkType {}
|
|
6925
7455
|
|
|
6926
|
-
#[derive(Clone,
|
|
7456
|
+
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
6927
7457
|
#[serde(tag = "type")]
|
|
6928
7458
|
#[serde(rename_all = "camelCase")]
|
|
6929
7459
|
pub enum PageAction {
|
|
@@ -6974,7 +7504,8 @@ impl magnus::IntoValue for PageAction {
|
|
|
6974
7504
|
|
|
6975
7505
|
impl magnus::TryConvert for PageAction {
|
|
6976
7506
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
6977
|
-
//
|
|
7507
|
+
// Generated Data variants carry native DTOs, not JSON-compatible display strings.
|
|
7508
|
+
let class_name: Option<String> = val.class().funcall("name", ())?; // For data enums with fields (e.g., PageAction), try to deserialize from JSON first.
|
|
6978
7509
|
// For unit enums or when passed as a string, fall back to string-based conversion.
|
|
6979
7510
|
let json_str: String = if let Ok(s) = <String as magnus::TryConvert>::try_convert(val) {
|
|
6980
7511
|
s
|
|
@@ -7006,9 +7537,15 @@ impl magnus::TryConvert for PageAction {
|
|
|
7006
7537
|
|
|
7007
7538
|
unsafe impl IntoValueFromNative for PageAction {}
|
|
7008
7539
|
unsafe impl TryConvertOwned for PageAction {}
|
|
7540
|
+
|
|
7009
7541
|
impl PageAction {}
|
|
7542
|
+
impl std::fmt::Debug for PageAction {
|
|
7543
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
7544
|
+
f.write_str("PageAction(<redacted>)")
|
|
7545
|
+
}
|
|
7546
|
+
}
|
|
7010
7547
|
|
|
7011
|
-
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
7548
|
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
|
7012
7549
|
#[serde(rename_all = "camelCase")]
|
|
7013
7550
|
pub enum ScrollDirection {
|
|
7014
7551
|
Up,
|
|
@@ -7033,7 +7570,14 @@ impl magnus::IntoValue for ScrollDirection {
|
|
|
7033
7570
|
|
|
7034
7571
|
impl magnus::TryConvert for ScrollDirection {
|
|
7035
7572
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
7036
|
-
|
|
7573
|
+
// IntoValue emits Symbols, including when this enum is a Hash key.
|
|
7574
|
+
// Accept that exact representation as well as String inputs; do not
|
|
7575
|
+
// coerce arbitrary objects through to_s.
|
|
7576
|
+
let s: String = if let Some(symbol) = magnus::Symbol::from_value(val) {
|
|
7577
|
+
symbol.name()?.into_owned()
|
|
7578
|
+
} else {
|
|
7579
|
+
magnus::TryConvert::try_convert(val)?
|
|
7580
|
+
};
|
|
7037
7581
|
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
7038
7582
|
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
7039
7583
|
// existing consumer code written in any of those styles keep working.
|
|
@@ -7445,6 +7989,8 @@ impl From<BrowserConfig> for crawlberg::BrowserConfig {
|
|
|
7445
7989
|
backend: val.backend.into(),
|
|
7446
7990
|
endpoint: val.endpoint,
|
|
7447
7991
|
timeout: std::time::Duration::from_millis(val.timeout),
|
|
7992
|
+
overall_timeout: std::time::Duration::from_millis(val.overall_timeout),
|
|
7993
|
+
shutdown_timeout: std::time::Duration::from_millis(val.shutdown_timeout),
|
|
7448
7994
|
wait: val.wait.into(),
|
|
7449
7995
|
wait_selector: val.wait_selector,
|
|
7450
7996
|
extra_wait: val.extra_wait.map(std::time::Duration::from_millis),
|
|
@@ -7454,6 +8000,8 @@ impl From<BrowserConfig> for crawlberg::BrowserConfig {
|
|
|
7454
8000
|
robots_user_agent: val.robots_user_agent,
|
|
7455
8001
|
capture_network_events: val.capture_network_events,
|
|
7456
8002
|
session_affinity: val.session_affinity,
|
|
8003
|
+
chrome_path: val.chrome_path.map(Into::into),
|
|
8004
|
+
chrome_args: val.chrome_args.into_iter().collect(),
|
|
7457
8005
|
..Default::default()
|
|
7458
8006
|
}
|
|
7459
8007
|
}
|
|
@@ -7467,6 +8015,8 @@ impl From<crawlberg::BrowserConfig> for BrowserConfig {
|
|
|
7467
8015
|
backend: val.backend.into(),
|
|
7468
8016
|
endpoint: val.endpoint.map(|v| v.to_string()),
|
|
7469
8017
|
timeout: val.timeout.as_millis() as u64,
|
|
8018
|
+
overall_timeout: val.overall_timeout.as_millis() as u64,
|
|
8019
|
+
shutdown_timeout: val.shutdown_timeout.as_millis() as u64,
|
|
7470
8020
|
wait: val.wait.into(),
|
|
7471
8021
|
wait_selector: val.wait_selector.map(|v| v.to_string()),
|
|
7472
8022
|
extra_wait: val.extra_wait.map(|d| d.as_millis() as u64),
|
|
@@ -7476,6 +8026,8 @@ impl From<crawlberg::BrowserConfig> for BrowserConfig {
|
|
|
7476
8026
|
robots_user_agent: val.robots_user_agent.map(|v| v.to_string()),
|
|
7477
8027
|
capture_network_events: val.capture_network_events,
|
|
7478
8028
|
session_affinity: val.session_affinity,
|
|
8029
|
+
chrome_path: val.chrome_path.map(|p| p.to_string_lossy().to_string()),
|
|
8030
|
+
chrome_args: val.chrome_args.into_iter().collect(),
|
|
7479
8031
|
}
|
|
7480
8032
|
}
|
|
7481
8033
|
}
|
|
@@ -7564,6 +8116,7 @@ impl From<ContentConfig> for crawlberg::ContentConfig {
|
|
|
7564
8116
|
wrap: val.wrap,
|
|
7565
8117
|
wrap_width: val.wrap_width,
|
|
7566
8118
|
include_document_structure: val.include_document_structure,
|
|
8119
|
+
extract_metadata: val.extract_metadata,
|
|
7567
8120
|
..Default::default()
|
|
7568
8121
|
}
|
|
7569
8122
|
}
|
|
@@ -7584,6 +8137,7 @@ impl From<crawlberg::ContentConfig> for ContentConfig {
|
|
|
7584
8137
|
wrap: val.wrap,
|
|
7585
8138
|
wrap_width: val.wrap_width,
|
|
7586
8139
|
include_document_structure: val.include_document_structure,
|
|
8140
|
+
extract_metadata: val.extract_metadata,
|
|
7587
8141
|
}
|
|
7588
8142
|
}
|
|
7589
8143
|
}
|
|
@@ -7633,6 +8187,11 @@ impl From<CrawlConfig> for crawlberg::CrawlConfig {
|
|
|
7633
8187
|
allow_subdomains: val.allow_subdomains,
|
|
7634
8188
|
include_paths: val.include_paths.into_iter().collect(),
|
|
7635
8189
|
exclude_paths: val.exclude_paths.into_iter().collect(),
|
|
8190
|
+
path_patterns_match_query: val.path_patterns_match_query,
|
|
8191
|
+
path_patterns_match_url: val.path_patterns_match_url,
|
|
8192
|
+
dedup_include_query: val.dedup_include_query,
|
|
8193
|
+
strip_tracking_params: val.strip_tracking_params,
|
|
8194
|
+
tracking_params: val.tracking_params.into_iter().collect(),
|
|
7636
8195
|
custom_headers: val
|
|
7637
8196
|
.custom_headers
|
|
7638
8197
|
.into_iter()
|
|
@@ -7643,6 +8202,9 @@ impl From<CrawlConfig> for crawlberg::CrawlConfig {
|
|
|
7643
8202
|
max_redirects: val.max_redirects,
|
|
7644
8203
|
retry_count: val.retry_count,
|
|
7645
8204
|
retry_codes: val.retry_codes.into_iter().collect(),
|
|
8205
|
+
retry_initial_delay_ms: val.retry_initial_delay_ms,
|
|
8206
|
+
retry_max_delay_ms: val.retry_max_delay_ms,
|
|
8207
|
+
rate_limit_jitter_ratio: val.rate_limit_jitter_ratio,
|
|
7646
8208
|
cookies_enabled: val.cookies_enabled,
|
|
7647
8209
|
auth: val.auth.map(Into::into),
|
|
7648
8210
|
max_body_size: val.max_body_size,
|
|
@@ -7693,6 +8255,11 @@ impl From<crawlberg::CrawlConfig> for CrawlConfig {
|
|
|
7693
8255
|
allow_subdomains: val.allow_subdomains,
|
|
7694
8256
|
include_paths: val.include_paths.into_iter().collect(),
|
|
7695
8257
|
exclude_paths: val.exclude_paths.into_iter().collect(),
|
|
8258
|
+
path_patterns_match_query: val.path_patterns_match_query,
|
|
8259
|
+
path_patterns_match_url: val.path_patterns_match_url,
|
|
8260
|
+
dedup_include_query: val.dedup_include_query,
|
|
8261
|
+
strip_tracking_params: val.strip_tracking_params,
|
|
8262
|
+
tracking_params: val.tracking_params.into_iter().collect(),
|
|
7696
8263
|
custom_headers: val
|
|
7697
8264
|
.custom_headers
|
|
7698
8265
|
.into_iter()
|
|
@@ -7703,6 +8270,9 @@ impl From<crawlberg::CrawlConfig> for CrawlConfig {
|
|
|
7703
8270
|
max_redirects: val.max_redirects,
|
|
7704
8271
|
retry_count: val.retry_count,
|
|
7705
8272
|
retry_codes: val.retry_codes.into_iter().collect(),
|
|
8273
|
+
retry_initial_delay_ms: val.retry_initial_delay_ms,
|
|
8274
|
+
retry_max_delay_ms: val.retry_max_delay_ms,
|
|
8275
|
+
rate_limit_jitter_ratio: val.rate_limit_jitter_ratio,
|
|
7706
8276
|
cookies_enabled: val.cookies_enabled,
|
|
7707
8277
|
auth: val.auth.map(Into::into),
|
|
7708
8278
|
max_body_size: val.max_body_size,
|
|
@@ -7759,6 +8329,11 @@ impl From<CrawlPageResult> for crawlberg::CrawlPageResult {
|
|
|
7759
8329
|
extraction_meta: val.extraction_meta.map(Into::into),
|
|
7760
8330
|
downloaded_document: val.downloaded_document.map(Into::into),
|
|
7761
8331
|
browser_used: val.browser_used,
|
|
8332
|
+
final_url: val.final_url,
|
|
8333
|
+
redirect_count: val.redirect_count,
|
|
8334
|
+
noindex_detected: val.noindex_detected,
|
|
8335
|
+
nofollow_detected: val.nofollow_detected,
|
|
8336
|
+
ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
|
|
7762
8337
|
..Default::default()
|
|
7763
8338
|
}
|
|
7764
8339
|
}
|
|
@@ -7789,6 +8364,11 @@ impl From<crawlberg::CrawlPageResult> for CrawlPageResult {
|
|
|
7789
8364
|
extraction_meta: val.extraction_meta.map(Into::into),
|
|
7790
8365
|
downloaded_document: val.downloaded_document.map(Into::into),
|
|
7791
8366
|
browser_used: val.browser_used,
|
|
8367
|
+
final_url: val.final_url.to_string(),
|
|
8368
|
+
redirect_count: val.redirect_count,
|
|
8369
|
+
noindex_detected: val.noindex_detected,
|
|
8370
|
+
nofollow_detected: val.nofollow_detected,
|
|
8371
|
+
ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
|
|
7792
8372
|
}
|
|
7793
8373
|
}
|
|
7794
8374
|
}
|
|
@@ -8066,6 +8646,7 @@ impl From<InteractionResult> for crawlberg::InteractionResult {
|
|
|
8066
8646
|
final_html: val.final_html,
|
|
8067
8647
|
final_url: val.final_url,
|
|
8068
8648
|
screenshot_base64: val.screenshot_base64,
|
|
8649
|
+
ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
|
|
8069
8650
|
..Default::default()
|
|
8070
8651
|
}
|
|
8071
8652
|
}
|
|
@@ -8079,6 +8660,7 @@ impl From<crawlberg::InteractionResult> for InteractionResult {
|
|
|
8079
8660
|
final_html: val.final_html.to_string(),
|
|
8080
8661
|
final_url: val.final_url.to_string(),
|
|
8081
8662
|
screenshot_base64: val.screenshot_base64.map(|v| v.to_string()),
|
|
8663
|
+
ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
|
|
8082
8664
|
}
|
|
8083
8665
|
}
|
|
8084
8666
|
}
|
|
@@ -8383,6 +8965,7 @@ impl From<ScrapeResult> for crawlberg::ScrapeResult {
|
|
|
8383
8965
|
screenshot_base64: val.screenshot_base64,
|
|
8384
8966
|
downloaded_document: val.downloaded_document.map(Into::into),
|
|
8385
8967
|
browser: val.browser.map(Into::into),
|
|
8968
|
+
ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
|
|
8386
8969
|
..Default::default()
|
|
8387
8970
|
}
|
|
8388
8971
|
}
|
|
@@ -8421,6 +9004,7 @@ impl From<crawlberg::ScrapeResult> for ScrapeResult {
|
|
|
8421
9004
|
screenshot_base64: val.screenshot_base64.map(|v| v.to_string()),
|
|
8422
9005
|
downloaded_document: val.downloaded_document.map(Into::into),
|
|
8423
9006
|
browser: val.browser.map(Into::into),
|
|
9007
|
+
ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
|
|
8424
9008
|
}
|
|
8425
9009
|
}
|
|
8426
9010
|
}
|
|
@@ -8457,6 +9041,7 @@ impl From<SsrfPolicy> for crawlberg::SsrfPolicy {
|
|
|
8457
9041
|
Self {
|
|
8458
9042
|
deny_private: val.deny_private,
|
|
8459
9043
|
allowlist: val.allowlist.into_iter().map(Into::into).collect(),
|
|
9044
|
+
denylist: val.denylist.into_iter().map(Into::into).collect(),
|
|
8460
9045
|
max_redirects: val.max_redirects,
|
|
8461
9046
|
scheme_allowlist: val.scheme_allowlist.into_iter().collect(),
|
|
8462
9047
|
..Default::default()
|
|
@@ -8470,6 +9055,7 @@ impl From<crawlberg::SsrfPolicy> for SsrfPolicy {
|
|
|
8470
9055
|
Self {
|
|
8471
9056
|
deny_private: val.deny_private,
|
|
8472
9057
|
allowlist: val.allowlist.into_iter().map(Into::into).collect(),
|
|
9058
|
+
denylist: val.denylist.into_iter().map(Into::into).collect(),
|
|
8473
9059
|
max_redirects: val.max_redirects,
|
|
8474
9060
|
scheme_allowlist: val.scheme_allowlist.into_iter().collect(),
|
|
8475
9061
|
}
|
|
@@ -8619,7 +9205,7 @@ impl From<crawlberg::CrawlEvent> for CrawlEvent {
|
|
|
8619
9205
|
fn from(val: crawlberg::CrawlEvent) -> Self {
|
|
8620
9206
|
match val {
|
|
8621
9207
|
crawlberg::CrawlEvent::Page { result } => Self::Page {
|
|
8622
|
-
result: (*result).into(),
|
|
9208
|
+
result: Box::new((*result).into()),
|
|
8623
9209
|
},
|
|
8624
9210
|
crawlberg::CrawlEvent::Error { url, error } => Self::Error {
|
|
8625
9211
|
url: url.to_string(),
|
|
@@ -9109,6 +9695,10 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9109
9695
|
|
|
9110
9696
|
class.define_method("timeout", method!(BrowserConfig::timeout, 0))?;
|
|
9111
9697
|
|
|
9698
|
+
class.define_method("overall_timeout", method!(BrowserConfig::overall_timeout, 0))?;
|
|
9699
|
+
|
|
9700
|
+
class.define_method("shutdown_timeout", method!(BrowserConfig::shutdown_timeout, 0))?;
|
|
9701
|
+
|
|
9112
9702
|
class.define_method("wait", method!(BrowserConfig::wait, 0))?;
|
|
9113
9703
|
|
|
9114
9704
|
class.define_method("wait_selector", method!(BrowserConfig::wait_selector, 0))?;
|
|
@@ -9130,6 +9720,10 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9130
9720
|
|
|
9131
9721
|
class.define_method("session_affinity", method!(BrowserConfig::session_affinity, 0))?;
|
|
9132
9722
|
|
|
9723
|
+
class.define_method("chrome_path", method!(BrowserConfig::chrome_path, 0))?;
|
|
9724
|
+
|
|
9725
|
+
class.define_method("chrome_args", method!(BrowserConfig::chrome_args, 0))?;
|
|
9726
|
+
|
|
9133
9727
|
let class = module.define_class("BrowserExtras", ruby.class_object())?;
|
|
9134
9728
|
|
|
9135
9729
|
class.define_singleton_method("new", function!(BrowserExtras::new, -1))?;
|
|
@@ -9191,6 +9785,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9191
9785
|
method!(ContentConfig::include_document_structure, 0),
|
|
9192
9786
|
)?;
|
|
9193
9787
|
|
|
9788
|
+
class.define_method("extract_metadata", method!(ContentConfig::extract_metadata, 0))?;
|
|
9789
|
+
|
|
9194
9790
|
let class = module.define_class("CookieInfo", ruby.class_object())?;
|
|
9195
9791
|
|
|
9196
9792
|
class.define_singleton_method("new", function!(CookieInfo::new, -1))?;
|
|
@@ -9237,6 +9833,22 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9237
9833
|
|
|
9238
9834
|
class.define_method("exclude_paths", method!(CrawlConfig::exclude_paths, 0))?;
|
|
9239
9835
|
|
|
9836
|
+
class.define_method(
|
|
9837
|
+
"path_patterns_match_query",
|
|
9838
|
+
method!(CrawlConfig::path_patterns_match_query, 0),
|
|
9839
|
+
)?;
|
|
9840
|
+
|
|
9841
|
+
class.define_method(
|
|
9842
|
+
"path_patterns_match_url",
|
|
9843
|
+
method!(CrawlConfig::path_patterns_match_url, 0),
|
|
9844
|
+
)?;
|
|
9845
|
+
|
|
9846
|
+
class.define_method("dedup_include_query", method!(CrawlConfig::dedup_include_query, 0))?;
|
|
9847
|
+
|
|
9848
|
+
class.define_method("strip_tracking_params", method!(CrawlConfig::strip_tracking_params, 0))?;
|
|
9849
|
+
|
|
9850
|
+
class.define_method("tracking_params", method!(CrawlConfig::tracking_params, 0))?;
|
|
9851
|
+
|
|
9240
9852
|
class.define_method("custom_headers", method!(CrawlConfig::custom_headers, 0))?;
|
|
9241
9853
|
|
|
9242
9854
|
class.define_method("request_timeout", method!(CrawlConfig::request_timeout, 0))?;
|
|
@@ -9249,6 +9861,18 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9249
9861
|
|
|
9250
9862
|
class.define_method("retry_codes", method!(CrawlConfig::retry_codes, 0))?;
|
|
9251
9863
|
|
|
9864
|
+
class.define_method(
|
|
9865
|
+
"retry_initial_delay_ms",
|
|
9866
|
+
method!(CrawlConfig::retry_initial_delay_ms, 0),
|
|
9867
|
+
)?;
|
|
9868
|
+
|
|
9869
|
+
class.define_method("retry_max_delay_ms", method!(CrawlConfig::retry_max_delay_ms, 0))?;
|
|
9870
|
+
|
|
9871
|
+
class.define_method(
|
|
9872
|
+
"rate_limit_jitter_ratio",
|
|
9873
|
+
method!(CrawlConfig::rate_limit_jitter_ratio, 0),
|
|
9874
|
+
)?;
|
|
9875
|
+
|
|
9252
9876
|
class.define_method("cookies_enabled", method!(CrawlConfig::cookies_enabled, 0))?;
|
|
9253
9877
|
|
|
9254
9878
|
class.define_method("auth", method!(CrawlConfig::auth, 0))?;
|
|
@@ -9360,6 +9984,16 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9360
9984
|
|
|
9361
9985
|
class.define_method("browser_used", method!(CrawlPageResult::browser_used, 0))?;
|
|
9362
9986
|
|
|
9987
|
+
class.define_method("final_url", method!(CrawlPageResult::final_url, 0))?;
|
|
9988
|
+
|
|
9989
|
+
class.define_method("redirect_count", method!(CrawlPageResult::redirect_count, 0))?;
|
|
9990
|
+
|
|
9991
|
+
class.define_method("noindex_detected", method!(CrawlPageResult::noindex_detected, 0))?;
|
|
9992
|
+
|
|
9993
|
+
class.define_method("nofollow_detected", method!(CrawlPageResult::nofollow_detected, 0))?;
|
|
9994
|
+
|
|
9995
|
+
class.define_method("ssrf_refused_urls", method!(CrawlPageResult::ssrf_refused_urls, 0))?;
|
|
9996
|
+
|
|
9363
9997
|
let class = module.define_class("CrawlResult", ruby.class_object())?;
|
|
9364
9998
|
|
|
9365
9999
|
class.define_singleton_method("new", function!(CrawlResult::new, -1))?;
|
|
@@ -9509,6 +10143,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9509
10143
|
|
|
9510
10144
|
class.define_method("screenshot_base64", method!(InteractionResult::screenshot_base64, 0))?;
|
|
9511
10145
|
|
|
10146
|
+
class.define_method("ssrf_refused_urls", method!(InteractionResult::ssrf_refused_urls, 0))?;
|
|
10147
|
+
|
|
9512
10148
|
let class = module.define_class("JsonLdEntry", ruby.class_object())?;
|
|
9513
10149
|
|
|
9514
10150
|
class.define_singleton_method("new", function!(JsonLdEntry::new, -1))?;
|
|
@@ -9737,6 +10373,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9737
10373
|
|
|
9738
10374
|
class.define_method("browser", method!(ScrapeResult::browser, 0))?;
|
|
9739
10375
|
|
|
10376
|
+
class.define_method("ssrf_refused_urls", method!(ScrapeResult::ssrf_refused_urls, 0))?;
|
|
10377
|
+
|
|
9740
10378
|
let class = module.define_class("SitemapUrl", ruby.class_object())?;
|
|
9741
10379
|
|
|
9742
10380
|
class.define_singleton_method("new", function!(SitemapUrl::new, -1))?;
|
|
@@ -9757,6 +10395,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
9757
10395
|
|
|
9758
10396
|
class.define_method("allowlist", method!(SsrfPolicy::allowlist, 0))?;
|
|
9759
10397
|
|
|
10398
|
+
class.define_method("denylist", method!(SsrfPolicy::denylist, 0))?;
|
|
10399
|
+
|
|
9760
10400
|
class.define_method("max_redirects", method!(SsrfPolicy::max_redirects, 0))?;
|
|
9761
10401
|
|
|
9762
10402
|
class.define_method("scheme_allowlist", method!(SsrfPolicy::scheme_allowlist, 0))?;
|