Here's a "Hello, world!" example to be run by awful (hello-world.scm).

(use awful)(define-page(main-page-path)(lambda()"Hello, world!"))

To run this example, execute:

$ awful hello-world.scm

Then access localhost:8080 using your favourite web browser.

Without any configuration, awful listens on port 8080. Since awful uses Spiffy behind the scenes, you can configure the web server parameters using Spiffy's.

define-page is the primitive procedure to define pages. In the simplest case, it takes as arguments a path to the page and a procedure to generate the page contents. The path to the page you use as the first argument is the same to be used as the path part of the URL you use to access the page.

In the example we use the main-page-path parameter, which is one of the awful configuration parameters. The default is "/".

If you look at the page source code, you'll see that awful created an HTML page for you. Awful uses the html-tags's html-page procedure behind the scenes. You can customize the page either by passing html-page's keyword parameters to define-page or by setting the page-template parameter with your favourite procedure to generate pages. page-template is a one-mandatory-argument procedure which receives the page contents and returns a string representing the formatted contents. define-page would still pass the html-page keyword parameters, so you can make use of them (the page-template procedure should be defined considering them -- if you don't need them, just ignore them by defining (lambda (contents . args) ...)).

You can also use some global page-related parameters if all pages use the same CSS, doctype and charset (page-css, page-doctype and page-charset, respectively).

An alternative way to write Awful scripts is by using the #!/path/to/awful shebang line. Example:

