blob: cde6c5b9519507dce09fa2be498b4c5adf79c771 [file] [log] [blame]
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_log.h"
#include "http_main.h"
#include "util_script.h"
#include "http_conf_globals.h"
#include <tcl.h>
#include <string.h>
#include "tcl_commands.h"
#include "apache_request.h"
#include "apache_cookie.h"
#include "mod_dtcl.h"
#define BUFSZ 4096
extern module dtcl_module;
extern Tcl_Obj *uploadstorage[];
#define POOL (globals->r->pool)
/* Make a self-referencing URL */
int MakeURL(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "filename");
return TCL_ERROR;
}
Tcl_SetResult(interp, ap_construct_url(POOL, Tcl_GetString(objv[1]), globals->r), NULL);
return TCL_OK;
}
/* Include and parse a file */
int Parse(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *filename;
struct stat finfo;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)
ap_get_module_config(globals->r->server->module_config, &dtcl_module);
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "filename");
return TCL_ERROR;
}
filename = Tcl_GetStringFromObj (objv[1], (int *)NULL);
if (!strcmp(filename, globals->r->filename))
{
Tcl_AddErrorInfo(interp, "Cannot recursively call the same file!");
return TCL_ERROR;
}
if (stat(filename, &finfo))
{
Tcl_AddErrorInfo(interp, Tcl_PosixError(interp));
return TCL_ERROR;
}
if (get_parse_exec_file(globals->r, dsc, filename, 0) == TCL_OK)
return TCL_OK;
else
return TCL_ERROR;
}
/* Tcl command to include flat files */
int Include(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
Tcl_Channel fd;
int sz;
char buf[BUFSZ];
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc =
(dtcl_server_conf *)ap_get_module_config(globals->r->server->module_config,
&dtcl_module);
Tcl_Obj *outobj;
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "filename");
return TCL_ERROR;
}
fd = Tcl_OpenFileChannel(interp,
Tcl_GetStringFromObj(objv[1], (int *)NULL), "r", 0664);
if (fd == NULL)
{
return TCL_ERROR;
} else {
Tcl_SetChannelOption(interp, fd, "-translation", "lf");
}
/* print_headers(globals->r);
flush_output_buffer(globals->r); */
outobj = Tcl_NewObj();
Tcl_IncrRefCount(outobj);
while ((sz = Tcl_ReadChars(fd, outobj, BUFSZ - 1, 0)))
{
if (sz == -1)
{
Tcl_AddErrorInfo(interp, Tcl_PosixError(interp));
Tcl_DecrRefCount(outobj);
return TCL_ERROR;
}
buf[sz] = '\0';
/* we could include code to either ap_pwrite this or memwrite
it, depending on buffering */
Tcl_WriteObj(*(dsc->outchannel), outobj);
if (sz < BUFSZ - 1)
break;
}
Tcl_DecrRefCount(outobj);
return Tcl_Close(interp, fd);
}
/* Command to *only* add to the output buffer */
int Buffer_Add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)
ap_get_module_config(globals->r->server->module_config, &dtcl_module);
if (objc < 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "string");
return TCL_ERROR;
}
Tcl_WriteObj(*(dsc->outchannel), objv[1]);
*(dsc->content_sent) = 0;
return TCL_OK;
}
/* Tcl command to output some text to the web server */
int Hputs(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *arg1;
int length;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)
ap_get_module_config(globals->r->server->module_config, &dtcl_module);
if (objc < 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "?-error? string");
return TCL_ERROR;
}
arg1 = Tcl_GetStringFromObj(objv[1], &length);
if (!strncmp("-error", arg1, 6))
{
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 1, objv, "?-error? string");
return TCL_ERROR;
}
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
globals->r->server, "Mod_Dtcl Error: %s",
Tcl_GetStringFromObj (objv[2], (int *)NULL));
} else {
Tcl_DString outstring;
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "?-error? string");
return TCL_ERROR;
}
/* transform it from UTF to External representation */
Tcl_UtfToExternalDString(NULL, arg1, length, &outstring);
arg1 = Tcl_DStringValue(&outstring);
length = Tcl_DStringLength(&outstring);
if (*(dsc->buffer_output) == 1)
{
Tcl_DStringAppend(dsc->buffer, arg1, length);
} else {
print_headers(globals->r);
flush_output_buffer(globals->r);
ap_rwrite(arg1, length, globals->r);
}
Tcl_DStringFree(&outstring);
}
return TCL_OK;
}
/* Tcl command to manipulate headers */
int Headers(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *opt;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)
ap_get_module_config(globals->r->server->module_config, &dtcl_module);
if (objc < 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
return TCL_ERROR;
}
if (*(dsc->headers_printed) != 0)
{
Tcl_AddObjErrorInfo(interp, "Cannot manipulate headers - already sent", -1);
return TCL_ERROR;
}
opt = Tcl_GetStringFromObj(objv[1], NULL);
if (!strcmp("setcookie", opt)) /* ### setcookie ### */
{
int i;
ApacheCookie *cookie;
char *stringopts[12] = {NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL};
if (objc < 4 || objc > 14)
{
Tcl_WrongNumArgs(interp, 2, objv,
"-name cookie-name -value cookie-value ?-expires expires? ?-domain domain? ?-path path? ?-secure on/off?");
return TCL_ERROR;
}
/* SetCookie: foo=bar; EXPIRES=DD-Mon-YY HH:MM:SS; DOMAIN=domain; PATH=path; SECURE */
for (i = 0; i < objc - 2; i++)
{
stringopts[i] = Tcl_GetString(objv[i + 2]);
}
cookie = ApacheCookie_new(globals->r,
stringopts[0], stringopts[1],
stringopts[2], stringopts[3],
stringopts[4], stringopts[5],
stringopts[6], stringopts[7],
stringopts[8], stringopts[9],
stringopts[10], stringopts[11],
NULL);
ApacheCookie_bake(cookie);
}
else if (!strcmp("redirect", opt)) /* ### redirect ### */
{
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 2, objv, "new-url");
return TCL_ERROR;
}
ap_table_set(globals->r->headers_out, "Location",
Tcl_GetStringFromObj (objv[2], (int *)NULL));
globals->r->status = 301;
return TCL_RETURN;
}
else if (!strcmp("set", opt)) /* ### set ### */
{
if (objc != 4)
{
Tcl_WrongNumArgs(interp, 2, objv, "headername value");
return TCL_ERROR;
}
ap_table_set(globals->r->headers_out,
Tcl_GetStringFromObj (objv[2], (int *)NULL),
Tcl_GetStringFromObj (objv[3], (int *)NULL));
}
else if (!strcmp("type", opt)) /* ### set ### */
{
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 2, objv, "mime/type");
return TCL_ERROR;
}
set_header_type(globals->r, Tcl_GetStringFromObj(objv[2], (int *)NULL));
} else if (!strcmp("numeric", opt)) /* ### numeric ### */
{
int st = 200;
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 2, objv, "response code");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[2], &st) != TCL_ERROR)
globals->r->status = st;
else
return TCL_ERROR;
} else {
/* XXX Tcl_WrongNumArgs(interp, 1, objv, "headers option arg ?arg ...?"); */
return TCL_ERROR;
}
return TCL_OK;
}
/* turn buffering on and off */
int Buffered(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *opt = NULL;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)
ap_get_module_config(globals->r->server->module_config, &dtcl_module);
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 1, objv, "on/off");
return TCL_ERROR;
}
opt = Tcl_GetStringFromObj(objv[1], NULL);
if (!strncmp(opt, "on", 2))
{
*(dsc->buffer_output) = 1;
} else if (!strncmp(opt, "off", 3)) {
*(dsc->buffer_output) = 0;
print_headers(globals->r);
flush_output_buffer(globals->r);
} else {
return TCL_ERROR;
}
return TCL_OK;
}
/* Tcl command to flush the output stream */
int HFlush(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
if (objc != 1)
{
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
print_headers(globals->r);
flush_output_buffer(globals->r);
ap_rflush(globals->r);
return TCL_OK;
}
/* Tcl command to get and parse any CGI and environmental variables */
/* Get the environmental variables, but do it from a tcl function, so
we can decide whether we wish to or not */
int HGetVars(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *timefmt = DEFAULT_TIME_FORMAT;
#ifndef WIN32
struct passwd *pw;
#endif /* ndef WIN32 */
char *t;
char *authorization = NULL;
time_t date;
int i;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
array_header *hdrs_arr;
table_entry *hdrs;
array_header *env_arr;
table_entry *env;
Tcl_Obj *EnvsObj = NULL;
EnvsObj = Tcl_NewStringObj("::request::ENVS", -1);
Tcl_IncrRefCount(EnvsObj);
date = globals->r->request_time;
/* ensure that the system area which holds the cgi variables is empty */
ap_clear_table(globals->r->subprocess_env);
/* retrieve cgi variables */
ap_add_cgi_vars(globals->r);
ap_add_common_vars(globals->r);
hdrs_arr = ap_table_elts(globals->r->headers_in);
hdrs = (table_entry *) hdrs_arr->elts;
env_arr = ap_table_elts(globals->r->subprocess_env);
env = (table_entry *) env_arr->elts;
/* Get the user/pass info for Basic authentication */
(const char*)authorization = ap_table_get(globals->r->headers_in, "Authorization");
if (authorization && !strcasecmp(ap_getword_nc(POOL, &authorization, ' '), "Basic"))
{
char *tmp;
char *user;
char *pass;
tmp = ap_pbase64decode(POOL, authorization);
user = ap_getword_nulls_nc(POOL, &tmp, ':');
pass = tmp;
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("::request::USER", -1),
Tcl_NewStringObj("user", -1),
STRING_TO_UTF_TO_OBJ(user, POOL),
0);
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("::request::USER", -1),
Tcl_NewStringObj("pass", -1),
STRING_TO_UTF_TO_OBJ(pass, POOL),
0);
}
/* These were the "include vars" */
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("DATE_LOCAL", -1),
STRING_TO_UTF_TO_OBJ(ap_ht_time(POOL, date, timefmt, 0), POOL), 0);
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("DATE_GMT", -1),
STRING_TO_UTF_TO_OBJ(ap_ht_time(POOL, date, timefmt, 1), POOL), 0);
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("LAST_MODIFIED", -1),
STRING_TO_UTF_TO_OBJ(ap_ht_time(POOL, globals->r->finfo.st_mtime, timefmt, 0), POOL), 0);
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("DOCUMENT_URI", -1),
STRING_TO_UTF_TO_OBJ(globals->r->uri, POOL), 0);
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("DOCUMENT_PATH_INFO", -1),
STRING_TO_UTF_TO_OBJ(globals->r->path_info, POOL), 0);
#ifndef WIN32
pw = getpwuid(globals->r->finfo.st_uid);
if (pw)
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("USER_NAME", -1),
STRING_TO_UTF_TO_OBJ(ap_pstrdup(POOL, pw->pw_name), POOL), 0);
else
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("USER_NAME", -1),
STRING_TO_UTF_TO_OBJ(
ap_psprintf(POOL, "user#%lu",
(unsigned long) globals->r->finfo.st_uid), POOL), 0);
#endif
if ((t = strrchr(globals->r->filename, '/')))
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("DOCUMENT_NAME", -1),
STRING_TO_UTF_TO_OBJ(++t, POOL), 0);
else
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("DOCUMENT_NAME", -1),
STRING_TO_UTF_TO_OBJ(globals->r->uri, POOL), 0);
if (globals->r->args)
{
char *arg_copy = ap_pstrdup(POOL, globals->r->args);
ap_unescape_url(arg_copy);
Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("QUERY_STRING_UNESCAPED", -1),
STRING_TO_UTF_TO_OBJ(ap_escape_shell_cmd(POOL, arg_copy), POOL), 0);
}
/* ---------------------------- */
/* transfer client request headers to TCL request namespace */
for (i = 0; i < hdrs_arr->nelts; ++i)
{
if (!hdrs[i].key)
continue;
else {
Tcl_ObjSetVar2(interp, EnvsObj, STRING_TO_UTF_TO_OBJ(hdrs[i].key, POOL),
STRING_TO_UTF_TO_OBJ(hdrs[i].val, POOL), 0);
}
}
/* transfer apache internal cgi variables to TCL request namespace */
for (i = 0; i < env_arr->nelts; ++i)
{
if (!env[i].key)
continue;
Tcl_ObjSetVar2(interp, EnvsObj, STRING_TO_UTF_TO_OBJ(env[i].key, POOL),
STRING_TO_UTF_TO_OBJ(env[i].val, POOL), 0);
}
do { /* I do this because I want some 'local' variables */
ApacheCookieJar *cookies = ApacheCookie_parse(globals->r, NULL);
Tcl_Obj *cookieobj = Tcl_NewStringObj("::request::COOKIES", -1);
for (i = 0; i < ApacheCookieJarItems(cookies); i++) {
ApacheCookie *c = ApacheCookieJarFetch(cookies, i);
int j;
for (j = 0; j < ApacheCookieItems(c); j++) {
char *name = c->name;
char *value = ApacheCookieFetch(c, j);
Tcl_ObjSetVar2(interp, cookieobj,
Tcl_NewStringObj(name, -1),
Tcl_NewStringObj(value, -1), 0);
/* STRING_TO_UTF_TO_OBJ(name, POOL),
STRING_TO_UTF_TO_OBJ(value, POOL), 0); */
}
}
} while (0);
/* cleanup system cgi variables */
ap_clear_table(globals->r->subprocess_env);
return TCL_OK;
}
/* Tcl command to return a particular variable. */
/* Use:
var get foo
var list foo
var names
var number
var all
*/
int Var(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *command;
int i;
Tcl_Obj *result = NULL;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
array_header *parmsarray = ap_table_elts(globals->req->parms);
table_entry *parms = (table_entry *)parmsarray->elts;
if (objc < 2 || objc > 3)
{
Tcl_WrongNumArgs(interp, 1, objv,
"(get varname|list varname|exists varname|names|number|all)");
return TCL_ERROR;
}
command = Tcl_GetString(objv[1]);
if (!strcmp(command, "get"))
{
char *key = NULL;
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 2, objv, "variablename");
return TCL_ERROR;
}
key = Tcl_GetStringFromObj(objv[2], NULL);
/* This isn't real efficient - move to hash table later
on... */
for (i = 0; i < parmsarray->nelts; ++i)
{
if (!strncmp(key, StringToUtf(parms[i].key, POOL),
strlen(key) < strlen(parms[i].key) ?
strlen(parms[i].key) : strlen(key)))
{
/* The following makes sure that we get one string,
with no sub lists. */
if (result == NULL)
{
result = STRING_TO_UTF_TO_OBJ(parms[i].val, POOL);
Tcl_IncrRefCount(result);
} else {
Tcl_Obj *tmpobjv[2];
tmpobjv[0] = result;
tmpobjv[1] = STRING_TO_UTF_TO_OBJ(parms[i].val, POOL);
result = Tcl_ConcatObj(2, tmpobjv);
}
}
}
if (result == NULL)
Tcl_AppendResult(interp, "", NULL);
else
Tcl_SetObjResult(interp, result);
} else if(!strcmp(command, "exists")) {
char *key;
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 2, objv, "variablename");
return TCL_ERROR;
}
key = Tcl_GetString(objv[2]);
/* This isn't real efficient - move to hash table later on. */
for (i = 0; i < parmsarray->nelts; ++i)
{
if (!strncmp(key, StringToUtf(parms[i].key, POOL), strlen(key)))
{
result = Tcl_NewIntObj(1);
Tcl_IncrRefCount(result);
}
}
if (result == NULL)
Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
else
Tcl_SetObjResult(interp, result);
} else if(!strcmp(command, "list")) {
char *key;
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 2, objv, "variablename");
return TCL_ERROR;
}
key = Tcl_GetStringFromObj(objv[2], NULL);
/* This isn't real efficient - move to hash table later on. */
for (i = 0; i < parmsarray->nelts; ++i)
{
if (!strncmp(key, StringToUtf(parms[i].key, POOL), strlen(key)))
{
if (result == NULL)
{
result = Tcl_NewObj();
Tcl_IncrRefCount(result);
}
Tcl_ListObjAppendElement(interp, result,
STRING_TO_UTF_TO_OBJ(parms[i].val, POOL));
}
}
if (result == NULL)
Tcl_AppendResult(interp, "", NULL);
else
Tcl_SetObjResult(interp, result);
} else if(!strcmp(command, "names")) {
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 2, objv, NULL);
return TCL_ERROR;
}
result = Tcl_NewObj();
Tcl_IncrRefCount(result);
for (i = 0; i < parmsarray->nelts; ++i)
{
Tcl_ListObjAppendElement(interp, result,
STRING_TO_UTF_TO_OBJ(parms[i].key, POOL));
}
if (result == NULL)
Tcl_AppendResult(interp, "", NULL);
else
Tcl_SetObjResult(interp, result);
} else if(!strcmp(command, "number")) {
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 2, objv, NULL);
return TCL_ERROR;
}
result = Tcl_NewIntObj(parmsarray->nelts);
Tcl_IncrRefCount(result);
Tcl_SetObjResult(interp, result);
} else if(!strcmp(command, "all")) {
if (objc != 2)
{
Tcl_WrongNumArgs(interp, 2, objv, NULL);
return TCL_ERROR;
}
result = Tcl_NewObj();
Tcl_IncrRefCount(result);
for (i = 0; i < parmsarray->nelts; ++i)
{
Tcl_ListObjAppendElement(interp, result,
STRING_TO_UTF_TO_OBJ(parms[i].key, POOL));
Tcl_ListObjAppendElement(interp, result,
STRING_TO_UTF_TO_OBJ(parms[i].val, POOL));
}
if (result == NULL)
Tcl_AppendResult(interp, "", NULL);
else
Tcl_SetObjResult(interp, result);
} else {
/* bad command */
Tcl_AddErrorInfo(interp, "bad option: must be one of 'get, list, names, number, all'");
return TCL_ERROR;
}
return TCL_OK;
}
/*
upload get XYZ
channel # returns channel
save (name) # returns name?
data # returns data
with the third one reporting an error if this hasn't been enabled, or
the first two if it has.
upload info XYZ
exists
size
type
filename
upload names
gets all the upload names.
*/
int Upload(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *command = NULL;
Tcl_Obj *result = NULL;
ApacheUpload *upload;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)
ap_get_module_config(globals->r->server->module_config, &dtcl_module);
if (objc < 2 || objc > 5)
{
Tcl_WrongNumArgs(interp, 1, objv, "get ...|info ...|names");
return TCL_ERROR;
}
command = Tcl_GetString(objv[1]);
result = Tcl_NewObj();
if (!strcmp(command, "get"))
{
char *varname = NULL;
if (objc < 4)
{
Tcl_WrongNumArgs(interp, 2, objv, "varname channel|save filename|var varname");
return TCL_ERROR;
}
varname = Tcl_GetString(objv[2]);
upload = ApacheUpload_find(globals->req->upload, varname);
if (upload != NULL) /* make sure we have an upload */
{
Tcl_Channel chan;
char *method = Tcl_GetString(objv[3]);
if (!strcmp(method, "channel"))
{
if (ApacheUpload_FILE(upload) != NULL)
{
/* create and return a file channel */
char *channelname = NULL;
chan = Tcl_MakeFileChannel((ClientData)fileno(
ApacheUpload_FILE(upload)), TCL_READABLE);
Tcl_RegisterChannel(interp, chan);
channelname = Tcl_GetChannelName(chan);
Tcl_SetStringObj(result, channelname, -1);
}
} else if (!strcmp(method, "save")) {
/* save data to a specified filename */
int sz;
char savebuffer[BUFSZ];
Tcl_Channel savechan = NULL;
Tcl_Channel chan = NULL;
if (objc != 5)
{
Tcl_WrongNumArgs(interp, 4, objv, "filename");
return TCL_ERROR;
}
savechan = Tcl_OpenFileChannel(interp, Tcl_GetString(objv[4]), "w", 0600);
if (savechan == NULL)
return TCL_ERROR;
else
Tcl_SetChannelOption(interp, savechan, "-translation", "binary");
chan = Tcl_MakeFileChannel((ClientData)fileno(
ApacheUpload_FILE(upload)), TCL_READABLE);
Tcl_SetChannelOption(interp, chan, "-translation", "binary");
while ((sz = Tcl_Read(chan, savebuffer, BUFSZ)))
{
if (sz == -1)
{
Tcl_AddErrorInfo(interp, Tcl_PosixError(interp));
return TCL_ERROR;
}
Tcl_Write(savechan, savebuffer, sz);
if (sz < 4096)
break;
}
Tcl_Close(interp, savechan);
Tcl_SetIntObj(result, 1);
} else if (!strcmp(method, "data")) {
/* this sucks - we should use the hook, but I want to
get everything fixed and working first */
if (dsc->upload_files_to_var)
{
char *bytes = NULL;
Tcl_Channel chan = NULL;
bytes = Tcl_Alloc(ApacheUpload_size(upload));
chan = Tcl_MakeFileChannel((ClientData)fileno(
ApacheUpload_FILE(upload)), TCL_READABLE);
Tcl_SetChannelOption(interp, chan, "-translation", "binary");
Tcl_SetChannelOption(interp, chan, "-encoding", "binary");
/* put data in a variable */
Tcl_ReadChars(chan, result, ApacheUpload_size(upload), 0);
} else {
Tcl_AppendResult(interp, "Dtcl_UploadFilesToVar is not set", NULL);
return TCL_ERROR;
}
}
} else {
/* no variable found */
Tcl_SetStringObj(result, "", -1);
}
} else if (!strcmp(command, "info")) {
char *varname = NULL;
char *infotype = NULL;
if (objc != 4)
{
Tcl_WrongNumArgs(interp, 2, objv, "varname exists|size|type|filename");
return TCL_ERROR;
}
varname = Tcl_GetString(objv[2]);
infotype = Tcl_GetString(objv[3]);
upload = ApacheUpload_find(globals->req->upload, varname);
if (upload != NULL)
{
if (!strcmp(infotype, "exists"))
{
Tcl_SetIntObj(result, 1);
} else if (!strcmp(infotype, "size")) {
Tcl_SetIntObj(result, ApacheUpload_size(upload));
} else if (!strcmp(infotype, "type")) {
char *type = NULL;
type = (char *)ApacheUpload_type(upload);
if (type)
Tcl_SetStringObj(result, type, -1);
else
Tcl_SetStringObj(result, "", -1);
} else if (!strcmp(infotype, "filename")) {
Tcl_SetStringObj(result, StringToUtf(upload->filename, POOL), -1);
} else {
Tcl_AddErrorInfo(interp, "unknown upload info command, should be exists|size|type|filename");
return TCL_ERROR;
}
} else {
if (!strcmp(infotype, "exists")) {
Tcl_SetIntObj(result, 0);
} else {
Tcl_AddErrorInfo(interp, "variable doesn't exist");
return TCL_ERROR;
}
}
} else if (!strcmp(command, "names")) {
upload = ApacheRequest_upload(globals->req);
while (upload)
{
Tcl_ListObjAppendElement(interp, result,
STRING_TO_UTF_TO_OBJ(upload->name, POOL));
upload = upload->next;
}
} else {
Tcl_WrongNumArgs(interp, 1, objv, "upload get|info|names");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
/* Tcl command to get, and print some information about the current
state of affairs */
int Dtcl_Info(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *tble;
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)ap_get_module_config(globals->r->server->module_config, &dtcl_module);
tble = ap_psprintf(POOL,
"<table border=0 bgcolor=green><tr><td>\n"
"<table border=0 bgcolor=\"#000000\">\n"
"<tr><td align=center bgcolor=blue><font color=\"#ffffff\" size=\"+2\">dtcl_info</font><br></td></tr>\n"
"<tr><td><font color=\"#ffffff\">Free cache size: %d</font><br></td></tr>\n"
"<tr><td><font color=\"#ffffff\">PID: %d</font><br></td></tr>\n"
"</table>\n"
"</td></tr></table>\n", *(dsc->cache_free), getpid());
/* print_headers(globals->r);
flush_output_buffer(globals->r); */
Tcl_WriteObj(*(dsc->outchannel), Tcl_NewStringObj(tble, -1));
return TCL_OK;
}
/* Tcl command to erase body, so that only header is returned.
Necessary for 304 responses */
int No_Body(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
dtcl_interp_globals *globals = Tcl_GetAssocData(interp, "dtcl", NULL);
dtcl_server_conf *dsc = (dtcl_server_conf *)
ap_get_module_config(globals->r->server->module_config, &dtcl_module);
if (*(dsc->content_sent) == 1)
return TCL_ERROR;
print_headers(globals->r);
Tcl_DStringInit(dsc->buffer);
return TCL_OK;
}