httcld - Micro-HTTP server with embedded TCL

Version 1.1

Introduction

httcld is a very small HTTP server with an embedded TCL (http://www.tcl.tk/) interpreter. In addition to static .html files, it serves .htcl files, which are HTML with embedded tcl code. The tcl is executed on the server, and the resulting output is embedded in the stream sent back to the client. In addition, variables in the tcl namespace may be set and retrieved directly, say by an AJAX script.

The idea for this server came out of a need to have a flexible, fast, but very lightweight backend to support a GUI on an embedded platform. I also wanted efficient support for a more dynamic AJAX-like interface, but the existing backends were much too big for the box. Apache and it's modules took too much memory and storage space, Ruby and Rails likewise. Java was right out.

Thus was born the idea of a specialized HTTP server that could update a very dynamic UI without any more CPU overhead than necessary. Along the way, I decided that it would be nice if I could make the web pages in the UI smarter. This led to the embedded .htcl format.

Prerequisites

httcld requires 2 external libraries:

www.gnu.org/software/libmicrohttpd Version 0.4.0pre1

and

www.tcl.tk Version 8.5

The server also directly contains hash table code from David Crawshaw http://www.zentus.com/c/hash.html

In addition, some of the examples use the Prototype Javascript library from http://www.prototypejs.org/

Download

You may download the latest source tarball here
(http://sourceforge.net/project/platformdownload.php?group_id=247656).

The README file in the source distribution has complete information on building, configuring, and operating the server.

Embedded tcl

Here's an example .htcl file, illustrating embedded tcl and AJAX support (this is protoclock3.htcl in the examples/ directory):

<!--
httcld 1.1 example

This is an example of an Ajax page that calls a tcl proc named "getsysdata" to
periodically update multiple items on a page.  The proc is created in the tcl script
block below, and is called by the Javascript code further down.  This proc returns
multiple items in a JSON string, reducing the number of HTTP calls needed to
update a page.
-->

<tcl>
# this tcl code runs on the server

# return the current server time in JSON format
proc jclock {} {
  return [clock format [clock seconds] -format "\"hour\": \"%H\", \"min\": \"%M\", \"sec\": \"%S\" " ]
}

# return the system load average in JSON format
proc jload {} {
  # if the native.so library was is available
  if {$::native_loaded} {
    # get the load from the system
    return " \"load\": \"[nat_sysload]\" "
  } else {
    # fake a return value
    return " \"load\": \"0 0 0\" "
  }
}

# return a JSON string with the time and system load
proc getsysdata {} {
  # send JSON output
  puts "{\"jval\": { [jclock] , [jload] }}"
}

# log that we loaded this page
log_msg "$argv0 loaded"
</tcl>

<html>
  <head>
    <title> Prototype-based clock </title>
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
    <meta http-equiv="pragma" content="no-cache">
    <!-- load the prototype library here -->
    <script type="text/javascript" src="js/prototype.js"></script>
  </head>
<body>

<!-- here we create the page that the user sees.  Each element returned from
the /tcl/ proc is placed in it's corresponding div -->

Server time:<br>

<table>
 <tr>
  <td>hr:</td><td><div id="hour" class=""></div></td>
  <td>min:</td><td><div id="min" class=""></div></td>
  <td>sec:</td><td><div id="sec" class=""></div></td>
 </tr>
</table>

<table>
 <tr>
  <td>System Load Average: </td><td><div id="load" class=""></div></td><td></td>
 </tr>
</table>

<br>
<div id="debug" class="">

<!-- client-side script -->

<script type="text/javascript">
// this Javascript code runs in the browser

// url that activate the /tcl/ proc defined above
var url = '/tcl/proc?name=getsysdata';

// this sets up Prototype to periodically make the Ajax request to the
// server, and evaluate the JSON response.  The divs in the user page
// above are filled in with the values fron the JSON response.
//
// Note: This function starts on page load, and may be stopped at any
// time.  But once stopped, it can only be restarted by reloading the
// page.
var Ajc = new PeriodicalExecuter(function(pe) {
  new Ajax.Request(url, {
    method: 'get',
    evalJSON: 'force',
    onSuccess: function(transport) {
      // get the JSON output
      var json = transport.responseJSON;
      // now go fill in the divs above
      for (i in json.jval) {
        $(i).innerHTML = json.jval[i];
      }
    }
  });
}, 1); // update every 1 second
</script>

<!-- give it a control button -->
<input type="button" onClick="Ajc.stop();" value="Stop Update">

<body>
</html>

This page, once loaded and started, looks like this in the browser:

portion of example protoclock3 output

Everything within the <tcl> </tcl> tags is executed on the server, the rest is passed unchanged to the browser.

Notice that this example has both server-side and client-side code in the same file. This is one way to organize your code, but your don't have to do it this way. It's perfectly acceptable to group all your server-side tcl code in the init script, and your client-side Javascript in .html files like you normally would.

I used Prototype in the examples created so far. There's no reason that it wouldn't work just as well with Dojo, script.aculo.us, OAT, qooxdoo, or any other AJAX framework. Or, you don't even need a browser at all. Say you wanted a console TUI (thxt-based UI). You could write a shell script using curl to query server values using the /tcl/ URL handler, and dialog to present them to the user. Simple.

Support

There are the usual forums at Sourceforge - feel free to post questions or suggestions. Or drop me an email if you have any comments. I intend to improve the server and add features as I need them, but suggestions are always welcome.

License

Copyright (C) 2008 Mark Anacker

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

Mark Anacker
httcld at riven.tzo.com

Last updated: 12/25/2008 Project Web Hosted by SourceForge.net Logo