Updated 2011-08-26 02:15:24 by RLE

Web server in one page of Tcl code:
 What: DustMote
 Where: http://www.simtel.net/pub/pd/6948.html
 Description: Tiny HTTP server written in Tcl with nearly no features.
        Designed for the user to easily add the features they want in Tcl.
        Size is only 3k, so it can be easily modified.
        Uses non-blocking channels to support many clients simultaneously.
        Tested heavily on Windows 95, moderately on Linux, and lightly on MacOS.
 Updated: 10/2002
 Contact: mailto:hmk@nadn.navy.mil (Harold Melvin Kaplan)

LES on 20040929: The wind of time has taken this dust mote away. We shall be taken as well sooner or later.

Larry Smith on 20041007: It's small enough that it can be included here:
 # <html><head><title>DustMote source.</title></head>
 # <body bgcolor=white><plaintext>

 # This web server program has a smaller source than any other
 # that I have seen or heard of.
 # Its name is DustMote, and I hereby place it in the public domain.

 # I wrote it in the Tcl language because Tcl is free, easy, stable, and
 # well documented. For more documentation than comes with the Tcl
 # download, one may purchase Brent B. Welch's excellent book, "Practical
 # Programming in Tcl and Tk," second edition, Prentice Hall PTR. It is
 # well worth the money. It is true that Tcl is not remarkably speedy, but
 # it is fast enough for my site, and, though not multi-threaded, it can
 # handle many clients at the same time asynchronously, by the use of
 # non-blocking channels.

 # Of course, there are now many freeware server programs to be downloaded
 # from the web, and most of them are sturdy professional jobs that go like
 # lightning and swarm with useful features. The businessperson ought to
 # use one of those. I am an amateur, so I had to write the program myself.
 # There are nearly no features. All DustMote can do is serve files, both
 # text and image. I offer it to fellow amateurs, so they can ignore other
 # people's features and think up new features that have never been thought
 # up before.

 # If you do use my program, remember to change the definition of "root" to
 # suit your computer. Be sure to use forward slashes, not backward, or
 # else double them so Tcl will understand them rightly.

 # Please E-mail complaints to hmk@nadn.navy.mil and do not try to spare my
 # feelings. The date of this revision is May 26, 1998.

 # Yours truly,
 # Harold Kaplan.

 set root "f:/public_html"
 set default "index.html"
 set port 80

 proc bgerror {trouble} {puts stdout "bgerror: $trouble"}

 proc answer {socketChannel host2 port2} {
   fileevent $socketChannel readable [list readIt $socketChannel]

 proc readIt {socketChannel} {
   global root default
   fconfigure $socketChannel -blocking 0
   set gotLine [gets $socketChannel]
   if { [fblocked $socketChannel] } then {return}
   fileevent $socketChannel readable ""
   set shortName "/"
   regexp {/[^ ]*} $gotLine shortName
   set many [string length $shortName]
   set last [string index $shortName [expr {$many-1}] ]
   if {$last=="/"} then {set shortName $shortName$default }
   set wholeName $root$shortName

   if {[catch {set fileChannel [open $wholeName RDONLY] } ]} {
     puts $socketChannel "HTTP/1.0 404 Not found"
     puts $socketChannel ""
     puts $socketChannel "<html><head><title><No such URL.></title></head>"
     puts $socketChannel "<body><center>"
     puts $socketChannel "The URL you requested does not exist on this site."
     puts $socketChannel "</center></body></html>"
     close $socketChannel
   } else {
     fconfigure $fileChannel -translation binary
     fconfigure $socketChannel -translation binary -buffering full
     puts $socketChannel "HTTP/1.0 200 OK"
     puts $socketChannel ""
     fcopy $fileChannel $socketChannel -command [list done $fileChannel $socketChannel]


 proc done {inChan outChan args} {
   close $inChan
   close $outChan

 socket -server answer $port
 vwait forEver

MS offers a small change that will increase the performance for multiple simultaneous queries. Key idea: replace read/puts with fcopy. Incidentally, that should be puts -nonewline in the original.

The idea is to add
    proc done {inChan outChan args} {
        close $inChan
        close $outChan

move the "close $socketChannel" to the first branch, and replace the last three lines of the second branch with
     fcopy $fileChannel $socketChannel -command [list done $fileChannel $socketChannel]

MJ - 20070128: Added suggestion by MS and braced expr's


  • outstanding 41 lines of code!
  • works with images
  • smaller than wibble
  • mini demo webserver seems not to work with images
  • smallest tcl server to run a internal info website with just tcl 8.6 and dustmote! awesome!

See also: