"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 ** mod_trigger.c -- Fire off triggers for events
3 ** -Brian (brian@tangent.org)
4 */
5
6 #include "httpd.h"
7 #include "http_config.h"
8 #include "http_protocol.h"
9 #include "ap_config.h"
10 #include "fnmatch.h"
11 #include "http_log.h"
12
13 /* Strings for help */
14 #define TriggerEngine "On or Off (Off by default). This enables the trigger engine."
15 #define TriggerLog "Triggers will send a log message to the error log when found."
16 #define TriggerHandler "Supply a handler and then either a script or uri to call if the handler is found."
17 #define TriggerURI "Supply a URI and then either a script or uri to call if the URI is found."
18 #define TriggerAgent "Supply a browser agent and then either a script or uri to call if the agent is found."
19 #define TriggerReferer "Supply a referer and then either a script or uri to call if the referer is found."
20 #define TriggerMime "Supply a mime-type and then either a script or uri to call if the mime-type is found."
21 #define TriggerAddress "Supply an IP address and then either a script or uri to call if the address is found."
22 #define TriggerUser "Supply a username (REMOTE_USER) and then either a script or uri to call if the user is found."
23 #define TriggerIdent "Supply an ident and then either a script or uri to call if the ident is found."
24 #define TriggerPathInfo "Supply a pthinfo and then either a script or uri to call if the pathinfo is found."
25 #define TriggerAccept "Supply an accept header and then either a script or uri to call if the accept header is found."
26 #define TriggerCookie "Supply a cookie name and then either a script or uri to call if the cookie is found."
27
28 #define WATCHPOINT printf("WATCHPOINT %s %d\n", __FILE__, __LINE__);
29
30 module MODULE_VAR_EXPORT trigger_module;
31
32 typedef struct {
33 int enabled;
34 int log;
35 table *handler;
36 table *uri;
37 table *agent;
38 table *referer;
39 table *mime;
40 table *address;
41 table *user;
42 table *ident;
43 table *pathinfo;
44 table *accept;
45 table *cookie;
46 table *args;
47 } trigger_conf;
48
49 static void *create_dir_mconfig(pool *p, char *dir) {
50 trigger_conf *cfg;
51 cfg = ap_pcalloc(p, sizeof(trigger_conf));
52
53 cfg->enabled=0;
54 cfg->log=0;
55 cfg->handler = NULL;
56 cfg->uri = NULL;
57 cfg->agent = NULL;
58 cfg->referer = NULL;
59 cfg->mime = NULL;
60 cfg->address = NULL;
61 cfg->user = NULL;
62 cfg->ident = NULL;
63 cfg->pathinfo = NULL;
64 cfg->accept = NULL;
65 cfg->cookie = NULL;
66 cfg->args = NULL;
67
68 return (void *) cfg;
69 }
70
71 int call_container(request_rec *r, char *uri) {
72 int status = OK;
73 request_rec *subr;
74
75 subr = (request_rec *) ap_sub_req_lookup_uri(uri, r);
76 ap_table_setn(subr->headers_in, "Content-Length", "0");
77 subr->assbackwards = 1;
78
79 ap_table_setn(subr->subprocess_env, "TRIGGER_SCRIPT_NAME", r->uri);
80 ap_table_setn(subr->subprocess_env, "TRIGGER_PATH_INFO", r->path_info);
81 ap_table_setn(subr->subprocess_env, "TRIGGER_QUERY_STRING", r->args);
82 ap_table_setn(subr->subprocess_env, "TRIGGER_FILENAME", r->filename);
83 subr->args = r->args;
84
85 status = ap_run_sub_req(subr);
86 ap_destroy_sub_req(subr);
87
88 return status;
89 }
90
91 static int call_program(void *rp, child_info *pinfo) {
92 char **env;
93 request_rec *r = (request_rec *)rp;
94
95 ap_add_cgi_vars(r);
96 env = (char **)ap_create_environment(r->pool, r->subprocess_env);
97 ap_error_log2stderr(r->server);
98 ap_cleanup_for_exec();
99 (void)ap_call_exec(r, pinfo, r->filename, env, 0);
100 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "exec for %s failed", r->filename);
101 exit(0);
102 return 0;
103 }
104
105 static void execute(request_rec *r, char *string) {
106 int status = OK;
107 struct stat sbuf;
108 char *temp = NULL;
109 BUFF *pipe;
110
111 /* Ok, reality? We should set this up to determine
112 this ahead of time.
113 */
114 ap_table_setn(r->subprocess_env, "TRIGGER_SCRIPT_NAME", r->uri);
115 ap_table_setn(r->subprocess_env, "TRIGGER_PATH_INFO", r->path_info);
116 ap_table_setn(r->subprocess_env, "TRIGGER_QUERY_STRING", r->args);
117 ap_table_setn(r->subprocess_env, "TRIGGER_FILENAME", r->filename);
118 if(!stat(string, &sbuf)) {
119 temp = r->filename;
120 r->filename = string;
121 if(!ap_bspawn_child(r->pool, call_program,
122 (void *) r, kill_after_timeout,
123 NULL, &pipe, NULL)) {
124 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
125 "could not spawn: %s", string);
126 }
127 r->filename = temp;
128 } else {
129 if ((status = call_container(r, string)) != OK) {
130 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
131 "The following error occured while processing the Triger : %s : %d", string, status);
132 }
133 }
134
135 }
136
137 void table_execute(request_rec *r, const table *t, const char *key, int log) {
138 array_header *hdrs_arr;
139 table_entry *elts;
140 int x = 0;
141
142 if (key == NULL)
143 return;
144 if (t == NULL)
145 return;
146
147 hdrs_arr = ap_table_elts(t);
148 elts = (table_entry *) hdrs_arr->elts;
149
150 for (x = 0; x < hdrs_arr->nelts; ++x) {
151 if (!ap_fnmatch(elts[x].key, key, FNM_CASE_BLIND)) {
152 execute(r, elts[x].val);
153 if(log)
154 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
155 "mod_trigger:Firing off trigger %s, for %s", elts[x].val, elts[x].key);
156 }
157 }
158
159 return;
160 }
161
162 /* Borrowed from mod_rewrite (and modified) */
163 static char *lookup_header(request_rec *r, const char *name) {
164 array_header *hdrs_arr;
165 table_entry *hdrs;
166 int i;
167
168 hdrs_arr = ap_table_elts(r->headers_in);
169 hdrs = (table_entry *)hdrs_arr->elts;
170 for (i = 0; i < hdrs_arr->nelts; ++i) {
171 if (hdrs[i].key == NULL) {
172 continue;
173 }
174 if (!strcasecmp(hdrs[i].key, name)) {
175 return hdrs[i].val;
176 }
177 }
178 return NULL;
179 }
180
181 void table_print(request_rec *r, table *t, char *caption) {
182 array_header *hdrs_arr;
183 table_entry *elts;
184 int x = 0;
185
186 if (t == NULL)
187 return;
188
189 hdrs_arr = ap_table_elts(t);
190 elts = (table_entry *) hdrs_arr->elts;
191
192 ap_rprintf(r, "Caption: %s\n", caption);
193 for (x = 0; x < hdrs_arr->nelts; ++x) {
194 ap_rprintf(r, "%s:%s\n", elts[x].key, elts[x].val);
195 }
196 }
197
198 static int trigger_handler(request_rec *r) {
199 trigger_conf *cfg;
200 cfg = ap_get_module_config(r->per_dir_config, &trigger_module);
201 r->content_type = "text/html";
202 ap_rputs(DOCTYPE_HTML_3_2
203 "<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</HEAD><BODY>\n",
204 r);
205 ap_rputs("<H1>Apache Server Status for ", r);
206 ap_rvputs(r, ap_get_server_name(r), "</H1>\n\n", NULL);
207 ap_rvputs(r, "Server Version: ",
208 ap_get_server_version(), "<br>\n", NULL);
209 ap_rvputs(r, "Server Built: ",
210 ap_get_server_built(), "<br>\n<hr>\n", NULL);
211 /*
212 ap_rvputs(r, "Current Time: ",
213 ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0), "<br>\n", NULL);
214 ap_rvputs(r, "Restart Time: ",
215 ap_ht_time(r->pool, ap_restart_time, DEFAULT_TIME_FORMAT, 0),
216 "<br>\n", NULL);
217 */
218 ap_send_http_header(r);
219 if (r->header_only)
220 return OK;
221 if(cfg->handler)
222 table_print(r, cfg->handler, "This is the default caption" );
223 if(cfg->uri)
224 table_print(r, cfg->uri, "This is the default caption" );
225 if(cfg->agent)
226 table_print(r, cfg->agent, "This is the default caption" );
227 if(cfg->referer)
228 table_print(r, cfg->referer, "This is the default caption" );
229 if(cfg->mime)
230 table_print(r, cfg->mime, "This is the default caption" );
231 if(cfg->address)
232 table_print(r, cfg->address, "This is the default caption" );
233 if(cfg->user)
234 table_print(r, cfg->user, "This is the default caption" );
235 if(cfg->ident)
236 table_print(r, cfg->ident, "This is the default caption" );
237 if(cfg->pathinfo)
238 table_print(r, cfg->pathinfo,"This is the default caption" );
239 if(cfg->accept)
240 table_print(r, cfg->accept, "This is the default caption" );
241 if(cfg->cookie)
242 table_print(r, cfg->cookie, "This is the default caption" );
243 if(cfg->args)
244 table_print(r, cfg->args, "This is the default caption" );
245 ap_rputs("</HTML>", r);
246
247 return OK;
248 }
249
250 static int trigger_log (request_rec *r) {
251 trigger_conf *cfg;
252 cfg = ap_get_module_config(r->per_dir_config, &trigger_module);
253
254 if(!cfg->enabled)
255 return DECLINED;
256
257 if(cfg->handler)
258 table_execute(r, cfg->handler, r->handler, cfg->log);
259 if(cfg->uri)
260 table_execute(r, cfg->uri, r->uri, cfg->log);
261 if(cfg->agent)
262 table_execute(r, cfg->agent, lookup_header(r, "User-Agent"), cfg->log);
263 if(cfg->referer)
264 table_execute(r, cfg->referer, lookup_header(r, "Referer"), cfg->log);
265 if(cfg->mime)
266 table_execute(r, cfg->mime, r->content_type, cfg->log);
267 if(cfg->address)
268 table_execute(r, cfg->address, r->connection->remote_ip, cfg->log);
269 if(cfg->user)
270 table_execute(r, cfg->user, r->connection->user, cfg->log);
271 if(cfg->ident)
272 table_execute(r, cfg->ident, (char *)ap_get_remote_logname(r, r), cfg->log);
273 if(cfg->pathinfo)
274 table_execute(r, cfg->pathinfo, r->path_info, cfg->log);
275 if(cfg->accept)
276 table_execute(r, cfg->accept, lookup_header(r, "Accept"), cfg->log);
277 if(cfg->cookie)
278 table_execute(r, cfg->cookie, lookup_header(r, "Cookie"), cfg->log);
279 if(cfg->args)
280 table_execute(r, cfg->args, r->args, cfg->log);
281
282 return DECLINED;
283 }
284
285 /* Dispatch list of content handlers */
286 static const handler_rec trigger_handlers[] = {
287 { "trigger-status", trigger_handler },
288 { NULL, NULL }
289 };
290
291 static const char * add_trigger (cmd_parms *cmd, void *mconfig, char *key, char *value) {
292 trigger_conf *cfg = (trigger_conf *) mconfig;
293
294 if(!strcasecmp(cmd->cmd->name, "TriggerHandler")) {
295 if(!cfg->handler)
296 cfg->handler = ap_make_table(cmd->pool, 1);
297 ap_table_set(cfg->handler, key, value);
298 } else if(!strcasecmp(cmd->cmd->name, "TriggerURI")) {
299 if(!cfg->uri)
300 cfg->uri = ap_make_table(cmd->pool, 1);
301 ap_table_set(cfg->uri, key, value);
302 } else if(!strcasecmp(cmd->cmd->name, "TriggerAgent")) {
303 if(!cfg->agent)
304 cfg->agent = ap_make_table(cmd->pool, 1);
305 ap_table_set(cfg->agent, key, value);
306 } else if(!strcasecmp(cmd->cmd->name, "TriggerReferer")) {
307 if(!cfg->referer)
308 cfg->referer = ap_make_table(cmd->pool, 1);
309 ap_table_set(cfg->referer, key, value);
310 } else if(!strcasecmp(cmd->cmd->name, "TriggerMime")) {
311 if(!cfg->mime)
312 cfg->mime = ap_make_table(cmd->pool, 1);
313 ap_table_set(cfg->mime, key, value);
314 } else if(!strcasecmp(cmd->cmd->name, "TriggerAddress")) {
315 if(!cfg->address)
316 cfg->address = ap_make_table(cmd->pool, 1);
317 ap_table_set(cfg->address, key, value);
318 } else if(!strcasecmp(cmd->cmd->name, "TriggerUser")) {
319 if(!cfg->user)
320 cfg->user = ap_make_table(cmd->pool, 1);
321 ap_table_set(cfg->user, key, value);
322 } else if(!strcasecmp(cmd->cmd->name, "TriggerIdent")) {
323 if(!cfg->ident)
324 cfg->ident = ap_make_table(cmd->pool, 1);
325 ap_table_set(cfg->ident, key, value);
326 } else if(!strcasecmp(cmd->cmd->name, "TriggerPathInfo")) {
327 if(!cfg->pathinfo)
328 cfg->pathinfo = ap_make_table(cmd->pool, 1);
329 ap_table_set(cfg->pathinfo, key, value);
330 } else if(!strcasecmp(cmd->cmd->name, "TriggerAccept")) {
331 if(!cfg->accept)
332 cfg->accept = ap_make_table(cmd->pool, 1);
333 ap_table_set(cfg->accept, key, value);
334 } else if(!strcasecmp(cmd->cmd->name, "TriggerCookie")) {
335 if(!cfg->cookie)
336 cfg->cookie = ap_make_table(cmd->pool, 1);
337 ap_table_set(cfg->cookie, key, value);
338 } else if(!strcasecmp(cmd->cmd->name, "TriggerArgs")) {
339 if(!cfg->args)
340 cfg->args = ap_make_table(cmd->pool, 1);
341 ap_table_set(cfg->args, key, value);
342 }
343
344 return NULL;
345 }
346
347 static const command_rec trigger_cmds[] = {
348
349 {"TriggerEngine", ap_set_flag_slot, (void *) XtOffsetOf(trigger_conf, enabled), OR_ALL, TAKE1, TriggerHandler},
350 {"TriggerLog", ap_set_flag_slot, (void *) XtOffsetOf(trigger_conf, log), OR_ALL, TAKE1, TriggerLog},
351 {"TriggerHandler", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
352 {"TriggerURI", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
353 {"TriggerAgent", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
354 {"TriggerReferer", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
355 {"TriggerMime", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
356 {"TriggerAddress", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
357 {"TriggerUser", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
358 {"TriggerIdent", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
359 {"TriggerPathInfo", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
360 {"TriggerAccept", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
361 {"TriggerCookie", add_trigger, NULL, OR_ALL, TAKE2, TriggerHandler},
362 {NULL},
363 };
364
365 /* Dispatch list for API hooks */
366 module MODULE_VAR_EXPORT trigger_module = {
367 STANDARD_MODULE_STUFF,
368 NULL, /* module initializer */
369 create_dir_mconfig, /* create per-dir config structures */
370 NULL, /* merge per-dir config structures */
371 NULL, /* create per-server config structures */
372 NULL, /* merge per-server config structures */
373 trigger_cmds, /* table of config file commands */
374 trigger_handlers, /* [#8] MIME-typed-dispatched handlers */
375 NULL, /* [#1] URI to filename translation */
376 NULL, /* [#4] validate user id from request */
377 NULL, /* [#5] check if the user is ok _here_ */
378 NULL, /* [#3] check access by host address */
379 NULL, /* [#6] determine MIME type */
380 NULL, /* [#7] pre-run fixups */
381 trigger_log, /* [#9] log a transaction */
382 NULL, /* [#2] header parser */
383 NULL, /* child_init */
384 NULL, /* child_exit */
385 NULL /* [#0] post read-request */
386 };
387