source: project/wiki/eggref/4/awful @ 25607

Last change on this file since 25607 was 25607, checked in by Mario Domenech Goulart, 9 years ago

awful (wiki): fixed links to screencasts

  • Property svnwiki:tags set to web awful
  • Property svnwiki:title set to Awful
File size: 89.2 KB
Line 
1== Awful
2
3[[toc:]]
4
5=== Description
6
7awful provides an application and an extension to ease the development of web-based applications.
8
9Here's a short summary of awful features:
10
11* Straightforward interface to databases (currently supported are postgresql and sqlite3)
12* Support for page dispatching via regular expressions
13* Easy access to query string and body request variables from HTTP requests
14* Ajax support via [[http://jquery.com/|JQuery]]
15* Reasonably flexible (several configuration parameters)
16* Compiled pages made easy
17* Session inspector
18* Web REPL
19
20==== Screencasts
21
22Here are some screencasts about awful:
23
24; [[http://parenteses.org/mario/awful/awful.ogv|Awful in 35s]] : a 35 seconds video showing the installation of the awful egg and the development of a "hello, world" example
25
26; [[http://parenteses.org/mario/awful/awful-guess.ogv|Number guessing game]] : a video demonstrating the development of a very simple number guessing game using ajax and the web REPL
27
28
29=== Author
30
31[[/users/mario-domenech-goulart|Mario Domenech Goulart]]
32
33
34=== Requirements
35
36The following eggs are required:
37
38* [[/egg/spiffy|spiffy]]
39* [[/egg/spiffy-cookies|spiffy-cookies]]
40* [[/egg/spiffy-request-vars|spiffy-request-vars]]
41* [[/egg/html-tags|html-tags]]
42* [[/egg/html-utils|html-utils]]
43* [[/egg/json|json]]
44* [[/egg/http-session|http-session]]
45
46
47=== Components
48
49awful is composed by two parts: an application, which can be thought as a web server; and an extension, which provides most of the supported features.
50
51
52=== A "Hello, world!" example
53
54Here's a "Hello, world!" example to be run by awful ({{hello-world.scm}}).
55
56<enscript highlight=scheme>
57(use awful)
58
59(define-page (main-page-path)
60  (lambda ()
61    "Hello, world!"))
62</enscript>
63
64To run this example, execute:
65
66  $ awful hello-world.scm
67
68Then access localhost:8080 using your favourite web browser.
69
70Without any configuration, awful listens on port 8080.  Since awful
71uses Spiffy behind the scenes, you can configure the web server
72parameters using Spiffy's.
73
74{{define-page}} is the primitive procedure to define pages.  In the
75simplest case, it takes as arguments a path to the page and a
76procedure to generate the page contents. The path to the page you use
77as the first argument is the same to be used as the path part of the
78URL you use to access the page.
79
80In the example we use the {{main-page-path}} parameter, which is one
81of the awful configuration parameters.  The default is {{"/"}}.
82
83If you look at the page source code, you'll see that awful created an
84HTML page for you.  Awful uses the [[/egg/html-utils|html-tags]]'s
85{{html-page}} procedure behind the scenes.  You can customize the page
86either by passing {{html-page}}'s keyword parameters to
87{{define-page}} or by setting the {{page-template}} parameter with
88your favourite procedure to generate pages. {{page-template}} is a
89one-mandatory-argument procedure which receives the page contents and
90returns a string representing the formatted contents. {{define-page}}
91would still pass the {{html-page}} keyword parameters, so you can make
92use of them (the {{page-template}} procedure should be defined
93considering them -- if you don't need them, just ignore them by
94defining {{(lambda (contents . args) ...)}}).
95
96You can also use some global page-related parameters if all pages use
97the same CSS, doctype and charset ({{page-css}}, {{page-doctype}} and
98{{page-charset}}, respectively).
99
100
101An alternative way to write Awful '''scripts''' is by using the
102{{#!/path/to/awful}} shebang line.  Example:
103
104<enscript highlight=scheme>
105#! /usr/bin/awful
106
107(use awful)
108
109(define-page (main-page-path)
110  (lambda ()
111    "Hello, world!"))
112</enscript>
113
114Then you just need to run your script (assuming the file has execution
115permissions):
116
117  $ ./hello-world.scm
118
119
120=== Accessing request variables
121
122Awful provides a procedure ({{$}}) to access variables from the
123request, both from the query string (GET method) and from the request
124body (e.g., POST method).
125
126Here's a modified "Hello, world!" example to greet some person instead
127of the whole world:
128
129<enscript highlight=scheme>
130(use awful)
131
132(define-page (main-page-path)
133  (lambda ()
134    (++ "Hello, " ($ 'person "world") "!")))
135</enscript>
136
137The {{++}} procedure is an alias to {{string-append}} (name inspired
138by Haskell's operator to concatenate strings).
139
140So, restart the web server to reload the code, then access the main
141page using an argument, represented by the {{person}} query string
142variable: {{http://localhost:8080/?person=Mario}}. You'll see a page
143showing {{Hello, Mario!}}.
144
145
146=== Re-evaluating the code by reloading the page
147
148When we upgraded our "Hello, world!" example to the improved one which
149can use an argument passed through the URL, we needed to modify the
150code and restart the web server to reload the application code.  Awful
151provides a way to reload the code via URL without restarting the
152server.  To do that, we can define a special page whose handler just
153reloads the code:
154
155<enscript highlight=scheme>
156(use awful)
157
158(define-page "/reload"
159  (lambda ()
160    (reload-apps (awful-apps))
161    "Reloaded"))
162</enscript>
163
164and restart the awful server.  Now, whenever you want to reload the
165application code, access {{http://localhost:8080/reload}}.
166
167You can control which IP numbers can access the reload page by using
168the {{page-access-control}} parameter.  For example, allowing only the
169localhost to reload the apps:
170
171<enscript highlight=scheme>
172(use awful spiffy)
173
174(page-access-control
175 (lambda (path)
176   (if (equal? path "/reload")
177       (member (remote-address) '("127.0.0.1"))
178       #t)))
179</enscript>
180
181When used in development mode (see the {{--development-mode}} command
182line option for the awful application server), awful automatically
183defines a {{/reload}} path (available to any host) for reloading all
184the applications.
185
186
187=== Using ajax
188
189Awful provides a way to (hopefully) make the use of ajax
190straightforward for web applications.
191
192By default, the ajax support is disabled, but it can be easily
193globally enabled by setting the {{enable-ajax}} parameter to {{#t}}.
194When you enable ajax via {{enable-ajax}}, all the pages defined via
195{{define-page}} will be linked to the JQuery javascript library. If
196you want just a couple of pages to have ajax support (i.e., not global
197ajax support), you can use the {{use-ajax}} keyword parameter for
198{{define-page}}, so only the pages defined with {{use-ajax: #t}} have
199ajax support.
200
201When you have ajax enabled and you want to disable it for specific
202pages, you can pass {{#f}} as the value for the {{define-page}}
203keyword parameter {{no-ajax}}.
204
205The URL of the JQuery file can be customized by setting the
206{{ajax-library}} parameter (the default is Google's API JQuery file).
207
208So, if we now change our code to
209
210<enscript highlight=scheme>
211(use awful)
212
213(define-page (main-page-path)
214  (lambda ()
215    (++ "Hello, " ($ 'person "world") "!"))
216  use-ajax: #t)
217</enscript>
218
219and reload the application, we'll have our page linked to JQuery.
220
221Awful provides some procedures to do ajax.  We start by the more
222generic one ({{ajax}}) to reply the page greetings when we click
223"Hello, <person>!".
224
225<enscript highlight=scheme>
226(use awful html-tags)
227
228(define-page (main-page-path)
229  (lambda ()
230    (ajax "greetings" 'greetings 'click
231          (lambda ()
232            (<b> "Hello, awful!"))
233          target: "greetings-reply")
234    (++ (<a> href: "#"
235             id: "greetings"
236             (++ "Hello, " ($ 'person "world") "!"))
237        (<div> id: "greetings-reply")))
238  use-ajax: #t)
239</enscript>
240
241The {{ajax}} procedure uses at least four arguments:
242
2431. The URL path to the server-side handler (a string).  This path is relative to {{ajax-namespace}} parameter (default is {{ajax}}.  So, in the example, we'll have {{/ajax/greetings}} as the ajax path to be generated if we pass {{ajax}} as the first argument.
244
2452. The ID of the DOM element to observe.
246
2473. The event to be handled
248
2494. The procedure to be run on the server-side.
250
251So, in the example, {{ajax}} will bind the fourth argument (the
252procedure) to the first argument (the path) on the server side. Then
253it will add javascript code to the page in order to wait for click
254events for the element of ID {{greetings}}.  When we click "Hello,
255<person>!", we'll get {{Hello, awful!}} printed on the page as reply.
256{{ajax}} updates the DOM element whose id is the value of the
257{{target}} keyword parameter ({{"greetings-reply"}}, in the example).
258
259For the very specific case of creating links that execute server side
260code when clicked, awful provides the {{ajax-link}} procedure.  So our
261example could be coded like:
262
263<enscript highlight=scheme>
264(use awful)
265
266(define-page (main-page-path)
267  (lambda ()
268    (++ (ajax-link "greetings" 'greetings
269                   (lambda ()
270                     (<b> "Hello, awful!"))
271                   target: "greetings-reply")
272        (<div> id: "greetings-reply")))
273  use-ajax: #t)
274</enscript>
275
276
277
278=== Adding arbitrary javascript code to pages
279
280Awful provides a procedure which can be used to add arbitrary
281javascript code to the page. It's called {{add-javascript}}.  Here's
282an example using javascript's {{alert}} and our "Hello, world!"
283example:
284
285<enscript highlight=scheme>
286(use awful)
287
288(define-page (main-page-path)
289  (lambda ()
290    (add-javascript "alert('Hello!');")
291    (++ (ajax-link "greetings" 'greetings
292                   (lambda ()
293                     (<b> "Hello, awful!"))
294                   target: "greetings-reply")
295        (<div> id: "greetings-reply")))
296  use-ajax: #t)
297</enscript>
298
299
300
301=== Database access
302
303To access databases, you need some of the awful eggs which provide
304database access.  Currently, these are the possible options:
305
306* [[/egg/awful-postgresql|awful-postgresql]] (for Postgresql databases, using the [[/egg/postgresql|postgresql]] egg)
307
308* [[/egg/awful-sqlite3|awful-sqlite3]] (for Sqlite3 databases, using the [[/egg/sqlite3|sqlite3]] egg)
309* [[/egg/awful-sql-de-lite|awful-sql-de-lite]] (for Sqlite3 databases, using the [[/egg/sql-de-lite|sql-de-lite]] egg)
310
311As with ajax, database access is not enabled by default.  To enable
312it, you need to pick one the awful database support eggs and call the
313{{enable-db}} procedure.  Since version 0.10, and differently from the
314{{enable-*}} parameters, {{enable-db}} is a zero-argument procedure
315provided by each of awful database-support eggs.  So, if you use
316{{awful-postgresql}}, the {{enable-db}} procedure will automatically
317set up awful to use a postgresql database.
318
319Additionally, to access the db, you need to provide the credentials.
320You can provide the credentials by setting the {{db-credentials}}
321parameter.  See the documentation for the eggs corresponding to the
322database type you are using ([[/egg/postgresql|postgresql]] for
323Postgresql and [[/egg/sqlite3|sqlite3]] or
324[[/egg/sql-de-lite|sql-de-lite]] for Sqlite3.)
325
326To actually query the database, there's the {{$db}} procedure, which
327uses as arguments a string representing the query and, optionally, a
328default value (a keyword parameter) to be used in case the query
329doesn't return any result. {{$db}} returns a list of lists. Below is
330an usage example:
331
332<enscript highlight=scheme>
333(use awful awful-postgresql)
334
335(enable-db)
336(db-credentials '((dbname . "my-db")
337                  (user . "mario")
338                  (password . "secret")
339                  (host . "localhost")))
340
341(define-page "db-example"
342  (lambda ()
343    (with-output-to-string
344      (lambda ()
345        (pp ($db "select full_name, phone from users"))))))
346</enscript>
347
348''Hint'': for Sqlite3 databases, {{db-credentials}} should be the path
349to the database file.
350
351There's also the {{$db-row-obj}} procedure for when you want to access
352the results of a query by row name.  {{$db-row-obj}} returns a
353procedure of two arguments: the name of the field and, optionally, a
354default value to be used in case the field value is {{#f}}.
355
356<enscript highlight=scheme>
357(define-page "db-example"
358  (lambda ()
359    (let ((& ($db-row-obj "select full_name, phone from users where user_id=1")))
360      (<p> "Full name: " (& 'full_name))
361      (<p> "Phone: " (& 'phone)))))
362</enscript>
363
364''Warning'': currently {{$db-row-obj}} is only implemented for Postgresql.
365
366If you need more flexibility to query the database, you can always use
367the {{(db-connection}}) parameter to get the database connection
368object and use it with the procedures available from the your favorite
369database egg API.
370
371
372=== Login pages and session
373
374Awful provides a very basic (awful?) support for creating
375authentication pages.
376
377The basic things you have to do is:
378
3791. Enable the use of sessions:
380
381<enscript highlight=scheme>
382(enable-session #t)
383</enscript>
384
3852. 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:
386
387<enscript highlight=scheme>
388(valid-password?
389  (lambda (user password)
390    (equal? user password)))
391</enscript>
392
3933. Define a login trampoline, which is an intermediate page accessed when redirecting from the login page to the main page.
394
395<enscript highlight=scheme>
396(define-login-trampoline "/login-trampoline")
397</enscript>
398
3994. 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).
400
401<enscript highlight=scheme>
402(use awful)
403
404(enable-session #t)
405
406(define-login-trampoline "/login-trampoline")
407
408(valid-password?
409  (lambda (user password)
410    (equal? user password)))
411
412(define-page (main-page-path)
413  (lambda ()
414    "Hello world!"))
415
416(define-page (login-page-path)
417  (lambda ()
418    (login-form))
419  no-session: #t)
420</enscript>
421
422That's the very basic we need to set an auth page.  If the password is
423valid for the given user, awful will perform a redirect to the main
424page ({{main-page-path}} parameter) passing the {{user}} variable and
425its value in the query string .  If the password is not valid, awful
426will redirect to the login page ({{login-page-path}} parameter) and
427pass the following variables and values:
428
429; {{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).
430
431; {{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.
432
433; {{user}} : the user used for the form user field.
434
435Now we're gonna change our main page to store the user in the session
436and retrieve it to make the greetings message:
437
438<enscript highlight=scheme>
439(define-page (main-page-path)
440  (lambda ()
441    ($session-set! 'user ($ 'user))
442    (++ "Hello " ($session 'user "world") "!")))
443</enscript>
444
445Here we can see the two procedures to access the session: {{$session}}
446and {{$session-set!}}.
447
448{{$session-set!}} accepts two arguments: the first one is the name of
449the session variable and the second one is its value.
450
451{{$session}} takes the name of the session variable as argument and
452returns its session value.  We can optionally use a second argument to
453specify a default value, in case the session variable is not bound or
454is {{#f}}.
455
456
457=== Session inspector
458
459Awful provides a session inspector, so we can easily see the session
460contents for a given session identifier.  By default, the session
461inspector is disabled.  We can enabled it using the
462{{enable-session-inspector}} procedure, passing the session inspector
463URL path as argument:
464
465<enscript highlight=scheme>
466(enable-session-inspector "session-inspector")
467</enscript>
468
469Now, if you log in and try to access
470{{http://localhost:8080/session-inspector}}, you'll get ... an access
471denied page.
472
473Awful provides a way to control access to the session inspector
474({{session-inspector-access-control}} parameter).  The
475{{session-inspector-access-control}} parameter is an one-argument
476procedure which returns {{#f}} or some other value to indicate whether
477the access to the session inspector is allowed or not. By default, it
478blocks all access.  Let's configure it so we can access the session
479inspector from the local machine (whose IP number is 127.0.0.1):
480
481<enscript highlight=scheme>
482(session-inspector-access-control
483 (lambda ()
484   (member (remote-address) '("127.0.0.1"))))
485</enscript>
486
487Regarding to the access denied message, you can customize it by
488setting the {{session-inspector-access-denied-message}}.
489
490Now we can access {{http://localhost:8080/session-inspector}} and see
491the session contents.
492
493''Note'': if {{enable-session-cookie}} is {{#f}}, you need to pass the
494session identifier in the query string (e.g.,
495{{http://localhost:8080/session-inspector?sid=the-session-cookie-here}}).
496
497Here's a screenshot:
498
499[[image:http://parenteses.org/mario/img/awful/session-inspector.png|Awful session inspector]]
500
501When {{enable-session}} is {{#t}} and the {{--development-mode}}
502option is given to the awful application server, the session inspector
503is automatically enabled and is avaliable from {{/session-inspector}}.
504
505=== Web REPL
506
507For further run-time, server-side web hacking, awful provides a REPL
508that you can use via web browser.
509
510The web REPL can use either a plain HTML textarea for the input area
511or a more featureful editor (based on
512[[http://codemirror.net|codemirror]]).  By default, the web REPL uses
513the ''fancy'' editor.
514
515The activation and control access are basically the same as for the
516session inspector.  The relevant procedure and parameters are:
517
518* {{enable-web-repl}}
519* {{web-repl-access-control}}
520* {{web-repl-access-denied-message}}
521* {{enable-web-repl-fancy-editor}}
522* {{web-repl-fancy-editor-base-uri}}
523
524Here's a screenshot (using the fancy editor):
525
526[[image:http://parenteses.org/mario/img/awful/fancy-web-repl.png|Awful web REPL]]
527
528When the {{--development-mode}} option is given to the awful
529application server, the web REPL is automatically enabled and is
530avaliable from {{/web-repl}}. The awful application server also
531accepts the {{--disable-web-repl-fancy-editor}} command line option to
532disable the web REPL fancy editor.
533
534
535=== Pages access control
536
537To allow/deny access to pages, you can use the {{page-access-control}}
538parameter.  It's an one-argument procedure (the page path) which can
539be set to determine if the access to the page is allowed or not.
540
541The example bellow shows a very silly access control to the main page:
542it only allows the access when the value of the request variable
543{{user}} is {{"mario"}}:
544
545<enscript highlight=scheme>
546(use awful)
547
548(enable-session #t)
549
550(define-login-trampoline "/login-trampoline")
551
552(valid-password?
553 (lambda (user password)
554   (equal? user password)))
555
556(page-access-control
557 (lambda (path)
558   (or (member path `(,(login-page-path) "/login-trampoline")) ;; allow access to login-related pages
559       (and (equal? ($ 'user) "mario")
560            (equal? path (main-page-path))))))
561
562(define-page (main-page-path)
563  (lambda ()
564    "Hello world"))
565
566(define-page (login-page-path)
567  (lambda ()
568    (login-form))
569  no-session: #t)
570</enscript>
571
572You can customize the access denied message by setting the
573{{page-access-denied-message}} with an one-argument procedure (the
574page path).
575
576
577=== Compiled pages
578
579Since Chicken is a compiler and our pages are Chicken code, we can
580compile them to have faster pages.  We just need to compile our app
581and pass the generated {{.so}} to the {{awful}} application:
582
583  $ csc -s hello-world.scm
584  $ awful hello-world.so
585
586
587
588=== Multiple applications support
589
590Parameters are thread-safe, but [[/egg/spiffy|Spiffy]] (the web server
591used by awful) doesn't garantee that each request will be handled by a
592different thread, so awful has to provide a way to overcome that,
593otherwise hosting multiple applications under the same virtual host
594can be very painful, since it's not guaranteed that parameters will be
595reset at each request (awful does reset some critical and obviously
596per-request ones like {{http-request-variables}},
597{{awful-response-headers}}, {{db-connection}} and {{sid}}).
598
599Awful provides the possibility of running hooks when handling
600requests, so you can set parameters for multiple applications in a way
601that they don't interfere with others.
602
603See the documentation for
604[[/egg/awful#add-request-handler-hook|{{add-request-handler-hook!}}]]
605for an example about how to do that.
606=== The awful application server
607
608Awful consists of an application server and an extension module.  The awful application server is a command line program whose usage is:
609
610 $ awful --help
611 awful [ -h | --help ]
612 awful [ -v | --version ]
613 awful [ --development-mode ] [ --disable-web-repl-fancy-editor ] [ --ip-address=<ip address> ] [ --port=<port number> ] [ <app1> <app2> ... ]
614
615{{<app1> <app2> ...}} are files containing code to be loaded by the awful application server.
616
617{{--ip-address}} can be used to bind the web server to the given IP address.
618
619{{--port}} can be used to make the web server listen to the given port.
620
621{{--ip-address}} and {{--port}} take precedence over the Spiffy parameters to specify the server IP address ({{server-bind-address}}) and port ({{server-port}}).
622
623The {{--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.
624
625When in development mode, the web REPL and the session inspector are available from the {{/web-repl}} and {{/session-inspector}} paths.
626
627If 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).
628
629The {{--disable-web-repl-fancy-editor}} command line option disables the web REPL fancy editor.
630
631The {{--privileged-code}} command line options specify code to be run in privileged mode, for the cases when you specify a user/group to run the server ({{spiffy-user}}/{{spiffy-group}}).  In this case, you usually run awful as a user with administrator privileges (e.g., {{root}} in Unix[-like] systems) and spiffy switches to the specified user/group.  To make things clearer, let's take a look at awful's workflow:
632
633         |
634         v
635 load privileged code
636         |
637         v
638      listen
639         |
640         v
641  switch user/group
642         |
643         v
644  load applications
645         |
646         v
647       accept
648         |
649         v
650
651As you can see, the privileged code is loaded and evaluated '''before''' switching user/group.  So, if you run awful with administrator privileges, the privileged code will the loaded with administrator privileges.  Running code with administrator privileges is usually not recommended, but it is necessary if you want, for example, to specify the user and group to switch to before acceting connections. So, the {{--privileged-code}} command line option should be used strictly to specify code which must be run with administrator privileges (like specifying server user/group and [[/egg/awful-ssl|enabling SSL]], for example).
652
653The privileged code is '''not''' reloaded when you reload applications via a defined reload page.
654
655=== Deploying Awful
656
657Here are some tips about how to deploy awful on your system.
658
659
660==== On Unix[-like] systems
661
662Create a user for running awful.  For example, on GNU/Linux systems,
663you can use the adduser program:
664
665  # adduser --system --no-create-home --disabled-password --disabled-login --group awful
666
667This will create a user and a group called {{awful}}.
668
669
670Create a directory for the awful configuration file:
671
672  # mkdir /etc/awful
673
674
675Create a directory for log files:
676
677  # mkdir /var/log/awful
678
679Create a directory for static files:
680
681  # mkdir /var/www/awful
682
683You may also want to create a directory for your awful applications:
684
685  # mkdir /var/lib/awful
686
687
688Create configuration files for awful.  In the privileged configuration
689file ({{privileged.conf}} below) you can set all the configuration
690parameters for awful and spiffy which require administrator
691provileges.
692
693In another file ({{awful.conf}} below) you can put whatever code which
694does not need administrator provileges.
695
696Here's some example configuration for awful listening on port 80
697(strictly speaking, [[/egg/spiffy|spiffy]] -- the actual web server --
698listens on this port):
699
700===== privileged.conf
701
702<enscript highlight=scheme>
703;; -*- scheme -*-
704
705(use spiffy awful)
706(spiffy-user "awful")
707(server-port 80)
708(root-path "/var/www/awful")
709(debug-log "/var/log/awful/debug.log")
710(error-log "/var/log/awful/error.log")
711</enscript>
712
713
714===== awful.conf
715<enscript highlight=scheme>
716(load "/var/lib/awful/my-app") ;; if you don't use file suffixes, Chicken will
717                               ;; pick .so files when you compile your apps
718</enscript>
719
720
721Set the permissions for the configuration, log, static files and awful
722applications directories:
723
724  # chown -R awful:awful /etc/awful /var/log/awful /var/www/awful /var/lib/awful
725
726
727Set up an init script for your system.  Basically, it should call
728
729  /usr/bin/awful --privileged-code=/etc/awful/privileged.conf /etc/awful/awful.conf &> /var/log/awful/init.log &
730
731If awful doesn't start, take a look at {{/var/log/awful/init.log}}
732
733You can find an [[http://anonymous@code.call-cc.org/svn/chicken-eggs/release/4/awful/extra/awful-debian-init|init script]] for [[http://www.debian.org|Debian]] systems (or derivatives, like [[http://www.ubuntulinux.com|Ubuntu]]) at the [[http://anonymous@code.call-cc.org/svn/chicken-eggs/release/4/awful/trunk|awful source repository]].  Here are the steps to install it:
734
735  # cd /etc/init.d
736  # wget --user=anonymous --password='' http://code.call-cc.org/svn/chicken-eggs/release/4/awful/extra/awful-debian-init -O awful
737  # chmod 755 awful
738  # update-rc.d awful defaults
739
740There's also an [[http://anonymous@code.call-cc.org/svn/chicken-eggs/release/4/awful/extra/awful-gentoo-init|init script for Gentoo]] (by [[/users/david-krentzlin|David Krentzlin]]).
741
742=== Awful & SSL
743
744To make awful serve pages using SSL, see the documentation for the [[/egg/awful-ssl|awful-ssl]] egg.
745=== List of user configurable parameters
746
747==== Debugging (parameters)
748
749===== {{debug-file}}
750<parameter>(debug-file [file path])</parameter>
751
752If {{#f}}, indicates that debugging should be disabled.  When set to a
753string, it should be the path to the file where the debug messages go
754(when {{debug}} or {{debug-pp}} is used.)
755
756The default value is {{#f}}.
757
758
759===== {{debug-db-query?}}
760<parameter>(debug-db-query? [boolean])</parameter>
761
762When not {{#f}}, all queries passed to {{$db}} and to {{$db-row-obj}}
763are printed to the debug file.
764
765The default value is {{#f}}.
766
767
768===== {{debug-db-query-prefix}}
769<parameter>(debug-db-query-prefix [string])</parameter>
770
771Prefix to be used for queries debugging when {{debug-db-query}} is not
772{{#f}}.
773
774The default value is {{""}}.
775
776
777===== {{debug-resources}}
778<parameter>(debug-resources [boolean])</parameter>
779
780When {{#t}}, enables debugging of awful's resources table (an alist
781mapping paths (or regexes) and vhost paths to their corresponding
782procedures to be executed on the server side upon request).  The
783debugging data is sent to the file pointed by {{debug-file}}.  The
784default value is {{#f}}.
785
786
787==== Database (parameters)
788
789===== {{db-credentials}}
790<parameter>(db-credentials [boolean or list])</parameter>
791
792Credentials to be used to access the database (see the documentation
793for the egg corresponding to the database backend you selected.)  When
794{{#f}}, no database access is performed.
795
796The default value is {{#f}}.
797
798
799==== Ajax (parameters)
800
801===== {{ajax-library}}
802<parameter>(ajax-library [string])</parameter>
803
804URL or path to the ajax library (currently only
805[[http://jquery.com|JQuery]] is supported.)
806
807The default value is
808{{"http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"}}
809
810
811===== {{enable-ajax}}
812<parameter>(enable-ajax [boolean])</parameter>
813
814When {{#t}}, makes {{define-page}} link the {{ajax-library}} to the
815generated page.  It's effect is global, that is, once {{enable-ajax}}
816is set to {{#t}}, all pages defined via {{define-page}} will be linked
817to the ajax library, unless when the {{no-ajax}} keyword parameter is
818explicitly set.
819
820The default value is {{#f}}
821
822
823===== {{ajax-namespace}}
824<parameter>(ajax-namespace [string])</parameter>
825
826Name to be used as a namespace for ajax URL paths.
827
828The default value is {{"ajax"}}.
829
830
831===== {{ajax-invalid-session-message}}
832<parameter>(ajax-invalid-session-message [string])</parameter>
833
834The message to be used when attempting the make an ajax call using an
835invalid session identifier.
836
837The default value is {{"Invalid session"}}.
838
839
840
841==== Sessions (parameters)
842
843===== {{enable-session}}
844<parameter>(enable-session [boolean])</parameter>
845
846When {{#t}}, session support is enabled.
847
848The default value is {{#f}}.
849
850
851===== {{enable-session-cookie}}
852<parameter>(enable-session-cookie [boolean])</parameter>
853
854When {{#t}}, awful uses cookies to store the session identifier.
855Otherwise, the session identifier is passed as a value in the query
856string or in the request body. The default value is {{#t}}.
857
858
859===== {{session-cookie-name}}
860<parameter>(session-cookie-name [string])</parameter>
861
862The name of the cookie for storing the session identifier.  The dafult
863value is {{"awful-cookie"}}.
864
865
866==== Access control (parameters)
867
868===== {{page-access-control}}
869<parameter>(page-access-control [procedure])</parameter>
870
871An one-argument (URL path of the current page) procedure which tells
872whether the access to the page is allowed or not.
873
874The default value is {{(lambda (path) #t)}}.
875
876
877===== {{page-access-denied-message}}
878<parameter>(page-access-denied-message [procedure])</parameter>
879
880An one-argument (URL path of the current page) procedure which returns
881the access denied message.
882
883The default value is {{(lambda (path) (<h3> "Access denied."))}}.
884
885
886===== {{valid-password?}}
887<parameter>(valid-password? [procedure])</parameter>
888
889A two-argument (user and password) procedure which indicates whether
890the given password is valid for the given user.
891
892The default value is {{(lambda (user password) #f)}}.
893
894
895==== Pages (parameters)
896
897===== {{page-doctype}}
898<parameter>(page-doctype [string])</parameter>
899
900The doctype (see the [[/egg/doctype|doctype]] egg) to be applied to
901all pages defined by {{define-page}}.  It can be overwritten by
902{{define-page}}'s {{doctype}} keyword parameter.
903
904The default value is {{""}}.
905
906
907===== {{page-css}}
908<parameter>(page-css [boolean or string])</parameter>
909
910The CSS file to be linked by all pages defined by {{define-page}}.  It
911can be overwritten by {{define-page}}'s {{css}} keyword parameter.
912See [[/egg/html-utils|html-utils]]'s {{html-page}} procedure to know
913about the {{css}} keyword parameter syntax.
914
915The default value is {{#f}} (no CSS).
916
917
918===== {{page-charset}}
919<parameter>(page-charset [boolean or string])</parameter>
920
921The page charset to be used by all pages defined by {{define-page}}.
922It can be overwritten by {{define-page}}'s {{charset}} keyword
923parameter.
924
925The default value is {{#f}} (no explicit charset).
926
927
928===== {{page-template}}
929<parameter>(page-template [procedure])</parameter>
930
931An one-mandatory-argument procedure to be used by {{define-page}}
932(unless {{define-page}}'s {{no-template}} keyword parameter is set to
933{{#f}}) to generate HTML pages. Although this procedure can take only
934one mandatory argument, the following keyword arguments are passed:
935
936* css
937* title
938* doctype
939* headers
940* charset
941* no-ajax
942* no-template
943* no-session
944* no-db
945
946The default value is {{html-page}} (see the
947[[/egg/html-utils|html-utils]] egg documentation.)
948
949
950===== {{page-exception-message}}
951<parameter>(page-exception-message [procedure])</parameter>
952
953An one-argument procedure to be used when an exception occurs while
954{{define-page}} tries to evaluate its contents.
955
956The default value is {{(lambda (exn) (<h3> "An error has accurred while processing your request."))}}
957
958
959
960==== Page paths (parameters)
961
962===== {{main-page-path}}
963<parameter>(main-page-path [string])</parameter>
964
965The URL path to the app main page.
966
967The default value is {{"/"}}.
968
969
970===== {{app-root-path}}
971<parameter>(app-root-path [string])</parameter>
972
973The base path to be used by the application.  All the pages defined by
974{{define-page}} will use {{app-root-path}} as the base directory.  For
975example, if {{app-root-path}} is set to {{"/my-app"}} and
976{{"my-page"}} is used as first argument to {{define-page}}, the page
977would be available at {{http://<server>:<port>/my-app/my-page}}.
978
979The default value is {{"/"}}.
980
981'''Important''': this parameter is evaluated both at page definition
982time and page request handling time.
983
984
985===== {{login-page-path}}
986<parameter>(login-page-path [string])</parameter>
987
988The URL path for the login page.  When creating a login page, be sure
989to set the {{no-session}} keyword parameter for {{define-page}} to
990{{#t}}, otherwise you'll get an endless loop.
991
992The default value is {{"/login"}}.
993
994
995
996==== Headers (parameters)
997
998===== {{awful-response-headers}}
999<parameter>(awful-response-headers [alist])</parameter>
1000
1001An alist to specify the headers to be used in the response.  If the
1002{{content-length}} header is not provided, awful will calculate it
1003automatically.
1004
1005Here's an example:
1006
1007<enscript highlight=scheme>
1008(use awful)
1009
1010(define (define-json path body)
1011  (define-page path
1012    (lambda ()
1013      (awful-response-headers '((content-type "text/json")))
1014      (body))
1015    no-template: #t))
1016
1017
1018(define-json (main-page-path)
1019  (lambda ()
1020    "{a: 1}"))
1021</enscript>
1022
1023
1024
1025==== Web REPL (parameters)
1026
1027===== {{web-repl-access-control}}
1028<parameter>(web-repl-access-control [procedure])</parameter>
1029
1030A no-argument procedure to control access to the web REPL.
1031
1032The default value is {{(lambda () #f)}}.
1033
1034
1035===== {{web-repl-access-denied-message}}
1036<parameter>(web-repl-access-denied-message [string])</parameter>
1037
1038Message to be printed when the access to the web REPL is denied.
1039
1040The default value is {{(<h3> "Access denied.")}}.
1041
1042
1043===== {{enable-web-repl-fancy-editor}}
1044<parameter>(enable-web-repl-fancy-editor [boolean])</parameter>
1045
1046Indicates whether the web REPL should use a fancier editor for the
1047input area.  The editor is based on
1048[[http://codemirror.net|codemirror]].  Without the fancy editor, the
1049input area is a simple HTML textarea.  The default value for
1050{{use-fancy-editor}} is {{#t}}.
1051
1052
1053===== {{web-repl-fancy-editor-base-uri}}
1054<parameter>(web-repl-fancy-editor-base-uri [string])</parameter>
1055
1056The URI which indicates the fancy editor source files (javascript and
1057CSS) location.  The default value is
1058{{http://parenteses.org/awful/codemirror}}.
1059
1060
1061
1062==== Session inspector (parameters)
1063
1064===== {{session-inspector-access-control}}
1065<parameter>(session-inspector-access-control [procedure])</parameter>
1066
1067A no-argument procedure to control access to the session inspector.
1068
1069The default value is {{(lambda () #f)}}.
1070
1071
1072===== {{session-inspector-access-denied-message}}
1073<parameter>(session-inspector-access-denied-message [string])</parameter>
1074
1075Message to be printed when the access to the session inspector is denied.
1076
1077The default value is {{(<h3> "Access denied.")}}.
1078
1079
1080==== Javascript (parameters)
1081
1082===== {{enable-javascript-compression}}
1083<parameter>(enable-javascript-compression [boolean])</parameter>
1084
1085Enable javascript compression support.  When enabled the compressor
1086set by {{javascript-compressor}} is used.
1087
1088The default value is {{#f}}.
1089
1090
1091===== {{javascript-compressor}}
1092<parameter>(javascript-compressor [procedure])</parameter>
1093
1094An one-argument procedure (the javascript code) which return the given
1095javascript code compressed.  Only used when
1096{{enable-javascript-compression}} is not {{#f}}.
1097
1098The default value is the {{identity}} procedure.
1099
1100A possible value for {{javascript-compressor}} is {{jsmin-string}}
1101(see the [[/egg/jsmin|jsmin]] egg.)
1102
1103
1104===== {{javascript-position}}
1105<parameter>(javascript-position [symbol])</parameter>
1106
1107A symbol indicating the position of javascript code in the generated
1108pages.  Possible values are {{top}} (in the page headers) and
1109{{bottom}} (right before {{</body>}}).  The default value is {{top}}.
1110
1111
1112
1113=== List of read-only parameters available to users
1114
1115Note: these parameters should not be explicitly set and when their use
1116is needed, it's a string sign you're doing something you shouldn't
1117(except for {{db-connection}}, which can be used by procedures from
1118the [[/egg/postgresql|postgresql]] egg API).
1119
1120
1121===== {{http-request-variables}}
1122<parameter>(http-request-variables)</parameter>
1123
1124The per-request value returned by
1125[[/egg/spiffy-request-vars|spiffy-request-vars]]'s {{request-vars}}.
1126
1127
1128===== {{db-connection}}
1129<parameter>(db-connection)</parameter>
1130
1131A per-request database connection object.  The connection is
1132automatically opened and closed by awful in a per-request basis
1133(unless databases are not being used the {{no-db}} keyword parameter
1134for {{define-page}} is {{#t}}.)
1135
1136
1137===== {{page-javascript}}
1138<parameter>(page-javascript)</parameter>
1139
1140Javascript code to be added to the pages defined by {{define-page}}.
1141
1142
1143===== {{sid}}
1144<parameter>(sid)</parameter>
1145
1146The session identifier.
1147
1148
1149===== {{awful-apps}}
1150<parameter>(awful-apps)</parameter>
1151
1152The list of awful applications, as given to the awful server when
1153invoked from the command line.
1154
1155
1156===== {{development-mode?}}
1157<parameter>(development-mode?)</parameter>
1158
1159Indicates whether awful is running in development mode (see the
1160{{--development-mode}} command line option for the awful application
1161server).
1162
1163=== List of procedures and macros
1164
1165
1166==== Miscelaneous
1167
1168===== {{++}}
1169<procedure>(++ string1 string2 ... stringn)</procedure>
1170
1171A shortcut to {{string-append}}.
1172
1173===== {{concat}}
1174<procedure>(concat args #!optional (sep ""))</procedure>
1175
1176Convert {{args}} to string and intersperse the resulting strings with {{sep}}.
1177
1178===== {{awful-version}}
1179<procedure>(awful-version)</procedure>
1180
1181Return the awful version (a string).
1182
1183
1184==== Javascript
1185
1186===== {{include-javascript}}
1187<procedure>(include-javascript . files)</procedure>
1188
1189A shortcut to {{(<script> type: "text/javascript" src: file)}}.
1190
1191
1192===== {{add-javascript}}
1193<procedure>(add-javascript . code)</procedure>
1194
1195Add arbitrary javascript code to the pages defined by {{define-page}}
1196and {{define-session-page}}.
1197
1198
1199==== Debugging
1200
1201===== {{debug}}
1202<procedure>(debug . args)</procedure>
1203
1204Print {{args}}, concatenated, to the file {{debug-file}}.
1205
1206
1207===== {{debug-pp}}
1208<procedure>(debug-pp arg)</procedure>
1209
1210Pretty-print {{arg}} to the file {{debug-file}}.
1211
1212
1213
1214==== Sessions and authentication
1215
1216===== {{$session}}
1217<procedure>($session var #!optional default)</procedure>
1218
1219Return the value of {{var}} in the session (or {{default}} if {{var}}
1220does not exist or is {{#f}}).
1221
1222
1223===== {{$session-set!}}
1224<procedure>($session-set! var #!optional val)</procedure>
1225
1226If {{var}} is a quoted symbol, set the value of {{var}} to {{val}}.
1227If {{val}} is not provided, {{var}} will have its value set to {{#f}}.
1228
1229{{var}} can be an alist mapping session variable names to their
1230corresponding values.
1231
1232Examples:
1233
1234<enscript highlight=scheme>
1235($session-set! 'foo "foo value")
1236
1237($session-set! '((foo . "foo value")
1238                 (bar . "bar value")
1239                 (baz . "baz value")))
1240</enscript>
1241
1242
1243===== {{link}}
1244<procedure>(link url text . rest)</procedure>
1245
1246Return a session-aware HTML code for a link, using the {{<a>}}
1247procedure from [[/egg/html-tags|html-tags]].
1248
1249The {{rest}} arguments are the same as the ones for the {{<a>}}
1250procedure from [[/egg/html-tags|html-tags]], plus the following:
1251
1252; {{no-session}} : a boolean.  If {{#t}}, forces {{link}} to ignore the session even when {{enable-session}} is {{#t}}.
1253
1254; {{arguments}} : an alist mapping variable names to their corresponding values, to be passed to uri-common's {{form-urlencode}} procedure.
1255; {{separator}} : the value to the {{separator}} keyword argument to be passed to to uri-common's {{form-urlencode}} procedure.
1256
1257When {{enable-session}} is {{#t}}, {{link}} automatically encodes the session identifier in the URI (unless {{no-session}} is {{#t}}).
1258
1259
1260===== {{form}}
1261<procedure>(form contents . rest)</procedure>
1262
1263Return a session-aware HTML code for a form, using the {{<form>}}
1264procedure from [[/egg/html-tags|html-tags]].
1265
1266The {{rest}} arguments are the same as the ones for the {{<form>}}
1267procedure from [[/egg/html-tags|html-tags]], plus {{no-session}}, a
1268boolean.  If {{no-session}} is {{#t}}, it forces {{form}} to ignore
1269the session even when {{enable-session}} is {{#t}}.
1270
1271When {{enable-session}} is {{#t}}, {{form}} automatically generates a
1272hidden input field to pass the session identifier (unless
1273{{no-session}} is {{#t}}).
1274
1275
1276===== {{define-login-trampoline}}
1277<procedure>(define-login-trampoline path #!key vhost-root-path hook)</procedure>
1278
1279Define a trampoline -- an intermediate page accessed when redirecting
1280from the login page to the main page.
1281
1282===== {{login-form}}
1283<procedure>(login-form #!key (user-label "User: ") (password-label "Password: ") (submit-label "Submit") (refill-user #t))</procedure>
1284
1285Return a user/password login form (e.g., for using in authentication pages).
1286
1287When the {{refill-user}} is {{#t}}, the User field is reffiled with
1288the value from the {{user}} query string value when either the session
1289or the password is invalid.
1290
1291The {{user-label}}, {{password-label}} and {{submit-label}} keyword
1292parameters are labels to be used for the user, password and submit
1293form widgets, respectively.
1294
1295
1296
1297==== Request variables and values
1298
1299===== {{$}}
1300<procedure>($ var #!optional default/converter)</procedure>
1301
1302Return the HTTP request value for the given variable {{var}}.  The
1303variable is looked for in both the query string (GET method) and
1304request body (e.g., POST method).  See the documentation for the
1305procedure returned by
1306[[/eggref/4/spiffy-request-vars|spiffy-request-vars]]'s
1307{{request-vars}} for further details.
1308
1309
1310===== {{with-request-variables}}
1311<macro>(with-request-variables (var1 var2 ... varn) expression1 ...)</macro>
1312
1313A wrapper around [[/egg/spiffy-request-vars|spiffy-request-vars]]'s
1314{{with-request-vars*}}.
1315
1316All the [[/egg/spiffy-request-vars|spiffy-request-vars]]'s converter
1317procedures are exported, for convenience.
1318
1319
1320==== Database access
1321
1322===== {{$db}}
1323<procedure>($db q #!key default values)</procedure>
1324
1325Execute the given query ({{q}}) on the database and return the result
1326as a list of lists or {{default}} if the result set is empty.
1327
1328The {{values}} keyword parameter (a list) is a list of values to
1329replace the placehoders in the query.
1330
1331Example:
1332
1333<enscript highlight=scheme>
1334($db "insert into foo (bar, baz) values (?, ?)" values: '("bar-val" "baz-val"))
1335</enscript>
1336
1337
1338===== {{$db-row-obj}}
1339<procedure>($db-row-obj q)</procedure>
1340
1341Execute the given query {{q}} on the database and return an
1342one-argument procedure which takes as argument the name of the
1343database field to get the value.
1344
1345Example:
1346
1347<enscript highlight=scheme>
1348(let ((& ($db-row-obj "select full_name, phone from users where user_id=1")))
1349  (<p> "Full name: " (& 'full_name))
1350  (<p> "Phone: " (& 'phone)))
1351</enscript>
1352
1353''Warning'': currently {{$db-row-obj}} is only implemented for
1354Postgresql databases.
1355
1356
1357===== {{sql-quote}}
1358<procedure>(sql-quote . data)</procedure>
1359
1360Escape and quote the concatenation of {{data}} to be used in SQL queries.
1361
1362''Warning'': for Sqlite databases, {{sql-quote}} just replaces {{'}}
1363by {{''}} and quotes the {{data}}.  For Postgresql, {{sql-quote}}
1364quotes the result of {{escape-string}}.
1365
1366Consider using the API for placeholders of your favorite database egg
1367instead od {{sql-quote}} whenever possible.
1368
1369
1370==== Pages
1371
1372===== {{define-page}}
1373<procedure>(define-page path contents #!key css title doctype headers charset no-ajax use-ajax no-template no-session no-db no-javascript-compression method)</procedure>
1374
1375Define an awful page.
1376
1377{{path}} is the path to the page.  It can be represented by two types:
1378a string and a regular expression object.  If it is a string, the path
1379used in the URI will be bound to the given no-argument procedure
1380{{contents}}.  If it is a regular expression object, any request whose
1381URL path matches the regular expression will br handled by the
1382one-argument procedure {{contents}}.  This procedure will be given the
1383requested path.
1384
1385{{method}} (a symbol or a list) indicates the HTTP method to be used
1386(e.g., {{GET}}, {{POST}}, {{PUT}}).  {{method}} can also be a list of
1387methods.  In this case, awful will define a page for each method of
1388the list.  Methods are case-insensitive.  Pages that use different
1389methods can use the same path.
1390
1391The {{css}}, {{title}}, {{doctype}}, {{headers}} and {{charset}}
1392keyword parameters have the same meaning as {{html-page}} (from the
1393[[/egg/html-utils|html-utils]] egg).
1394
1395If {{no-ajax}} is {{#t}}, it means that the page won't use ajax, even
1396if the {{enable-ajax}} parameter is {{#t}}.
1397
1398If {{use-ajax}} is {{#t}}, it means that the page will be linked to
1399the ajax library, even if the {{enable-ajax}} parameter is {{#f}}.
1400
1401If {{no-template}} is {{#t}}, it means that no page template (see the
1402{{page-template}} parameter) should be used.
1403
1404If {{no-session}} is {{#t}}, it means that the page should not use session.
1405
1406If {{no-db}} is {{#t}}, it means that the page should not use the
1407database, even when database usage is activated by {{enable-db}} and
1408{{db-credentials}} is not {{#f}}.
1409
1410If {{no-javascript-compression}} is {{#t}} the javascript code for the
1411page is not compressed, even when {{enable-javascript-compression}} is
1412not {{#f}}.
1413
1414Examples:
1415
1416<enscript highlight=scheme>
1417(use srfi-1 ;; for filter-map
1418     regex) ;; for regexp
1419
1420;; http://host:port/foo => "bar"
1421(define-page "/foo"
1422  (lambda ()
1423    "bar"))
1424
1425;; http://host:port/add/1/2/3 => 6
1426(define-page (regexp "/add/.*")
1427  (lambda (path)
1428    (let ((numbers (filter-map string->number (string-split path "/"))))
1429      (number->string (apply + numbers)))))
1430</enscript>
1431
1432
1433===== {{define-session-page}}
1434<procedure>(define-session-page path contents . rest)</procedure>
1435
1436Define a session-aware page.  When the page is accessed and a
1437correponding session does not exist, it is created.  If the session
1438already exists and is not valid, it is recreated.  If the session
1439already exists and is valid, then it is refreshed.
1440
1441The {{rest}} parameters are the same as for {{define-page}}.
1442
1443Here's an example (the [[http://www.paulgraham.com/arcchallenge.html|arc challenge]]):
1444
1445<enscript highlight=scheme>
1446(use awful html-utils)
1447
1448(define-session-page "said"
1449  (lambda ()
1450    (with-request-variables (said)
1451      (cond (said
1452             ($session-set! 'said said)
1453             (link "said" "click here"))
1454            (($session 'said)
1455             => (lambda (said)
1456                  (++ "You said: " said)))
1457            (else (form (++ (text-input 'said)
1458                            (submit-input))
1459                        action: "said"
1460                        method: 'post))))))
1461</enscript>
1462
1463
1464===== {{undefine-page}}
1465<procedure>(undefine-page path #!optional vhost-root-path)</procedure>
1466
1467Undefine a page whose path is {{path}} (a string or a regular
1468expression object).
1469
1470The optional parameter {{vhost-root-path}} is the path of virtual host
1471where the page is to be undefined.  If omited, {{(root-path)}} is
1472used.
1473
1474
1475==== Ajax
1476
1477===== {{ajax}}
1478<procedure>(ajax path selector event proc #!key target (action 'html) (method 'POST) (arguments '()) success no-session no-db vhost-root-path live prelude update-targets cache error-handler)</procedure>
1479
1480Generate javascript code to be added to the page defined by
1481{{define-page}}.  Return the generated javascript code (which usually
1482is not useful, so should be discarded).
1483
1484{{path}} is the URL path (a string) of the server side handler. This
1485path is placed under the {{(app-root-path)/(ajax-namespace)}} path.
1486So, if your {{app-root-path}} is {{"my-app"}}, your {{ajax-namespace}}
1487is {{"ajax"}} and you use {{"do-something"}} as the first argument to
1488{{ajax}}, the URL for the server side handler would be
1489{{"/my-app/ajax/do-something"}}.
1490
1491{{selector}} is the selector for the DOM element to be observed.  If
1492it is a quoted symbol, awful generates a JQuery selector by DOM id
1493(e.g., {{'my-selector}} generates {{"#my-selector"}}).  If it is a
1494string, awful uses it as-is to generate the JQuery selector (e.g.,
1495{{"input[name^=omg]"}} generates {{"input[name^=omg]"}}).
1496
1497{{event}} (a quoted symbol or a list) is the event(s) to be
1498observed. If it is a quoted symbol (e.g., {{'click}}), only this event
1499will be bound.  If {{event}} is a list of events, all the events from
1500the list will be bound.
1501
1502{{proc}} is a no-argument procedure to be executed on the server side.
1503
1504The {{target}} keyword parameter is the id of the DOM element to be
1505affected by the result of {{proc}}.
1506
1507The {{method}} (a quoted symbol, usually {{'GET}} or {{'POST}})
1508keyword parameter is the HTTP method to be used by the ajax request.
1509
1510The {{arguments}} keyword parameter is an alist mapping request
1511variables (symbols) to their values (strings).  {{ajax}} uses these
1512arguments to assembly the query string or the request body to send to
1513the server when performing the ajax request.
1514
1515Example:
1516
1517<enscript highlight=scheme>
1518arguments: '((var1 . "$('#var1').val()")
1519             (var2 . "$('#var2').val()"))
1520</enscript>
1521
1522If the {{no-session}} keyword parameter is {{#t}}, it means that no
1523session should be considered ({{ajax}} implicit sends the session
1524identifier when {{no-session}} is {{#f}}).
1525
1526If the {{no-db}} keyword parameter is {{#t}}, it means that the should
1527be no attempt to connect the database, even when database usage is
1528activated by {{enable-db}} and {{db-credentials}} is not {{#f}}.
1529
1530The {{vhost-root-path}} keyword parameter (a string) is the vhost root
1531path.  It is useful for explicitly separate pages defined using the
1532same path (see {{define-page}}) but for different vhosts.
1533
1534The {{live}} keyword parameter (boolean) indicates wheter ajax should
1535use JQuery's live method (see [[http://api.jquery.com/live/]]).
1536
1537The {{prelude}} keyword parameter (string) is an arbitrary piece of
1538javascript code to be placed right before the ajax request.
1539
1540The {{update-targets}} keyword parameter a boolean indicating whether
1541multiple targets should be updated upon ajax response.  When
1542{{update-targets}} is used, the procedure {{proc}} used as argument to
1543{{ajax}} should yield an alist as result.  The alist maps DOM elements
1544identifiers to their corresponding values.
1545
1546Here's an example:
1547
1548<enscript highlight=scheme>
1549(use awful html-tags)
1550
1551(enable-ajax #t)
1552
1553(define-page (main-page-path)
1554  (lambda ()
1555
1556    (ajax "foo" 'foo 'click
1557          (lambda ()
1558            '((a . 1) (b . 2) (c . 3)))
1559          update-targets: #t)
1560
1561    (<div>
1562     (link "#" "foo" id: "foo")
1563     (<div> id: "a")
1564     (<div> id: "b")
1565     (<div> id: "c"))))
1566</enscript>
1567
1568The {{success}} keyword parameter (string) can be any arbitrary
1569javascript code to be executed on the successful ajax request.  The
1570javascript code can assume that a variable {{response}} is bound and
1571contains the request resulting data.  Here's an example:
1572
1573<enscript highlight=scheme>
1574(use awful html-tags)
1575
1576(enable-ajax #t)
1577
1578(define-page (main-page-path)
1579  (lambda ()
1580
1581    (ajax "foo" 'foo "click"
1582          (lambda ()
1583            "hey")
1584          success: "$('#bar').html(response + ' you!')")
1585
1586    (++ (link "#" "foo" id: "foo")
1587        (<div> id: "bar"))))
1588</enscript>
1589
1590The {{cache}} keyword parameter (boolean), if set to {{#f}}, it will
1591force requested pages not to be cached by the browser.  The default
1592value is not set, leaving it to be set by JQuery. See
1593[[http://api.jquery.com/jQuery.ajax/|JQuery's documentation]] for
1594further details.
1595
1596The {{error-handler}} keyword parameter expects a JavaScript callback
1597to be used as the error handler for the Ajax request.  See the
1598{{error}} attribute for the {{settings}} object given as argument to
1599jQuery.ajax
1600([[http://api.jquery.com/jQuery.ajax/|http://api.jquery.com/jQuery.ajax/]]).
1601
1602The {{ajax}} procedure is session, HTTP request and database -aware.
1603
1604
1605===== {{periodical-ajax}}
1606<procedure>(periodical-ajax path interval proc #!key target (action 'html) (method 'POST) (arguments '()) success no-session no-db vhost-root-path live prelude update-targets error-handler)</procedure>
1607
1608Periodically execute {{proc}} on the server side, using
1609{{(app-root-path)/(ajax-namespace)/path}} as the URL path for the
1610server side handler.
1611
1612{{interval}} (a number) is the interval between consecutive executions
1613of {{proc}}, in milliseconds.
1614
1615The meaning of the keyword parameters is the same as for {{ajax}}'s.
1616
1617
1618===== {{ajax-link}}
1619<procedure>(ajax-link path id text proc #!key target (action 'html) (method 'POST) (arguments '()) success no-session no-db (event 'click) vhost-root-path live class hreflang type rel rev charset coords shape accesskey tabindex a-target prelude update-targets error-handler)</procedure>
1620
1621A shortcut to
1622
1623<enscript highlight=scheme>
1624(begin
1625  (ajax path id 'click proc ...)
1626  (<a> href: "#" [...other <a> keyword parameters...] id: id text))
1627</enscript>
1628
1629The meaning of the {{target}}, {{action}}, {{method}}, {{arguments}},
1630{{success}}, {{no-session}}, {{no-db}}, {{event}},
1631{{vhost-root-path}}, {{update-targets}} and {{live}} keyword
1632parameters is the same as for {{ajax}}'s.
1633
1634The meaning of the {{class}}, {{hreflang}}, {{type}}, {{rel}},
1635{{rev}}, {{charset}}, {{coords}}, {{shape}}, {{accesskey}},
1636{{tabindex}} and {{a-target}} are the same as for
1637[[/egg/html-tags|html-tags]]' {{<a>}} procedure (except that
1638{{a-target}} is {{<a>}}'s {{target}}, since {{ajax}} uses the
1639{{target}} keyword parameter).
1640
1641The {{event}} keyword parameter syntax is the same for {{ajax}}'s
1642{{event}} mandatory parameter.
1643
1644
1645==== Redirection
1646
1647===== {{redirecto-to}}
1648<procedure>(redirect-to uri)</procedure>
1649
1650Perform an HTTP redirection (code 302) to the given {{uri}} (either a
1651string or a [[/eggref/4/uri-common|uri-common]] uri object).  To be
1652used from {{define-page}} contents.  Example:
1653
1654<enscript highlight=scheme>
1655(use awful)
1656
1657;; / -> /foo
1658(define-page "/"
1659  (lambda ()
1660    (redirect-to "/foo")))
1661
1662(define-page "/foo"
1663  (lambda ()
1664    "foo"))
1665</enscript>
1666
1667The example above shows a redirection from {{/}} to {{/foo}}.
1668Redirections can also be performed when the origin path is a regular
1669expression:
1670
1671<enscript highlight=scheme>
1672(use awful)
1673
1674;; /bar.* -> /foo
1675(define-page (regexp "/bar.*")
1676  (lambda (_)
1677    (redirect-to "/foo")))
1678
1679(define-page "/foo"
1680  (lambda ()
1681    "foo"))
1682</enscript>
1683
1684
1685==== Request handler hooks
1686
1687Awful provides the possibility of plugin hooks to the request handler,
1688so that deploying multiple awful applications under the same virtual
1689host is possible and easy.
1690
1691===== {{add-request-handler-hook!}}
1692<procedure>(add-request-handler-hook! hook-id proc)</procedure>
1693
1694Adds a hook identified by {{id}} (can be used to remove the hook if
1695necessary). {{proc}} is a two-argument procedure which receives the
1696requested path and its handler.
1697
1698Here's a simple usage example:
1699
1700<enscript highlight=scheme>
1701(add-request-handler-hook!
1702 'foo
1703 (lambda (path handler)
1704   (when (string-prefix? "/foo" path)
1705     (parameterize
1706         ((debug-file "/tmp/foo-debug")
1707          (enable-ajax #t))
1708       (handler))))
1709</enscript>
1710
1711By using request handlers, you can parameterize parameter values in a
1712way that they don't affect other applications.
1713
1714===== {{remove-request-handler-hook!}}
1715<procedure>(remove-request-handler-hook! hook-id)</procedure>
1716
1717Removes the request handler hook identified by {{id}}.
1718
1719
1720==== Web REPL
1721
1722===== {{enable-web-repl}}
1723<procedure>(enable-web-repl path #!key css title)</procedure>
1724
1725Enable the web REPL.  {{path}} is the URL path to the web REPL.
1726
1727The keyword parameter {{css}} is the CSS to be used the the web REPL
1728page (see the documentation for {{html-page}}, from the
1729[[/egg/html-utils|html-utils]] egg, for the {{css}} keyword
1730parameter.)
1731
1732The keyword parameter {{title}} (a string) is the title for the web
1733REPL page (see the documentation for {{html-page}}, from the
1734[[/egg/html-utils|html-utils]] egg, for the {{title}} keyword
1735parameter.)
1736
1737The web REPL is automatically enabled by the awful application server
1738when the {{--development-mode}} is provided (available from
1739{{/web-repl}}).  By default, the fancy editor is used, but can be
1740disabled with the {{--disable-web-repl-fancy-editor}} command line
1741option for the awful application server.
1742
1743
1744==== Session inspector
1745
1746===== {{enable-session-inspector}}
1747<procedure>(enable-session-inspector path #!key css title)</procedure>
1748
1749Enable the session inspector.  {{path}} is the URL path to the session
1750inspector.
1751
1752The keyword parameter {{css}} is the CSS to be used the the session
1753inspector page (see the documentation for {{html-page}}, from the
1754[[/egg/html-utils|html-utils]] egg, for the {{css}} keyword
1755parameter.)
1756
1757The keyword parameter {{title}} (a string) is the title for the
1758session inspector page (see the documentation for {{html-page}}, from
1759the [[/egg/html-utils|html-utils]] egg, for the {{title}} keyword
1760parameter.)
1761
1762The session inspector is automatically enabled by the awful
1763application server when the {{--development-mode}} is provided
1764(available from {{/session-inspector}}).
1765
1766
1767==== Applications
1768
1769===== {{load-apps}}
1770<procedure>(load-apps apps)</procedure>
1771
1772Load the given applications ({{apps}} - a list) (using
1773[[http://wiki.call-cc.org/man/4/Unit%20eval#load|load]]).
1774
1775
1776===== {{reload-apps}}
1777<procedure>(reload-apps apps)</procedure>
1778
1779The same as {{load-apps}} but also reseting the resources table (the
1780thing that maps URIs to procedures) before loading applications.
1781
1782
1783==== The awful server
1784
1785===== {{awful-start}}
1786<procedure>(awful-start thunk #!key dev-mode? port ip-address use-fancy-web-repl? privileged-code))</procedure>
1787
1788Starts awful.  This procedure is only useful for standalone
1789applications which intent to embed awful.  For example, the awful
1790application server (the awful command line tool) uses it.
1791
1792This procedure does all the listening, switching user/group and
1793entering the accept loop dance.
1794
1795{{thunk}} is a procedure to be executed upon starting awful.  It can
1796be Scheme code just like any other that can be loaded as an awful
1797application.
1798
1799{{dev-mode?}} (boolean) indicates whether awful should run in development mode.
1800
1801{{port}} (integer) indicates to port to bind to.
1802
1803{{ip-address}} (string) indicates the IP address to bind to.
1804
1805{[use-fancy-web-repl?}} (boolean): indicates whether the web REPL
1806should use the fancy editor.
1807
1808{{privileged-code}} (procedure): a thunk that is executed while awful
1809is still running with privileged permissions (when run by the
1810superuser).
1811
1812=== Tips and tricks
1813
1814==== Use {{link}} and {{form}} for links and forms
1815
1816Instead of using {{<a>}} and {{<form>}} for creating links and forms,
1817respectively, consider using the {{link}} and {{form}} procedures
1818instead.  They are specially useful when using sessions, since they
1819transparently handle the session identifier for you.  Even if you
1820don't use sessions, they may save you some work if one day you decide
1821to use sessions (then you won't have do to anything regarding to links
1822and forms).
1823
1824
1825==== Use {{with-request-variables}} when referencing the same request variable multiple times
1826
1827When you need to access the same request variable more than once,
1828consider using {{with-request-variables}}.
1829
1830For example, instead of:
1831
1832<enscript highlight=scheme>
1833(use awful)
1834
1835(define-page "save-and-show-user"
1836  (lambda ()
1837    ($session-set! 'user ($ 'user))
1838    (++ "Welcome " ($ 'user) "!")))
1839</enscript>
1840
1841consider using something like:
1842
1843<enscript highlight=scheme>
1844(use awful)
1845
1846(define-page "save-and-show-user"
1847  (lambda ()
1848    (with-request-variables (user)
1849      ($session-set! 'user user)
1850      (++ "Welcome " user))))
1851</enscript>
1852
1853
1854==== Use the web REPL and the session inspector for debugging
1855
1856You can simply use the {{--development-mode}} option for the awful
1857application server to enable the web REPL and the session inspector
1858(when {{enable-session}} is {{#t}}).  The development mode allows
1859access to them for the localhost.  When in development mode, the web
1860REPL and the session inspector are available at the {{/web-repl}} and
1861{{/session-inspector}} paths.
1862
1863If you want further flexibility, you can customize the web REPL and
1864the session inspector.
1865
1866Here's a simple recipe to allow access for your local machine to the
1867web REPL ({{/repl}}) and to the session inspector
1868({{/session-inspector}}).
1869
1870<enscript highlight=scheme>
1871(session-inspector-access-control
1872 (lambda ()
1873   (member (remote-address) '("127.0.0.1"))))
1874
1875(enable-session-inspector "/session-inspector")
1876
1877
1878(web-repl-access-control
1879 (lambda ()
1880   (member (remote-address) '("127.0.0.1"))))
1881
1882(enable-web-repl "/repl")
1883</enscript>
1884
1885To access them, just point your browser to
1886{{http://localhost:<port>/repl}} and
1887{{http://localhost:<port>/session-inspector}}, respectively.
1888
1889
1890==== Create custom page definers when {{page-template}} and/or plain {{define-page}} are not enough
1891
1892You can define your own page definers when {{page-template}} or the
1893plain {{define-page}} is not enough for what you need.  Here's an
1894example:
1895
1896<enscript highlight=scheme>
1897(use awful html-tags)
1898
1899(define (define-custom-page path contents)
1900  (define-page path
1901    (lambda ()
1902      (<html> (<body> (contents))))
1903    no-template: #t))
1904
1905(define-custom-page (main-page-path)
1906  (lambda ()
1907    "Hey!"))
1908</enscript>
1909
1910If you access {{http://localhost:8080}} you'll get the following HTML code:
1911
1912  <html><body>Hey!</body></html>
1913
1914
1915==== Debugging: error messages on the browser window
1916
1917Error messages right on the browser window can be quite handy for
1918debugging (although not for production environments).  Here's a way to
1919accomplish that:
1920
1921<enscript highlight=scheme>
1922(use awful html-tags)
1923
1924(page-exception-message
1925 (lambda (exn)
1926   (<pre> convert-to-entities?: #t
1927          (with-output-to-string
1928            (lambda ()
1929              (print-call-chain)
1930              (print-error-message exn))))))
1931</enscript>
1932
1933This feature is automatically enabled when the awful application
1934server is used with the {{--development-mode}} option.
1935
1936
1937
1938==== Run awful without arguments to quickly share a file
1939
1940When invoked without arguments, awful (the application) starts the web
1941server using the current directory as root path and keeps listening on
1942port 8080.  So, if you want to quickly share a file (or some files),
1943change to the directory containing the files and execute {{awful}}.
1944The access {{http://<host>:8080/<the-file-you-want>}}.
1945
1946
1947==== Awful & SXML
1948
1949By default, awful uses
1950[[http://wiki.call-cc.org/egg/html-tags|html-tags]] to generate HTML
1951for pages.  Of course, it can be changed, and you can even use SXML.
1952Here's an example (see
1953[[http://wiki.call-cc.org/egg/sxml-transforms|sxml-transforms egg]]
1954for more information about SXML transformation):
1955
1956<enscript highlight=scheme>
1957(use awful sxml-transforms doctype)
1958
1959(define (sxml->html sxml) 
1960  ;; Generates an HTML string out of SXML
1961  (with-output-to-string
1962    (lambda ()
1963      (let* ((rules `((literal *preorder* . ,(lambda (t b) b))
1964                      . ,universal-conversion-rules*)))
1965        (SRV:send-reply (pre-post-order* sxml rules))))))
1966
1967(define (define-sxml-page path contents)
1968  (define-page path
1969    (lambda ()
1970      (sxml->html `(html (body ,(contents)))))
1971    doctype: doctype-xhtml-1.0-transitional
1972    no-template: #t))
1973
1974(define-sxml-page (main-page-path)
1975  (lambda ()
1976    '(p "Awful SXML example")))
1977</enscript>
1978
1979==== Reloading awful from Emacs
1980
1981Here's a quick hack to reload awful apps from Emacs.  It can be handy
1982when you are developing using awful in development mode
1983({{--development-mode}}, or when you defined your own reload path).
1984
1985<enscript highlight=elisp>
1986(defun awful-reload ()
1987  (interactive)
1988  (shell-command "lynx -dump http://localhost:8080/reload"))
1989
1990(add-hook 'scheme-mode-hook
1991   #'(lambda ()
1992       (local-set-key "\C-cR" 'awful-reload)))
1993</enscript>
1994
1995The code above defines an {{awful-reload}} procedure, which requests
1996the {{/reload}} path (automatically defined by awful when running in
1997development mode) using {{lynx}}.  You can use whatever command line
1998HTTP client you want. {{lynx}} is handy because of the {{-dump}}
1999option, which can be readly displayed by Emacs in the shell command
2000output buffer.
2001
2002Here's a screenshot:
2003
2004[[image:http://parenteses.org/mario/img/awful/awful-reload-emacs.png|Reloading awful apps from Emacs]]
2005
2006
2007==== Performance tweaks
2008
2009* if you don't intend to use static index files, you may configure the
2010[[/egg/spiffy|Spiffy]] {{index-files}} parameter to {{'()}}.  That
2011will disable the lookup for static index files (or you can configure
2012it to contain only the static index files you use).
2013
2014
2015==== Awful badge
2016
2017Here's a suggestion:  [[image:http://parenteses.org/mario/img/thats-awful.png|That's awful!]]
2018
2019=== Examples
2020
2021Here are some simple examples using assorted awful features.
2022
2023
2024==== Number guessing game
2025
2026A screencast showing this example is available at
2027[[http://parenteses.org/mario/awful/awful-guess.ogv|http://parenteses.org/mario/awful/awful-guess.ogv]]
2028
2029This examples shows a simple guessing game. A random number is
2030generated on the server side and the user tries to guess it.  It shows
2031some basic ajax features.
2032
2033<enscript highlight=scheme>
2034(use awful html-tags)
2035
2036(enable-ajax #t)
2037
2038(define (prompt-guess)
2039  (<input> type: "text" id: "guess"))
2040
2041(define-page (main-page-path)
2042  (lambda ()
2043    (ajax "try-guess" 'guess 'change
2044          (lambda ()
2045            (let ((guess ($ 'guess as-number))
2046                  (thinking (random 10)))
2047              (<p> (if (and guess (= guess thinking))
2048                       "You guessed it right!"
2049                       (conc "You guessed it wrong. I'm thinking " thinking ".")))))
2050            target: "verdict"
2051            arguments: '((guess . "$('#guess').val()")))
2052    (++ (<p> "Guess the number I'm thinking:")
2053        (prompt-guess)
2054        (<div> id: "verdict"))))
2055</enscript>
2056
2057To run it, execute:
2058
2059  $ awful number-guess.scm
2060
2061(considering you saved the code above in a file called
2062{{number-guess.scm}}), then access {{http://localhost:8080}}.
2063
2064
2065
2066==== Sandboxed Chicken Web REPL
2067
2068This example was featured in the
2069[[http://gazette.call-cc.org/issues/10.html|Chicken Gazette #10]].
2070
2071It shows how to implement a very simple web-based Chicken REPL using a
2072sandbox environment (see the
2073[[http://wiki.call-cc.org/egg/sandbox|sandbox egg]] documentation) for
2074safe evaluation.
2075
2076The idea is to have a web page with an input box. Users type the forms
2077they want to evaluate and submit them to the server. The server
2078evaluates the given forms in a sandbox environment and return the
2079results.
2080
2081Here's the commented code:
2082
2083<enscript highlight=scheme>
2084(use html-tags awful sandbox)
2085
2086;; Here we define the REPL page.  It uses the session to store the
2087;; sandboxed environment.  By default, the `main-page-path' parameter
2088;; value is "/".
2089(define-session-page (main-page-path)
2090  (lambda ()
2091
2092    ;; Create the sandbox environment (if it does not exist yet) and
2093    ;; store it in the user session.
2094    (unless ($session 'sandbox-env)
2095      ($session-set! 'sandbox-env
2096                     (make-safe-environment
2097                      parent: default-safe-environment
2098                      mutable: #t
2099                      extendable: #t)))
2100
2101    ;; Here we set an ajax handler for the REPL expressions
2102    ;; submission.  When users change the REPL input widget (i.e., by
2103    ;; pressing ENTER), the contents of the text input field are
2104    ;; submitted and handled by the procedure given as the forth
2105    ;; argument to `ajax'.
2106    (ajax "eval" 'repl-input 'change
2107          (lambda ()
2108
2109            ;; This binds the variable `repl-input' from the POST
2110            ;; method the the `repl-input' Scheme variable
2111            (let ((repl-input ($ 'repl-input)))
2112
2113              ;; We'd better handle exceptions when trying to
2114              ;; evaluate the expressions given by users.
2115              (handle-exceptions
2116               exn
2117               ;; If something goes wrong, we print the error message
2118               ;; and the call chain.
2119               (<pre> convert-to-entities?: #t
2120                      (with-output-to-string
2121                        (lambda ()
2122                          (print-error-message exn)
2123                          (print-call-chain))))
2124               ;; Here we try to evaluate the given expression in the
2125               ;; sandboxed environment stored in the user session.
2126               ;; The `repl-output' page div is updated with the result.
2127               (<pre> convert-to-entities?: #t
2128                      (safe-eval
2129                       (with-input-from-string repl-input read)
2130                       fuel: 100
2131                       allocation-limit: 100
2132                       environment: ($session 'sandbox-env))))))
2133
2134          ;; Here we pass the contents of the text input to the ajax
2135          ;; handler.  The default HTTP method used by `ajax' is POST.
2136          arguments: `((repl-input . "$('#repl-input').val()"))
2137
2138          ;; The output of the ajax handler updates the `repl-output'
2139          ;; page div.
2140          target: "repl-output")
2141
2142    ;; Here's what is displayed to users
2143    (++ (<h1> "Sandboxed Chicken web REPL")
2144        (<input> type: "text" id: "repl-input")
2145        (<div> id: "repl-output")))
2146
2147  ;; This tells `define-session-page' to link the page to JQuery
2148  use-ajax: #t)
2149</enscript>
2150
2151To run the code above you'll need to install awful and sandbox:
2152
2153  $ chicken-install awful sandbox
2154
2155Then (considering you save the code above in a file called {{web-sandbox.scm}}), run:
2156
2157  $ awful web-sandbox.scm
2158
2159and access {{http://localhost:8080}}.
2160
2161
2162Here are some screenshots of the code above running on Firefox:
2163
2164[[image:http://gazette.call-cc.org/img/10/web-sandbox.png|Screenshot of the sandboxed web REPL running on Firefox]]
2165
2166If you try something nasty, the sandbox will abort the evaluation and you'll get an error message and the call chain:
2167
2168[[image:http://gazette.call-cc.org/img/10/web-sandbox-loop.png|Screenshot of the sandboxed web REPL running on Firefox]]
2169
2170We can also compile the web application:
2171
2172 $ csc -s web-sandbox.scm
2173 $ awful web-sandbox.so
2174
2175
2176==== Color chooser
2177
2178Here's an example provided by
2179[[http://wiki.call-cc.org/users/christian-kellermann|Christian Kellermann]] demonstrating an ajax-based color chooser:
2180
2181<enscript highlight=scheme>
2182(use awful html-utils html-tags)
2183
2184(define color-table
2185  '("f63353" "fead76" "107279" "10fabc" "1181bf" "120902" "129105"
2186    "131848" "13a04b" "1427ee" "14a8b1" "1532d4" "15bcf7" "16671a"
2187    "16c13d" "175b60" "17d583" "186fa6" "18ecc9" "1973ec"))
2188
2189(enable-ajax #t)
2190
2191(define (color-picker counter color)
2192  (<div> class: "color-box" style: (conc  "background-color: " (conc "#" color))
2193         (text-input (conc "change-color-" counter) value: color)))
2194
2195(define (make-color-chooser counter c)
2196  (ajax "ajax" (conc "#change-color-" counter) 'change
2197        (lambda ()
2198          (let ((color (or ($ 'color) c))
2199                (counter ($ 'counter)))
2200            (color-picker counter color)))
2201        target: (conc "color-box-" counter)
2202        arguments: `((color . ,(conc  "$('#change-color-" counter "').val()"))
2203                     (counter . ,counter))
2204        live: #t)
2205  (<div> id: (conc "color-box-" counter) (color-picker counter c)))
2206
2207(define-page (main-page-path)
2208  (lambda ()
2209    (concat (map (let ((counter -1))
2210                   (lambda (c)
2211                     (set! counter (add1 counter))
2212                     (make-color-chooser counter c)))
2213                 color-table))))
2214
2215</enscript>
2216
2217Here's a screenshot:
2218
2219[[image:http://parenteses.org/mario/img/awful/color-chooser.png|Awful color chooser]]
2220
2221To run this example (considering you save the code above in a file called {{color-chooser.scm}}):
2222
2223  $ awful color-chooser.scm
2224
2225then access {{http://localhost:8080}}.  You can change the colors by
2226editing the input boxes then pressing enter.
2227
2228
2229==== Fortune server
2230
2231This example is a fortune server in awful.  It demonstrates some handy
2232awful features like database access and ajax.  You'll need the
2233[[http://wiki.call-cc.org/egg/awful-sql-de-lite|awful-sql-de-lite]]
2234egg and its dependencies (which should be automatically installed by
2235{{chicken-install}}).
2236
2237Here are instructions to install and use it:
2238
22391. Install [[http://wiki.call-cc.org/egg/awful-sql-de-lite|awful-sql-de-lite]]
2240
2241   $ chicken-install awful-sql-de-lite
2242
2243
22442. Create the fortunes database (see the code below):
2245
2246   $ csi -s create-database.scm
2247
2248
22493. Run the fortune server (see the code below):
2250
2251   $ awful fortune-server.scm
2252
2253
2254Here's the code for {{create-database.scm}} which creates and populates the fortune database:
2255
2256<enscript highlight=scheme>
2257(use sql-de-lite posix)
2258
2259(define fortunes
2260  '(("Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
2261     "Brian Kernighan")
2262    ("In order to understand recursion, one must first understand recursion.")
2263    ("If debugging is the process of removing software bugs, then programming must be the process of putting them in."
2264     "Edsger Dijkstra")
2265    ("Controlling complexity is the essence of computer programming."
2266     "Brian Kernigan")
2267    ("The function of good software is to make the complex appear to be simple."
2268     "Grady Booch")
2269    ("That's the thing about people who think they hate computers.  What they really hate is lousy programmers."
2270     "Larry Niven")
2271    ("First learn computer science and all the theory.  Next develop a programming style.  Then forget all that and just hack."
2272    "George Carrette")
2273    ("To iterate is human, to recurse divine."
2274    "L. Peter Deutsch")
2275    ("The best thing about a boolean is even if you are wrong, you are only off by a bit.")
2276    ("Optimism is an occupational hazard of programming; feedback is the treatment."
2277     "Kent Beck")
2278    ("Simplicity is prerequisite for reliability."
2279     "Edsger W. Dijkstra")
2280    ("Simplicity is the ultimate sophistication."
2281     "Leonardo da Vinci")
2282    ("The unavoidable price of reliability is simplicity."
2283     "C.A.R. Hoare")
2284    ("The ability to simplify means to eliminate the unnecessary so that the necessary may speak."
2285     "Hans Hoffmann")
2286    ("Simplicity is hard to build, easy to use, and hard to charge for. Complexity is easy to build, hard to use, and easy to charge for."
2287     "Chris Sacca")))
2288
2289(delete-file* "fortunes.db")
2290
2291(let ((db (open-database "fortunes.db")))
2292  (exec (sql db "create table fortunes(sentence text, author text)"))
2293  (for-each (lambda (fortune)
2294              (let* ((sentence (car fortune))
2295                     (author (cdr fortune))
2296                     (statement
2297                      (string-append
2298                       "insert into fortunes (sentence, author) values (?,?)")))
2299                (exec (sql db statement)
2300                      sentence
2301                      (if (null? author) "" (car author)))))
2302            fortunes)
2303  (close-database db))
2304</enscript>
2305
2306Here's the code for the fortune server:
2307
2308<enscript highlight=scheme>
2309(use awful html-tags awful-sql-de-lite)
2310
2311(enable-db)
2312(db-credentials "fortunes.db")
2313
2314(define (random-fortune)
2315  (car ($db "select sentence, author from fortunes order by random() limit 1")))
2316
2317(define-page (main-page-path)
2318  (lambda ()
2319    (ajax "new-fortune" 'new-fortune 'click
2320          (lambda ()
2321            (let ((fortune (random-fortune)))
2322              `((sentence . ,(car fortune))
2323                (author . ,(cadr fortune)))))
2324          update-targets: #t)
2325
2326    (<div> id: "content"
2327           (<div> id: "sentence" "Click the button below to get a new fortune")
2328           (<div> id: "author")
2329           (<button> id: "new-fortune" "New fortune")))
2330
2331  css: "fortune.css"
2332  use-ajax: #t
2333  charset: "utf-8")
2334</enscript>
2335
2336
2337The contents of the {{fortune.css}} file are:
2338
2339  body
2340  { font-family: arial, verdana, sans-serif;
2341  }
2342 
2343  #sentence
2344  { width: 20em;
2345    background-color: #DEE7EC;
2346    padding: 6px;
2347    min-height: 7em;
2348  }
2349 
2350  #author
2351  { width: 20em;
2352    min-height: 2em;
2353    padding: 6px;
2354    background-color: #eee;
2355  }
2356
2357Here's a screenshot:
2358
2359[[image:http://parenteses.org/mario/img/awful/fortune-server.png|Awful fortune server]]
2360=== The name
2361
2362Awful doesn't mean anything special.  It's just awful.  But folks on freenode's #chicken (IRC) have suggested some acronym expansions:
2363
2364* A Whole Freaking Universe of Lambdas
2365* Authored Without Full Understanding of Logic
2366* Another Web Framework Understating Logic
2367* All Worthless Frameworks Unchain Laziness
2368* Armed With Flimsy Utility Lisp
2369* Awful Will Fed Up Lispers
2370* Awful Wildly Finalizes Unfinished Loops
2371* Another Widely Foolish Unknown Language
2372* Ain't Work For Unpleasant Laywers
2373* Aliens Would Find it Utterly Lame
2374* Aren't We Funny and Uncaring Lurkers
2375* Awful Will F*** Up Logic
2376* Awful Will Fart Upon Leaving
2377* Again Web Frameworks Underscore Lameness
2378* Attention While Fully Utilizing Laziness
2379* Another Webserver F***ing Up the Line
2380* Again We Forget Unclosed Lambdas
2381* All Web Features Understood Losslessly
2382* Anything With Fully Universal Lambdas
2383* Again We Fail Under Load
2384* Apocalyptic Warthogs Find Undiscovered Lands
2385* Accessible Web Framework Using Lisp
2386* Another Weird Framework Using Lisp
2387* All Waffles Fear Unicorn Landings
2388* A Working Facility Underscoring Laziness
2389* Another Webbot Flapping Under Lines
2390* Anybody Will Fake Unrealistic Loveletters
2391* Armadillos Would First Use Legs
2392* Astonishing Whales Fill Up Lakes
2393* Alternative Way to F*** Up Lisp
2394* Another Way to Find Undressed Ladies
2395* Amazing! Wonderful! Fantastic! Unbelievable! Lame.
2396* All Wonders Feel Useless Later
2397* Amazingly Wonderful Feeling, Using Lambdas
2398* Alligators Will Fear Us, Lunatics
2399* All Wussies Fear Ultimate Lambda
2400* Animals Will Find Us Letal
2401* Advanced Web Framework: Ultimate Lucubration
2402* Awful Will Feed Urban Lethargy
2403* Argument With Focus Upon Labelling
2404* Another Word Faking Unpremeditated Label
2405* Again We Find it Utterly Useless
2406* Ain't Work For Unattractive Ladies
2407* A Way For Using Lambdas
2408* Awful Way For Using Lambdas
2409* Apparently We Freaks Understand Lambdas
2410* Again We Foolishly Use Lists
2411* At Work Fools Use Lisp
2412* Again We Foolishly Use Lisp
2413* Another Wimp Fall Upon Lisp
2414* Accepting Whatever Fools Undertake Lightly
2415* Absurd Word For Unnatural Lingo
2416* Alternative Word For Useless Loser
2417* Acronym With Filled Up Letters
2418* Acronym We Find Utterly Lame
2419* Another Webserver Functioning Until Launched
2420* Applications With Familiar, Understandable Language
2421* (Awful Words Forming Useless List)
2422* All Who Force Unusual Layout
2423* Again We Fear Undescribable Lamenting
2424* Awful Will Favour Ugly Layouts
2425* Apes With Frequent Uncontrolled Lunacy
2426
2427==== Acknowledgements (IRC nicknames on freenode's #chicken):
2428
2429
2430* C-Keen
2431* DerGuteMoritz
2432* elderK
2433* elf
2434* florz
2435* merlincorey
2436* sjamaan
2437
2438=== FAQ (aka Fakely Asked Questions)
2439
2440==== How does awful bind URIs to files/directories on the filesystem and procedures?
2441
2442Explanation by example:
2443
2444When a procedure is bound to a path {{a}} (like {{(define-page "a" (lambda ...))}}) and the request is made to {{a/}}, the awful behavior is the following:
2445
2446* if the path {{a}} does not exist in the filesystem (under the {{root-path}}), the server replies with the result of the evaluation of the procedure bound to {{a}}.
2447
2448* if {{a}} is an existent file, the server replies with the file contents (or the result of processing the file, in case it is a special one like [[/egg/spiffy#web-scheme-handler|web-scheme]] or {{.ssp}} files)
2449
2450* if {{a}} is an existing directory and the directory contains one of the files in {{index-file}} (see documentation for [[/egg/spiffy|Spiffy]]), with the index file contents (or the result of processing the file, in case it is a special one like [[/egg/spiffy#web-scheme-handler|web-scheme]]'s or {{.ssp}})
2451
2452* if {{a}} is an existing directory and does not contain index files, the server replies with the result of the evaluation of the  procedure bound to {{a}}.
2453
2454=== Known bugs and limitations
2455
2456* Awful currently doesn't detect if cookies are enabled on the client side.
2457
2458* Reloading of compiled applications is not supported (i.e., you have defined a page to reload your compiled applications). See [[http://bugs.call-cc.org/ticket/442|ticket #442]].
2459=== License
2460
2461BSD
2462
2463=== Version history
2464
2465===== version 0.32
2466* Added {{method}} keyword parameter for {{define-page}}.  Now the page router takes into account the HTTP method, so it is possible to have two different pages using the same path but different methods.
2467* Added {{error-handler}} keyword parameter for {{ajax}}, {{ajax-link}} and {{periodical-ajax}} (suggested by Thomas Hintz)
2468* {{ajax}} and friends send {{Content-Type: application/json}} when {{update-targets}} is non-#f
2469* {{ajax}} bugfix: only opens db connection and refresh session when the page access is allowed
2470* The default value for {{awful-backlog}} has been set to 100
2471* Updated JQuery from version 1.5.2 to 1.6.3
2472* Dropped {{-lambda-lift}} build option
2473* Added the {{reload-apps}} procedure. {{load-apps}} no longer resets the resources table
2474* {{awful-start}} requires a thunk as argument. With this, awful can be embedded into standalone applications
2475
2476
2477===== version 0.31
2478* Added a tiny wrapper around [[/egg/spiffy-request-vars|spiffy-request-vars]], adding the {{with-request-variables}} macro and exporting {{spiffy-request-vars}}'s converters.
2479* Updated JQuery from version 1.5.1 to 1.5.2.
2480* Better support for multiple applications under the same virtual host ({{add-request-handler-hook!}} and {{remove-request-handler-hook!}})
2481* {{$db}} checks if database access is enabled via {{(enable-db)}} and throws an error if it is not.
2482* Fixed critical bug regarding to parameters and thread reuse by Spiffy
2483* Fixed {{redirect-to}} but introduced in version 0.29
2484
2485===== version 0.30
2486* The {{(ajax-library)}} is always linked before any other scripts and javascript code in the headers (e.g., when {{(javascript-position)}} is {{top}}).
2487* Ajax-related procedures simplifications and bugfix in the session awareness code when called from {{define-session-page}}.
2488
2489===== version 0.29
2490* Updated JQuery from version 1.5.0 to 1.5.1.
2491* {{ajax}} and {{periodical-ajax}} bugfix (for situations when they are used simultaneously, or {{periodical-ajax}} and {{add-javascript}}).
2492* The default URI for {{ajax-library}} is now protocol-relative (thanks to Peter Bex).
2493* Added the {{javascript-position}} parameter.
2494
2495===== version 0.28
2496* Updated JQuery from version 1.4.3 to 1.5.0.
2497* {{ajax}} and friends ({{periodical-ajax}}, {{ajax-link}}) are now session-aware when called from {{define-session-page}} (e.g., you don't need to explicitly pass the session identifier).
2498* Added the {{cache}} keyword parameter for {{ajax}}, {{ajax-link}} and {{periodical-ajax}}.
2499* The HTTP request variables are now parsed and made available on demand, when {{$}} is called for the first time for each request (thanks to David Krentzlin).
2500* Applications are no longer loaded with administrator privileges when awful is run by administrator and configured to switch to a non privileged user. For code which needs administrator privileges (like binding to low ports, IP addresses, user/group settings etc), there's a new command line option for the awful application server: {{--privileged-code}}.  '''Warning''': if you rely on your configuration performing actions with administrator privileges, this change may affect your code.
2501* {{define-session-page}} bug fix (it was not properly obtaining the session identifier).
2502
2503
2504===== version 0.27
2505* Require the {{regex}} egg, for chickens >= 4.6.2
2506
2507===== version 0.26
2508* {{define-page}} allows page redefinitions
2509* Added the {{undefine-page}} procedure
2510* Fancy web REPL (enabled by default).  The awful application server now accepts the {{--disable-web-repl-fancy-editor}} command line option to disable the web REPL fancy editor.
2511* Added the following parameters, related to the fancy web REPL: {{enable-web-repl-fancy-editor}} and {{web-repl-fancy-editor-base-uri}}.
2512* Bug fix for the development mode: requests to the {{/reload}} path killed {{/web-repl}} and {{/session-inspector}}
2513
2514===== version 0.25
2515* The awful application server can now be used with the {{--development-mode}} command line option, which enables the web REPL, the session inspector (when {{enable-session}} is #t) for the localhost and on-browser error messages and backtraces.  When running in development mode, the {{/reload}} path is defined to reload awful apps.
2516* The awful application server now supports the {{--ip-address}} and {{--port}} command line options.
2517* {{use-ajax}} keyword parameter for {{define-page}} (for when {{enable-ajax}} is {{#f}} and you need ajax for some specific pages only)
2518* Added {{awful-response-headers}} and {{development-mode?}} parameters
2519
2520===== version 0.24
2521* initial support for storing session identifiers in cookies.  Added the {{enable-session-cookie}} and {{session-cookie-name}} parameters.  By default, cookies-sessions are enabled (relevant only when using sessions, of course). '''Warning''': if your code relies on the availability of session identifiers in the query string or in the request body for whatever reason, it will break.
2522* initial support for HTTP redirection via {{redirect-to}}.
2523* web-repl and session-inspector beautification
2524* web-repl and session inspector provide a {{headers}} keyword parameter
2525* fixes for {{define-page}} regarding to regex-based paths
2526* {{ajax}} always prioritizes the {{success}} keyword parameter value (when it's given) to generate code for JQuery's {{success}} attribute, even when {{target}} and {{update-targets}} are given
2527* awful (the application) handles the {{-v}} and {{--version}} command line options
2528
2529===== version 0.23
2530* added the {{update-targets}} keyword parameter for {{ajax}}, {{periodical-ajax}} and {{ajax-link}} procedures (multiple targets update support)
2531* added the {{debug-resources}} parameter for debugging the resources table
2532* the {{js}} keyword parameter for {{ajax}}, {{periodical-ajax}} and {{ajax-link}} has been renamed to {{success}} (to match JQuery's API naming for Ajax). '''Warning''': if your code uses the {{js}} keyword parameter for {{ajax}}, {{periodical-ajax}} or {{ajax-link}}, this change will break your code.
2533* the javascript variable bound to the response data on successful ajax request has been renamed to {{response}} (it was {{h}} before). The same warning for the {{js}}->{{success}} renaming is valid for this change, since it is directly related to {{js}} (now {{success}}).
2534* the default value for {{main-page-path}} is now {{"/"}} (it was {{"/main"}} before).  There's no more main page redirection.  '''Warning''': if your code relies on hardcoded {{"/main"}} paths (instead of using {{(main-page-path)}}) or if you rely on the main page automatic redirection, this change will break your code.
2535* {{ajax}} bugfix regarding to session identifiers (could cause "Invalid session ID" errors in some cases, specially with {{define-session-page}}).
2536* better handling of URI paths regarding to paths as directories (see FAQ's ''How does awful bind URIs to files/directories on the filesystem and procedures?'')
2537
2538===== version 0.22
2539* bug fix: fixed unintended shadowing of {{js}} in ajax
2540* added the {{prelude}} keyword parameter for {{ajax}}, {{periodical-ajax}} and {{ajax-link}}
2541* {{$db}} supports the {{values}} keyword parameter (patch by Stephen Eilert)
2542* awful (the application) can now be invoked without arguments
2543* awful (the application) handles {{-h}} and {{--help}}
2544* dropped [[/eggref/4/jsmin|jsmin]] requirement
2545
2546===== version 0.21
2547* ajax and main page redirection issues fixes
2548
2549===== version 0.20
2550* {{page-access-control}} controls access to pages even when no session is in use
2551* '''Warning''': the following parameters have been removed: {{enable-reload}}, {{reload-path}} and {{reload-message}}.  Now the way to define reloaders is via {{define-page}}.
2552* new parameter: {{awful-apps}} (a list of awful applications as passed to the awful server)
2553
2554===== version 0.19
2555* bug fix for {{(reload-path)}} handler
2556
2557===== version 0.18
2558* support for regex-based page paths (see {{define-page}})
2559* {{define-page}} checks whether the second arg is a procedure.
2560* use {{-O3 -lambda-lift}} instead of {{-O2}} for compilation
2561* {{main-page-path}} redirection made with code stolen from [[/egg/spiffy|spiffy]]'s {{send-response}}
2562
2563===== version 0.17
2564* .meta bug fix.  postgresql is not required as a dependency (thanks to Stephen Pedrosa Eilert for pointing this issue).
2565
2566===== version 0.16
2567* added {{define-session-page}}
2568* bug fix for {{link}}
2569
2570===== version 0.15
2571* jquery updated to 1.4.2 ({{ajax-library}}).
2572
2573===== version 0.14
2574* {{link}}'s {{args}} keyword parameter renamed to {{arguments}} (the same as {{ajax}}'s).
2575
2576===== version 0.13
2577* Session-aware {{link}} and {{form}} procedures.  Bug fix for {{ajax-link}} (was not passing the {{class}} keyword argument to <a>).
2578
2579===== version 0.12
2580* Containers for user and password fields ({{login-form}})
2581
2582===== version 0.11
2583* awful sets Spiffy's {{root-path}} to {{(current-directory)}}
2584
2585===== version 0.10
2586* Multiple database support. Currently Postgresql (via [[/egg/postgresql|postgresql]] egg) and Sqlite3 (via [[/egg/sqlite3|sqlite3]] and [[/egg/sql-de-lite|sql-de-lite]] eggs) are supported.  See [[/egg/awful-postgresql|awful-postgresql]], [[/egg/sqlite3|sqlite3]] and [[/egg/sql-de-lite|sql-de-lite]] eggs.
2587* Removed requirement for postgresql
2588* {{enable-db}} is now a procedure (not a parameter as before) and accepts no arguments
2589
2590===== version 0.9
2591* {{login-form}} gets the {{user}} refilled when the session or passowrd is not valid.  This feature may be disabled by setting the {{refill-user}} keyword parameter for {{login-form}} to {{#f}} (default is {{#t}}).  Thanks to Arthur Maciel for suggesting this feature.
2592
2593===== version 0.8
2594* jquery updated to 1.4.1 ({{ajax-library}}).
2595* support for jquery's {{live}} method ({{live}} keyword parameter for {{ajax}}, {{ajax-link}} and {{periodical-ajax}}).  See [[http://api.jquery.com/live/]]
2596* bug fixes: {{periodical-ajax}} and {{ajax-link}} propagate {{vhost-root-path}} to {{ajax}}
2597* added {{awful-start}} and dropped spiffy requirement for awful (the server)
2598* dropped requirement for miscmacros
2599* added more ajax tests
2600
2601===== version 0.7
2602* {{ajax-link}} accepts all {{<a>}}'s keyword arguments
2603
2604===== version 0.6
2605* Explicitly depends on [[/egg/http-session|http-session]] 2.0
2606
2607===== version 0.5
2608* Reload handler register the reload path after reloading.
2609
2610===== version 0.4
2611* {{disable-reload?}} renamed to {{enable-reload}}.  {{enable-reload}} is {{#f}} by default.
2612
2613===== version 0.3
2614* {{awful}} (the server) allows applications to use Chicken syntax ({{use}}, {{include}} etc)
2615
2616===== version 0.2
2617* Added javascript compression support
2618
2619===== version 0.1
2620* Initial release
2621
Note: See TracBrowser for help on using the repository browser.