Fermion – The Scheme Web Server
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)
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.
Links:
Fermion documentation.