1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
use crate::header::{Entry, HeaderMap, HeaderValue, OccupiedEntry};
use std::fmt;
pub fn basic_auth<U, P>(username: U, password: Option<P>) -> HeaderValue
where
U: std::fmt::Display,
P: std::fmt::Display,
{
use base64::prelude::BASE64_STANDARD;
use base64::write::EncoderWriter;
use std::io::Write;
let mut buf = b"Basic ".to_vec();
{
let mut encoder = EncoderWriter::new(&mut buf, &BASE64_STANDARD);
let _ = write!(encoder, "{username}:");
if let Some(password) = password {
let _ = write!(encoder, "{password}");
}
}
let mut header = HeaderValue::from_bytes(&buf).expect("base64 is always valid HeaderValue");
header.set_sensitive(true);
header
}
// xor-shift
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn fast_random() -> u64 {
use std::cell::Cell;
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hasher};
use std::num::Wrapping;
thread_local! {
static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
}
fn seed() -> u64 {
let seed = RandomState::new();
let mut out = 0;
let mut cnt = 0;
while out == 0 {
cnt += 1;
let mut hasher = seed.build_hasher();
hasher.write_usize(cnt);
out = hasher.finish();
}
out
}
RNG.with(|rng| {
let mut n = rng.get();
debug_assert_ne!(n.0, 0);
n ^= n >> 12;
n ^= n << 25;
n ^= n >> 27;
rng.set(n);
n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
})
}
pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
// IntoIter of HeaderMap yields (Option<HeaderName>, HeaderValue).
// The first time a name is yielded, it will be Some(name), and if
// there are more values with the same name, the next yield will be
// None.
let mut prev_entry: Option<OccupiedEntry<_>> = None;
for (key, value) in src {
match key {
Some(key) => match dst.entry(key) {
Entry::Occupied(mut e) => {
e.insert(value);
prev_entry = Some(e);
}
Entry::Vacant(e) => {
let e = e.insert_entry(value);
prev_entry = Some(e);
}
},
None => match prev_entry {
Some(ref mut entry) => {
entry.append(value);
}
None => unreachable!("HeaderMap::into_iter yielded None first"),
},
}
}
}
#[cfg(feature = "cookies")]
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn add_cookie_header(
headers: &mut HeaderMap,
cookie_store: &dyn crate::cookie::CookieStore,
url: &url::Url,
) {
if let Some(header) = cookie_store.cookies(url) {
headers.insert(crate::header::COOKIE, header);
}
}
pub(crate) struct Escape<'a>(&'a [u8]);
#[cfg(not(target_arch = "wasm32"))]
impl<'a> Escape<'a> {
pub(crate) fn new(bytes: &'a [u8]) -> Self {
Escape(bytes)
}
}
impl fmt::Debug for Escape<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "b\"{}\"", self)?;
Ok(())
}
}
impl fmt::Display for Escape<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for &c in self.0 {
// https://doc.rust-lang.org/reference.html#byte-escapes
if c == b'\n' {
write!(f, "\\n")?;
} else if c == b'\r' {
write!(f, "\\r")?;
} else if c == b'\t' {
write!(f, "\\t")?;
} else if c == b'\\' || c == b'"' {
write!(f, "\\{}", c as char)?;
} else if c == b'\0' {
write!(f, "\\0")?;
// ASCII printable
} else if c >= 0x20 && c < 0x7f {
write!(f, "{}", c as char)?;
} else {
write!(f, "\\x{c:02x}")?;
}
}
Ok(())
}
}
|