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

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

awful (wiki): markup typo fix (awful-start)

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