Skip to content

Commit 8cb38f3

Browse files
committed
servo: Merge #10661 - write cookie_jar, hsts_list, auth_cache to file if profile_dir option is present (from DDEFISHER:master); r=jdm
For Persistent sessions student project "if the profile directory command-line option is present when the ResourceThread is instructed to exit, serialize the data contained in cookie_storage, hsts_list, and the new HTTP authorization cache, and write the serialized data in separate files inside the profile directory." and "perform the same serialization on shutdown for local_data in storage_thread.rs, which represents the LocalStorage API." Source-Repo: https://github.com/servo/servo Source-Revision: 75d99eec0ff02718f1ec8d1b6fd58fff7c2d6fb3 UltraBlame original commit: 05236dcfca50666486bf1db3a2d6023bcda84a5e
1 parent 8344010 commit 8cb38f3

File tree

6 files changed

+150
-13
lines changed

6 files changed

+150
-13
lines changed

servo/components/net/cookie.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use cookie_rs;
99
use net_traits::CookieSource;
1010
use pub_domains::PUB_DOMAINS;
11+
use rustc_serialize::{Encodable, Encoder};
1112
use std::borrow::ToOwned;
1213
use std::net::{Ipv4Addr, Ipv6Addr};
1314
use time::{Tm, now, at, Duration};
@@ -175,3 +176,65 @@ impl Cookie {
175176
true
176177
}
177178
}
179+
180+
impl Encodable for Cookie {
181+
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
182+
s.emit_struct("Cookie", 6, |e| {
183+
try!(e.emit_struct_field("cookie", 0, |e| RsCookie(self.cookie.clone()).encode(e)));
184+
try!(e.emit_struct_field("host_only", 1, |e| self.host_only.encode(e)));
185+
try!(e.emit_struct_field("persistent", 2, |e| self.persistent.encode(e)));
186+
try!(e.emit_struct_field("creation_time", 3, |e| Time(self.creation_time).encode(e)));
187+
try!(e.emit_struct_field("last_access", 4, |e| Time(self.last_access).encode(e)));
188+
match self.expiry_time {
189+
Some(time) => try!(e.emit_struct_field("expiry_time", 5, |e| Time(time).encode(e))),
190+
None => {},
191+
}
192+
Ok(())
193+
})
194+
}
195+
}
196+
197+
struct Time(Tm);
198+
199+
impl Encodable for Time {
200+
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
201+
let Time(time) = *self;
202+
s.emit_struct("Time", 11, |e| {
203+
try!(e.emit_struct_field("tm_sec", 0, |e| time.tm_sec.encode(e)));
204+
try!(e.emit_struct_field("tm_min", 1, |e| time.tm_min.encode(e)));
205+
try!(e.emit_struct_field("tm_hour", 2, |e| time.tm_hour.encode(e)));
206+
try!(e.emit_struct_field("tm_mday", 3, |e| time.tm_mday.encode(e)));
207+
try!(e.emit_struct_field("tm_mon", 4, |e| time.tm_mon.encode(e)));
208+
try!(e.emit_struct_field("tm_year", 5, |e| time.tm_year.encode(e)));
209+
try!(e.emit_struct_field("tm_wday", 6, |e| time.tm_wday.encode(e)));
210+
try!(e.emit_struct_field("tm_yday", 7, |e| time.tm_yday.encode(e)));
211+
try!(e.emit_struct_field("tm_isdst", 8, |e| time.tm_isdst.encode(e)));
212+
try!(e.emit_struct_field("tm_utcoff", 9, |e| time.tm_utcoff.encode(e)));
213+
try!(e.emit_struct_field("tm_nsec", 10, |e| time.tm_nsec.encode(e)));
214+
Ok(())
215+
})
216+
}
217+
}
218+
219+
struct RsCookie(cookie_rs::Cookie);
220+
221+
impl Encodable for RsCookie {
222+
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
223+
let RsCookie(ref rs_cookie) = *self;
224+
s.emit_struct("RsCookie", 9, |e| {
225+
try!(e.emit_struct_field("name", 0, |e| rs_cookie.name.encode(e)));
226+
try!(e.emit_struct_field("value", 1, |e| rs_cookie.value.encode(e)));
227+
match rs_cookie.expires {
228+
Some(time) => try!(e.emit_struct_field("expires", 2, |e| Time(time).encode(e))),
229+
None => {},
230+
}
231+
try!(e.emit_struct_field("max_age", 3, |e| rs_cookie.max_age.encode(e)));
232+
try!(e.emit_struct_field("domain", 4, |e| rs_cookie.domain.encode(e)));
233+
try!(e.emit_struct_field("path", 5, |e| rs_cookie.path.encode(e)));
234+
try!(e.emit_struct_field("secure", 6, |e| rs_cookie.secure.encode(e)));
235+
try!(e.emit_struct_field("httponly", 7, |e| rs_cookie.httponly.encode(e)));
236+
try!(e.emit_struct_field("custom", 8, |e| rs_cookie.custom.encode(e)));
237+
Ok(())
238+
})
239+
}
240+
}

