id: "greetings-reply")))
use-ajax: #t)
=== Database access
To access databases, you need some of the awful eggs which provide database access. Currently, these are the possible options:
* [[/egg/awful-postgresql|awful-postgresql]] (for Postgresql databases, using the [[/egg/postgresql|postgresql]] egg)
* [[/egg/awful-sqlite3|awful-sqlite3]] (for Sqlite3 databases, using the [[/egg/sqlite3|sqlite3]] egg)
* [[/egg/awful-sql-de-lite|awful-sql-de-lite]] (for Sqlite3 databases, using the [[/egg/sql-de-lite|sql-de-lite]] egg)
As with ajax, database access is not enabled by default. To enable it, you need to pick one the awful database support eggs and call the {{enable-db}} procedure. Since version 0.10, and differently from the {{enable-*}} parameters, {{enable-db}} is a zero-argument procedure provided by each of awful database-support eggs. So, if you use {{awful-postgresql}}, the {{enable-db}} procedure will automatically set up awful to use a postgresql database.
Additionally, to access the db, you need to provide the credentials. You can provide the credentials by setting the {{db-credentials}} parameter. See the documentation for the eggs corresponding to the database type you are using ([[/egg/postgresql|postgresql]] for Postgresql and [[/egg/sqlite3|sqlite3]] or [[/egg/sql-de-lite|sql-de-lite]] for Sqlite3.)
To actually query the database, there's the {{$db}} procedure, which uses as arguments a string representing the query and, optionally, a default value (a keyword parameter) to be used in case the query doesn't return any result. {{$db}} returns a list of lists. Below is an usage example:
(use awful awful-postgresql)
(enable-db)
(db-credentials '((dbname . "my-db")
(user . "mario")
(password . "secret")
(host . "localhost")))
(define-page "db-example"
(lambda ()
(with-output-to-string
(lambda ()
(pp ($db "select full_name, phone from users"))))))
''Hint'': for Sqlite3 databases, {{db-credentials}} should be the path to the database file.
There's also the {{$db-row-obj}} procedure for when you want to access the results of a query by row name. {{$db-row-obj}} returns a procedure of two arguments: the name of the field and, optionally, a default value to be used in case the field value is {{#f}}.
(define-page "db-example"
(lambda ()
(let ((& ($db-row-obj "select full_name, phone from users where user_id=1")))
( "Full name: " (& 'full_name))
(
"Phone: " (& 'phone)))))
''Warning'': currently {{$db-row-obj}} is only implemented for Postgresql.
If you need more flexibility to query the database, you can always use the {{(db-connection}}) parameter to get the database connection object and use it with the procedures available from the your favorite database egg API.
=== Login pages and session
Awful provides a very basic (awful?) support for creating authentication pages.
The basic things you have to do is:
1. Enable the use of sessions:
(enable-session #t)
2. Set the password validation parameter. This parameter is a two argument procedure (user and password) which returns a value (usually {{#t}} or {{#f}}) indicating whether the password is valid for the given user. The default is a password which returns {{#f}}. Let's set it to a procedure which returns {{#t}} is the user and the password are the same:
(valid-password?
(lambda (user password)
(equal? user password)))
3. Define a login trampoline, which is an intermediate page accessed when redirecting from the login page to the main page.
(define-login-trampoline "/login-trampoline")
4. Create a login page. Awful provides a simple user/password login form ({{login-form}}), which we are going to use. Here's our full example so far (using the basic "Hello, world!" as main page).
(use awful)
(enable-session #t)
(define-login-trampoline "/login-trampoline")
(valid-password?
(lambda (user password)
(equal? user password)))
(define-page (main-page-path)
(lambda ()
"Hello world!"))
(define-page (login-page-path)
(lambda ()
(login-form))
no-session: #t)
That's the very basic we need to set an auth page. If the password is valid for the given user, awful will perform a redirect to the main page ({{main-page-path}} parameter) passing the {{user}} variable and its value in the query string . If the password is not valid, awful will redirect to the login page ({{login-page-path}} parameter) and pass the following variables and values:
; {{reason}} : the reason why awful redirected to the login page. It may be {{invalid-password}}, for when the password is invalid for the given user; or {{invalid-session}} for when the session identifier is not valid (e.g., the session expired).
; {{attempted-page}} : the URL path to page the user tried to access, but couldn't because either he/she was not logged in or he/she provided an invalid session identifier.
; {{user}} : the user used for the form user field.
Now we're gonna change our main page to store the user in the session and retrieve it to make the greetings message:
(define-page (main-page-path)
(lambda ()
($session-set! 'user ($ 'user))
(++ "Hello " ($session 'user "world") "!")))
Here we can see the two procedures to access the session: {{$session}} and {{$session-set!}}.
{{$session-set!}} accepts two arguments: the first one is the name of the session variable and the second one is its value.
{{$session}} takes the name of the session variable as argument and returns its session value. We can optionally use a second argument to specify a default value, in case the session variable is not bound or is {{#f}}.
=== Session inspector
Awful provides a session inspector, so we can easily see the session contents for a given session identifier. By default, the session inspector is disabled. We can enabled it using the {{enable-session-inspector}} procedure, passing the session inspector URL path as argument:
(enable-session-inspector "session-inspector")
Now, if you log in and try to access {{http://localhost:8080/session-inspector}}, you'll get ... an access denied page.
Awful provides a way to control access to the session inspector ({{session-inspector-access-control}} parameter). The {{session-inspector-access-control}} parameter is an one-argument procedure which returns {{#f}} or some other value to indicate whether the access to the session inspector is allowed or not. By default, it blocks all access. Let's configure it so we can access the session inspector from the local machine (whose IP number is 127.0.0.1):
(session-inspector-access-control
(lambda ()
(member (remote-address) '("127.0.0.1"))))
Regarding to the access denied message, you can customize it by setting the {{session-inspector-access-denied-message}}.
Now we can access {{http://localhost:8080/session-inspector}} and see the session contents.
''Note'': if {{enable-session-cookie}} is {{#f}}, you need to pass the session identifier in the query string (e.g., {{http://localhost:8080/session-inspector?sid=the-session-cookie-here}}).
Here's a screenshot:
[[image:http://parenteses.org/mario/img/awful/session-inspector.png|Awful session inspector]]
When {{enable-session}} is {{#t}} and the {{--development-mode}} option is given to the awful application server, the session inspector is automatically enabled and is avaliable from {{/session-inspector}}.
=== Web REPL
For further run-time, server-side web hacking, awful provides a REPL that you can use via web browser. The activation and control access are basically the same as for the session inspector. The relevant procedure and parameters are:
* {{enable-web-repl}}
* {{web-repl-access-control}}
* {{web-repl-access-denied-message}}
Here's a screenshot:
[[image:http://parenteses.org/mario/img/awful/repl.png|Awful web REPL]]
When the {{--development-mode}} option is given to the awful application server, the web REPL is automatically enabled and is avaliable from {{/web-repl}}.
=== Pages access control
To allow/deny access to pages, you can use the {{page-access-control}} parameter. It's an one-argument procedure (the page path) which can be set to determine if the access to the page is allowed or not.
The example bellow shows a very silly access control to the main page: it only allows the access when the value of the request variable {{user}} is {{"mario"}}:
(use awful)
(enable-session #t)
(define-login-trampoline "/login-trampoline")
(valid-password?
(lambda (user password)
(equal? user password)))
(page-access-control
(lambda (path)
(or (member path `(,(login-page-path) "/login-trampoline")) ;; allow access to login-related pages
(and (equal? ($ 'user) "mario")
(equal? path (main-page-path))))))
(define-page (main-page-path)
(lambda ()
"Hello world"))
(define-page (login-page-path)
(lambda ()
(login-form))
no-session: #t)
You can customize the access denied message by setting the {{page-access-denied-message}} with an one-argument procedure (the page path).
=== Compiled pages
Since Chicken is a compiler and our pages are Chicken code, we can compile them to have faster pages. We just need to compile our app and pass the generated {{.so}} to the {{awful}} application:
$ csc -s hello-world.scm
$ awful hello-world.so
=== Multiple applications support
To be able to deploy multiple awful applications with different configurations under the same server, use Spiffy access files. See Spiffy's [[/egg/spiffy#access-files|access files documentation]] for further details.
=== The awful application server
Awful consists of an application server and an extension module. The awful application server is a command line program whose usage is:
$ awful --help
awful [ -h | --help ]
awful [ -v | --version ]
awful [ --development-mode ] [ --ip-address=
] [ --port= ] [ ... ]
{{ ...}} are files containing code to be loaded by the awful application server.
{{--ip-address}} can be used to bind the web server to the given IP address.
{{--port}} can be used to make the web server listen to the given port.
{{--ip-address}} and {{--port}} take precedence over the Spiffy parameters to specify the server IP address ({{server-bind-address}}) and port ({{server-port}}).
The {{--development-mode}} option is intended to be used during the development of your web application. It's not recommended to run awful with {{--development-mode}} in production. The development mode enables the web REPL and the session inspector (when {{enable-session}} is {{#t}}) for the localhost, prints error messages and backtraces to the client (e.g., web browser) and HTTP server debugging messages to the {{current-error-port}}. It also makes the {{/reload}} path available for reloading awful applications.
When in development mode, the web REPL and the session inspector are available from the {{/web-repl}} and {{/session-inspector}} paths.
If you enable the development mode you can still use {{enable-web-repl}} and {{enable-session-inspector}} to customize their respective paths and access control procedures (although the development mode always allows access to web REPL and session inspector for the localhost).
=== Deploying awful
See the [[/deploying-awful|Deploying Awful]] page on the [[http://wiki.call-cc.org|Chicken Wiki]].
=== List of user configurable parameters
==== Debugging
(debug-file [file path])
If {{#f}}, indicates that debugging should be disabled. When set to a string, it should be the path to the file where the debug messages go (when {{debug}} or {{debug-pp}} is used.)
The default value is {{#f}}.
(debug-db-query? [boolean])
When not {{#f}}, all queries passed to {{$db}} and to {{$db-row-obj}} are printed to the debug file.
The default value is {{#f}}.
(debug-db-query-prefix [string])
Prefix to be used for queries debugging when {{debug-db-query}} is not {{#f}}.
The default value is {{""}}.
(debug-resources [boolean])
When {{#t}}, enables debugging of awful's resources table (an alist mapping paths (or regexes) and vhost paths to their corresponding procedures to be executed on the server side upon request). The debugging data is sent to the file pointed by {{debug-file}}. The default value is {{#f}}.
==== Database
(db-credentials [boolean or list])
Credentials to be used to access the database (see the documentation for the egg corresponding to the database backend you selected.) When {{#f}}, no database access is performed.
The default value is {{#f}}.
==== Ajax
(ajax-library [string])
URL or path to the ajax library (currently only [[http://jquery.com|JQuery]] is supported.)
The default value is {{"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"}}
(enable-ajax [boolean])
When {{#t}}, makes {{define-page}} link the {{ajax-library}} to the generated page. It's effect is global, that is, once {{enable-ajax}} is set to {{#t}}, all pages defined via {{define-page}} will be linked to the ajax library, unless when the {{no-ajax}} keyword parameter is explicitly set.
The default value is {{#f}}
(ajax-namespace [string])
Name to be used as a namespace for ajax URL paths.
The default value is {{"ajax"}}.
(ajax-invalid-session-message [string])
The message to be used when attempting the make an ajax call using an invalid session identifier.
The default value is {{"Invalid session"}}.
==== Sessions
(enable-session [boolean])
When {{#t}}, session support is enabled.
The default value is {{#f}}.
(enable-session-cookie [boolean])
When {{#t}}, awful uses cookies to store the session identifier. Otherwise, the session identifier is passed as a value in the query string or in the request body. The default value is {{#t}}.
(session-cookie-name [string])
The name of the cookie for storing the session identifier. The dafult value is {{"awful-cookie"}}.
==== Access control
(page-access-control [procedure])
An one-argument (URL path of the current page) procedure which tells whether the access to the page is allowed or not.
The default value is {{(lambda (path) #t)}}.
(page-access-denied-message [procedure])
An one-argument (URL path of the current page) procedure which returns the access denied message.
The default value is {{(lambda (path) ( "Access denied."))}}.
(valid-password? [procedure])
A two-argument (user and password) procedure which indicates whether the given password is valid for the given user.
The default value is {{(lambda (user password) #f)}}.
==== Pages
(page-doctype [string])
The doctype (see the [[/egg/doctype|doctype]] egg) to be applied to all pages defined by {{define-page}}. It can be overwritten by {{define-page}}'s {{doctype}} keyword parameter.
The default value is {{""}}.
(page-css [boolean or string])
The CSS file to be linked by all pages defined by {{define-page}}. It can be overwritten by {{define-page}}'s {{css}} keyword parameter. See [[/egg/html-utils|html-utils]]'s {{html-page}} procedure to know about the {{css}} keyword parameter syntax.
The default value is {{#f}} (no CSS).
(page-charset [boolean or string])
The page charset to be used by all pages defined by {{define-page}}. It can be overwritten by {{define-page}}'s {{charset}} keyword parameter.
The default value is {{#f}} (no explicit charset).
(page-template [procedure])
An one-mandatory-argument procedure to be used by {{define-page}} (unless {{define-page}}'s {{no-template}} keyword parameter is set to {{#f}}) to generate HTML pages. Although this procedure can take only one mandatory argument, the following keyword arguments are passed:
* css
* title
* doctype
* headers
* charset
* no-ajax
* no-template
* no-session
* no-db
The default value is {{html-page}} (see the [[/egg/html-utils|html-utils]] egg documentation.)
(page-exception-message [procedure])
An one-argument procedure to be used when an exception occurs while {{define-page}} tries to evaluate its contents.
The default value is {{(lambda (exn) ( "An error has accurred while processing your request."))}}
==== Page paths
(main-page-path [string])
The URL path to the app main page.
The default value is {{"/"}}.
(app-root-path [string])
The base path to be used by the application. All the pages defined by {{define-page}} will use {{app-root-path}} as the base directory. For example, if {{app-root-path}} is set to {{"/my-app"}} and {{"my-page"}} is used as first argument to {{define-page}}, the page would be available at {{http://:/my-app/my-page}}.
The default value is {{"/"}}.
(login-page-path [string])
The URL path for the login page. When creating a login page, be sure to set the {{no-session}} keyword parameter for {{define-page}} to {{#t}}, otherwise you'll get an endless loop.
The default value is {{"/login"}}.
==== Headers
(awful-response-headers [alist])
An alist to specify the headers to be used in the response. If the {{content-length}} header is not provided, awful will calculate it automatically.
Here's an example:
#!/usr/bin/awful
(use awful)
(define (define-json path body)
(define-page path
(lambda ()
(awful-response-headers '((content-type "text/json")))
(body))
no-template: #t))
(define-json (main-page-path)
(lambda ()
"{a: 1}"))
==== Web REPL
(web-repl-access-control [procedure])
A no-argument procedure to control access to the web REPL.
The default value is {{(lambda () #f)}}.
(web-repl-access-denied-message [string])
Message to be printed when the access to the web REPL is denied.
The default value is {{( "Access denied.")}}.
==== Session inspector
(session-inspector-access-control [procedure])
A no-argument procedure to control access to the session inspector.
The default value is {{(lambda () #f)}}.
(session-inspector-access-denied-message [string])
Message to be printed when the access to the session inspector is denied.
The default value is {{( "Access denied.")}}.
==== Javascript
(enable-javascript-compression [boolean])
Enable javascript compression support. When enabled the compressor set by {{javascript-compressor}} is used.
The default value is {{#f}}.
(javascript-compressor [procedure])
An one-argument procedure (the javascript code) which return the given javascript code compressed. Only used when {{enable-javascript-compression}} is not {{#f}}.
The default value is the {{identity}} procedure.
A possible value for {{javascript-compressor}} is {{jsmin-string}} (see the [[/egg/jsmin|jsmin]] egg.)
=== List of read-only parameters available to users
Note: these parameters should not be explicitly set and when their use is needed, it's a string sign you're doing something you shouldn't (except for {{db-connection}}, which can be used by procedures from the [[/egg/postgresql|postgresql]] egg API).
(http-request-variables)
The per-request value returned by [[/egg/spiffy-request-vars|spiffy-request-vars]]'s {{request-vars}}.
(db-connection)
A per-request databaseconnection object. The connection is automatically opened and closed by awful in a per-request basis (unless databases are not being used the {{no-db}} keyword parameter for {{define-page}} is {{#t}}.)
(page-javascript)
Javascript code to be added to the pages defined by {{define-page}}.
(sid)
The session identifier.
(awful-apps)
The list of awful applications, as given to the awful server when invoked from the command line.
(development-mode?)
Indicates whether awful is running in development mode (see the {{--development-mode}} command line option for the awful application server).
=== List of procedures
==== Miscelaneous
(++ string1 string2 ... stringn)
A shortcut to {{string-append}}.
(concat args #!optional (sep ""))
Convert {{args}} to string and intersperse the resulting strings with {{sep}}.
(awful-version)
Return the awful version (a string).
==== Javascript
(include-javascript file)
A shortcut to {{(