1 /* mod_rivet.h -- The apache module itself, for Apache 2.4. */
2 
3 /*
4     Licensed to the Apache Software Foundation (ASF) under one
5     or more contributor license agreements.  See the NOTICE file
6     distributed with this work for additional information
7     regarding copyright ownership.  The ASF licenses this file
8     to you under the Apache License, Version 2.0 (the
9     "License"); you may not use this file except in compliance
10     with the License.  You may obtain a copy of the License at
11 
12       http://www.apache.org/licenses/LICENSE-2.0
13 
14     Unless required by applicable law or agreed to in writing,
15     software distributed under the License is distributed on an
16     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17     KIND, either express or implied.  See the License for the
18     specific language governing permissions and limitations
19     under the License.
20 */
21 
22 #ifndef __mod_rivet_h__
23 #define __mod_rivet_h__
24 
25 #include <apr_queue.h>
26 #include <apr_tables.h>
27 #include <apr_thread_proc.h>
28 #include <apr_thread_cond.h>
29 #include <tcl.h>
30 #include "rivet.h"
31 #include "apache_request.h"
32 
33 /* Rivet config */
34 #ifdef HAVE_CONFIG_H
35 #include <rivet_config.h>
36 #endif
37 
38 /*
39  * Petasis 16 Dec 2018: This causes the symbol to be exported also from MPMs...
40  *
41  * APLOG_USE_MODULE(rivet);
42  *
43  *  PLEASE: do not use any of APLOG_USE_MODULE, AP_DECLARE_MODULE,
44  *  AP_MODULE_DECLARE_DATA in this header file!
45  *
46  */
47 
48 /* init.tcl file relative to the server root directory */
49 
50 #define RIVET_DIR  RIVET_RIVETLIB_DESTDIR
51 #define RIVET_INIT RIVET_RIVETLIB_DESTDIR"/init.tcl"
52 
53 #if 0
54 #define FILEDEBUGINFO fprintf(stderr, "Function " __FUNCTION__ "\n")
55 #else
56 #define FILEDEBUGINFO
57 #endif
58 
59 /* Configuration options  */
60 
61 /*
62    If you do not have a threaded Tcl, you can define this to 0.  This
63    has the effect of running Tcl Init code in the main parent init
64    handler, instead of in child init handlers.
65  */
66 #ifdef __MINGW32__
67 #define THREADED_TCL 1
68 #else
69 #define THREADED_TCL 0 /* Unless you have MINGW32, modify this one! */
70 #endif
71 
72 /* End Configuration options  */
73 
74 #define VAR_SRC_QUERYSTRING 1
75 #define VAR_SRC_POST 		2
76 #define VAR_SRC_ALL 		3
77 
78 #define DEFAULT_ERROR_MSG 	"[an error occurred while processing this directive]"
79 #define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
80 #define MULTIPART_FORM_DATA 1
81 
82 #define USER_SCRIPTS_UPDATED 1
83 #define USER_SCRIPTS_CONF    1<<1
84 #define USER_SCRIPTS_MERGED  1<<2
85 
86 #define IS_USER_CONF(mc)        ((mc->user_scripts_status & USER_SCRIPTS_CONF) != 0)
87 #define USER_CONF_UPDATED(mc)   ((mc->user_scripts_status & USER_SCRIPTS_UPDATED) != 0)
88 #define USER_CONF_MERGED(mc)    ((mc->user_scripts_status & USER_SCRIPTS_MERGED) != 0)
89 
90 /* IMPORTANT: If you make any changes to the rivet_server_conf struct,
91  * you need to make the appropriate modifications to Rivet_CopyConfig,
92  * Rivet_CreateConfig, Rivet_MergeConfig and so on. */
93 
94 /*
95  * Petasis 10 Aug 2017: This causes the symbol to be exported also from MPMs...
96  *
97  *  module AP_MODULE_DECLARE_DATA rivet_module;
98  *
99  */
100 
101 typedef struct _rivet_server_conf {
102 
103     char*       rivet_global_init_script;   /* run once when apache is started */
104     char*       rivet_child_init_script;
105     char*       rivet_child_exit_script;
106     char*       request_handler;            /* request handler script           */
107     char*       rivet_error_script;         /*            for errors            */
108     char*       rivet_abort_script;         /* script run upon abort_page call  */
109     char*       after_every_script;         /* script to be always run          */
110 
111     /* these scripts are kept for compatibility. They may disappear in future versions */
112 
113     char*       rivet_before_script;        /* script run before each page      */
114     char*       rivet_after_script;         /*            after                 */
115 
116     /* --------------------------------------------------------------------------- */
117 
118     /* This flag is used with the above directives. If any of them have changed, it gets set. */
119 
120     unsigned int user_scripts_status;
121 
122     int          default_cache_size;
123     int          upload_max;
124     int          upload_files_to_var;
125     int          honor_header_only_reqs;
126 
127     int          export_rivet_ns;        /* export the ::rivet namespace commands        */
128     int          import_rivet_ns;        /* import into the global namespace the
129                                             exported ::rivet commands                    */
130     char*        server_name;
131     const char*  upload_dir;
132     apr_table_t* rivet_server_vars;
133     apr_table_t* rivet_dir_vars;
134     apr_table_t* rivet_user_vars;
135     int          idx;                   /* server record index (to be used for the interps db)    */
136     char*        path;                  /* copy of the path field of a cmd_parms structure:       *
137                                          * should enable us to tell if a conf record comes from a *
138                                          * Directory section                                      */
139 } rivet_server_conf;
140 
141 #define TCL_INTERPS 1
142 
143 /* thread private interpreter error flags */
144 
145 #define RIVET_CACHE_FULL            1
146 #define RIVET_INTERP_INITIALIZED    2
147 
148 typedef struct _interp_running_scripts {
149     Tcl_Obj*    request_processing;         /* request processing central procedure             */
150     Tcl_Obj*    rivet_before_script;        /* script run before each page                      */
151     Tcl_Obj*    rivet_after_script;         /*            after                                 */
152     Tcl_Obj*    rivet_error_script;
153     Tcl_Obj*    rivet_abort_script;
154     Tcl_Obj*    after_every_script;
155 } running_scripts;
156 
157 typedef struct _rivet_thread_interp {
158     Tcl_Interp*         interp;
159     Tcl_Channel*        channel;            /* the Tcl interp private channel                   */
160     int                 cache_size;
161     int                 cache_free;
162     Tcl_HashTable*      objCache;           /* Objects cache - the key is the script name       */
163     char**              objCacheList;       /* Array of cached objects (for priority handling)  */
164     apr_pool_t*         pool;               /* interpreters cache private memory pool           */
165     running_scripts*    scripts;            /* base server conf scripts                         */
166     apr_hash_t*         per_dir_scripts;    /* per dir running scripts                          */
167     unsigned int        flags;              /* signals of various interp specific conditions    */
168 } rivet_thread_interp;
169 
170 typedef struct _thread_worker_private rivet_thread_private;
171 
172 typedef int                     (RivetBridge_ServerInit)    (apr_pool_t*,apr_pool_t*,apr_pool_t*,server_rec*);
173 typedef void                    (RivetBridge_ThreadInit)    (apr_pool_t* pPool,server_rec* s);
174 typedef int                     (RivetBridge_Request)       (request_rec*,rivet_req_ctype);
175 typedef apr_status_t            (RivetBridge_Finalize)      (void*);
176 typedef rivet_thread_interp*    (RivetBridge_Master_Interp) (void);
177 typedef int                     (RivetBridge_Exit_Handler)  (rivet_thread_private*);
178 typedef rivet_thread_interp*    (RivetBridge_Thread_Interp) (rivet_thread_private*,rivet_server_conf *,rivet_thread_interp*);
179 
180 typedef struct _mpm_bridge_table {
181     RivetBridge_ServerInit    *server_init;
182     RivetBridge_ThreadInit    *thread_init;
183     RivetBridge_Request       *request_processor;
184     RivetBridge_Finalize      *child_finalize;
185     RivetBridge_Exit_Handler  *exit_handler;
186     RivetBridge_Thread_Interp *thread_interp;
187 } rivet_bridge_table;
188 
189 /* we need also a place where to store globals with module wide scope */
190 
191 typedef struct mpm_bridge_status mpm_bridge_status;
192 
193 typedef struct _mod_rivet_globals {
194     apr_pool_t*         pool;
195     char*               rivet_mpm_bridge;       /* name of the MPM bridge                   */
196     server_rec*         server;                 /* default host server_rec obj              */
197     int                 vhosts_count;           /* Number of configured virtual host including   *
198                                                  * the root server thus it's supposed to be >= 1 */
199     char*				default_handler;		/* Default request handler code             */
200     int					default_handler_size;	/* Size of the default_handler buffer       */
201     rivet_thread_interp*
202                         server_interp;          /* server and prefork MPM interpreter       */
203     apr_thread_mutex_t* pool_mutex;             /* threads commmon pool mutex               */
204     rivet_bridge_table* bridge_jump_table;      /* Jump table to bridge specific procedures */
205     const char*         rivet_server_init_script; /* run before children are forked         */
206     const char*         mpm_bridge;             /* MPM bridge. if not null the module will  */
207                                                 /* try to load the file name in this field. */
208                                                 /* The string should be either a full       */
209                                                 /* path to a file name, or a string from    */
210                                                 /* which a file name will be composed using */
211                                                 /* the pattern 'rivet_(mpm_bridge)_mpm.so   */
212     mpm_bridge_status*  mpm;                    /* bridge private control structure         */
213     int                 single_thread_exit;     /* With a threaded bridge allow a single    */
214                                                 /* thread to exit instead of forcing the    */
215                                                 /* whole process to terminate               */
216     int                 separate_virtual_interps;
217                                                 /* Virtual host have their own interpreter  */
218     int                 separate_channels;      /* when true a vhosts get their private channel */
219 #ifdef RIVET_SERIALIZE_HTTP_REQUESTS
220     apr_thread_mutex_t* req_mutex;
221 #endif
222 } mod_rivet_globals;
223 
224 typedef struct mpm_bridge_specific mpm_bridge_specific;
225 
226 typedef struct _thread_worker_private {
227     apr_pool_t*         pool;               /* threads private memory pool          */
228     Tcl_Channel*        channel;            /* the Tcl thread private channel       */
229     int                 req_cnt;            /* requests served by thread            */
230     rivet_req_ctype     ctype;              /*                                      */
231     request_rec*        r;                  /* current request_rec                  */
232     TclWebRequest*      req;
233     rivet_server_conf*  running_conf;       /* running configuration                */
234     running_scripts*    running;            /* (per request) running conf scripts   */
235     int                 thread_exit;        /* Thread exit code                     */
236     int                 exit_status;        /* status code to be passed to exit()   */
237     int                 page_aborting;      /* abort_page flag                      */
238     Tcl_Obj*            abort_code;         /* To be reset by before request        *
239                                              * processing completes                 */
240     Tcl_Obj*            default_error_script; /* mod_rivet default error handler    */
241     request_rec*        rivet_panic_request_rec;
242     apr_pool_t*         rivet_panic_pool;
243     server_rec*         rivet_panic_server_rec;
244 
245     mpm_bridge_specific* ext;               /* bridge specific extension            */
246 } rivet_thread_private;
247 
248 /* eventually we will transfer 'global' variables in here and 'de-globalize' them */
249 
250 typedef struct _rivet_interp_globals {
251     Tcl_Namespace*      rivet_ns;           /* Rivet commands namespace             */
252 } rivet_interp_globals;
253 
254 rivet_server_conf *Rivet_GetConf(request_rec *r);
255 
256 /*
257  * Petasis, 04/08/2017: I think the following is wrong, as both "functions" are
258  * defined through preprocessor definitions in http_config.h. At least under
259  * windows, they do not exist as functions in libhttpd.lib.
260  *
261 #ifdef ap_get_module_config
262 #undef ap_get_module_config
263 #endif
264 #ifdef ap_set_module_config
265 #undef ap_set_module_config
266 #endif
267 */
268 
269 #define RIVET_SERVER_CONF(module) (rivet_server_conf *)ap_get_module_config(module, &rivet_module)
270 #define RIVET_NEW_CONF(p)         (rivet_server_conf *)apr_pcalloc(p, sizeof(rivet_server_conf))
271 
272 Tcl_Obj* Rivet_BuildConfDictionary (Tcl_Interp* interp,rivet_server_conf* rivet_conf);
273 Tcl_Obj* Rivet_ReadConfParameter (Tcl_Interp* interp,rivet_server_conf* rivet_conf,Tcl_Obj* par_name);
274 Tcl_Obj* Rivet_CurrentConfDict (Tcl_Interp* interp,rivet_server_conf* rivet_conf);
275 Tcl_Obj* Rivet_CurrentServerRec (Tcl_Interp* interp, server_rec* s);
276 
277 /* rivet or tcl file */
278 
279 #define RIVET_TEMPLATE_CTYPE    "application/x-httpd-rivet"
280 #define RIVET_TCLFILE_CTYPE     "application/x-rivet-tcl"
281 
282 #define CTYPE_NOT_HANDLED   0
283 #define RIVET_TEMPLATE      1
284 #define RIVET_TCLFILE       2
285 
286 /* these three must go in their own file */
287 
288 /* temporary content generation handler */
289 //EXTERN int RivetContent (rivet_thread_private* private);
290 
291 /* error code set by command 'abort_page' */
292 
293 #define ABORTPAGE_CODE              "ABORTPAGE"
294 #define THREAD_EXIT_CODE            "THREAD_EXIT"
295 
296 /* Configuration defaults */
297 
298 #define SINGLE_THREAD_EXIT_UNDEF   -1    /* pre config undefined value for single
299                                             thread exit flag in the module globals
300                                             structure */
301 
302 #define TCL_MAX_CHANNEL_BUFFER_SIZE (1024*1024)
303 #define MODNAME                     "mod_rivet"
304 
305 /*
306  * RIVET_CONF_SELECT:
307  *
308  * This macro avoids unnecessary verbosity of repetitive code in functions
309  * overlaying and merging configuration records
310  */
311 
312 #define RIVET_CONF_SELECT(selected,base,overlay,field) \
313     selected->field = overlay->field ? overlay->field : base->field;
314 
315 #define RIVET_CR_TERM(pool,string)  apr_pstrcat(pool,string,"\n",NULL)
316 
317 #define RIVET_SCRIPT_INIT(p,running_script,rivet_conf_rec,objscript) \
318     if (rivet_conf_rec->objscript == NULL) {\
319         running_script->objscript = NULL;\
320     } else {\
321         running_script->objscript = Tcl_NewStringObj(RIVET_CR_TERM(p,rivet_conf_rec->objscript),-1);\
322         Tcl_IncrRefCount(running_script->objscript);\
323     }
324 
325 #define RIVET_SCRIPT_DISPOSE(running_scripts,script_name) \
326     if (running_scripts->script_name != NULL) {\
327         Tcl_DecrRefCount(running_scripts->script_name);\
328     }
329 
330 #define RIVET_MPM_BRIDGE_TABLE         bridge_jump_table
331 #define RIVET_MPM_BRIDGE_FUNCTION(fun) module_globals->bridge_jump_table->fun
332 
333 #define RIVET_MPM_BRIDGE_CALL(fun,...) if ((*module_globals->bridge_jump_table->fun) != NULL) {\
334     (*module_globals->bridge_jump_table->fun)(__VA_ARGS__);\
335 }
336 
337 #define RIVET_PEEK_INTERP(thread_private,running_conf) \
338         (module_globals->bridge_jump_table->thread_interp)(thread_private,running_conf,NULL)
339 
340 #define RIVET_POKE_INTERP(thread_private,running_conf,interp) \
341         (module_globals->bridge_jump_table->thread_interp)(thread_private,running_conf,interp)
342 
343 #define RIVET_MPM_BRIDGE rivet_bridge_table bridge_jump_table =
344 
345 #define RIVET_MPM_BRIDGE_COMPOSE(bridge) RIVET_DIR,"/mpm/rivet_",bridge,"_mpm.so"
346 
347 #endif /* MOD_RIVET_H */
348