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