[AMG]: This page is for questions and answers about how to use the [Wibble] web server. Report bugs at [Wibble bugs]. <> ---- **Put your question here** [JM] 12Feb2012 - the file index.html.tmpl on the "image file upload, cookies, sessions" example on [Wibble examples] is somehow connected to the "image.script" file mentioned in step 3, how that works? [AMG]: image.script serves the images; that's all it does. I'll repeat it here, annotated with copious comments: ======tcl # If there is a sessionid cookie in the header, if {[dict exists $header cookie sessionid ""]} { # Link the local session variable to an element in the global session array. # The linked element is the one whose key is the same as the value stored in # the sessionid cookie. It's quite possible that the element doesn't exist, # but create the link anyway. upvar #0 sessions([dict get $header cookie sessionid ""]) session } # If: # 1. [info exists session]: there was a sessionid cookie, and there exists an # associated element in the global sessions array, # 2. [dict exists $session imagetype]: the imagetype dict element exists in # the value stored in the session variable, # 3. [dict exists $session imagedata]: and the imagedata dict element exists, if {[info exists session] && [dict exists $session imagetype] && [dict exists $session imagedata]} { # Serve the image to the client. Use the imagetype dict element as the HTTP # content-type, and use the imagedata dict element as the content. dict set response header content-type [dict get $session imagetype] dict set response content [dict get $session imagedata] } else { # But if any of that stuff wasn't true (e.g., no session data), 404 error. dict set response status 404 } ====== [JM] 13Mar2012 - Thanks for the explanation, what I do not understand is what is it triggering this code (i.e. I was expecting image.script to be part of the ACTION form so that whenever the submit button is clicked, such action is then triggered). I may be missing something basic, I appreciate your help. [AMG]: It gets [source]d by [[scriptfile]] in order to serve `http://localhost:8080/image`, which you will notice is referenced by ``. The form's action is left at the HTML default, which is the same as the page that served the form to begin with. That page is provided by index.html.tmpl, which handles the image '''upload'''. That's very different from image.script, which handles the image '''download''', i.e. display. ---- [SEH] 01Apr2012 -- I'm studying wibble in hopes of replacing tclhttpd with it. Overall it looks great, but I still may want to carry over some of the best of tclhttpd's code to my project. As a small example, tclhttpd has a shorter, seemingly tighter proc for url-decoding strings as compared to wibble's dehex. To wit: ====== proc ::wibble::dehex {str} { set pos 0 while {[regexp -indices -start $pos {%([[:xdigit:]]{2})} $str range code]} { set char [binary format H2 [string range $str {*}$code]] set str [string replace $str {*}$range $char] set pos [expr {[lindex $range 0] + 1}] } return $str } ====== compare to: ====== proc UrlDecodeData {data} { regsub -all {([][$\\])} $data {\\\1} data regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data {[format %c 0x\1]} data return [subst $data] } ====== for good measure, here's ncgi's decode: ====== proc ::ncgi::decode {str} { # rewrite "+" back to space # protect \ from quoting another '\' set str [string map [list + { } "\\" "\\\\"] $str] # prepare to process all %-escapes regsub -all -- {%([A-Fa-f0-9][A-Fa-f0-9])} $str {\\u00\1} str # process \u unicode mapped chars return [subst -novar -nocommand $str] } ====== Is there any evident reason to prefer one of these approaches over the others (leaving aside ncgi's handling of "+")? If one wishes wibble's performance to scale, small refinements may become crucial. [AMG]: Thanks for the input! I wrote Wibble without looking at the source for tclhttpd or any other server, so it's very likely that there's plenty of room to tactically requisition good ideas. :^) Refinements are definitely welcome. To the best of my knowledge, Wibble has never been benchmarked, aside from a note that it's somehow incompatible with siege [http://wiki.tcl.tk/27382#pagetocd98ce46d]. Regarding [[UrlDecodeData]], there's some magic in there. Let me work it out: * `regsub -all {([[]][[$\\]])} $data {\\\1} data`: prefix brackets, dollar signs, and backslashes with backslashes * `regsub -all {%([[0-9a-fA-F]][[0-9a-fA-F]])} $data {[[format %c 0x\1]]} data`: replace % followed by two hexadecimal digits with a string that will later be interpreted as a command substitution * `return [[subst $data]]`: perform all the command substitutions inserted in the previous step, and remove all the extra backslashes inserted in first step [[::ncgi::decode]] does very nearly the same thing, though it trusts subst's -novariables and -nocommands options rather than internally putting backslashes in front of dollar signs and brackets. Whenever I see [[subst]] given options, I immediately think "BUG", but I think this combination is actually safe. The bug, of course, is that [[subst]] is powerless to stop substitutions performed inside command substitution. It also can't stop command and backslash substitution when used to form the array element name in a variable substitution. But I don't see anything wrong with this exact combination of options. Also, the other difference in [[::ncgi::decode]] is that it uses \u instead of command substitution. Seems that should be faster. A little commentary. What I do in Wibble is a straightforward translation of the logic required to do the conversion. The other two procedures employ trickery to get what they want in a roundabout way. They are also likely to be much faster. I've found that when a script performs less looping and manipulation and instead leaves more of the work to a command that's implemented in C, it runs faster, sometimes much faster, and it's usually worth massaging the data a little bit to fit the conventions imposed by that command. Benchmark time! ====== [andy@toaster|~]$ cat /proc/cpuinfo model name : Pentium II (Deschutes) cpu MHz : 348.184 [andy@toaster|~]$ tclsh % info patchlevel 8.6b2 % set str {[exit]%5bexit%5d$tcl_version%24tcl_version%555test%7e} % dehex $str [exit][exit]$tcl_version$tcl_versionU5test~ % UrlDecodeData $str [exit][exit]$tcl_version$tcl_versionU5test~ % decode $str [exit][exit]$tcl_version$tcl_versionU5test~ % time {dehex $str} 1000 1679.468 microseconds per iteration % time {UrlDecodeData $str} 1000 1570.29 microseconds per iteration % time {decode $str} 1000 795.562 microseconds per iteration ====== As expected, [[UrlDecodeData]] is faster because all the looping and processing is done in C rather than Tcl, and [[::ncgi::decode]] is much faster because it lets [[subst]] do the work internally rather than have to chain to [[format]]. So, here's the new version of [[::wibble::dehex]]: ====== proc ::wibble::dehex {str} { subst -novariables -nocommands\ [regsub -all {%([[:xdigit:]]{2})} [string map {\\ \\\\} $str] {\\u00\1}] } ====== This is [[::ncgi::decode]], translated to use the pithy trainwreck coding style used throughout Wibble. Performance: ====== % time {dehex $str} 1000 785.424 microseconds per iteration ====== That's 213.8% as fast as the original code! <> Wibble