This is an automated email from the ASF dual-hosted git repository. mxmanghi pushed a commit to branch quattuor in repository https://gitbox.apache.org/repos/asf/tcl-rivet.git
commit 29047a56369e7607528b56941c16618f98a2c1b6 Author: Massimo Manghi <massimo.man...@gmail.com> AuthorDate: Mon Oct 25 18:47:19 2021 +0200 merging latest commit in trunk, including environment variable internals revision, Session package cache table having larger 'data' columns --- ChangeLog | 15 + doc/xml/commands.xml | 123 ++++---- rivet/packages/session/session-class.tcl | 3 +- rivet/packages/session/session-create-mysql.sql | 6 +- rivet/packages/session/session-create-oracle.sql | 12 +- rivet/packages/session/session-create-sqlite.sql | 6 +- src/mod_rivet_ng/TclWebapache.c | 363 +++++++++++++++-------- src/mod_rivet_ng/mod_rivet_generator.c | 2 +- src/mod_rivet_ng/rivetCore.c | 8 +- src/mod_rivet_ng/rivet_types.h | 2 +- src/rivet.h | 1 + tests/apachetest/template.conf.1.tcl | 2 +- tests/env.rvt | 22 +- tests/env.test | 45 ++- tests/rivet.test | 19 +- 15 files changed, 420 insertions(+), 209 deletions(-) diff --git a/ChangeLog b/ChangeLog index 132cf24..e431eea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2021-10-25 Massimo Manghi <mxman...@apache.org> + * src/mod_rivet_ng/Tclwebapache.c: extended comments + * src/rivet.h: new macro MINSTRLEN + +2021-10-20 Massimo Manghi <mxman...@apache.org> + * src/mod_rivet_ng/Tclwebapache.c: new environment variable handling. + Command ::rivet::env doesn't necessarily trigger the whole enviroment load + into request_rec, it tries to resolve a variable incrementally. Need + to recommend the usage of ::rivet::env instead of ::rivet::load_env + * tests/env.rvt: adding new tests to environment variable resolution + +2021-09-06 Massimo Manghi <mxman...@apache.org> + * rivet/packages/session/session-create-*.sql: making cache fields larger + * rivet/packages/session/session-create-*.sql: making cache fields larger + 2021-04-13 Massimo Manghi <mxman...@apache.org> * src/mod_rivet_ng/rivetInspect.c: add server current loglevel. Removed unneeded ref count management in the server array construction diff --git a/doc/xml/commands.xml b/doc/xml/commands.xml index 0b95309..d3104fe 100644 --- a/doc/xml/commands.xml +++ b/doc/xml/commands.xml @@ -460,61 +460,63 @@ </refentry> <refentry id="debug"> - <refnamediv> - <refname>debug</refname> - <refpurpose> - A command to print strings, arrays - and the values of variables as specified by the arguments. - </refpurpose> - </refnamediv> - <refsynopsisdiv> - <cmdsynopsis> - <command>::rivet::debug</command> - <arg choice="plain">-subst</arg><arg><on|off></arg> - <arg choice="plain">-separator</arg><arg><string></arg> - <arg choice="plain">-option</arg><arg><replaceable><value></replaceable></arg> - <arg choice="plain">-option</arg><arg><replaceable><value></replaceable></arg> - <arg choice="plain">...</arg> - </cmdsynopsis> - </refsynopsisdiv> + <refnamediv> + <refname>debug</refname> + <refpurpose> + A command to print strings, arrays + and the values of variables as specified by the arguments. + </refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>::rivet::debug</command> + <arg choice="plain">-subst</arg><arg><on|off></arg> + <arg choice="plain">-separator</arg><arg><string></arg> + <arg choice="plain">-option</arg><arg><replaceable><value></replaceable></arg> + <arg choice="plain">-option</arg><arg><replaceable><value></replaceable></arg> + <arg choice="plain">...</arg> + </cmdsynopsis> + </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - A command to make debugging more convenient print strings, arrays - and the values of variables as specified by the arguments. - </para> - <para> - Also allows the setting of an array called debug which will pick up - options for all debug commands. - </para> - </refsect1> + <refsect1> + <title>Description</title> + <para> + A command to make debugging more convenient print strings, arrays + and the values of variables as specified by the arguments. + </para> + <para> + Also allows the setting of an array called debug which will pick up + options for all debug commands. + </para> + </refsect1> </refentry> - <refentry id="env"> - <refnamediv> - <refname>env</refname> - <refpurpose> - Loads a single "environmental variable" into a Tcl variable. - </refpurpose> - </refnamediv> + <refnamediv> + <refname>env</refname> + <refpurpose> + Returns the value a single "environmental variable". + </refpurpose> + </refnamediv> - <refsynopsisdiv> - <cmdsynopsis> - <command>::rivet::env</command> - <arg><replaceable>varName</replaceable></arg> - </cmdsynopsis> - </refsynopsisdiv> + <refsynopsisdiv> + <cmdsynopsis> + <command>::rivet::env</command> + <arg><replaceable>environment_variable_name</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - If it is only necessary to load one environmental variable, - this command may be used to avoid the overhead of loading - and storing the entire array. - </para> - </refsect1> + <refsect1> + <title>Description</title> + <para> + If just one environmental variable is needed <command>::rivet::env</command> + returns the variable value or an empty string if the environment + variable name in the argument is not defined. + This command has some performance advantages with respect to + <command>::rivet::load_env</command> since it avoids the + loading of the whole set of environment and header variables. + </para> + </refsect1> </refentry> <refentry id="escape_sgml_chars"> @@ -530,19 +532,16 @@ </cmdsynopsis> </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - Scans through each character in the specified string looking - for any special (with respect to SGML, and hence HTML) characters - from the specified string, and returns the result. - For example, the right angle bracket is escaped to the corrected - ampersand gt symbol. - </para> - <!--note> - You must require the <command>rivetlib</command> package in order to gain access to this command - </note --> - </refsect1> + <refsect1> + <title>Description</title> + <para> + Scans through each character in the specified string looking + for any special (with respect to SGML, and hence HTML) characters + from the specified string, and returns the result. + For example, the right angle bracket is escaped to the corrected + ampersand gt symbol. + </para> + </refsect1> </refentry> <refentry id="escape_shell_command"> diff --git a/rivet/packages/session/session-class.tcl b/rivet/packages/session/session-class.tcl index abc62fa..28fb3e1 100644 --- a/rivet/packages/session/session-class.tcl +++ b/rivet/packages/session/session-class.tcl @@ -1,7 +1,6 @@ # # Session - Itcl object for web session management for Rivet # -# $Id$ # # Copyright 2004 The Apache Software Foundation @@ -476,7 +475,7 @@ package require Itcl } # - # is_new_sesion - return a 1 if it's a new session, else a zero if there + # is_new_session - return a 1 if it's a new session, else a zero if there # were one or more prior pages creating and/or using this session ID # method is_new_session {} { diff --git a/rivet/packages/session/session-create-mysql.sql b/rivet/packages/session/session-create-mysql.sql index 0e79087..93fae67 100644 --- a/rivet/packages/session/session-create-mysql.sql +++ b/rivet/packages/session/session-create-mysql.sql @@ -18,9 +18,9 @@ create table rivet_session ( DROP TABLE IF EXISTS `rivet_session_cache`; create table rivet_session_cache( session_id varchar(128) default NULL, - package_ varchar(64) default NULL, - key_ varchar(128) default NULL, - data varchar(255) default NULL, + package_ varchar(128) default NULL, + key_ varchar(256) default NULL, + data varchar(4096) default NULL, UNIQUE KEY riv_sess_cache_ix( session_id, package_, key_ ), KEY rivet_session_cache_idx (session_id), diff --git a/rivet/packages/session/session-create-oracle.sql b/rivet/packages/session/session-create-oracle.sql index ad4b0d9..4d5b1b1 100644 --- a/rivet/packages/session/session-create-oracle.sql +++ b/rivet/packages/session/session-create-oracle.sql @@ -4,10 +4,10 @@ -- Arnulf -- CREATE TABLE rivet_session - (ip_address VARCHAR2(23) DEFAULT NULL, + (ip_address VARCHAR2(23) DEFAULT NULL, session_start_time DATE DEFAULT NULL, session_update_time DATE DEFAULT NULL, - session_id VARCHAR2(50) NOT NULL + session_id VARCHAR2(64) NOT NULL ) / @@ -16,10 +16,10 @@ ALTER TABLE rivet_session ADD PRIMARY KEY (session_id) / CREATE TABLE rivet_session_cache - (session_id VARCHAR2(50) DEFAULT NULL, - package_ VARCHAR2(100) DEFAULT NULL, - key_ VARCHAR2(50) DEFAULT NULL, - data VARCHAR2(255) DEFAULT NULL + (session_id VARCHAR2(128) DEFAULT NULL, + package_ VARCHAR2(128) DEFAULT NULL, + key_ VARCHAR2(256) DEFAULT NULL, + data VARCHAR2(4096) DEFAULT NULL ) / diff --git a/rivet/packages/session/session-create-sqlite.sql b/rivet/packages/session/session-create-sqlite.sql index 36b1a3d..868cbce 100644 --- a/rivet/packages/session/session-create-sqlite.sql +++ b/rivet/packages/session/session-create-sqlite.sql @@ -7,9 +7,9 @@ CREATE TABLE rivet_session ( ); CREATE TABLE rivet_session_cache ( session_id varchar(128) default NULL PRIMARY KEY ON CONFLICT FAIL, - package_ varchar(64) default NULL, - key_ varchar(128) default NULL, - data varchar(255) default NULL, + package_ varchar(128) default NULL, + key_ varchar(256) default NULL, + data varchar(4096) default NULL, -- KEY rivet_session_cache_idx (session_id), CONSTRAINT session_cleanup FOREIGN KEY (session_id) REFERENCES rivet_session(session_id) ON DELETE CASCADE diff --git a/src/mod_rivet_ng/TclWebapache.c b/src/mod_rivet_ng/TclWebapache.c index 9d573ee..fba67b7 100644 --- a/src/mod_rivet_ng/TclWebapache.c +++ b/src/mod_rivet_ng/TclWebapache.c @@ -41,15 +41,29 @@ extern module rivet_module; extern mod_rivet_globals* module_globals; -#define TCLWEBPOOL req->req->pool -#define BUFSZ 4096 +/* It's kind of an overkill: we define macros for handling the + * flags that control the handling of the three environment variables + * classes (common, CGI and include variables). */ + +#define ENV_COMMON_VARS_M 1 +#define ENV_CGI_VARS_M 2 +#define ENV_VARS_M 4 +#define ENV_VARS_RESET(env) env = 0; +#define ENV_COMMON_VARS(env) env |= ENV_COMMON_VARS_M; +#define ENV_CGI_VARS(env) env |= ENV_CGI_VARS_M; +#define ENV_VARS(env) env |= ENV_VARS_M; + +#define ENV_IS_LOADED(env) (env == (ENV_COMMON_VARS_M | ENV_CGI_VARS_M | ENV_VARS_M)) +#define ENV_COMMON_VARS_LOADED(env) (env & ENV_COMMON_VARS_M) != 0 +#define ENV_CGI_VARS_LOADED(env) (env & ENV_CGI_VARS_M) != 0 +#define ENV_VARS_LOADED(env) (env & ENV_VARS_M) != 0 /* This is used below to determine what part of the parmsarray to parse. */ -#define PARMSARRAY_COORDINATES i = 0; j = parmsarray->nelts; \ -if (source == VAR_SRC_QUERYSTRING) { j = req->apachereq->nargs; } \ -else if (source == VAR_SRC_POST) { i = req->apachereq->nargs; } +#define PARMSARRAY_COORDINATES(i,j,parray,nargs) i = 0; j = parray->nelts; \ +if (source == VAR_SRC_QUERYSTRING) { j = nargs; } \ +else if (source == VAR_SRC_POST) { i = nargs; } /* * -- TclWeb_NewRequestObject @@ -67,13 +81,12 @@ TclWeb_NewRequestObject (apr_pool_t *p) req->apachereq = ApacheRequest_new(p); req->headers_printed = 0; req->headers_set = 0; - req->environment_set = 0; + ENV_VARS_RESET(req->environment_set) req->charset = NULL; /* we will test against NULL to check if a charset * * was specified in the conf */ return req; } - /* * -- TclWeb_InitRequest * @@ -101,16 +114,18 @@ TclWeb_InitRequest(rivet_thread_private* private, Tcl_Interp *interp) req->apachereq = ApacheRequest_init(req->apachereq,r); req->headers_printed = 0; req->headers_set = 0; - req->environment_set = 0; + ENV_VARS_RESET(req->environment_set) req->charset = NULL; /* * if strlen(req->content_type) > strlen([RIVET|TCL]_FILE_CTYPE) - * a charset parameters might be there + * a charset parameters might be in the configuration like + * + * AddType 'application/x-httpd-rivet;charset=utf-8' rvt */ if (((private->ctype==RIVET_TEMPLATE) && (content_type_len > strlen(RIVET_TEMPLATE_CTYPE))) || \ - ((private->ctype==RIVET_TCLFILE) && (content_type_len > strlen(RIVET_TCLFILE_CTYPE)))) { + ((private->ctype==RIVET_TCLFILE) && (content_type_len > strlen(RIVET_TCLFILE_CTYPE)))) { char* charset; @@ -156,8 +171,6 @@ TclWeb_SetHeaderType(char *header, TclWebRequest *req) if (req->headers_set) return TCL_ERROR; -// req->req->content_type = (char *) apr_pstrdup(req->req->pool, header); - ap_set_content_type(req->req,apr_pstrdup(req->req->pool, header)); req->headers_set = 1; return TCL_OK; @@ -187,7 +200,6 @@ TclWeb_PrintHeaders(TclWebRequest *req) */ TclWeb_SendHeaders(req); - /* ap_send_http_header(req->req); */ req->headers_printed = 1; return TCL_OK; @@ -207,7 +219,7 @@ TclWeb_PrintError(CONST84 char *errstr, int htmlflag, TclWebRequest *req) { if (htmlflag != 1) { - ap_rputs(ap_escape_html(TCLWEBPOOL, errstr), req->req); + ap_rputs(ap_escape_html(req->req->pool,errstr),req->req); } else { ap_rputs(errstr, req->req); } @@ -270,65 +282,66 @@ INLINE int TclWeb_MakeURL(Tcl_Obj *result, char *filename, TclWebRequest *req) { Tcl_SetStringObj(result, - ap_construct_url(TCLWEBPOOL,filename,req->req),-1); + ap_construct_url(req->req->pool,filename,req->req),-1); return TCL_OK; } int TclWeb_GetVar(Tcl_Obj *result, char *varname, int source, TclWebRequest *req) { - int i, j; - apr_array_header_t *parmsarray = (apr_array_header_t *) - apr_table_elts(req->apachereq->parms); - apr_table_entry_t *parms = (apr_table_entry_t *)parmsarray->elts; + int i,j; + apr_array_header_t *parmsarray = (apr_array_header_t *)apr_table_elts(req->apachereq->parms); + apr_table_entry_t *parms = (apr_table_entry_t *)parmsarray->elts; int flag = 0; - PARMSARRAY_COORDINATES; + PARMSARRAY_COORDINATES(i,j,parmsarray,req->apachereq->nargs) /* This isn't real efficient - move to hash table later on... */ while (i < j) { char *parmkey = TclWeb_StringToUtf(parms[i].key, req); - if (!strncmp(varname, parmkey, + if (!strncmp(varname,parmkey, strlen(varname) < strlen(parmkey) ? strlen(parmkey) : strlen(varname))) { + /* The following makes sure that we get one string, with no sub lists. */ + if (flag == 0) { + flag = 1; - Tcl_SetStringObj(result, - TclWeb_StringToUtf(parms[i].val, req), -1); + Tcl_SetStringObj (result,TclWeb_StringToUtf(parms[i].val,req),-1); + } else { + Tcl_Obj *tmpobj; Tcl_Obj *tmpobjv[2]; tmpobjv[0] = result; - tmpobjv[1] = TclWeb_StringToUtfToObj(parms[i].val, req); - tmpobj = Tcl_ConcatObj(2, tmpobjv); - Tcl_SetStringObj(result, Tcl_GetString(tmpobj), -1); + tmpobjv[1] = TclWeb_StringToUtfToObj (parms[i].val,req); + tmpobj = Tcl_ConcatObj (2,tmpobjv); + Tcl_SetStringObj (result,Tcl_GetString(tmpobj),-1); + } + } i++; } - if (result->length == 0) - { - return TCL_ERROR; - } + if (result->length == 0) { return TCL_ERROR; } return TCL_OK; } int -TclWeb_GetVarAsList(Tcl_Obj *result, char *varname, int source, TclWebRequest *req) -{ +TclWeb_GetVarAsList(Tcl_Obj *result, char *varname, int source, TclWebRequest *req) { int i, j; apr_array_header_t *parmsarray = (apr_array_header_t *) apr_table_elts(req->apachereq->parms); apr_table_entry_t *parms = (apr_table_entry_t *)parmsarray->elts; - PARMSARRAY_COORDINATES; + PARMSARRAY_COORDINATES(i,j,parmsarray,req->apachereq->nargs) /* This isn't real efficient - move to hash table later on. */ while (i < j) @@ -359,20 +372,20 @@ TclWeb_GetAllVars(Tcl_Obj *result, int source, TclWebRequest *req) apr_table_elts(req->apachereq->parms); apr_table_entry_t *parms = (apr_table_entry_t *)parmsarray->elts; - PARMSARRAY_COORDINATES; + PARMSARRAY_COORDINATES(i,j,parmsarray,req->apachereq->nargs) while (i < j) { - Tcl_ListObjAppendElement(req->interp, result, - TclWeb_StringToUtfToObj(parms[i].key, req)); - Tcl_ListObjAppendElement(req->interp, result, - TclWeb_StringToUtfToObj(parms[i].val, req)); - i++; + Tcl_ListObjAppendElement(req->interp,result, + TclWeb_StringToUtfToObj(parms[i].key,req)); + Tcl_ListObjAppendElement(req->interp,result, + TclWeb_StringToUtfToObj(parms[i].val,req)); + i++; } if (result == NULL) { - return TCL_ERROR; + return TCL_ERROR; } return TCL_OK; } @@ -385,18 +398,18 @@ TclWeb_GetVarNames(Tcl_Obj *result, int source, TclWebRequest *req) apr_table_elts(req->apachereq->parms); apr_table_entry_t *parms = (apr_table_entry_t *)parmsarray->elts; - PARMSARRAY_COORDINATES; + PARMSARRAY_COORDINATES(i,j,parmsarray,req->apachereq->nargs) while (i < j) { - Tcl_ListObjAppendElement(req->interp, result, - TclWeb_StringToUtfToObj(parms[i].key, req)); - i++; + Tcl_ListObjAppendElement(req->interp, result, + TclWeb_StringToUtfToObj(parms[i].key, req)); + i++; } if (result == NULL) { - return TCL_ERROR; + return TCL_ERROR; } return TCL_OK; @@ -410,7 +423,7 @@ TclWeb_VarExists(Tcl_Obj *result, char *varname, int source, TclWebRequest *req) apr_table_elts(req->apachereq->parms); apr_table_entry_t *parms = (apr_table_entry_t *)parmsarray->elts; - PARMSARRAY_COORDINATES; + PARMSARRAY_COORDINATES(i,j,parmsarray,req->apachereq->nargs) /* This isn't real efficient - move to hash table later on. */ while (i < j) @@ -445,79 +458,181 @@ TclWeb_VarNumber(Tcl_Obj *result, int source, TclWebRequest *req) return TCL_OK; } +/* These 2 array must be aligned and a one-to-one correspondence preserved + * The enum include_vars_idx must be terminated by 'invalid_env_var' + */ + +static const char* include_env_vars[] = +{ + "DATE_LOCAL","DATE_GMT","LAST_MODIFIED","DOCUMENT_URI","DOCUMENT_PATH_INFO","DOCUMENT_NAME", + "QUERY_STRING_UNESCAPED","USER_NAME","RIVET_CACHE_FREE","RIVET_CACHE_SIZE", + NULL +}; +enum include_vars_idx { + date_local=0,date_gmt,last_modified,document_uri,document_path_info,document_name, + query_string_unescaped,user_name,rivet_cache_free,rivet_cache_size, + invalid_env_var +}; + +static char* +TclWeb_SelectEnvIncludeVar (rivet_thread_private* private,int idx) +{ + switch (idx) + { + case date_local: + { + apr_pool_t* pool = private->req->req->pool; + apr_time_t date = private->req->req->request_time; + + return ap_ht_time(pool,date,DEFAULT_TIME_FORMAT,0); + } + case date_gmt: + { + apr_pool_t* pool = private->req->req->pool; + apr_time_t date = private->req->req->request_time; + + return ap_ht_time(pool,date,DEFAULT_TIME_FORMAT,1); + } + case last_modified: + { + apr_pool_t* pool = private->req->req->pool; + + return ap_ht_time(pool,private->req->req->finfo.mtime,DEFAULT_TIME_FORMAT,1); + } + case document_uri: + { + return private->req->req->uri; + } + case document_path_info: + { + return private->req->req->path_info; + } + case document_name: + { + char *t; + + if ((t = strrchr(private->req->req->filename,'/'))) { + return ++t; + } else { + return private->req->req->uri; + } + } + case query_string_unescaped: + { + if (private->req->req->args) { + apr_pool_t* pool = private->req->req->pool; + char *arg_copy = (char*) apr_pstrdup(pool,private->req->req->args); + + ap_unescape_url(arg_copy); + return ap_escape_shell_cmd(pool,arg_copy); + } else { + return NULL; + } + + } + case user_name: + { +#ifndef WIN32 + struct passwd *pw = (struct passwd *) getpwuid(private->req->req->finfo.user); + if (pw) { + //apr_table_set( table, "USER_NAME", + // apr_pstrdup( pool, pw->pw_name ) ); + return pw->pw_name; + } else { + apr_pool_t* pool = private->req->req->pool; + return (char*) apr_psprintf(pool,"user#%lu",(unsigned long)private->req->req->finfo.user); + } +#else + return NULL; +#endif + } + case rivet_cache_free: + { + apr_pool_t* pool = private->req->req->pool; + return (char*) apr_psprintf (pool, "%d",(RIVET_PEEK_INTERP(private,private->running_conf))->cache_free); + } + case rivet_cache_size: + { + apr_pool_t* pool = private->req->req->pool; + return (char*) apr_psprintf (pool, "%d",(RIVET_PEEK_INTERP(private,private->running_conf))->cache_size); + } + } + return NULL; +} + /* - * Load the Apache environment and CGI variables into the request. If we - * have already done so, we don't need to do it again. + * -- TclWeb_InitEnvVars + * + * Load the CGI and environment variables into the request_rec environment structure + * Variables belong to 3 cathegories + * + * + common variables (ap_add_common_vars) + * + CGI variables (ad_cgi_vars) + * + a miscellaneous set of variables + * listed in the array include_env_vars + * + * Each cathegory is controlled by flags in order to reduce the overhead of getting them + * into request_rec in case previous call to ::rivet::env could have already forced them + * into request_rec */ + static void TclWeb_InitEnvVars (rivet_thread_private* private) { - //rivet_server_conf *rsc; - char *timefmt = DEFAULT_TIME_FORMAT; - char *t; - apr_time_t date; -#ifndef WIN32 - struct passwd *pw; -#endif /* ndef WIN32 */ - TclWebRequest *req; - apr_table_t *table; + TclWebRequest *req = private->req; + apr_table_t *table; + int idx; - req = private->req; - table = req->req->subprocess_env; - date = req->req->request_time; - - if( req->environment_set ) return; + if (ENV_IS_LOADED(req->environment_set)) return; - //rsc = RIVET_SERVER_CONF( req->req->server->module_config ); + table = req->req->subprocess_env; /* Retrieve cgi variables. */ - ap_add_cgi_vars( req->req ); - ap_add_common_vars( req->req ); - - /* These were the "include vars" */ - - apr_table_set( table, "DATE_LOCAL", - ap_ht_time( TCLWEBPOOL, date, timefmt, 0 ) ); - apr_table_set( table, "DATE_GMT", - ap_ht_time( TCLWEBPOOL, date, timefmt, 1 ) ); - apr_table_set( table, "LAST_MODIFIED", - ap_ht_time( TCLWEBPOOL, req->req->finfo.mtime, timefmt, 1 ) ); - apr_table_set( table, "DOCUMENT_URI", req->req->uri ); - apr_table_set( table, "DOCUMENT_PATH_INFO", req->req->path_info ); - - if ((t = strrchr(req->req->filename, '/'))) { - apr_table_set( table, "DOCUMENT_NAME", ++t ); - } else { - apr_table_set( table, "DOCUMENT_NAME", req->req->uri ); + if (!ENV_CGI_VARS_LOADED(req->environment_set)) + { + ap_add_cgi_vars(req->req); + ENV_CGI_VARS(req->environment_set); } - - if( req->req->args ) { - char *arg_copy = (char*) apr_pstrdup(TCLWEBPOOL, req->req->args); - ap_unescape_url(arg_copy); - apr_table_set( table, "QUERY_STRING_UNESCAPED", - ap_escape_shell_cmd( TCLWEBPOOL, arg_copy ) ); + if (!ENV_COMMON_VARS_LOADED(req->environment_set)) + { + ap_add_common_vars(req->req); + ENV_COMMON_VARS(req->environment_set) } -#ifndef WIN32 - pw = (struct passwd *) getpwuid(req->req->finfo.user); - if( pw ) { - //apr_table_set( table, "USER_NAME", - // apr_pstrdup( TCLWEBPOOL, pw->pw_name ) ); - } else { - apr_table_set( table, "USER_NAME", - (char*) apr_psprintf( TCLWEBPOOL, "user#%lu", - (unsigned long)req->req->finfo.user ) ); + /* Loading into 'table' the include vars */ + + /* actually this is not necessary. ENV_VARS is modified only here therefore + * if it's set this function has been called already + * and it should have returned at the beginning of the execution. I keep + * it for clarity and uniformity with the CGI variables and in case + * the incremental environment control is extended + */ + + if (!ENV_VARS_LOADED(req->environment_set)) + { + for (idx = 0;idx < invalid_env_var;idx++) + { + apr_table_set(table,include_env_vars[idx],TclWeb_SelectEnvIncludeVar(private,idx)); + } + ENV_VARS(req->environment_set) } -#endif - /* Here we create some variables with Rivet internal information. */ +} - apr_table_set (table, "RIVET_CACHE_FREE", - (char*) apr_psprintf (TCLWEBPOOL, "%d",(RIVET_PEEK_INTERP(private,private->running_conf))->cache_free)); - apr_table_set (table, "RIVET_CACHE_SIZE", - (char*) apr_psprintf (TCLWEBPOOL, "%d",(RIVET_PEEK_INTERP(private,private->running_conf))->cache_size)); +static char* +TclWeb_GetEnvIncludeVar (rivet_thread_private* private,char* key) +{ + int idx; - req->environment_set = 1; + for (idx = 0;idx < invalid_env_var; idx++) + { + const char* include_var_p = include_env_vars[idx]; + if (strncmp(key,include_var_p,strlen(key) < strlen(include_var_p) ? strlen(key) : strlen(include_var_p)) == 0) + { + return TclWeb_SelectEnvIncludeVar(private,idx); + } + } + return NULL; } int @@ -610,21 +725,21 @@ TclWeb_GetHeaderVars(Tcl_Obj *headersvar,rivet_thread_private* private) INLINE int TclWeb_Base64Encode(char *out, char *in, TclWebRequest *req) { - out = ap_pbase64encode(TCLWEBPOOL, in); + out = ap_pbase64encode(req->req->pool, in); return TCL_OK; } INLINE int TclWeb_Base64Decode(char *out, char *in, TclWebRequest *req) { - out = ap_pbase64decode(TCLWEBPOOL, in); + out = ap_pbase64decode(req->req->pool, in); return TCL_OK; } INLINE int TclWeb_EscapeShellCommand(char *out, char *in, TclWebRequest *req) { - out = ap_escape_shell_cmd(TCLWEBPOOL, in); + out = ap_escape_shell_cmd(req->req->pool, in); return TCL_OK; } @@ -639,7 +754,7 @@ char *TclWeb_StringToUtf(char *in, TclWebRequest *req) Tcl_DString dstr; Tcl_DStringInit(&dstr); Tcl_ExternalToUtfDString(NULL, in, (signed)strlen(in), &dstr); - tmp = (char*) apr_pstrdup(TCLWEBPOOL, Tcl_DStringValue(&dstr)); + tmp = (char*) apr_pstrdup(req->req->pool, Tcl_DStringValue(&dstr)); Tcl_DStringFree(&dstr); return tmp; } @@ -679,7 +794,7 @@ int TclWeb_UploadChannel(char *varname, TclWebRequest *req) } Tcl_RegisterChannel(req->interp,chan); - result = Tcl_NewObj(); + result = Tcl_NewObj(); Tcl_SetStringObj(result, Tcl_GetChannelName(chan), -1); Tcl_SetObjResult(req->interp, result); @@ -801,23 +916,37 @@ char * TclWeb_GetEnvVar(rivet_thread_private* private,char *key) { char *val; - TclWebRequest *req; - - req = private->req; - TclWeb_InitEnvVars(private); + TclWebRequest *req = private->req; /* Check to see if it's a header variable first. */ - val = (char *)apr_table_get( req->req->headers_in, key ); + val = (char *)apr_table_get (req->req->headers_in,key); + if (val) { return val; } + + /* We incrementally prepare subprocess_env */ + /* CGI common vars first */ - if( !val ) { - val = (char *)apr_table_get( req->req->subprocess_env, key ); + if (!ENV_COMMON_VARS_LOADED(req->environment_set)) + { + ap_add_common_vars(req->req); + ENV_COMMON_VARS(req->environment_set) } + val = (char *)apr_table_get(req->req->subprocess_env,key); + if (val) { return val; } - return val; + /* CGI HTTP 1.1 vars */ + + if (!ENV_CGI_VARS_LOADED(req->environment_set)) + { + ap_add_cgi_vars(req->req); + ENV_CGI_VARS(req->environment_set) + } + val = (char *)apr_table_get(req->req->subprocess_env,key); + if (val) { return val; } + return TclWeb_GetEnvIncludeVar(private,key); } char * -TclWeb_GetVirtualFile( TclWebRequest *req, char *virtualname ) +TclWeb_GetVirtualFile(TclWebRequest *req, char *virtualname) { request_rec *apreq; char *filename = NULL; diff --git a/src/mod_rivet_ng/mod_rivet_generator.c b/src/mod_rivet_ng/mod_rivet_generator.c index 9ec8469..65d0f11 100644 --- a/src/mod_rivet_ng/mod_rivet_generator.c +++ b/src/mod_rivet_ng/mod_rivet_generator.c @@ -174,7 +174,7 @@ Rivet_SendContent(rivet_thread_private *private,request_rec* r) scripts = Rivet_RunningScripts (private->pool,scripts,newconfig); apr_hash_set (interp_obj->per_dir_scripts,rdc->path,strlen(rdc->path),scripts); - + private->running = scripts; } } diff --git a/src/mod_rivet_ng/rivetCore.c b/src/mod_rivet_ng/rivetCore.c index 3c115b1..3ed9d21 100644 --- a/src/mod_rivet_ng/rivetCore.c +++ b/src/mod_rivet_ng/rivetCore.c @@ -670,9 +670,9 @@ TCL_CMD_HEADER ( Rivet_Var ) "|number|all)"); return TCL_ERROR; } - cmd = Tcl_GetString(objv[0]); + cmd = Tcl_GetString(objv[0]); command = Tcl_GetString(objv[1]); - result = Tcl_NewObj(); + result = Tcl_NewObj(); /* determine if var_qs, var_post or var was called */ @@ -1417,9 +1417,9 @@ TCL_CMD_HEADER( Rivet_EnvCmd ) return TCL_ERROR; } - key = Tcl_GetStringFromObj( objv[1], NULL ); + key = Tcl_GetStringFromObj (objv[1],NULL); - val = TclWeb_GetEnvVar( private, key ); + val = TclWeb_GetEnvVar (private,key); Tcl_SetObjResult(interp, Tcl_NewStringObj( val, -1 ) ); return TCL_OK; diff --git a/src/mod_rivet_ng/rivet_types.h b/src/mod_rivet_ng/rivet_types.h index 04e060b..4f4fd23 100644 --- a/src/mod_rivet_ng/rivet_types.h +++ b/src/mod_rivet_ng/rivet_types.h @@ -87,7 +87,7 @@ typedef struct TclWebRequest { int headers_printed; /* has the header been printed yet? */ int headers_set; /* has the header been set yet? */ int content_sent; - int environment_set; /* have we setup the environment variables? */ + unsigned int environment_set; /* have we setup the environment variables? */ char* charset; } TclWebRequest; diff --git a/src/rivet.h b/src/rivet.h index c01d9f9..f3213b1 100644 --- a/src/rivet.h +++ b/src/rivet.h @@ -33,6 +33,7 @@ typedef int rivet_req_ctype; #define TCL_STORAGE_CLASS DLLEXPORT #endif /* BUILD_rivet */ +#define MINSTRLEN(s1,s2) strlen(s1) < strlen(s2) ? strlen(s1) : strlen(s2) #define STREQU(s1,s2) (s1[0] == s2[0] && strcmp(s1, s2) == 0) #define STRNEQU(s1,s2) (s1[0] == s2[0] && strncmp(s1, s2, strlen(s2)) == 0) #define RIVET_NS "::rivet" diff --git a/tests/apachetest/template.conf.1.tcl b/tests/apachetest/template.conf.1.tcl index 5b96c92..b63cacc 100644 --- a/tests/apachetest/template.conf.1.tcl +++ b/tests/apachetest/template.conf.1.tcl @@ -1,4 +1,4 @@ -# \$Id\$ + # Minimal config file for testing # Parsed by makeconf.tcl diff --git a/tests/env.rvt b/tests/env.rvt index d039ce0..fe45389 100644 --- a/tests/env.rvt +++ b/tests/env.rvt @@ -1,7 +1,25 @@ <? -::rivet::load_env +if {[::rivet::var_qs exists protocol]} { -puts "env(DOCUMENT_NAME) = $env(DOCUMENT_NAME)\n" + puts [::rivet::env SERVER_PROTOCOL] +} else { + + set load_env_f [::rivet::var get load_env 0] + + if {[string is true $load_env_f]} { + + # test env-1.1 + + ::rivet::load_env + puts "env(DOCUMENT_NAME) = $env(DOCUMENT_NAME)\n" + } else { + + # test env-1.2 + + set doc_name [::rivet::env DOCUMENT_NAME] + puts "env(DOCUMENT_NAME) = $doc_name\n" + } +} ?> diff --git a/tests/env.test b/tests/env.test index 05de770..155836c 100644 --- a/tests/env.test +++ b/tests/env.test @@ -1,9 +1,44 @@ -# $Id$ +# +# testing how the environment variables resolution +# is handled by mod_rivet +# -set testfilename1 env.rvt +set rvttestfilename env.rvt ::tcltest::test env-1.1 {Environment variable} { - set page [ ::http::geturl "${urlbase}$testfilename1" ] - regexp -line "^env\\(DOCUMENT_NAME\\) = $testfilename1\$" [ ::http::data $page ] match + set page [ ::http::geturl "${urlbase}$rvttestfilename?load_env=true" ] + regexp -line "^env\\(DOCUMENT_NAME\\) = $rvttestfilename\$" [::http::data $page] match set match -} "env(DOCUMENT_NAME) = $testfilename1" +} "env(DOCUMENT_NAME) = $rvttestfilename" + +::tcltest::test env-1.2 {Environment variable} { + set page [ ::http::geturl "${urlbase}$rvttestfilename?load_env=false" ] + regexp -line "^env\\(DOCUMENT_NAME\\) = $rvttestfilename\$" [::http::data $page] match + set match +} "env(DOCUMENT_NAME) = $rvttestfilename" + +::tcltest::test env-1.2.1 {CGI Environment variable double translation} { + set page1 [ ::http::geturl "${urlbase}$rvttestfilename?protocol=1"] + set match1 [string trim [::http::data $page1]] + set page2 [ ::http::geturl "${urlbase}$rvttestfilename?protocol=1"] + set match2 [string trim [::http::data $page2]] + #puts "proto: $match1 $match2" + expr [string match $match1 $match2] +} "1" + +set envmethod env_methods.tcl +set env_vars [list "DATE_LOCAL" "DATE_GMT" "LAST_MODIFIED" "DOCUMENT_URI" "DOCUMENT_PATH_INFO" "DOCUMENT_NAME" \ + "QUERY_STRING_UNESCAPED" "RIVET_CACHE_FREE" "RIVET_CACHE_SIZE" "HTTP_ACCEPT" "HTTP_HOST" \ + "QUERY_STRING" "SCRIPT_FILENAME" "SERVER_NAME" "SERVER_PORT" "SERVER_PROTOCOL"] + +puts "comparing ::rivet::env and ::rivet::load_env for variable resolution" +foreach v $env_vars { + puts -nonewline "$v " + ::tcltest::test env-1.3 {Environment variable methods} { + set page [::http::geturl "${urlbase}$envmethod?envvar=$v"] + ::http::data $page + } "$v: OK" +} +puts "" + + diff --git a/tests/rivet.test b/tests/rivet.test index fade49a..6ed3950 100755 --- a/tests/rivet.test +++ b/tests/rivet.test @@ -2,6 +2,23 @@ # the next line restarts using tclsh \ exec tclsh "$0" "$@" +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + # Rivet test suite, by David N. Welton <dav...@apache.org> # See README file for more information. @@ -27,8 +44,6 @@ set testgroup1 1 set testgroup2 1 set testgroup3 1 -#lappend TestList failtest.test - # Run all tests against one server process. if { $testgroup1 } { --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@tcl.apache.org For additional commands, e-mail: commits-h...@tcl.apache.org