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 a 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) [/sourcecode] The procedure <em>greet</em> will be executed by the web server, by passing it two arguments. <em>new-uri</em> will be a dynamically generated URI to which any further requests, like a form POST, should be send. <em>state</em> 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 <em>greet</em> sample also makes use of a library called <em>aura</em> which can be used to write SGML documents in Scheme syntax. Fermion is a <em>secure </em>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.
Spark-Scheme has moved to GitHub. The new repository is located here. So far, my experience with GitHub can be described as “delightful”. Git is fast. Managing and merging forks are easy. GitHub provides a nice interface to all the good facilities offered by git.
BTW, Amit Saha has volunteered to help me with the project. Welcome, and enjoy the ride Amit!