servo/components/net/cookie_storage.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77

88
use cookie::Cookie;
99
use net_traits::CookieSource;
10+
use rustc_serialize::{Encodable, Encoder};
1011
use std::cmp::Ordering;
1112
use url::Url;
1213

14+
#[derive(RustcEncodable, Clone)]
1315
pub struct CookieStorage {
16+
version: u32,
1417
cookies: Vec<Cookie>
1518
}
1619

1720
impl CookieStorage {
1821
pub fn new() -> CookieStorage {
1922
CookieStorage {
23+
version: 1,
2024
cookies: Vec::new()
2125
}
2226
}

servo/components/net/http_loader.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ use net_traits::{CookieSource, IncludeSubdomains, LoadConsumer, LoadContext, Loa
3131
use net_traits::{Metadata, NetworkError};
3232
use openssl::ssl::error::{SslError, OpensslError};
3333
use openssl::ssl::{SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_VERIFY_PEER, SslContext, SslMethod};
34-
use resource_thread::{CancellationListener, send_error, start_sending_sniffed_opt, AuthCacheEntry};
34+
use resource_thread::{CancellationListener, send_error, start_sending_sniffed_opt, AuthCache, AuthCacheEntry};
3535
use std::borrow::ToOwned;
3636
use std::boxed::FnBox;
37-
use std::collections::{HashMap, HashSet};
37+
use std::collections::HashSet;
3838
use std::error::Error;
3939
use std::io::{self, Read, Write};
4040
use std::sync::mpsc::Sender;
@@ -128,15 +128,15 @@ fn inner_url(url: &Url) -> Url {
128128
pub struct HttpState {
129129
pub hsts_list: Arc<RwLock<HstsList>>,
130130
pub cookie_jar: Arc<RwLock<CookieStorage>>,
131-
pub auth_cache: Arc<RwLock<HashMap<Url, AuthCacheEntry>>>,
131+
pub auth_cache: Arc<RwLock<AuthCache>>,
132132
}
133133

134134
impl HttpState {
135135
pub fn new() -> HttpState {
136136
HttpState {
137137
hsts_list: Arc::new(RwLock::new(HstsList::new())),
138138
cookie_jar: Arc::new(RwLock::new(CookieStorage::new())),
139-
auth_cache: Arc::new(RwLock::new(HashMap::new())),
139+
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
140140
}
141141
}
142142
}
@@ -522,7 +522,7 @@ pub fn modify_request_headers(headers: &mut Headers,
522522
url: &Url,
523523
user_agent: &str,
524524
cookie_jar: &Arc<RwLock<CookieStorage>>,
525-
auth_cache: &Arc<RwLock<HashMap<Url, AuthCacheEntry>>>,
525+
auth_cache: &Arc<RwLock<AuthCache>>,
526526
load_data: &LoadData) {
527527

528528
let host = Host {
@@ -555,13 +555,13 @@ pub fn modify_request_headers(headers: &mut Headers,
555555

556556
fn set_auth_header(headers: &mut Headers,
557557
url: &Url,
558-
auth_cache: &Arc<RwLock<HashMap<Url, AuthCacheEntry>>>) {
558+
auth_cache: &Arc<RwLock<AuthCache>>) {
559559

560560
if !headers.has::<Authorization<Basic>>() {
561561
if let Some(auth) = auth_from_url(url) {
562562
headers.set(auth);
563563
} else {
564-
if let Some(ref auth_entry) = auth_cache.read().unwrap().get(url) {
564+
if let Some(ref auth_entry) = auth_cache.read().unwrap().entries.get(url) {
565565
auth_from_entry(&auth_entry, headers);
566566
}
567567
}
@@ -820,7 +820,7 @@ pub fn load<A, B>(load_data: &LoadData,
820820
password: auth_header.password.to_owned().unwrap(),
821821
};
822822

823-
http_state.auth_cache.write().unwrap().insert(doc_url.clone(), auth_entry);
823+
http_state.auth_cache.write().unwrap().entries.insert(doc_url.clone(), auth_entry);
824824
}
825825
}
826826

servo/components/net/resource_thread.rs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44

55

6-
76
use about_loader;
87
use chrome_loader;
98
use cookie;
@@ -23,13 +22,20 @@ use net_traits::ProgressMsg::Done;
2322
use net_traits::{AsyncResponseTarget, Metadata, ProgressMsg, ResourceThread, ResponseAction};
2423
use net_traits::{ControlMsg, CookieSource, LoadConsumer, LoadData, LoadResponse, ResourceId};
2524
use net_traits::{NetworkError, WebSocketCommunicate, WebSocketConnectData};
25+
use rustc_serialize::Encodable;
26+
use rustc_serialize::json;
2627
use std::borrow::ToOwned;
2728
use std::boxed::FnBox;
2829
use std::cell::Cell;
2930
use std::collections::HashMap;
31+
use std::error::Error;
32+
use std::fs::File;
33+
use std::io::prelude::*;
34+
use std::path::Path;
3035
use std::sync::mpsc::{Receiver, Sender, channel};
3136
use std::sync::{Arc, RwLock};
3237
use url::Url;
38+
use util::opts;
3339
use util::prefs;
3440
use util::thread::spawn_named;
3541
use websocket_loader;
@@ -190,12 +196,54 @@ impl ResourceChannelManager {
190196
ControlMsg::Synchronize(sender) => {
191197
let _ = sender.send(());
192198
}
193-
ControlMsg::Exit => break,
199+
ControlMsg::Exit => {
200+
if let Some(ref profile_dir) = opts::get().profile_dir {
201+
match self.resource_manager.auth_cache.read() {
202+
Ok(auth_cache) => write_json_to_file(&*auth_cache, profile_dir, "auth_cache.json"),
203+
Err(_) => warn!("Error writing auth cache to disk"),
204+
}
205+
match self.resource_manager.cookie_jar.read() {
206+
Ok(jar) => write_json_to_file(&*jar, profile_dir, "cookie_jar.json"),
207+
Err(_) => warn!("Error writing cookie jar to disk"),
208+
}
209+
match self.resource_manager.hsts_list.read() {
210+
Ok(hsts) => write_json_to_file(&*hsts, profile_dir, "hsts_list.json"),
211+
Err(_) => warn!("Error writing hsts list to disk"),
212+
}
213+
}
214+
break;
215+
}
216+
194217
}
195218
}
196219
}
197220
}
198221

222+
pub fn write_json_to_file<T: Encodable>(data: &T, profile_dir: &str, filename: &str) {
223+
let json_encoded: String;
224+
match json::encode(&data) {
225+
Ok(d) => json_encoded = d,
226+
Err(_) => return,
227+
}
228+
let path = Path::new(profile_dir).join(filename);
229+
let display = path.display();
230+
231+
let mut file = match File::create(&path) {
232+
Err(why) => panic!("couldn't create {}: {}",
233+
display,
234+
Error::description(&why)),
235+
Ok(file) => file,
236+
};
237+
238+
match file.write_all(json_encoded.as_bytes()) {
239+
Err(why) => {
240+
panic!("couldn't write to {}: {}", display,
241+
Error::description(&why))
242+
},
243+
Ok(_) => println!("successfully wrote to {}", display),
244+
}
245+
}
246+
199247

200248
pub struct CancellableResource {
201249

@@ -259,15 +307,32 @@ impl Drop for CancellationListener {
259307
}
260308
}
261309

310+
#[derive(RustcDecodable, RustcEncodable, Clone)]
262311
pub struct AuthCacheEntry {
263312
pub user_name: String,
264313
pub password: String,
265314
}
266315

316+
impl AuthCache {
317+
318+
pub fn new() -> AuthCache {
319+
AuthCache {
320+
version: 1,
321+
entries: HashMap::new()
322+
}
323+
}
324+
}
325+
326+
#[derive(RustcDecodable, RustcEncodable, Clone)]
327+
pub struct AuthCache {
328+
pub version: u32,
329+
pub entries: HashMap<Url, AuthCacheEntry>,
330+
}
331+
267332
pub struct ResourceManager {
268333
user_agent: String,
269334
cookie_jar: Arc<RwLock<CookieStorage>>,
270-
auth_cache: Arc<RwLock<HashMap<Url, AuthCacheEntry>>>,
335+
auth_cache: Arc<RwLock<AuthCache>>,
271336
mime_classifier: Arc<MIMEClassifier>,
272337
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
273338
hsts_list: Arc<RwLock<HstsList>>,
@@ -283,7 +348,7 @@ impl ResourceManager {
283348
ResourceManager {
284349
user_agent: user_agent,
285350
cookie_jar: Arc::new(RwLock::new(CookieStorage::new())),
286-
auth_cache: Arc::new(RwLock::new(HashMap::new())),
351+
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
287352
mime_classifier: Arc::new(MIMEClassifier::new()),
288353
devtools_chan: devtools_channel,
289354
hsts_list: Arc::new(RwLock::new(hsts_list)),

servo/components/net/storage_thread.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
66
use net_traits::storage_thread::{StorageThread, StorageThreadMsg, StorageType};
7+
use resource_thread;
78
use std::borrow::ToOwned;
89
use std::collections::BTreeMap;
910
use std::collections::HashMap;
1011
use url::Url;
12+
use util::opts;
1113
use util::thread::spawn_named;
1214

1315
const QUOTA_SIZE_LIMIT: usize = 5 * 1024 * 1024;
@@ -69,6 +71,9 @@ impl StorageManager {
6971
self.clear(sender, url, storage_type)
7072
}
7173
StorageThreadMsg::Exit => {
74+
if let Some(ref profile_dir) = opts::get().profile_dir {
75+
resource_thread::write_json_to_file(&self.local_data, profile_dir, "local_data.json");
76+
}
7277
break
7378
}
7479
}

servo/tests/unit/net/http_loader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1382,7 +1382,7 @@ fn test_if_auth_creds_not_in_url_but_in_cache_it_sets_it() {
13821382
password: "test".to_owned(),
13831383
};
13841384

1385-
http_state.auth_cache.write().unwrap().insert(url.clone(), auth_entry);
1385+
http_state.auth_cache.write().unwrap().entries.insert(url.clone(), auth_entry);
13861386

13871387
let mut load_data = LoadData::new(LoadContext::Browsing, url, None);
13881388
load_data.credentials_flag = true;

0 commit comments

Comments
 (0)