Changeset 73
- Timestamp:
- 08/26/08 10:59:27 (3 months ago)
- Location:
- trunk/main/claw
- Files:
-
- 6 modified
-
claw.asd (modified) (1 diff)
-
src/auth.lisp (modified) (1 diff)
-
src/lisplet.lisp (modified) (7 diffs)
-
src/misc.lisp (modified) (2 diffs)
-
src/packages.lisp (modified) (2 diffs)
-
src/server.lisp (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/main/claw/claw.asd
r65 r73 32 32 :author "Andrea Chiumenti" 33 33 :description "Common Lisp Active Web.A famework to write web applications" 34 :depends-on (:closer-mop : alexandria :cl-ppcre :cl-fad:local-time :split-sequence :bordeaux-threads :md5)34 :depends-on (:closer-mop :cl-ppcre :cl-fad :alexandria :local-time :split-sequence :bordeaux-threads :md5) 35 35 :components ((:module src 36 36 :components ((:file "packages") -
trunk/main/claw/src/auth.lisp
r65 r73 58 58 "Performs user authentication for the reaml where the request has been created" 59 59 (let* ((login-config (gethash *claw-current-realm* (clawserver-login-config *clawserver*)))) 60 (configuration-login login-config))) 60 (when (and login-config (null (current-principal))) 61 (setf (current-principal) (configuration-login login-config))))) -
trunk/main/claw/src/lisplet.lisp
r65 r73 126 126 (let ((lisplets (clawserver-lisplets clawserver)) 127 127 (location (lisplet-base-path lisplet))) 128 (unless (string= "/" (subseq location 0 1)) 129 (setf location (concatenate 'string "/" location))) 128 130 (setf (clawserver-lisplets clawserver) (sort-by-location (pushnew-location 129 131 (cons location … … 134 136 (let ((lisplets (clawserver-lisplets clawserver)) 135 137 (location (lisplet-base-path lisplet))) 138 (unless (string= "/" (subseq location 0 1)) 139 (setf location (concatenate 'string "/" location))) 136 140 (remove-by-location location lisplets))) 137 141 … … 147 151 148 152 (defmethod lisplet-register-function-location ((lisplet lisplet) function location &key welcome-page-p login-page-p) 153 (unless (string= "/" (subseq location 0 1)) 154 (setf location (concatenate 'string "/" location))) 149 155 (let ((pages (lisplet-pages lisplet))) 150 156 (setf (lisplet-pages lisplet) … … 156 162 157 163 (defmethod lisplet-register-resource-location ((lisplet lisplet) resource-path location &optional content-type) 164 (unless (string= "/" (subseq location 0 1)) 165 (setf location (concatenate 'string "/" location))) 158 166 (let ((pages (lisplet-pages lisplet))) 159 167 (setf (lisplet-pages lisplet) … … 166 174 (+ (length (clawserver-base-path *clawserver*)) 167 175 (length (lisplet-base-path lisplet)) 168 (length location) 1)))176 (length location) ))) 169 177 resource-path))) 170 178 (claw-handle-static-file resource-full-path content-type))) … … 175 183 (defmethod lisplet-dispatch-request ((lisplet lisplet) uri) 176 184 (let ((dispatchers (lisplet-pages lisplet)) 177 (rel-script-name (subseq uri (1+ (length (build-lisplet-location lisplet)))))) 185 (rel-script-name (subseq uri (length (build-lisplet-location lisplet))))) 186 (setf (claw-return-code) +http-not-found+) 178 187 (loop for dispatcher in dispatchers 179 188 for url = (car dispatcher) 180 189 for action = (cdr dispatcher) 181 do (when (starts-with-subseq rel-script-name url) (return (funcall action)))))) 190 do (when (starts-with-subseq url rel-script-name) 191 (setf (claw-return-code) +http-ok+) 192 (return (funcall action)))))) 182 193 183 194 (defmethod lisplet-dispatch-method ((lisplet lisplet)) … … 233 244 for match = (format nil "~a/~a" base-path (car protected-resource)) 234 245 for allowed-roles = (cdr protected-resource) 235 do (when (or (starts-with-subseq match uri) (string= login-page-url uri)) 236 (cond 237 ((and princp (not (user-in-role-p allowed-roles)) (not (string= login-page-url uri))) 238 (setf (claw-return-code) +http-forbidden+) 239 (throw 'handler-done nil)) 240 ((and (null princp) auth-basicp) 241 (setf (claw-return-code) +http-authorization-required+ 242 (claw-header-out "WWW-Authenticate") (format nil "Basic realm=\"~A\"" *claw-current-realm*)) 243 (throw 'handler-done nil)) 244 ((and (null princp) (null auth-basicp) (not (string= login-page-url uri))) 245 (redirect-to-https login-page-url) 246 (throw 'handler-done nil)) 247 ((and sslport (not (= (claw-server-port) sslport))) 248 (redirect-to-https) 249 (throw 'handler-done nil)))))))) 246 do 247 (when (or (starts-with-subseq match uri) (string= login-page-url uri)) 248 (cond 249 ((and princp (not (user-in-role-p allowed-roles)) (not (string= login-page-url uri))) 250 (setf (claw-return-code) +http-forbidden+) 251 (throw 'handler-done nil)) 252 ((and (null princp) auth-basicp) 253 (setf (claw-return-code) +http-authorization-required+ 254 (claw-header-out "WWW-Authenticate") (format nil "Basic realm=\"~A\"" *claw-current-realm*)) 255 (throw 'handler-done nil)) 256 ((and (null princp) (null auth-basicp) (not (string= login-page-url uri))) 257 (redirect-to-https login-page-url) 258 (throw 'handler-done nil)) 259 ((and sslport (not (= (claw-server-port) sslport))) 260 (redirect-to-https) 261 (throw 'handler-done nil)))))))) -
trunk/main/claw/src/misc.lisp
r65 r73 416 416 (let ((principal (current-principal))) 417 417 (when principal 418 (loop for el in (principal-roles principal) thereis (member el roles )))))418 (loop for el in (principal-roles principal) thereis (member el roles :test #'string-equal))))) 419 419 420 420 (defun current-config () … … 496 496 (defun register-library-resource (location resource-path &optional content-type) 497 497 "Adds a RESOURCE \(a file or directory) as a library exposed resource to the given relative LOCATION." 498 (unless (string= "/" (subseq location 0 1)) 499 (setf location (concatenate 'string "/" location))) 498 500 (setf *claw-libraries-resources* 499 501 (sort-by-location (pushnew-location -
trunk/main/claw/src/packages.lisp
r65 r73 32 32 33 33 (defpackage :claw 34 (:use :cl :closer-mop :alexandria :cl-ppcre : cl-fad :local-time :split-sequence :bordeaux-threads :md5)34 (:use :cl :closer-mop :alexandria :cl-ppcre :local-time :split-sequence :bordeaux-threads :md5) 35 35 (:shadow :flatten) 36 (:import-from :cl-fad :directory-pathname-p) 36 37 (:documentation "A comprehensive web application framework and server for the Common Lisp programming language") 37 38 (:export #:*clawserver-base-path* … … 136 137 #:session-manager 137 138 #:default-session-manager 138 139 #:error-page 140 #:error-page-renderer 139 #:error-renderer 141 140 142 141 #:mime-type 143 142 #:duplicate-back-slashes 144 145 #:make-page-renderer146 147 143 #:lisplet 148 144 #:lisplet-log-manager -
trunk/main/claw/src/server.lisp
r65 r73 1 ;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-1 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- 2 2 ;;; $Header: src/server.lisp $ 3 3 … … 31 31 32 32 ;;------------------------------------------------------------------------------------------ 33 (defgeneric error- page-renderer (clawserver &key error-code)33 (defgeneric error-renderer (clawserver &key error-code) 34 34 (:documentation "Method for rendering http errors. This method should be overridden.")) 35 35 … … 42 42 43 43 (defgeneric clawserver-request-uri (clawserver) 44 (:documentation "Returns the URI for request. 44 (:documentation "Returns the URI for request. 45 45 Note that this not the full URI but only the part behind the scheme and authority components, so that if the user has typed http://user:password@www.domain.com/xxx/frob.html?foo=bar into his browser, this function will return \"/xxx/frob.html?foo=bar\". \(This corresponds to the environment variable REQUEST_URI in CGI scripts.")) 46 46 47 47 (defgeneric clawserver-script-name (connector) 48 (:documentation "Returns the file name \(or path) component of the URI for request, i.e. the part of the string returned by REQUEST-URI in front of the first question mark \(if any). 48 (:documentation "Returns the file name \(or path) component of the URI for request, i.e. the part of the string returned by REQUEST-URI in front of the first question mark \(if any). 49 49 \(This corresponds to the environment variable SCRIPT_NAME in CGI scripts.)")) 50 50 … … 62 62 63 63 (defgeneric clawserver-post-parameter (clawserver name) 64 (:documentation "Returns the value of the POST parameter \(as provided in the request's body) named by the string name. 65 Note that only the first value will be returned if the client provided more than one POST parameter with the name name. 64 (:documentation "Returns the value of the POST parameter \(as provided in the request's body) named by the string name. 65 Note that only the first value will be returned if the client provided more than one POST parameter with the name name. 66 66 This value will usually be a string \(or NIL if there ain't no POST parameter with this name). 67 67 If, however, the browser sent a file through a multipart/form-data form, the value of this function is a three-element list … … 69 69 \(path file-name content-type) 70 70 71 where path is a pathname denoting the place were the uploaded file was stored, file-name \(a string) is the file name sent by the browser, and content-type \(also a string) is the content type sent by the browser. 71 where path is a pathname denoting the place were the uploaded file was stored, file-name \(a string) is the file name sent by the browser, and content-type \(also a string) is the content type sent by the browser. 72 72 The file denoted by path will be deleted after the request has been handled - you have to move or copy it somewhere else if you want to keep it.")) 73 73 … … 81 81 82 82 (defgeneric clawserver-header-in (clawserver name) 83 (:documentation "Returns the incoming header named by the keyword name as a string \(or NIL if there ain't no header with this name). 83 (:documentation "Returns the incoming header named by the keyword name as a string \(or NIL if there ain't no header with this name). 84 84 Note that this queries the headers sent to Hunchentoot by the client or by mod_lisp. In the latter case this may not only include the incoming http headers but also some headers sent by mod_lisp. 85 85 For backwards compatibility, name can also be a string which is matched case-insensitively. See also CLAWSERVER-HEADERS-IN.")) … … 101 101 102 102 (defgeneric clawserver-real-remote-addr (clawserver) 103 (:documentation "Returns the value of the incoming X-Forwarded-For http header as the second value in the form of a list of IP addresses and the first element of this list as the first value if this header exists. 103 (:documentation "Returns the value of the incoming X-Forwarded-For http header as the second value in the form of a list of IP addresses and the first element of this list as the first value if this header exists. 104 104 Otherwise returns the value of CLAWSERVER-REMOTE-ADDR as the only value.")) 105 105 … … 146 146 147 147 (defgeneric (setf clawserver-header-out) (value clawserver name) 148 (:documentation "SETF of HEADER-OUT changes the current value of the header named name \(name parameter must be a symbol).149 If no header named name exists it is created. 150 Note that the headers Set-Cookie, Content-Length, and Content-Type must not be set by SETF of HEADER-OUT. 148 (:documentation "SETF of HEADER-OUT changes the current value of the header named name \(name parameter must be a symbol). 149 If no header named name exists it is created. 150 Note that the headers Set-Cookie, Content-Length, and Content-Type must not be set by SETF of HEADER-OUT. 151 151 Also, there are a couple of \"technical\" headers like Connection or Transfer-Encoding that you're not supposed to set yourself. 152 152 See also CLAWSERVER-HEADERS-OUT, CLAWSERVER-CONTENT-TYPE, CLAWSERVER-CONTENT-LENGTH, CLAWSERVER-COOKIES-OUT, and CLAWSERVER-COOKIE-OUT")) … … 154 154 (defgeneric clawserver-headers-out (clawserver) 155 155 (:documentation "Returns an alist of all outgoing http parameters \(except for Set-Cookie, Content-Length, and Content-Type). 156 The car of each element of this list is the headers's name while the cdr is its value. 156 The car of each element of this list is the headers's name while the cdr is its value. 157 157 This alist should not be manipulated directly, use SETF of CLAWSERVER-HEADER-OUT instead")) 158 158 … … 297 297 (rel-script-name) 298 298 (rel-script-name-libs) 299 (http-result)) 300 (handler-bind ((error (lambda (cond) 301 (logger-log (clawserver-log-manager clawserver) :error "~a" cond) 302 (with-output-to-string (*standard-output*) 303 (error-page-renderer clawserver :error-code +http-internal-server-error+))))) 304 (unwind-protect 305 (catch 'handler-done 306 (if (starts-with-subseq script-name base-path) 307 (progn 308 (setf rel-script-name (subseq script-name (length base-path)) 309 rel-script-name-libs (subseq script-name (1+ (length base-path)))) 310 (setf http-result (or 311 (loop for dispatcher in *claw-libraries-resources* 312 for url = (car dispatcher) 313 for action = (cdr dispatcher) 314 do (when (starts-with-subseq rel-script-name-libs url) (funcall action))) 315 (loop for lisplet-cons in lisplets 316 for url = (car lisplet-cons) 317 for lisplet = (cdr lisplet-cons) 318 do (when (starts-with-subseq rel-script-name url) (return (funcall #'lisplet-dispatch-method lisplet)))))))))) 319 (or http-result 320 (let ((error-handler (and *claw-current-lisplet* 321 (gethash (or 322 (let ((return-code (claw-return-code))) 323 (if (= return-code +http-ok+) 324 nil 325 return-code)) 326 +http-not-found+) 327 (lisplet-error-handlers *claw-current-lisplet*))))) 328 (when error-handler 329 (funcall error-handler))) 330 (with-output-to-string (*standard-output*) 331 (error-page-renderer clawserver (or 332 (let ((return-code (claw-return-code))) 333 (if (= return-code +http-ok+) 334 nil 335 return-code)) 336 +http-not-found+))))))) 299 (http-result nil)) 300 (handler-case 301 (progn 302 (unwind-protect 303 (catch 'handler-done 304 (progn 305 (setf (claw-return-code) +http-not-found+) 306 (if (starts-with-subseq base-path script-name) 307 (progn 308 (setf rel-script-name (subseq script-name (length base-path)) 309 rel-script-name-libs (subseq script-name (length base-path))) 310 (setf http-result (or 311 (loop for dispatcher in *claw-libraries-resources* 312 for url = (car dispatcher) 313 for action = (cdr dispatcher) 314 do (when (starts-with-subseq url rel-script-name-libs) 315 (setf (claw-return-code) +http-ok+) 316 (funcall action))) 317 (loop for lisplet-cons in lisplets 318 for url = (car lisplet-cons) 319 for lisplet = (cdr lisplet-cons) 320 do (when (starts-with-subseq url rel-script-name) 321 (setf (claw-return-code) +http-ok+) 322 (return (funcall #'lisplet-dispatch-method lisplet))))))))))) 323 (or http-result 324 (and (>= (claw-return-code) 400) 325 (or 326 (let ((error-handler (and *claw-current-lisplet* 327 (gethash (or 328 (let ((return-code (claw-return-code))) 329 (if (= return-code +http-ok+) 330 nil 331 return-code)) 332 +http-not-found+) 333 (lisplet-error-handlers *claw-current-lisplet*))))) 334 (when error-handler 335 (funcall error-handler))) 336 (with-output-to-string (*standard-output*) 337 (error-renderer clawserver :error-code (or 338 (let ((return-code (claw-return-code))) 339 (if (= return-code +http-ok+) 340 nil 341 return-code)) 342 +http-not-found+))))) 343 )) 344 (error (cond) 345 (logger-log (clawserver-log-manager clawserver) :error "~a" cond) 346 (with-output-to-string (*standard-output*) (error-renderer clawserver :error-code +http-internal-server-error+)))))) 337 347 338 348 339 349 (defmethod clawserver-dispatch-method ((clawserver clawserver)) 340 (let ((result (clawserver-dispatch-request clawserver)) 341 (connector (clawserver-connector clawserver))) 342 (if (null result) 343 #'(lambda () (when (= (connector-return-code connector) 200) ;OK 344 (setf (connector-return-code connector) 404))) ; Not found 345 #'(lambda () result)))) 350 #'(lambda () (clawserver-dispatch-request clawserver))) 346 351 347 352 (defmethod clawserver-start ((clawserver clawserver)) … … 512 517 (connector-script-name (clawserver-connector clawserver))) 513 518 514 (defmethod error-page-renderer ((clawserver clawserver) &key (error-code 404)) 515 (format nil "<html> 519 (defmethod error-renderer ((clawserver clawserver) &key (error-code 404)) 520 (let ((request-uri (connector-request-uri (clawserver-connector clawserver))) 521 (connector (clawserver-connector clawserver)) 522 (style "body { 523 font-family: arial, elvetica; 524 font-size: 7pt; 525 } 526 span.blue { 527 padding: 0 3px; 528 background-color: #525D76; 529 color: white; 530 font-weight: bolder; 531 margin-right: .25em; 532 } 533 p.h1, p.h2 { 534 padding: 0 3px; 535 background-color: #525D76; 536 color: white; 537 font-weight: bolder; 538 font-size: 2em; 539 margin: 0; 540 margin-bottom: .5em; 541 } 542 p.h2 {font-size: 1.5em;}")) 543 (setf (connector-return-code connector) error-code) 544 (format t "<html> 516 545 <head> 517 546 <title>Error ~a</title> 547 <style>~a</style> 518 548 </head> 519 549 <body> 520 <h1>HTTP Status ~a</h1> 521 <h2>~a</h2> 550 <p> 551 <p class='h1'> 552 HTTP Status ~a - ~a 553 </p> 554 <hr noshade='noshade'> 555 <p> 556 <span class='blue'>type</span> 557 Status report 558 </p> 559 <p> 560 <span class='blue'>url</span> 561 ~a 562 </p> 563 <p> 564 <span class='blue'>description</span> 565 ~a 566 </p> 567 <hr noshade='noshade'> 568 <p class='h2'> 569 CLAW server 570 </p> 571 </p> 522 572 </body> 523 </html>" error-code error-code (gethash error-code *http-reason-phrase-map*))) 573 </html>" 574 error-code ;title 575 style ;tyle 576 error-code request-uri 577 request-uri 578 (gethash error-code *http-reason-phrase-map*))))
