diff --git a/uri.scm b/uri.scm index 57c9ef9..4aa7a17 100644 --- a/uri.scm +++ b/uri.scm @@ -103,7 +103,7 @@ ; length of the ; unescaped ; string - (ns (make-string nlen))) ; the result + (ns (make-string nlen))) ; stores the result (let lp ((i start) (j 0)) ; sweap over the string (if (< j nlen) @@ -258,33 +258,35 @@ (join-strings plist "/")) ; Insert slashes between elts of PLIST. -;;; Remove . and foo/.. elts from path. After simplification, there are no -;;; . elements, and the only .. elements occur at the beginning of the path -;;; (i.e., they attempt to back up past root). One could argue that this is -;;; illegal, and we should error out in this case, reporting an unresolvable -;;; URL. The URI "spec" is not even slightly clear on this issue. -;;; -;;; URI's are pathetic. The case of /a/b//../c is ambiguous. Do we -;;; 1) not simplify across multi-slashes? -;;; 2) Flush the "empty" dir, giving /a/b//c -;;; 3) Flush across multi-slashes, giving /a/c -;;; What is the meaning of //../a ? /../b ? /../../c ? +;;; Remove . and /.. elements from path. The result is a +;;; (maybe empty) list representing a path that does not contain "." +;;; and ".." elements neither at the beginning nor somewhere else. I +;;; tried to follow RFC2396 here. The procedure returns #f if the path +;;; tries to back up past root (like "//.." or "/foo/../.."). "//" may +;;; occur somewhere in the path but not being backed up. Usually, +;;; relative paths are intended to be used with a base +;;; url. Accordingly to RFC2396 (as I hope) relative paths are +;;; considered not to start with "/". They are appended to a base +;;; URL-path and then simplified. So before you start to simplify a +;;; URL try to find out if it is a relative path (i.e. it does not +;;; start with a "/"). -(define (simplify-uri-path p) ; P must be non-null. - (reverse (let lp ((path-list p) - (ans '())) - (let ((elt (car path-list)) - (path-list (cdr path-list))) - (? ((pair? path-list) - (? ((string=? "." elt) ; Kill . - (lp path-list ans)) - ((string=? ".." elt) - (if (pair? ans) - (lp path-list (cddr ans)) - (lp path-list (cons elt ans)))) - (else - (lp path-list (cons elt ans))))) - ;; Last element of list. - ((string=? ".." elt) - (if (null? ans) '("..") (cddr ans))) - (else (cons elt ans))))))) +(define (simplify-uri-path p) + (if (null? p) #f ; P must be non-null + (let lp ((path-list (cdr p)) + (stack (list (car p)))) + (if (null? path-list) ; we're done + (reverse stack) + (cond + ((string=? (car path-list) "..") ; back up + ; neither the empty path nor root + (if (not (or (null? stack) (string=? (car stack) ""))) + (lp (cdr path-list) (cdr stack)) + #f)) + ((string=? (car path-list) ".") ; leave this + (lp (cdr path-list) stack)) + ((string=? (car path-list) "") ; back to root + (lp (cdr path-list) '(""))) + (else ; usual segment + (lp (cdr path-list) (cons (car path-list) stack)))))))) +