summaryrefslogtreecommitdiffstatsabout
path: root/mod_log_sql.c
diff options
context:
space:
mode:
authorChristopher Powell <chris@grubbybaby.com>2002-04-21 23:01:53 (GMT)
committer Christopher Powell <chris@grubbybaby.com>2002-04-21 23:01:53 (GMT)
commitb63c5d2438aabf0d7721c38387995cb4fb98345f (patch)
tree73f99f046bb7daae711c5a7bdfe0f89677e22bda /mod_log_sql.c
parent13e1ecc20c883f71b54bf1fe09488b028e51171e (diff)
Significant bugfixes and feature additions on the way to 1.16...
Diffstat (limited to 'mod_log_sql.c')
-rw-r--r--mod_log_sql.c674
1 files changed, 383 insertions, 291 deletions
diff --git a/mod_log_sql.c b/mod_log_sql.c
index 16deada..02b0dd7 100644
--- a/mod_log_sql.c
+++ b/mod_log_sql.c
@@ -1,52 +1,72 @@
1/* $Id: mod_log_sql.c,v 1.8 2002/04/08 07:06:20 helios Exp $ */ 1/* $Id: mod_log_sql.c,v 1.9 2002/04/21 23:01:53 helios Exp $ */
2 2
3/* --------*
4 * DEFINES *
5 * --------*/
3 6
4/* DEFINES */ 7/* The enduser probably won't modify these */
5#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") 8#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
6#define ERRLEVEL APLOG_ERR|APLOG_NOERRNO 9#define ERRLEVEL APLOG_ERR|APLOG_NOERRNO
7#define WARNINGLEVEL APLOG_WARNING|APLOG_NOERRNO 10#define WARNINGLEVEL APLOG_WARNING|APLOG_NOERRNO
8#define NOTICELEVEL APLOG_NOTICE|APLOG_NOERRNO 11#define NOTICELEVEL APLOG_NOTICE|APLOG_NOERRNO
9#define DEBUGLEVEL APLOG_INFO|APLOG_NOERRNO 12#define DEBUGLEVEL APLOG_DEBUG|APLOG_NOERRNO
10#define PRESERVEFILE "/tmp/mysql-preserve"
11/* (MYSQLSOCKET, DEBUG and WANT_SSL_LOGGING are defined in the Makefile DEFS line.) */
12 13
14/* The enduser may wish to modify these */
15#define WANT_SSL_LOGGING
16#undef DEBUG
13 17
14 18
15/* INCLUDES */ 19/* ---------*
20 * INCLUDES *
21 * ---------*/
16#include <time.h> 22#include <time.h>
17#include <mysql/mysql.h> 23#include <mysql/mysql.h>
18#include <stdio.h> 24#include <stdio.h>
19
20#include "httpd.h" 25#include "httpd.h"
21#include "http_config.h" 26#include "http_config.h"
22#include "http_log.h" 27#include "http_log.h"
23#include "http_core.h" 28#include "http_core.h"
24 29
25/* M_M_N is defined in /usr/local/Apache/include/ap_mmn.h, 19990320 as of this writing. */ 30#if MODULE_MAGIC_NUMBER >= 19980324 /* M_M_N is defined in /usr/local/Apache/include/ap_mmn.h, 19990320 as of this writing. */
26#if MODULE_MAGIC_NUMBER >= 19980324 /* 1.3b6 or later */
27 #include "ap_compat.h" 31 #include "ap_compat.h"
28#endif 32#endif
29 33
30#ifdef WANT_SSL_LOGGING /* Defined in Makefile */ 34#ifdef WANT_SSL_LOGGING
31 #include "mod_ssl.h" 35 #include "mod_ssl.h"
32#endif 36#endif
33 37
34 38
39/* -------------*
40 * DECLARATIONS *
41 * -------------*/
35 42
36/* DECLARATIONS */ 43/* Declare ourselves so the configuration routines can find and know us. */
37module mysql_log_module; 44module mysql_log_module;
38 45
46/* The contents of these are known 'Apache wide' and are not variable
47 * on a per-virtual-server basis. Every virtual server 'knows' the
48 * same versions of these variables.
49 */
39MYSQL sql_server, *mysql_log = NULL; 50MYSQL sql_server, *mysql_log = NULL;
40 51
52int massvirtual = 0;
41char *db_name = NULL; 53char *db_name = NULL;
42char *db_host = NULL; 54char *db_host = NULL;
43char *db_user = NULL; 55char *db_user = NULL;
44char *db_pwd = NULL; 56char *db_pwd = NULL;
45char *cookie_name = NULL; 57char *socket_file = "/var/lib/mysql/mysql.sock";
46 58
47typedef const char *(*item_key_func) (request_rec *, char *); 59typedef const char *(*item_key_func) (request_rec *, char *);
48 60
61/* But the contents of this structure will vary by virtual server.
62 * This permits each virtual server to vary its configuration slightly
63 * for per-server customization.
64 *
65 * Each child process has its own segregated copy of this structure.
66 */
49typedef struct { 67typedef struct {
68 int create_tables;
69 int table_made;
50 char *referer_table_name; 70 char *referer_table_name;
51 char *agent_table_name; 71 char *agent_table_name;
52 char *transfer_table_name; 72 char *transfer_table_name;
@@ -54,11 +74,14 @@ typedef struct {
54 array_header *transfer_ignore_list; 74 array_header *transfer_ignore_list;
55 array_header *remhost_ignore_list; 75 array_header *remhost_ignore_list;
56 char *transfer_log_format; 76 char *transfer_log_format;
77 char *preserve_file;
78 char *cookie_name;
57} log_mysql_state; 79} log_mysql_state;
58 80
59 81
60 82/* -----------------*
61/* FUNCTIONS */ 83 * HELPER FUNCTIONS *
84 * -----------------*/
62static char *format_integer(pool *p, int i) 85static char *format_integer(pool *p, int i)
63{ 86{
64 char dummy[40]; 87 char dummy[40];
@@ -110,7 +133,7 @@ static const char *extract_ssl_keysize(request_rec *r, char *a)
110 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { 133 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) {
111 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_USEKEYSIZE"); 134 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_USEKEYSIZE");
112 #ifdef DEBUG 135 #ifdef DEBUG
113 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: SSL_KEYSIZE: %s", result); 136 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_KEYSIZE: %s", result);
114 #endif 137 #endif
115 if (result != NULL && result[0] == '\0') 138 if (result != NULL && result[0] == '\0')
116 result = NULL; 139 result = NULL;
@@ -127,7 +150,7 @@ static const char *extract_ssl_maxkeysize(request_rec *r, char *a)
127 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { 150 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) {
128 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_ALGKEYSIZE"); 151 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_ALGKEYSIZE");
129 #ifdef DEBUG 152 #ifdef DEBUG
130 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: SSL_ALGKEYSIZE: %s", result); 153 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_ALGKEYSIZE: %s", result);
131 #endif 154 #endif
132 if (result != NULL && result[0] == '\0') 155 if (result != NULL && result[0] == '\0')
133 result = NULL; 156 result = NULL;
@@ -144,7 +167,7 @@ static const char *extract_ssl_cipher(request_rec *r, char *a)
144 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { 167 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) {
145 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER"); 168 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
146 #ifdef DEBUG 169 #ifdef DEBUG
147 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: SSL_CIPHER: %s", result); 170 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_CIPHER: %s", result);
148 #endif 171 #endif
149 if (result != NULL && result[0] == '\0') 172 if (result != NULL && result[0] == '\0')
150 result = NULL; 173 result = NULL;
@@ -299,15 +322,27 @@ static const char *extract_cookie(request_rec *r, char *a)
299 char *isvalid; 322 char *isvalid;
300 char *cookiebuf; 323 char *cookiebuf;
301 324
325 log_mysql_state *cls = get_module_config(r->server->module_config, &mysql_log_module);
326
327 #ifdef DEBUG
328 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"watching for cookie '%s'", cls->cookie_name);
329 #endif
330
331 /* Fetch out the cookie header */
302 cookiestr = (char *)table_get(r->headers_in, "cookie2"); 332 cookiestr = (char *)table_get(r->headers_in, "cookie2");
303 if (cookiestr != NULL) { 333 if (cookiestr != NULL) {
304 #ifdef DEBUG 334 #ifdef DEBUG
305 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: Cookie2: [%s]", cookiestr); 335 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie2: [%s]", cookiestr);
306 #endif 336 #endif
307 isvalid = strstr(cookiestr, cookie_name); 337 /* Does the cookie string contain one with our name? */
338 isvalid = strstr(cookiestr, cls->cookie_name);
308 if (isvalid != NULL) { 339 if (isvalid != NULL) {
309 isvalid += strlen(cookie_name) + 1; 340 /* Move past the cookie name and equal sign */
341 isvalid += strlen(cls->cookie_name) + 1;
342 /* Duplicate it into the pool */
310 cookiebuf = ap_pstrdup(r->pool, isvalid); 343 cookiebuf = ap_pstrdup(r->pool, isvalid);
344 /* Segregate just this cookie out of the string
345 * with a terminating nul at the first semicolon */
311 cookieend = strchr(cookiebuf, ';'); 346 cookieend = strchr(cookiebuf, ';');
312 if (cookieend != NULL) 347 if (cookieend != NULL)
313 *cookieend = '\0'; 348 *cookieend = '\0';
@@ -318,11 +353,11 @@ static const char *extract_cookie(request_rec *r, char *a)
318 cookiestr = (char *)table_get(r->headers_in, "cookie"); 353 cookiestr = (char *)table_get(r->headers_in, "cookie");
319 if (cookiestr != NULL) { 354 if (cookiestr != NULL) {
320 #ifdef DEBUG 355 #ifdef DEBUG
321 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: Cookie: [%s]", cookiestr); 356 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie: [%s]", cookiestr);
322 #endif 357 #endif
323 isvalid = strstr(cookiestr, cookie_name); 358 isvalid = strstr(cookiestr, cls->cookie_name);
324 if (isvalid != NULL) { 359 if (isvalid != NULL) {
325 isvalid += strlen(cookie_name) + 1; 360 isvalid += strlen(cls->cookie_name) + 1;
326 cookiebuf = ap_pstrdup(r->pool, isvalid); 361 cookiebuf = ap_pstrdup(r->pool, isvalid);
327 cookieend = strchr(cookiebuf, ';'); 362 cookieend = strchr(cookiebuf, ';');
328 if (cookieend != NULL) 363 if (cookieend != NULL)
@@ -334,11 +369,11 @@ static const char *extract_cookie(request_rec *r, char *a)
334 cookiestr = table_get(r->headers_out, "set-cookie"); 369 cookiestr = table_get(r->headers_out, "set-cookie");
335 if (cookiestr != NULL) { 370 if (cookiestr != NULL) {
336 #ifdef DEBUG 371 #ifdef DEBUG
337 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: Set-Cookie: [%s]", cookiestr); 372 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Set-Cookie: [%s]", cookiestr);
338 #endif 373 #endif
339 isvalid = strstr(cookiestr, cookie_name); 374 isvalid = strstr(cookiestr, cls->cookie_name);
340 if (isvalid != NULL) { 375 if (isvalid != NULL) {
341 isvalid += strlen(cookie_name) + 1; 376 isvalid += strlen(cls->cookie_name) + 1;
342 cookiebuf = ap_pstrdup(r->pool, isvalid); 377 cookiebuf = ap_pstrdup(r->pool, isvalid);
343 cookieend = strchr(cookiebuf, ';'); 378 cookieend = strchr(cookiebuf, ';');
344 if (cookieend != NULL) 379 if (cookieend != NULL)
@@ -350,23 +385,6 @@ static const char *extract_cookie(request_rec *r, char *a)
350 return "-"; 385 return "-";
351} 386}
352 387
353/*
354static const char *extract_forwarded(request_rec *r, char *a)
355{
356 return table_get(r->subprocess_env, "HTTP_FORWARDED");
357}
358
359static const char *extract_via(request_rec *r, char *a)
360{
361 return table_get(r->subprocess_env, "HTTP_VIA");
362}
363
364static const char *extract_forwarded_for(request_rec *r, char *a)
365{
366 return table_get(r->subprocess_env, "HTTP_X_FORWARDED_FOR");
367}
368*/
369
370static const char *extract_request_timestamp(request_rec *r, char *a) 388static const char *extract_request_timestamp(request_rec *r, char *a)
371{ 389{
372 char tstr[32]; 390 char tstr[32];
@@ -390,11 +408,11 @@ static const char *extract_env_var(request_rec *r, char *a)
390 408
391 409
392struct log_mysql_item_list { 410struct log_mysql_item_list {
393 char ch; 411 char ch; /* its letter code */
394 item_key_func func; 412 item_key_func func; /* its extraction function */
395 const char *sql_field_name; 413 const char *sql_field_name; /* its column in SQL */
396 int want_orig_default; 414 int want_orig_default; /* if it requires the original request prior to internal redirection */
397 int string_contents; 415 int string_contents; /* if it returns a string */
398 } log_mysql_item_keys[] = { 416 } log_mysql_item_keys[] = {
399 417
400 { 'A', extract_agent, "agent", 1, 1 }, 418 { 'A', extract_agent, "agent", 1, 1 },
@@ -420,10 +438,6 @@ struct log_mysql_item_list {
420 { 'u', extract_remote_user, "remote_user", 0, 1 }, 438 { 'u', extract_remote_user, "remote_user", 0, 1 },
421 { 'U', extract_request_uri, "request_uri", 1, 1 }, 439 { 'U', extract_request_uri, "request_uri", 1, 1 },
422 { 'v', extract_virtual_host, "virtual_host", 0, 1 }, 440 { 'v', extract_virtual_host, "virtual_host", 0, 1 },
423/* { 'V', extract_via, "via", 0, 1 },
424 { 'w', extract_forwarded, "forwarded", 0, 1 },
425 { 'W', extract_forwarded_for, "forwarded_for", 0, 1 },
426 */
427 #ifdef WANT_SSL_LOGGING 441 #ifdef WANT_SSL_LOGGING
428 { 'q', extract_ssl_keysize, "ssl_keysize", 0, 1 }, 442 { 'q', extract_ssl_keysize, "ssl_keysize", 0, 1 },
429 { 'Q', extract_ssl_maxkeysize, "ssl_maxkeysize", 0, 1 }, 443 { 'Q', extract_ssl_maxkeysize, "ssl_maxkeysize", 0, 1 },
@@ -436,66 +450,54 @@ struct log_mysql_item_list {
436/* Routine to escape the 'dangerous' characters that would otherwise 450/* Routine to escape the 'dangerous' characters that would otherwise
437 * corrupt the INSERT string: ', \, and " 451 * corrupt the INSERT string: ', \, and "
438 */ 452 */
439const char *mysql_escape_log(const char *str, pool *p) 453const char *escape_query(const char *from_str, pool *p)
440{ 454{
441 register int i = 0, j = 0; 455 if (!from_str)
442 int need_to_escape = 0;
443
444 if (!str) {
445 return NULL; 456 return NULL;
446 } 457 else {
447 458 char *to_str;
448 /* First find out if we need to escape. */ 459 unsigned long length = strlen(from_str);
449 i = 0; 460 unsigned long retval;
450 while (str[i]) { 461
451 /* WAS THIS WRONG in 1.05?!? if (str[i] != '\'' || str[i] != '\\' || str[i] != '\"') { */
452 if (str[i] == '\'' || str[i] == '\\' || str[i] == '\"') {
453 need_to_escape = 1;
454 break;
455 }
456 i++;
457 }
458
459 if (need_to_escape) {
460 char *tmp_str;
461 int length = strlen(str);
462
463 /* Pre-allocate a new string that could hold twice the original, which would only 462 /* Pre-allocate a new string that could hold twice the original, which would only
464 * happen if the whole original string was 'dangerous' characters. 463 * happen if the whole original string was 'dangerous' characters.
465 */ 464 */
466 tmp_str = (char *) palloc(p, length * 2 + 1); 465 to_str = (char *) ap_palloc(p, length * 2 + 1);
467 if (!tmp_str) { 466 if (!to_str) {
468 return str; 467 return from_str;
469 } 468 }
470 469
471 /* Walk through character-by-character, escaping any dangerous characters found. */ 470 if (!mysql_log) {
472 for (i = 0, j = 0; i < length; i++, j++) { 471 /* Well, I would have liked to use the current database charset. mysql is
473 switch (str[i]) { 472 * unavailable, however, so I fall back to the slightly less respectful
474 case '\'': 473 * mysql_escape_string() function that uses the default charset.
475 case '\"': 474 */
476 case '\\': 475 retval = mysql_escape_string(to_str, from_str, length);
477 tmp_str[j] = '\\'; 476 } else {
478 j++; 477 /* MySQL is available, so I'll go ahead and respect the current charset when
479 default: 478 * I perform the escape.
480 tmp_str[j] = str[i]; 479 */
481 } 480 retval = mysql_real_escape_string(mysql_log, to_str, from_str, length);
482 } 481 }
483 tmp_str[j] = '\0'; 482
484 return tmp_str; 483 if (retval)
485 } else { 484 return to_str;
486 return str; 485 else
486 return from_str;
487 } 487 }
488} 488}
489 489
490int open_logdb_link() 490int open_logdb_link()
491{ 491{
492 /* Returns 2 if already connected, 1 if successful, 0 if unsuccessful */
493
492 if (mysql_log != NULL) { 494 if (mysql_log != NULL) {
493 return 2; 495 return 2;
494 } 496 }
495 497
496 if (db_name) { 498 if (db_name) {
497 mysql_init(&sql_server); 499 mysql_init(&sql_server);
498 mysql_log = mysql_real_connect(&sql_server, db_host, db_user, db_pwd, db_name, 0, MYSQLSOCKET, 0); 500 mysql_log = mysql_real_connect(&sql_server, db_host, db_user, db_pwd, db_name, 0, socket_file, 0);
499 501
500 if (mysql_log != NULL) { 502 if (mysql_log != NULL) {
501 return 1; 503 return 1;
@@ -509,18 +511,27 @@ int open_logdb_link()
509void preserve_entry(request_rec *r, const char *query) 511void preserve_entry(request_rec *r, const char *query)
510{ 512{
511 FILE *fp; 513 FILE *fp;
514 log_mysql_state *cls = get_module_config(r->server->module_config, &mysql_log_module);
512 515
513 fp = fopen(PRESERVEFILE, "a"); 516 fp = pfopen(r->pool, cls->preserve_file, "a");
514 if (fp == NULL) 517 if (fp == NULL)
515 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: attempted append of local offline file but failed."); 518 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"attempted append of local offline file but failed.");
516 else 519 else
517 fprintf(fp,"%s;\n", query); 520 fprintf(fp,"%s;\n", query);
518 fclose(fp); 521 pfclose(r->pool, fp);
519} 522}
520 523
524/*-----------------------------------------------------*/
525/* safe_mysql_query: perform a database insert with */
526/* a degree of safety and error checking. */
527/* */
528/* Parms: request record, SQL insert statement */
529/* Returns: 0 (OK) on success */
530/* mysql return code on error */
531/*-----------------------------------------------------*/
521int safe_mysql_query(request_rec *r, const char *query) 532int safe_mysql_query(request_rec *r, const char *query)
522{ 533{
523 int retval = 1; 534 int retval;
524 struct timespec delay, remainder; 535 struct timespec delay, remainder;
525 int ret; 536 int ret;
526 char *str; 537 char *str;
@@ -539,19 +550,22 @@ int safe_mysql_query(request_rec *r, const char *query)
539 * at any time, hence the check. */ 550 * at any time, hence the check. */
540 if ( retval != 0 ) 551 if ( retval != 0 )
541 { 552 {
553 log_mysql_state *cls = get_module_config(r->server->module_config, &mysql_log_module);
554
542 /* Something went wrong, so start by trying to restart the db link. */ 555 /* Something went wrong, so start by trying to restart the db link. */
543 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: attempting reconnect because API said: %s", MYSQL_ERROR(mysql_log)); 556 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"attempting reconnect because API said: %s", mysql_error(mysql_log));
544 557
545 mysql_log = NULL; 558 mysql_log = NULL;
546 open_logdb_link(); 559 open_logdb_link();
547 560
548 if (mysql_log == NULL) { /* still unable to link */ 561 if (mysql_log == NULL) { /* still unable to link */
549 signal(SIGPIPE, handler); 562 signal(SIGPIPE, handler);
550 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: httpd child reconnect failed, unable to reach database. SQL logging stopped until an httpd child regains a db connection."); 563 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"httpd child reconnect failed, unable to reach database. SQL logging stopped until an httpd child regains a db connection.");
551 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: log entries are being preserved in %s",PRESERVEFILE); 564 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"log entries are being preserved in %s", cls->preserve_file);
565 preserve_entry(r, query);
552 return retval; 566 return retval;
553 } else { 567 } else {
554 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: reconnect successful."); 568 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"reconnect successful.");
555 } 569 }
556 570
557 /* Attempt a single re-try... First sleep for a tiny amount of time. */ 571 /* Attempt a single re-try... First sleep for a tiny amount of time. */
@@ -559,7 +573,7 @@ int safe_mysql_query(request_rec *r, const char *query)
559 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */ 573 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */
560 ret = nanosleep(&delay, &remainder); 574 ret = nanosleep(&delay, &remainder);
561 if (ret && errno != EINTR) 575 if (ret && errno != EINTR)
562 perror("nanosleep"); 576 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"nanosleep unsuccessful.");
563 577
564 /* Now make our second attempt */ 578 /* Now make our second attempt */
565 retval = mysql_query(mysql_log,query); 579 retval = mysql_query(mysql_log,query);
@@ -567,13 +581,13 @@ int safe_mysql_query(request_rec *r, const char *query)
567 /* If this one also failed, log that and append to our local offline file */ 581 /* If this one also failed, log that and append to our local offline file */
568 if ( retval != 0 ) 582 if ( retval != 0 )
569 { 583 {
570 str = pstrcat(r->pool, "MySQL delayed insert attempt failed, API said: ", MYSQL_ERROR(mysql_log), NULL); 584 str = ap_pstrcat(r->pool, "delayed insert attempt failed, API said: ", MYSQL_ERROR(mysql_log), NULL);
571 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,str); 585 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,str);
572 586
573 preserve_entry(r, query); 587 preserve_entry(r, query);
574 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: entry preserved in %s",PRESERVEFILE); 588 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"entry preserved in %s", cls->preserve_file);
575 } else { 589 } else {
576 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: insert successful after a delayed retry."); 590 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"insert successful after a delayed retry.");
577 } 591 }
578 } 592 }
579 593
@@ -584,52 +598,44 @@ int safe_mysql_query(request_rec *r, const char *query)
584} 598}
585 599
586 600
601/* ------------------------------------------------*
602 * Command handlers that are called according *
603 * to the directives found at Apache runtime. *
604 * ------------------------------------------------*/
587 605
588const char *set_referer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg) 606const char *set_massvirtual(cmd_parms *parms, void *dummy, int flag)
589{ 607{
590 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 608 massvirtual = ( flag ? 1 : 0);
591
592 cls->referer_table_name = arg;
593 return NULL; 609 return NULL;
594} 610}
595 611
596 612const char *set_log_mysql_create(cmd_parms *parms, void *dummy, int flag)
597const char *set_agent_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
598{ 613{
599 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 614 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
600 615
601 cls->agent_table_name = arg; 616 cls->create_tables = ( flag ? 1 : 0);
602 return NULL; 617 return NULL;
603} 618}
604 619
605 620const char *set_log_mysql_db(cmd_parms *parms, void *dummy, char *arg)
606const char *set_transfer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
607{ 621{
608 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 622 db_name = arg;
609
610 cls->transfer_table_name = arg;
611 return NULL; 623 return NULL;
612} 624}
613 625
614 626const char *set_log_mysql_cookie(cmd_parms *parms, void *dummy, char *arg)
615const char *set_transfer_log_format(cmd_parms *parms, void *dummy, char *arg)
616{ 627{
617 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 628 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
618 629
619 cls->transfer_log_format = arg; 630 cls->cookie_name = arg;
620 return NULL; 631 return NULL;
621} 632}
622 633
623 634const char *set_log_mysql_preserve_file(cmd_parms *parms, void *dummy, char *arg)
624const char *set_log_mysql_db(cmd_parms *parms, void *dummy, char *arg)
625{ 635{
626 db_name = arg; 636 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
627 return NULL;
628}
629 637
630const char *set_log_mysql_cookie(cmd_parms *parms, void *dummy, char *arg) 638 cls->preserve_file = arg;
631{
632 cookie_name = arg;
633 return NULL; 639 return NULL;
634} 640}
635 641
@@ -647,12 +653,59 @@ const char *set_log_mysql_info(cmd_parms *parms, void *dummy, char *host, char *
647 return NULL; 653 return NULL;
648} 654}
649 655
656const char *set_transfer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
657{
658 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
659
660 if (massvirtual == 1) {
661 char *base = "access_";
662 char *tablename;
663 int i;
664
665 /* Find memory long enough to hold the table name + \0. */
666 /* old way: */
667 /* tablename = (char*)ap_palloc(parms->pool, (strlen(base) + strlen(parms->server->server_hostname) + 1) * sizeof(char));*/
668 /* strcpy(tablename, base);*/
669 /* strcat(tablename, parms->server->server_hostname);*/
670
671 tablename = ap_pstrcat(parms->pool, base, parms->server->server_hostname, NULL);
672
673 /* Transform any dots to underscores */
674 for (i = 0; i < strlen(tablename); i++) {
675 if (tablename[i] == '.')
676 tablename[i] = '_';
677 }
678
679 /* Tell this virtual server its transfer table name, and
680 * turn on create_tables, which is implied by massvirtual.
681 */
682 cls->transfer_table_name = tablename;
683 cls->create_tables = 1;
684 } else {
685 cls->transfer_table_name = arg;
686 }
687 return NULL;
688}
689
690const char *set_transfer_log_format(cmd_parms *parms, void *dummy, char *arg)
691{
692 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
693
694 cls->transfer_log_format = arg;
695 return NULL;
696}
697
698const char *set_mysql_socket_file(cmd_parms *parms, void *dummy, char *arg)
699{
700 socket_file = arg;
701
702 return NULL;
703}
650 704
651const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) 705const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
652{ 706{
653 char **addme; 707 char **addme;
654 log_mysql_state *cls = get_module_config(parms->server->module_config, 708 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
655 &mysql_log_module);
656 709
657 addme = push_array(cls->referer_ignore_list); 710 addme = push_array(cls->referer_ignore_list);
658 *addme = pstrdup(cls->referer_ignore_list->pool, arg); 711 *addme = pstrdup(cls->referer_ignore_list->pool, arg);
@@ -662,8 +715,7 @@ const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
662const char *add_transfer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) 715const char *add_transfer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
663{ 716{
664 char **addme; 717 char **addme;
665 log_mysql_state *cls = get_module_config(parms->server->module_config, 718 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
666 &mysql_log_module);
667 719
668 addme = push_array(cls->transfer_ignore_list); 720 addme = push_array(cls->transfer_ignore_list);
669 *addme = pstrdup(cls->transfer_ignore_list->pool, arg); 721 *addme = pstrdup(cls->transfer_ignore_list->pool, arg);
@@ -673,8 +725,7 @@ const char *add_transfer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
673const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) 725const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
674{ 726{
675 char **addme; 727 char **addme;
676 log_mysql_state *cls = get_module_config(parms->server->module_config, 728 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
677 &mysql_log_module);
678 729
679 addme = push_array(cls->remhost_ignore_list); 730 addme = push_array(cls->remhost_ignore_list);
680 *addme = pstrdup(cls->remhost_ignore_list->pool, arg); 731 *addme = pstrdup(cls->remhost_ignore_list->pool, arg);
@@ -682,24 +733,91 @@ const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
682} 733}
683 734
684 735
685/* 736
686 * Apache-specific hooks into the module code 737
687 * that are defined in the array 'mysql_lgog_module' (at EOF) 738/*------------------------------------------------------------*
739 * Apache-specific hooks into the module code *
740 * that are defined in the array 'mysql_lgog_module' (at EOF) *
741 *------------------------------------------------------------*/
742
743
744/*
745 * This function is called during server initialisation when an heavy-weight
746 * process (such as a child) is being initialised. As with the
747 * module-initialisation function, any information that needs to be recorded
748 * must be in static cells, since there's no configuration record.
749 *
750 * There is no return value.
688 */ 751 */
752static void log_mysql_child_init(server_rec *s, pool *p)
753{
754 int retval;
755
756 retval = open_logdb_link();
757 #ifdef DEBUG
758 if (retval > 0) {
759 ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"open_logdb_link successful");
760 }
761 #endif
762}
689 763
764/*
765 * This function is called when an heavy-weight process (such as a child) is
766 * being run down or destroyed. As with the child-initialisation function,
767 * any information that needs to be recorded must be in static cells, since
768 * there's no configuration record.
769 *
770 * There is no return value.
771 */
772static void log_mysql_child_exit(server_rec *s, pool *p)
773{
774 mysql_close(mysql_log);
775}
776
777
778/*
779void *log_mysql_initializer(server_rec *main_server, pool *p)
780{
781 server_rec *s;
782
783 log_mysql_state main_conf = ap_get_module_config(main_server->module_config, &mysql_log_module);
690 784
691/* Set up space for the various major configuration options */ 785 for (server_rec *s = main_server; s; s = s->next) {
786 conf = ap_get_module_config(s->module_config, &mysql_log_module);
787 if (conf->transfer_log_format == NULL && s != main_server) {
788 *conf = *main_conf;
789 }
790
791}
792 */
793
794/*
795 * This function gets called to create a per-server configuration
796 * record. It will always be called for the main server and
797 * for each virtual server that is established. Each server maintains
798 * its own state that is separate from the others' states.
799 *
800 * The return value is a pointer to the created module-specific
801 * structure.
802 */
692void *log_mysql_make_state(pool *p, server_rec *s) 803void *log_mysql_make_state(pool *p, server_rec *s)
693{ 804{
694 log_mysql_state *cls = (log_mysql_state *) palloc(p, sizeof(log_mysql_state)); 805
806 log_mysql_state *cls = (log_mysql_state *) ap_palloc(p, sizeof(log_mysql_state));
807
695 808
696 cls->referer_table_name = cls->agent_table_name = cls->transfer_table_name = ""; 809 cls->transfer_table_name = NULL;
810 cls->transfer_log_format = NULL;
697 811
698 cls->referer_ignore_list = make_array(p, 1, sizeof(char *)); 812 cls->referer_ignore_list = make_array(p, 1, sizeof(char *));
699 cls->transfer_ignore_list = make_array(p, 1, sizeof(char *)); 813 cls->transfer_ignore_list = make_array(p, 1, sizeof(char *));
700 cls->remhost_ignore_list = make_array(p, 1, sizeof(char *)); 814 cls->remhost_ignore_list = make_array(p, 1, sizeof(char *));
701 815
702 cls->transfer_log_format = ""; 816 cls->table_made = 0;
817 cls->create_tables = 0;
818
819 cls->preserve_file = "/tmp/mysql-preserve";
820
703 return (void *) cls; 821 return (void *) cls;
704} 822}
705 823
@@ -708,12 +826,6 @@ void *log_mysql_make_state(pool *p, server_rec *s)
708 * Structure: command, function called, NULL, where available, how many arguments, verbose description 826 * Structure: command, function called, NULL, where available, how many arguments, verbose description
709 */ 827 */
710command_rec log_mysql_cmds[] = { 828command_rec log_mysql_cmds[] = {
711 {"MySQLRefererLogTable", set_referer_log_mysql_table, NULL, RSRC_CONF, TAKE1,
712 "The MySQL table that holds the referer log"}
713 ,
714 {"MySQLAgentLogTable", set_agent_log_mysql_table, NULL, RSRC_CONF, TAKE1,
715 "The MySQL table that holds the agent log"}
716 ,
717 {"MySQLTransferLogTable", set_transfer_log_mysql_table, NULL, RSRC_CONF, TAKE1, 829 {"MySQLTransferLogTable", set_transfer_log_mysql_table, NULL, RSRC_CONF, TAKE1,
718 "The MySQL table that holds the transfer log"} 830 "The MySQL table that holds the transfer log"}
719 , 831 ,
@@ -738,6 +850,18 @@ command_rec log_mysql_cmds[] = {
738 {"MySQLLoginInfo", set_log_mysql_info, NULL, RSRC_CONF, TAKE3, 850 {"MySQLLoginInfo", set_log_mysql_info, NULL, RSRC_CONF, TAKE3,
739 "The MySQL host, user-id and password for logging"} 851 "The MySQL host, user-id and password for logging"}
740 , 852 ,
853 {"MySQLCreateTables", set_log_mysql_create, NULL, RSRC_CONF, FLAG,
854 "Turn on module's capability to create its SQL tables on the fly"}
855 ,
856 {"MySQLMassVirtualHosting", set_massvirtual, NULL, RSRC_CONF, FLAG,
857 "Activates option(s) useful for ISPs performing mass virutal hosting"}
858 ,
859 {"MySQLPreserveFile", set_log_mysql_preserve_file, NULL, RSRC_CONF, TAKE1,
860 "Name of the file to use for data preservation during database downtime"}
861 ,
862 {"MySQLSocketFile", set_mysql_socket_file, NULL, RSRC_CONF, TAKE1,
863 "Name of the file to employ for socket connections to MySQL"}
864 ,
741 {NULL} 865 {NULL}
742}; 866};
743 867
@@ -749,102 +873,25 @@ command_rec log_mysql_cmds[] = {
749int log_mysql_transaction(request_rec *orig) 873int log_mysql_transaction(request_rec *orig)
750{ 874{
751 char **ptrptr, **ptrptr2; 875 char **ptrptr, **ptrptr2;
752 log_mysql_state *cls = get_module_config(orig->server->module_config, 876 log_mysql_state *cls = get_module_config(orig->server->module_config, &mysql_log_module);
753 &mysql_log_module); 877 const char *str;
754 char *str;
755 const char *referer;
756 request_rec *r; 878 request_rec *r;
757 int retvalue = DECLINED;
758 int referer_needed, agent_needed, transfer_needed;
759
760 879
761 /* Are there configuration directives for these SQL logs? For each found 880 /* Are there configuration directives for these SQL logs? For each found
762 * config directive that is found, mark that type as 'needed'. 881 * config directive that is found, mark that type as 'needed'.
763 */ 882 */
764 referer_needed = ((cls->referer_table_name[0] != '\0') ? 1 : 0); 883 if ( ((cls->transfer_table_name == NULL) ? 1 : 0) ) {
765 agent_needed = ((cls->agent_table_name[0] != '\0') ? 1 : 0); 884 return DECLINED;
766 transfer_needed = ((cls->transfer_table_name[0] != '\0') ? 1 : 0); 885 } else {
767
768 if (!referer_needed && !agent_needed && !transfer_needed) {
769 return OK;
770 }
771
772
773 for (r = orig; r->next; r = r->next) {
774 continue;
775 }
776
777 /* Log the 'referer' to its own log if configured to do so. */
778 if (referer_needed) {
779 retvalue = OK;
780 referer = table_get(orig->headers_in, "Referer");
781 if (referer != NULL) {
782
783 /* The following is an upsetting mess of pointers, I'm sorry
784 * Anyone with the motiviation and/or the time should feel free
785 * to make this cleaner... */
786 ptrptr2 = (char **) (cls->referer_ignore_list->elts + (cls->referer_ignore_list->nelts * cls->referer_ignore_list->elt_size));
787
788 /* Go through each element of the ignore list and compare it to the
789 * referer_host. If we get a match, return without logging */
790 for (ptrptr = (char **) cls->referer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->referer_ignore_list->elt_size)) {
791 if (strstr(referer, *ptrptr)) {
792 return OK;
793 }
794 }
795 str = pstrcat(orig->pool, "insert into ", cls->referer_table_name, " (referer,url,time_stamp) values ('", mysql_escape_log(referer, orig->pool), "','", mysql_escape_log(r->uri, orig->pool), "',unix_timestamp(now()) )", NULL);
796
797 if (mysql_log == NULL) { /* child's mysql link not up, re-establish it */
798 open_logdb_link();
799 if (mysql_log == NULL) {
800 preserve_entry(r, str);
801 return OK;
802 } else {
803 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection");
804 safe_mysql_query(orig, str);
805 }
806 } else {
807 safe_mysql_query(orig, str);
808 }
809
810 }
811 }
812
813 /* Log the 'user agent' to its own log if configured to do so. */
814 if (agent_needed) {
815 const char *agent, *str;
816
817 retvalue = OK;
818 agent = table_get(orig->headers_in, "User-Agent");
819
820 if (agent != NULL) {
821 str = pstrcat(orig->pool, "insert into ", cls->agent_table_name, "(agent,time_stamp) values ('", mysql_escape_log(agent, orig->pool), "',unix_timestamp(now()) )", NULL);
822
823 if (mysql_log == NULL) { /* child's mysql link not up, re-establish it */
824 open_logdb_link();
825 if (mysql_log == NULL) {
826 preserve_entry(r, str);
827 return OK;
828 } else {
829 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection");
830 safe_mysql_query(orig, str);
831 }
832 } else {
833 safe_mysql_query(orig, str);
834 }
835 }
836 }
837
838 /* Log the transfer to its own log if configured to do so. */
839 if (transfer_needed) {
840 const char *thehost; 886 const char *thehost;
841
842 char *fields = "", *values = ""; 887 char *fields = "", *values = "";
843 const char *formatted_item; 888 const char *formatted_item;
844 int i, j, length; 889 int i, j, length;
890 char *createstring = NULL;
845 891
846 retvalue = OK; 892 for (r = orig; r->next; r = r->next) {
847 893 continue;
894 }
848 895
849 /* The following is a stolen upsetting mess of pointers, I'm sorry 896 /* The following is a stolen upsetting mess of pointers, I'm sorry
850 * Anyone with the motiviation and/or the time should feel free 897 * Anyone with the motiviation and/or the time should feel free
@@ -856,7 +903,7 @@ int log_mysql_transaction(request_rec *orig)
856 if (r->uri) { 903 if (r->uri) {
857 for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) { 904 for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) {
858 if (strstr(r->uri, *ptrptr)) { 905 if (strstr(r->uri, *ptrptr)) {
859 return retvalue; 906 return OK;
860 } 907 }
861 } 908 }
862 } 909 }
@@ -868,13 +915,13 @@ int log_mysql_transaction(request_rec *orig)
868 if (thehost) { 915 if (thehost) {
869 for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size)) { 916 for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size)) {
870 if (strstr(thehost, *ptrptr)) { 917 if (strstr(thehost, *ptrptr)) {
871 return retvalue; 918 return OK;
872 } 919 }
873 } 920 }
874 } 921 }
875 922
876 /* If not specified by the user, use the default format */ 923 /* If not specified by the user, use the default format */
877 if (cls->transfer_log_format[0] == '\0') { 924 if (cls->transfer_log_format == NULL) {
878 cls->transfer_log_format = "AbHhmRSsTUuv"; 925 cls->transfer_log_format = "AbHhmRSsTUuv";
879 } 926 }
880 length = strlen(cls->transfer_log_format); 927 length = strlen(cls->transfer_log_format);
@@ -883,8 +930,10 @@ int log_mysql_transaction(request_rec *orig)
883 * what the user has configured. */ 930 * what the user has configured. */
884 for (i = 0; i < length; i++) { 931 for (i = 0; i < length; i++) {
885 j = 0; 932 j = 0;
933
886 while (log_mysql_item_keys[j].ch) { 934 while (log_mysql_item_keys[j].ch) {
887 if (log_mysql_item_keys[j].ch == cls->transfer_log_format[i]) { 935
936 if (log_mysql_item_keys[j].ch == cls->transfer_log_format[i]) {
888 /* Yes, this key is one of the configured keys. 937 /* Yes, this key is one of the configured keys.
889 * Call the key's function and put the returned value into 'formatted_item' */ 938 * Call the key's function and put the returned value into 'formatted_item' */
890 formatted_item = log_mysql_item_keys[j].func(log_mysql_item_keys[j].want_orig_default ? orig : r, ""); 939 formatted_item = log_mysql_item_keys[j].func(log_mysql_item_keys[j].want_orig_default ? orig : r, "");
@@ -894,91 +943,134 @@ int log_mysql_transaction(request_rec *orig)
894 formatted_item = ""; 943 formatted_item = "";
895 } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_mysql_item_keys[j].string_contents) { 944 } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_mysql_item_keys[j].string_contents) {
896 /* If apache tried to log a '-' character for a numeric field, convert that to a zero 945 /* If apache tried to log a '-' character for a numeric field, convert that to a zero
897 * because the database expects an integer. */ 946 * because the database expects a numeral and will reject the '-' character. */
898 formatted_item = "0"; 947 formatted_item = "0";
899 } 948 }
900 949
901 /* Append the fieldname and value-to-insert to teh appropriate strings, quoting stringvals with ' as appropriate */ 950 /* Append the fieldname and value-to-insert to the appropriate strings, quoting stringvals with ' as appropriate */
902 fields = pstrcat(orig->pool, fields, (i > 0 ? "," : ""), log_mysql_item_keys[j].sql_field_name, NULL); 951 fields = pstrcat(r->pool, fields, (i > 0 ? "," : ""),
903 values = pstrcat(orig->pool, values, (i > 0 ? "," : ""), (log_mysql_item_keys[j].string_contents ? "'" : ""), mysql_escape_log(formatted_item, orig->pool), (log_mysql_item_keys[j].string_contents ? "'" : ""), NULL); 952 log_mysql_item_keys[j].sql_field_name, NULL);
953
954 values = pstrcat(r->pool, values, (i > 0 ? "," : ""),
955 (log_mysql_item_keys[j].string_contents ? "'" : ""),
956 escape_query(formatted_item, r->pool),
957 (log_mysql_item_keys[j].string_contents ? "'" : ""), NULL);
904 break; 958 break;
905 } 959 }
906 j++; 960 j++;
961
907 } 962 }
908 } 963 }
909 964
910 /* Set up the actual INSERT statement and execute it. */ 965
911 str = pstrcat(orig->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL); 966 /* Is this virtual server's table flagged as made? We flag it as such in order
967 * to avoid extra processing with each request. If it's not flagged as made,
968 * set up the CREATE string.
969 */
970 if ((cls->table_made != 1) && (cls->create_tables != 0)) {
971 char *createprefix = "create table if not exists ";
972 char *createsuffix =
973 " (agent varchar(255),\
974 bytes_sent int unsigned,\
975 child_pid smallint unsigned,\
976 cookie varchar(255),\
977 request_file varchar(255),\
978 referer varchar(255),\
979 remote_host varchar(50),\
980 remote_logname varchar(50),\
981 remote_user varchar(50),\
982 request_duration smallint unsigned,\
983 request_line varchar(255),\
984 request_method varchar(6),\
985 request_protocol varchar(10),\
986 request_time char(28),\
987 request_uri varchar(50),\
988 server_port smallint unsigned,\
989 ssl_cipher varchar(25),\
990 ssl_keysize smallint unsigned,\
991 ssl_maxkeysize smallint unsigned,\
992 status smallint unsigned,\
993 time_stamp int unsigned,\
994 virtual_host varchar(50))";
995
996 /* Find memory long enough to hold the whole CREATE string + \0 */
997 /* old way:
998 * createstring = (char*)ap_palloc(orig->pool,(strlen(createprefix) + strlen(cls->transfer_table_name) + strlen(createsuffix) + 1) * sizeof(char));
999 * strcpy (createstring, createprefix);
1000 * strcat (createstring, cls->transfer_table_name);
1001 * strcat (createstring, createsuffix); */
1002
1003 createstring = ap_pstrcat(orig->pool, createprefix, cls->transfer_table_name, createsuffix, NULL);
1004
1005 #ifdef DEBUG
1006 ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"create string: %s", createstring);
1007 #endif
912 1008
1009 }
1010
1011 /* Set up the actual INSERT statement and escape it. */
1012 str = ap_pstrcat(r->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL);
913 1013
1014 #ifdef DEBUG
1015 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"insert string: %s", str);
1016 #endif
1017
1018
914 /* How's our mysql link integrity? */ 1019 /* How's our mysql link integrity? */
915 if (mysql_log == NULL) { 1020 if (mysql_log == NULL) {
916 1021
917 /* Try to regain the link */ 1022 /* Make a try to establish the link */
918 open_logdb_link(); 1023 open_logdb_link();
919 1024
920 if (mysql_log == NULL) { 1025 if (mysql_log == NULL) {
921 /* Unable to re-establish a DB link, so assume that it's really 1026 /* Unable to re-establish a DB link, so assume that it's really
922 * gone and send the entry to the preserve file instead. */ 1027 * gone and send the entry to the preserve file instead.
923 preserve_entry(r, str); 1028 * Note that we don't keep logging the db error over and over. */
1029 preserve_entry(orig, str);
924 return OK; 1030 return OK;
925 } else { 1031 } else {
926 /* Whew, we got the DB link back */ 1032 /* Whew, we got the DB link back */
927 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection"); 1033 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"httpd child established database connection");
928 safe_mysql_query(orig, str);
929 } 1034 }
930 } else {
931 /* Everything was fine */
932 safe_mysql_query(orig, str);
933 } 1035 }
1036
1037 if ((cls->table_made != 1) && (cls->create_tables != 0)) {
1038 mysql_query(mysql_log,createstring);
1039 cls->table_made = 1;
1040 }
1041
1042 /* Make the insert */
1043 safe_mysql_query(orig, str);
934 1044
1045 return OK;
935 } 1046 }
936 return retvalue;
937} 1047}
938 1048
939 1049
940/* Called on the exit of an httpd child process */
941static void log_mysql_child_exit(server_rec *s, pool *p)
942{
943 mysql_close(mysql_log);
944}
945
946/* Called on the init of an httpd child process */
947static void log_mysql_child_init(server_rec *s, pool *p)
948{
949 int retval;
950
951 retval = open_logdb_link();
952 #ifdef DEBUG
953 if (retval > 0) {
954 ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"MySQL: open_logdb_link successful");
955 }
956 #endif
957}
958 1050
959 1051
960/* The configuration array that sets up the hooks into the module. */ 1052/* The configuration array that sets up the hooks into the module. */
961module mysql_log_module = { 1053module mysql_log_module = {
962 STANDARD_MODULE_STUFF, 1054 STANDARD_MODULE_STUFF,
963 NULL, /* initializer */ 1055 NULL, /* module initializer */
964 NULL, /* create per-dir config */ 1056 NULL, /* create per-dir config */
965 NULL, /* merge per-dir config */ 1057 NULL, /* merge per-dir config */
966 log_mysql_make_state, /* server config */ 1058 log_mysql_make_state, /* create server config */
967 NULL, /* merge server config */ 1059 NULL, /* merge server config */
968 log_mysql_cmds, /* command table */ 1060 log_mysql_cmds, /* config directive table */
969 NULL, /* handlers */ 1061 NULL, /* [9] content handlers */
970 NULL, /* filename translation */ 1062 NULL, /* [2] URI-to-filename translation */
971 NULL, /* check_user_id */ 1063 NULL, /* [5] check/validate user_id */
972 NULL, /* check auth */ 1064 NULL, /* [6] check authorization */
973 NULL, /* check access */ 1065 NULL, /* [4] check access by host */
974 NULL, /* type_checker */ 1066 NULL, /* [7] MIME type checker/setter */
975 NULL, /* fixups */ 1067 NULL, /* [8] fixups */
976 log_mysql_transaction, /* logger */ 1068 log_mysql_transaction, /* [10] logger */
977 NULL, /* header parser */ 1069 NULL /* [3] header parser */
978#if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */ 1070#if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */
979 log_mysql_child_init, /* child_init */ 1071 ,log_mysql_child_init, /* child process initializer */
980 log_mysql_child_exit, /* process exit/cleanup */ 1072 log_mysql_child_exit, /* process exit/cleanup */
981 NULL /* [#0] post read-request */ 1073 NULL /* [1] post read-request */
982#endif 1074#endif
983 1075
984}; 1076};