Coverage report: /home/ellis/comp/core/lib/obj/uri/path.lisp
Kind | Covered | All | % |
expression | 0 | 510 | 0.0 |
branch | 0 | 120 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; obj/uri/path.lisp --- URI Path merging functions
7
;; merging and unmerging
8
(defmethod merge-uris ((uri string) (base string) &optional place)
9
(merge-uris (parse-uri uri) (parse-uri base) place))
11
(defmethod merge-uris ((uri uri) (base string) &optional place)
12
(merge-uris uri (parse-uri base) place))
14
(defmethod merge-uris ((uri string) (base uri) &optional place)
15
(merge-uris (parse-uri uri) base place))
17
(defmethod merge-uris ((uri uri) (base uri) &optional place)
18
;; When PLACE is nil, this function returns a new URI.
19
;; When PLACE is non-nil, it is return.
21
(when (and (null (uri-path uri))
22
(null (uri-scheme uri))
24
(null (uri-userinfo uri))
26
(null (uri-query uri)))
27
(return-from merge-uris
28
(let ((new (copy-uri base :place place)))
30
(setf (uri-query new) (uri-query uri)))
31
(when (uri-fragment uri)
32
(setf (uri-fragment new) (uri-fragment uri)))
35
(setq uri (copy-uri uri :place place))
37
(when (uri-scheme uri) (go :done))
39
(setf (uri-scheme uri) (uri-scheme base))
41
;; if URI has a host, we're done
42
(when (uri-host uri) (go :done))
48
(setf (uri-userinfo uri) (uri-userinfo base))
49
(setf (uri-port uri) (uri-port base))
51
(let ((p (uri-parsed-path uri)))
53
(setf (uri-path uri) (uri-path base))
56
(when (and p (eq :absolute (car p)))
57
(if* (equal '(:absolute "") p)
58
then ;; Canonicalize the way parsing does:
59
(setf (uri-path uri) nil)
60
elseif (eq :absolute (first p))
61
then ;; this also sets uri-path
62
(multiple-value-bind (new changed)
63
(canonicalize-path-list p)
65
(setf (uri-parsed-path uri) new))))
69
(or (uri-parsed-path base)
70
;; needed because we canonicalize away a path of just `/':
72
(path (uri-parsed-path uri))
74
(when (not (eq :absolute (car base-path)))
75
(error "Cannot merge ~a and ~a, since the latter is not absolute."
79
(append (butlast base-path)
80
(if* path then (cdr path) else '(""))))
82
(let ((last (last new-path-list)))
83
(if* (atom (car last))
84
then (when (string= "." (car last))
86
else (when (string= "." (caar last))
87
(setf (caar last) ""))))
89
(delete "." new-path-list :test #'(lambda (a b)
94
(let ((npl (cdr new-path-list))
97
(string= ".." (let ((l (car (last npl))))
104
:test #'(lambda (a b)
109
(when (null index) (return))
112
then ;; rfe11852: RFC 3986, in section 5.4.2 (Abnormal
113
;; Examples) says parsers; must be careful in handling
114
;; cases where there are more ".." segments in a
115
;; relative-path reference than there are in the base
116
;; URI's path. The examples, between the two RFC's were
117
;; changed to show the additional, leading ..'s to be
118
;; removed. So, we'll do that now.
121
then (setq npl (cddr npl))
123
(dotimes (x (- index 2)) (setq tmp (cdr tmp)))
124
(setf (cdr tmp) (cdddr tmp))))
125
(setf (cdr new-path-list) npl)
126
(when fix-tail (setq new-path-list (nconc new-path-list '("")))))
128
(when (eq :absolute (first new-path-list))
129
(multiple-value-bind (new changed)
130
(canonicalize-path-list new-path-list)
131
(when changed (setq new-path-list new))))
133
;; Also sets uri-path:
134
(setf (uri-parsed-path uri) new-path-list))
137
(return-from merge-uris uri)))
139
(defun canonicalize-path-list (path-list &aux changed)
140
;; Return two values: new version of PATH-LIST and an indicator if it was
141
;; changed. We are only called when (car path-list) is :absolute.
142
(loop while (or (equal "." (second path-list))
143
(equal ".." (second path-list)))
144
do (setf (cdr path-list) (cddr path-list))
146
(values path-list changed))
148
(defmethod merge-uris ((urn urn) (base urn) &optional place)
150
then (setf (urn-nid place) (urn-nid urn))
151
(setf (urn-nss place) (urn-nss urn))
155
(defmethod merge-uris ((urn urn) (base uri) &optional place)
157
then (setf (urn-nid place) (urn-nid urn))
158
(setf (urn-nss place) (urn-nss urn))
162
(defmethod merge-uris ((uri uri) (base urn) &optional place)
163
(copy-uri uri :place place))
165
(defmethod enough-uri ((uri string) (base string) &optional place)
166
(enough-uri (parse-uri uri) (parse-uri base) place))
168
(defmethod enough-uri ((uri uri) (base string) &optional place)
169
(enough-uri uri (parse-uri base) place))
171
(defmethod enough-uri ((uri string) (base uri) &optional place)
172
(enough-uri (parse-uri uri) base place))
174
(defmethod enough-uri ((uri uri) (base uri) &optional place)
175
;; Like ENOUGH-PATHNAME, but for URIs.
176
(let ((new-scheme nil)
182
(new-parsed-path nil))
184
;; If the scheme and authority are not the same, then return URI.
185
(when (or (and (uri-scheme uri)
186
(not (equalp (uri-scheme uri) (uri-scheme base))))
187
;; We don't use uri-authority, because it conses a lot.
189
(not (equalp (uri-host uri) (uri-host base))))
190
(not (equalp (uri-userinfo uri) (uri-userinfo base)))
191
(not (equalp (uri-port uri) (uri-port base))))
192
(return-from enough-uri uri))
194
;; For this group, if the slot is nil in URI, then the return value is
195
;; copied from from BASE:
196
(when (null (uri-scheme uri)) (setq new-scheme (uri-scheme base)))
197
(when (null (uri-host uri))
198
;; These are copied as a unit:
199
(setq new-host (%uri-host base))
200
(setq new-ipv6 (%uri-ipv6 base))
201
(setq new-zone-id (%uri-zone-id base)))
202
(when (null (uri-userinfo uri)) (setq new-userinfo (uri-userinfo base)))
203
(when (null (uri-port uri)) (setq new-port (uri-port base)))
205
;; Now, for the hard one, path.
206
;; We essentially do here what enough-namestring does.
207
(do* ((base-path (uri-parsed-path base))
208
(path (uri-parsed-path uri))
209
(bp base-path (cdr bp))
211
((or (null bp) (null p))
212
;; If p is nil, that means we have something like
213
;; (enough-uri "/foo/bar" "/foo/bar/baz.htm"), so
214
;; new-parsed-path will be nil.
216
(setq new-parsed-path (copy-list p))
217
(when (not (symbolp (car new-parsed-path)))
218
(push :relative new-parsed-path))))
219
(if* (equal (car bp) (car p))
221
else (setq new-parsed-path (copy-list p))
222
(when (not (symbolp (car new-parsed-path)))
223
(push :relative new-parsed-path))
227
(or (when new-parsed-path
228
(render-parsed-path new-parsed-path
229
;; don't know, so have to assume:
231
;; can't have a completely empty uri!
233
(copy-uri nil :class (class-of uri) :place place
234
;;; these come from base if the original slot was nil
239
:userinfo new-userinfo
242
:parsed-path new-parsed-path
243
;;; never from base... why? is this documented?
244
:query (uri-query uri)
245
:fragment (uri-fragment uri)
246
:plist (copy-list (uri-plist uri))))))
248
(defmethod enough-uri ((urn urn) (base urn) &optional place)
250
then (setf (urn-nid place) (urn-nid urn))
251
(setf (urn-nss place) (urn-nss urn))
255
(defmethod enough-uri ((urn urn) (base uri) &optional place)
256
(declare (ignore place))
257
(error "enough-uri of a URN (~a) and URI (~a)." urn base))
259
(defmethod enough-uri ((uri uri) (base urn) &optional place)
260
(declare (ignore place))
261
(error "enough-uri of a URI (~a) and URN (~a)." uri base))
263
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
265
(defun uri-to-pathname (uri)
266
;; On Windows, turn file:///d:/foo/bar.cl into #p"d:/foo/bar.cl"
267
;; On UNIX, turn file:///foo/bar.cl into #p"/foo/bar.cl"
268
(when (not (eq :file (uri-scheme uri)))
269
(error "Only file: URIs can be converted to pathnames: ~s." uri))
270
(when (null (uri-path uri)) (error "URI has no path: ~s." uri))
272
(percent-decode-string
276
(defun pathname-to-uri (pathname)
277
(when (not (uiop:absolute-pathname-p pathname t))
278
(error "A relative pathname cannot be converted to a URI: ~s." pathname))
280
(let ((s (percent-encode-string
281
#+mswindows (substitute #\/ #\\ (namestring pathname))
282
#-mswindows (namestring pathname)
283
*pchar/-bitvector*)))
284
#-mswindows (format nil "file://~a" s)
285
#+mswindows (if* (pathname-device pathname)
286
then (format nil "file:///~a" s)
287
else (format nil "file://~a" s)))))