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()
         }