2009 August 19
Fermion is a fast and secure web server written in Scheme. It is optimized to serve dynamic content generated by Scheme scripts. It is part of the larger Spark-Scheme project. It uses light-weight green threads to handle client requests and can efficiently serve thousands of simultaneous connections. The following code starts an instance of Fermion:
;; file: my-http.ss
(import (net) (http))
(web-server-start (web-server))
Create an HTML file called 'index.html' and place it along with 'my-http.ss'. This will be the default page served by our http server. Start the web server with the command `spark my-http.ss'. You will be able to access 'index.html' with the URL: http://localhost.
The forte of Fermion is not in serving static files, but in generating content dynamically based on user input or some other volatile parameter. Let us write a simple web application that will greet the user based on the time of the day.
;; file: greet.ss
(import (aura))
(define (greet new-uri state)
(((sgml
`(html
(body
(b ,(greeting-by-hour)))))
'text)))
(define (greeting-by-hour)
(let ((hour (date-hour (seconds->date (current-seconds)))))
(cond ((<= hour 12) "Good morning!")
((<= hour 17) "Good afternoon!")
(else "Good evening"))))
(list greet)
The procedure 'greet' will be executed by the web server, by passing it two arguments. 'new-uri' will be a dynamically generated URI to which any further requests, like a form POST, should be send. 'state' is a hash table that contains the current state of the session. For instance, it will contain values posted by previous requests. The web application exports a list of
procedures that will be executed by Fermion, in the given order. Thus the programmer can design a web application as a sequence of operations, much like a normal console program. The greet sample also makes use of a library called aura which can be used to write SGML documents in Scheme syntax.
Fermion is a secure web server. It is possible to impose some control over HTTP requests by using configuration options. An example is given below:
(define httpd (web-server
(list 'port 8080 ;; Web server will listen
;; on port 8080.
'session-timeout (* 2 60) ;; 2 minutes
'max-header-length (* 112 1024)
'max-body-length (* 512 1024)
'max-response-size (* 512 1024))))
Fermion provide hooks where new procedures can be plugged-in to implement advanced security and compliance features. For instance, the following sample shows how to hook in a procedure to check the length of the request URI. If the URI contain more than 512 characters, the request will be blocked.
(import (net)
(http-request-parser)
(http))
(define httpd (web-server))
;; The security hook procedure.
(define (check-uri-length httpd
client-connection
http-request)
(cond ((> (string-length (http-request-uri http-request))
512)
(printf "Request URI too long. Closing connection.~n")
(flush-output)
(socket-close (connection-socket client-connection))
#f)
(else ;; Let the web server's request
;; handler do its job.
#t)))
(web-server-hook! httpd 'before-handle-request
check-uri-length)
(web-server-start httpd)
User defined policies can be applied on the response by using the 'before-send-response hook.
I hope that Scheme hackers will find Fermion useful in their real-world web development tasks.