wala-rust

Content-adressed HTTP file server
Info | Log | Files | Refs | README | LICENSE

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 }