You are viewing a plain text version of this content. The canonical link for it is here.
Posted to site-cvs@tcl.apache.org by mx...@apache.org on 2014/08/13 18:56:14 UTC

svn commit: r1617763 [1/2] - in /tcl/rivet/trunk: ./ src/experimental/

Author: mxmanghi
Date: Wed Aug 13 16:56:13 2014
New Revision: 1617763

URL: http://svn.apache.org/r1617763
Log:
    * src/experimental/rivet_[prefork|worker]_mpm.c: bridges integrated. Removed substantial code
    from rivet_prefork_mpm.c and merged with the current approach handling hosts interpreters using
    vhost_interp objects and storing everything in a child process/thread private data
    * src/experimental/apache_config.[c|h]: eventually these files had to be copied here from common
    and modified to reflect the new model for handling server records
    * src/experimental/mod_rivet_common.c: same for this file
    * src/experimental/mod_rivet.c: further generalization of the code to provide consistent
    support for the bridges. Adding a new hook for mpm_master_interp, a function implemented by
    a bridge responsible for returning the child process/thread master interpreter.



Added:
    tcl/rivet/trunk/src/experimental/TclWebapache.c
    tcl/rivet/trunk/src/experimental/apache_config.c
    tcl/rivet/trunk/src/experimental/apache_config.h
    tcl/rivet/trunk/src/experimental/mod_rivet_common.c
    tcl/rivet/trunk/src/experimental/mod_rivet_common.h
Modified:
    tcl/rivet/trunk/ChangeLog
    tcl/rivet/trunk/Makefile.in
    tcl/rivet/trunk/src/experimental/Makefile.am
    tcl/rivet/trunk/src/experimental/mod_rivet.c
    tcl/rivet/trunk/src/experimental/mod_rivet.h
    tcl/rivet/trunk/src/experimental/rivet_prefork_mpm.c
    tcl/rivet/trunk/src/experimental/rivet_worker_mpm.c

Modified: tcl/rivet/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/ChangeLog?rev=1617763&r1=1617762&r2=1617763&view=diff
==============================================================================
--- tcl/rivet/trunk/ChangeLog (original)
+++ tcl/rivet/trunk/ChangeLog Wed Aug 13 16:56:13 2014
@@ -1,3 +1,14 @@
+2014-08-12 Massimo Manghi <mx...@apache.org>
+    * src/experimental/rivet_[prefork|worker]_mpm.c: bridges integrated. Removed substantial code
+    from rivet_prefork_mpm.c and merged with the current approach handling hosts interpreters using
+    vhost_interp objects and storing everything in a child process/thread private data
+    * src/experimental/apache_config.[c|h]: eventually these files had to be copied here from common
+    and modified to reflect the new model for handling server records
+    * src/experimental/mod_rivet_common.c: same for this file
+    * src/experimental/mod_rivet.c: further generalization of the code to provide consistent
+    support for the bridges. Adding a new hook for mpm_master_interp, a function implemented by
+    a bridge responsible for returning the child process/thread master interpreter.
+
 2014-08-11 Massimo Manghi <mx...@apache.org>
     * src/experimental/rivet_worker_mpm.c: redesigning virtual hosts resource management for threads
     * src/experimental/mod_rivet[c|h]: implementing thread private interpreters management

Modified: tcl/rivet/trunk/Makefile.in
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/Makefile.in?rev=1617763&r1=1617762&r2=1617763&view=diff
==============================================================================
--- tcl/rivet/trunk/Makefile.in (original)
+++ tcl/rivet/trunk/Makefile.in Wed Aug 13 16:56:13 2014
@@ -17,7 +17,7 @@
 #
 # top-level Makefile.am for Apache Rivet: gets turned into a Makefile.in by automake
 #
-# $Id: Makefile.am 1517859 2013-08-27 16:08:31Z mxmanghi $
+# $Id: Makefile.am 1616967 2014-08-09 15:29:07Z mxmanghi $
 #
 # 2007/12/25: Added target uninistall-local that removes the tcl stuff (mxmanghi)
 # 2010/06/22: target instal-data-local searches for pkgIndex.tcl files and deletes them

Modified: tcl/rivet/trunk/src/experimental/Makefile.am
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/Makefile.am?rev=1617763&r1=1617762&r2=1617763&view=diff
==============================================================================
--- tcl/rivet/trunk/src/experimental/Makefile.am (original)
+++ tcl/rivet/trunk/src/experimental/Makefile.am Wed Aug 13 16:56:13 2014
@@ -10,13 +10,13 @@ apxs_libexec_LTLIBRARIES = mod_rivet.la
 mod_rivet_la_SOURCES =  mod_rivet.c                                         \
                         ../@apache_request@/apache_multipart_buffer.c 	    \
                         ../@apache_request@/apache_request.c                \
-                        ../@rivet_commands@/rivetCore.c                    \
-                        ../@rivet_commands@/rivetInspect.c                 \
+                        ../@rivet_commands@/rivetCore.c                     \
+                        ../@rivet_commands@/rivetInspect.c                  \
                         ../@rivet_channel@/rivetChannel.c                   \
-                        ../common/TclWebapache.c                            \
-                        ../common/apache_config.c                           \
-                        ../common/mod_rivet_common.c                        \
-                        ../parser/rivetParser.c
+                        ../parser/rivetParser.c                             \
+                        TclWebapache.c                                      \
+                        apache_config.c                                     \
+                        mod_rivet_common.c
 
 mod_rivet_la_LDFLAGS = @TCL_LIB_SPEC@ @APXS_LDFLAGS@ @APR_LDFLAGS@ -module -avoid-version
 mod_rivet_la_LIBADD = @TCL_LIBS@ @APXS_LIBS@ 