The ++ procedure is an alias to string-append (name inspired by Haskell's operator to concatenate strings).

So, restart the web server to reload the code, then access the main page using an argument, represented by the person query string variable: http://localhost:8080/?person=Mario. You'll see a page showing Hello, Mario!.

When we upgraded our "Hello, world!" example to the improved one which can use an argument passed through the URL, we needed to modify the code and restart the web server to reload the application code. Awful provides a way to reload the code via URL without restarting the server. To do that, we can define a special page whose handler just reloads the code:

When used in development mode (see the --development-mode command line option for the awful application server), awful automatically defines a /reload path (available to any host) for reloading all the applications.

Awful provides a way to (hopefully) make the use of ajax straightforward for web applications.

By default, the ajax support is disabled, but it can be easily globally enabled by setting the enable-ajax parameter to #t. When you enable ajax via enable-ajax, all the pages defined via define-page will be linked to the JQuery javascript library. If you want just a couple of pages to have ajax support (i.e., not global ajax support), you can use the use-ajax keyword parameter for define-page, so only the pages defined with use-ajax: #t have ajax support.

When you have ajax enabled and you want to disable it for specific pages, you can pass #f as the value for the define-page keyword parameter no-ajax.

The URL of the JQuery file can be customized by setting the ajax-library parameter (the default is Google's API JQuery file).

1. 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.

2. The ID of the DOM element to observe.

3. The event to be handled

4. The procedure to be run on the server-side.

So, in the example, ajax will bind the fourth argument (the procedure) to the first argument (the path) on the server side. Then it will add javascript code to the page in order to wait for click events for the element of ID greetings. When we click "Hello, <person>!", we'll get Hello, awful! printed on the page as reply. ajax updates the DOM element whose id is the value of the target keyword parameter ("greetings-reply", in the example).

For the very specific case of creating links that execute server side code when clicked, awful provides the ajax-link procedure. So our example could be coded like:

As with ajax, database access is not enabled by default. To enable it, you need to pick one the awful database support eggs and call the enable-db procedure. Since version 0.10, and differently from the enable-* parameters, enable-db is a zero-argument procedure provided by each of awful database-support eggs. So, if you use awful-postgresql, the enable-db procedure will automatically set up awful to use a postgresql database.

Additionally, to access the db, you need to provide the credentials. You can provide the credentials by setting the db-credentials parameter. See the documentation for the eggs corresponding to the database type you are using (postgresql for Postgresql and sqlite3 or sql-de-lite for Sqlite3.)

To actually query the database, there's the $db procedure, which uses as arguments a string representing the query and, optionally, a default value (a keyword parameter) to be used in case the query doesn't return any result. $db returns a list of lists. Below is an usage example:

Hint: for Sqlite3 databases, db-credentials should be the path to the database file.

There's also the $db-row-obj procedure for when you want to access the results of a query by row name. $db-row-obj returns a procedure of two arguments: the name of the field and, optionally, a default value to be used in case the field value is #f.

If you need more flexibility to query the database, you can always use the (db-connection) parameter to get the database connection object and use it with the procedures available from the your favorite database egg API.

Awful provides a very basic (awful?) support for creating authentication pages.

The basic things you have to do is:

1. Enable the use of sessions:

(enable-session #t)

2. Set the password validation parameter. This parameter is a two argument procedure (user and password) which returns a value (usually #t or #f) indicating whether the password is valid for the given user. The default is a password which returns #f. Let's set it to a procedure which returns #t is the user and the password are the same:

(valid-password?
(lambda(user password)(equal? user password)))

3. Define a login trampoline, which is an intermediate page accessed when redirecting from the login page to the main page.

(define-login-trampoline"/login-trampoline")

4. Create a login page. Awful provides a simple user/password login form (login-form), which we are going to use. Here's our full example so far (using the basic "Hello, world!" as main page).

That's the very basic we need to set an auth page. If the password is valid for the given user, awful will perform a redirect to the main page (main-page-path parameter) passing the user variable and its value in the query string . If the password is not valid, awful will redirect to the login page (login-page-path parameter) and pass the following variables and values:

reason

the reason why awful redirected to the login page. It may be invalid-password, for when the password is invalid for the given user; or invalid-session for when the session identifier is not valid (e.g., the session expired).

attempted-page

the URL path to page the user tried to access, but couldn't because either he/she was not logged in or he/she provided an invalid session identifier.

user

the user used for the form user field.

Now we're gonna change our main page to store the user in the session and retrieve it to make the greetings message:

Here we can see the two procedures to access the session: $session and $session-set!.

$session-set! accepts two arguments: the first one is the name of the session variable and the second one is its value.

$session takes the name of the session variable as argument and returns its session value. We can optionally use a second argument to specify a default value, in case the session variable is not bound or is #f.

Awful provides a session inspector, so we can easily see the session contents for a given session identifier. By default, the session inspector is disabled. We can enabled it using the enable-session-inspector procedure, passing the session inspector URL path as argument:

(enable-session-inspector "session-inspector")

Now, if you log in and try to access http://localhost:8080/session-inspector, you'll get ... an access denied page.

Awful provides a way to control access to the session inspector (session-inspector-access-control parameter). The session-inspector-access-control parameter is an one-argument procedure which returns #f or some other value to indicate whether the access to the session inspector is allowed or not. By default, it blocks all access. Let's configure it so we can access the session inspector from the local machine (whose IP number is 127.0.0.1):

For further run-time, server-side web hacking, awful provides a REPL that you can use via web browser.

The web REPL can use either a plain HTML textarea for the input area or a more featureful editor (based on codemirror). By default, the web REPL uses the fancy editor.

The activation and control access are basically the same as for the session inspector. The relevant procedure and parameters are:

enable-web-repl

web-repl-access-control

web-repl-access-denied-message

enable-web-repl-fancy-editor

web-repl-fancy-editor-base-uri

Here's a screenshot (using the fancy editor):

When the --development-mode option is given to the awful application server, the web REPL is automatically enabled and is avaliable from /web-repl. The awful application server also accepts the --disable-web-repl-fancy-editor command line option to disable the web REPL fancy editor.

Parameters are thread-safe, but Spiffy (the web server used by awful) doesn't garantee that each request will be handled by a different thread, so awful has to provide a way to overcome that, otherwise hosting multiple applications under the same virtual host can be very painful, since it's not guaranteed that parameters will be reset at each request (awful does reset some critical and obviously per-request ones like http-request-variables, awful-response-headers, db-connection and sid).

Awful provides the possibility of running hooks when handling requests, so you can set parameters for multiple applications in a way that they don't interfere with others.

<app1> <app2> ... are files containing code to be loaded by the awful application server.

--ip-address can be used to bind the web server to the given IP address.

--port can be used to make the web server listen to the given port.

--ip-address and --port take precedence over the Spiffy parameters to specify the server IP address (server-bind-address) and port (server-port).

The --development-mode option is intended to be used during the development of your web application. It's not recommended to run awful with --development-mode in production. The development mode enables the web REPL and the session inspector (when enable-session is #t) for the localhost, prints error messages and backtraces to the client (e.g., web browser) and HTTP server debugging messages to the current-error-port. It also makes the /reload path available for reloading awful applications.

When in development mode, the web REPL and the session inspector are available from the /web-repl and /session-inspector paths.

If you enable the development mode you can still use enable-web-repl and enable-session-inspector to customize their respective paths and access control procedures (although the development mode always allows access to web REPL and session inspector for the localhost).

The --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:

As 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 accepting 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 enabling SSL, for example).

The privileged code is not reloaded when you reload applications via a defined reload page.

Create configuration files for awful. In the privileged configuration file (privileged.conf below) you can set all the configuration parameters for awful and spiffy which require administrator provileges.

In another file (awful.conf below) you can put whatever code which does not need administrator provileges.

When #t, enables debugging of awful's resources table (an alist mapping paths (or regexes) and vhost paths to their corresponding procedures to be executed on the server side upon request). The debugging data is sent to the file pointed by debug-file. The default value is #f.

When #t, makes define-page link the ajax-library to the generated page. It's effect is global, that is, once enable-ajax is set to #t, all pages defined via define-page will be linked to the ajax library, unless when the no-ajax keyword parameter is explicitly set.

The CSS file to be linked by all pages defined by define-page. It can be overwritten by define-page's css keyword parameter. See html-utils's html-page procedure to know about the css keyword parameter syntax.

An one-mandatory-argument procedure to be used by define-page (unless define-page's no-template keyword parameter is set to #f) to generate HTML pages. Although this procedure can take only one mandatory argument, the following keyword arguments are passed:

css

title

doctype

headers

charset

no-ajax

no-template

no-session

no-db

The default value is html-page (see the html-utils egg documentation.)

The base path to be used by the application. All the pages defined by define-page will use app-root-path as the base directory. For example, if app-root-path is set to "/my-app" and "my-page" is used as first argument to define-page, the page would be available at http://<server>:<port>/my-app/my-page.

The default value is "/".

Important: this parameter is evaluated both at page definition time and page request handling time.

Indicates whether the web REPL should use a fancier editor for the input area. The editor is based on codemirror. Without the fancy editor, the input area is a simple HTML textarea. The default value for use-fancy-editor is #t.

Note: these parameters should not be explicitly set and when their use is needed, it's a string sign you're doing something you shouldn't (except for db-connection, which can be used by procedures from the postgresql egg API).

A per-request databaseconnection object. The connection is automatically opened and closed by awful in a per-request basis (unless databases are not being used the no-db keyword parameter for define-page is #t.)

Return a session-aware HTML code for a form, using the <form> procedure from html-tags.

The rest arguments are the same as the ones for the <form> procedure from html-tags, plus no-session, a boolean. If no-session is #t, it forces form to ignore the session even when enable-session is #t.

When enable-session is #t, form automatically generates a hidden input field to pass the session identifier (unless no-session is #t).

Return the HTTP request value for the given variable var. The variable is looked for in both the query string (GET method) and request body (e.g., POST method). See the documentation for the procedure returned by spiffy-request-vars's request-vars for further details.

path is the path to the page. It can be represented by two types: a string and a regular expression object. If it is a string, the path used in the URI will be bound to the given no-argument procedure contents. If it is a regular expression object, any request whose URL path matches the regular expression will br handled by the one-argument procedure contents. This procedure will be given the requested path.

The css, title, doctype, headers and charset keyword parameters have the same meaning as html-page (from the html-utils egg).

If no-ajax is #t, it means that the page won't use ajax, even if the enable-ajax parameter is #t.

If use-ajax is #t, it means that the page will be linked to the ajax library, even if the enable-ajax parameter is #f.

If no-template is #t, it means that no page template (see the page-template parameter) should be used.

If no-session is #t, it means that the page should not use session.

If no-db is #t, it means that the page should not use the database, even when database usage is activated by enable-db and db-credentials is not #f.

If no-javascript-compression is #t the javascript code for the page is not compressed, even when enable-javascript-compression is not #f.

Define a session-aware page. When the page is accessed and a correponding session does not exist, it is created. If the session already exists and is not valid, it is recreated. If the session already exists and is valid, then it is refreshed.

Generate javascript code to be added to the page defined by define-page. Return the generated javascript code (which usually is not useful, so should be discarded).

path is the URL path (a string) of the server side handler. This path is placed under the (app-root-path)/(ajax-namespace) path. So, if your app-root-path is "my-app", your ajax-namespace is "ajax" and you use "do-something" as the first argument to ajax, the URL for the server side handler would be "/my-app/ajax/do-something".

selector is the selector for the DOM element to be observed. If it is a quoted symbol, awful generates a JQuery selector by DOM id (e.g., 'my-selector generates "#my-selector"). If it is a string, awful uses it as-is to generate the JQuery selector (e.g., "input[name^=omg]" generates "input[name^=omg]").

event (a quoted symbol or a list) is the event(s) to be observed. If it is a quoted symbol (e.g., 'click), only this event will be bound. If event is a list of events, all the events from the list will be bound.

proc is a no-argument procedure to be executed on the server side.

The target keyword parameter is the id of the DOM element to be affected by the result of proc.

The method (a quoted symbol, usually 'GET or 'POST) keyword parameter is the HTTP method to be used by the ajax request.

The arguments keyword parameter is an alist mapping request variables (symbols) to their values (strings). ajax uses these arguments to assembly the query string or the request body to send to the server when performing the ajax request.

Example:

arguments: '((var1 . "$('#var1').val()")(var2 . "$('#var2').val()"))

If the no-session keyword parameter is #t, it means that no session should be considered (ajax implicit sends the session identifier when no-session is #f).

If the no-db keyword parameter is #t, it means that the should be no attempt to connect the database, even when database usage is activated by enable-db and db-credentials is not #f.

The vhost-root-path keyword parameter (a string) is the vhost root path. It is useful for explicitly separate pages defined using the same path (see define-page) but for different vhosts.

The prelude keyword parameter (string) is an arbitrary piece of javascript code to be placed right before the ajax request.

The update-targets keyword parameter a boolean indicating whether multiple targets should be updated upon ajax response. When update-targets is used, the procedure proc used as argument to ajax should yield an alist as result. The alist maps DOM elements identifiers to their corresponding values.

The success keyword parameter (string) can be any arbitrary javascript code to be executed on the successful ajax request. The javascript code can assume that a variable response is bound and contains the request resulting data. Here's an example:

The cache keyword parameter (boolean), if set to #f, it will force requested pages not to be cached by the browser. The default value is not set, leaving it to be set by JQuery. See JQuery's documentation for further details.

The meaning of the target, action, method, arguments, success, no-session, no-db, event, vhost-root-path, update-targets and live keyword parameters is the same as for ajax's.

The meaning of the class, hreflang, type, rel, rev, charset, coords, shape, accesskey, tabindex and a-target are the same as for html-tags' <a> procedure (except that a-target is <a>'s target, since ajax uses the target keyword parameter).

The event keyword parameter syntax is the same for ajax's event mandatory parameter.

The keyword parameter css is the CSS to be used the the web REPL page (see the documentation for html-page, from the html-utils egg, for the css keyword parameter.)

The keyword parameter title (a string) is the title for the web REPL page (see the documentation for html-page, from the html-utils egg, for the title keyword parameter.)

The web REPL is automatically enabled by the awful application server when the --development-mode is provided (available from /web-repl). By default, the fancy editor is used, but can be disabled with the --disable-web-repl-fancy-editor command line option for the awful application server.

Instead of using <a> and <form> for creating links and forms, respectively, consider using the link and form procedures instead. They are specially useful when using sessions, since they transparently handle the session identifier for you. Even if you don't use sessions, they may save you some work if one day you decide to use sessions (then you won't have do to anything regarding to links and forms).

You can simply use the --development-mode option for the awful application server to enable the web REPL and the session inspector (when enable-session is #t). The development mode allows access to them for the localhost. When in development mode, the web REPL and the session inspector are available at the /web-repl and /session-inspector paths.

If you want further flexibility, you can customize the web REPL and the session inspector.

Here's a simple recipe to allow access for your local machine to the web REPL (/repl) and to the session inspector (/session-inspector).

When invoked without arguments, awful (the application) starts the web server using the current directory as root path and keeps listening on port 8080. So, if you want to quickly share a file (or some files), change to the directory containing the files and execute awful. The access http://<host>:8080/<the-file-you-want>.

By default, awful uses html-tags to generate HTML for pages. Of course, it can be changed, and you can even use SXML. Here's an example by setting the page-template parameter to use SXML (see the sxml-transforms egg):

Finally, you can create a define-sxml-page procedure which calls define-page and uses the SXML transformations in the page definition body for the <body> section only, using the original template to generate the <html> and <head> sections. This allows you to use the css, doctype and charset parameters in the definition of define-sxml-page.

The code above defines an awful-reload procedure, which requests the /reload path (automatically defined by awful when running in development mode) using lynx. You can use whatever command line HTTP client you want. lynx is handy because of the -dump option, which can be readly displayed by Emacs in the shell command output buffer.

It shows how to implement a very simple web-based Chicken REPL using a sandbox environment (see the sandbox egg documentation) for safe evaluation.

The idea is to have a web page with an input box. Users type the forms they want to evaluate and submit them to the server. The server evaluates the given forms in a sandbox environment and return the results.

Here's the commented code:

(use html-tags awful sandbox);; Here we define the REPL page. It uses the session to store the
;; sandboxed environment. By default, the `main-page-path' parameter
;; value is "/".
(define-session-page(main-page-path)(lambda();; Create the sandbox environment (if it does not exist yet) and
;; store it in the user session.
(unless ($session 'sandbox-env)($session-set! 'sandbox-env
(make-safe-environment
parent:default-safe-environmentmutable: #t
extendable: #t)));; Here we set an ajax handler for the REPL expressions
;; submission. When users change the REPL input widget (i.e., by
;; pressing ENTER), the contents of the text input field are
;; submitted and handled by the procedure given as the forth
;; argument to `ajax'.
(ajax "eval" 'repl-input 'change
(lambda();; This binds the variable `repl-input' from the POST
;; method the the `repl-input' Scheme variable
(let((repl-input ($ 'repl-input)));; We'd better handle exceptions when trying to
;; evaluate the expressions given by users.
(handle-exceptions
exn
;; If something goes wrong, we print the error message
;; and the call chain.
(<pre> convert-to-entities?: #t
(with-output-to-string(lambda()(print-error-message exn)(print-call-chain))));; Here we try to evaluate the given expression in the
;; sandboxed environment stored in the user session.
;; The `repl-output' page div is updated with the result.
(<pre> convert-to-entities?: #t
(safe-eval
(with-input-from-string repl-input read)fuel: 100
allocation-limit: 100
environment:($session 'sandbox-env))))));; Here we pass the contents of the text input to the ajax
;; handler. The default HTTP method used by `ajax' is POST.
arguments: `((repl-input . "$('#repl-input').val()"));; The output of the ajax handler updates the `repl-output'
;; page div.
target:"repl-output");; Here's what is displayed to users
(++ (<h1> "Sandboxed Chicken web REPL")(<input> type:"text"id:"repl-input")(<div> id:"repl-output")));; This tells `define-session-page' to link the page to JQuery
use-ajax: #t)

To run the code above you'll need to install awful and sandbox:

$ chicken-install awful sandbox

Then (considering you save the code above in a file called web-sandbox.scm), run:

$ awful web-sandbox.scm

and access http://localhost:8080.

Here are some screenshots of the code above running on Firefox:

If you try something nasty, the sandbox will abort the evaluation and you'll get an error message and the call chain:

This example is a fortune server in awful. It demonstrates some handy awful features like database access and ajax. You'll need the awful-sql-de-lite egg and its dependencies (which should be automatically installed by chicken-install).

Here's the code for create-database.scm which creates and populates the fortune database:

(use sql-de-lite posix)(define fortunes
'(("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.""Brian Kernighan")("In order to understand recursion, one must first understand recursion.")("If debugging is the process of removing software bugs, then programming must be the process of putting them in.""Edsger Dijkstra")("Controlling complexity is the essence of computer programming.""Brian Kernigan")("The function of good software is to make the complex appear to be simple.""Grady Booch")("That's the thing about people who think they hate computers. What they really hate is lousy programmers.""Larry Niven")("First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.""George Carrette")("To iterate is human, to recurse divine.""L. Peter Deutsch")("The best thing about a boolean is even if you are wrong, you are only off by a bit.")("Optimism is an occupational hazard of programming; feedback is the treatment.""Kent Beck")("Simplicity is prerequisite for reliability.""Edsger W. Dijkstra")("Simplicity is the ultimate sophistication.""Leonardo da Vinci")("The unavoidable price of reliability is simplicity.""C.A.R. Hoare")("The ability to simplify means to eliminate the unnecessary so that the necessary may speak.""Hans Hoffmann")("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.""Chris Sacca")))(delete-file* "fortunes.db")(let((db (open-database "fortunes.db")))(exec (sql db "create table fortunes(sentence text, author text)"))(for-each (lambda(fortune)(let*((sentence (car fortune))(author (cdr fortune))(statement
(string-append
"insert into fortunes (sentence, author) values (?,?)")))(exec (sql db statement)
sentence
(if(null? author)""(car author)))))
fortunes)(close-database db))

When 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:

if the path a does not exist, the server replies with the result of the evaluation of the procedure bound to a.

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 web-scheme or .ssp files)

if a is an existing directory and the directory contains one of the files in index-file (see documentation for Spiffy), with the index file contents (or the result of processing the file, in case it is a special one like web-scheme's or .ssp)

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.

Awful currently doesn't detect if cookies are enabled on the client side.

If you are facing weird problems when reloading compiled applications (i.e., you have defined a page to reload your compiled applications), it is possible that a Chicken issue is the cause (see ticket #442).

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).

Added the cache keyword parameter for ajax, ajax-link and periodical-ajax.

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).

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.

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.

The awful application server now supports the --ip-address and --port command line options.

use-ajax keyword parameter for define-page (for when enable-ajax is #f and you need ajax for some specific pages only)

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.

initial support for HTTP redirection via redirect-to.

web-repl and session-inspector beautification

web-repl and session inspector provide a headers keyword parameter

fixes for define-page regarding to regex-based paths

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

awful (the application) handles the -v and --version command line options

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.

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).

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.

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.