mod_neoinclude.c
in your Configuration file and run
Configure, it'll put our module into the build for your webserver.
Note -- you will also need our log module, mod_log_neo.c
, for
estimate_hits_per_hour to work.
Here's what happens in our module startup C code:
At startup of the webserver, when it is still a single thread (the parent thread), init_neoincludes runs.
It creates a Tcl interpreter, records a start time for the server, runs Tcl_Init to initialize the Tcl interpreter, Tclx_Init to add Extended Tcl, and Tcl_InitExtensions to add in our webserver-oriented extensions (NeoWebScript).
...and then it sources init.tcl
from your server root's
conf directory.
init.tcl
loads in a number of standard functions from
conf/common.tcl
from the server root directory.
These functions can be included by external Tcl programs that you write to administer your NeoWebScript databases.
Next the NeoWebScript procs are defined. If these are procs that run in the trusted interpreter in response to requests received from the untrusted interpreter, those commands begin with SAFE_.
SAFE commands typically manipulate data within the untrusted interpreter using the child interpreter access functions provided by Tcl.
Finally procs are defined to handle requests to execute code in response to the server-side neoscript requests seen in webpages. These are called things like handle_server_side_variable, handle_server_side_expr, etc.
We make use the request_config data in the request record structure. This allows each module to set a pointer and find it later. We follow the request_rec structure from ours back to the main one (if we aren't the main one) to find a non-NULL pointer for our module in the request_config structure. If there isn't one to be found, it is the first invocation of NeoWebScript for this page.
If it's the first use of NeoWebScript for this page, or if this page is being included in another page but is not owned by the same owner as the other page, we create a safe interpreter, set it into the request_config structure for our module, register for the cleanup routine to destroy the interpreter, and configure and propagate the variables to the safe interpreter.
Tcl_request_rec is a global pointer to the current request_rec being processed. We save the previous value on the stack while we're executing handle_neoscript, and put it back afterwards. That way Tcl procedures don't have to all pass around a magic cookie to find the request rec, yet multiple interpreters can exist and code in existant interpreters can be invoked for subordinate includes when the criteria for doing that are met.
If it's the first use of NeoWebScript for this page, then if a safe interpreter previously existed, it is destroyed. A new safe interpreter is created, and various environment variables, server variables, etc, are exported to it by propagate_vars_to_neoscript.
handle_neoscript builds up the command to be executed. It sets up to call handle_neoscript_request. The first argument is the name of the safe interpreter. The second is the key of the key-value pair read from the server-side-include. Last comes the value of the key-value pair.
It is most important that neither the key nor the value are ever evaluated within the trusted interpreter, or the user will have defeated the protection mechanisms provided by the safe interpreter.
Since we build up the command to be executed as a list, the key and value will be quoted to make a valid list element, so they won't be evaluated by the trusted interpreter when handle_neoscript_request is called.
We then evaluate the constructed command. If there is an error, we send the error result to the webpage being constructed.
Finally we restore the Tcl_request_rec global request rec pointer with whatever was in there before. It is intialized to NULL at the start, and should automatically be restored to that when the top level page of NeoWebScript code completes.
This command is responsible for actually processing embedded NeoWebScript
requests from within webpages. It is defined in conf/init.tcl
.
It switches on the tag, which can currently be return, code, eval, var or expr. Anything else is treated as an error.
Valid tags are handled using handle_server_side_return, handle_server_side_eval, handle_server_side_variable, and handle_server_side_expr. These routines are called with the name of the safe interpreter and the code (or variable, or expression) to evaluate. The code is evaluated within the safe interpreter. Errors are caught and traced back.
These routines were defined as procs by init.tcl, and they
use the interp eval
command to do the right thing to the untrusted
interpreter to cause code to be executed, results to be returned,
etc.
devel.tcl is used by people who are modifying NeoWebScript by changing code that runs in the trusted code base. This should only be done by people who really know what they're doing, because errors here can compromise the security of your webserver.
If debugging is set to 1 in init.tcl, then every time a
page begins NeoWebScript execution, devel.tcl
is sourced in, and
devel_setup is executed. This makes it easy
to work on new functions, without having to restart the webserver
all the time.
If debugging is set to 0 in init.tcl
,
then devel.tcl
is loaded it at
server startup time only, although devel_setup is still run each
time an interpreter is set up to do something to a page.