Added: tcl/rivet/trunk/src/experimental/TclWebapache.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/TclWebapache.c?rev=1617763&view=auto
==============================================================================
--- tcl/rivet/trunk/src/experimental/TclWebapache.c (added)
+++ tcl/rivet/trunk/src/experimental/TclWebapache.c Wed Aug 13 16:56:13 2014
@@ -0,0 +1,770 @@
+/*
+ * TclWeb.c --
+ *
+ * 	Common API layer.
+ *
+ * This file contains the Apache-based versions of the functions in
+ * TclWeb.h.  They rely on Apache and apreq to perform the underlying
+ * operations.
+ *
+ */
+
+/* Copyright 2002-2014 The Apache Software Foundation
+
+   Licensed 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.
+*/
+
+/* $Id: TclWebapache.c,v 1.49 2005/08/12 22:37:57 davidw Exp $ */
+
+/* Rivet config */
+#ifdef HAVE_CONFIG_H
+#include <rivet_config.h>
+#endif
+
+#include <tcl.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <httpd.h>
+#include <http_request.h>
+#include <ap_compat.h>
+#include <apr_strings.h>
+#include "apache_request.h"
+#include "mod_rivet.h"
+#include "TclWeb.h"
+
+extern module rivet_module;
+#define TCLWEBPOOL req->req->pool
+
+#define BUFSZ 4096
+
+/* 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; }
+
+/* 
+ * -- TclWeb_NewRequestObject
+ *
+ *
+ */
+
+TclWebRequest*
+TclWeb_NewRequestObject (apr_pool_t *p)
+{
+    TclWebRequest*  req = (TclWebRequest *)apr_pcalloc(p, sizeof(TclWebRequest));
+
+    req->interp             = NULL;
+    req->req                = NULL;
+    req->apachereq          = ApacheRequest_new(p);
+    req->headers_printed    = 0;
+    req->headers_set        = 0;
+    req->environment_set    = 0;
+    req->charset            = NULL;  /* we will test against NULL to check if a charset */
+                                     /* was specified in the conf */
+    return req;
+}
+
+
+/*
+ * -- TclWeb_InitRequest
+ *
+ * called once on every HTTP request initializes fields and
+ * objects referenced in a TclWebRequest object
+ *
+ * Arguments:
+ *
+ *  *req:    a pointer to a TclWebRequest object to be intialized
+ *  *interp: current Tcl_Interp object serving the request
+ *  *arg:    generic pointer. Current implementation passes the
+ *           request_rec object pointer 
+ *
+ */
+
+int
+TclWeb_InitRequest(TclWebRequest *req, Tcl_Interp *interp, void *arg)
+{
+    request_rec *r = (request_rec *)arg;
+
+    req->interp             = interp;
+    req->req                = r;
+    req->apachereq          = ApacheRequest_init(req->apachereq,r);
+    req->headers_printed    = 0;
+    req->headers_set        = 0;
+    req->environment_set    = 0;
+
+
+    req->charset = NULL;
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_SendHeaders(TclWebRequest *req)
+{
+    //TODO: fix ap_send_http_header
+    
+    ap_send_http_header(req->req);
+
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_StopSending(TclWebRequest *req)
+{
+    req->req->connection->aborted = 1;
+    return TCL_OK;
+}
+
+/* Set up the content type header */
+
+int
+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;
+}
+
+/* Printer headers if they haven't been printed yet */
+int
+TclWeb_PrintHeaders(TclWebRequest *req)
+{
+    if (req->headers_printed)
+        return TCL_ERROR;
+
+    if (req->headers_set == 0)
+    {
+        TclWeb_SetHeaderType(DEFAULT_HEADER_TYPE, req);
+    }
+    
+    /*
+     * seems that ap_send_http_header is redefined to ; in Apache2.2
+     * ap_send_http_header(req->req);
+     */
+    
+    TclWeb_SendHeaders(req);
+    /* ap_send_http_header(req->req); */
+
+    req->headers_printed = 1;
+    return TCL_OK;
+}
+
+/* Print nice HTML formatted errors */
+int
+TclWeb_PrintError(CONST84 char *errstr, int htmlflag, TclWebRequest *req)
+{
+    TclWeb_SetHeaderType(DEFAULT_HEADER_TYPE, req);
+    TclWeb_PrintHeaders(req);
+
+    if (htmlflag != 1)
+	ap_rputs(ER1, req->req);
+
+    if (errstr != NULL)
+    {
+	if (htmlflag != 1)
+	{
+	    ap_rputs(ap_escape_html(TCLWEBPOOL, errstr), req->req);
+	} else {
+	    ap_rputs(errstr, req->req);
+	}
+    }
+    if (htmlflag != 1)
+	ap_rputs(ER2, req->req);
+
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_HeaderSet(char *header, char *val, TclWebRequest *req)
+{
+    apr_table_set(req->req->headers_out, header, val);
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_HeaderAdd(char *header, char *val, TclWebRequest *req)
+{
+    apr_table_add(req->req->headers_out, header, val);
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_SetStatus(int status, TclWebRequest *req)
+{
+    req->req->status = status;
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_MakeURL(Tcl_Obj *result, char *filename, TclWebRequest *req)
+{
+    Tcl_SetStringObj(result, ap_construct_url(TCLWEBPOOL,
+					      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 flag = 0;
+
+    PARMSARRAY_COORDINATES;
+
+    /* 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,
+                    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);
+            } 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);
+            }
+        }
+        i++;
+    }
+
+    if (result->length == 0)
+    {
+	return TCL_ERROR;
+    }
+
+    return TCL_OK;
+}
+
+int
+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;
+
+    /* This isn't real efficient - move to hash table later on. */
+    while (i < j)
+    {
+
+	if (!strncmp(varname, TclWeb_StringToUtf(parms[i].key, req),
+		     strlen(varname) < strlen(parms[i].key) ?
+		     strlen(parms[i].key) : strlen(varname)))
+	{
+	    Tcl_ListObjAppendElement(req->interp, result,
+				     TclWeb_StringToUtfToObj(parms[i].val, req));
+	}
+	i++;
+    }
+
+    if (result == NULL)
+    {
+	return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+int
+TclWeb_GetAllVars(Tcl_Obj *result, 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;
+
+    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++;
+    }
+
+    if (result == NULL)
+    {
+	return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+int
+TclWeb_GetVarNames(Tcl_Obj *result, 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;
+
+    while (i < j)
+    {
+	Tcl_ListObjAppendElement(req->interp, result,
+				 TclWeb_StringToUtfToObj(parms[i].key, req));
+	i++;
+    }
+
+    if (result == NULL)
+    {
+	return TCL_ERROR;
+    }
+
+    return TCL_OK;
+}
+
+int
+TclWeb_VarExists(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;
+
+    /* This isn't real efficient - move to hash table later on. */
+    while (i < j)
+    {
+        if (!strncmp(varname, TclWeb_StringToUtf(parms[i].key, req),
+                    strlen(varname) < strlen(parms[i].key) ?
+                    strlen(parms[i].key) : strlen(varname)))
+        {
+            Tcl_SetIntObj(result, 1);
+            return TCL_OK;
+        }
+        i++;
+    }
+    Tcl_SetIntObj(result, 0);
+    return TCL_OK;
+}
+
+int
+TclWeb_VarNumber(Tcl_Obj *result, int source, TclWebRequest *req)
+{
+    apr_array_header_t *parmsarray = (apr_array_header_t *)
+        apr_table_elts(req->apachereq->parms);
+
+    if (source == VAR_SRC_QUERYSTRING) {
+	Tcl_SetIntObj(result, req->apachereq->nargs);
+    } else if (source == VAR_SRC_POST) {
+	Tcl_SetIntObj(result, parmsarray->nelts - req->apachereq->nargs);
+    } else {
+	Tcl_SetIntObj(result, parmsarray->nelts);
+    }
+
+    return TCL_OK;
+}
+
+/*
+ * Load the Apache environment and CGI variables into the request.  If we
+ * have already done so, we don't need to do it again.
+ */
+static void
+TclWeb_InitEnvVars( TclWebRequest *req )
+{
+    //rivet_server_conf *rsc;
+    apr_table_t *table = req->req->subprocess_env;
+    char *timefmt = DEFAULT_TIME_FORMAT;
+    char *t;
+    apr_time_t date = req->req->request_time;
+#ifndef WIN32
+    struct passwd *pw;
+#endif /* ndef WIN32 */
+
+    if( req->environment_set ) return;
+
+    //rsc = RIVET_SERVER_CONF( req->req->server->module_config );
+
+    /* 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( 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 ) );
+    }
+
+#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 ) );
+    }
+#endif
+
+    /* Here we create some variables with Rivet internal information. */
+
+    /* TODO: this information has to be fetched from the thread private data */
+    /*
+    apr_table_set( table, "RIVET_CACHE_FREE",
+            (char*)apr_psprintf( TCLWEBPOOL, "%d", *(rsc->cache_free) ) );
+    apr_table_set( table, "RIVET_CACHE_SIZE",
+            (char*)apr_psprintf( TCLWEBPOOL, "%d", *(rsc->cache_size) ) );
+    */
+
+    req->environment_set = 1;
+}
+
+int
+TclWeb_GetEnvVars(Tcl_Obj *envvar, TclWebRequest *req)
+{
+    int i;
+
+    apr_array_header_t *env_arr;
+    apr_table_entry_t  *env;
+    Tcl_Obj *key;
+    Tcl_Obj *val;
+
+    TclWeb_InitEnvVars( req );
+
+    Tcl_IncrRefCount(envvar);
+    /* Transfer Apache internal CGI variables to TCL request namespace. */
+    env_arr = (apr_array_header_t *) apr_table_elts(req->req->subprocess_env);
+    env     = (apr_table_entry_t *) env_arr->elts;
+    for (i = 0; i < env_arr->nelts; ++i)
+    {
+	if ((!env[i].key) || (!env[i].val)) {
+	    continue;
+	}
+
+	key = TclWeb_StringToUtfToObj(env[i].key, req);
+	val = TclWeb_StringToUtfToObj(env[i].val, req);
+	Tcl_IncrRefCount(key);
+	Tcl_IncrRefCount(val);
+
+    /* Variable scope resolution changed to default (flags: 0)
+     * to enable creation of the array in the caller's local scope.
+     * Default behavior (creation in the ::request namespace)
+     * is now more consistently constrained by fully qualifying
+     * the default array names (see rivetCore.c). This should fix
+     * Bug 48963 
+     */
+
+        Tcl_ObjSetVar2(req->interp, envvar, key, val, 0);
+
+ 	Tcl_DecrRefCount(key);
+	Tcl_DecrRefCount(val);
+    }
+    Tcl_DecrRefCount(envvar);
+
+    return TCL_OK;
+}
+
+int
+TclWeb_GetHeaderVars(Tcl_Obj *headersvar, TclWebRequest *req)
+{
+    int i;
+
+    apr_array_header_t *hdrs_arr;
+    apr_table_entry_t  *hdrs;
+    Tcl_Obj *key;
+    Tcl_Obj *val;
+
+    TclWeb_InitEnvVars( req );
+
+    Tcl_IncrRefCount(headersvar);
+    /* Transfer client request headers to TCL request namespace. */
+    hdrs_arr = (apr_array_header_t*) apr_table_elts(req->req->headers_in);
+    hdrs = (apr_table_entry_t *) hdrs_arr->elts;
+    for (i = 0; i < hdrs_arr->nelts; ++i)
+    {
+	if (!hdrs[i].key)
+	    continue;
+
+	key = TclWeb_StringToUtfToObj(hdrs[i].key, req);
+	val = TclWeb_StringToUtfToObj(hdrs[i].val, req);
+	Tcl_IncrRefCount(key);
+	Tcl_IncrRefCount(val);
+
+        /* See comment in TclWeb_GetEnvVars concerning Bug 48963*/
+
+        Tcl_ObjSetVar2(req->interp, headersvar, key, val, 0);
+ 	Tcl_DecrRefCount(key);
+	Tcl_DecrRefCount(val);
+    }
+
+    /* Transfer Apache internal CGI variables to TCL request namespace. */
+    Tcl_DecrRefCount(headersvar);
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_Base64Encode(char *out, char *in, TclWebRequest *req)
+{
+    out = ap_pbase64encode(TCLWEBPOOL, in);
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_Base64Decode(char *out, char *in, TclWebRequest *req)
+{
+    out = ap_pbase64decode(TCLWEBPOOL, in);
+    return TCL_OK;
+}
+
+INLINE int
+TclWeb_EscapeShellCommand(char *out, char *in, TclWebRequest *req)
+{
+    out = ap_escape_shell_cmd(TCLWEBPOOL, in);
+    return TCL_OK;
+}
+
+/* Functions to convert strings to UTF encoding */
+
+/* These API's are a bit different, because it's so much more
+ * practical. */
+
+char *TclWeb_StringToUtf(char *in, TclWebRequest *req)
+{
+    char *tmp;
+    Tcl_DString dstr;
+    Tcl_DStringInit(&dstr);
+    Tcl_ExternalToUtfDString(NULL, in, (signed)strlen(in), &dstr);
+    tmp = (char*) apr_pstrdup(TCLWEBPOOL, Tcl_DStringValue(&dstr));
+    Tcl_DStringFree(&dstr);
+    return tmp;
+}
+
+INLINE Tcl_Obj *
+TclWeb_StringToUtfToObj(char *in, TclWebRequest *req)
+{
+    return Tcl_NewStringObj(TclWeb_StringToUtf(in, req), -1);
+}
+
+int TclWeb_PrepareUpload(char *varname, TclWebRequest *req)
+{
+    req->upload = ApacheUpload_find(req->apachereq->upload, varname);
+    if (req->upload == NULL) {
+	return TCL_ERROR;
+    } else {
+	return TCL_OK;
+    }
+}
+
+int TclWeb_UploadChannel(char *varname, Tcl_Channel *chan, TclWebRequest *req)
+{
+    *chan = Tcl_OpenFileChannel (req->interp, req->upload->tempname, "r", 0);
+    if (chan == NULL) {
+	return TCL_ERROR;
+    } else {
+	if (Tcl_SetChannelOption(req->interp, *chan,
+			         "-translation", "binary") == TCL_ERROR) {
+	    return TCL_ERROR;
+	}
+	if (Tcl_SetChannelOption(req->interp, *chan,
+				 "-encoding", "binary") == TCL_ERROR) {
+	    return TCL_ERROR;
+	}
+	Tcl_RegisterChannel (req->interp, *chan);
+	return TCL_OK;
+    }
+}
+
+int TclWeb_UploadTempname(Tcl_Obj *tempname, TclWebRequest *req)
+{
+    Tcl_SetStringObj(tempname,
+		     TclWeb_StringToUtf(req->upload->tempname,
+					req), -1);
+    return TCL_OK;
+}
+
+
+int TclWeb_UploadSave(char *varname, Tcl_Obj *filename, TclWebRequest *req)
+{
+	apr_status_t	status;
+	status = apr_file_copy(req->upload->tempname ,Tcl_GetString(filename),APR_FILE_SOURCE_PERMS,req->req->pool);
+	if ( status == 0 ) {
+	    return TCL_OK;
+	} else {
+		return TCL_ERROR;
+	}
+}
+
+int TclWeb_UploadData(char *varname, Tcl_Obj *data, TclWebRequest *req)
+{
+    rivet_server_conf *rsc = NULL;
+
+    rsc  = RIVET_SERVER_CONF( req->req->server->module_config );
+    /* This sucks - we should use the hook, but I want to
+       get everything fixed and working first */
+    if (rsc->upload_files_to_var)
+    {
+	Tcl_Channel chan;
+	chan = Tcl_OpenFileChannel (req->interp, req->upload->tempname, "r", 0);
+	if (chan == NULL) {
+	    return TCL_ERROR;
+	}
+	if (Tcl_SetChannelOption(req->interp, chan,
+				 "-translation", "binary") == TCL_ERROR) {
+	    return TCL_ERROR;
+	}
+	if (Tcl_SetChannelOption(req->interp, chan,
+				 "-encoding", "binary") == TCL_ERROR) {
+	    return TCL_ERROR;
+	}
+
+	/* Put data in a variable  */
+	Tcl_ReadChars(chan, data, ApacheUpload_size(req->upload), 0);
+	if (Tcl_Close(req->interp, chan) == TCL_ERROR) {
+	    return TCL_ERROR;
+	}
+    } else {
+	Tcl_AppendResult(req->interp,
+			 "RivetServerConf UploadFilesToVar is not set", NULL);
+	return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+int TclWeb_UploadSize(Tcl_Obj *sz, TclWebRequest *req)
+{
+    Tcl_SetIntObj(sz, ApacheUpload_size(req->upload));
+    return TCL_OK;
+}
+
+int TclWeb_UploadType(Tcl_Obj *type, TclWebRequest *req)
+{
+    /* If there is a type, return it, if not, return blank. */
+    Tcl_SetStringObj(type, ApacheUpload_type(req->upload)
+		     ? (char *)ApacheUpload_type(req->upload) : (char *)"", -1);
+    return TCL_OK;
+}
+
+int TclWeb_UploadFilename(Tcl_Obj *filename, TclWebRequest *req)
+{
+    Tcl_SetStringObj(filename,
+		     TclWeb_StringToUtf(req->upload->filename,
+					req), -1);
+    return TCL_OK;
+}
+
+int TclWeb_UploadNames(Tcl_Obj *names, TclWebRequest *req)
+{
+    ApacheUpload *upload;
+
+    upload = ApacheRequest_upload(req->apachereq);
+    while (upload)
+    {
+	Tcl_ListObjAppendElement(
+	    req->interp, names,
+	    TclWeb_StringToUtfToObj(upload->name,req));
+	upload = upload->next;
+    }
+
+    return TCL_OK;
+}
+
+char *
+TclWeb_GetEnvVar( TclWebRequest *req, char *key )
+{
+    char *val;
+
+    TclWeb_InitEnvVars( req );
+
+    /* Check to see if it's a header variable first. */
+    val = (char *)apr_table_get( req->req->headers_in, key );
+
+    if( !val ) {
+        val = (char *)apr_table_get( req->req->subprocess_env, key );
+    }
+
+    return val;
+}
+
+char *
+TclWeb_GetVirtualFile( TclWebRequest *req, char *virtualname )
+{
+    request_rec *apreq;
+    char *filename = NULL;
+
+    apreq = ap_sub_req_lookup_uri( virtualname, req->req, NULL );
+
+    //if( apreq->status == 200 && apreq->finfo.st_mode != 0 ) {
+    //TODO: is this the right behaviour?
+    if( apreq->status == 200 && apreq->finfo.filetype != APR_NOFILE ) {
+        filename = apreq->filename;
+    }
+    if( apreq != NULL ) ap_destroy_sub_req( apreq );
+    return( filename );
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * TclWeb_GetRawPost --
+ *
+ * 	Fetch the raw POST data from the request.
+ *
+ * Results:
+ *	The data, or NULL if it's not a POST or there is no data.
+ *
+ * Side Effects:
+ *	None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+char *
+TclWeb_GetRawPost ( TclWebRequest *req )
+{
+    return ApacheRequest_get_raw_post(req->apachereq);
+}

Added: tcl/rivet/trunk/src/experimental/apache_config.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/apache_config.c?rev=1617763&view=auto
==============================================================================
--- tcl/rivet/trunk/src/experimental/apache_config.c (added)
+++ tcl/rivet/trunk/src/experimental/apache_config.c Wed Aug 13 16:56:13 2014
@@ -0,0 +1,652 @@
+/* apache_config.c -- configuration functions for apache 2.x */
+
+/* Copyright 2000-2005 The Apache Software Foundation
+
+   Licensed 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.
+*/
+
+/* $Id: apache_config.c 1609472 2014-07-10 15:08:52Z mxmanghi $ */
+
+/* Rivet config */
+#ifdef HAVE_CONFIG_H
+#include <rivet_config.h>
+#endif
+
+/* httpd includes */
+
+#include <httpd.h>
+#include <http_config.h>
+
+/* APR includes */
+
+#include <apr_pools.h>
+#include <apr_strings.h>
+#include <apr_tables.h>
+
+#include "mod_rivet.h"
+#include "apache_config.h"
+#include "rivet.h"
+
+/*
+ * -- Rivet_AssignStringtoConf --
+ *
+ *  Assign a string to a Tcl_Obj valued configuration parameter
+ *
+ * Arguments:
+ *
+ *  - objPnt: Pointer to a pointer to a Tcl_Obj. If the pointer *objPnt
+ *  is NULL (configuration script obj pointers are initialized to NULL)
+ *  a new Tcl_Obj is created
+ *  - string_value: a string to be assigned to the Tcl_Obj
+ *
+ * Results:
+ *  
+ *  - Pointer to a Tcl_Obj containing the parameter value.
+ *
+ */
+
+static Tcl_Obj* 
+Rivet_AssignStringToConf (Tcl_Obj** objPnt, const char* string_value)
+{
+    Tcl_Obj *objarg = NULL;
+    
+    if (*objPnt == NULL)
+    {
+        objarg = Tcl_NewStringObj(string_value,-1);
+        Tcl_IncrRefCount(objarg);
+        *objPnt = objarg;
+    } else {
+        objarg = *objPnt;
+        Tcl_AppendToObj(objarg, string_value, -1);
+    }
+    Tcl_AppendToObj( objarg, "\n", 1 );
+    return objarg;
+}
+
+/*
+ * -- Rivet_SetScript --
+ *
+ *  Add the text from an apache directive, such as UserConf, to
+ *  the corresponding variable in the rivet_server_conf structure.
+ *  In most cases, we append the new value to any previously
+ *  existing value, but Before, After and Error scripts override
+ *  the old directive completely.
+ *
+ * Results:
+ *
+ *  Returns a Tcl_Obj* pointing to the string representation of 
+ *  the current value for the directive.
+ *
+ */
+
+
+static const char *
+Rivet_SetScript (apr_pool_t *pool, rivet_server_conf *rsc, const char *script, const char *string)
+{
+    Tcl_Obj *objarg = NULL;
+
+    if( STREQU( script, "GlobalInitScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_global_init_script),string);
+    } else if( STREQU( script, "ChildInitScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_child_init_script),string);
+    } else if( STREQU( script, "ChildExitScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_child_exit_script),string);
+    } else if( STREQU( script, "BeforeScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_before_script),string);
+    } else if( STREQU( script, "AfterScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_after_script),string);
+    } else if( STREQU( script, "ErrorScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_error_script),string);
+    } else if( STREQU( script, "ServerInitScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_server_init_script),string);
+    } else if( STREQU( script, "AbortScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_abort_script),string);
+    } else if( STREQU( script, "AfterEveryScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->after_every_script),string);
+    }
+
+    if( !objarg ) return string;
+
+    return Tcl_GetStringFromObj( objarg, NULL );
+}
+
+/* 
+ * -- Rivet_GetConf
+ *
+ * Rivet_GetConf fetches the confguration from the server record
+ * and carries out a merge with server variables stored in directory
+ * specific configuration
+ *
+ * Arguments:
+ *
+ *  - request_rec* r: pointer to the request data
+ *
+ * Results:
+ *
+ *  - rivet_server_conf* rsc: the server merged configuration 
+ * 
+ * Side Effects:
+ *
+ *  None.
+ *
+ */
+
+rivet_server_conf *
+Rivet_GetConf( request_rec *r )
+{
+    rivet_server_conf *rsc = RIVET_SERVER_CONF( r->server->module_config );
+    void *dconf = r->per_dir_config;
+    rivet_server_conf *newconfig = NULL;
+    rivet_server_conf *rdc;
+    
+    FILEDEBUGINFO;
+
+    /* If there is no per dir config, just return the server config */
+    if (dconf == NULL) {
+        return rsc;
+    }
+    rdc = RIVET_SERVER_CONF( dconf ); 
+    
+    newconfig = RIVET_NEW_CONF( r->pool );
+
+    Rivet_CopyConfig( rsc, newconfig );
+    Rivet_MergeDirConfigVars( r->pool, newconfig, rsc, rdc );
+
+    return newconfig;
+}
+
+/*
+ * -- Rivet_CopyConfig --
+ *
+ *  Copy the rivet_server_conf struct.
+ *
+ * Results:
+ *  None.
+ *
+ * Side Effects:
+ *  None.
+ *
+ */
+void
+Rivet_CopyConfig( rivet_server_conf *oldrsc, rivet_server_conf *newrsc )
+{
+    FILEDEBUGINFO;
+
+    //newrsc->server_interp = oldrsc->server_interp;
+    newrsc->rivet_global_init_script = oldrsc->rivet_global_init_script;
+    newrsc->rivet_before_script = oldrsc->rivet_before_script;
+    newrsc->rivet_after_script = oldrsc->rivet_after_script;
+    newrsc->rivet_error_script = oldrsc->rivet_error_script;
+    newrsc->rivet_abort_script = oldrsc->rivet_abort_script;
+    newrsc->after_every_script = oldrsc->after_every_script;
+
+    newrsc->user_scripts_updated = oldrsc->user_scripts_updated;
+
+    newrsc->rivet_default_error_script = oldrsc->rivet_default_error_script;
+
+    /* These are pointers so that they can be passed around... */
+    newrsc->default_cache_size = oldrsc->default_cache_size;
+    //newrsc->cache_size = oldrsc->cache_size;
+    //newrsc->cache_free = oldrsc->cache_free;
+    newrsc->upload_max = oldrsc->upload_max;
+    newrsc->upload_files_to_var = oldrsc->upload_files_to_var;
+    newrsc->separate_virtual_interps = oldrsc->separate_virtual_interps;
+    newrsc->honor_header_only_reqs = oldrsc->honor_header_only_reqs;
+    newrsc->server_name = oldrsc->server_name;
+    newrsc->upload_dir = oldrsc->upload_dir;
+    newrsc->rivet_server_vars = oldrsc->rivet_server_vars;
+    newrsc->rivet_dir_vars = oldrsc->rivet_dir_vars;
+    newrsc->rivet_user_vars = oldrsc->rivet_user_vars;
+    newrsc->idx = oldrsc->idx;
+    //newrsc->objCacheList = oldrsc->objCacheList;
+    //newrsc->objCache = oldrsc->objCache;
+    //newrsc->outchannel = oldrsc->outchannel;
+}
+
+/*
+ * -- Rivet_MergeDirConfigVars
+ * 
+ * Merging of base configuration with per directory configuration
+ * is done checking each field in the configuration record. If
+ * a more specific (per directory) conf variable is defined then
+ * it supersedes the base record variable 
+ * 
+ * Arguments:
+ *
+ *  - apr_pool_t* t: pointer to an APR memory pool
+ *  - rivet_server_conf* new: pointer to a record to store the
+ *    merged configuration
+ *  - rivet_server_conf* base:
+ *  - rivet_server_conf* add:
+ *
+ * Results:
+ * 
+ *  configuration record are merge in place 
+ *
+ * Side Effects:
+ *
+ *   None.
+ */
+
+void
+Rivet_MergeDirConfigVars(apr_pool_t *p, rivet_server_conf *new,
+              rivet_server_conf *base, rivet_server_conf *add )
+{
+    FILEDEBUGINFO;
+    new->rivet_child_init_script = add->rivet_child_init_script ?
+        add->rivet_child_init_script : base->rivet_child_init_script;
+    new->rivet_child_exit_script = add->rivet_child_exit_script ?
+        add->rivet_child_exit_script : base->rivet_child_exit_script;
+
+    new->rivet_before_script = add->rivet_before_script ?
+        add->rivet_before_script : base->rivet_before_script;
+    new->rivet_after_script = add->rivet_after_script ?
+        add->rivet_after_script : base->rivet_after_script;
+    new->rivet_error_script = add->rivet_error_script ?
+        add->rivet_error_script : base->rivet_error_script;
+    new->rivet_abort_script = add->rivet_abort_script ?
+        add->rivet_abort_script : base->rivet_abort_script;
+    new->after_every_script = add->after_every_script ?
+        add->after_every_script : base->after_every_script;
+
+    new->user_scripts_updated = add->user_scripts_updated ?
+        add->user_scripts_updated : base->user_scripts_updated;
+
+    new->upload_dir = add->upload_dir ?
+        add->upload_dir : base->upload_dir;
+
+    /* Merge the tables of dir and user variables. */
+    if (base->rivet_dir_vars && add->rivet_dir_vars) {
+        new->rivet_dir_vars =
+            apr_table_overlay ( p, base->rivet_dir_vars, add->rivet_dir_vars );
+    } else {
+        new->rivet_dir_vars = base->rivet_dir_vars;
+    }
+    if (base->rivet_user_vars && add->rivet_user_vars) {
+        new->rivet_user_vars =
+            apr_table_overlay ( p, base->rivet_user_vars, add->rivet_user_vars );
+    } else {
+        new->rivet_user_vars = base->rivet_user_vars;
+    }
+}
+
+/*
+ * -- Rivet_CreateDirConfig
+ *
+ * Apache HTTP server framework calls this function to
+ * have a pointer to newly initialized directory specific 
+ * configuration record. 
+ *
+ * Arguments:
+ * 
+ *  - apr_pool_t*: pointer to an APR memory pool
+ *  - char*: string pointer to the directory name
+ *
+ * Returned value:
+ *
+ * - void* pointer to a brand new rivet configuration record
+ *
+ */
+
+
+void *
+Rivet_CreateDirConfig(apr_pool_t *p, char *dir)
+{
+    rivet_server_conf *rdc = RIVET_NEW_CONF(p);
+
+    FILEDEBUGINFO;
+
+    rdc->rivet_server_vars = (apr_table_t *) apr_table_make ( p, 4 );
+    rdc->rivet_dir_vars = (apr_table_t *) apr_table_make ( p, 4 );
+    rdc->rivet_user_vars = (apr_table_t *) apr_table_make ( p, 4 );
+
+    return rdc;
+}
+
+/*
+ * -- Rivet_MergeDirConfig
+ *
+ * Apache framework callback merging 2 per directory config records
+ *
+ * Arguments:
+ *
+ *  - apr_pool_t* p: pointer to an APR memory pool
+ *  - void* basev, addv: pointers to configuration records to be 
+ *    merged
+ * 
+ * Results:
+ * 
+ *  - void*: pointer to the resulting configuration
+ */
+
+void *
+Rivet_MergeDirConfig( apr_pool_t *p, void *basev, void *addv )
+{
+    rivet_server_conf *base = (rivet_server_conf *)basev;
+    rivet_server_conf *add  = (rivet_server_conf *)addv;
+    rivet_server_conf *new  = RIVET_NEW_CONF(p);
+
+    FILEDEBUGINFO;
+
+    Rivet_MergeDirConfigVars( p, new, base, add );
+
+    return new;
+}
+
+/*
+ * -- Rivet_MergeConfig --
+ *
+ *  This function is called when there is a config option set both
+ *  at the 'global' level, and for a virtual host.  It "resolves
+ *  the conflicts" so to speak, by creating a new configuration,
+ *  and this function is where we get to have our say about how to
+ *  go about doing that.  For most of the options, we override the
+ *  global option with the local one.
+ *
+ * Results:
+ *  Returns a new server configuration.
+ *
+ * Side Effects:
+ *  None.
+ *
+ */
+
+void *
+Rivet_MergeConfig(apr_pool_t *p, void *basev, void *overridesv)
+{
+    rivet_server_conf *rsc = RIVET_NEW_CONF(p);
+    rivet_server_conf *base = (rivet_server_conf *) basev;
+    rivet_server_conf *overrides = (rivet_server_conf *) overridesv;
+
+    FILEDEBUGINFO;
+
+    /* For completeness' sake, we list the fate of all the members of
+     * the rivet_server_conf struct. */
+
+    /* server_interp isn't set at this point. */
+    /* rivet_global_init_script is global, not per server. */
+
+    rsc->rivet_child_init_script = overrides->rivet_child_init_script ?
+        overrides->rivet_child_init_script : base->rivet_child_init_script;
+
+    rsc->rivet_child_exit_script = overrides->rivet_child_exit_script ?
+        overrides->rivet_child_exit_script : base->rivet_child_exit_script;
+
+    rsc->rivet_before_script = overrides->rivet_before_script ?
+        overrides->rivet_before_script : base->rivet_before_script;
+
+    rsc->rivet_after_script = overrides->rivet_after_script ?
+        overrides->rivet_after_script : base->rivet_after_script;
+
+    rsc->rivet_error_script = overrides->rivet_error_script ?
+        overrides->rivet_error_script : base->rivet_error_script;
+
+    rsc->rivet_default_error_script = overrides->rivet_default_error_script ?
+        overrides->rivet_default_error_script : base->rivet_default_error_script;
+
+    rsc->rivet_abort_script = overrides->rivet_abort_script ?
+        overrides->rivet_abort_script : base->rivet_abort_script;
+
+    rsc->after_every_script = overrides->after_every_script ?
+        overrides->after_every_script : base->after_every_script;
+
+    /* cache_size is global, and set up later. */
+    /* cache_free is not set up at this point. */
+
+    rsc->upload_max = overrides->upload_max ?
+        overrides->upload_max : base->upload_max;
+
+    rsc->separate_virtual_interps = base->separate_virtual_interps;
+    rsc->honor_header_only_reqs = base->honor_header_only_reqs;
+
+    /* server_name is set up later. */
+
+    rsc->upload_dir = overrides->upload_dir ?
+        overrides->upload_dir : base->upload_dir;
+
+    rsc->rivet_server_vars = overrides->rivet_server_vars ?
+        overrides->rivet_server_vars : base->rivet_server_vars;
+
+    rsc->rivet_dir_vars = overrides->rivet_dir_vars ?
+        overrides->rivet_dir_vars : base->rivet_dir_vars;
+
+    rsc->rivet_user_vars = overrides->rivet_user_vars ?
+        overrides->rivet_user_vars : base->rivet_user_vars;
+
+    /* objCacheList is set up later. */
+    /* objCache is set up later. */
+    /* outchannel is set up later. */
+
+    return rsc;
+}
+
+/*
+ * -- Rivet_CreateConfig
+ *
+ *
+ *
+ */
+
+void *
+Rivet_CreateConfig(apr_pool_t *p, server_rec *s )
+{
+    rivet_server_conf *rsc = RIVET_NEW_CONF(p);
+
+    FILEDEBUGINFO;
+
+    //rsc->server_interp          = NULL;
+
+/* scripts obj pointers *must* be initialized to NULL */
+
+    rsc->rivet_server_init_script   = NULL;
+    rsc->rivet_global_init_script   = NULL;
+    rsc->rivet_child_init_script    = NULL;
+    rsc->rivet_child_exit_script    = NULL;
+    rsc->rivet_before_script        = NULL;
+    rsc->rivet_after_script         = NULL;
+    rsc->rivet_error_script         = NULL;
+    rsc->rivet_abort_script         = NULL;
+    rsc->after_every_script         = NULL;
+
+    rsc->user_scripts_updated = 0;
+
+    rsc->rivet_default_error_script = Tcl_NewStringObj("::Rivet::handle_error", -1);
+    Tcl_IncrRefCount(rsc->rivet_default_error_script);
+
+    /* these are pointers so that they can be passed around...  */
+    //rsc->cache_size                 = apr_pcalloc(p, sizeof(int));
+    //rsc->cache_free                 = apr_pcalloc(p, sizeof(int));
+    //*(rsc->cache_size)              = -1;
+    //*(rsc->cache_free)              = 0;
+
+    rsc->default_cache_size         = -1;
+    rsc->upload_max                 = RIVET_MAX_POST;
+    rsc->upload_files_to_var        = RIVET_UPLOAD_FILES_TO_VAR;
+    rsc->separate_virtual_interps   = RIVET_SEPARATE_VIRTUAL_INTERPS;
+    rsc->honor_header_only_reqs     = RIVET_HEAD_REQUESTS;
+    rsc->upload_dir                 = RIVET_UPLOAD_DIR;
+    rsc->server_name                = NULL;
+    //rsc->objCacheList               = NULL;
+    //rsc->objCache                   = NULL;
+    //rsc->outchannel                 = NULL;
+
+    rsc->rivet_server_vars          = (apr_table_t *) apr_table_make ( p, 4 );
+    rsc->rivet_dir_vars             = (apr_table_t *) apr_table_make ( p, 4 );
+    rsc->rivet_user_vars            = (apr_table_t *) apr_table_make ( p, 4 );
+
+    return rsc;
+}
+
+/*
+ * -- Rivet_UserConf
+ *
+ * Implements the RivetUserConf Apache Directive
+ *
+ * Command Arguments:
+ *  RivetUserConf BeforeScript <script>
+ *  RivetUserConf AfterScript <script>
+ *  RivetUserConf ErrorScript <script>
+ */
+
+const char *
+Rivet_UserConf( cmd_parms *cmd, 
+                void *vrdc, 
+                const char *var, 
+                const char *val )
+{
+    rivet_server_conf *rdc = (rivet_server_conf *)vrdc;
+
+    FILEDEBUGINFO;
+
+    if ( var == NULL || val == NULL ) {
+        return "Rivet Error: RivetUserConf requires two arguments";
+    }
+
+    /* We have modified these scripts. */
+    /* This is less than ideal though, because it will get set to 1
+     * every time - FIXME. */
+
+    rdc->user_scripts_updated = 1;
+
+    if (STREQU(var,"BeforeScript")      || 
+        STREQU(var,"AfterScript")       || 
+        STREQU(var,"AbortScript")       ||
+        STREQU(var,"AfterEveryScript")  ||
+        STREQU(var,"UploadDirectory")  ||
+        STREQU(var,"ErrorScript"))
+    {
+        apr_table_set( rdc->rivet_user_vars, var, 
+                        Rivet_SetScript( cmd->pool, rdc, var, val));
+    }
+    else if (STREQU(var,"Debug")        ||
+             STREQU(var,"DebugIp")      ||
+             STREQU(var,"DebugSubst")   ||
+             STREQU(var,"DebugSeparator"))
+    {
+        apr_table_set( rdc->rivet_user_vars, var, val);
+    }
+    else
+    {
+        return apr_pstrcat(cmd->pool, "Rivet configuration error: '",var, 
+                                      "' not valid for RivetUserConf", NULL);
+    }
+
+    /* XXX Need to figure out what to do about setting the table.  */
+    // if (string != NULL) apr_table_set( rdc->rivet_user_vars, var, string );
+    return NULL;
+}
+
+
+/*
+ * Implements the RivetDirConf Apache Directive
+ *
+ * Command Arguments:
+ *  RivetDirConf BeforeScript <script>
+ *  RivetDirConf AfterScript <script>
+ *  RivetDirConf ErrorScript <script>
+ *  RivetDirConf AfterEveryScript <script>
+ *  RivetDirConf UploadDirectory <directory>
+ */
+
+const char *
+Rivet_DirConf( cmd_parms *cmd, void *vrdc, 
+               const char *var, const char *val )
+{
+    const char *string = val;
+    rivet_server_conf *rdc = (rivet_server_conf *)vrdc;
+
+    FILEDEBUGINFO;
+
+    if ( var == NULL || val == NULL ) {
+        return "Rivet Error: RivetDirConf requires two arguments";
+    }
+
+    if( STREQU( var, "UploadDirectory" ) ) {
+        rdc->upload_dir = val;
+    } else {
+        if (STREQU(var,"BeforeScript")      || 
+            STREQU(var,"AfterScript")       || 
+            STREQU(var,"AbortScript")       ||
+            STREQU(var,"AfterEveryScript")  ||
+            STREQU(var,"ErrorScript"))
+        {
+            string = Rivet_SetScript( cmd->pool, rdc, var, val );
+        }
+        else
+        {
+            return apr_pstrcat(cmd->pool, "Rivet configuration error: '",var, 
+                                          "' not valid for RivetDirConf", NULL);
+        }
+    }
+
+    if (string != NULL) apr_table_set( rdc->rivet_dir_vars, var, string );
+    return NULL;
+}
+
+/*
+ * Implements the RivetServerConf Apache Directive
+ *
+ * Command Arguments:
+ *
+ *  RivetServerConf ServerInitScript <script>
+ *  RivetServerConf GlobalInitScript <script>
+ *  RivetServerConf ChildInitScript <script>
+ *  RivetServerConf ChildExitScript <script>
+ *  RivetServerConf BeforeScript <script>
+ *  RivetServerConf AfterScript <script>
+ *  RivetServerConf ErrorScript <script>
+ *  RivetServerConf AfterEveryScript <script>
+ *  RivetServerConf CacheSize <integer>
+ *  RivetServerConf UploadDirectory <directory>
+ *  RivetServerConf UploadMaxSize <integer>
+ *  RivetServerConf UploadFilesToVar <yes|no>
+ *  RivetServerConf SeparateVirtualInterps <yes|no>
+ *  RivetServerConf HonorHeaderOnlyRequests <yes|no> (2008-06-20: mm)
+ */
+
+const char *
+Rivet_ServerConf( cmd_parms *cmd, void *dummy, 
+                  const char *var, const char *val )
+{
+    server_rec *s = cmd->server;
+    rivet_server_conf *rsc = RIVET_SERVER_CONF(s->module_config);
+    const char *string = val;
+
+    FILEDEBUGINFO;
+
+    if ( var == NULL || val == NULL ) {
+        return "Rivet Error: RivetServerConf requires two arguments";
+    }
+
+    if( STREQU( var, "CacheSize" ) ) {
+        rsc->default_cache_size = strtol( val, NULL, 10 );
+    } else if( STREQU( var, "UploadDirectory" ) ) {
+        rsc->upload_dir = val;
+    } else if( STREQU( var, "UploadMaxSize" ) ) {
+        rsc->upload_max = strtol( val, NULL, 10 );
+    } else if( STREQU( var, "UploadFilesToVar" ) ) {
+        Tcl_GetBoolean (NULL, val, &rsc->upload_files_to_var);
+    } else if( STREQU( var, "SeparateVirtualInterps" ) ) {
+        Tcl_GetBoolean (NULL, val, &rsc->separate_virtual_interps);
+    } else if( STREQU( var, "HonorHeaderOnlyRequests" ) ) {
+        Tcl_GetBoolean (NULL, val, &rsc->honor_header_only_reqs);
+    } else {
+        string = Rivet_SetScript( cmd->pool, rsc, var, val);
+    }
+
+    if (string != NULL) apr_table_set( rsc->rivet_server_vars, var, string );
+    return( NULL );
+}
+
+/* apache_config.c */
+

Added: tcl/rivet/trunk/src/experimental/apache_config.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/apache_config.h?rev=1617763&view=auto
==============================================================================
--- tcl/rivet/trunk/src/experimental/apache_config.h (added)
+++ tcl/rivet/trunk/src/experimental/apache_config.h Wed Aug 13 16:56:13 2014
@@ -0,0 +1,41 @@
+/* apache_config.h -- configuration functions for apache 2.x */
+
+/*
+    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.
+ */
+
+/* $Id: apache_config.h 1547463 2013-12-03 16:35:08Z mxmanghi $ */
+
+
+#ifndef __apache_config_h__
+#define __apache_config_h__
+
+#include "mod_rivet.h"
+
+void        Rivet_CopyConfig( rivet_server_conf *oldrsc, rivet_server_conf *newrsc);
+const char* Rivet_ServerConf(cmd_parms *cmd, void *dummy, const char *var, const char *val);
+const char* Rivet_DirConf(cmd_parms *cmd, void *vrdc, const char *var, const char *val);
+const char* Rivet_UserConf(cmd_parms *cmd, void *vrdc, const char *var, const char *val);
+void*       Rivet_CreateDirConfig(apr_pool_t *p, char *dir);
+void*       Rivet_MergeDirConfig( apr_pool_t *p, void *basev, void *addv);
+void*       Rivet_CreateConfig(apr_pool_t *p, server_rec *s);
+void*       Rivet_MergeConfig(apr_pool_t *p, void *basev, void *overridesv);
+void        Rivet_MergeDirConfigVars(apr_pool_t *p,rivet_server_conf *new,rivet_server_conf *base,rivet_server_conf *add);
+
+#endif
+

Modified: tcl/rivet/trunk/src/experimental/mod_rivet.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/mod_rivet.c?rev=1617763&r1=1617762&r2=1617763&view=diff
==============================================================================
--- tcl/rivet/trunk/src/experimental/mod_rivet.c (original)
+++ tcl/rivet/trunk/src/experimental/mod_rivet.c Wed Aug 13 16:56:13 2014
@@ -66,9 +66,206 @@ extern Tcl_ChannelType RivetChan;
 apr_threadkey_t*        rivet_thread_key;
 apr_threadkey_t*        handler_thread_key;
 
+void  Rivet_PerInterpInit(Tcl_Interp* interp, server_rec *s, apr_pool_t *p);
+
 #define ERRORBUF_SZ     256
 
-/* -----------------------------------------------------------------------------
+vhost_interp* Rivet_NewVHostInterp(apr_pool_t* pool)
+{
+    extern int ap_max_requests_per_child;
+    vhost_interp*       interp_obj = apr_pcalloc(pool,sizeof(vhost_interp));
+    rivet_server_conf*  rsc;
+
+    /* the cache size is global so we take it from here */
+    
+    rsc = RIVET_SERVER_CONF( module_globals->server->module_config );
+
+    /* This calls needs the root server_rec just for logging purposes*/
+
+    interp_obj->interp = Rivet_CreateTclInterp(module_globals->server); 
+
+    /* we now read from the pointers to the cache_size and cache_free conf parameters
+       for compatibility with mod_rivet current version, but these values must become
+       integers not pointers */
+    
+    if (rsc->default_cache_size < 0) {
+        if (ap_max_requests_per_child != 0) {
+            interp_obj->cache_size = ap_max_requests_per_child / 5;
+        } else {
+            interp_obj->cache_size = 50;    // Arbitrary number
+        }
+    } else if (rsc->default_cache_size > 0) {
+        interp_obj->cache_size = rsc->default_cache_size;
+    }
+
+    if (interp_obj->cache_size > 0) {
+        interp_obj->cache_free = interp_obj->cache_size;
+    }
+
+    // we now create memory from the cache pool as subpool of the thread private pool
+ 
+    if (apr_pool_create(&interp_obj->pool, pool) != APR_SUCCESS)
+    {
+        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, module_globals->server, 
+                     MODNAME ": could not initialize thread private pool");
+        return NULL;
+    }
+
+    // Initialize cache structures
+
+    if (interp_obj->cache_size) {
+        interp_obj->objCacheList = apr_pcalloc(interp_obj->pool, (signed)(interp_obj->cache_size*sizeof(char *)));
+        interp_obj->objCache = apr_pcalloc(interp_obj->pool, sizeof(Tcl_HashTable));
+        Tcl_InitHashTable(interp_obj->objCache, TCL_STRING_KEYS);
+    }
+
+    interp_obj->flags = 0;
+
+    return interp_obj;
+}
+
+rivet_thread_private* Rivet_VirtualHostsInterps (rivet_thread_private* private)
+{
+    server_rec*         s;
+    server_rec*         root_server = module_globals->server;
+    rivet_server_conf*  root_server_conf;
+    rivet_server_conf*  myrsc; 
+    vhost_interp*       root_interp;
+    void*               parentfunction;     /* this is topmost initialization script */
+    void*               function;
+
+    root_server_conf = RIVET_SERVER_CONF( root_server->module_config );
+    parentfunction = root_server_conf->rivet_child_init_script;
+    
+    root_interp = (*module_globals->mpm_master_interp)(private->pool);
+
+    if (root_interp == NULL)
+    {
+        return NULL;
+    }
+
+    for (s = root_server; s != NULL; s = s->next)
+    {
+        vhost_interp*   rivet_interp;
+
+        myrsc = RIVET_SERVER_CONF(s->module_config);
+        rivet_interp = root_interp;
+
+        if (s == root_server)
+        {
+            Tcl_RegisterChannel(rivet_interp->interp,*private->channel);
+        }
+        else if (root_server_conf->separate_virtual_interps)
+        {
+            rivet_interp = Rivet_NewVHostInterp(private->pool);
+            Tcl_RegisterChannel(rivet_interp->interp,*private->channel);
+        }
+
+        private->interps[myrsc->idx] = rivet_interp;
+
+        /* Basic Rivet packages and libraries are loaded here. Also the interpreter globals
+         * are setup here. We have to explore if could be sensed to moved them to the
+         * thread private data.
+         */
+
+        if ((rivet_interp->flags & RIVET_INTERP_INITIALIZED) == 0)
+        {
+            Rivet_PerInterpInit(rivet_interp->interp, root_server, private->pool);
+            rivet_interp->flags |= RIVET_INTERP_INITIALIZED;
+        }
+
+        /*  Check if it's absolutely necessary to lock the pool_mutex in order
+            to allocate from the module global pool 
+
+            this stuff must be allocated from the module global pool which
+            ha the same child process lifespan
+         */
+
+        apr_thread_mutex_lock(module_globals->pool_mutex);
+        myrsc->server_name = (char*)apr_pstrdup(module_globals->pool, s->server_hostname);
+        apr_thread_mutex_unlock(module_globals->pool_mutex);
+
+        function = myrsc->rivet_child_init_script;
+        if (function && 
+            (s == root_server || root_server_conf->separate_virtual_interps || function != parentfunction))
+        {
+            char*       errmsg = MODNAME ": Error in Child init script: %s";
+            Tcl_Interp* interp = rivet_interp->interp;
+
+            rivet_interp_globals* globals = Tcl_GetAssocData( interp, "rivet", NULL );
+            Tcl_Preserve (interp);
+
+            /* There a lot of passing around pointers to record object
+             * and we keep it just for compatibility with existing components
+             */
+
+            globals->srec = s;
+            if (Tcl_EvalObjEx(interp,function, 0) != TCL_OK) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, root_server,
+                             errmsg, Tcl_GetString(function));
+                ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, root_server, 
+                             "errorCode: %s",
+                                Tcl_GetVar(interp, "errorCode", 0));
+                ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, root_server, 
+                             "errorInfo: %s",
+                        Tcl_GetVar(interp, "errorInfo", 0));
+            }
+            Tcl_Release (interp);
+        }
+    }
+    return private;
+}
+
+
+/*----------------------------------------------------------------------------
+ * -- Rivet_ProcessorCleanup
+ *
+ * 
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void Rivet_ProcessorCleanup (void *data)
+{
+    rivet_thread_private*   private = (rivet_thread_private *) data;
+    Tcl_HashSearch*         searchCtx; 
+    Tcl_HashEntry*          entry;
+    int                     i;
+    rivet_server_conf*      rsc = RIVET_SERVER_CONF(module_globals->server->module_config);
+
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, module_globals->server, 
+            "Thread exiting after %d requests served", private->req_cnt);
+
+    for (i = 0; i < module_globals->vhosts_count; i++)
+    {
+
+        /* cleaning the cache contents and deleting it */
+
+        searchCtx = apr_pcalloc(private->pool,sizeof(Tcl_HashSearch));
+        entry = Tcl_FirstHashEntry(private->interps[i]->objCache,searchCtx);    
+        while (entry)
+        {
+            Tcl_DecrRefCount(Tcl_GetHashValue(entry)); /* Let Tcl clear the mem allocated */
+            Tcl_DeleteHashEntry(entry);
+
+            entry = Tcl_NextHashEntry(searchCtx);
+        }
+        
+        Tcl_UnregisterChannel(private->interps[i]->interp,*private->channel);
+        Tcl_DeleteInterp(private->interps[i]->interp);
+
+        /* if we are running the same interpreter instance for each vhost 
+           we can jump out of this loop after the first cycle */
+
+        if (!rsc->separate_virtual_interps) break;
+
+    }
+
+    apr_pool_destroy(private->pool);
+}
+
+
+/* ----------------------------------------------------------------------------
  * -- Rivet_SendContent
  *
  *   Set things up to execute a file, then execute 
@@ -117,7 +314,7 @@ Rivet_SendContent(rivet_thread_private *
     /* The current TclWebRequest record is assigned here to the thread private data
        for the channel to read it when actual output will flushed */
     
-    globals->req = private->req;
+    private->req = globals->req;
 
     /* Setting this pointer in globals is crucial as by assigning it
      * we signal to Rivet commands we are processing an HTTP request.
@@ -830,7 +1027,7 @@ void  Rivet_PerInterpInit(Tcl_Interp* in
  */
 
 static int
-Rivet_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *s)
+Rivet_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *server)
 {
     apr_status_t aprrv;
     char errorbuf[ERRORBUF_SZ];
@@ -848,9 +1045,18 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
 
     module_globals = apr_palloc(pPool,sizeof(mod_rivet_globals));
 
+    /* Creating the module global pool */
+
+    if (apr_pool_create(&module_globals->pool, NULL) != APR_SUCCESS) 
+    {
+        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
+                     MODNAME ": could not initialize mod_rivet private pool");
+        exit(1);
+    }
+
     /* Let's load the Rivet-MPM bridge */
 
-    /* TODO: This kludge to load off-path MPM model share libraries has to be removed because is a security hole */
+    /* TODO: This kludge to load off-path MPM bridges has to be removed because is a security hole */
 
     if (apr_env_get (&mpm_model_path,"RIVET_MPM_BRIDGE",pTemp) != APR_SUCCESS)
     {
@@ -863,7 +1069,7 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         apr_status_t                rv;
         apr_dso_handle_sym_t        func = NULL;
 
-        ap_log_error(APLOG_MARK,APLOG_INFO,0,s,"MPM bridge loaded: %s",mpm_model_path);
+        ap_log_error(APLOG_MARK,APLOG_INFO,0,server,"MPM bridge loaded: %s",mpm_model_path);
 
         rv = apr_dso_sym(&func,module_globals->dso_handle,"Rivet_MPM_ServerInit");
         if (rv == APR_SUCCESS)
@@ -872,7 +1078,7 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         }
         else
         {
-            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s, 
+            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
                          MODNAME ": Error loading symbol Rivet_MPM_ServerInit: %s", 
                          apr_dso_error(module_globals->dso_handle,errorbuf,ERRORBUF_SZ));
             exit(1);   
@@ -885,7 +1091,7 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         }
         else
         {
-            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s, 
+            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
                          MODNAME ": Error loading symbol Rivet_MPM_Init: %s", 
                          apr_dso_error(module_globals->dso_handle,errorbuf,ERRORBUF_SZ));
             exit(1);   
@@ -898,7 +1104,7 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         }
         else
         {
-            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s, 
+            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
                          MODNAME ": Error loading symbol Rivet_MPM_Request: %s", 
                          apr_dso_error(module_globals->dso_handle,errorbuf,ERRORBUF_SZ));
             exit(1);   
@@ -911,12 +1117,25 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         }
         else
         {
-            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s, 
+            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
                          MODNAME ": Error loading symbol Rivet_MPM_Finalize: %s", 
                          apr_dso_error(module_globals->dso_handle,errorbuf,ERRORBUF_SZ));
             exit(1);   
         }
 
+        rv = apr_dso_sym(&func,module_globals->dso_handle,"Rivet_MPM_MasterInterp");
+        if (rv == APR_SUCCESS)
+        {
+            module_globals->mpm_master_interp = (vhost_interp* (*)(apr_pool_t *)) func;
+        }
+        else
+        {
+            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
+                         MODNAME ": Error loading symbol Rivet_MPM_MasterInterp: %s", 
+                         apr_dso_error(module_globals->dso_handle,errorbuf,ERRORBUF_SZ));
+            exit(1);   
+        }
+
         /* active threads count */
         
         apr_atomic_init(pPool);
@@ -924,21 +1143,27 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         apr_atomic_set32(module_globals->threads_count,0);
 
         module_globals->rivet_panic_pool        = pPool;
-        module_globals->rivet_panic_server_rec  = s;
+        module_globals->rivet_panic_server_rec  = server;
         module_globals->rivet_panic_request_rec = NULL;
         module_globals->vhosts_count            = 0;
         module_globals->server_shutdown         = 0;
         module_globals->exiting                 = NULL;
-        //module_globals->server                = s;
 
-        (*module_globals->mpm_server_init)(pPool,pLog,pTemp,s);
+    /* Another crucial point: we are storing here in the globals a reference to the
+     * root server_rec object from which threads are supposed to derive 
+     * all the other chain of virtual hosts server records
+     */
+
+        module_globals->server = server;
+
+        (*module_globals->mpm_server_init)(pPool,pLog,pTemp,server);
     }
     else
     {
 
         /* If we don't find the mpm handler module we give up and exit */
 
-        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s, 
+        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
                      MODNAME " Error loading MPM manager: %s", 
                      apr_dso_error(module_globals->dso_handle,errorbuf,1024));
         exit(1);   
@@ -953,18 +1178,19 @@ static void Rivet_ChildInit (apr_pool_t 
     rivet_server_conf*  root_server_conf;
     server_rec*         s;
 
-    apr_thread_mutex_create(&module_globals->pool_mutex, APR_THREAD_MUTEX_UNNESTED, pChild);
+/* This code is run once per child process. In a threaded Tcl builds the forking 
+ * of a child process most likely has not preserved the thread where the Tcl 
+ * notifier runs. The Notifier should have been restarted by one the 
+ * pthread_atfork callbacks (setup in Tcl >= 8.5.14 and Tcl >= 8.6.1). In
+ * case pthread_atfork is not supported we unconditionally call Tcl_InitNotifier
+ * hoping for the best (Bug #55153)      
+ */
 
-    /* Creating the module global pool */
+#if !defined(HAVE_PTHREAD_ATFORK)
+    Tcl_InitNotifier();
+#endif
 
-    apr_thread_mutex_lock(module_globals->pool_mutex);
-    if (apr_pool_create(&module_globals->pool, NULL) != APR_SUCCESS) 
-    {
-        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
-                     MODNAME ": could not initialize mod_rivet private pool");
-        exit(1);
-    }
-    apr_thread_mutex_unlock(module_globals->pool_mutex);
+    apr_thread_mutex_create(&module_globals->pool_mutex, APR_THREAD_MUTEX_UNNESTED, pChild);
 
     /* Once we have established a pool with the same lifetime of the child process we
      * process all the configured server records assigning an integer as unique key 
@@ -993,12 +1219,7 @@ static void Rivet_ChildInit (apr_pool_t 
     }
     module_globals->vhosts_count = idx;
 
-    /* Another crucial point: we are storing here in the globals a reference to the
-     * root server_rec object from which threads are supposed to derive 
-     * all the other chain of virtual hosts server records
-     */
-
-    module_globals->server = server;
+    apr_threadkey_private_create (&rivet_thread_key, NULL, pChild);
 
     /* Calling the brigde child process initialization */
 

Modified: tcl/rivet/trunk/src/experimental/mod_rivet.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/mod_rivet.h?rev=1617763&r1=1617762&r2=1617763&view=diff
==============================================================================
--- tcl/rivet/trunk/src/experimental/mod_rivet.h (original)
+++ tcl/rivet/trunk/src/experimental/mod_rivet.h Wed Aug 13 16:56:13 2014
@@ -82,7 +82,7 @@ module AP_MODULE_DECLARE_DATA rivet_modu
 
 typedef struct _rivet_server_conf {
     /* we must keep this for compatibility with the module in apache-2 and stuff in common */
-    Tcl_Interp *server_interp;          /* per server Tcl interpreter 	   */
+    //Tcl_Interp *server_interp;          /* per server Tcl interpreter 	   */
 
     Tcl_Obj *rivet_server_init_script;  /* run before children are forked  */
     Tcl_Obj *rivet_global_init_script;	/* run once when apache is started */
@@ -99,8 +99,9 @@ typedef struct _rivet_server_conf {
     int user_scripts_updated;
 
     Tcl_Obj*        rivet_default_error_script;    /* for errors */
-    int*            cache_size;
-    int*            cache_free;
+    int             default_cache_size;
+    //int*            cache_size;
+    //int*            cache_free;
     int             upload_max;
     int             upload_files_to_var;
     int             separate_virtual_interps;
@@ -110,17 +111,17 @@ typedef struct _rivet_server_conf {
     apr_table_t*    rivet_server_vars;
     apr_table_t*    rivet_dir_vars;
     apr_table_t*    rivet_user_vars;
-    char**          objCacheList;		/* Array of cached objects (for priority handling)  */
-    Tcl_HashTable*  objCache;		    /* Objects cache - the key is the script name       */
+    //char**          objCacheList;		/* Array of cached objects (for priority handling)  */
+    //Tcl_HashTable*  objCache;		    /* Objects cache - the key is the script name       */
     /* this one must go, we keep just to avoid to duplicate the config handling function just
        to avoid to poke stuff into this field */
-    Tcl_Channel*    outchannel;		    /* stuff for buffering output                       */
+    //Tcl_Channel*    outchannel;		    /* stuff for buffering output                       */
 
     int             idx;                /* server record index (to be used for the interps db */
 
 } rivet_server_conf;
 
-#define TCL_INTERPS 1
+#define TCL_INTERPS 4
 typedef int rivet_thr_status;
 enum
 {
@@ -130,6 +131,21 @@ enum
     done
 };
 
+/* thread private interpreter error flags */
+
+#define RIVET_CACHE_FULL            1
+#define RIVET_INTERP_INITIALIZED    2
+
+typedef struct _vhost_interp {
+    Tcl_Interp*         interp;
+    int                 cache_size;
+    int                 cache_free;
+    Tcl_HashTable*      objCache;		    /* Objects cache - the key is the script name       */
+    char**              objCacheList;		/* Array of cached objects (for priority handling)  */
+    apr_pool_t*         pool;               /* interpreters cache private memory pool           */
+    unsigned int        flags;
+} vhost_interp;
+
 /* we need also a place where to store module wide globals */
 
 typedef struct _mod_rivet_globals {
@@ -137,6 +153,7 @@ typedef struct _mod_rivet_globals {
     apr_thread_t*       supervisor;
     int                 server_shutdown;
     int                 vhosts_count;
+    vhost_interp*       server_interp;      /* server init and prefork MPM master interpreter */
 
     apr_thread_cond_t*  job_cond;
     apr_thread_mutex_t* job_mutex;
@@ -149,32 +166,19 @@ typedef struct _mod_rivet_globals {
     apr_thread_t*       workers[TCL_INTERPS]; /* thread pool ids          */
 
     server_rec*         server;             /* default host server_rec obj */
-    Tcl_Channel*        outchannel;         /* this is the Rivet channel for prefork MPM */
+    //Tcl_Channel*      outchannel;         /* this is the Rivet channel for prefork MPM */
 
     int                 (*mpm_child_init)(apr_pool_t* pPool,server_rec* s);
     int                 (*mpm_request)(request_rec*);
     int                 (*mpm_server_init)(apr_pool_t*,apr_pool_t*,apr_pool_t*,server_rec*);
     apr_status_t        (*mpm_finalize)(void*);
+    vhost_interp*       (*mpm_master_interp)(apr_pool_t *);
 
     request_rec*        rivet_panic_request_rec;
     apr_pool_t*         rivet_panic_pool;
     server_rec*         rivet_panic_server_rec;
 } mod_rivet_globals;
 
-/* thread private interpreter error flags */
-
-#define RIVET_CACHE_FULL    1
-
-typedef struct _vhost_interp {
-    Tcl_Interp*         interp;
-    int                 cache_size;
-    int                 cache_free;
-    Tcl_HashTable*      objCache;		    /* Objects cache - the key is the script name       */
-    char**              objCacheList;		/* Array of cached objects (for priority handling)  */
-    apr_pool_t*         pool;               /* interpreters cache private memory pool           */
-    unsigned int        flags;
-} vhost_interp;
-
 
 typedef struct _thread_worker_private {
     vhost_interp**      interps;        /* database of virtual host interps     */

Added: tcl/rivet/trunk/src/experimental/mod_rivet_common.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/mod_rivet_common.c?rev=1617763&view=auto
==============================================================================
--- tcl/rivet/trunk/src/experimental/mod_rivet_common.c (added)
+++ tcl/rivet/trunk/src/experimental/mod_rivet_common.c Wed Aug 13 16:56:13 2014
@@ -0,0 +1,295 @@
+/*
+    mod_rivet_common.c - functions likely to be shared among 
+    different versions of mod_rivet.c 
+
+    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.
+*/
+
+/* $Id: mod_rivet.c 1609472 2014-07-10 15:08:52Z mxmanghi $ */
+
+#include <httpd.h>
+#include <apr_strings.h>
+#include <ap_mpm.h>
+/* as long as we need to emulate ap_chdir_file we need to include unistd.h */
+#include <unistd.h>
+
+#include "mod_rivet.h"
+#include "mod_rivet_common.h"
+#include "TclWeb.h"
+#include "rivetParser.h"
+#include "rivet.h"
+#include "apache_config.h"
+
+extern mod_rivet_globals* module_globals;
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Rivet_PanicProc --
+ *
+ *  Called when Tcl panics, usually because of memory problems.
+ *  We log the request, in order to be able to determine what went
+ *  wrong later.
+ *
+ * Results:
+ *  None.
+ *
+ * Side Effects:
+ *  Calls abort(), which does not return - the child exits.
+ *
+ *-----------------------------------------------------------------------------
+ */
+void Rivet_Panic TCL_VARARGS_DEF(CONST char *, arg1)
+{
+    va_list argList;
+    char *buf;
+    char *format;
+
+    format = (char *) TCL_VARARGS_START(char *,arg1,argList);
+    buf    = (char *) apr_pvsprintf(module_globals->rivet_panic_pool, format, argList);
+
+    if (module_globals->rivet_panic_request_rec != NULL) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, APR_EGENERAL, 
+                     module_globals->rivet_panic_server_rec,
+                     MODNAME ": Critical error in request: %s", 
+                     module_globals->rivet_panic_request_rec->unparsed_uri);
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_CRIT, APR_EGENERAL, 
+                 module_globals->rivet_panic_server_rec, "%s", buf);
+
+    abort();
+}
+
+/*
+ * -- Rivet_CleanupRequest
+ *
+ * This function contained some come that cleaned up
+ * the user configuration before finishing a request
+ * processing. That code had been disabled and it's now
+ * removed, but we leave the function as a placeholder
+ * in case we want to stick into it something to do.
+ *
+ *  Arguments:
+ *
+ *      request_rec*    request object pointer
+ *
+ *  Returned value:
+ *
+ *      None
+ */
+
+void Rivet_CleanupRequest( request_rec *r )
+{
+}
+
+/*
+ * -- Rivet_InitServerVariables
+ *
+ * Setup an array in each interpreter to tell us things about Apache.
+ * This saves us from having to do any real call to load an entire
+ * environment.  This routine only gets called once, when the child process
+ * is created.
+ *
+ *  Arguments:
+ *
+ *      Tcl_Interp* interp: pointer to the Tcl interpreter
+ *      apr_pool_t* pool: pool used for calling Apache framework functions
+ *
+ * Returned value:
+ *      none
+ *
+ * Side effects:
+ *
+ *      within the global scope of the interpreter passed as first
+ *      argument a 'server' array is created and the variable associated
+ *      to the following keys are defined
+ *
+ *          SERVER_ROOT - Apache's root location
+ *          SERVER_CONF - Apache's configuration file
+ *          RIVET_DIR   - Rivet's Tcl source directory
+ *          RIVET_INIT  - Rivet's init.tcl file
+ *          RIVET_VERSION - Rivet version (only when RIVET_DISPLAY_VERSION is 1)
+ *          MPM_THREADED - It should contain the string 'unsupported' for a prefork MPM
+ *          MPM_FORKED - String describing the forking model of the MPM 
+ *
+ */
+
+void Rivet_InitServerVariables( Tcl_Interp *interp, apr_pool_t *pool )
+{
+    int     ap_mpm_result;
+    Tcl_Obj *obj;
+
+    obj = Tcl_NewStringObj(ap_server_root, -1);
+    Tcl_IncrRefCount(obj);
+    Tcl_SetVar2Ex(interp,
+            "server",
+            "SERVER_ROOT",
+            obj,
+            TCL_GLOBAL_ONLY);
+    Tcl_DecrRefCount(obj);
+
+    obj = Tcl_NewStringObj(ap_server_root_relative(pool,SERVER_CONFIG_FILE), -1);
+    Tcl_IncrRefCount(obj);
+    Tcl_SetVar2Ex(interp,
+            "server",
+            "SERVER_CONF",
+            obj,
+            TCL_GLOBAL_ONLY);
+    Tcl_DecrRefCount(obj);
+
+    obj = Tcl_NewStringObj(ap_server_root_relative(pool, RIVET_DIR), -1);
+    Tcl_IncrRefCount(obj);
+    Tcl_SetVar2Ex(interp,
+            "server",
+            "RIVET_DIR",
+            obj,
+            TCL_GLOBAL_ONLY);
+    Tcl_DecrRefCount(obj);
+
+    obj = Tcl_NewStringObj(ap_server_root_relative(pool, RIVET_INIT), -1);
+    Tcl_IncrRefCount(obj);
+    Tcl_SetVar2Ex(interp,
+            "server",
+            "RIVET_INIT",
+            obj,
+            TCL_GLOBAL_ONLY);
+    Tcl_DecrRefCount(obj);
+
+#if RIVET_DISPLAY_VERSION
+    obj = Tcl_NewStringObj(RIVET_VERSION, -1);
+    Tcl_IncrRefCount(obj);
+    Tcl_SetVar2Ex(interp,
+            "server",
+            "RIVET_VERSION",
+            obj,
+            TCL_GLOBAL_ONLY);
+    Tcl_DecrRefCount(obj);
+#endif
+
+    if (ap_mpm_query(AP_MPMQ_IS_THREADED,&ap_mpm_result) == APR_SUCCESS)
+    {
+        switch (ap_mpm_result) 
+        {
+            case AP_MPMQ_STATIC:
+                obj = Tcl_NewStringObj("static", -1);
+                break;
+            case AP_MPMQ_NOT_SUPPORTED:
+                obj = Tcl_NewStringObj("unsupported", -1);
+                break;
+            default: 
+                obj = Tcl_NewStringObj("undefined", -1);
+                break;
+        }
+        Tcl_IncrRefCount(obj);
+        Tcl_SetVar2Ex(interp,"server","MPM_THREADED",obj,TCL_GLOBAL_ONLY);
+        Tcl_DecrRefCount(obj);
+    }
+
+    if (ap_mpm_query(AP_MPMQ_IS_FORKED,&ap_mpm_result) == APR_SUCCESS)
+    {
+        switch (ap_mpm_result) 
+        {
+            case AP_MPMQ_STATIC:
+                obj = Tcl_NewStringObj("static", -1);
+                break;
+            case AP_MPMQ_DYNAMIC:
+                obj = Tcl_NewStringObj("dynamic", -1);
+                break;
+            default: 
+                obj = Tcl_NewStringObj("undefined", -1);
+                break;
+        }
+        Tcl_IncrRefCount(obj);
+        Tcl_SetVar2Ex(interp,"server","MPM_FORKED",obj,TCL_GLOBAL_ONLY);
+        Tcl_DecrRefCount(obj);
+    }
+}
+
+/*
+ * -- Rivet_chdir_file (const char* filename)
+ * 
+ * Determines the directory name from the filename argument
+ * and sets it as current working directory
+ *
+ * Argument:
+ * 
+ *   const char* filename:  file name to be used for determining
+ *                          the current directory (URI style path)
+ *                          the directory name is everything comes
+ *                          before the last '/' (slash) character
+ *
+ * This snippet of code came from the mod_ruby project, which is under a BSD license.
+ */
+ 
+int Rivet_chdir_file (const char *file)
+{
+    const char  *x;
+    int         chdir_retval = 0;
+    char        chdir_buf[HUGE_STRING_LEN];
+
+    x = strrchr(file, '/');
+    if (x == NULL) {
+        chdir_retval = chdir(file);
+    } else if (x - file < sizeof(chdir_buf) - 1) {
+        memcpy(chdir_buf, file, x - file);
+        chdir_buf[x - file] = '\0';
+        chdir_retval = chdir(chdir_buf);
+    }
+        
+    return chdir_retval;
+}
+/* 
+ * -- Rivet_CheckType (request_rec *r)
+ *
+ * Utility function internally used to determine which type
+ * of file (whether rvt template or plain Tcl script) we are
+ * dealing with. In order to speed up multiple tests the
+ * the test returns an integer (RIVET_TEMPLATE) for rvt templates
+ * or RIVET_TCLFILE for Tcl scripts
+ *
+ * Argument: 
+ *
+ *    request_rec*: pointer to the current request record
+ *
+ * Returns:
+ *
+ *    integer number meaning the type of file we are dealing with
+ *
+ * Side effects:
+ *
+ *    none.
+ *
+ */
+
+int
+Rivet_CheckType (request_rec *req)
+{
+    int ctype = CTYPE_NOT_HANDLED;
+
+    if ( req->content_type != NULL ) {
+        if( STRNEQU( req->content_type, RIVET_TEMPLATE_CTYPE) ) {
+            ctype  = RIVET_TEMPLATE;
+        } else if( STRNEQU( req->content_type, RIVET_TCLFILE_CTYPE) ) {
+            ctype = RIVET_TCLFILE;
+        } 
+    }
+    return ctype; 
+}
+
+

Added: tcl/rivet/trunk/src/experimental/mod_rivet_common.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/experimental/mod_rivet_common.h?rev=1617763&view=auto
==============================================================================
--- tcl/rivet/trunk/src/experimental/mod_rivet_common.h (added)
+++ tcl/rivet/trunk/src/experimental/mod_rivet_common.h Wed Aug 13 16:56:13 2014
@@ -0,0 +1,30 @@
+
+/*
+    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.
+*/
+
+#ifndef _MOD_RIVET_COMMON_
+#define _MOD_RIVET_COMMON_
+
+EXTERN int Rivet_chdir_file (const char *file);
+EXTERN int Rivet_CheckType (request_rec* r);
+EXTERN void Rivet_CleanupRequest(request_rec *r);
+EXTERN void Rivet_InitServerVariables(Tcl_Interp *interp, apr_pool_t *pool);
+EXTERN void Rivet_Panic TCL_VARARGS_DEF(CONST char *, arg1);
+
+#endif



---------------------------------------------------------------------
To unsubscribe, e-mail: site-cvs-unsubscribe@tcl.apache.org
For additional commands, e-mail: site-cvs-help@tcl.apache.org