1 Deprecation notice
1.1 Migrating to serve/ servlet without using Dispatch
1.2 Migrating to serve/ servlet using Dispatch
2 Using Instaweb
3 API
instaweb
4 Tips and caveats
5 Acknowledgements
Version: 4.1.3.3

Instaweb: Instant Web Publishing Tool

Noel Welsh and Dave Gurnell

{noel, dave} at untyped

Instaweb has been deprecated as of PLT 4.1.3. See the Deprecation notice for more information.

Instaweb makes running servlets in the PLT web server simple by:

1 Deprecation notice

As of version 4.1.3, the PLT Web Server contains a quick-start procedure called serve/servlet. This procedure makes Instaweb largely unnecessary: the package has consequently been deprecated and no future updates are planned.

Instaweb users are advised to rewrite their applications using serve/servlet. This is made considerably easier using the Dispatch package from Untyped.

The next section describes how to migrate from Instaweb to serve/servlet if you are not using Dispatch; the following section describes the transition if you are using Dispatch.

1.1 Migrating to serve/servlet without using Dispatch

Instaweb requires you to write your web application in a separate "servlet" module. serve/servlet removes this requirement by allowing you to pass a controller procedure directly as an argument. This is similar to the go! procedure in Instaservlet.

Instaweb and serve/servlet use filesystem and servlet dispatcher procedures to handle requests. The dispatchers are chained together such that if one cannot handle a request the other is invoked. However, the order of dispatch is different:

To recreate Instaweb-style behaviour using serve/servlet, use code like the following:

  (require net/url
           web-server/http
           web-server/servlet-env
           web-server/dispatchers/dispatch
           ; Servlet module:
           ; - provides a 'start' procedure
           ; - optionally provides a continuation 'manager'
           "servlet.ss")
  
  ; Helper procedures --------------------------------
  
  ; url -> boolean
  (define (static-file-url? url)
    (let ([str (url->string url)])
      (cond [(regexp-match #rx"^/stylesheets/" str) #t]
            [(regexp-match #rx"^/javascript/"  str) #t]
            ; and so on...
            [else #f])))
  
  ; request -> response
  (define (make-not-found-response request)
    ; create a pretty 404 response...)
  
  ; Servlet procedure --------------------------------
  
  ; request -> response
  (define (start-wrapper request)
    (when (static-file-url? (request-uri request))
      (next-dispatcher))
    (start request))
  
  ; Main program body -------------------------------
  
  (serve/servlet
   start-wrapper
   ; blank regexp passes all requests to the servlet:
   #:servlet-regexp #rx""
   ; initial URL to send to the browser:
   #:servlet-path "/"
   ; default port is different:
   #:port 8765
   ; customise the continuation manager:
   ; omit this argument if your servlet module does not
   ; provide a 'manager' identifier
   #:manager manager
   ; prettify 404 messages (optional):
   #:file-not-found-responder make-not-found-response)

1.2 Migrating to serve/servlet using Dispatch

As of version 1.6, Dispatch interoperates with serve/servlet in an intuitive manner: it calls next-dispatcher when none of the site’s URL patterns rather than displaying a 404 page.

To recreate Instaweb-style behaviour using serve/servlet and Dispatch, use code like the following:

  (require web-server/http
           web-server/servlet-env
           web-server/dispatchers/dispatch
           (planet untyped/dispatch)
           (planet untyped/dispatch/response)
           ; Servlet module:
           ; - provides a 'start' procedure that uses Dispatch
           ; - optionally provides a continuation 'manager'
           "servlet.ss")
  
  ; Main program body -------------------------------
  
  (serve/servlet
   ; provided by servlet.ss:
   start
   ; blank regexp passes all requests to the servlet:
   #:servlet-regexp #rx""
   ; initial URL to send to the browser:
   #:servlet-path "/"
   ; default port is different:
   #:port 8765
   ; customise the continuation manager:
   ; omit this argument if your servlet module does not
   ; provide a 'manager' identifier
   #:manager manager
   ; pretty 404 messages provided by Dispatch:
   #:file-not-found-responder make-not-found-response)

2 Using Instaweb

If you have a servlet in a module called "servlet.ss" in the current directory, you can run it in the web server simply by requiring Instaweb and calling the instaweb function with no arguments:

  #lang scheme/base
  (require (planet schematics/instaweb/instaweb))
  (instaweb)

This will start the web server on port 8765 and listening only to connections from localhost (127.0.0.1). You can view your servlet by visiting http://127.0.0.1:8765/ in your web browser.

You can override these defaults, and many others, by passing keyword arguments to the instaweb function. For example, you can choose a different port:

  (instaweb #:port 4567)

or use a different file name for your servlet:

  (instaweb #:servlet-path "my-servlet.ss")

If you give a relative path for the servlet, as above, it is resolved relative to the value of the current-directory parameter.

If you want to make your use of Instaweb unaffected by the value of current-directory, use the define-runtime-path form from the scheme/runtime-path package to define the path to the servlet:

  #lang scheme/base
  (require (for-syntax scheme/base)
           scheme/runtime-path)
  (define-runtime-path servlet-path "./servlet.ss")
  (instaweb #:servlet-path servlet-path)

If you want to serve static files in addition to your servlet you can put them in a directory called htdocs (again, relative to the current-directory parameter) or specify a different path to instaweb:

  (instaweb #:htdocs-path '("public-html"))

Note that you give a list of paths, so you can specify multiple directories. Files matching the path portion of the request URL are searched for in these directories. If no matching file is found control is passed to your servlet. This means your servlet will receive all HTTP requests that do not match the path of an existing file.

If the instaweb procedure is not sufficient for your needs, try the serve/servlet procedure in the PLT web server.

3 API

 (require (planet schematics/instaweb/instaweb))

The main API for Instaweb.

(instaweb [#:servlet-path servlet-path    
  #:port port    
  #:listen-ip listen-ip    
  #:htdocs-path htdocs-path    
  #:mime-types-path mime-types-path    
  #:servlet-namespace servlet-namespace])  void?
  servlet-path : (U path? string?)
   = (build-path (current-directory) "servlet.ss")
  port : integer? = 8765
  listen-ip : (U string? #f) = "127.0.0.1"
  htdocs-path : (listof (U path? string?))
   = (list (build-path (current-directory) "htdocs"))
  mime-types-path : path?
   = (build-path (instaweb-directory) "mime.types")
  servlet-namespace : (listof require-spec) = null

Runs Instaweb on an application that is packaged as a single servlet:

All relative paths are resolved relative to the current-directory.

4 Tips and caveats

Your servlet is not required to reside under a URL beginning with "/servlets/<file-name>". It receives all requests that don’t match a file in the htdocs direcory.

Calling your servlet is the last step in the web-server dispatching process. Your servlet should return a 404 response if it receives a URL it cannot process.

If you want to run a Instaweb launched servlet on a server you probably don’t want an interactive terminal. This is fine: Instaweb will detect when it doesn’t have a terminal and so avoid filling your logs with rubbish. Simply spawn a new process to run MzScheme and prevent signals from interferring with it:

  nohup mzscheme run-servlet.ss &

5 Acknowledgements

Matthew Flatt, Jens Axel Soegaard, and Dave Herman for suggestions for dealing with a missing terminal, and suspending the main thread.

Eric Hanchrow, for pointing out documentation typos.