Changeset 73

Show
Ignore:
Timestamp:
08/26/08 10:59:27 (3 months ago)
Author:
achiumenti
Message:

CLAW application server

Location:
trunk/main/claw
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • trunk/main/claw/claw.asd

    r65 r73  
    3232  :author "Andrea Chiumenti" 
    3333  :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) 
    3535  :components ((:module src 
    3636                        :components ((:file "packages") 
  • trunk/main/claw/src/auth.lisp

    r65 r73  
    5858  "Performs user authentication for the reaml where the request has been created" 
    5959  (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  
    126126  (let ((lisplets (clawserver-lisplets clawserver)) 
    127127        (location (lisplet-base-path lisplet))) 
     128    (unless (string= "/" (subseq location 0 1)) 
     129      (setf location (concatenate 'string "/" location))) 
    128130    (setf (clawserver-lisplets clawserver) (sort-by-location (pushnew-location 
    129131                                                                 (cons location 
     
    134136  (let ((lisplets (clawserver-lisplets clawserver)) 
    135137        (location (lisplet-base-path lisplet))) 
     138    (unless (string= "/" (subseq location 0 1)) 
     139      (setf location (concatenate 'string "/" location))) 
    136140    (remove-by-location location lisplets))) 
    137141 
     
    147151 
    148152(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))) 
    149155  (let ((pages (lisplet-pages lisplet))) 
    150156    (setf (lisplet-pages lisplet) 
     
    156162 
    157163(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))) 
    158166  (let ((pages (lisplet-pages lisplet))) 
    159167    (setf (lisplet-pages lisplet) 
     
    166174                                                                                               (+ (length (clawserver-base-path *clawserver*)) 
    167175                                                                                                  (length (lisplet-base-path lisplet)) 
    168                                                                                                   (length location) 1))) 
     176                                                                                                  (length location) ))) 
    169177                                                                      resource-path))) 
    170178                                             (claw-handle-static-file resource-full-path content-type))) 
     
    175183(defmethod lisplet-dispatch-request ((lisplet lisplet) uri) 
    176184  (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+) 
    178187    (loop for dispatcher in dispatchers 
    179188       for url = (car dispatcher) 
    180189       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)))))) 
    182193 
    183194(defmethod lisplet-dispatch-method ((lisplet lisplet)) 
     
    233244         for match = (format nil "~a/~a" base-path (car protected-resource)) 
    234245         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  
    416416  (let ((principal (current-principal))) 
    417417    (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))))) 
    419419 
    420420(defun current-config () 
     
    496496(defun register-library-resource (location resource-path &optional content-type) 
    497497  "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))) 
    498500  (setf *claw-libraries-resources* 
    499501        (sort-by-location (pushnew-location 
  • trunk/main/claw/src/packages.lisp

    r65 r73  
    3232 
    3333(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) 
    3535  (:shadow :flatten) 
     36  (:import-from :cl-fad :directory-pathname-p) 
    3637  (:documentation "A comprehensive web application framework and server for the Common Lisp programming language") 
    3738  (:export #:*clawserver-base-path* 
     
    136137           #:session-manager 
    137138           #:default-session-manager 
    138  
    139            #:error-page 
    140            #:error-page-renderer 
     139           #:error-renderer 
    141140 
    142141           #:mime-type 
    143142           #:duplicate-back-slashes 
    144  
    145            #:make-page-renderer 
    146  
    147143           #:lisplet 
    148144           #: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 -*- 
    22;;; $Header: src/server.lisp $ 
    33 
     
    3131 
    3232;;------------------------------------------------------------------------------------------ 
    33 (defgeneric error-page-renderer (clawserver &key error-code) 
     33(defgeneric error-renderer (clawserver &key error-code) 
    3434  (:documentation "Method for rendering http errors. This method should be overridden.")) 
    3535 
     
    4242 
    4343(defgeneric clawserver-request-uri (clawserver) 
    44   (:documentation "Returns the URI for request.  
     44  (:documentation "Returns the URI for request. 
    4545Note 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.")) 
    4646 
    4747(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). 
    4949\(This corresponds to the environment variable SCRIPT_NAME in CGI scripts.)")) 
    5050 
     
    6262 
    6363(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. 
     65Note that only the first value will be returned if the client provided more than one POST parameter with the name name. 
    6666This value will usually be a string \(or NIL if there ain't no POST parameter with this name). 
    6767If, however, the browser sent a file through a multipart/form-data form, the value of this function is a three-element list 
     
    6969\(path file-name content-type) 
    7070 
    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.  
     71where 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. 
    7272The 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.")) 
    7373 
     
    8181 
    8282(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). 
    8484Note 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. 
    8585For backwards compatibility, name can also be a string which is matched case-insensitively. See also CLAWSERVER-HEADERS-IN.")) 
     
    101101 
    102102(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. 
    104104Otherwise returns the value of CLAWSERVER-REMOTE-ADDR as the only value.")) 
    105105 
     
    146146 
    147147(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). 
     149If no header named name exists it is created. 
     150Note that the headers Set-Cookie, Content-Length, and Content-Type must not be set by SETF of HEADER-OUT. 
    151151Also, there are a couple of \"technical\" headers like Connection or Transfer-Encoding that you're not supposed to set yourself. 
    152152See also CLAWSERVER-HEADERS-OUT, CLAWSERVER-CONTENT-TYPE, CLAWSERVER-CONTENT-LENGTH, CLAWSERVER-COOKIES-OUT, and CLAWSERVER-COOKIE-OUT")) 
     
    154154(defgeneric clawserver-headers-out (clawserver) 
    155155  (: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.  
     156The car of each element of this list is the headers's name while the cdr is its value. 
    157157This alist should not be manipulated directly, use SETF of CLAWSERVER-HEADER-OUT instead")) 
    158158 
     
    297297         (rel-script-name) 
    298298         (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+)))))) 
    337347 
    338348 
    339349(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))) 
    346351 
    347352(defmethod clawserver-start ((clawserver clawserver)) 
     
    512517  (connector-script-name (clawserver-connector clawserver))) 
    513518 
    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} 
     526span.blue { 
     527  padding: 0 3px; 
     528  background-color: #525D76; 
     529  color: white; 
     530  font-weight: bolder; 
     531  margin-right: .25em; 
     532} 
     533p.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} 
     542p.h2 {font-size: 1.5em;}")) 
     543    (setf (connector-return-code connector) error-code) 
     544    (format t "<html> 
    516545<head> 
    517546  <title>Error ~a</title> 
     547  <style>~a</style> 
    518548</head> 
    519549<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> 
    522572</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*))))