Sven Van Caekenberghe's s-http-server Tutorial

How to get started with Sven's minimal Common Lisp s-http-server.

Prerequisite

This page assumes that you are using LispWorks OS X Personal Edition 4.4.6 though s-http-server is written in portable ANSI Common Lisp, and should work out of the box in other environments.

Requirements

You have a working asdf intallation. You can get asdf here and follow this installation instructions.

Get the source

You will need to get s-http-server source from Sven's homepage. Specifically, if you use darcs, wou will need to cd to your chosen destination directory and issue the following commands:

        darcs get http://www.beta9.be/darcs/s-http-server
        darcs get http://www.beta9.be/darcs/s-sysdeps
        darcs get http://www.beta9.be/darcs/s-base-64
        darcs get http://www.beta9.be/darcs/s-utils
        darcs get http://www.beta9.be/darcs/puri
        

In order for asdf to be able to locate each of the required components, you will need to create a symbolic link to each of the .asd file, as in:

        ln -s /Users/verec/workspace/WebLisp/s-http-server/s-http-server.asd .
        ln -s /Users/verec/workspace/WebLisp/s-sysdeps/s-sysdeps.asd .
        ln -s /Users/verec/workspace/WebLisp/s-base-64/s-base-64.asd .
        ln -s /Users/verec/workspace/WebLisp/s-utils/s-utils.asd .
        ln -s /Users/verec/workspace/WebLisp/puri/puri.asd .
        
Where the final . (dot) of the ln command refers to the current directory, that which you specified as your asdf repository when first installing asdf.

        (setf *print-case* :downcase)     ;; tell Lisp to quit SHOUTING
        
        (load (compile-file "/Users/verec/workspace/WebLisp/asdf.lisp"))
        
        (pushnew "/Users/verec/workspace/registry/" asdf:*central-registry* :test #'equal)
        (asdf:operate 'asdf:compile-op :asdf-install)
        (asdf:operate 'asdf:load-op :asdf-install)
        

Install on your environment

This should be as simple as the follwoing command:

        (asdf:oos 'asdf:load-op :s-http-server)
        

Note that at this time, s-http-server is not asdf-intallable.

Hello World

We set to create a plain vanilla server:

        CL-USER 1 > (asdf:oos 'asdf:load-op :s-http-server)
        
        CL-USER 2 > (in-package :s-http-server)
        #<The S-HTTP-SERVER package, 91/128 internal, 29/64 external>
        
        S-HTTP-SERVER 3 > (defvar *server* (make-s-http-server :name "Hello-World Server"))
        *server*
        
        S-HTTP-SERVER 4 > (inspect *server*)
        
        #<s-http-server "Hello-World Server" port 1701 not running 1009578B>
                            is a s-http-server
        port                1701
        name                "Hello-World Server"
        debug-mode          t
        server-process      nil
        log-stream          #<editor::rubber-stream #<editor:buffer CAPI
                            interactive-pane 3> 10EC2907>
        contexts            ((s-http-server-handler "/s-http-server" :builtin))
        
        S-HTTP-SERVER 6 : Inspect 2 > :q
        

Checking the Installation

We can now check whether everything works. Since the server object is instantiated but not started yet, we get:

We now activate the server:

        S-HTTP-SERVER 8 > (start-server *server*)
        ;; HELLO-WORLD SERVER: Started a new server on port 1701
        #<s-http-server "Hello-World Server" port 1701 running 10ED58DF>
        
        S-HTTP-SERVER 9 > (inspect *server*)
        
        #<s-http-server "Hello-World Server" port 1701 running 10ED58DF>
                            is a s-http-server
        port                1701
        name                "Hello-World Server"
        debug-mode          t
        server-process      #<mp:process Name "Hello-World Server"
                            Priority 3 State "Waiting for connection">
        log-stream          #<editor::rubber-stream #<editor:buffer CAPI
                            interactive-pane 3> 10EC2907>
        contexts            ((s-http-server-handler "/s-http-server" :builtin))
        
        S-HTTP-SERVER 10 : Inspect 1 > :q
        

Adding a static resource handler

We can now add a "static page" server. Note that static-resource-handler is builtin within s-http-server.

        S-HTTP-SERVER 13 > (register-context-handler *server*
                                                     "/my-site"
                                                     'static-resource-handler
                                                     :arguments
                                                        '("/Users/verec/Sites/lisp/tutorials/svc/"))
        

Adding a dynamic handler

But things get really interesting when we can add dynamic contents. For this, we define our own dynamic content handler:

        (in-package :s-http-server)
        
        (defun dynamic-context-handler (s-http-server handler http-request stream)
          "The Dynamic Version that takes over when no default applies."
          (logm s-http-server "Running dynamic s-http-server handler")
          (let ((body (with-output-to-string (out)
                        (format out "<p>Active handler binding is ~s for path ~s</p>"
                                handler
                                (get-path http-request)))))
            (standard-http-html-message-response http-request stream "S-HTTP-SERVER" body)
            t))
        

And register it with s-http-server:

        S-HTTP-SERVER 14 > (register-context-handler *server*
                                                     "/"
                                                     'dynamic-context-handler
                                                     :arguments
                                                        '("no one cares, really")
                                                     :at-end-p t)
        

Note the use of the :at-end-p keyword. This is so more specific handlers will get a chance to match the request first, otherwise, the dynamic-context-handler would always be the most specific handler for any possible query.

Release History

    20060109    JFB     added reference to kpax
    20051223    JFB     first release -- unedited draft