diff --git a/src/context/context.rs b/src/context/context.rs index 607653c8816cc68faf7e46c6871ee79c854afebb..7c794f5281cbb5b2850c8aa3865d77db810d51a1 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -133,20 +133,6 @@ impl Context { .iter().rposition(|&b| b == b'/' || b == b':') .map_or(cwd.len(), |i| i + 1)] .to_vec() - } else if path.starts_with(b"./") { - let mut canon = cwd.clone(); - if ! canon.ends_with(b"/") { - canon.push(b'/'); - } - canon.extend_from_slice(&path[2..]); - canon - } else if path.starts_with(b"../") { - let mut canon = cwd[..cwd[..cwd.len() - 1] - .iter().rposition(|&b| b == b'/' || b == b':') - .map_or(cwd.len(), |i| i + 1)] - .to_vec(); - canon.extend_from_slice(&path[3..]); - canon } else if path.starts_with(b"/") { let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec(); canon.extend_from_slice(&path); @@ -157,8 +143,35 @@ impl Context { canon.push(b'/'); } canon.extend_from_slice(&path); - canon - } + // NOTE: assumes the scheme does not include anything like "../" or "./" + let rparts = canon.split(|&c| c == b'/') + .filter(|&part| part != b".") + .rev() + .scan(0, |nskip, part| { + if part == b".." { + *nskip += 1; + Some(None) + } else { + if *nskip > 0 { + *nskip -= 1; + Some(None) + } else { + Some(Some(part)) + } + } + }) + .filter_map(|x| x) + .collect::<Vec<_>>(); + let mut result = rparts + .iter() + .rev() + .fold(Vec::new(), |mut vec, &part| { + vec.extend_from_slice(part); + vec.push(b'/'); + vec + }); + result.pop(); // remove extra '/' + result } else { path.to_vec() }