mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
clippy: fix warnings in components/net (#31564)
* clippy: fix some warnings in components/net * fix: review comments * fix: tidy
This commit is contained in:
parent
099bb0fa19
commit
67b277c992
22 changed files with 325 additions and 379 deletions
|
@ -54,7 +54,7 @@ impl Service<Destination> for ServoHttpConnector {
|
||||||
let authority = if let Some(port) = auth.port() {
|
let authority = if let Some(port) = auth.port() {
|
||||||
format!("{}:{}", host, port.as_str())
|
format!("{}:{}", host, port.as_str())
|
||||||
} else {
|
} else {
|
||||||
format!("{}", &*host)
|
(*host).to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(authority) = Authority::from_maybe_shared(authority) {
|
if let Ok(authority) = Authority::from_maybe_shared(authority) {
|
||||||
|
|
|
@ -106,8 +106,8 @@ impl Cookie {
|
||||||
""
|
""
|
||||||
})
|
})
|
||||||
.to_owned();
|
.to_owned();
|
||||||
if path.chars().next() != Some('/') {
|
if !path.starts_with('/') {
|
||||||
path = Cookie::default_path(&request.path().to_owned()).to_string();
|
path = Cookie::default_path(request.path()).to_string();
|
||||||
}
|
}
|
||||||
cookie.set_path(path);
|
cookie.set_path(path);
|
||||||
|
|
||||||
|
@ -152,12 +152,12 @@ impl Cookie {
|
||||||
// http://tools.ietf.org/html/rfc6265#section-5.1.4
|
// http://tools.ietf.org/html/rfc6265#section-5.1.4
|
||||||
pub fn default_path(request_path: &str) -> &str {
|
pub fn default_path(request_path: &str) -> &str {
|
||||||
// Step 2
|
// Step 2
|
||||||
if request_path.chars().next() != Some('/') {
|
if !request_path.starts_with('/') {
|
||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
let rightmost_slash_idx = request_path.rfind("/").unwrap();
|
let rightmost_slash_idx = request_path.rfind('/').unwrap();
|
||||||
if rightmost_slash_idx == 0 {
|
if rightmost_slash_idx == 0 {
|
||||||
// There's only one slash; it's the first character
|
// There's only one slash; it's the first character
|
||||||
return "/";
|
return "/";
|
||||||
|
@ -178,11 +178,11 @@ impl Cookie {
|
||||||
(
|
(
|
||||||
// The cookie-path is a prefix of the request-path, and the last
|
// The cookie-path is a prefix of the request-path, and the last
|
||||||
// character of the cookie-path is %x2F ("/").
|
// character of the cookie-path is %x2F ("/").
|
||||||
cookie_path.ends_with("/") ||
|
cookie_path.ends_with('/') ||
|
||||||
// The cookie-path is a prefix of the request-path, and the first
|
// The cookie-path is a prefix of the request-path, and the first
|
||||||
// character of the request-path that is not included in the cookie-
|
// character of the request-path that is not included in the cookie-
|
||||||
// path is a %x2F ("/") character.
|
// path is a %x2F ("/") character.
|
||||||
request_path[cookie_path.len()..].starts_with("/")
|
request_path[cookie_path.len()..].starts_with('/')
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,15 +205,13 @@ impl Cookie {
|
||||||
if self.cookie.domain() != domain {
|
if self.cookie.domain() != domain {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else if let (Some(domain), Some(cookie_domain)) = (domain, &self.cookie.domain()) {
|
||||||
if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain()) {
|
if !Cookie::domain_match(domain, cookie_domain) {
|
||||||
if !Cookie::domain_match(domain, cookie_domain) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref cookie_path) = self.cookie.path() {
|
if let Some(cookie_path) = self.cookie.path() {
|
||||||
if !Cookie::path_match(url.path(), cookie_path) {
|
if !Cookie::path_match(url.path(), cookie_path) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl CookieStorage {
|
||||||
source: CookieSource,
|
source: CookieSource,
|
||||||
) -> Result<Option<Cookie>, ()> {
|
) -> Result<Option<Cookie>, ()> {
|
||||||
let domain = reg_host(cookie.cookie.domain().as_ref().unwrap_or(&""));
|
let domain = reg_host(cookie.cookie.domain().as_ref().unwrap_or(&""));
|
||||||
let cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
let cookies = self.cookies_map.entry(domain).or_default();
|
||||||
|
|
||||||
// https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 2
|
// https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 2
|
||||||
if !cookie.cookie.secure().unwrap_or(false) && !url.is_secure_scheme() {
|
if !cookie.cookie.secure().unwrap_or(false) && !url.is_secure_scheme() {
|
||||||
|
@ -90,7 +90,7 @@ impl CookieStorage {
|
||||||
}
|
}
|
||||||
pub fn clear_storage(&mut self, url: &ServoUrl) {
|
pub fn clear_storage(&mut self, url: &ServoUrl) {
|
||||||
let domain = reg_host(url.host_str().unwrap_or(""));
|
let domain = reg_host(url.host_str().unwrap_or(""));
|
||||||
let cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
let cookies = self.cookies_map.entry(domain).or_default();
|
||||||
for cookie in cookies.iter_mut() {
|
for cookie in cookies.iter_mut() {
|
||||||
cookie.set_expiry_time_negative();
|
cookie.set_expiry_time_negative();
|
||||||
}
|
}
|
||||||
|
@ -116,12 +116,12 @@ impl CookieStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 12
|
// Step 12
|
||||||
let domain = reg_host(&cookie.cookie.domain().as_ref().unwrap_or(&""));
|
let domain = reg_host(cookie.cookie.domain().as_ref().unwrap_or(&""));
|
||||||
let cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
let cookies = self.cookies_map.entry(domain).or_default();
|
||||||
|
|
||||||
if cookies.len() == self.max_per_host {
|
if cookies.len() == self.max_per_host {
|
||||||
let old_len = cookies.len();
|
let old_len = cookies.len();
|
||||||
cookies.retain(|c| !is_cookie_expired(&c));
|
cookies.retain(|c| !is_cookie_expired(c));
|
||||||
let new_len = cookies.len();
|
let new_len = cookies.len();
|
||||||
|
|
||||||
// https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt
|
// https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt
|
||||||
|
@ -153,8 +153,8 @@ impl CookieStorage {
|
||||||
let domain = reg_host(url.host_str().unwrap_or(""));
|
let domain = reg_host(url.host_str().unwrap_or(""));
|
||||||
if let Entry::Occupied(mut entry) = self.cookies_map.entry(domain) {
|
if let Entry::Occupied(mut entry) = self.cookies_map.entry(domain) {
|
||||||
let cookies = entry.get_mut();
|
let cookies = entry.get_mut();
|
||||||
cookies.retain(|c| !is_cookie_expired(&c));
|
cookies.retain(|c| !is_cookie_expired(c));
|
||||||
if cookies.len() == 0 {
|
if cookies.is_empty() {
|
||||||
entry.remove_entry();
|
entry.remove_entry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,10 +179,10 @@ impl CookieStorage {
|
||||||
};
|
};
|
||||||
// Step 2
|
// Step 2
|
||||||
let domain = reg_host(url.host_str().unwrap_or(""));
|
let domain = reg_host(url.host_str().unwrap_or(""));
|
||||||
let cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
let cookies = self.cookies_map.entry(domain).or_default();
|
||||||
|
|
||||||
let mut url_cookies: Vec<&mut Cookie> = cookies.iter_mut().filter(filterer).collect();
|
let mut url_cookies: Vec<&mut Cookie> = cookies.iter_mut().filter(filterer).collect();
|
||||||
url_cookies.sort_by(|a, b| CookieStorage::cookie_comparator(*a, *b));
|
url_cookies.sort_by(|a, b| CookieStorage::cookie_comparator(a, b));
|
||||||
|
|
||||||
let reducer = |acc: String, c: &mut &mut Cookie| -> String {
|
let reducer = |acc: String, c: &mut &mut Cookie| -> String {
|
||||||
// Step 3
|
// Step 3
|
||||||
|
@ -211,7 +211,7 @@ impl CookieStorage {
|
||||||
source: CookieSource,
|
source: CookieSource,
|
||||||
) -> impl Iterator<Item = cookie_rs::Cookie<'static>> + 'a {
|
) -> impl Iterator<Item = cookie_rs::Cookie<'static>> + 'a {
|
||||||
let domain = reg_host(url.host_str().unwrap_or(""));
|
let domain = reg_host(url.host_str().unwrap_or(""));
|
||||||
let cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
let cookies = self.cookies_map.entry(domain).or_default();
|
||||||
|
|
||||||
cookies
|
cookies
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
@ -223,7 +223,7 @@ impl CookieStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reg_host<'a>(url: &'a str) -> String {
|
fn reg_host(url: &str) -> String {
|
||||||
reg_suffix(url).to_lowercase()
|
reg_suffix(url).to_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool {
|
||||||
cookies.remove(index);
|
cookies.remove(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> Option<(usize, Tm)> {
|
fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> Option<(usize, Tm)> {
|
||||||
|
|
|
@ -130,7 +130,7 @@ impl Decoder {
|
||||||
Decoder {
|
Decoder {
|
||||||
inner: Inner::Pending(Pending {
|
inner: Inner::Pending(Pending {
|
||||||
body: ReadableChunks::new(body),
|
body: ReadableChunks::new(body),
|
||||||
type_: type_,
|
type_,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ impl Gzip {
|
||||||
Gzip {
|
Gzip {
|
||||||
buf: BytesMut::with_capacity(INIT_BUFFER_SIZE),
|
buf: BytesMut::with_capacity(INIT_BUFFER_SIZE),
|
||||||
inner: Box::new(gzip::Decoder::new(Peeked::new(stream))),
|
inner: Box::new(gzip::Decoder::new(Peeked::new(stream))),
|
||||||
reader: reader,
|
reader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,7 @@ impl Brotli {
|
||||||
Self {
|
Self {
|
||||||
buf: BytesMut::with_capacity(INIT_BUFFER_SIZE),
|
buf: BytesMut::with_capacity(INIT_BUFFER_SIZE),
|
||||||
inner: Box::new(Decompressor::new(Peeked::new(stream), BUF_SIZE)),
|
inner: Box::new(Decompressor::new(Peeked::new(stream), BUF_SIZE)),
|
||||||
reader: reader,
|
reader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ impl Deflate {
|
||||||
Self {
|
Self {
|
||||||
buf: BytesMut::with_capacity(INIT_BUFFER_SIZE),
|
buf: BytesMut::with_capacity(INIT_BUFFER_SIZE),
|
||||||
inner: Box::new(DeflateDecoder::new(Peeked::new(stream))),
|
inner: Box::new(DeflateDecoder::new(Peeked::new(stream))),
|
||||||
reader: reader,
|
reader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,7 +382,7 @@ impl<R> Peeked<R> {
|
||||||
Peeked {
|
Peeked {
|
||||||
state: PeekedState::NotReady,
|
state: PeekedState::NotReady,
|
||||||
peeked_buf: [0; 10],
|
peeked_buf: [0; 10],
|
||||||
inner: inner,
|
inner,
|
||||||
pos: 0,
|
pos: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,10 +418,10 @@ impl<R: Read> Read for Peeked<R> {
|
||||||
return Ok(len);
|
return Ok(len);
|
||||||
},
|
},
|
||||||
PeekedState::NotReady => {
|
PeekedState::NotReady => {
|
||||||
let mut buf = &mut self.peeked_buf[self.pos..];
|
let buf = &mut self.peeked_buf[self.pos..];
|
||||||
let stream = self.inner.clone();
|
let stream = self.inner.clone();
|
||||||
let mut reader = stream.lock().unwrap();
|
let mut reader = stream.lock().unwrap();
|
||||||
let read = reader.read(&mut buf);
|
let read = reader.read(buf);
|
||||||
|
|
||||||
match read {
|
match read {
|
||||||
Ok(0) => self.ready(),
|
Ok(0) => self.ready(),
|
||||||
|
@ -444,7 +444,7 @@ impl<S> ReadableChunks<S> {
|
||||||
fn new(stream: S) -> Self {
|
fn new(stream: S) -> Self {
|
||||||
ReadableChunks {
|
ReadableChunks {
|
||||||
state: ReadState::NotReady,
|
state: ReadState::NotReady,
|
||||||
stream: stream,
|
stream,
|
||||||
waker: None,
|
waker: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,11 +60,11 @@ impl CorsCacheEntry {
|
||||||
header_or_method: HeaderOrMethod,
|
header_or_method: HeaderOrMethod,
|
||||||
) -> CorsCacheEntry {
|
) -> CorsCacheEntry {
|
||||||
CorsCacheEntry {
|
CorsCacheEntry {
|
||||||
origin: origin,
|
origin,
|
||||||
url: url,
|
url,
|
||||||
max_age: max_age,
|
max_age,
|
||||||
credentials: credentials,
|
credentials,
|
||||||
header_or_method: header_or_method,
|
header_or_method,
|
||||||
created: time::now().to_timespec(),
|
created: time::now().to_timespec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,14 +77,10 @@ fn match_headers(cors_cache: &CorsCacheEntry, cors_req: &Request) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple, vector-based CORS Cache
|
/// A simple, vector-based CORS Cache
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct CorsCache(Vec<CorsCacheEntry>);
|
pub struct CorsCache(Vec<CorsCacheEntry>);
|
||||||
|
|
||||||
impl CorsCache {
|
impl CorsCache {
|
||||||
pub fn new() -> CorsCache {
|
|
||||||
CorsCache(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_entry_by_header<'a>(
|
fn find_entry_by_header<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
request: &Request,
|
request: &Request,
|
||||||
|
@ -122,7 +118,7 @@ impl CorsCache {
|
||||||
/// Returns true if an entry with a
|
/// Returns true if an entry with a
|
||||||
/// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found
|
/// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found
|
||||||
pub fn match_header(&mut self, request: &Request, header_name: &HeaderName) -> bool {
|
pub fn match_header(&mut self, request: &Request, header_name: &HeaderName) -> bool {
|
||||||
self.find_entry_by_header(&request, header_name).is_some()
|
self.find_entry_by_header(request, header_name).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates max age if an entry for a
|
/// Updates max age if an entry for a
|
||||||
|
@ -136,7 +132,7 @@ impl CorsCache {
|
||||||
new_max_age: u32,
|
new_max_age: u32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self
|
match self
|
||||||
.find_entry_by_header(&request, header_name)
|
.find_entry_by_header(request, header_name)
|
||||||
.map(|e| e.max_age = new_max_age)
|
.map(|e| e.max_age = new_max_age)
|
||||||
{
|
{
|
||||||
Some(_) => true,
|
Some(_) => true,
|
||||||
|
@ -156,7 +152,7 @@ impl CorsCache {
|
||||||
/// Returns true if an entry with a
|
/// Returns true if an entry with a
|
||||||
/// [matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found
|
/// [matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found
|
||||||
pub fn match_method(&mut self, request: &Request, method: Method) -> bool {
|
pub fn match_method(&mut self, request: &Request, method: Method) -> bool {
|
||||||
self.find_entry_by_method(&request, method).is_some()
|
self.find_entry_by_method(request, method).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates max age if an entry for
|
/// Updates max age if an entry for
|
||||||
|
@ -170,7 +166,7 @@ impl CorsCache {
|
||||||
new_max_age: u32,
|
new_max_age: u32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self
|
match self
|
||||||
.find_entry_by_method(&request, method.clone())
|
.find_entry_by_method(request, method.clone())
|
||||||
.map(|e| e.max_age = new_max_age)
|
.map(|e| e.max_age = new_max_age)
|
||||||
{
|
{
|
||||||
Some(_) => true,
|
Some(_) => true,
|
||||||
|
|
|
@ -17,14 +17,14 @@ pub fn determine_nosniff(headers: &HeaderMap) -> bool {
|
||||||
|
|
||||||
match values {
|
match values {
|
||||||
None => false,
|
None => false,
|
||||||
Some(values) => !values.is_empty() && (&values[0]).eq_ignore_ascii_case("nosniff"),
|
Some(values) => !values.is_empty() && values[0].eq_ignore_ascii_case("nosniff"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split>
|
/// <https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split>
|
||||||
fn get_header_value_as_list(name: &str, headers: &HeaderMap) -> Option<Vec<String>> {
|
fn get_header_value_as_list(name: &str, headers: &HeaderMap) -> Option<Vec<String>> {
|
||||||
fn char_is_not_quote_or_comma(c: char) -> bool {
|
fn char_is_not_quote_or_comma(c: char) -> bool {
|
||||||
return c != '\u{0022}' && c != '\u{002C}';
|
c != '\u{0022}' && c != '\u{002C}'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
|
@ -33,7 +33,7 @@ fn get_header_value_as_list(name: &str, headers: &HeaderMap) -> Option<Vec<Strin
|
||||||
if let Some(input) = initial_value {
|
if let Some(input) = initial_value {
|
||||||
// https://fetch.spec.whatwg.org/#header-value-get-decode-and-split
|
// https://fetch.spec.whatwg.org/#header-value-get-decode-and-split
|
||||||
// Step 1
|
// Step 1
|
||||||
let input = input.into_iter().map(|u| char::from(u)).collect::<String>();
|
let input = input.into_iter().map(char::from).collect::<String>();
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
let mut position = input.chars().peekable();
|
let mut position = input.chars().peekable();
|
||||||
|
@ -81,7 +81,7 @@ fn get_header_value_as_list(name: &str, headers: &HeaderMap) -> Option<Vec<Strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points>
|
/// <https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points>
|
||||||
|
@ -102,13 +102,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
return result;
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://fetch.spec.whatwg.org/#collect-an-http-quoted-string>
|
/// <https://fetch.spec.whatwg.org/#collect-an-http-quoted-string>
|
||||||
fn collect_http_quoted_string(position: &mut Peekable<Chars>, extract_value: bool) -> String {
|
fn collect_http_quoted_string(position: &mut Peekable<Chars>, extract_value: bool) -> String {
|
||||||
fn char_is_not_quote_or_backslash(c: char) -> bool {
|
fn char_is_not_quote_or_backslash(c: char) -> bool {
|
||||||
return c != '\u{0022}' && c != '\u{005C}';
|
c != '\u{0022}' && c != '\u{005C}'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
|
@ -159,5 +159,5 @@ fn collect_http_quoted_string(position: &mut Peekable<Chars>, extract_value: boo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6, 7
|
// Step 6, 7
|
||||||
return value;
|
value
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ pub struct CancellationListener {
|
||||||
impl CancellationListener {
|
impl CancellationListener {
|
||||||
pub fn new(cancel_chan: Option<IpcReceiver<()>>) -> Self {
|
pub fn new(cancel_chan: Option<IpcReceiver<()>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cancel_chan: cancel_chan,
|
cancel_chan,
|
||||||
cancelled: false,
|
cancelled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ pub async fn fetch(request: &mut Request, target: Target<'_>, context: &FetchCon
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_attribute(ResourceAttribute::StartTime(ResourceTimeValue::FetchStart));
|
.set_attribute(ResourceAttribute::StartTime(ResourceTimeValue::FetchStart));
|
||||||
|
|
||||||
fetch_with_cors_cache(request, &mut CorsCache::new(), target, context).await;
|
fetch_with_cors_cache(request, &mut CorsCache::default(), target, context).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_with_cors_cache(
|
pub async fn fetch_with_cors_cache(
|
||||||
|
@ -161,7 +161,7 @@ pub async fn fetch_with_cors_cache(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 8.
|
// Step 8.
|
||||||
main_fetch(request, cache, false, false, target, &mut None, &context).await;
|
main_fetch(request, cache, false, false, target, &mut None, context).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://www.w3.org/TR/CSP/#should-block-request>
|
/// <https://www.w3.org/TR/CSP/#should-block-request>
|
||||||
|
@ -209,15 +209,15 @@ pub async fn main_fetch(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
if request.local_urls_only {
|
if request.local_urls_only &&
|
||||||
if !matches!(
|
!matches!(
|
||||||
request.current_url().scheme(),
|
request.current_url().scheme(),
|
||||||
"about" | "blob" | "data" | "filesystem"
|
"about" | "blob" | "data" | "filesystem"
|
||||||
) {
|
)
|
||||||
response = Some(Response::network_error(NetworkError::Internal(
|
{
|
||||||
"Non-local scheme".into(),
|
response = Some(Response::network_error(NetworkError::Internal(
|
||||||
)));
|
"Non-local scheme".into(),
|
||||||
}
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2.2.
|
// Step 2.2.
|
||||||
|
@ -267,7 +267,7 @@ pub async fn main_fetch(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
request.referrer = referrer_url.map_or(Referrer::NoReferrer, |url| Referrer::ReferrerUrl(url));
|
request.referrer = referrer_url.map_or(Referrer::NoReferrer, Referrer::ReferrerUrl);
|
||||||
|
|
||||||
// Step 9.
|
// Step 9.
|
||||||
// TODO: handle FTP URLs.
|
// TODO: handle FTP URLs.
|
||||||
|
@ -451,7 +451,7 @@ pub async fn main_fetch(
|
||||||
*body = ResponseBody::Empty;
|
*body = ResponseBody::Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal_response.get_network_error().map(|e| e.clone())
|
internal_response.get_network_error().cloned()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute deferred rebinding of response.
|
// Execute deferred rebinding of response.
|
||||||
|
@ -469,7 +469,7 @@ pub async fn main_fetch(
|
||||||
response_loaded = true;
|
response_loaded = true;
|
||||||
|
|
||||||
// Step 19.2.
|
// Step 19.2.
|
||||||
let ref integrity_metadata = &request.integrity_metadata;
|
let integrity_metadata = &request.integrity_metadata;
|
||||||
if response.termination_reason.is_none() &&
|
if response.termination_reason.is_none() &&
|
||||||
!is_response_integrity_valid(integrity_metadata, &response)
|
!is_response_integrity_valid(integrity_metadata, &response)
|
||||||
{
|
{
|
||||||
|
@ -502,8 +502,8 @@ pub async fn main_fetch(
|
||||||
// in http_network_fetch. However, we can't yet follow the request
|
// in http_network_fetch. However, we can't yet follow the request
|
||||||
// upload progress, so I'm keeping it here for now and pretending
|
// upload progress, so I'm keeping it here for now and pretending
|
||||||
// the body got sent in one chunk
|
// the body got sent in one chunk
|
||||||
target.process_request_body(&request);
|
target.process_request_body(request);
|
||||||
target.process_request_eof(&request);
|
target.process_request_eof(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 22.
|
// Step 22.
|
||||||
|
@ -518,7 +518,7 @@ pub async fn main_fetch(
|
||||||
target.process_response_eof(&response);
|
target.process_response_eof(&response);
|
||||||
|
|
||||||
if let Ok(http_cache) = context.state.http_cache.write() {
|
if let Ok(http_cache) = context.state.http_cache.write() {
|
||||||
http_cache.update_awaiting_consumers(&request, &response);
|
http_cache.update_awaiting_consumers(request, &response);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 25-27.
|
// Steps 25-27.
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom};
|
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom};
|
||||||
use std::mem;
|
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{self, AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{self, AtomicBool, AtomicUsize, Ordering};
|
||||||
|
@ -103,13 +102,12 @@ impl FileManager {
|
||||||
let store = self.store.clone();
|
let store = self.store.clone();
|
||||||
self.thread_pool
|
self.thread_pool
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.and_then(|pool| {
|
.map(|pool| {
|
||||||
pool.spawn(move || {
|
pool.spawn(move || {
|
||||||
if let Err(e) = store.try_read_file(&sender, id, origin) {
|
if let Err(e) = store.try_read_file(&sender, id, origin) {
|
||||||
let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e)));
|
let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Some(())
|
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
warn!("FileManager tried to read a file after CoreResourceManager has exited.");
|
warn!("FileManager tried to read a file after CoreResourceManager has exited.");
|
||||||
|
@ -160,11 +158,10 @@ impl FileManager {
|
||||||
let embedder = self.embedder_proxy.clone();
|
let embedder = self.embedder_proxy.clone();
|
||||||
self.thread_pool
|
self.thread_pool
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.and_then(|pool| {
|
.map(|pool| {
|
||||||
pool.spawn(move || {
|
pool.spawn(move || {
|
||||||
store.select_file(filter, sender, origin, opt_test_path, embedder);
|
store.select_file(filter, sender, origin, opt_test_path, embedder);
|
||||||
});
|
});
|
||||||
Some(())
|
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
warn!(
|
warn!(
|
||||||
|
@ -177,11 +174,10 @@ impl FileManager {
|
||||||
let embedder = self.embedder_proxy.clone();
|
let embedder = self.embedder_proxy.clone();
|
||||||
self.thread_pool
|
self.thread_pool
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.and_then(|pool| {
|
.map(|pool| {
|
||||||
pool.spawn(move || {
|
pool.spawn(move || {
|
||||||
store.select_files(filter, sender, origin, opt_test_paths, embedder);
|
store.select_files(filter, sender, origin, opt_test_paths, embedder);
|
||||||
});
|
});
|
||||||
Some(())
|
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
warn!(
|
warn!(
|
||||||
|
@ -221,7 +217,7 @@ impl FileManager {
|
||||||
let done_sender = done_sender.clone();
|
let done_sender = done_sender.clone();
|
||||||
self.thread_pool
|
self.thread_pool
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.and_then(|pool| {
|
.map(|pool| {
|
||||||
pool.spawn(move || {
|
pool.spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
if cancellation_listener.lock().unwrap().cancelled() {
|
if cancellation_listener.lock().unwrap().cancelled() {
|
||||||
|
@ -266,7 +262,7 @@ impl FileManager {
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
let mut body = res_body.lock().unwrap();
|
let mut body = res_body.lock().unwrap();
|
||||||
let completed_body = match *body {
|
let completed_body = match *body {
|
||||||
ResponseBody::Receiving(ref mut body) => mem::replace(body, vec![]),
|
ResponseBody::Receiving(ref mut body) => std::mem::take(body),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
*body = ResponseBody::Done(completed_body);
|
*body = ResponseBody::Done(completed_body);
|
||||||
|
@ -276,7 +272,6 @@ impl FileManager {
|
||||||
reader.consume(length);
|
reader.consume(length);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Some(())
|
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
warn!("FileManager tried to fetch a file in chunks after CoreResourceManager has exited.");
|
warn!("FileManager tried to fetch a file in chunks after CoreResourceManager has exited.");
|
||||||
|
@ -373,7 +368,7 @@ impl FileManager {
|
||||||
FileImpl::Sliced(parent_id, inner_rel_pos) => {
|
FileImpl::Sliced(parent_id, inner_rel_pos) => {
|
||||||
// Next time we don't need to check validity since
|
// Next time we don't need to check validity since
|
||||||
// we have already done that for requesting URL if necessary.
|
// we have already done that for requesting URL if necessary.
|
||||||
return self.fetch_blob_buf(
|
self.fetch_blob_buf(
|
||||||
done_sender,
|
done_sender,
|
||||||
cancellation_listener,
|
cancellation_listener,
|
||||||
&parent_id,
|
&parent_id,
|
||||||
|
@ -383,7 +378,7 @@ impl FileManager {
|
||||||
RelativePos::full_range().slice_inner(&inner_rel_pos),
|
RelativePos::full_range().slice_inner(&inner_rel_pos),
|
||||||
),
|
),
|
||||||
response,
|
response,
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,7 +406,7 @@ impl FileManagerStore {
|
||||||
origin_in: &FileOrigin,
|
origin_in: &FileOrigin,
|
||||||
) -> Result<FileImpl, BlobURLStoreError> {
|
) -> Result<FileImpl, BlobURLStoreError> {
|
||||||
match self.entries.read().unwrap().get(id) {
|
match self.entries.read().unwrap().get(id) {
|
||||||
Some(ref entry) => {
|
Some(entry) => {
|
||||||
if *origin_in != *entry.origin {
|
if *origin_in != *entry.origin {
|
||||||
Err(BlobURLStoreError::InvalidOrigin)
|
Err(BlobURLStoreError::InvalidOrigin)
|
||||||
} else {
|
} else {
|
||||||
|
@ -441,7 +436,7 @@ impl FileManagerStore {
|
||||||
let zero_refs = entry.refs.load(Ordering::Acquire) == 0;
|
let zero_refs = entry.refs.load(Ordering::Acquire) == 0;
|
||||||
|
|
||||||
// Check if no other fetch has acquired a token for this file.
|
// Check if no other fetch has acquired a token for this file.
|
||||||
let no_outstanding_tokens = entry.outstanding_tokens.len() == 0;
|
let no_outstanding_tokens = entry.outstanding_tokens.is_empty();
|
||||||
|
|
||||||
// Check if there is still a blob URL outstanding.
|
// Check if there is still a blob URL outstanding.
|
||||||
let valid = entry.is_valid_url.load(Ordering::Acquire);
|
let valid = entry.is_valid_url.load(Ordering::Acquire);
|
||||||
|
@ -450,7 +445,7 @@ impl FileManagerStore {
|
||||||
let do_remove = zero_refs && no_outstanding_tokens && !valid;
|
let do_remove = zero_refs && no_outstanding_tokens && !valid;
|
||||||
|
|
||||||
if do_remove {
|
if do_remove {
|
||||||
entries.remove(&file_id);
|
entries.remove(file_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,7 +456,7 @@ impl FileManagerStore {
|
||||||
let parent_id = match entries.get(file_id) {
|
let parent_id = match entries.get(file_id) {
|
||||||
Some(entry) => {
|
Some(entry) => {
|
||||||
if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl {
|
if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl {
|
||||||
Some(parent_id.clone())
|
Some(*parent_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -477,7 +472,7 @@ impl FileManagerStore {
|
||||||
return FileTokenCheck::ShouldFail;
|
return FileTokenCheck::ShouldFail;
|
||||||
}
|
}
|
||||||
let token = Uuid::new_v4();
|
let token = Uuid::new_v4();
|
||||||
entry.outstanding_tokens.insert(token.clone());
|
entry.outstanding_tokens.insert(token);
|
||||||
return FileTokenCheck::Required(token);
|
return FileTokenCheck::Required(token);
|
||||||
}
|
}
|
||||||
FileTokenCheck::ShouldFail
|
FileTokenCheck::ShouldFail
|
||||||
|
@ -585,7 +580,6 @@ impl FileManagerStore {
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let _ = sender.send(Err(FileManagerThreadError::UserCancelled));
|
let _ = sender.send(Err(FileManagerThreadError::UserCancelled));
|
||||||
return;
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -631,7 +625,6 @@ impl FileManagerStore {
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let _ = sender.send(Err(FileManagerThreadError::UserCancelled));
|
let _ = sender.send(Err(FileManagerThreadError::UserCancelled));
|
||||||
return;
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -672,7 +665,7 @@ impl FileManagerStore {
|
||||||
id,
|
id,
|
||||||
FileStoreEntry {
|
FileStoreEntry {
|
||||||
origin: origin.to_string(),
|
origin: origin.to_string(),
|
||||||
file_impl: file_impl,
|
file_impl,
|
||||||
refs: AtomicUsize::new(1),
|
refs: AtomicUsize::new(1),
|
||||||
// Invalid here since create_entry is called by file selection
|
// Invalid here since create_entry is called by file selection
|
||||||
is_valid_url: AtomicBool::new(false),
|
is_valid_url: AtomicBool::new(false),
|
||||||
|
@ -687,11 +680,11 @@ impl FileManagerStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(SelectedFile {
|
Ok(SelectedFile {
|
||||||
id: id,
|
id,
|
||||||
filename: filename_path.to_path_buf(),
|
filename: filename_path.to_path_buf(),
|
||||||
modified: modified_epoch,
|
modified: modified_epoch,
|
||||||
size: file_size,
|
size: file_size,
|
||||||
type_string: type_string,
|
type_string,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -798,13 +791,13 @@ impl FileManagerStore {
|
||||||
let is_valid = entry.is_valid_url.load(Ordering::Acquire);
|
let is_valid = entry.is_valid_url.load(Ordering::Acquire);
|
||||||
|
|
||||||
// Check if no fetch has acquired a token for this file.
|
// Check if no fetch has acquired a token for this file.
|
||||||
let no_outstanding_tokens = entry.outstanding_tokens.len() == 0;
|
let no_outstanding_tokens = entry.outstanding_tokens.is_empty();
|
||||||
|
|
||||||
// Can we remove this file?
|
// Can we remove this file?
|
||||||
let do_remove = !is_valid && no_outstanding_tokens;
|
let do_remove = !is_valid && no_outstanding_tokens;
|
||||||
|
|
||||||
if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl {
|
if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl {
|
||||||
(do_remove, Some(parent_id.clone()))
|
(do_remove, Some(*parent_id))
|
||||||
} else {
|
} else {
|
||||||
(do_remove, None)
|
(do_remove, None)
|
||||||
}
|
}
|
||||||
|
@ -867,13 +860,13 @@ impl FileManagerStore {
|
||||||
let zero_refs = entry.refs.load(Ordering::Acquire) == 0;
|
let zero_refs = entry.refs.load(Ordering::Acquire) == 0;
|
||||||
|
|
||||||
// Check if no fetch has acquired a token for this file.
|
// Check if no fetch has acquired a token for this file.
|
||||||
let no_outstanding_tokens = entry.outstanding_tokens.len() == 0;
|
let no_outstanding_tokens = entry.outstanding_tokens.is_empty();
|
||||||
|
|
||||||
// Can we remove this file?
|
// Can we remove this file?
|
||||||
let do_remove = zero_refs && no_outstanding_tokens;
|
let do_remove = zero_refs && no_outstanding_tokens;
|
||||||
|
|
||||||
if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl {
|
if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl {
|
||||||
(do_remove, Some(parent_id.clone()), Ok(()))
|
(do_remove, Some(*parent_id), Ok(()))
|
||||||
} else {
|
} else {
|
||||||
(do_remove, None, Ok(()))
|
(do_remove, None, Ok(()))
|
||||||
}
|
}
|
||||||
|
@ -913,7 +906,7 @@ fn read_file_in_chunks(
|
||||||
buf.truncate(n);
|
buf.truncate(n);
|
||||||
let blob_buf = BlobBuf {
|
let blob_buf = BlobBuf {
|
||||||
filename: opt_filename,
|
filename: opt_filename,
|
||||||
type_string: type_string,
|
type_string,
|
||||||
size: size as u64,
|
size: size as u64,
|
||||||
bytes: buf,
|
bytes: buf,
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@ lazy_static! {
|
||||||
fn create_host_table() -> Option<HashMap<String, IpAddr>> {
|
fn create_host_table() -> Option<HashMap<String, IpAddr>> {
|
||||||
let path = env::var_os("HOST_FILE")?;
|
let path = env::var_os("HOST_FILE")?;
|
||||||
|
|
||||||
let file = File::open(&path).ok()?;
|
let file = File::open(path).ok()?;
|
||||||
let mut reader = BufReader::new(file);
|
let mut reader = BufReader::new(file);
|
||||||
|
|
||||||
let mut lines = String::new();
|
let mut lines = String::new();
|
||||||
|
|
|
@ -33,9 +33,9 @@ impl HstsEntry {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(HstsEntry {
|
Some(HstsEntry {
|
||||||
host: host,
|
host,
|
||||||
include_subdomains: (subdomains == IncludeSubdomains::Included),
|
include_subdomains: (subdomains == IncludeSubdomains::Included),
|
||||||
max_age: max_age,
|
max_age,
|
||||||
timestamp: Some(time::get_time().sec as u64),
|
timestamp: Some(time::get_time().sec as u64),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -60,18 +60,12 @@ impl HstsEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct HstsList {
|
pub struct HstsList {
|
||||||
pub entries_map: HashMap<String, Vec<HstsEntry>>,
|
pub entries_map: HashMap<String, Vec<HstsEntry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HstsList {
|
impl HstsList {
|
||||||
pub fn new() -> HstsList {
|
|
||||||
HstsList {
|
|
||||||
entries_map: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an `HstsList` from the bytes of a JSON preload file.
|
/// Create an `HstsList` from the bytes of a JSON preload file.
|
||||||
pub fn from_preload(preload_content: &str) -> Option<HstsList> {
|
pub fn from_preload(preload_content: &str) -> Option<HstsList> {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -81,14 +75,14 @@ impl HstsList {
|
||||||
|
|
||||||
let hsts_entries: Option<HstsEntries> = serde_json::from_str(preload_content).ok();
|
let hsts_entries: Option<HstsEntries> = serde_json::from_str(preload_content).ok();
|
||||||
|
|
||||||
hsts_entries.map_or(None, |hsts_entries| {
|
hsts_entries.map(|hsts_entries| {
|
||||||
let mut hsts_list: HstsList = HstsList::new();
|
let mut hsts_list: HstsList = HstsList::default();
|
||||||
|
|
||||||
for hsts_entry in hsts_entries.entries {
|
for hsts_entry in hsts_entries.entries {
|
||||||
hsts_list.push(hsts_entry);
|
hsts_list.push(hsts_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(hsts_list);
|
hsts_list
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +106,7 @@ impl HstsList {
|
||||||
|
|
||||||
fn has_domain(&self, host: &str, base_domain: &str) -> bool {
|
fn has_domain(&self, host: &str, base_domain: &str) -> bool {
|
||||||
self.entries_map.get(base_domain).map_or(false, |entries| {
|
self.entries_map.get(base_domain).map_or(false, |entries| {
|
||||||
entries.iter().any(|e| e.matches_domain(&host))
|
entries.iter().any(|e| e.matches_domain(host))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,10 +122,7 @@ impl HstsList {
|
||||||
let have_domain = self.has_domain(&entry.host, base_domain);
|
let have_domain = self.has_domain(&entry.host, base_domain);
|
||||||
let have_subdomain = self.has_subdomain(&entry.host, base_domain);
|
let have_subdomain = self.has_subdomain(&entry.host, base_domain);
|
||||||
|
|
||||||
let entries = self
|
let entries = self.entries_map.entry(base_domain.to_owned()).or_default();
|
||||||
.entries_map
|
|
||||||
.entry(base_domain.to_owned())
|
|
||||||
.or_insert(vec![]);
|
|
||||||
if !have_domain && !have_subdomain {
|
if !have_domain && !have_subdomain {
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
} else if !have_subdomain {
|
} else if !have_subdomain {
|
||||||
|
|
|
@ -126,7 +126,7 @@ pub struct CachedResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A memory cache.
|
/// A memory cache.
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(Default, MallocSizeOf)]
|
||||||
pub struct HttpCache {
|
pub struct HttpCache {
|
||||||
/// cached responses.
|
/// cached responses.
|
||||||
entries: HashMap<CacheKey, Vec<CachedResource>>,
|
entries: HashMap<CacheKey, Vec<CachedResource>>,
|
||||||
|
@ -192,19 +192,18 @@ fn calculate_response_age(response: &Response) -> Duration {
|
||||||
/// or uses a heuristic if none are present.
|
/// or uses a heuristic if none are present.
|
||||||
fn get_response_expiry(response: &Response) -> Duration {
|
fn get_response_expiry(response: &Response) -> Duration {
|
||||||
// Calculating Freshness Lifetime <https://tools.ietf.org/html/rfc7234#section-4.2.1>
|
// Calculating Freshness Lifetime <https://tools.ietf.org/html/rfc7234#section-4.2.1>
|
||||||
let age = calculate_response_age(&response);
|
let age = calculate_response_age(response);
|
||||||
if let Some(directives) = response.headers.typed_get::<CacheControl>() {
|
if let Some(directives) = response.headers.typed_get::<CacheControl>() {
|
||||||
if directives.no_cache() {
|
if directives.no_cache() {
|
||||||
// Requires validation on first use.
|
// Requires validation on first use.
|
||||||
return Duration::seconds(0i64);
|
return Duration::seconds(0i64);
|
||||||
} else {
|
}
|
||||||
if let Some(secs) = directives.max_age().or(directives.s_max_age()) {
|
if let Some(secs) = directives.max_age().or(directives.s_max_age()) {
|
||||||
let max_age = Duration::from_std(secs).unwrap();
|
let max_age = Duration::from_std(secs).unwrap();
|
||||||
if max_age < age {
|
if max_age < age {
|
||||||
return Duration::seconds(0i64);
|
return Duration::seconds(0i64);
|
||||||
}
|
|
||||||
return max_age - age;
|
|
||||||
}
|
}
|
||||||
|
return max_age - age;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match response.headers.typed_get::<Expires>() {
|
match response.headers.typed_get::<Expires>() {
|
||||||
|
@ -217,9 +216,8 @@ fn get_response_expiry(response: &Response) -> Duration {
|
||||||
|
|
||||||
if desired > current {
|
if desired > current {
|
||||||
return desired - current;
|
return desired - current;
|
||||||
} else {
|
|
||||||
return Duration::seconds(0i64);
|
|
||||||
}
|
}
|
||||||
|
return Duration::seconds(0i64);
|
||||||
},
|
},
|
||||||
// Malformed Expires header, shouldn't be used to construct a valid response.
|
// Malformed Expires header, shouldn't be used to construct a valid response.
|
||||||
None if response.headers.contains_key(header::EXPIRES) => return Duration::seconds(0i64),
|
None if response.headers.contains_key(header::EXPIRES) => return Duration::seconds(0i64),
|
||||||
|
@ -246,24 +244,23 @@ fn get_response_expiry(response: &Response) -> Duration {
|
||||||
let last_modified = Timespec::new(last_modified.as_secs() as i64, 0);
|
let last_modified = Timespec::new(last_modified.as_secs() as i64, 0);
|
||||||
// A typical setting of this fraction might be 10%.
|
// A typical setting of this fraction might be 10%.
|
||||||
let raw_heuristic_calc = (current - last_modified) / 10;
|
let raw_heuristic_calc = (current - last_modified) / 10;
|
||||||
let result = if raw_heuristic_calc < max_heuristic {
|
|
||||||
|
if raw_heuristic_calc < max_heuristic {
|
||||||
raw_heuristic_calc
|
raw_heuristic_calc
|
||||||
} else {
|
} else {
|
||||||
max_heuristic
|
max_heuristic
|
||||||
};
|
}
|
||||||
result
|
|
||||||
} else {
|
} else {
|
||||||
max_heuristic
|
max_heuristic
|
||||||
};
|
};
|
||||||
if is_cacheable_by_default(*code) {
|
if is_cacheable_by_default(*code) {
|
||||||
// Status codes that are cacheable by default can use heuristics to determine freshness.
|
// Status codes that are cacheable by default can use heuristics to determine freshness.
|
||||||
return heuristic_freshness;
|
return heuristic_freshness;
|
||||||
} else {
|
}
|
||||||
// Other status codes can only use heuristic freshness if the public cache directive is present.
|
// Other status codes can only use heuristic freshness if the public cache directive is present.
|
||||||
if let Some(ref directives) = response.headers.typed_get::<CacheControl>() {
|
if let Some(ref directives) = response.headers.typed_get::<CacheControl>() {
|
||||||
if directives.public() {
|
if directives.public() {
|
||||||
return heuristic_freshness;
|
return heuristic_freshness;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,9 +332,9 @@ fn create_cached_response(
|
||||||
response.status = cached_resource.data.status.clone();
|
response.status = cached_resource.data.status.clone();
|
||||||
response.raw_status = cached_resource.data.raw_status.clone();
|
response.raw_status = cached_resource.data.raw_status.clone();
|
||||||
response.url_list = cached_resource.data.url_list.clone();
|
response.url_list = cached_resource.data.url_list.clone();
|
||||||
response.https_state = cached_resource.data.https_state.clone();
|
response.https_state = cached_resource.data.https_state;
|
||||||
response.referrer = request.referrer.to_url().cloned();
|
response.referrer = request.referrer.to_url().cloned();
|
||||||
response.referrer_policy = request.referrer_policy.clone();
|
response.referrer_policy = request.referrer_policy;
|
||||||
response.aborted = cached_resource.aborted.clone();
|
response.aborted = cached_resource.aborted.clone();
|
||||||
let expires = cached_resource.data.expires;
|
let expires = cached_resource.data.expires;
|
||||||
let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires);
|
let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires);
|
||||||
|
@ -347,10 +344,9 @@ fn create_cached_response(
|
||||||
// TODO: take must-revalidate into account <https://tools.ietf.org/html/rfc7234#section-5.2.2.1>
|
// TODO: take must-revalidate into account <https://tools.ietf.org/html/rfc7234#section-5.2.2.1>
|
||||||
// TODO: if this cache is to be considered shared, take proxy-revalidate into account
|
// TODO: if this cache is to be considered shared, take proxy-revalidate into account
|
||||||
// <https://tools.ietf.org/html/rfc7234#section-5.2.2.7>
|
// <https://tools.ietf.org/html/rfc7234#section-5.2.2.7>
|
||||||
let has_expired =
|
let has_expired = adjusted_expires <= time_since_validated;
|
||||||
(adjusted_expires < time_since_validated) || (adjusted_expires == time_since_validated);
|
|
||||||
let cached_response = CachedResponse {
|
let cached_response = CachedResponse {
|
||||||
response: response,
|
response,
|
||||||
needs_validation: has_expired,
|
needs_validation: has_expired,
|
||||||
};
|
};
|
||||||
Some(cached_response)
|
Some(cached_response)
|
||||||
|
@ -370,12 +366,12 @@ fn create_resource_with_bytes_from_resource(
|
||||||
data: Measurable(MeasurableCachedResource {
|
data: Measurable(MeasurableCachedResource {
|
||||||
metadata: resource.data.metadata.clone(),
|
metadata: resource.data.metadata.clone(),
|
||||||
location_url: resource.data.location_url.clone(),
|
location_url: resource.data.location_url.clone(),
|
||||||
https_state: resource.data.https_state.clone(),
|
https_state: resource.data.https_state,
|
||||||
status: Some((StatusCode::PARTIAL_CONTENT, "Partial Content".into())),
|
status: Some((StatusCode::PARTIAL_CONTENT, "Partial Content".into())),
|
||||||
raw_status: Some((206, b"Partial Content".to_vec())),
|
raw_status: Some((206, b"Partial Content".to_vec())),
|
||||||
url_list: resource.data.url_list.clone(),
|
url_list: resource.data.url_list.clone(),
|
||||||
expires: resource.data.expires.clone(),
|
expires: resource.data.expires,
|
||||||
last_validated: resource.data.last_validated.clone(),
|
last_validated: resource.data.last_validated,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,7 +409,7 @@ fn handle_range_request(
|
||||||
// see <https://tools.ietf.org/html/rfc7233#section-4.3>.
|
// see <https://tools.ietf.org/html/rfc7233#section-4.3>.
|
||||||
// TODO: add support for complete and partial resources,
|
// TODO: add support for complete and partial resources,
|
||||||
// whose body is in the ResponseBody::Receiving state.
|
// whose body is in the ResponseBody::Receiving state.
|
||||||
(&(Bound::Included(beginning), Bound::Included(end)), Some(ref complete_resource)) => {
|
(&(Bound::Included(beginning), Bound::Included(end)), Some(complete_resource)) => {
|
||||||
if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() {
|
if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() {
|
||||||
if end == u64::max_value() {
|
if end == u64::max_value() {
|
||||||
// Prevent overflow on the addition below.
|
// Prevent overflow on the addition below.
|
||||||
|
@ -427,7 +423,7 @@ fn handle_range_request(
|
||||||
create_resource_with_bytes_from_resource(bytes, complete_resource);
|
create_resource_with_bytes_from_resource(bytes, complete_resource);
|
||||||
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
||||||
let cached_response =
|
let cached_response =
|
||||||
create_cached_response(request, &new_resource, &*cached_headers, done_chan);
|
create_cached_response(request, &new_resource, &cached_headers, done_chan);
|
||||||
if let Some(cached_response) = cached_response {
|
if let Some(cached_response) = cached_response {
|
||||||
return Some(cached_response);
|
return Some(cached_response);
|
||||||
}
|
}
|
||||||
|
@ -451,7 +447,7 @@ fn handle_range_request(
|
||||||
if res_beginning <= beginning && res_end >= end {
|
if res_beginning <= beginning && res_end >= end {
|
||||||
let resource_body = &*partial_resource.body.lock().unwrap();
|
let resource_body = &*partial_resource.body.lock().unwrap();
|
||||||
let requested = match resource_body {
|
let requested = match resource_body {
|
||||||
&ResponseBody::Done(ref body) => {
|
ResponseBody::Done(body) => {
|
||||||
let b = beginning as usize - res_beginning as usize;
|
let b = beginning as usize - res_beginning as usize;
|
||||||
let e = end as usize - res_beginning as usize + 1;
|
let e = end as usize - res_beginning as usize + 1;
|
||||||
body.get(b..e)
|
body.get(b..e)
|
||||||
|
@ -460,9 +456,9 @@ fn handle_range_request(
|
||||||
};
|
};
|
||||||
if let Some(bytes) = requested {
|
if let Some(bytes) = requested {
|
||||||
let new_resource =
|
let new_resource =
|
||||||
create_resource_with_bytes_from_resource(&bytes, partial_resource);
|
create_resource_with_bytes_from_resource(bytes, partial_resource);
|
||||||
let cached_response =
|
let cached_response =
|
||||||
create_cached_response(request, &new_resource, &*headers, done_chan);
|
create_cached_response(request, &new_resource, &headers, done_chan);
|
||||||
if let Some(cached_response) = cached_response {
|
if let Some(cached_response) = cached_response {
|
||||||
return Some(cached_response);
|
return Some(cached_response);
|
||||||
}
|
}
|
||||||
|
@ -470,7 +466,7 @@ fn handle_range_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(&(Bound::Included(beginning), Bound::Unbounded), Some(ref complete_resource)) => {
|
(&(Bound::Included(beginning), Bound::Unbounded), Some(complete_resource)) => {
|
||||||
if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() {
|
if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() {
|
||||||
let b = beginning as usize;
|
let b = beginning as usize;
|
||||||
let requested = body.get(b..);
|
let requested = body.get(b..);
|
||||||
|
@ -479,7 +475,7 @@ fn handle_range_request(
|
||||||
create_resource_with_bytes_from_resource(bytes, complete_resource);
|
create_resource_with_bytes_from_resource(bytes, complete_resource);
|
||||||
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
||||||
let cached_response =
|
let cached_response =
|
||||||
create_cached_response(request, &new_resource, &*cached_headers, done_chan);
|
create_cached_response(request, &new_resource, &cached_headers, done_chan);
|
||||||
if let Some(cached_response) = cached_response {
|
if let Some(cached_response) = cached_response {
|
||||||
return Some(cached_response);
|
return Some(cached_response);
|
||||||
}
|
}
|
||||||
|
@ -505,7 +501,7 @@ fn handle_range_request(
|
||||||
if res_beginning < beginning && res_end == total - 1 {
|
if res_beginning < beginning && res_end == total - 1 {
|
||||||
let resource_body = &*partial_resource.body.lock().unwrap();
|
let resource_body = &*partial_resource.body.lock().unwrap();
|
||||||
let requested = match resource_body {
|
let requested = match resource_body {
|
||||||
&ResponseBody::Done(ref body) => {
|
ResponseBody::Done(body) => {
|
||||||
let from_byte = beginning as usize - res_beginning as usize;
|
let from_byte = beginning as usize - res_beginning as usize;
|
||||||
body.get(from_byte..)
|
body.get(from_byte..)
|
||||||
},
|
},
|
||||||
|
@ -513,9 +509,9 @@ fn handle_range_request(
|
||||||
};
|
};
|
||||||
if let Some(bytes) = requested {
|
if let Some(bytes) = requested {
|
||||||
let new_resource =
|
let new_resource =
|
||||||
create_resource_with_bytes_from_resource(&bytes, partial_resource);
|
create_resource_with_bytes_from_resource(bytes, partial_resource);
|
||||||
let cached_response =
|
let cached_response =
|
||||||
create_cached_response(request, &new_resource, &*headers, done_chan);
|
create_cached_response(request, &new_resource, &headers, done_chan);
|
||||||
if let Some(cached_response) = cached_response {
|
if let Some(cached_response) = cached_response {
|
||||||
return Some(cached_response);
|
return Some(cached_response);
|
||||||
}
|
}
|
||||||
|
@ -523,7 +519,7 @@ fn handle_range_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(&(Bound::Unbounded, Bound::Included(offset)), Some(ref complete_resource)) => {
|
(&(Bound::Unbounded, Bound::Included(offset)), Some(complete_resource)) => {
|
||||||
if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() {
|
if let ResponseBody::Done(ref body) = *complete_resource.body.lock().unwrap() {
|
||||||
let from_byte = body.len() - offset as usize;
|
let from_byte = body.len() - offset as usize;
|
||||||
let requested = body.get(from_byte..);
|
let requested = body.get(from_byte..);
|
||||||
|
@ -532,7 +528,7 @@ fn handle_range_request(
|
||||||
create_resource_with_bytes_from_resource(bytes, complete_resource);
|
create_resource_with_bytes_from_resource(bytes, complete_resource);
|
||||||
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
|
||||||
let cached_response =
|
let cached_response =
|
||||||
create_cached_response(request, &new_resource, &*cached_headers, done_chan);
|
create_cached_response(request, &new_resource, &cached_headers, done_chan);
|
||||||
if let Some(cached_response) = cached_response {
|
if let Some(cached_response) = cached_response {
|
||||||
return Some(cached_response);
|
return Some(cached_response);
|
||||||
}
|
}
|
||||||
|
@ -551,8 +547,8 @@ fn handle_range_request(
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if !(total >= res_beginning) ||
|
if total < res_beginning ||
|
||||||
!(total >= res_end) ||
|
total < res_end ||
|
||||||
offset == 0 ||
|
offset == 0 ||
|
||||||
offset == u64::max_value()
|
offset == u64::max_value()
|
||||||
{
|
{
|
||||||
|
@ -562,7 +558,7 @@ fn handle_range_request(
|
||||||
if (total - res_beginning) > (offset - 1) && (total - res_end) < offset + 1 {
|
if (total - res_beginning) > (offset - 1) && (total - res_end) < offset + 1 {
|
||||||
let resource_body = &*partial_resource.body.lock().unwrap();
|
let resource_body = &*partial_resource.body.lock().unwrap();
|
||||||
let requested = match resource_body {
|
let requested = match resource_body {
|
||||||
&ResponseBody::Done(ref body) => {
|
ResponseBody::Done(body) => {
|
||||||
let from_byte = body.len() - offset as usize;
|
let from_byte = body.len() - offset as usize;
|
||||||
body.get(from_byte..)
|
body.get(from_byte..)
|
||||||
},
|
},
|
||||||
|
@ -570,9 +566,9 @@ fn handle_range_request(
|
||||||
};
|
};
|
||||||
if let Some(bytes) = requested {
|
if let Some(bytes) = requested {
|
||||||
let new_resource =
|
let new_resource =
|
||||||
create_resource_with_bytes_from_resource(&bytes, partial_resource);
|
create_resource_with_bytes_from_resource(bytes, partial_resource);
|
||||||
let cached_response =
|
let cached_response =
|
||||||
create_cached_response(request, &new_resource, &*headers, done_chan);
|
create_cached_response(request, &new_resource, &headers, done_chan);
|
||||||
if let Some(cached_response) = cached_response {
|
if let Some(cached_response) = cached_response {
|
||||||
return Some(cached_response);
|
return Some(cached_response);
|
||||||
}
|
}
|
||||||
|
@ -587,13 +583,6 @@ fn handle_range_request(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpCache {
|
impl HttpCache {
|
||||||
/// Create a new memory cache instance.
|
|
||||||
pub fn new() -> HttpCache {
|
|
||||||
HttpCache {
|
|
||||||
entries: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructing Responses from Caches.
|
/// Constructing Responses from Caches.
|
||||||
/// <https://tools.ietf.org/html/rfc7234#section-4>
|
/// <https://tools.ietf.org/html/rfc7234#section-4>
|
||||||
pub fn construct_response(
|
pub fn construct_response(
|
||||||
|
@ -608,11 +597,11 @@ impl HttpCache {
|
||||||
debug!("non-GET method, not caching");
|
debug!("non-GET method, not caching");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let entry_key = CacheKey::new(&request);
|
let entry_key = CacheKey::new(request);
|
||||||
let resources = self
|
let resources = self
|
||||||
.entries
|
.entries
|
||||||
.get(&entry_key)?
|
.get(&entry_key)?
|
||||||
.into_iter()
|
.iter()
|
||||||
.filter(|r| !r.aborted.load(Ordering::Relaxed));
|
.filter(|r| !r.aborted.load(Ordering::Relaxed));
|
||||||
let mut candidates = vec![];
|
let mut candidates = vec![];
|
||||||
for cached_resource in resources {
|
for cached_resource in resources {
|
||||||
|
@ -671,36 +660,35 @@ impl HttpCache {
|
||||||
range_spec.iter().collect(),
|
range_spec.iter().collect(),
|
||||||
done_chan,
|
done_chan,
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
while let Some(cached_resource) = candidates.pop() {
|
while let Some(cached_resource) = candidates.pop() {
|
||||||
// Not a Range request.
|
// Not a Range request.
|
||||||
// Do not allow 206 responses to be constructed.
|
// Do not allow 206 responses to be constructed.
|
||||||
//
|
//
|
||||||
// See https://tools.ietf.org/html/rfc7234#section-3.1
|
// See https://tools.ietf.org/html/rfc7234#section-3.1
|
||||||
//
|
//
|
||||||
// A cache MUST NOT use an incomplete response to answer requests unless the
|
// A cache MUST NOT use an incomplete response to answer requests unless the
|
||||||
// response has been made complete or the request is partial and
|
// response has been made complete or the request is partial and
|
||||||
// specifies a range that is wholly within the incomplete response.
|
// specifies a range that is wholly within the incomplete response.
|
||||||
//
|
//
|
||||||
// TODO: Combining partial content to fulfill a non-Range request
|
// TODO: Combining partial content to fulfill a non-Range request
|
||||||
// see https://tools.ietf.org/html/rfc7234#section-3.3
|
// see https://tools.ietf.org/html/rfc7234#section-3.3
|
||||||
match cached_resource.data.raw_status {
|
match cached_resource.data.raw_status {
|
||||||
Some((ref code, _)) => {
|
Some((ref code, _)) => {
|
||||||
if *code == 206 {
|
if *code == 206 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => continue,
|
None => continue,
|
||||||
}
|
}
|
||||||
// Returning a response that can be constructed
|
// Returning a response that can be constructed
|
||||||
// TODO: select the most appropriate one, using a known mechanism from a selecting header field,
|
// TODO: select the most appropriate one, using a known mechanism from a selecting header field,
|
||||||
// or using the Date header to return the most recent one.
|
// or using the Date header to return the most recent one.
|
||||||
let cached_headers = cached_resource.data.metadata.headers.lock().unwrap();
|
let cached_headers = cached_resource.data.metadata.headers.lock().unwrap();
|
||||||
let cached_response =
|
let cached_response =
|
||||||
create_cached_response(request, cached_resource, &*cached_headers, done_chan);
|
create_cached_response(request, cached_resource, &cached_headers, done_chan);
|
||||||
if let Some(cached_response) = cached_response {
|
if let Some(cached_response) = cached_response {
|
||||||
return Some(cached_response);
|
return Some(cached_response);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("couldn't find an appropriate response, not caching");
|
debug!("couldn't find an appropriate response, not caching");
|
||||||
|
@ -712,7 +700,7 @@ impl HttpCache {
|
||||||
/// whose response body was still receiving data when the resource was constructed,
|
/// whose response body was still receiving data when the resource was constructed,
|
||||||
/// and whose response has now either been completed or cancelled.
|
/// and whose response has now either been completed or cancelled.
|
||||||
pub fn update_awaiting_consumers(&self, request: &Request, response: &Response) {
|
pub fn update_awaiting_consumers(&self, request: &Request, response: &Response) {
|
||||||
let entry_key = CacheKey::new(&request);
|
let entry_key = CacheKey::new(request);
|
||||||
|
|
||||||
let cached_resources = match self.entries.get(&entry_key) {
|
let cached_resources = match self.entries.get(&entry_key) {
|
||||||
None => return,
|
None => return,
|
||||||
|
@ -762,9 +750,9 @@ impl HttpCache {
|
||||||
done_chan: &mut DoneChannel,
|
done_chan: &mut DoneChannel,
|
||||||
) -> Option<Response> {
|
) -> Option<Response> {
|
||||||
assert_eq!(response.status.map(|s| s.0), Some(StatusCode::NOT_MODIFIED));
|
assert_eq!(response.status.map(|s| s.0), Some(StatusCode::NOT_MODIFIED));
|
||||||
let entry_key = CacheKey::new(&request);
|
let entry_key = CacheKey::new(request);
|
||||||
if let Some(cached_resources) = self.entries.get_mut(&entry_key) {
|
if let Some(cached_resources) = self.entries.get_mut(&entry_key) {
|
||||||
for cached_resource in cached_resources.iter_mut() {
|
if let Some(cached_resource) = cached_resources.iter_mut().next() {
|
||||||
// done_chan will have been set to Some(..) by http_network_fetch.
|
// done_chan will have been set to Some(..) by http_network_fetch.
|
||||||
// If the body is not receiving data, set the done_chan back to None.
|
// If the body is not receiving data, set the done_chan back to None.
|
||||||
// Otherwise, create a new dedicated channel to update the consumer.
|
// Otherwise, create a new dedicated channel to update the consumer.
|
||||||
|
@ -794,9 +782,9 @@ impl HttpCache {
|
||||||
);
|
);
|
||||||
constructed_response.body = cached_resource.body.clone();
|
constructed_response.body = cached_resource.body.clone();
|
||||||
constructed_response.status = cached_resource.data.status.clone();
|
constructed_response.status = cached_resource.data.status.clone();
|
||||||
constructed_response.https_state = cached_resource.data.https_state.clone();
|
constructed_response.https_state = cached_resource.data.https_state;
|
||||||
constructed_response.referrer = request.referrer.to_url().cloned();
|
constructed_response.referrer = request.referrer.to_url().cloned();
|
||||||
constructed_response.referrer_policy = request.referrer_policy.clone();
|
constructed_response.referrer_policy = request.referrer_policy;
|
||||||
constructed_response.raw_status = cached_resource.data.raw_status.clone();
|
constructed_response.raw_status = cached_resource.data.raw_status.clone();
|
||||||
constructed_response.url_list = cached_resource.data.url_list.clone();
|
constructed_response.url_list = cached_resource.data.url_list.clone();
|
||||||
cached_resource.data.expires = get_response_expiry(&constructed_response);
|
cached_resource.data.expires = get_response_expiry(&constructed_response);
|
||||||
|
@ -831,12 +819,12 @@ impl HttpCache {
|
||||||
self.invalidate_for_url(&url);
|
self.invalidate_for_url(&url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(Ok(ref content_location)) = response
|
if let Some(Ok(content_location)) = response
|
||||||
.headers
|
.headers
|
||||||
.get(header::CONTENT_LOCATION)
|
.get(header::CONTENT_LOCATION)
|
||||||
.map(HeaderValue::to_str)
|
.map(HeaderValue::to_str)
|
||||||
{
|
{
|
||||||
if let Ok(url) = request.current_url().join(&content_location) {
|
if let Ok(url) = request.current_url().join(content_location) {
|
||||||
self.invalidate_for_url(&url);
|
self.invalidate_for_url(&url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -862,7 +850,7 @@ impl HttpCache {
|
||||||
// responses to be stored is present in the response.
|
// responses to be stored is present in the response.
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let entry_key = CacheKey::new(&request);
|
let entry_key = CacheKey::new(request);
|
||||||
let metadata = match response.metadata() {
|
let metadata = match response.metadata() {
|
||||||
Ok(FetchMetadata::Filtered {
|
Ok(FetchMetadata::Filtered {
|
||||||
filtered: _,
|
filtered: _,
|
||||||
|
@ -874,7 +862,7 @@ impl HttpCache {
|
||||||
if !response_is_cacheable(&metadata) {
|
if !response_is_cacheable(&metadata) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let expiry = get_response_expiry(&response);
|
let expiry = get_response_expiry(response);
|
||||||
let cacheable_metadata = CachedMetadata {
|
let cacheable_metadata = CachedMetadata {
|
||||||
headers: Arc::new(Mutex::new(response.headers.clone())),
|
headers: Arc::new(Mutex::new(response.headers.clone())),
|
||||||
data: Measurable(MeasurableCachedMetadata {
|
data: Measurable(MeasurableCachedMetadata {
|
||||||
|
@ -892,7 +880,7 @@ impl HttpCache {
|
||||||
data: Measurable(MeasurableCachedResource {
|
data: Measurable(MeasurableCachedResource {
|
||||||
metadata: cacheable_metadata,
|
metadata: cacheable_metadata,
|
||||||
location_url: response.location_url.clone(),
|
location_url: response.location_url.clone(),
|
||||||
https_state: response.https_state.clone(),
|
https_state: response.https_state,
|
||||||
status: response.status.clone(),
|
status: response.status.clone(),
|
||||||
raw_status: response.raw_status.clone(),
|
raw_status: response.raw_status.clone(),
|
||||||
url_list: response.url_list.clone(),
|
url_list: response.url_list.clone(),
|
||||||
|
@ -900,7 +888,7 @@ impl HttpCache {
|
||||||
last_validated: time::now(),
|
last_validated: time::now(),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
let entry = self.entries.entry(entry_key).or_insert_with(|| vec![]);
|
let entry = self.entries.entry(entry_key).or_default();
|
||||||
entry.push(entry_resource);
|
entry.push(entry_resource);
|
||||||
// TODO: Complete incomplete responses, including 206 response, when stored here.
|
// TODO: Complete incomplete responses, including 206 response, when stored here.
|
||||||
// See A cache MAY complete a stored incomplete response by making a subsequent range request
|
// See A cache MAY complete a stored incomplete response by making a subsequent range request
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::mem;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::sync::{Arc as StdArc, Condvar, Mutex, RwLock};
|
use std::sync::{Arc as StdArc, Condvar, Mutex, RwLock};
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
@ -21,8 +19,8 @@ use headers::authorization::Basic;
|
||||||
use headers::{
|
use headers::{
|
||||||
AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowMethods,
|
AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowMethods,
|
||||||
AccessControlAllowOrigin, AccessControlMaxAge, AccessControlRequestHeaders,
|
AccessControlAllowOrigin, AccessControlMaxAge, AccessControlRequestHeaders,
|
||||||
AccessControlRequestMethod, Authorization, CacheControl, ContentEncoding, ContentLength,
|
AccessControlRequestMethod, Authorization, CacheControl, ContentLength, HeaderMapExt,
|
||||||
HeaderMapExt, IfModifiedSince, LastModified, Origin as HyperOrigin, Pragma, Referer, UserAgent,
|
IfModifiedSince, LastModified, Origin as HyperOrigin, Pragma, Referer, UserAgent,
|
||||||
};
|
};
|
||||||
use http::header::{
|
use http::header::{
|
||||||
self, HeaderValue, ACCEPT, CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_LOCATION, CONTENT_TYPE,
|
self, HeaderValue, ACCEPT, CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_LOCATION, CONTENT_TYPE,
|
||||||
|
@ -101,15 +99,15 @@ pub struct HttpState {
|
||||||
pub override_manager: CertificateErrorOverrideManager,
|
pub override_manager: CertificateErrorOverrideManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpState {
|
impl Default for HttpState {
|
||||||
pub fn new() -> HttpState {
|
fn default() -> Self {
|
||||||
let override_manager = CertificateErrorOverrideManager::new();
|
let override_manager = CertificateErrorOverrideManager::new();
|
||||||
HttpState {
|
Self {
|
||||||
hsts_list: RwLock::new(HstsList::new()),
|
hsts_list: RwLock::new(HstsList::default()),
|
||||||
cookie_jar: RwLock::new(CookieStorage::new(150)),
|
cookie_jar: RwLock::new(CookieStorage::new(150)),
|
||||||
auth_cache: RwLock::new(AuthCache::new()),
|
auth_cache: RwLock::new(AuthCache::default()),
|
||||||
history_states: RwLock::new(HashMap::new()),
|
history_states: RwLock::new(HashMap::new()),
|
||||||
http_cache: RwLock::new(HttpCache::new()),
|
http_cache: RwLock::new(HttpCache::default()),
|
||||||
http_cache_state: Mutex::new(HashMap::new()),
|
http_cache_state: Mutex::new(HashMap::new()),
|
||||||
client: create_http_client(create_tls_config(
|
client: create_http_client(create_tls_config(
|
||||||
CACertificates::Default,
|
CACertificates::Default,
|
||||||
|
@ -193,7 +191,7 @@ fn no_referrer_when_downgrade(referrer_url: ServoUrl, current_url: ServoUrl) ->
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// Step 2
|
// Step 2
|
||||||
return strip_url_for_use_as_referrer(referrer_url, false);
|
strip_url_for_use_as_referrer(referrer_url, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin>
|
/// <https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin>
|
||||||
|
@ -237,8 +235,8 @@ fn is_schemelessy_same_site(site_a: &ImmutableOrigin, site_b: &ImmutableOrigin)
|
||||||
let host_b_reg = reg_suffix(&host_b);
|
let host_b_reg = reg_suffix(&host_b);
|
||||||
|
|
||||||
// Step 2.2-2.3
|
// Step 2.2-2.3
|
||||||
(site_a.host() == site_b.host() && host_a_reg == "") ||
|
(site_a.host() == site_b.host() && host_a_reg.is_empty()) ||
|
||||||
(host_a_reg == host_b_reg && host_a_reg != "")
|
(host_a_reg == host_b_reg && !host_a_reg.is_empty())
|
||||||
} else {
|
} else {
|
||||||
// Step 3
|
// Step 3
|
||||||
false
|
false
|
||||||
|
@ -345,7 +343,7 @@ fn set_cookies_from_headers(
|
||||||
) {
|
) {
|
||||||
for cookie in headers.get_all(header::SET_COOKIE) {
|
for cookie in headers.get_all(header::SET_COOKIE) {
|
||||||
if let Ok(cookie_str) = std::str::from_utf8(cookie.as_bytes()) {
|
if let Ok(cookie_str) = std::str::from_utf8(cookie.as_bytes()) {
|
||||||
set_cookie_for_url(&cookie_jar, &url, &cookie_str);
|
set_cookie_for_url(cookie_jar, url, cookie_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,16 +361,16 @@ fn prepare_devtools_request(
|
||||||
is_xhr: bool,
|
is_xhr: bool,
|
||||||
) -> ChromeToDevtoolsControlMsg {
|
) -> ChromeToDevtoolsControlMsg {
|
||||||
let request = DevtoolsHttpRequest {
|
let request = DevtoolsHttpRequest {
|
||||||
url: url,
|
url,
|
||||||
method: method,
|
method,
|
||||||
headers: headers,
|
headers,
|
||||||
body: body,
|
body,
|
||||||
pipeline_id: pipeline_id,
|
pipeline_id,
|
||||||
startedDateTime: now,
|
startedDateTime: now,
|
||||||
timeStamp: now.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as i64,
|
timeStamp: now.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as i64,
|
||||||
connect_time: connect_time,
|
connect_time,
|
||||||
send_time: send_time,
|
send_time,
|
||||||
is_xhr: is_xhr,
|
is_xhr,
|
||||||
};
|
};
|
||||||
let net_event = NetworkEvent::HttpRequest(request);
|
let net_event = NetworkEvent::HttpRequest(request);
|
||||||
|
|
||||||
|
@ -396,10 +394,10 @@ fn send_response_to_devtools(
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
) {
|
) {
|
||||||
let response = DevtoolsHttpResponse {
|
let response = DevtoolsHttpResponse {
|
||||||
headers: headers,
|
headers,
|
||||||
status: status,
|
status,
|
||||||
body: None,
|
body: None,
|
||||||
pipeline_id: pipeline_id,
|
pipeline_id,
|
||||||
};
|
};
|
||||||
let net_event_response = NetworkEvent::HttpResponse(response);
|
let net_event_response = NetworkEvent::HttpResponse(response);
|
||||||
|
|
||||||
|
@ -411,7 +409,7 @@ fn auth_from_cache(
|
||||||
auth_cache: &RwLock<AuthCache>,
|
auth_cache: &RwLock<AuthCache>,
|
||||||
origin: &ImmutableOrigin,
|
origin: &ImmutableOrigin,
|
||||||
) -> Option<Authorization<Basic>> {
|
) -> Option<Authorization<Basic>> {
|
||||||
if let Some(ref auth_entry) = auth_cache
|
if let Some(auth_entry) = auth_cache
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.entries
|
.entries
|
||||||
|
@ -503,9 +501,9 @@ async fn obtain_response(
|
||||||
.clone()
|
.clone()
|
||||||
.into_url()
|
.into_url()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.replace("|", "%7C")
|
.replace('|', "%7C")
|
||||||
.replace("{", "%7B")
|
.replace('{', "%7B")
|
||||||
.replace("}", "%7D");
|
.replace('}', "%7D");
|
||||||
|
|
||||||
let request = if let Some(chunk_requester) = body {
|
let request = if let Some(chunk_requester) = body {
|
||||||
let (sink, stream) = if source_is_null {
|
let (sink, stream) = if source_is_null {
|
||||||
|
@ -649,7 +647,7 @@ async fn obtain_response(
|
||||||
.set_attribute(ResourceAttribute::ConnectEnd(connect_end));
|
.set_attribute(ResourceAttribute::ConnectEnd(connect_end));
|
||||||
|
|
||||||
let request_id = request_id.map(|v| v.to_owned());
|
let request_id = request_id.map(|v| v.to_owned());
|
||||||
let pipeline_id = pipeline_id.clone();
|
let pipeline_id = *pipeline_id;
|
||||||
let closure_url = url.clone();
|
let closure_url = url.clone();
|
||||||
let method = method.clone();
|
let method = method.clone();
|
||||||
let send_start = precise_time_ms();
|
let send_start = precise_time_ms();
|
||||||
|
@ -760,13 +758,13 @@ pub async fn http_fetch(
|
||||||
let method_mismatch = !method_cache_match &&
|
let method_mismatch = !method_cache_match &&
|
||||||
(!is_cors_safelisted_method(&request.method) || request.use_cors_preflight);
|
(!is_cors_safelisted_method(&request.method) || request.use_cors_preflight);
|
||||||
let header_mismatch = request.headers.iter().any(|(name, value)| {
|
let header_mismatch = request.headers.iter().any(|(name, value)| {
|
||||||
!cache.match_header(&*request, &name) &&
|
!cache.match_header(&*request, name) &&
|
||||||
!is_cors_safelisted_request_header(&name, &value)
|
!is_cors_safelisted_request_header(&name, &value)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sub-substep 1
|
// Sub-substep 1
|
||||||
if method_mismatch || header_mismatch {
|
if method_mismatch || header_mismatch {
|
||||||
let preflight_result = cors_preflight_fetch(&request, cache, context).await;
|
let preflight_result = cors_preflight_fetch(request, cache, context).await;
|
||||||
// Sub-substep 2
|
// Sub-substep 2
|
||||||
if let Some(e) = preflight_result.get_network_error() {
|
if let Some(e) = preflight_result.get_network_error() {
|
||||||
return Response::network_error(e.clone());
|
return Response::network_error(e.clone());
|
||||||
|
@ -798,7 +796,7 @@ pub async fn http_fetch(
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Substep 4
|
// Substep 4
|
||||||
if cors_flag && cors_check(&request, &fetch_result).is_err() {
|
if cors_flag && cors_check(request, &fetch_result).is_err() {
|
||||||
return Response::network_error(NetworkError::Internal("CORS check failed".into()));
|
return Response::network_error(NetworkError::Internal("CORS check failed".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +832,7 @@ pub async fn http_fetch(
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
HeaderValue::to_str(v)
|
HeaderValue::to_str(v)
|
||||||
.map(|l| {
|
.map(|l| {
|
||||||
ServoUrl::parse_with_base(response.actual_response().url(), &l)
|
ServoUrl::parse_with_base(response.actual_response().url(), l)
|
||||||
.map_err(|err| err.to_string())
|
.map_err(|err| err.to_string())
|
||||||
})
|
})
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -1093,7 +1091,7 @@ fn try_immutable_origin_to_hyper_origin(url_origin: &ImmutableOrigin) -> Option<
|
||||||
("http", 80) | ("https", 443) => None,
|
("http", 80) | ("https", 443) => None,
|
||||||
_ => Some(*port),
|
_ => Some(*port),
|
||||||
};
|
};
|
||||||
HyperOrigin::try_from_parts(&scheme, &host.to_string(), port).ok()
|
HyperOrigin::try_from_parts(scheme, &host.to_string(), port).ok()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1257,13 +1255,14 @@ async fn http_network_or_cache_fetch(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 5
|
// Substep 5
|
||||||
if authentication_fetch_flag && authorization_value.is_none() {
|
if authentication_fetch_flag &&
|
||||||
if has_credentials(¤t_url) {
|
authorization_value.is_none() &&
|
||||||
authorization_value = Some(Authorization::basic(
|
has_credentials(¤t_url)
|
||||||
current_url.username(),
|
{
|
||||||
current_url.password().unwrap_or(""),
|
authorization_value = Some(Authorization::basic(
|
||||||
));
|
current_url.username(),
|
||||||
}
|
current_url.password().unwrap_or(""),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 6
|
// Substep 6
|
||||||
|
@ -1285,7 +1284,7 @@ async fn http_network_or_cache_fetch(
|
||||||
// That one happens when a fetch gets a cache hit, and the resource is pending completion from the network.
|
// That one happens when a fetch gets a cache hit, and the resource is pending completion from the network.
|
||||||
{
|
{
|
||||||
let (lock, cvar) = {
|
let (lock, cvar) = {
|
||||||
let entry_key = CacheKey::new(&http_request);
|
let entry_key = CacheKey::new(http_request);
|
||||||
let mut state_map = context.state.http_cache_state.lock().unwrap();
|
let mut state_map = context.state.http_cache_state.lock().unwrap();
|
||||||
&*state_map
|
&*state_map
|
||||||
.entry(entry_key)
|
.entry(entry_key)
|
||||||
|
@ -1314,7 +1313,7 @@ async fn http_network_or_cache_fetch(
|
||||||
// Step 5.19
|
// Step 5.19
|
||||||
if let Ok(http_cache) = context.state.http_cache.read() {
|
if let Ok(http_cache) = context.state.http_cache.read() {
|
||||||
if let Some(response_from_cache) =
|
if let Some(response_from_cache) =
|
||||||
http_cache.construct_response(&http_request, done_chan)
|
http_cache.construct_response(http_request, done_chan)
|
||||||
{
|
{
|
||||||
let response_headers = response_from_cache.response.headers.clone();
|
let response_headers = response_from_cache.response.headers.clone();
|
||||||
// Substep 1, 2, 3, 4
|
// Substep 1, 2, 3, 4
|
||||||
|
@ -1378,7 +1377,7 @@ async fn http_network_or_cache_fetch(
|
||||||
// if no stores are pending.
|
// if no stores are pending.
|
||||||
fn update_http_cache_state(context: &FetchContext, http_request: &Request) {
|
fn update_http_cache_state(context: &FetchContext, http_request: &Request) {
|
||||||
let (lock, cvar) = {
|
let (lock, cvar) = {
|
||||||
let entry_key = CacheKey::new(&http_request);
|
let entry_key = CacheKey::new(http_request);
|
||||||
let mut state_map = context.state.http_cache_state.lock().unwrap();
|
let mut state_map = context.state.http_cache_state.lock().unwrap();
|
||||||
&*state_map
|
&*state_map
|
||||||
.get_mut(&entry_key)
|
.get_mut(&entry_key)
|
||||||
|
@ -1437,7 +1436,7 @@ async fn http_network_or_cache_fetch(
|
||||||
if http_request.cache_mode == CacheMode::OnlyIfCached {
|
if http_request.cache_mode == CacheMode::OnlyIfCached {
|
||||||
// The cache will not be updated,
|
// The cache will not be updated,
|
||||||
// set its state to ready to construct.
|
// set its state to ready to construct.
|
||||||
update_http_cache_state(context, &http_request);
|
update_http_cache_state(context, http_request);
|
||||||
return Response::network_error(NetworkError::Internal(
|
return Response::network_error(NetworkError::Internal(
|
||||||
"Couldn't find response in cache".into(),
|
"Couldn't find response in cache".into(),
|
||||||
));
|
));
|
||||||
|
@ -1452,7 +1451,7 @@ async fn http_network_or_cache_fetch(
|
||||||
if let Some((200..=399, _)) = forward_response.raw_status {
|
if let Some((200..=399, _)) = forward_response.raw_status {
|
||||||
if !http_request.method.is_safe() {
|
if !http_request.method.is_safe() {
|
||||||
if let Ok(mut http_cache) = context.state.http_cache.write() {
|
if let Ok(mut http_cache) = context.state.http_cache.write() {
|
||||||
http_cache.invalidate(&http_request, &forward_response);
|
http_cache.invalidate(http_request, &forward_response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1467,7 +1466,7 @@ async fn http_network_or_cache_fetch(
|
||||||
// Ensure done_chan is None,
|
// Ensure done_chan is None,
|
||||||
// since the network response will be replaced by the revalidated stored one.
|
// since the network response will be replaced by the revalidated stored one.
|
||||||
*done_chan = None;
|
*done_chan = None;
|
||||||
response = http_cache.refresh(&http_request, forward_response.clone(), done_chan);
|
response = http_cache.refresh(http_request, forward_response.clone(), done_chan);
|
||||||
}
|
}
|
||||||
wait_for_cached_response(done_chan, &mut response).await;
|
wait_for_cached_response(done_chan, &mut response).await;
|
||||||
}
|
}
|
||||||
|
@ -1477,7 +1476,7 @@ async fn http_network_or_cache_fetch(
|
||||||
if http_request.cache_mode != CacheMode::NoStore {
|
if http_request.cache_mode != CacheMode::NoStore {
|
||||||
// Subsubstep 2, doing it first to avoid a clone of forward_response.
|
// Subsubstep 2, doing it first to avoid a clone of forward_response.
|
||||||
if let Ok(mut http_cache) = context.state.http_cache.write() {
|
if let Ok(mut http_cache) = context.state.http_cache.write() {
|
||||||
http_cache.store(&http_request, &forward_response);
|
http_cache.store(http_request, &forward_response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Subsubstep 1
|
// Subsubstep 1
|
||||||
|
@ -1488,7 +1487,7 @@ async fn http_network_or_cache_fetch(
|
||||||
let mut response = response.unwrap();
|
let mut response = response.unwrap();
|
||||||
|
|
||||||
// The cache has been updated, set its state to ready to construct.
|
// The cache has been updated, set its state to ready to construct.
|
||||||
update_http_cache_state(context, &http_request);
|
update_http_cache_state(context, http_request);
|
||||||
|
|
||||||
// Step 8
|
// Step 8
|
||||||
// TODO: if necessary set response's range-requested flag
|
// TODO: if necessary set response's range-requested flag
|
||||||
|
@ -1537,7 +1536,7 @@ async fn http_network_or_cache_fetch(
|
||||||
// Step 5
|
// Step 5
|
||||||
if let Origin::Origin(ref request_origin) = request.origin {
|
if let Origin::Origin(ref request_origin) = request.origin {
|
||||||
let schemeless_same_origin =
|
let schemeless_same_origin =
|
||||||
is_schemelessy_same_site(&request_origin, ¤t_url_origin);
|
is_schemelessy_same_site(request_origin, ¤t_url_origin);
|
||||||
if schemeless_same_origin &&
|
if schemeless_same_origin &&
|
||||||
(request_origin.scheme() == Some("https") ||
|
(request_origin.scheme() == Some("https") ||
|
||||||
response.https_state == HttpsState::None)
|
response.https_state == HttpsState::None)
|
||||||
|
@ -1555,7 +1554,7 @@ async fn http_network_or_cache_fetch(
|
||||||
}
|
}
|
||||||
|
|
||||||
if http_request.response_tainting != ResponseTainting::CorsTainting &&
|
if http_request.response_tainting != ResponseTainting::CorsTainting &&
|
||||||
cross_origin_resource_policy_check(&http_request, &response) ==
|
cross_origin_resource_policy_check(http_request, &response) ==
|
||||||
CrossOriginResourcePolicy::Blocked
|
CrossOriginResourcePolicy::Blocked
|
||||||
{
|
{
|
||||||
return Response::network_error(NetworkError::Internal(
|
return Response::network_error(NetworkError::Internal(
|
||||||
|
@ -1722,7 +1721,7 @@ async fn http_network_fetch(
|
||||||
.map(|body| body.source_is_null())
|
.map(|body| body.source_is_null())
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
&request.pipeline_id,
|
&request.pipeline_id,
|
||||||
request_id.as_ref().map(Deref::deref),
|
request_id.as_deref(),
|
||||||
is_xhr,
|
is_xhr,
|
||||||
context,
|
context,
|
||||||
fetch_terminated_sender,
|
fetch_terminated_sender,
|
||||||
|
@ -1796,7 +1795,7 @@ async fn http_network_fetch(
|
||||||
));
|
));
|
||||||
response.headers = res.headers().clone();
|
response.headers = res.headers().clone();
|
||||||
response.referrer = request.referrer.to_url().cloned();
|
response.referrer = request.referrer.to_url().cloned();
|
||||||
response.referrer_policy = request.referrer_policy.clone();
|
response.referrer_policy = request.referrer_policy;
|
||||||
|
|
||||||
let res_body = response.body.clone();
|
let res_body = response.body.clone();
|
||||||
|
|
||||||
|
@ -1834,7 +1833,7 @@ async fn http_network_fetch(
|
||||||
send_response_to_devtools(
|
send_response_to_devtools(
|
||||||
&sender,
|
&sender,
|
||||||
request_id.unwrap(),
|
request_id.unwrap(),
|
||||||
meta_headers.map(|hdrs| Serde::into_inner(hdrs)),
|
meta_headers.map(Serde::into_inner),
|
||||||
meta_status,
|
meta_status,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
);
|
);
|
||||||
|
@ -1852,7 +1851,6 @@ async fn http_network_fetch(
|
||||||
res.into_body()
|
res.into_body()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
warn!("Error streaming response body: {:?}", e);
|
warn!("Error streaming response body: {:?}", e);
|
||||||
()
|
|
||||||
})
|
})
|
||||||
.try_fold(res_body, move |res_body, chunk| {
|
.try_fold(res_body, move |res_body, chunk| {
|
||||||
if cancellation_listener.lock().unwrap().cancelled() {
|
if cancellation_listener.lock().unwrap().cancelled() {
|
||||||
|
@ -1862,7 +1860,7 @@ async fn http_network_fetch(
|
||||||
}
|
}
|
||||||
if let ResponseBody::Receiving(ref mut body) = *res_body.lock().unwrap() {
|
if let ResponseBody::Receiving(ref mut body) = *res_body.lock().unwrap() {
|
||||||
let bytes = chunk;
|
let bytes = chunk;
|
||||||
body.extend_from_slice(&*bytes);
|
body.extend_from_slice(&bytes);
|
||||||
let _ = done_sender.send(Data::Payload(bytes.to_vec()));
|
let _ = done_sender.send(Data::Payload(bytes.to_vec()));
|
||||||
}
|
}
|
||||||
future::ready(Ok(res_body))
|
future::ready(Ok(res_body))
|
||||||
|
@ -1871,7 +1869,7 @@ async fn http_network_fetch(
|
||||||
debug!("successfully finished response for {:?}", url1);
|
debug!("successfully finished response for {:?}", url1);
|
||||||
let mut body = res_body.lock().unwrap();
|
let mut body = res_body.lock().unwrap();
|
||||||
let completed_body = match *body {
|
let completed_body = match *body {
|
||||||
ResponseBody::Receiving(ref mut body) => mem::replace(body, vec![]),
|
ResponseBody::Receiving(ref mut body) => std::mem::take(body),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
*body = ResponseBody::Done(completed_body);
|
*body = ResponseBody::Done(completed_body);
|
||||||
|
@ -1886,7 +1884,7 @@ async fn http_network_fetch(
|
||||||
debug!("finished response for {:?}", url2);
|
debug!("finished response for {:?}", url2);
|
||||||
let mut body = res_body2.lock().unwrap();
|
let mut body = res_body2.lock().unwrap();
|
||||||
let completed_body = match *body {
|
let completed_body = match *body {
|
||||||
ResponseBody::Receiving(ref mut body) => mem::replace(body, vec![]),
|
ResponseBody::Receiving(ref mut body) => std::mem::take(body),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
*body = ResponseBody::Done(completed_body);
|
*body = ResponseBody::Done(completed_body);
|
||||||
|
@ -1913,16 +1911,6 @@ async fn http_network_fetch(
|
||||||
// Step 6-11
|
// Step 6-11
|
||||||
// (needs stream bodies)
|
// (needs stream bodies)
|
||||||
|
|
||||||
// Step 12
|
|
||||||
// TODO when https://bugzilla.mozilla.org/show_bug.cgi?id=1030660
|
|
||||||
// is resolved, this step will become uneccesary
|
|
||||||
// TODO this step
|
|
||||||
if let Some(encoding) = response.headers.typed_get::<ContentEncoding>() {
|
|
||||||
if encoding.contains("gzip") {
|
|
||||||
} else if encoding.contains("compress") {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Step 13
|
// Step 13
|
||||||
// TODO this step isn't possible yet (CSP)
|
// TODO this step isn't possible yet (CSP)
|
||||||
|
|
||||||
|
@ -1974,8 +1962,8 @@ async fn cors_preflight_fetch(
|
||||||
Origin::Origin(origin) => origin.clone(),
|
Origin::Origin(origin) => origin.clone(),
|
||||||
})
|
})
|
||||||
.pipeline_id(request.pipeline_id)
|
.pipeline_id(request.pipeline_id)
|
||||||
.initiator(request.initiator.clone())
|
.initiator(request.initiator)
|
||||||
.destination(request.destination.clone())
|
.destination(request.destination)
|
||||||
.referrer_policy(request.referrer_policy)
|
.referrer_policy(request.referrer_policy)
|
||||||
.mode(RequestMode::CorsMode)
|
.mode(RequestMode::CorsMode)
|
||||||
.response_tainting(ResponseTainting::CorsTainting)
|
.response_tainting(ResponseTainting::CorsTainting)
|
||||||
|
@ -2007,7 +1995,7 @@ async fn cors_preflight_fetch(
|
||||||
let response =
|
let response =
|
||||||
http_network_or_cache_fetch(&mut preflight, false, false, &mut None, context).await;
|
http_network_or_cache_fetch(&mut preflight, false, false, &mut None, context).await;
|
||||||
// Step 7
|
// Step 7
|
||||||
if cors_check(&request, &response).is_ok() &&
|
if cors_check(request, &response).is_ok() &&
|
||||||
response
|
response
|
||||||
.status
|
.status
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -2079,7 +2067,7 @@ async fn cors_preflight_fetch(
|
||||||
|
|
||||||
// Substep 6
|
// Substep 6
|
||||||
if request.headers.iter().any(|(name, _)| {
|
if request.headers.iter().any(|(name, _)| {
|
||||||
is_cors_non_wildcard_request_header_name(&name) &&
|
is_cors_non_wildcard_request_header_name(name) &&
|
||||||
header_names.iter().all(|hn| hn != name)
|
header_names.iter().all(|hn| hn != name)
|
||||||
}) {
|
}) {
|
||||||
return Response::network_error(NetworkError::Internal(
|
return Response::network_error(NetworkError::Internal(
|
||||||
|
@ -2116,12 +2104,12 @@ async fn cors_preflight_fetch(
|
||||||
|
|
||||||
// Substep 12, 13
|
// Substep 12, 13
|
||||||
for method in &methods {
|
for method in &methods {
|
||||||
cache.match_method_and_update(&*request, method.clone(), max_age);
|
cache.match_method_and_update(request, method.clone(), max_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 14, 15
|
// Substep 14, 15
|
||||||
for header_name in &header_names {
|
for header_name in &header_names {
|
||||||
cache.match_header_and_update(&*request, &*header_name, max_age);
|
cache.match_header_and_update(request, header_name, max_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 16
|
// Substep 16
|
||||||
|
|
|
@ -44,14 +44,11 @@ use crate::resource_thread::CoreResourceThreadPool;
|
||||||
|
|
||||||
fn decode_bytes_sync(key: LoadKey, bytes: &[u8], cors: CorsStatus) -> DecoderMsg {
|
fn decode_bytes_sync(key: LoadKey, bytes: &[u8], cors: CorsStatus) -> DecoderMsg {
|
||||||
let image = load_from_memory(bytes, cors);
|
let image = load_from_memory(bytes, cors);
|
||||||
DecoderMsg {
|
DecoderMsg { key, image }
|
||||||
key: key,
|
|
||||||
image: image,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_placeholder_image(webrender_api: &WebrenderIpcSender, data: &[u8]) -> Arc<Image> {
|
fn get_placeholder_image(webrender_api: &WebrenderIpcSender, data: &[u8]) -> Arc<Image> {
|
||||||
let mut image = load_from_memory(&data, CorsStatus::Unsafe).unwrap();
|
let mut image = load_from_memory(data, CorsStatus::Unsafe).unwrap();
|
||||||
set_webrender_image_key(webrender_api, &mut image);
|
set_webrender_image_key(webrender_api, &mut image);
|
||||||
Arc::new(image)
|
Arc::new(image)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +60,7 @@ fn set_webrender_image_key(webrender_api: &WebrenderIpcSender, image: &mut Image
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
let is_opaque = match image.format {
|
let is_opaque = match image.format {
|
||||||
PixelFormat::BGRA8 => {
|
PixelFormat::BGRA8 => {
|
||||||
bytes.extend_from_slice(&*image.bytes);
|
bytes.extend_from_slice(&image.bytes);
|
||||||
pixels::rgba8_premultiply_inplace(bytes.as_mut_slice())
|
pixels::rgba8_premultiply_inplace(bytes.as_mut_slice())
|
||||||
},
|
},
|
||||||
PixelFormat::RGB8 => {
|
PixelFormat::RGB8 => {
|
||||||
|
@ -130,7 +127,7 @@ impl AllPendingLoads {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
|
fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
|
||||||
self.loads.remove(key).and_then(|pending_load| {
|
self.loads.remove(key).map(|pending_load| {
|
||||||
self.url_to_load_key
|
self.url_to_load_key
|
||||||
.remove(&(
|
.remove(&(
|
||||||
pending_load.url.clone(),
|
pending_load.url.clone(),
|
||||||
|
@ -138,16 +135,16 @@ impl AllPendingLoads {
|
||||||
pending_load.cors_setting,
|
pending_load.cors_setting,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Some(pending_load)
|
pending_load
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cached<'a>(
|
fn get_cached(
|
||||||
&'a mut self,
|
&mut self,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
origin: ImmutableOrigin,
|
origin: ImmutableOrigin,
|
||||||
cors_status: Option<CorsSettings>,
|
cors_status: Option<CorsSettings>,
|
||||||
) -> CacheResult<'a> {
|
) -> CacheResult<'_> {
|
||||||
match self
|
match self
|
||||||
.url_to_load_key
|
.url_to_load_key
|
||||||
.entry((url.clone(), origin.clone(), cors_status))
|
.entry((url.clone(), origin.clone(), cors_status))
|
||||||
|
@ -192,10 +189,7 @@ struct CompletedLoad {
|
||||||
|
|
||||||
impl CompletedLoad {
|
impl CompletedLoad {
|
||||||
fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad {
|
fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad {
|
||||||
CompletedLoad {
|
CompletedLoad { image_response, id }
|
||||||
image_response: image_response,
|
|
||||||
id: id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +218,7 @@ impl ImageBytes {
|
||||||
ImageBytes::InProgress(ref mut bytes) => bytes,
|
ImageBytes::InProgress(ref mut bytes) => bytes,
|
||||||
ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
|
ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
|
||||||
};
|
};
|
||||||
mem::replace(own_bytes, vec![])
|
std::mem::take(own_bytes)
|
||||||
};
|
};
|
||||||
let bytes = Arc::new(bytes);
|
let bytes = Arc::new(bytes);
|
||||||
*self = ImageBytes::Complete(bytes.clone());
|
*self = ImageBytes::Complete(bytes.clone());
|
||||||
|
@ -233,8 +227,8 @@ impl ImageBytes {
|
||||||
|
|
||||||
fn as_slice(&self) -> &[u8] {
|
fn as_slice(&self) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
ImageBytes::InProgress(ref bytes) => &bytes,
|
ImageBytes::InProgress(ref bytes) => bytes,
|
||||||
ImageBytes::Complete(ref bytes) => &*bytes,
|
ImageBytes::Complete(ref bytes) => bytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +301,7 @@ impl PendingLoad {
|
||||||
metadata: None,
|
metadata: None,
|
||||||
result: None,
|
result: None,
|
||||||
listeners: vec![],
|
listeners: vec![],
|
||||||
url: url,
|
url,
|
||||||
load_origin,
|
load_origin,
|
||||||
final_url: None,
|
final_url: None,
|
||||||
cors_setting,
|
cors_setting,
|
||||||
|
@ -368,7 +362,7 @@ impl ImageCacheStore {
|
||||||
let completed_load = CompletedLoad::new(image_response.clone(), key);
|
let completed_load = CompletedLoad::new(image_response.clone(), key);
|
||||||
self.completed_loads.insert(
|
self.completed_loads.insert(
|
||||||
(
|
(
|
||||||
pending_load.url.into(),
|
pending_load.url,
|
||||||
pending_load.load_origin,
|
pending_load.load_origin,
|
||||||
pending_load.cors_setting,
|
pending_load.cors_setting,
|
||||||
),
|
),
|
||||||
|
@ -441,7 +435,7 @@ impl ImageCache for ImageCacheImpl {
|
||||||
completed_loads: HashMap::new(),
|
completed_loads: HashMap::new(),
|
||||||
placeholder_image: get_placeholder_image(&webrender_api, &rippy_data),
|
placeholder_image: get_placeholder_image(&webrender_api, &rippy_data),
|
||||||
placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
|
placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
|
||||||
webrender_api: webrender_api,
|
webrender_api,
|
||||||
})),
|
})),
|
||||||
thread_pool: CoreResourceThreadPool::new(thread_count),
|
thread_pool: CoreResourceThreadPool::new(thread_count),
|
||||||
}
|
}
|
||||||
|
@ -501,9 +495,9 @@ impl ImageCache for ImageCacheImpl {
|
||||||
CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
|
CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
|
||||||
(&Some(Ok(_)), _) => {
|
(&Some(Ok(_)), _) => {
|
||||||
debug!("Sync decoding {} ({:?})", url, key);
|
debug!("Sync decoding {} ({:?})", url, key);
|
||||||
decode_bytes_sync(key, &pl.bytes.as_slice(), pl.cors_status)
|
decode_bytes_sync(key, pl.bytes.as_slice(), pl.cors_status)
|
||||||
},
|
},
|
||||||
(&None, &Some(ref meta)) => {
|
(&None, Some(meta)) => {
|
||||||
debug!("Metadata available for {} ({:?})", url, key);
|
debug!("Metadata available for {} ({:?})", url, key);
|
||||||
return ImageCacheResult::Available(
|
return ImageCacheResult::Available(
|
||||||
ImageOrMetadataAvailable::MetadataAvailable(meta.clone()),
|
ImageOrMetadataAvailable::MetadataAvailable(meta.clone()),
|
||||||
|
@ -589,7 +583,7 @@ impl ImageCache for ImageCacheImpl {
|
||||||
fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) {
|
fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) {
|
||||||
match (action, id) {
|
match (action, id) {
|
||||||
(FetchResponseMsg::ProcessRequestBody, _) |
|
(FetchResponseMsg::ProcessRequestBody, _) |
|
||||||
(FetchResponseMsg::ProcessRequestEOF, _) => return,
|
(FetchResponseMsg::ProcessRequestEOF, _) => (),
|
||||||
(FetchResponseMsg::ProcessResponse(response), _) => {
|
(FetchResponseMsg::ProcessResponse(response), _) => {
|
||||||
debug!("Received {:?} for {:?}", response.as_ref().map(|_| ()), id);
|
debug!("Received {:?} for {:?}", response.as_ref().map(|_| ()), id);
|
||||||
let mut store = self.store.lock().unwrap();
|
let mut store = self.store.lock().unwrap();
|
||||||
|
@ -648,7 +642,7 @@ impl ImageCache for ImageCacheImpl {
|
||||||
|
|
||||||
let local_store = self.store.clone();
|
let local_store = self.store.clone();
|
||||||
self.thread_pool.spawn(move || {
|
self.thread_pool.spawn(move || {
|
||||||
let msg = decode_bytes_sync(key, &*bytes, cors_status);
|
let msg = decode_bytes_sync(key, &bytes, cors_status);
|
||||||
debug!("Image decoded");
|
debug!("Image decoded");
|
||||||
local_store.lock().unwrap().handle_decoder(msg);
|
local_store.lock().unwrap().handle_decoder(msg);
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,6 +49,21 @@ pub enum NoSniffFlag {
|
||||||
Off,
|
Off,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for MimeClassifier {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
image_classifier: GroupedClassifier::image_classifer(),
|
||||||
|
audio_video_classifier: GroupedClassifier::audio_video_classifier(),
|
||||||
|
scriptable_classifier: GroupedClassifier::scriptable_classifier(),
|
||||||
|
plaintext_classifier: GroupedClassifier::plaintext_classifier(),
|
||||||
|
archive_classifier: GroupedClassifier::archive_classifier(),
|
||||||
|
binary_or_plaintext: BinaryOrPlaintextClassifier,
|
||||||
|
feeds_classifier: FeedsClassifier,
|
||||||
|
font_classifier: GroupedClassifier::font_classifier(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MimeClassifier {
|
impl MimeClassifier {
|
||||||
//Performs MIME Type Sniffing Algorithm (sections 7 and 8)
|
//Performs MIME Type Sniffing Algorithm (sections 7 and 8)
|
||||||
pub fn classify<'a>(
|
pub fn classify<'a>(
|
||||||
|
@ -164,19 +179,6 @@ impl MimeClassifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> MimeClassifier {
|
|
||||||
MimeClassifier {
|
|
||||||
image_classifier: GroupedClassifier::image_classifer(),
|
|
||||||
audio_video_classifier: GroupedClassifier::audio_video_classifier(),
|
|
||||||
scriptable_classifier: GroupedClassifier::scriptable_classifier(),
|
|
||||||
plaintext_classifier: GroupedClassifier::plaintext_classifier(),
|
|
||||||
archive_classifier: GroupedClassifier::archive_classifier(),
|
|
||||||
binary_or_plaintext: BinaryOrPlaintextClassifier,
|
|
||||||
feeds_classifier: FeedsClassifier,
|
|
||||||
font_classifier: GroupedClassifier::font_classifier(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate(&self) -> Result<(), String> {
|
pub fn validate(&self) -> Result<(), String> {
|
||||||
self.image_classifier.validate()?;
|
self.image_classifier.validate()?;
|
||||||
self.audio_video_classifier.validate()?;
|
self.audio_video_classifier.validate()?;
|
||||||
|
@ -240,13 +242,13 @@ impl MimeClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_media_type(mime: &Mime) -> Option<MediaType> {
|
fn get_media_type(mime: &Mime) -> Option<MediaType> {
|
||||||
if MimeClassifier::is_xml(&mime) {
|
if MimeClassifier::is_xml(mime) {
|
||||||
Some(MediaType::Xml)
|
Some(MediaType::Xml)
|
||||||
} else if MimeClassifier::is_html(&mime) {
|
} else if MimeClassifier::is_html(mime) {
|
||||||
Some(MediaType::Html)
|
Some(MediaType::Html)
|
||||||
} else if MimeClassifier::is_image(&mime) {
|
} else if MimeClassifier::is_image(mime) {
|
||||||
Some(MediaType::Image)
|
Some(MediaType::Image)
|
||||||
} else if MimeClassifier::is_audio_video(&mime) {
|
} else if MimeClassifier::is_audio_video(mime) {
|
||||||
Some(MediaType::AudioVideo)
|
Some(MediaType::AudioVideo)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -256,7 +258,7 @@ impl MimeClassifier {
|
||||||
fn maybe_get_media_type(supplied_type: &Option<Mime>) -> Option<MediaType> {
|
fn maybe_get_media_type(supplied_type: &Option<Mime>) -> Option<MediaType> {
|
||||||
supplied_type
|
supplied_type
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|ref mime| MimeClassifier::get_media_type(mime))
|
.and_then(MimeClassifier::get_media_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +340,7 @@ impl MIMEChecker for ByteMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self) -> Result<(), String> {
|
fn validate(&self) -> Result<(), String> {
|
||||||
if self.pattern.len() == 0 {
|
if self.pattern.is_empty() {
|
||||||
return Err(format!("Zero length pattern for {:?}", self.content_type));
|
return Err(format!("Zero length pattern for {:?}", self.content_type));
|
||||||
}
|
}
|
||||||
if self.pattern.len() != self.mask.len() {
|
if self.pattern.len() != self.mask.len() {
|
||||||
|
@ -436,8 +438,8 @@ impl BinaryOrPlaintextClassifier {
|
||||||
} else if data.iter().any(|&x| {
|
} else if data.iter().any(|&x| {
|
||||||
x <= 0x08u8 ||
|
x <= 0x08u8 ||
|
||||||
x == 0x0Bu8 ||
|
x == 0x0Bu8 ||
|
||||||
(x >= 0x0Eu8 && x <= 0x1Au8) ||
|
(0x0Eu8..=0x1Au8).contains(&x) ||
|
||||||
(x >= 0x1Cu8 && x <= 0x1Fu8)
|
(0x1Cu8..=0x1Fu8).contains(&x)
|
||||||
}) {
|
}) {
|
||||||
mime::APPLICATION_OCTET_STREAM
|
mime::APPLICATION_OCTET_STREAM
|
||||||
} else {
|
} else {
|
||||||
|
@ -618,7 +620,7 @@ impl FeedsClassifier {
|
||||||
// TODO: need max_bytes to prevent inadvertently examining html document
|
// TODO: need max_bytes to prevent inadvertently examining html document
|
||||||
// eg. an html page with a feed example
|
// eg. an html page with a feed example
|
||||||
loop {
|
loop {
|
||||||
if matcher.find(|&x| *x == b'<').is_none() {
|
if !matcher.any(|x| *x == b'<') {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::{self, BufReader};
|
use std::io::{self, BufReader};
|
||||||
use std::ops::Deref;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -160,8 +159,8 @@ fn create_http_states(
|
||||||
ignore_certificate_errors: bool,
|
ignore_certificate_errors: bool,
|
||||||
) -> (Arc<HttpState>, Arc<HttpState>) {
|
) -> (Arc<HttpState>, Arc<HttpState>) {
|
||||||
let mut hsts_list = HstsList::from_servo_preload();
|
let mut hsts_list = HstsList::from_servo_preload();
|
||||||
let mut auth_cache = AuthCache::new();
|
let mut auth_cache = AuthCache::default();
|
||||||
let http_cache = HttpCache::new();
|
let http_cache = HttpCache::default();
|
||||||
let mut cookie_jar = CookieStorage::new(150);
|
let mut cookie_jar = CookieStorage::new(150);
|
||||||
if let Some(config_dir) = config_dir {
|
if let Some(config_dir) = config_dir {
|
||||||
read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json");
|
read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json");
|
||||||
|
@ -189,9 +188,9 @@ fn create_http_states(
|
||||||
let private_http_state = HttpState {
|
let private_http_state = HttpState {
|
||||||
hsts_list: RwLock::new(HstsList::from_servo_preload()),
|
hsts_list: RwLock::new(HstsList::from_servo_preload()),
|
||||||
cookie_jar: RwLock::new(CookieStorage::new(150)),
|
cookie_jar: RwLock::new(CookieStorage::new(150)),
|
||||||
auth_cache: RwLock::new(AuthCache::new()),
|
auth_cache: RwLock::new(AuthCache::default()),
|
||||||
history_states: RwLock::new(HashMap::new()),
|
history_states: RwLock::new(HashMap::new()),
|
||||||
http_cache: RwLock::new(HttpCache::new()),
|
http_cache: RwLock::new(HttpCache::default()),
|
||||||
http_cache_state: Mutex::new(HashMap::new()),
|
http_cache_state: Mutex::new(HashMap::new()),
|
||||||
client: create_http_client(create_tls_config(
|
client: create_http_client(create_tls_config(
|
||||||
ca_certificates,
|
ca_certificates,
|
||||||
|
@ -213,7 +212,7 @@ impl ResourceChannelManager {
|
||||||
memory_reporter: IpcReceiver<ReportsChan>,
|
memory_reporter: IpcReceiver<ReportsChan>,
|
||||||
) {
|
) {
|
||||||
let (public_http_state, private_http_state) = create_http_states(
|
let (public_http_state, private_http_state) = create_http_states(
|
||||||
self.config_dir.as_ref().map(Deref::deref),
|
self.config_dir.as_deref(),
|
||||||
self.ca_certificates.clone(),
|
self.ca_certificates.clone(),
|
||||||
self.ignore_certificate_errors,
|
self.ignore_certificate_errors,
|
||||||
);
|
);
|
||||||
|
@ -426,11 +425,10 @@ pub fn write_json_to_file<T>(data: &T, config_dir: &Path, filename: &str)
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
let json_encoded: String;
|
let json_encoded: String = match serde_json::to_string_pretty(&data) {
|
||||||
match serde_json::to_string_pretty(&data) {
|
Ok(d) => d,
|
||||||
Ok(d) => json_encoded = d,
|
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
}
|
};
|
||||||
let path = config_dir.join(filename);
|
let path = config_dir.join(filename);
|
||||||
let display = path.display();
|
let display = path.display();
|
||||||
|
|
||||||
|
@ -451,9 +449,9 @@ pub struct AuthCacheEntry {
|
||||||
pub password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthCache {
|
impl Default for AuthCache {
|
||||||
pub fn new() -> AuthCache {
|
fn default() -> Self {
|
||||||
AuthCache {
|
Self {
|
||||||
version: 1,
|
version: 1,
|
||||||
entries: HashMap::new(),
|
entries: HashMap::new(),
|
||||||
}
|
}
|
||||||
|
@ -531,7 +529,7 @@ impl CoreResourceThreadPool {
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let state = Arc::new(Mutex::new(ThreadPoolState::new()));
|
let state = Arc::new(Mutex::new(ThreadPoolState::new()));
|
||||||
CoreResourceThreadPool { pool: pool, state }
|
CoreResourceThreadPool { pool, state }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawn work on the thread-pool, if still active.
|
/// Spawn work on the thread-pool, if still active.
|
||||||
|
@ -613,7 +611,7 @@ impl CoreResourceManager {
|
||||||
let pool = CoreResourceThreadPool::new(16);
|
let pool = CoreResourceThreadPool::new(16);
|
||||||
let pool_handle = Arc::new(pool);
|
let pool_handle = Arc::new(pool);
|
||||||
CoreResourceManager {
|
CoreResourceManager {
|
||||||
user_agent: user_agent,
|
user_agent,
|
||||||
devtools_sender,
|
devtools_sender,
|
||||||
sw_managers: Default::default(),
|
sw_managers: Default::default(),
|
||||||
filemanager: FileManager::new(embedder_proxy, Arc::downgrade(&pool_handle)),
|
filemanager: FileManager::new(embedder_proxy, Arc::downgrade(&pool_handle)),
|
||||||
|
@ -708,7 +706,7 @@ impl CoreResourceManager {
|
||||||
let response = Response::from_init(res_init, timing_type);
|
let response = Response::from_init(res_init, timing_type);
|
||||||
http_redirect_fetch(
|
http_redirect_fetch(
|
||||||
&mut request,
|
&mut request,
|
||||||
&mut CorsCache::new(),
|
&mut CorsCache::default(),
|
||||||
response,
|
response,
|
||||||
true,
|
true,
|
||||||
&mut sender,
|
&mut sender,
|
||||||
|
|
|
@ -47,10 +47,10 @@ impl StorageManager {
|
||||||
resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json");
|
resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json");
|
||||||
}
|
}
|
||||||
StorageManager {
|
StorageManager {
|
||||||
port: port,
|
port,
|
||||||
session_data: HashMap::new(),
|
session_data: HashMap::new(),
|
||||||
local_data: local_data,
|
local_data,
|
||||||
config_dir: config_dir,
|
config_dir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ impl StorageManager {
|
||||||
let origin = self.origin_as_string(url);
|
let origin = self.origin_as_string(url);
|
||||||
let data = self.select_data(storage_type);
|
let data = self.select_data(storage_type);
|
||||||
sender
|
sender
|
||||||
.send(data.get(&origin).map_or(0, |&(_, ref entry)| entry.len()))
|
.send(data.get(&origin).map_or(0, |(_, entry)| entry.len()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ impl StorageManager {
|
||||||
let data = self.select_data(storage_type);
|
let data = self.select_data(storage_type);
|
||||||
let key = data
|
let key = data
|
||||||
.get(&origin)
|
.get(&origin)
|
||||||
.and_then(|&(_, ref entry)| entry.keys().nth(index as usize))
|
.and_then(|(_, entry)| entry.keys().nth(index as usize))
|
||||||
.cloned();
|
.cloned();
|
||||||
sender.send(key).unwrap();
|
sender.send(key).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ impl StorageManager {
|
||||||
let data = self.select_data(storage_type);
|
let data = self.select_data(storage_type);
|
||||||
let keys = data
|
let keys = data
|
||||||
.get(&origin)
|
.get(&origin)
|
||||||
.map_or(vec![], |&(_, ref entry)| entry.keys().cloned().collect());
|
.map_or(vec![], |(_, entry)| entry.keys().cloned().collect());
|
||||||
|
|
||||||
sender.send(keys).unwrap();
|
sender.send(keys).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ impl StorageManager {
|
||||||
sender
|
sender
|
||||||
.send(
|
.send(
|
||||||
data.get(&origin)
|
data.get(&origin)
|
||||||
.and_then(|&(_, ref entry)| entry.get(&name))
|
.and_then(|(_, entry)| entry.get(&name))
|
||||||
.map(String::clone),
|
.map(String::clone),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -244,9 +244,9 @@ impl StorageManager {
|
||||||
let old_value = data
|
let old_value = data
|
||||||
.get_mut(&origin)
|
.get_mut(&origin)
|
||||||
.and_then(|&mut (ref mut total, ref mut entry)| {
|
.and_then(|&mut (ref mut total, ref mut entry)| {
|
||||||
entry.remove(&name).and_then(|old| {
|
entry.remove(&name).map(|old| {
|
||||||
*total -= name.as_bytes().len() + old.as_bytes().len();
|
*total -= name.as_bytes().len() + old.as_bytes().len();
|
||||||
Some(old)
|
old
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
sender.send(old_value).unwrap();
|
sender.send(old_value).unwrap();
|
||||||
|
|
|
@ -11,7 +11,7 @@ use generic_array::ArrayLength;
|
||||||
use net_traits::response::{Response, ResponseBody, ResponseType};
|
use net_traits::response::{Response, ResponseBody, ResponseType};
|
||||||
use sha2::{Digest, Sha256, Sha384, Sha512};
|
use sha2::{Digest, Sha256, Sha384, Sha512};
|
||||||
|
|
||||||
const SUPPORTED_ALGORITHM: &'static [&'static str] = &["sha256", "sha384", "sha512"];
|
const SUPPORTED_ALGORITHM: &[&str] = &["sha256", "sha384", "sha512"];
|
||||||
pub type StaticCharVec = &'static [char];
|
pub type StaticCharVec = &'static [char];
|
||||||
/// A "space character" according to:
|
/// A "space character" according to:
|
||||||
///
|
///
|
||||||
|
@ -33,7 +33,7 @@ impl SriEntry {
|
||||||
SriEntry {
|
SriEntry {
|
||||||
alg: alg.to_owned(),
|
alg: alg.to_owned(),
|
||||||
val: val.to_owned(),
|
val: val.to_owned(),
|
||||||
opt: opt,
|
opt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ pub fn parsed_metadata(integrity_metadata: &str) -> Vec<SriEntry> {
|
||||||
// Step 3
|
// Step 3
|
||||||
let tokens = split_html_space_chars(integrity_metadata);
|
let tokens = split_html_space_chars(integrity_metadata);
|
||||||
for token in tokens {
|
for token in tokens {
|
||||||
let parsed_data: Vec<&str> = token.split("-").collect();
|
let parsed_data: Vec<&str> = token.split('-').collect();
|
||||||
|
|
||||||
if parsed_data.len() > 1 {
|
if parsed_data.len() > 1 {
|
||||||
let alg = parsed_data[0];
|
let alg = parsed_data[0];
|
||||||
|
@ -55,7 +55,7 @@ pub fn parsed_metadata(integrity_metadata: &str) -> Vec<SriEntry> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: Vec<&str> = parsed_data[1].split("?").collect();
|
let data: Vec<&str> = parsed_data[1].split('?').collect();
|
||||||
let digest = data[0];
|
let digest = data[0];
|
||||||
|
|
||||||
let opt = if data.len() > 1 {
|
let opt = if data.len() > 1 {
|
||||||
|
@ -68,7 +68,7 @@ pub fn parsed_metadata(integrity_metadata: &str) -> Vec<SriEntry> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://w3c.github.io/webappsec-subresource-integrity/#getprioritizedhashfunction>
|
/// <https://w3c.github.io/webappsec-subresource-integrity/#getprioritizedhashfunction>
|
||||||
|
@ -78,11 +78,11 @@ pub fn get_prioritized_hash_function(
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let left_priority = SUPPORTED_ALGORITHM
|
let left_priority = SUPPORTED_ALGORITHM
|
||||||
.iter()
|
.iter()
|
||||||
.position(|s| s.to_owned() == hash_func_left)
|
.position(|s| *s == hash_func_left)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let right_priority = SUPPORTED_ALGORITHM
|
let right_priority = SUPPORTED_ALGORITHM
|
||||||
.iter()
|
.iter()
|
||||||
.position(|s| s.to_owned() == hash_func_right)
|
.position(|s| *s == hash_func_right)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if left_priority == right_priority {
|
if left_priority == right_priority {
|
||||||
|
@ -102,7 +102,7 @@ pub fn get_strongest_metadata(integrity_metadata_list: Vec<SriEntry>) -> Vec<Sri
|
||||||
|
|
||||||
for integrity_metadata in &integrity_metadata_list[1..] {
|
for integrity_metadata in &integrity_metadata_list[1..] {
|
||||||
let prioritized_hash =
|
let prioritized_hash =
|
||||||
get_prioritized_hash_function(&integrity_metadata.alg, &*current_algorithm);
|
get_prioritized_hash_function(&integrity_metadata.alg, ¤t_algorithm);
|
||||||
if prioritized_hash.is_none() {
|
if prioritized_hash.is_none() {
|
||||||
result.push(integrity_metadata.clone());
|
result.push(integrity_metadata.clone());
|
||||||
} else if let Some(algorithm) = prioritized_hash {
|
} else if let Some(algorithm) = prioritized_hash {
|
||||||
|
@ -174,9 +174,7 @@ pub fn is_response_integrity_valid(integrity_metadata: &str, response: &Response
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_html_space_chars<'a>(
|
pub fn split_html_space_chars(s: &str) -> Filter<Split<'_, StaticCharVec>, fn(&&str) -> bool> {
|
||||||
s: &'a str,
|
|
||||||
) -> Filter<Split<'a, StaticCharVec>, fn(&&str) -> bool> {
|
|
||||||
fn not_empty(&split: &&str) -> bool {
|
fn not_empty(&split: &&str) -> bool {
|
||||||
!split.is_empty()
|
!split.is_empty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -385,7 +385,7 @@ fn test_cors_preflight_cache_fetch() {
|
||||||
static ACK: &'static [u8] = b"ACK";
|
static ACK: &'static [u8] = b"ACK";
|
||||||
let state = Arc::new(AtomicUsize::new(0));
|
let state = Arc::new(AtomicUsize::new(0));
|
||||||
let counter = state.clone();
|
let counter = state.clone();
|
||||||
let mut cache = CorsCache::new();
|
let mut cache = CorsCache::default();
|
||||||
let handler = move |request: HyperRequest<Body>, response: &mut HyperResponse<Body>| {
|
let handler = move |request: HyperRequest<Body>, response: &mut HyperResponse<Body>| {
|
||||||
if request.method() == Method::OPTIONS && state.clone().fetch_add(1, Ordering::SeqCst) == 0
|
if request.method() == Method::OPTIONS && state.clone().fetch_add(1, Ordering::SeqCst) == 0
|
||||||
{
|
{
|
||||||
|
@ -757,7 +757,7 @@ fn test_fetch_with_hsts() {
|
||||||
let (server, url) = make_ssl_server(handler);
|
let (server, url) = make_ssl_server(handler);
|
||||||
|
|
||||||
let mut context = FetchContext {
|
let mut context = FetchContext {
|
||||||
state: Arc::new(HttpState::new()),
|
state: Arc::new(HttpState::default()),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: None,
|
devtools_chan: None,
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
|
@ -816,7 +816,7 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() {
|
||||||
url.as_mut_url().set_scheme("https").unwrap();
|
url.as_mut_url().set_scheme("https").unwrap();
|
||||||
|
|
||||||
let mut context = FetchContext {
|
let mut context = FetchContext {
|
||||||
state: Arc::new(HttpState::new()),
|
state: Arc::new(HttpState::default()),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: None,
|
devtools_chan: None,
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
|
@ -873,7 +873,7 @@ fn test_fetch_self_signed() {
|
||||||
url.as_mut_url().set_scheme("https").unwrap();
|
url.as_mut_url().set_scheme("https").unwrap();
|
||||||
|
|
||||||
let mut context = FetchContext {
|
let mut context = FetchContext {
|
||||||
state: Arc::new(HttpState::new()),
|
state: Arc::new(HttpState::default()),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: None,
|
devtools_chan: None,
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
|
|
|
@ -33,7 +33,7 @@ fn test_refreshing_resource_sets_done_chan_the_appropriate_value() {
|
||||||
response
|
response
|
||||||
.headers
|
.headers
|
||||||
.insert(EXPIRES, HeaderValue::from_str("-10").unwrap());
|
.insert(EXPIRES, HeaderValue::from_str("-10").unwrap());
|
||||||
let mut cache = HttpCache::new();
|
let mut cache = HttpCache::default();
|
||||||
response_bodies.iter().for_each(|body| {
|
response_bodies.iter().for_each(|body| {
|
||||||
*response.body.lock().unwrap() = body.clone();
|
*response.body.lock().unwrap() = body.clone();
|
||||||
// First, store the 'normal' response.
|
// First, store the 'normal' response.
|
||||||
|
|
|
@ -103,7 +103,7 @@ fn new_fetch_context(
|
||||||
let sender = fc.unwrap_or_else(|| create_embedder_proxy());
|
let sender = fc.unwrap_or_else(|| create_embedder_proxy());
|
||||||
|
|
||||||
FetchContext {
|
FetchContext {
|
||||||
state: Arc::new(HttpState::new()),
|
state: Arc::new(HttpState::default()),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
|
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
|
|
|
@ -53,7 +53,7 @@ fn test_sniff_mp4_matcher_long() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validate_classifier() {
|
fn test_validate_classifier() {
|
||||||
let classifier = MimeClassifier::new();
|
let classifier = MimeClassifier::default();
|
||||||
classifier.validate().expect("Validation error")
|
classifier.validate().expect("Validation error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ fn test_sniff_with_flags(
|
||||||
let mut filename = PathBuf::from("tests/parsable_mime/");
|
let mut filename = PathBuf::from("tests/parsable_mime/");
|
||||||
filename.push(filename_orig);
|
filename.push(filename_orig);
|
||||||
|
|
||||||
let classifier = MimeClassifier::new();
|
let classifier = MimeClassifier::default();
|
||||||
|
|
||||||
let read_result = read_file(&filename);
|
let read_result = read_file(&filename);
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ fn create_request(
|
||||||
}
|
}
|
||||||
|
|
||||||
if resource_url.password().is_some() || resource_url.username() != "" {
|
if resource_url.password().is_some() || resource_url.username() != "" {
|
||||||
let basic = base64::engine::general_purpose::STANDARD.encode(&format!(
|
let basic = base64::engine::general_purpose::STANDARD.encode(format!(
|
||||||
"{}:{}",
|
"{}:{}",
|
||||||
resource_url.username(),
|
resource_url.username(),
|
||||||
resource_url.password().unwrap_or("")
|
resource_url.password().unwrap_or("")
|
||||||
|
@ -147,7 +147,7 @@ fn process_ws_response(
|
||||||
.hsts_list
|
.hsts_list
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.update_hsts_list_from_response(resource_url, &response.headers());
|
.update_hsts_list_from_response(resource_url, response.headers());
|
||||||
|
|
||||||
Ok(protocol_in_use)
|
Ok(protocol_in_use)
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ fn connect(
|
||||||
&req_url,
|
&req_url,
|
||||||
&req_builder.origin.ascii_serialization(),
|
&req_builder.origin.ascii_serialization(),
|
||||||
&protocols,
|
&protocols,
|
||||||
&*http_state,
|
&http_state,
|
||||||
) {
|
) {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue