request.rs (9862B)
1 use std::path::Path; 2 use std::str::FromStr; 3 use tiny_http::{ 4 Method, 5 // Response, 6 // Request, 7 // StatusCode, 8 }; 9 use crate::record::{ 10 put_immutable, 11 put_mutable, 12 get as get_record, 13 ResourceKey, 14 RequestResult, 15 RequestResultType, 16 }; 17 use crate::auth::{ 18 AuthResult, 19 }; 20 use std::io::Read; 21 22 #[cfg(feature = "meta")] 23 use crate::meta::{ 24 get_type as get_meta_type, 25 get_filename as get_meta_filename, 26 }; 27 28 use log::{ 29 debug, 30 error, 31 }; 32 33 /// Handle client input by method type. 34 /// 35 /// # Arguments 36 /// 37 /// * `method` - The HTTP method of the client request. 38 /// * `url` - The local part of the URL of the client request. 39 /// * `f` - Reader providing the content body of a client PUT request. 40 /// * `expected_size` - Size hint for content body. 41 /// * `path` - Absolute path to storage directory. 42 /// * `auth_result` - Result of authentication (if any) the client has provided with the request. 43 //pub fn process_method(method: &Method, url: String, mut f: impl Read, expected_size: usize, path: &Path, auth_result: AuthResult) -> RequestResult { 44 pub fn process_method(method: &Method, url: String, f: impl Read, expected_size: usize, path: &Path, auth_result: AuthResult) -> RequestResult { 45 match method { 46 Method::Put => { 47 if !auth_result.valid() { 48 return RequestResult::new(RequestResultType::AuthError); 49 } 50 if auth_result.active() { 51 let mut res: RequestResult; 52 let rk = ResourceKey::from_str(url.as_str()).unwrap(); 53 debug!("mutable put, authenticated as {:?} using mutable key {} -> {}", auth_result, &url, &rk); 54 //let ptr = rk.pointer_for(&auth_result); 55 match put_mutable(path, f, expected_size, &rk, &auth_result) { 56 Ok(v) => { 57 let digest_hex = hex::encode(v.digest); 58 let alias_hex = hex::encode(v.alias.unwrap()); 59 res = RequestResult::new(RequestResultType::Changed); 60 res = res.with_content(digest_hex); 61 res = res.with_auth(auth_result); 62 res = res.with_aliased(alias_hex); 63 }, 64 Err(e) => { 65 let err_str = format!("{:?}", e); 66 error!("{}", err_str); 67 res = RequestResult::new(RequestResultType::RecordError); 68 res = res.with_content(String::from(err_str)); 69 }, 70 }; 71 return res; 72 } else { 73 debug!("immutable put"); 74 let mut res: RequestResult; 75 match put_immutable(path, f, expected_size) { 76 Ok(v) => { 77 let digest_hex = hex::encode(v.digest); 78 res = RequestResult::new(RequestResultType::Changed); 79 res = res.with_content(digest_hex); 80 }, 81 Err(e) => { 82 let err_str = format!("{}", e); 83 res = RequestResult::new(RequestResultType::RecordError); 84 res = res.with_content(String::from(err_str)); 85 }, 86 }; 87 return res; 88 } 89 }, 90 Method::Get => { 91 if &url == "" { 92 let mut res = RequestResult::new(RequestResultType::Found); 93 res = res.with_content(String::new()); 94 return res; 95 } 96 let digest = match hex::decode(&url) { 97 Err(e) => { 98 let err_str = format!("{}", e); 99 let mut res = RequestResult::new(RequestResultType::InputError); 100 res = res.with_content(String::from(err_str)); 101 return res; 102 }, 103 Ok(v) => { 104 v 105 }, 106 }; 107 108 let full_path_buf = path.join(&url); 109 debug!("url {} resolved to {:?}", &url, &full_path_buf); 110 111 match get_record(digest.clone(), full_path_buf.as_path()) { 112 Some(v) => { 113 let mut res = RequestResult::new(RequestResultType::Found); 114 res = res.with_file(v); 115 116 #[cfg(feature = "meta")] 117 { 118 res.m = get_meta_type(path, &digest); 119 res.n = get_meta_filename(path, &digest); 120 } 121 return res; 122 }, 123 None => { 124 return RequestResult::new(RequestResultType::RecordError); 125 }, 126 }; 127 }, 128 Method::Head => { 129 if &url == "" { 130 let mut res = RequestResult::new(RequestResultType::RecordError); 131 res = res.with_content(String::new()); 132 return res; 133 } 134 let digest = match hex::decode(&url) { 135 Err(e) => { 136 let err_str = format!("{}", e); 137 let mut res = RequestResult::new(RequestResultType::InputError); 138 res = res.with_content(String::from(err_str)); 139 return res; 140 }, 141 Ok(v) => { 142 v 143 }, 144 }; 145 146 let full_path_buf = path.join(&url); 147 debug!("url {} resolved to {:?}", &url, &full_path_buf); 148 let mut res = RequestResult::new(RequestResultType::Found); 149 match full_path_buf.metadata() { 150 Ok(m) => { 151 res = res.with_length(m.len()); 152 #[cfg(feature = "meta")] 153 { 154 res.m = get_meta_type(path, &digest); 155 res.n = get_meta_filename(path, &digest); 156 } 157 }, 158 Err(_) => { 159 res = RequestResult::new(RequestResultType::ReadError); 160 }, 161 } 162 return res; 163 }, 164 _ => {}, 165 }; 166 RequestResult::new(RequestResultType::InputError) 167 } 168 169 #[cfg(test)] 170 mod tests { 171 use tempfile::tempdir; 172 use tiny_http::Method; 173 use super::process_method; 174 use std::fs::{ 175 read, 176 write, 177 File, 178 }; 179 use std::path::Path; 180 use crate::auth::AuthResult; 181 use crate::record::RequestResultType; 182 use env_logger; 183 184 185 #[test] 186 fn test_get_ok() { 187 let d = tempdir().unwrap(); 188 let url = String::from("deadbeef"); 189 let data = "foobar"; 190 191 let fp = d.path().join(&url); //.as_path().to_string().unwrap(); 192 write(&fp, data); 193 let f = File::open(&fp).unwrap(); 194 195 let method = Method::Get; 196 197 let auth = AuthResult { 198 identity: vec!(), 199 error: false, 200 }; 201 202 let res = process_method(&method, url, f, 6, &d.path(), auth); 203 assert_eq!(res.typ, RequestResultType::Found); 204 } 205 206 #[test] 207 fn test_get_bogus() { 208 let d = tempdir().unwrap(); 209 let url = String::from("teadbeef"); 210 let data = "foobar"; 211 212 let fp = d.path().join(&url); //.as_path().to_string().unwrap(); 213 write(&fp, data); 214 let f = File::open(&fp).unwrap(); 215 216 let method = Method::Get; 217 218 let auth = AuthResult { 219 identity: vec!(), 220 error: false, 221 }; 222 223 let res = process_method(&method, url, f, 6, &d.path(), auth); 224 assert_eq!(res.typ, RequestResultType::InputError); 225 } 226 227 #[test] 228 fn test_put_immutable() { 229 let d = tempdir().unwrap(); 230 let mut url = String::from("deadbeef"); 231 let data = "foobar"; 232 233 let fp = d.path().join(&url); //.as_path().to_string().unwrap(); 234 write(&fp, data); 235 let f = File::open(&fp).unwrap(); 236 237 let method = Method::Put; 238 239 let auth = AuthResult { 240 identity: vec!(), 241 error: false, 242 }; 243 244 url = String::new(); 245 let res = process_method(&method, url, f, 6, &d.path(), auth); 246 assert_eq!(res.typ, RequestResultType::Changed); 247 248 let content_ref = String::from("c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"); 249 assert_eq!(res.v.unwrap(), content_ref); 250 251 } 252 253 #[test] 254 fn test_put_mutable() { 255 let d = tempdir().unwrap(); 256 let url = String::from("deadbeef"); 257 let data = "foobar"; 258 259 let fp = d.path().join(&url); //.as_path().to_string().unwrap(); 260 write(&fp, data); 261 let f = File::open(&fp).unwrap(); 262 263 let method = Method::Put; 264 265 let auth = AuthResult { 266 identity: vec!(0x66, 0x6f, 0x6f), 267 error: false, 268 }; 269 270 let res = process_method(&method, url, f, 6, &d.path(), auth); 271 assert_eq!(res.typ, RequestResultType::Changed); 272 273 let content_ref = String::from("129208a8eac1bedd060645411baaae4aabc5d9e4c858942defe139b5ba15aba6"); 274 assert_eq!(res.v.unwrap(), content_ref); 275 276 let fp_immutable = d.path().join(&content_ref); 277 let r = read(fp_immutable).unwrap(); 278 279 assert_eq!(data.as_bytes(), r); 280 } 281 282 #[test] 283 fn test_put_mutable_noauth() { 284 let d = tempdir().unwrap(); 285 let url = String::from("deadbeef"); 286 let data = "foobar"; 287 288 let fp = d.path().join(&url); //.as_path().to_string().unwrap(); 289 write(&fp, data); 290 let f = File::open(&fp).unwrap(); 291 292 let method = Method::Put; 293 294 let auth = AuthResult { 295 identity: vec!(0x2a), 296 error: true, 297 }; 298 299 let res = process_method(&method, url, f, 6, &d.path(), auth); 300 assert_eq!(res.typ, RequestResultType::AuthError); 301 } 302 }