X-Git-Url: http://git.kpe.io/?p=puri.git;a=blobdiff_plain;f=src.lisp;h=da6d9fd2af08c1a8812a6c428678e79c2c4a6971;hp=6ba041700a3980191f81c9390027cd7bb1767aa8;hb=HEAD;hpb=feebbfdc402097d14c9a4cd27bf1a7a12120f7c9 diff --git a/src.lisp b/src.lisp index 6ba0417..4a4d5db 100644 --- a/src.lisp +++ b/src.lisp @@ -4,7 +4,7 @@ ;; ;; copyright (c) 1999-2002 Franz Inc, Berkeley, CA - All rights reserved. ;; copyright (c) 2002-2005 Franz Inc, Oakland, CA - All rights reserved. -;; copyright (c) 2003-2006 Kevin Rosenberg (porting changes) +;; copyright (c) 2003-2010 Kevin Rosenberg ;; ;; This code is free software; you can redistribute it and/or ;; modify it under the terms of the version 2.1 of @@ -21,12 +21,10 @@ ;; but without any warranty; without even the implied warranty of ;; merchantability or fitness for a particular purpose. See the GNU ;; Lesser General Public License for more details. -;; -;; $Id$ (defpackage #:puri (:use #:cl) - #-allegro (:nicknames #:net.uri) + #-(or allegro zacl) (:nicknames #:net.uri) (:export #:uri ; the type and a function #:uri-p @@ -36,6 +34,7 @@ #:uri-host #:uri-port #:uri-path #:uri-query + #:uri-is-ip6 #:uri-fragment #:uri-plist #:uri-authority ; pseudo-slot accessor @@ -240,6 +239,10 @@ :initarg :parsed-path :initform nil :accessor .uri-parsed-path) + (is-ip6 + :initarg :is-ip6 + :initform nil + :accessor uri-is-ip6) (hashcode ;; cached sxhash, so we don't have to compute it more than once. :initarg :hashcode :initform nil :accessor uri-hashcode))) @@ -355,13 +358,19 @@ ;; Parsing (defparameter *excluded-characters* - '(;; `delims' (except #\%, because it's handled specially): + (append + ;; exclude control characters + (loop for i from 0 to #x1f + collect (code-char i)) + '(;; `delims' (except #\%, because it's handled specially): #\< #\> #\" #\space #\# + #\Rubout ;; (code-char #x7f) ;; `unwise': #\{ #\} #\| #\\ #\^ #\[ #\] #\`)) + "Excluded charcters from RFC2396 (http://www.ietf.org/rfc/rfc2396.txt 2.4.3)") (defun reserved-char-vector (chars &key except) - (do* ((a (make-array 127 :element-type 'bit :initial-element 0)) + (do* ((a (make-array 128 :element-type 'bit :initial-element 0)) (chars chars (cdr chars)) (c (car chars) (car chars))) ((null chars) a) @@ -379,7 +388,7 @@ (defparameter *reserved-path-characters* (reserved-char-vector (append *excluded-characters* - '(#\; + '(#\; #\% ;;;;The rfc says this should be here, but it doesn't make sense. ;; #\= #\/ #\?)))) @@ -417,19 +426,27 @@ (append *excluded-characters* '(#\& #\~ #\/ #\?)))) (defparameter *illegal-characters* - (reserved-char-vector (remove #\# *excluded-characters*))) + (reserved-char-vector (set-difference *excluded-characters* + '(#\# #\[ #\])))) (defparameter *strict-illegal-query-characters* (reserved-char-vector (append '(#\?) (remove #\# *excluded-characters*)))) (defparameter *illegal-query-characters* (reserved-char-vector *excluded-characters* :except '(#\^ #\| #\#))) +(defparameter *valid-ip6-characters* + (reserved-char-vector + '#.(nconc (gen-char-range-list #\a #\f) + (gen-char-range-list #\A #\F) + (gen-char-range-list #\0 #\9) + '(#\: #\])))) + (defun parse-uri (thing &key (class 'uri) &aux escape) (when (uri-p thing) (return-from parse-uri thing)) (setq escape (escape-p thing)) - (multiple-value-bind (scheme host port path query fragment) + (multiple-value-bind (scheme host port path query fragment is-ip6) (parse-uri-string thing) (when scheme (setq scheme @@ -477,6 +494,7 @@ (make-instance 'uri :scheme scheme :host host + :is-ip6 is-ip6 :port port :path path :query query @@ -486,6 +504,7 @@ (make-instance class :scheme scheme :host host + :is-ip6 is-ip6 :port port :path path :query query @@ -510,6 +529,7 @@ ;; simulating: ;; ^(([^:/?#]+):)? ;; (//([^/?#]*))? + ;; May include a []-pair for ipv6 ;; ([^?#]*) ;; (\?([^#]*))? ;; (#(.*))? @@ -519,6 +539,7 @@ (tokval nil) (scheme nil) (host nil) + (is-ip6 nil) (port nil) (path-components '()) (query nil) @@ -558,10 +579,14 @@ URI ~s contains illegal character ~s at position ~d." (#\? (return :question)) (#\# (return :hash)))) (:query (case c (#\# (return :hash)))) + (:ip6 (case c + (#\] (return :close-bracket)))) (:rest) (t (case c (#\: (return :colon)) (#\? (return :question)) + (#\[ (return :open-bracket)) + (#\] (return :close-bracket)) (#\# (return :hash)) (#\/ (return :slash))))) (incf start))) @@ -639,11 +664,20 @@ URI ~s contains illegal character ~s at position ~d." (setq state 6)) (:end (push "/" path-components) (setq state 9)))) + (66 ;; seen [:]//[ + (ecase (read-token :ip6 *valid-ip6-characters*) + (:string (setq host tokval) + (setq is-ip6 t) + (setq state 67)))) + (67 ;; seen [:]//[ip6] + (ecase (read-token t) + (:close-bracket (setq state 11)))) (4 ;; seen [:]// (ecase (read-token t) (:colon (failure)) (:question (failure)) (:hash (failure)) + (:open-bracket (setq state 66)) (:slash (if* (and (equalp "file" scheme) (null host)) @@ -721,7 +755,7 @@ URI ~s contains illegal character ~s at position ~d." (values scheme host port (apply #'concatenate 'string (nreverse path-components)) - query fragment))) + query fragment is-ip6))) ;; URN parsing: (15 ;; seen urn:, read nid now (case (read-token :colon *valid-nid-characters*) @@ -825,6 +859,7 @@ URI ~s contains illegal character ~s at position ~d." (setf (uri-string uri) (let ((scheme (uri-scheme uri)) (host (uri-host uri)) + (is-ip6 (uri-is-ip6 uri)) (port (uri-port uri)) (path (uri-path uri)) (query (uri-query uri)) @@ -837,20 +872,21 @@ URI ~s contains illegal character ~s at position ~d." *reserved-characters* escape)) (when scheme ":") (when (or host (eq :file scheme)) "//") + (when is-ip6 "[") (when host (encode-escaped-encoding host *reserved-authority-characters* escape)) + (when is-ip6 "]") (when port ":") (when port #-allegro (format nil "~D" port) #+allegro (with-output-to-string (s) (excl::maybe-print-fast s port)) ) - (when path - (encode-escaped-encoding path - nil - ;;*reserved-path-characters* - escape)) + (encode-escaped-encoding (or path "/") + nil + ;;*reserved-path-characters* + escape) (when query "?") (when query (encode-escaped-encoding query nil escape)) (when fragment "#") @@ -1315,13 +1351,6 @@ Executes the forms once for each uri with var bound to the current uri" "#u takes a string or list argument: ~s" arg))))) -#+allegro -excl:: -#+allegro -(locally (declare (special std-lisp-readtable)) - (let ((*readtable* std-lisp-readtable)) - (set-dispatch-macro-character #\# #\u #'puri::sharp-u))) -#-allegro (set-dispatch-macro-character #\# #\u #'puri::sharp-u) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;