Tclhttpd Hints and Tips

Scott Gamon explains how to expose SOAP and XMLRPC methods from tclhttpd at: [L1 ]. Also, exposing those same methods through REpresentational State Transfer, REST: [L2 ].

Look at Wikit configuration to see how to integrate the Wikit (with static page-access) into TclHttpd.

Prevent results of method calls and variable assignments from being output in a template - WJR Occasionally I have a need to set variables in the context of a template - session variables for example. The result of this action is output in the template. Some means to prevent this would be nice as I don't always want to show this result to a user.

schlenk Try 'package require html', 'html::set var value'. Should do what you want.

WJR - That works perfectly, thank you!

CMCc - Alternatively, wrap it in <!-- and --> or use the following form which is quite useful for whole blocks of code:

      set var val
      return ""

WJR - Yes, I was using the former method previous to the html::set method. In a way it's a nice technique since it helps with debugging.

CMCc - it's worth noting that the new subst semantics allows you to use continue and break inside the [] as well, giving you more control over what's evaluated and rendered.

dzach If needing to unset variables used in a .tml file so that the global space is not 'poluted', this must be done before the last tcl command in the template, since the last command returns the value of the template. One elegant way of doing it, is by using the K combinator:

 proc K {x y} {set x}

like this:

   # ... previous commands
   append _html "</body>\n</html>\n"
   K [set _html] [unset _html]

Direct_Url multithreading - TV: A mechanism or description of how to make multi-sink DirectUrls... A multi sink Direct_Url is a Direct_Url which somehow can serve more than on thing at the time. A Direct_Url links a procedure to a Url. The procedure returns the Html which is fed back to the requester of that page, which is very handy; but when a lengthy or stalling procedure is used as directurl, the whole server hangs, and certainly also there can not be two (semi) parallel requests for such a page, as there can be for files. Lets say one wants to slowly feed a video file with a directurl, than the whole server stalls until that request is completely downloaded!

CMcC I believe [Httpd_Suspend $sock] and [Httpd_Resume $sock] will do what you want. You suspend a socket and allow the server to process other sockets, you can later resume a socket and send a little more data, and so on. To find the current socket, use [Httpd_CurrentSocket] as you don't have the socket in a Direct_Url.

This should work. Of course you'll have to write your service in an event driven way, and generate the event yourself (perhaps with an [after]). This probably warrants a TclHttpd Threading page.

Analog LOGFORMATs for TclHttpd

(02-12-04) Here's the latest Analog [L3 ] LOGFORMATs for TclHttpd. These should work with TclHttpd 3.4.3+:

 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c - "%f" "%B")
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c %b "%f" "%B")
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c %b - "%B")

LOGFORMATs for Pre 3.4.3:

 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c - "%f" "%B" -)
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c - - "%B" -)
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c - - - -)
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c %j "%f" "%B" -)
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c %j %j "%B" "%j")
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c %j - - -)
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] - - - - - -)
 LOGFORMAT (%s - - [%d/%M/%Y:%h:%n:%j] "%j%w%r%w%j" %c %j - "%B" -)

Logging in general is much improved in the latest versions.


SS: I wonder if Tclhttpd log files for default work with Visitors [L4 ]. If somebody will try Visitors against Tclhttpd logs please tell me if it works vanilla or with the Analog LOGFORMAT so that I can add it in the documentation.

LES on Mar 21, 2004: Before delving into documentation, one is likely to want to get started with TclHttpd right away, i.e. use the server and build a site. And at that, a Windows user may wonder: if I run it with wish, I get this widget floating permanently; if I run it with tclsh, I get this DOS console box floating permanently; how do I make TclHttpd run "invisible"?

PT 21-Mar-2004: My advice (without checking the sources yet) would be to start it with wish. Then you get a window. If you then also [package require dde; dde servername tclhttpd] you could withdraw the toplevel window and later on control it via dde. eg: [dde eval tclhttpd wm deiconify .]

LES I don't have Tcl Dev Kit. And I am on Windows 98. I think I'll just follow PT's advice, but hacking srvui.tcl directly instead.

schlenk I once just withdrew . and put an icon in the system tray with winico, that popped up a control panel for tclhttpd. Works just fine with Win 9x.

Does Threading Work in Linux? - NB: Was the setuid/getuid linux pthreads stuff ever resolved?

CMCc Threading works in TclHttpd under Linux. Only sf bug relating to this suggests that there may be a problem with TclX and threading. yahalom removing 'package require TclX' makes threading possible on linux

The setuid/getuid problem in Linux pthreads is an artefact of what I think is a broken threading implementation under Linux, imposed by the evils of the posix threading model (don't get me started.) IIRC, Linux created a thread with the initial uid, a so-called 'master' thread which seems to mediate inter-thread communications and synchronisation. The problem arises when you change the uid and start up a new thread - the new thread gets the right uid, but it can no longer communicate with the master thread. I personally put it down as broken by design and forgot about it.

The only need I could see to change the uid is to run as root then surrender privileges, primarily to grant access to privileged ports (specifically port 80.) I found it more satisfactory, and safer, to map port 80 to port 8015 with xinetd (or ipchains) and run as user www-data.

BBW Yeah, CMCc is correct - the setuid() syscall only applies to the current thread, and Tcl creates a Notifier thread very early. So, if you do a setuid you end up with a Tcl thread that cannot usefully communicate with the Tcl notifier thread because that involves signaling deep under the covers. What AOLserver does is to fork a listener thread very early and let that run as root. The rest of the world does a setuid to something else, and then the listener thread uses OS-dependent facilities to pass an accepted connection over to the rest of the server. In short, to do this you need to have a fairly modified Tcl shell that does this. It sounds like the port mapping with xinetd/ipchains may be more feasible, but I haven't tried that.

CMcC 20040609 - Here's my iptables setup. It may well be sub-optimal ... someone should come up with a tcl wrapper for iptables :)

    # map local port 80 to local port 8015
    iptables -A INPUT -j ACCEPT -p tcp --dport 80
    iptables -A FORWARD -j ACCEPT -p tcp --dport 80
    iptables -t nat -A PREROUTING -p tcp -d $EXTERNAL_INTERFACES --dport 80 -j REDIRECT --to-ports 8015
    iptables -t nat -A PREROUTING -p tcp -d $INTERNAL_INTERFACES --dport 80 -j REDIRECT --to-ports 8015
    iptables -t nat -A PREROUTING -p tcp -d lo --dport 80 -j REDIRECT --to-ports 8015

Mini-Tutorial: Content type and file extension - Tclhttpd and content type

CMcC 20050109 - Httpd_CacheableData requires the modification time of the data. Remember, when generating that time, to generate the GMT time (otherwise known as -timezone :UTC), else the remote browser will interpret your local time as GMT, and you'll get strange cache behavior.

Add a symbolic link for the current log file GP-L 20090501 — Very useful for fail2ban [L5 ] in my case. tclhttpd80_current.log (for example, the beginning of the name may vary on your config) is created in the log directory and always points to the current log.

The following code is to be added in lib/log.tcl, just after the code creating the log directory (search for ‘# Create log directory, if neccesary, then open the log file’):

# Create a symlink to the current log. Useful for log watchers as Fail2ban
if {[catch {
    set currentLog $Log(log)current.log
    file delete -- $currentLog
    file link -symbolic $currentLog $Log(log_file)
} err]} {
    Stderr $err