| 
						
						
						
					 | 
					@ -1,5 +1,7 @@ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use std::io::prelude::*; | 
					 | 
					 | 
					use std::io::prelude::*; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					use std::fs::{create_dir_all, File}; | 
					 | 
					 | 
					use std::fs::{symlink_metadata, create_dir_all, remove_file, File}; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					use std::time::SystemTime; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					use std::error::Error; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use rocket::Route; | 
					 | 
					 | 
					use rocket::Route; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use rocket::response::Content; | 
					 | 
					 | 
					use rocket::response::Content; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -44,12 +46,23 @@ fn get_icon (domain: &str) -> Vec<u8> { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        }, | 
					 | 
					 | 
					        }, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Err(e) => { | 
					 | 
					 | 
					        Err(e) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            error!("Error downloading icon: {:?}", e); | 
					 | 
					 | 
					            error!("Error downloading icon: {:?}", e); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            mark_negcache(&path); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            get_fallback_icon() | 
					 | 
					 | 
					            get_fallback_icon() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					fn get_cached_icon(path: &str) -> Option<Vec<u8>> { | 
					 | 
					 | 
					fn get_cached_icon(path: &str) -> Option<Vec<u8>> { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // Check for expiration of negatively cached copy
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    if icon_is_negcached(path) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        return Some(get_fallback_icon()); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // Check for expiration of successfully cached copy
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    if icon_is_expired(path) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        return None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // Try to read the cached icon, and return it if it exists
 | 
					 | 
					 | 
					    // Try to read the cached icon, and return it if it exists
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if let Ok(mut f) = File::open(path) { | 
					 | 
					 | 
					    if let Ok(mut f) = File::open(path) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let mut buffer = Vec::new(); | 
					 | 
					 | 
					        let mut buffer = Vec::new(); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -62,6 +75,47 @@ fn get_cached_icon(path: &str) -> Option<Vec<u8>> { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    None | 
					 | 
					 | 
					    None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					fn file_is_expired(path: &str, ttl: u64) -> Result<bool, Box<Error>> { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    let meta = symlink_metadata(path)?; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    let modified = meta.modified()?; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    let age = SystemTime::now().duration_since(modified)?; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    Ok(ttl > 0 && ttl <= age.as_secs()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					fn icon_is_negcached(path: &str) -> bool { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    let miss_indicator = path.to_owned() + ".miss"; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    let expired = file_is_expired(&miss_indicator, CONFIG.icon_cache_negttl); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    match expired { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        // No longer negatively cached, drop the marker
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        Ok(true) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            match remove_file(&miss_indicator) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                Ok(_) => {}, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                Err(e) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    error!("Could not remove negative cache indicator for icon {:?}: {:?}", path, e); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            false | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        }, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        // The marker hasn't expired yet.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        Ok(false) => { true } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        // The marker is missing or inaccessible in some way.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        Err(_) => { false } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					fn mark_negcache(path: &str) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    let miss_indicator = path.to_owned() + ".miss"; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    File::create(&miss_indicator).expect("Error creating negative cache marker"); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					fn icon_is_expired(path: &str) -> bool { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    let expired = file_is_expired(path, CONFIG.icon_cache_ttl); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    expired.unwrap_or(true) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					fn get_icon_url(domain: &str) -> String { | 
					 | 
					 | 
					fn get_icon_url(domain: &str) -> String { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if CONFIG.local_icon_extractor { | 
					 | 
					 | 
					    if CONFIG.local_icon_extractor { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        format!("http://{}/favicon.ico", domain) | 
					 | 
					 | 
					        format!("http://{}/favicon.ico", domain) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					
  |