Source for cntr_module
1-86 /* Comments */
87 #include "httpd.h"
88 #include "http_config.h"
89 #include "http_core.h"
90 #include "http_log.h"
91 #include "http_protocol.h"
92 #include <ndbm.h>
93 #include <msql.h>
94
95 module cntr_module;
96
97 /* Data structures */
100 typedef enum { CntrMsql } CounterType;
101 typedef struct {
102 unsigned long count;
103 char* date;
104 } cntr_results;
106 typedef struct {
107 int cntr_default;
108 CounterType cntr_type;
109 int cntr_auto_add;
110 char* cntr_db;
111 char* cntr_table;
112 } cntr_config_rec;
113
114 #define DEF_CNTRTYPE 01
115 #define DEF_CNTRAA 02
116 #define DEF_CNTRDB 04
117 #define DEF_ALL (DEF_CNTRTYPE|DEF_CNTRAA|DEF_CNTRDB)
118
119 /* Set defaults */
122 #define DEFAULT_CNTR_TYPE CntrMsql
123 #define DEFAULT_TIME_FORMAT "%A, %d-%b-%y %T %Z"
124 #define DEFAULT_DIRCNTR_DB ""
125 #define DEFAULT_DIRCNTR_TABLE ""
126 #define DEFAULT_SVRCNTR_DB ""
127 #define DEFAULT_SVRCNTR_TABLE ""
128
129 /* Create config data structure */
132 void* create_cntr_dir_config_rec(pool* p, char* d)
133 {
134 /* Set the defaults */
137 cntr_config_rec * rec =
138 (cntr_config_rec*)pcalloc(p, sizeof(cntr_config_rec));
139 rec->cntr_type = DEFAULT_CNTR_TYPE;
140 rec->cntr_auto_add = 0;
141 rec->cntr_db = DEFAULT_DIRCNTR_DB ? pstrdup(p, DEFAULT_DIRCNTR_DB) : NULL;
142 rec->cntr_table = DEFAULT_DIRCNTR_TABLE ? pstrdup(p, DEFAULT_DIRCNTR_TABLE) : NULL;
143 rec->cntr_default = DEF_ALL;
145 return(rec);
146 }
148 void* create_cntr_srv_config_rec(pool* p, server_rec* d )
149 {
150 /* Set the defaults */
153 cntr_config_rec * rec =
154 (cntr_config_rec*)pcalloc(p, sizeof(cntr_config_rec));
155 rec->cntr_type = DEFAULT_CNTR_TYPE;
156 rec->cntr_auto_add = 0;
157 rec->cntr_file = DEFAULT_SVRCNTR_DB ? pstrdup(p, DEFAULT_SVRCNTR_DB) : NULL;
158 rec->cntr_file=DEFAULT_SVRCNTR_TABLE ? pstrdup(p, DEFAULT_SVRCNTR_TABLE) : NULL;
159 rec->cntr_default = DEF_ALL;
161 return(rec);
162 }
164 void* merge_config_rec( pool* p, void* parent, void* sub )
165 {
166 cntr_config_rec * par = (cntr_config_rec *)parent;
167 cntr_config_rec * chld = (cntr_config_rec *)sub;
168 cntr_config_rec * mrg = (cntr_config_rec *)palloc(p, sizeof(*mrg));
169 if (chld->cntr_default & DEF_CNTRTYPE)
170 mrg->cntr_type = par->cntr_type;
171 else
172 mrg->cntr_type = chld->cntr_type;
173 if (chld->cntr_default & DEF_CNTRAA)
174 mrg->cntr_auto_add = par->cntr_auto_add;
175 else
176 mrg->cntr_auto_add = chld->cntr_auto_add;
177 if (chld->cntr_default & DEF_CNTRDB) {
178 mrg->cntr_db = par->cntr_db;
179 mrg->cntr_table = par->cntr_table;
180 } else {
181 mrg->cntr_db = chld->cntr_db;
182 mrg->cntr_table = chld->cntr_table;
183 }
184 mrg->cntr_default = 0;
185 return(mrg);
186 }
188 const char* set_cntr_type(cmd_parms* cmd, void* ct, char* arg )
189 {
190 void* ret = NULL;
191 cntr_config_rec* conf = (cntr_config_rec*)ct;
193 if (!strcasecmp(arg, "msql"))
194 conf->cntr_type = CntrMsql;
195 else
196 ret = "CounterType must be Msql";
197 conf->cntr_default &= ~DEF_CNTRTYPE;
199 return(ret);
200 }
202 const char* set_cntr_autoadd(cmd_parms* cmd, void* ct, int arg )
203 {
204 cntr_config_rec* conf = (cntr_config_rec*)ct;
205 conf->cntr_auto_add = arg;
206 conf->cntr_default &= ~DEF_CNTRAA;
207 return(NULL);
208 }
210 const char* set_cntr_db( cmd_parms* cmd, void* ct, char* arg1, char* arg2 )
211 {
212 void* ret = NULL;
213 cntr_config_rec* conf = (cntr_config_rec*)ct;
215 conf->cntr_db = arg1;
216 conf->cntr_table = arg2;
217 conf->cntr_default &= ~DEF_CNTRFILE;
219 return(ret);
220 }
222 const char* set_svr_cntr_type(cmd_parms* cmd, void* ct, char* arg )
223 {
224 return(set_cntr_type(cmd, get_module_config(cmd->server->module_config, &cntr_module), arg));
225 }
226
227 const char* set_svr_cntr_autoadd(cmd_parms* cmd, void* ct, int arg )
228 {
229 return(set_cntr_autoadd(cmd,
230 get_module_config(cmd->server->module_config, &cntr_module), arg));
231 }
233 const char* set_svr_cntr_db(cmd_parms* cmd, void* ct, char* arg1, char* arg2 )
234 {
235 return(set_cntr_db(cmd,
236 get_module_config(cmd->server->module_config, &cntr_module), arg1, arg2));
237 }
239 command_rec cntr_cmds[] = {
240 { "CounterType", set_cntr_type, NULL, ACCESS_CONF, TAKE1, NULL },
241 { "CounterAutoAdd", set_cntr_autoadd, NULL, ACCESS_CONF, FLAG, NULL },
242 { "CounterDB", set_cntr_db, NULL, ACCESS_CONF, TAKE2,
243 "Name of counter Msql database followed by the name of the table" },
245 { "ServerCounterType", set_svr_cntr_type, NULL, RSRC_CONF, TAKE1, NULL },
246 { "ServerCounterAutoAdd", set_svr_cntr_autoadd, NULL, RSRC_CONF, FLAG, NULL },
247 { "ServerCounterDB", set_svr_cntr_db, NULL, RSRC_CONF, TAKE2,
248 "Name of counter Msql database followed by the name of the table" },
250 { NULL }
251 };
253 char* cntr_incmsql( pool* p, cntr_results* results,
254 cntr_config_rec* r, char* uri )
255 {
256 int dbh = 0;
257 int msql_result = 0;
258 char in_query[HUGE_STRING_LEN];
259 char out_query[HUGE_STRING_LEN];
260 m_result *msql_out;
261 m_row msql_data;
262
263 /* Connect to local Msql server */
264 dbh = msqlConnect(NULL);
265 if (dbh == -1)
266 return(pstrcat(p,"Failed to connect to local Msql server: ", msqlErrMsg, NULL));
267
268 /* Select database given to us */
269 msql_result = msqlSelectDB(dbh, r->cntr_db);
270 if (msql_result == -1) {
271 msqlClose(dbh);
272 return(pstrcat(p, "Failed to connect to database ", r->cntr_db, ": ", msqlErrMsg, NULL));
273 }
274 sprintf(in_query, "SELECT cntr_count, cntr_date FROM %s WHERE uri='%s'", r->cntr_table, uri);
275 msql_result = msqlQuery(dbh, in_query);
276 if (msql_result == -1) {
277 msqlClose(dbh);
278 return(pstrcat(p, "SELECT Query Failed: ", msqlErrMsg, NULL));
279 }
280 msql_out = msqlStoreResult();
281 msql_result = msqlNumRows(msql_out);
282 if (msql_result) {
283 msql_data = msqlFetchRow(msql_out);
284 results->count = atoi( msql_data[0]) + 1;
285 results->date = msql_data[1];
286 sprintf(out_query, "UPDATE %s SET cntr_count=%lu WHERE uri='%s'", r->cntr_table, results->count, uri);
287 msql_result = msqlQuery(dbh,out_query);
288 if (msql_result == -1) {
289 msqlFreeResult(msql_out);
290 msqlClose(dbh);
291 return(pstrcat(p, "UPDATE Query Failed: ", msqlErrMsg, NULL));
292 }
293 } else if (r->cntr_auto_add) {
294 results->count = 1;
295 results->date = ht_time(p, time(0L), DEFAULT_TIME_FORMAT, 0);
296 sprintf(out_query, "INSERT INTO %s (uri, cntr_count, cntr_date) VALUES ('%s', %lu, '%s')",
297 r->cntr_table, uri, results->count, results->date);
298 msql_result = msqlQuery( dbh,out_query);
299 if (msql_result = -1) {
300 msqlFreeResult(msql_out);
301 msqlClose(dbh);
302 return(pstrcat(p, "INSERT Query Failed: ", msqlErrMsg, " : ", out_query, NULL));
303 }
304 }
305 msqlFreeResult(msql_out);
306 msqlClose(dbh);
307 return(OK);
308 }
310 char* cntr_inc( pool* p, cntr_results* results,
311 cntr_config_rec* r, char* uri )
312 {
313 /* Normalize the URI stripping out double "//" */
314 char* puri = pstrdup(p, uri);
315 char* ptr = puri;
316 while (ptr && *ptr) {
317 if (*ptr == '/' && *(ptr+1) == '/') {
318 char* q = ptr + 1;
319 while (*q = *(q+1))
320 q++;
321 } else
322 ptr++;
323 }
325 if (r->cntr_type == CntrMsql)
326 return cntr_incmsql(p, results, r, puri);
327 else
328 return NULL;
329 }
331 int cntr_update( request_rec* r )
332 {
333 char* buf;
334 char* dbfile;
335 int ret = OK;
336 cntr_results * res;
337 cntr_config_rec *svr, *dir;
338 cntr_results *sres, *dres;
339
340 /* Get actual file, if locally redirected */
343 while (r->next)
344 r = r->next;
346 / * Skip if missing URI or this is an * included request */
348 if (!r->uri || !strcmp(r->protocol, "INCLUDED"))
349 return(DECLINED);
350 if (!S_ISREG(r->finfo.st_mode))
351 return(DECLINED);
352
353 /* Get each of the counter files */
356 svr = get_module_config( r->server->module_config, &cntr_module);
357 dir = get_module_config( r->per_dir_config, &cntr_module);
358
359 /* Return if no counter database */
362 if (!*svr->cntr_db && !*dir->cntr_db)
363 return(DECLINED);
364
365 /* Allocate result structures */
368 sres = (cntr_results*)pcalloc(r->pool, sizeof(cntr_results));
369 dres = (cntr_results*)pcalloc(r->pool, sizeof(cntr_results));
370
371 /* Bump up server configured counter */
374 if (*svr->cntr_db)
375 if (buf = cntr_inc(r->pool, sres, svr, r->uri))
376 log_error(buf, r->server);
377
378 /* Increment the directory counter file using
380 * the full file name instead of the URL */
382 if (*dir->cntr_db)
383 if (buf = cntr_inc(r->pool, dres, dir, r->filename))
384 log_error(buf, r->server);
386
388/* Now set the environment variables, take the
389 * server config as preference over the directory * directory config. */
391 res = (sres->count) ? sres : dres;
392 dbfile = "Msql";
393 buf = pcalloc(r->pool, 16);
394 sprintf(buf, "%lu", res->count);
395 table_set(r->subprocess_env, "URL_COUNT", buf);
396 table_set(r->subprocess_env, "URL_COUNT_RESET", res->date);
397 table_set(r->subprocess_env, "URL_COUNT_DB", dbfile);
399 return ret;
400 }
402
403 module cntr_module = {
404 STANDARD_MODULE_STUFF,
405 NULL, /* initializer */
406 create_cntr_dir_config_rec, /* dir config creater */
407 NULL, /* dir merger --- default is to override */
408 create_cntr_srv_config_rec, /* server config */
409 NULL, /* merge server config */
410 cntr_cmds, /* command table */
411 NULL, /* handlers */
412 NULL, /* filename translation */
413 NULL, /* check_user_id */
414 NULL, /* check auth */
415 NULL, /* check access */
416 NULL, /* type_checker */
417 cntr_update, /* fixups */
418 NULL /* logger */
419 };