@@ -107,43 +107,6 @@ pub fn spoof_chrome_linux_ua_with_randomizer(thread_rng: &mut Rng) -> &'static s
107107 pick_rand ( Some ( thread_rng) , STATIC_CHROME_LINUX_AGENTS )
108108}
109109
110- /// Desktop agents.
111- pub fn desktop_agents ( ) -> & ' static [ & ' static str ] {
112- let v = [
113- STATIC_CHROME_WINDOWS_AGENTS ,
114- STATIC_CHROME_MAC_AGENTS ,
115- STATIC_CHROME_LINUX_AGENTS ,
116- STATIC_FIREFOX_WINDOWS_AGENTS ,
117- STATIC_FIREFOX_MAC_AGENTS ,
118- STATIC_FIREFOX_LINUX_AGENTS ,
119- STATIC_SAFARI_MAC_AGENTS ,
120- ]
121- . concat ( ) ;
122- Box :: leak ( v. into_boxed_slice ( ) )
123- }
124-
125- /// Mobile agents.
126- pub fn mobile_agents ( ) -> & ' static [ & ' static str ] {
127- let v = [
128- STATIC_CHROME_MOBILE_AGENTS ,
129- STATIC_FIREFOX_MOBILE_AGENTS ,
130- STATIC_SAFARI_MOBILE_AGENTS ,
131- ]
132- . concat ( ) ;
133- Box :: leak ( v. into_boxed_slice ( ) )
134- }
135-
136- /// Tablet agents.
137- pub fn tablet_agents ( ) -> & ' static [ & ' static str ] {
138- let v = [
139- STATIC_CHROME_TABLET_AGENTS ,
140- STATIC_FIREFOX_TABLET_AGENTS ,
141- STATIC_SAFARI_TABLET_AGENTS ,
142- ]
143- . concat ( ) ;
144- Box :: leak ( v. into_boxed_slice ( ) )
145- }
146-
147110/// Slices for each generated family (zero-copy, no alloc).
148111#[ inline]
149112pub fn chrome_agents ( ) -> & ' static [ & ' static str ] {
@@ -404,13 +367,35 @@ pub fn spoof_by(
404367 // Any Safari fallback → global Safari list
405368 ( _, _, Some ( Browser :: Safari ) ) => pick_rand ( rng, STATIC_SAFARI_AGENTS ) ,
406369
407- // --- FormFactor match only ---
408- // Desktop
409- ( _, Some ( FormFactor :: Desktop ) , _) => pick_rand ( rng, desktop_agents ( ) ) ,
410- // Mobile
411- ( _, Some ( FormFactor :: Mobile ) , _) => pick_rand ( rng, mobile_agents ( ) ) ,
412- // Tablet
413- ( _, Some ( FormFactor :: Tablet ) , _) => pick_rand ( rng, tablet_agents ( ) ) ,
370+ // --- FormFactor match only (NO ALLOC, NO LEAK) ---
371+ ( _, Some ( FormFactor :: Desktop ) , _) => pick_rand_multi (
372+ rng,
373+ & [
374+ STATIC_CHROME_WINDOWS_AGENTS ,
375+ STATIC_CHROME_MAC_AGENTS ,
376+ STATIC_CHROME_LINUX_AGENTS ,
377+ STATIC_FIREFOX_WINDOWS_AGENTS ,
378+ STATIC_FIREFOX_MAC_AGENTS ,
379+ STATIC_FIREFOX_LINUX_AGENTS ,
380+ STATIC_SAFARI_MAC_AGENTS ,
381+ ] ,
382+ ) ,
383+ ( _, Some ( FormFactor :: Mobile ) , _) => pick_rand_multi (
384+ rng,
385+ & [
386+ STATIC_CHROME_MOBILE_AGENTS ,
387+ STATIC_FIREFOX_MOBILE_AGENTS ,
388+ STATIC_SAFARI_MOBILE_AGENTS ,
389+ ] ,
390+ ) ,
391+ ( _, Some ( FormFactor :: Tablet ) , _) => pick_rand_multi (
392+ rng,
393+ & [
394+ STATIC_CHROME_TABLET_AGENTS ,
395+ STATIC_FIREFOX_TABLET_AGENTS ,
396+ STATIC_SAFARI_TABLET_AGENTS ,
397+ ] ,
398+ ) ,
414399
415400 // --- Fall Back ---
416401 // IE: until IE lists are generated, fall back to mixed static
@@ -566,6 +551,30 @@ fn pick_rand<'a>(rng: Option<&mut Rng>, candidates: &'a [&'a str]) -> &'a str {
566551 }
567552}
568553
554+ /// Pick randomly across multiple candidate slices without allocating.
555+ #[ inline]
556+ fn pick_rand_multi < ' a > ( rng : Option < & mut Rng > , groups : & [ & ' a [ & ' a str ] ] ) -> & ' a str {
557+ let total: usize = groups. iter ( ) . map ( |g| g. len ( ) ) . sum ( ) ;
558+ if total == 0 {
559+ return "" ;
560+ }
561+
562+ let mut idx = match rng {
563+ Some ( r) => r. usize ( ..total) ,
564+ None => fastrand:: usize ( ..total) ,
565+ } ;
566+
567+ for g in groups {
568+ if idx < g. len ( ) {
569+ return g[ idx] ;
570+ }
571+ idx -= g. len ( ) ;
572+ }
573+
574+ // unreachable if `total` computed correctly
575+ ""
576+ }
577+
569578#[ cfg( test) ]
570579mod tests {
571580 use super :: * ;
0 commit comments