Version 20 of Wibble examples

Updated 2011-03-05 22:13:44 by AMG

AMG: This page contains example pages and applications for the Wibble web server. There may be some overlap with the Wibble zone handlers page. If all you have is a zone handler, put it in the zone handlers page. If you are explaining it in the context of a complete application, put it here. If you're showing off a useful modification of Wibble, maybe put that here too. And if you have a sample page or template, that's also welcome here.

Fetching backrefs...

Hello world

AMG: Put this in a file called index.html.tmpl and see what happens.

% dict set response header content-type text/html
<html><head><title>Hello from Wibble! - $uri</title></head><body>
% set rand [expr {rand()}]
% if {$rand > 0.5} {
random=[format %.3f $rand] &gt; 0.5<br/>
% } else {
random=[format %.3f $rand] &lt;= 0.5<br/>
% }
time/date=[clock format [clock seconds]]<br/>
milliseconds=[clock milliseconds]<br/>
clicks=[clock clicks]<br/>
% if {[info exists query] && ![dict exists $query noiframe]} {
<iframe src="?noiframe" width="100%"/>
% }
</body></html>

AMG: Thanks JBLZ for the bug fix. I had to make a similar one to [dirslash]; I don't think I've posted it yet.


Image file upload, cookies, sessions

AMG: Step 1. Make a directory, then create a file called wibble.tcl in that directory. Paste the Wibble implementation into the file. For this example, I used this version: [L1 ]. (Later versions may be incompatible, and I may forget to update this example!)

Step 2. Create a file in the same directory called index.html.tmpl with the following contents:

% dict set response header content-type text/html
%
% if {[dict exists $header cookie sessionid ""]} {
%   set sessionid [dict get $header cookie sessionid ""]
%   upvar #0 sessions($sessionid) session
% }
%
% set now [clock seconds]
%
% if {![info exists session]} {
%   set sessionid [format %llX [string reverse\
%       [string range [expr rand()] 2 end]]]
%   upvar #0 sessions($sessionid) session
%   set timeout 60
%   dict set response header set-cookie\
%       sessionid=$sessionid\;Max-Age=$timeout\;Version=1
%   dict set session expiration [clock add $now $timeout seconds]
%   after [expr {$timeout * 1000}] [list apply {{sessionid} {
%     unset -nocomplain ::sessions($sessionid)
%   }} $sessionid]
% }
%
% if {[dict exists $post imagetitle ""]
%  && [dict exists $post imagedata ""]
%  && [dict exists $post imagedata content-disposition filename]
%  && [dict exists $post imagedata content-type ""]
%  && [string length [dict get $post imagedata ""]]} {
%   set imagetitle [dict get $post imagetitle ""]
%   set imagefilename [dict get $post imagedata content-disposition filename]
%   set imagetype [dict get $post imagedata content-type ""]
%   dict set session imagetitle $imagetitle
%   dict set session imagedata [dict get $post imagedata ""]
%   dict set session imagefilename $imagefilename
%   dict set session imagetype $imagetype
% } elseif {[dict exists $session imagetitle]} {
%   set imagetitle [dict get $session imagetitle]
% } else {
%   set imagetitle "My Image"
% }
%
<html><head><title>Image file upload test</title></head><body>
<form method="post" enctype="multipart/form-data">
  <table border="1"><tr><th>
    Session ID
  </th><td>
    [enhtml $sessionid]
  </th></tr><tr><th>
    Expiration
  </th><td>
% set expiration [dict get $session expiration]
    [enhtml [clock format $expiration]], [expr {$expiration - $now}]s left
  </th></tr><tr><th>
    Sessions
  </th><td>
    <table>
% foreach id [lsort [array names ::sessions]] {
%   set expiration [dict get $::sessions($id) expiration]
    <tr><th>
      [enhtml $id]
    </th><td>
      [enhtml [clock format $expiration]], [expr {$expiration - $now}]s left
    </td></tr>
% }
    </table>
  </th></tr><tr><th>
    Image title
  </th><td>
    <input type="text" name="imagetitle" value="[enattr $imagetitle]" />
  </td></tr><tr><th>
    Image file
  </th><td>
    <input type="file" name="imagedata" />
    <input type="submit" value="Upload Image" />
% if {[dict exists $session imagedata]} {
  </td></tr><tr><th>
    File name
  </th><td>
    [enhtml [dict get $session imagefilename]]
  </td></tr><tr><th>
    Type
  </th><td>
    [enhtml [dict get $session imagetype]]
  </td></tr><tr><th>
    Image
  </th><td>
    <img src="image" />
% }
  </td></tr></table>
</form>
</html>

Step 3. Create another file in the same directory called image.script with the following contents:

if {[dict exists $header cookie sessionid ""]} {
  upvar #0 sessions([dict get $header cookie sessionid ""]) session
}

if {[info exists session] && [dict exists $session imagetype]
 && [dict exists $session imagedata]} {
  dict set response header content-type [dict get $session imagetype]
  dict set response content [dict get $session imagedata]
} else {
  dict set response status 404
}

Step 4. Run wibble.tcl using tclsh, wish, tclkit, or whatever you prefer. You're now up and running.

Step 5. Point your Web browser to http://localhost:8080/ , and upload images. Access the site from multiple browsers on multiple computers. If you have Firecookie [L2 ] or similar, try messing with your cookies. Edit the files you created. Look at the index.html.script file that Wibble generated from index.html.tmpl. Have fun.


AJAX

AMG: AJAX long polling can be done in Wibble. Here, I'll show you. Make a file called delay.html and put it in your docroot:

<html><head><script type="text/javascript">
  function delay() {
    if (window.XMLHttpRequest) {
      xmlhttp = new XMLHttpRequest();
    } else {
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        document.getElementById("result").innerHTML = xmlhttp.responseText;
      }
    }
    document.getElementById("result").innerHTML = "Waiting...";
    time = document.getElementById("time").value;
    xmlhttp.open("GET", "delay?time=" + time, true);
    xmlhttp.send();
  }
</script></head><body>
  <p>How long shall I wait?</p>
  <p><input type="text" id="time" /> milliseconds</p>
  <p><button type="button" onclick="delay()">Do It!</button></p>
  <div id="result" />
</body></html>

And another called delay.script:

after [dict get $query time ""] [resume timer]
set start [clock milliseconds]
suspend timer
set finish [clock milliseconds]
dict set response header content-type text/plain
dict set response content "I waited for [expr {$finish - $start}] milliseconds."

Go to http://localhost:8080/delay.html , type a number in the box, click the button, and wait. ;^)

dzach 2011-3-1: Looks like something is missing. I'm getting an error invalid command name "resume" while executing "resume timer".

AMG: Oops, you're right. I made a bunch of changes to Wibble since writing this example, which is now out of date, and I forgot to update it. Try again using this version: [L3 ]. It's the second-to-most recent version. This change log entry [L4 ] shows what all has been done since then.

Part of the reason I haven't updated the examples is that I'm not sure I have ICC quite right. When I get some time (who knows when that will be...), I'll finish the large example AJAX application I've been working on, quite possibly redoing ICC in the process. You see, I can't know that I've chosen the right set of functionality until I've tried using it. Anyway, at that time I'll update the other examples too.

dzach: Thanks for the reply, it works now.