home > writings > Fermion - The Scheme Web Server
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'. Now you can 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) ;; Size of request header ;; limited to 112kb. 'max-body-length (* 512 1024) ;; Size of request body limited to ;; 512kb. 'max-response-size (* 512 1024)))) ;; Size of response limited to ;; 512kb.
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 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.
Comments: