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 };