summaryrefslogtreecommitdiffstatsabout
path: root/mod_log_sql.c
diff options
context:
space:
mode:
Diffstat (limited to 'mod_log_sql.c')
-rw-r--r--mod_log_sql.c786
1 files changed, 786 insertions, 0 deletions
diff --git a/mod_log_sql.c b/mod_log_sql.c
new file mode 100644
index 0000000..1493e41
--- /dev/null
+++ b/mod_log_sql.c
@@ -0,0 +1,786 @@
1/* $Id: mod_log_sql.c,v 1.1 2001/11/28 05:26:55 helios Exp $
2 *
3 * mod_log_mysql.c
4 *
5 * Hi, I'm the new maintainer of this code. If you have any questions,
6 * comments or suggestions (which are always welcome), please contact Chris
7 * Powell <chris@grubbybaby.com>. This code still falls under the rules of
8 * the Apache license, and all credit for the code up to my changes is still
9 * preserved below.
10 *
11 * ====================================================================
12 *
13 * The original preface from version 1.05: This module was patched, wrapped
14 * and coded by Zeev Suraski <bourbon@netvision.net.il>
15 *
16 * It may be used freely, with the same restrictions as its predecessors
17 * (specified below). This module is based on code from standard apache
18 * modules. Their copyright notice follows.
19 *
20 * ====================================================================
21 * Copyright (c) 1995-1997 The Apache Group. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 *
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 *
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in
32 * the documentation and/or other materials provided with the
33 * distribution.
34 *
35 * 3. All advertising materials mentioning features or use of this
36 * software must display the following acknowledgment:
37 * "This product includes software developed by the Apache Group
38 * for use in the Apache HTTP server project (http://www.apache.org/)."
39 *
40 * 4. The names "Apache Server" and "Apache Group" must not be used to
41 * endorse or promote products derived from this software without
42 * prior written permission.
43 *
44 * 5. Redistributions of any form whatsoever must retain the following
45 * acknowledgment:
46 * "This product includes software developed by the Apache Group
47 * for use in the Apache HTTP server project (http://www.apache.org/)."
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
50 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
53 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
58 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
60 * OF THE POSSIBILITY OF SUCH DAMAGE.
61 * ====================================================================
62 *
63 * This software consists of voluntary contributions made by many
64 * individuals on behalf of the Apache Group and was originally based
65 * on public domain software written at the National Center for
66 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
67 * For more information on the Apache Group and the Apache HTTP server
68 * project, please see <http://www.apache.org/>.
69 *
70 */
71
72
73#include "httpd.h"
74#include "http_config.h"
75#include "http_log.h"
76#if MODULE_MAGIC_NUMBER >= 19980324
77#include "ap_compat.h"
78#endif
79#include "http_core.h"
80#include <time.h>
81#include <mysql/mysql.h>
82
83module mysql_log_module;
84MYSQL log_sql_server, *mysql_log = NULL;
85char *log_db_name = NULL, *db_host = NULL, *db_user = NULL, *db_pwd = NULL;
86
87#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
88
89typedef const char *(*item_key_func) (request_rec *, char *);
90typedef struct {
91 char *referer_table_name, *agent_table_name, *transfer_table_name;
92 array_header *referer_ignore_list;
93 array_header *transfer_ignore_list;
94 array_header *remhost_ignore_list;
95 char *transfer_log_format;
96} log_mysql_state;
97
98
99#if MODULE_MAGIC_NUMBER < 19970103
100extern const char *log_remote_host(request_rec * r, char *a);
101extern const char *log_remote_logname(request_rec * r, char *a);
102extern const char *log_remote_user(request_rec * r, char *a);
103extern const char *log_request_time(request_rec * r, char *a);
104extern const char *log_request_timestamp(request_rec * r, char *a);
105extern const char *log_request_duration(request_rec * r, char *a);
106extern const char *log_request_line(request_rec * r, char *a);
107extern const char *log_request_file(request_rec * r, char *a);
108extern const char *log_request_uri(request_rec * r, char *a);
109extern const char *log_status(request_rec * r, char *a);
110extern const char *log_bytes_sent(request_rec * r, char *a);
111extern const char *log_header_in(request_rec * r, char *a);
112extern const char *log_header_out(request_rec * r, char *a);
113extern const char *log_note(request_rec * r, char *a);
114extern const char *log_env_var(request_rec * r, char *a);
115extern const char *log_virtual_host(request_rec * r, char *a);
116extern const char *log_server_port(request_rec * r, char *a);
117extern const char *log_child_pid(request_rec * r, char *a);
118#else
119static char *format_integer(pool *p, int i)
120{
121 char dummy[40];
122 ap_snprintf(dummy, sizeof(dummy), "%d", i);
123 return pstrdup(p, dummy);
124}
125
126static char *pfmt(pool *p, int i)
127{
128 if (i <= 0) {
129 return "-";
130 } else {
131 return format_integer(p, i);
132 }
133}
134
135static const char *log_remote_host(request_rec * r, char *a)
136{
137 return (char *) get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME);
138}
139
140static const char *log_remote_logname(request_rec * r, char *a)
141{
142 return (char *) get_remote_logname(r);
143}
144
145static const char *log_remote_user(request_rec * r, char *a)
146{
147 char *rvalue = r->connection->user;
148
149 if (rvalue == NULL) {
150 rvalue = "-";
151 } else if (strlen(rvalue) == 0) {
152 rvalue = "\"\"";
153 }
154 return rvalue;
155}
156
157static const char *log_request_line(request_rec * r, char *a)
158{
159 return r->the_request;
160}
161
162static const char *log_request_file(request_rec * r, char *a)
163{
164 return r->filename;
165}
166
167static const char *log_request_uri(request_rec * r, char *a)
168{
169 return r->uri;
170}
171
172static const char *log_status(request_rec * r, char *a)
173{
174 return pfmt(r->pool, r->status);
175}
176
177static const char *log_bytes_sent(request_rec * r, char *a)
178{
179 if (!r->sent_bodyct) {
180 return "-";
181 } else {
182 long int bs;
183 char dummy[40];
184 bgetopt(r->connection->client, BO_BYTECT, &bs);
185 ap_snprintf(dummy, sizeof(dummy), "%ld", bs);
186 return pstrdup(r->pool, dummy);
187 }
188}
189
190static const char *log_header_in(request_rec * r, char *a)
191{
192 return table_get(r->headers_in, a);
193}
194
195static const char *log_header_out(request_rec * r, char *a)
196{
197 const char *cp = table_get(r->headers_out, a);
198 if (!strcasecmp(a, "Content-type") && r->content_type) {
199 cp = r->content_type;
200 }
201 if (cp) {
202 return cp;
203 }
204 return table_get(r->err_headers_out, a);
205}
206
207static const char *log_request_time(request_rec * r, char *a)
208{
209 int timz;
210 struct tm *t;
211 char tstr[MAX_STRING_LEN];
212
213 t = get_gmtoff(&timz);
214
215 if (a && *a) { /* Custom format */
216 strftime(tstr, MAX_STRING_LEN, a, t);
217 } else { /* CLF format */
218 char sign = (timz < 0 ? '-' : '+');
219
220 if (timz < 0) {
221 timz = -timz;
222 }
223 strftime(tstr, MAX_STRING_LEN, "[%d/%b/%Y:%H:%M:%S ", t);
224 ap_snprintf(tstr + strlen(tstr), sizeof(tstr) - strlen(tstr), "%c%.2d%.2d]", sign, timz / 60, timz % 60);
225 }
226
227 return pstrdup(r->pool, tstr);
228}
229
230static const char *log_request_duration(request_rec * r, char *a)
231{
232 char duration[22]; /* Long enough for 2^64 */
233
234 ap_snprintf(duration, sizeof(duration), "%ld", time(NULL) - r->request_time);
235 return pstrdup(r->pool, duration);
236}
237
238static const char *log_virtual_host(request_rec * r, char *a)
239{
240 return pstrdup(r->pool, r->server->server_hostname);
241}
242
243static const char *log_server_port(request_rec * r, char *a)
244{
245 char portnum[22];
246
247 ap_snprintf(portnum, sizeof(portnum), "%u", r->server->port);
248 return pstrdup(r->pool, portnum);
249}
250
251static const char *log_child_pid(request_rec * r, char *a)
252{
253 char pidnum[22];
254 ap_snprintf(pidnum, sizeof(pidnum), "%ld", (long) getpid());
255 return pstrdup(r->pool, pidnum);
256}
257
258static const char *log_referer(request_rec * r, char *a)
259{
260 const char *tempref;
261
262 tempref = table_get(r->headers_in, "Referer");
263 if (!tempref)
264 {
265 return "-";
266 } else {
267 return tempref;
268 }
269
270}
271
272static const char *log_agent(request_rec * r, char *a)
273{
274 const char *tempag;
275
276 tempag = table_get(r->headers_in, "User-Agent");
277 if (!tempag)
278 {
279 return "-";
280 } else {
281 return tempag;
282 }
283}
284
285const char *log_request_timestamp(request_rec * r, char *a)
286{
287 char tstr[32];
288
289 snprintf(tstr, 32, "%ld", time(NULL));
290 return pstrdup(r->pool, tstr);
291}
292
293static const char *log_note(request_rec * r, char *a)
294{
295 return table_get(r->notes, a);
296}
297
298static const char *log_env_var(request_rec * r, char *a)
299{
300 return table_get(r->subprocess_env, a);
301}
302#endif
303
304struct log_mysql_item_list {
305 char ch;
306 item_key_func func;
307 const char *sql_field_name;
308 int want_orig_default;
309 int string_contents;
310} log_mysql_item_keys[] = {
311
312 { 'h', log_remote_host, "remote_host", 0, 1 },
313 { 'l', log_remote_logname, "remote_logname", 0, 1 },
314 { 'u', log_remote_user, "remote_user", 0, 1 },
315 { 't', log_request_time, "request_time", 0, 1 },
316 { 'S', log_request_timestamp, "time_stamp", 0, 0 },
317 { 'T', log_request_duration, "request_duration", 1, 0 },
318 { 'r', log_request_line, "request_line", 1, 1 },
319 { 'f', log_request_file, "request_file", 0, 1 },
320 { 'U', log_request_uri, "request_uri", 1, 1 },
321 { 's', log_status, "status", 1, 0 },
322 { 'b', log_bytes_sent, "bytes_sent", 0, 0 },
323 { 'i', log_header_in, "header_in", 0, 1 },
324 { 'o', log_header_out, "header_out", 0, 1 },
325 { 'n', log_note, "note", 0, 1 },
326 { 'e', log_env_var, "env_var", 0, 1 },
327 { 'v', log_virtual_host, "virtual_host", 0, 1 },
328 { 'p', log_server_port, "server_port", 0, 0 },
329 { 'P', log_child_pid, "child_pid", 0, 0 },
330 { 'R', log_referer, "referer", 0, 1 },
331 { 'A', log_agent, "agent", 0, 1 },
332 { '\0'}
333};
334
335
336/* Routine to escape 'dangerous' characters that would otherwise
337 * corrupt the INSERT string.
338 */
339const char *mysql_escape_log(const char *str, pool *p)
340{
341 register int i = 0, j = 0;
342 int need_to_escape = 0;
343
344 if (!str) {
345 return NULL;
346 }
347 /* first find out if we need to escape */
348 i = 0;
349 while (str[i]) {
350 if (str[i] != '\'' || str[i] != '\\' || str[i] != '\"') {
351 need_to_escape = 1;
352 break;
353 }
354 i++;
355 }
356
357 if (need_to_escape) {
358 char *tmp_str;
359 int length = strlen(str);
360
361 tmp_str = (char *) palloc(p, length * 2 + 1); /* worst case situation, which wouldn't be a pretty sight :) */
362 if (!tmp_str) {
363 return str;
364 }
365 for (i = 0, j = 0; i < length; i++, j++) {
366 switch (str[i]) {
367 case '\'':
368 case '\"':
369 case '\\':
370 tmp_str[j] = '\\';
371 j++;
372 default:
373 tmp_str[j] = str[i];
374 }
375 }
376 tmp_str[j] = 0;
377 return tmp_str;
378 } else {
379 return str;
380 }
381}
382
383
384void open_log_dblink()
385{
386 if (mysql_log != NULL) { /* virtual database link shared with main server */
387 return;
388 }
389 if (log_db_name) { /* open an SQL link */
390 /* link to the MySQL database and register its cleanup!@$ */
391 mysql_log = mysql_connect(&log_sql_server, db_host, db_user, db_pwd);
392 if (mysql_log) { /* link opened */
393 if (mysql_select_db(mysql_log, log_db_name) != 0) { /* unable to select database */
394 mysql_close(mysql_log);
395 mysql_log = NULL;
396 }
397 }
398 }
399}
400
401
402void *make_log_mysql_state(pool *p, server_rec * s)
403{
404 log_mysql_state *cls = (log_mysql_state *) palloc(p, sizeof(log_mysql_state));
405
406 cls->referer_table_name = cls->agent_table_name = cls->transfer_table_name = "";
407 cls->referer_ignore_list = make_array(p, 1, sizeof(char *));
408 cls->transfer_ignore_list = make_array(p, 1, sizeof(char *));
409 cls->remhost_ignore_list = make_array(p, 1, sizeof(char *));
410 cls->transfer_log_format = "";
411 return (void *) cls;
412}
413
414const char *set_referer_log_mysql_table(cmd_parms * parms, void *dummy, char *arg)
415{
416 log_mysql_state *cls = get_module_config(parms->server->module_config,
417 &mysql_log_module);
418
419 cls->referer_table_name = arg;
420 return NULL;
421}
422
423
424const char *set_agent_log_mysql_table(cmd_parms * parms, void *dummy, char *arg)
425{
426 log_mysql_state *cls = get_module_config(parms->server->module_config,
427 &mysql_log_module);
428
429 cls->agent_table_name = arg;
430 return NULL;
431}
432
433
434const char *set_transfer_log_mysql_table(cmd_parms * parms, void *dummy, char *arg)
435{
436 log_mysql_state *cls = get_module_config(parms->server->module_config,
437 &mysql_log_module);
438
439 cls->transfer_table_name = arg;
440 return NULL;
441}
442
443
444const char *set_transfer_log_format(cmd_parms * parms, void *dummy, char *arg)
445{
446 log_mysql_state *cls = get_module_config(parms->server->module_config,
447 &mysql_log_module);
448
449 cls->transfer_log_format = arg;
450 return NULL;
451}
452
453
454const char *set_log_mysql_db(cmd_parms * parms, void *dummy, char *arg)
455{
456 log_db_name = arg;
457 return NULL;
458}
459
460const char *set_log_mysql_info(cmd_parms * parms, void *dummy, char *host, char *user, char *pwd)
461{
462 if (*host != '.') {
463 db_host = host;
464 }
465 if (*user != '.') {
466 db_user = user;
467 }
468 if (*pwd != '.') {
469 db_pwd = pwd;
470 }
471 return NULL;
472}
473
474
475const char *add_referer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg)
476{
477 char **addme;
478 log_mysql_state *cls = get_module_config(parms->server->module_config,
479 &mysql_log_module);
480
481 addme = push_array(cls->referer_ignore_list);
482 *addme = pstrdup(cls->referer_ignore_list->pool, arg);
483 return NULL;
484}
485
486const char *add_transfer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg)
487{
488 char **addme;
489 log_mysql_state *cls = get_module_config(parms->server->module_config,
490 &mysql_log_module);
491
492 addme = push_array(cls->transfer_ignore_list);
493 *addme = pstrdup(cls->transfer_ignore_list->pool, arg);
494 return NULL;
495}
496
497const char *add_remhost_mysql_ignore(cmd_parms * parms, void *dummy, char *arg)
498{
499 char **addme;
500 log_mysql_state *cls = get_module_config(parms->server->module_config,
501 &mysql_log_module);
502
503 addme = push_array(cls->remhost_ignore_list);
504 *addme = pstrdup(cls->remhost_ignore_list->pool, arg);
505 return NULL;
506}
507
508command_rec log_mysql_cmds[] = {
509 {"RefererLogMySQLTable", set_referer_log_mysql_table, NULL, RSRC_CONF, TAKE1,
510 "the table of the referer log"}
511 ,
512 {"AgentLogMySQLTable", set_agent_log_mysql_table, NULL, RSRC_CONF, TAKE1,
513 "the table of the agent log"}
514 ,
515 {"TransferLogMySQLTable", set_transfer_log_mysql_table, NULL, RSRC_CONF, TAKE1,
516 "the table of the transfer log"}
517 ,
518 {"TransferLogMySQLFormat", set_transfer_log_format, NULL, RSRC_CONF, TAKE1,
519 "specific format for the MySQL transfer log"}
520 ,
521 {"RefererIgnore", add_referer_mysql_ignore, NULL, RSRC_CONF, ITERATE,
522 "referer hostnames to ignore"}
523 ,
524 {"RequestIgnore", add_transfer_mysql_ignore, NULL, RSRC_CONF, ITERATE,
525 "transfer log URIs to ignore"}
526 ,
527 {"RemhostIgnore", add_remhost_mysql_ignore, NULL, RSRC_CONF, ITERATE,
528 "transfer log remote hosts to ignore"}
529 ,
530 {"LogMySQLDB", set_log_mysql_db, NULL, RSRC_CONF, TAKE1,
531 "the database of the referer log"}
532 ,
533 {"LogMySQLInfo", set_log_mysql_info, NULL, RSRC_CONF, TAKE3,
534 "host, user and password for MySQL link"}
535 ,
536 {NULL}
537};
538
539
540void log_mysql_child(void *cmd)
541{
542 /* Child process code for 'RefererLog "|..."';
543 * may want a common framework for this, since I expect it will
544 * be common for other foo-loggers to want this sort of thing...
545 */
546
547 cleanup_for_exec();
548 signal(SIGHUP, SIG_IGN);
549#ifdef __EMX__
550 /* For OS/2 we need to use a '/' */
551 execl(SHELL_PATH, SHELL_PATH, "/c", (char *) cmd, NULL);
552#else
553 execl(SHELL_PATH, SHELL_PATH, "-c", (char *) cmd, NULL);
554#endif
555 perror("execl");
556 fprintf(stderr, "Exec of shell for logging failed!!!\n");
557 exit(1);
558}
559
560
561int safe_mysql_query(request_rec * r, const char *query)
562{
563 int error = 1;
564 struct timespec delay, remainder;
565 int ret;
566 char *str;
567 void (*handler) (int);
568
569 handler = signal(SIGPIPE, SIG_IGN); /* a failed mysql_query() may send a SIGPIPE */
570
571 if ( !mysql_log ||
572 (
573 (error = mysql_query(mysql_log, query)) &&
574 !strcasecmp(mysql_error(mysql_log), "MySQL server has gone away")
575 )
576 )
577
578 { /* We need to restart the server link */
579
580 mysql_log = NULL;
581 log_error("MySQL: connection lost, attempting reconnect", r->server);
582
583 open_log_dblink();
584
585 if (mysql_log == NULL) { /* unable to link */
586 signal(SIGPIPE, handler);
587 log_error("MySQL: reconnect failed.", r->server);
588 return error;
589 }
590
591 log_error("MySQL: reconnect successful.", r->server);
592 error = mysql_query(mysql_log, query);
593 }
594
595 signal(SIGPIPE, handler);
596
597 if (error) {
598 /* Attempt a single re-try... First sleep for a tiny amount of time. */
599
600 delay.tv_sec = 0;
601 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */
602 ret = nanosleep(&delay, &remainder);
603 if (ret && errno != EINTR)
604 perror("nanosleep");
605
606 /* Now re-attempt */
607 error = mysql_query(mysql_log,query);
608
609 if (error) {
610 str = pstrcat(r->pool, "MySQL query failed: ", query, NULL);
611 log_error(str, r->server);
612 str = pstrcat(r->pool, "MySQL failure reason: ", MYSQL_ERROR(mysql_log), NULL);
613 log_error(str, r->server);
614 } else {
615 log_error("MySQL: INSERT successful after a delayed retry.", r->server);
616 }
617 }
618 return error;
619}
620
621
622/* Routine to perform the actual construction and execution of the relevant
623 * INSERT statements.
624 */
625int log_mysql_transaction(request_rec * orig)
626{
627 char **ptrptr, **ptrptr2;
628 log_mysql_state *cls = get_module_config(orig->server->module_config,
629 &mysql_log_module);
630 char *str;
631 const char *referer;
632 request_rec *r;
633 int retvalue = DECLINED;
634 int referer_needed, agent_needed, transfer_needed;
635
636 /* Are there configuration directives for these logs? For each found
637 * config directive that is found, mark that type as 'needed'.
638 */
639 referer_needed = ((cls->referer_table_name[0] != '\0') ? 1 : 0);
640 agent_needed = ((cls->agent_table_name[0] != '\0') ? 1 : 0);
641 transfer_needed = ((cls->transfer_table_name[0] != '\0') ? 1 : 0);
642
643 if (!referer_needed && !agent_needed && !transfer_needed) {
644 return OK;
645 }
646 if (mysql_log == NULL) { /* mysql link not up, hopefully we can do something about it */
647 open_log_dblink();
648 if (mysql_log == NULL) {
649 return OK;
650 }
651 }
652 for (r = orig; r->next; r = r->next) {
653 continue;
654 }
655
656 /* Log the 'referer' to its own log if configured to do so. */
657 if (referer_needed) {
658 retvalue = OK;
659 referer = table_get(orig->headers_in, "Referer");
660 if (referer != NULL) {
661
662 /* The following is an upsetting mess of pointers, I'm sorry
663 Anyone with the motiviation and/or the time should feel free
664 to make this cleaner... */
665 ptrptr2 = (char **) (cls->referer_ignore_list->elts + (cls->referer_ignore_list->nelts * cls->referer_ignore_list->elt_size));
666
667 /* Go through each element of the ignore list and compare it to the
668 referer_host. If we get a match, return without logging */
669 for (ptrptr = (char **) cls->referer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->referer_ignore_list->elt_size)) {
670 if (strstr(referer, *ptrptr)) {
671 return OK;
672 }
673 }
674 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);
675 safe_mysql_query(orig, str);
676 }
677 }
678
679 /* Log the 'user agent' to its own log if configured to do so. */
680 if (agent_needed) {
681 const char *agent, *str;
682 retvalue = OK;
683 agent = table_get(orig->headers_in, "User-Agent");
684 if (agent != NULL) {
685 str = pstrcat(orig->pool, "insert into ", cls->agent_table_name, "(agent,time_stamp) values ('", mysql_escape_log(agent, orig->pool), "',unix_timestamp(now()) )", NULL);
686 safe_mysql_query(orig, str);
687 }
688 }
689
690 /* Log the transfer to its own log if configured to do so. */
691 if (transfer_needed) {
692 const char *thehost;
693
694 char *fields = "", *values = "", *query;
695 const char *formatted_item;
696 int i, j, length;
697
698 retvalue = OK;
699
700
701 /* The following is a stolen upsetting mess of pointers, I'm sorry
702 Anyone with the motiviation and/or the time should feel free
703 to make this cleaner, and while at it, clean the same mess at the RefererLog part :) */
704 ptrptr2 = (char **) (cls->transfer_ignore_list->elts + (cls->transfer_ignore_list->nelts * cls->transfer_ignore_list->elt_size));
705
706 /* Go through each element of the ignore list and compare it to the
707 request_uri. If we get a match, return without logging */
708 if (r->uri) {
709 for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) {
710 if (strstr(r->uri, *ptrptr)) {
711 return retvalue;
712 }
713 }
714 }
715
716
717 /* Go through each element of the ignore list and compare it to the
718 remote host. If we get a match, return without logging */
719 ptrptr2 = (char **) (cls->remhost_ignore_list->elts + (cls->remhost_ignore_list->nelts * cls->remhost_ignore_list->elt_size));
720 thehost = get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME);
721 if (thehost) {
722 for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size)) {
723 if (strstr(thehost, *ptrptr)) {
724 return retvalue;
725 }
726 }
727 }
728
729
730 if (cls->transfer_log_format[0] == '\0') {
731 /* If not specified by the user, use the default format */
732 cls->transfer_log_format = "huSUsbTvRA";
733 }
734 length = strlen(cls->transfer_log_format);
735
736 /* Iterate through the characters and set up the INSERT string according to
737 * what the user has configured. */
738 for (i = 0; i < length; i++) {
739 j = 0;
740 while (log_mysql_item_keys[j].ch) {
741 if (log_mysql_item_keys[j].ch == cls->transfer_log_format[i]) {
742 /* Yes, this key is one of the configured keys */
743 formatted_item = log_mysql_item_keys[j].func(log_mysql_item_keys[j].want_orig_default ? orig : r, "");
744 if (!formatted_item) {
745 formatted_item = "";
746 } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_mysql_item_keys[j].string_contents) {
747 /* If apache tried to log a '-' character for a numeric field, convert that to a zero
748 * because the database expects an integer. */
749 formatted_item = "0";
750 }
751 fields = pstrcat(orig->pool, fields, (i > 0 ? "," : ""), log_mysql_item_keys[j].sql_field_name, NULL);
752 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);
753 break;
754 }
755 j++;
756 }
757 }
758
759 /* Set up the actual INSERT statement and execute it. */
760 query = pstrcat(orig->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL);
761 safe_mysql_query(orig, query);
762
763 }
764 return retvalue;
765}
766
767
768
769module mysql_log_module = {
770 STANDARD_MODULE_STUFF,
771 NULL, /* initializer */
772 NULL, /* create per-dir config */
773 NULL, /* merge per-dir config */
774 make_log_mysql_state, /* server config */
775 NULL, /* merge server config */
776 log_mysql_cmds, /* command table */
777 NULL, /* handlers */
778 NULL, /* filename translation */
779 NULL, /* check_user_id */
780 NULL, /* check auth */
781 NULL, /* check access */
782 NULL, /* type_checker */
783 NULL, /* fixups */
784 log_mysql_transaction, /* logger */
785 NULL /* header parser */
786};