(module awful (;; Parameters awful-apps debug-file debug-db-query? debug-db-query-prefix db-credentials ajax-library enable-ajax ajax-namespace enable-session page-access-control page-access-denied-message page-doctype page-css page-charset login-page-path main-page-path app-root-path valid-password? page-template ajax-invalid-session-message web-repl-access-control web-repl-access-denied-message session-inspector-access-control session-inspector-access-denied-message page-exception-message http-request-variables db-connection page-javascript sid enable-javascript-compression javascript-compressor debug-resources enable-session-cookie session-cookie-name awful-response-headers development-mode? enable-web-repl-fancy-editor web-repl-fancy-editor-base-uri awful-listen awful-accept awful-backlog awful-listener javascript-position ;; Procedures ++ concat include-javascript add-javascript debug debug-pp $session $session-set! $ $db $db-row-obj sql-quote define-page undefine-page define-session-page ajax ajax-link periodical-ajax login-form define-login-trampoline enable-web-repl enable-session-inspector awful-version load-apps link form redirect-to ;; Required by the awful server add-resource! register-dispatcher register-root-dir-handler awful-start ;; Required by db-support eggs db-enabled? db-inquirer db-connect db-disconnect sql-quoter db-make-row-obj ) ; end export list (import scheme chicken data-structures utils extras ports srfi-69 files srfi-1) ;; Units (use posix srfi-13 tcp) ;; Eggs (use intarweb spiffy spiffy-request-vars html-tags html-utils uri-common http-session json spiffy-cookies regex) ;;; Version (define (awful-version) "0.30") ;;; Parameters ;; User-configurable parameters (define awful-apps (make-parameter '())) (define debug-file (make-parameter #f)) (define debug-db-query? (make-parameter #t)) (define debug-db-query-prefix (make-parameter "")) (define db-credentials (make-parameter #f)) (define ajax-library (make-parameter "//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js")) (define enable-ajax (make-parameter #f)) (define ajax-namespace (make-parameter "ajax")) (define enable-session (make-parameter #f)) (define page-access-control (make-parameter (lambda (path) #t))) (define page-access-denied-message (make-parameter (lambda (path) (

"Access denied.")))) (define page-doctype (make-parameter "")) (define page-css (make-parameter #f)) (define page-charset (make-parameter #f)) (define login-page-path (make-parameter "/login")) ;; don't forget no-session: #t for this page (define main-page-path (make-parameter "/")) (define app-root-path (make-parameter "/")) (define valid-password? (make-parameter (lambda (user password) #f))) (define page-template (make-parameter html-page)) (define ajax-invalid-session-message (make-parameter "Invalid session.")) (define web-repl-access-control (make-parameter (lambda () #f))) (define web-repl-access-denied-message (make-parameter (

"Access denied."))) (define session-inspector-access-control (make-parameter (lambda () #f))) (define session-inspector-access-denied-message (make-parameter (

"Access denied."))) (define enable-javascript-compression (make-parameter #f)) (define javascript-compressor (make-parameter identity)) (define awful-response-headers (make-parameter #f)) (define development-mode? (make-parameter #f)) (define enable-web-repl-fancy-editor (make-parameter #t)) (define web-repl-fancy-editor-base-uri (make-parameter "http://parenteses.org/awful/codemirror")) (define page-exception-message (make-parameter (lambda (exn) (

"An error has accurred while processing your request.")))) (define debug-resources (make-parameter #f)) ;; usually useful for awful development debugging (define enable-session-cookie (make-parameter #t)) (define session-cookie-name (make-parameter "awful-cookie")) (define javascript-position (make-parameter 'top)) ;; Parameters for internal use (but exported, since they are internally used by other eggs) (define http-request-variables (make-parameter #f)) (define db-connection (make-parameter #f)) (define page-javascript (make-parameter "")) (define sid (make-parameter #f)) (define db-enabled? (make-parameter #f)) (define awful-listen (make-parameter tcp-listen)) (define awful-accept (make-parameter tcp-accept)) (define awful-backlog (make-parameter 10)) (define awful-listener (make-parameter (let ((listener #f)) (lambda () (unless listener (set! listener ((awful-listen) (server-port) (awful-backlog) (server-bind-address)))) listener)))) ;; Parameters for internal use and not exported (define %redirect (make-parameter #f)) (define %web-repl-path (make-parameter #f)) (define %session-inspector-path (make-parameter #f)) (define %error (make-parameter #f)) ;; db-support parameters (set by awful- eggs) (define missing-db-msg "Database access is not enabled (see `enable-db').") (define db-inquirer (make-parameter (lambda (query) (error '$db missing-db-msg)))) (define db-connect (make-parameter (lambda (credentials) (error 'db-connect missing-db-msg)))) (define db-disconnect (make-parameter (lambda (connection) (error 'db-disconnect missing-db-msg)))) (define sql-quoter (make-parameter (lambda args (error 'sql-quote missing-db-msg)))) (define db-make-row-obj (make-parameter (lambda (q) (error '$db-row-obj missing-db-msg)))) ;;; Misc (define ++ string-append) (define (concat args #!optional (sep "")) (string-intersperse (map ->string args) sep)) (define (string->symbol* str) (if (string? str) (string->symbol str) str)) (define (load-apps apps) (set! *resources* (make-hash-table equal?)) (for-each load apps) (when (development-mode?) (development-mode-actions))) (define (define-reload-page) ;; Define a /reload page for reloading awful apps (define-page "/reload" (lambda () (load-apps (awful-apps)) (++ (

"The following awful apps have been reloaded on " (seconds->string (current-seconds))) (itemize (map (awful-apps))))) no-ajax: #t title: "Awful reloaded applications")) (define (development-mode-actions) (print "Awful is running in development mode.") (debug-log (current-error-port)) ;; Print the call chain, the error message and links to the ;; web-repl and session-inspector (if enabled) (page-exception-message (lambda (exn) (++ (

 convert-to-entities?: #t
                (with-output-to-string
                  (lambda ()
                    (print-call-chain)
                    (print-error-message exn))))
         (

"[" ( href: (or (%web-repl-path) "/web-repl") "Web REPL") "]" (if (enable-session) (++ " [" ( href: (or (%session-inspector-path) "/session-inspector") "Session inspector") "]") ""))))) ;; If web-repl has not been activated, activate it allowing access ;; to the localhost at least (`web-repl-access-control' can be ;; used to provide more permissive control) (unless (%web-repl-path) (let ((old-access-control (web-repl-access-control))) (web-repl-access-control (lambda () (or (old-access-control) (equal? (remote-address) "127.0.0.1"))))) (enable-web-repl "/web-repl")) ;; If session-inspector has not been activated, and if ;; `enable-session' is #t, activate it allowing access to the ;; localhost at least (`session-inspector-access-control' can be ;; used to provide more permissive control) (when (and (enable-session) (not (%session-inspector-path))) (let ((old-access-control (session-inspector-access-control))) (session-inspector-access-control (lambda () (or (old-access-control) (equal? (remote-address) "127.0.0.1")))) (enable-session-inspector "/session-inspector"))) ;; The reload page (define-reload-page)) (define (awful-start #!key dev-mode? port ip-address use-fancy-web-repl? privileged-code) (enable-web-repl-fancy-editor use-fancy-web-repl?) (when dev-mode? (development-mode? #t)) ;; `load-apps' also calls `development-mode-actions', so only call ;; `development-mode-actions' when `(awful-apps)' is null (in this ;; case `load-apps' is not called). (when (and dev-mode? (null? (awful-apps))) (development-mode-actions)) (when port (server-port port)) (when ip-address (server-bind-address ip-address)) ;; if privileged-code is provided, it is loaded before switching ;; user/group (when privileged-code (load privileged-code)) (let ((listener ((awful-listener)))) (switch-user/group (spiffy-user) (spiffy-group)) (when (zero? (current-effective-user-id)) (print "WARNING: awful is running with administrator privileges (not recommended)")) ;; load apps (load-apps (awful-apps)) ;; Check for invalid javascript positioning (unless (memq (javascript-position) '(top bottom)) (error 'awful-start "Invalid value for `javascript-position'. Valid ones are: `top' and `bottom'.")) (register-root-dir-handler) (register-dispatcher) (accept-loop listener (awful-accept)))) (define (get-sid #!optional force-read-sid) (and (or (enable-session) force-read-sid) (if (enable-session-cookie) (or (read-cookie (session-cookie-name)) ($ 'sid)) ($ 'sid)))) (define (redirect-to new-uri) ;; Just set the `%redirect' internal parameter, so `run-resource' is ;; able to know where to redirect. (%redirect new-uri)) ;;; Javascript (define (include-javascript . files) (string-intersperse (map (lambda (file) (