summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorChristopher Powell <chris@grubbybaby.com>2001-11-30 08:29:04 (GMT)
committer Christopher Powell <chris@grubbybaby.com>2001-11-30 08:29:04 (GMT)
commit69fa0ad0d21465573b9dcb07c87ae27f993dfe31 (patch)
treec05c2d94edd4d7ff330272e06e8c320d0a504f80
parent92d85f793b1a41bbbde1811004ae2708a47a44aa (diff)
A lot of code cleanup and tweaking, plus cookie logging:1.10
* New capability: log mod_usertrack cookies. * Some code cleanup and commenting. * Referer and User-Agent now set to want_orig=1 ( a very minor detail ) * Corrected mysql_escape_log to properly check for and escape strings with 'dangerous' characters. It appears that it was doing this incorrectly before. * Deleted log_mysql_child(), a function that was never called.
-rw-r--r--CHANGELOG14
-rw-r--r--mod_log_sql.c311
2 files changed, 194 insertions, 131 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 674fbec..9f2295b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,12 +1,24 @@
1$Id: CHANGELOG,v 1.1 2001/11/28 05:26:54 helios Exp $ 1$Id: CHANGELOG,v 1.2 2001/11/30 08:29:04 helios Stab $
2 2
3 3
4TODO: 4TODO:
5* Full commenting of the code. 5* Full commenting of the code.
6* Bounds checking on all data prior to INSERT
6 7
7 8
8CHANGES: 9CHANGES:
9 10
111.10:
12
13* New capability: log mod_usertrack cookies.
14* Some code cleanup and commenting.
15* Referer and User-Agent now set to want_orig=1 ( a very minor detail )
16* Corrected mysql_escape_log to properly check for and escape strings
17 with `dangerous' characters. It appears that it was doing this
18 incorrectly before.
19* Deleted log_mysql_child(), a function that was never called.
20
21
101.09: 221.09:
11 23
12* If the MySQL INSERT causes an error, we re-try that INSERT after 24* If the MySQL INSERT causes an error, we re-try that INSERT after
diff --git a/mod_log_sql.c b/mod_log_sql.c
index 1493e41..0739372 100644
--- a/mod_log_sql.c
+++ b/mod_log_sql.c
@@ -1,6 +1,7 @@
1/* $Id: mod_log_sql.c,v 1.1 2001/11/28 05:26:55 helios Exp $ 1/* $Id: mod_log_sql.c,v 1.2 2001/11/30 08:29:04 helios Stab $
2 * 2 *
3 * mod_log_mysql.c 3 * mod_log_mysql.c
4 * Release v 1.10
4 * 5 *
5 * Hi, I'm the new maintainer of this code. If you have any questions, 6 * 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 * comments or suggestions (which are always welcome), please contact Chris
@@ -70,15 +71,16 @@
70 */ 71 */
71 72
72 73
74#include <time.h>
75#include <mysql/mysql.h>
76
73#include "httpd.h" 77#include "httpd.h"
74#include "http_config.h" 78#include "http_config.h"
75#include "http_log.h" 79#include "http_log.h"
80#include "http_core.h"
76#if MODULE_MAGIC_NUMBER >= 19980324 81#if MODULE_MAGIC_NUMBER >= 19980324
77#include "ap_compat.h" 82 #include "ap_compat.h"
78#endif 83#endif
79#include "http_core.h"
80#include <time.h>
81#include <mysql/mysql.h>
82 84
83module mysql_log_module; 85module mysql_log_module;
84MYSQL log_sql_server, *mysql_log = NULL; 86MYSQL log_sql_server, *mysql_log = NULL;
@@ -95,26 +97,26 @@ typedef struct {
95 char *transfer_log_format; 97 char *transfer_log_format;
96} log_mysql_state; 98} log_mysql_state;
97 99
98 100/* Defined in /usr/local/Apache/include/ap_mmn.h, 19990320 as of this writing. */
99#if MODULE_MAGIC_NUMBER < 19970103 101#if MODULE_MAGIC_NUMBER < 19970103
100extern const char *log_remote_host(request_rec * r, char *a); 102extern const char *log_remote_host(request_rec *r, char *a);
101extern const char *log_remote_logname(request_rec * r, char *a); 103extern const char *log_remote_logname(request_rec *r, char *a);
102extern const char *log_remote_user(request_rec * r, char *a); 104extern const char *log_remote_user(request_rec *r, char *a);
103extern const char *log_request_time(request_rec * r, char *a); 105extern const char *log_request_time(request_rec *r, char *a);
104extern const char *log_request_timestamp(request_rec * r, char *a); 106extern const char *log_request_timestamp(request_rec *r, char *a);
105extern const char *log_request_duration(request_rec * r, char *a); 107extern const char *log_request_duration(request_rec *r, char *a);
106extern const char *log_request_line(request_rec * r, char *a); 108extern const char *log_request_line(request_rec *r, char *a);
107extern const char *log_request_file(request_rec * r, char *a); 109extern const char *log_request_file(request_rec *r, char *a);
108extern const char *log_request_uri(request_rec * r, char *a); 110extern const char *log_request_uri(request_rec *r, char *a);
109extern const char *log_status(request_rec * r, char *a); 111extern const char *log_status(request_rec *r, char *a);
110extern const char *log_bytes_sent(request_rec * r, char *a); 112extern const char *log_bytes_sent(request_rec *r, char *a);
111extern const char *log_header_in(request_rec * r, char *a); 113extern const char *log_header_in(request_rec *r, char *a);
112extern const char *log_header_out(request_rec * r, char *a); 114extern const char *log_header_out(request_rec *r, char *a);
113extern const char *log_note(request_rec * r, char *a); 115extern const char *log_note(request_rec *r, char *a);
114extern const char *log_env_var(request_rec * r, char *a); 116extern const char *log_env_var(request_rec *r, char *a);
115extern const char *log_virtual_host(request_rec * r, char *a); 117extern const char *log_virtual_host(request_rec *r, char *a);
116extern const char *log_server_port(request_rec * r, char *a); 118extern const char *log_server_port(request_rec *r, char *a);
117extern const char *log_child_pid(request_rec * r, char *a); 119extern const char *log_child_pid(request_rec *r, char *a);
118#else 120#else
119static char *format_integer(pool *p, int i) 121static char *format_integer(pool *p, int i)
120{ 122{
@@ -132,17 +134,22 @@ static char *pfmt(pool *p, int i)
132 } 134 }
133} 135}
134 136
135static const char *log_remote_host(request_rec * r, char *a) 137/* Begin the individual functions that, given a request r,
138 * extract the needed information from it and return the
139 * value to the calling entity.
140 */
141
142static const char *log_remote_host(request_rec *r, char *a)
136{ 143{
137 return (char *) get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); 144 return (char *) get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME);
138} 145}
139 146
140static const char *log_remote_logname(request_rec * r, char *a) 147static const char *log_remote_logname(request_rec *r, char *a)
141{ 148{
142 return (char *) get_remote_logname(r); 149 return (char *) get_remote_logname(r);
143} 150}
144 151
145static const char *log_remote_user(request_rec * r, char *a) 152static const char *log_remote_user(request_rec *r, char *a)
146{ 153{
147 char *rvalue = r->connection->user; 154 char *rvalue = r->connection->user;
148 155
@@ -154,27 +161,27 @@ static const char *log_remote_user(request_rec * r, char *a)
154 return rvalue; 161 return rvalue;
155} 162}
156 163
157static const char *log_request_line(request_rec * r, char *a) 164static const char *log_request_line(request_rec *r, char *a)
158{ 165{
159 return r->the_request; 166 return r->the_request;
160} 167}
161 168
162static const char *log_request_file(request_rec * r, char *a) 169static const char *log_request_file(request_rec *r, char *a)
163{ 170{
164 return r->filename; 171 return r->filename;
165} 172}
166 173
167static const char *log_request_uri(request_rec * r, char *a) 174static const char *log_request_uri(request_rec *r, char *a)
168{ 175{
169 return r->uri; 176 return r->uri;
170} 177}
171 178
172static const char *log_status(request_rec * r, char *a) 179static const char *log_status(request_rec *r, char *a)
173{ 180{
174 return pfmt(r->pool, r->status); 181 return pfmt(r->pool, r->status);
175} 182}
176 183
177static const char *log_bytes_sent(request_rec * r, char *a) 184static const char *log_bytes_sent(request_rec *r, char *a)
178{ 185{
179 if (!r->sent_bodyct) { 186 if (!r->sent_bodyct) {
180 return "-"; 187 return "-";
@@ -187,12 +194,12 @@ static const char *log_bytes_sent(request_rec * r, char *a)
187 } 194 }
188} 195}
189 196
190static const char *log_header_in(request_rec * r, char *a) 197static const char *log_header_in(request_rec *r, char *a)
191{ 198{
192 return table_get(r->headers_in, a); 199 return table_get(r->headers_in, a);
193} 200}
194 201
195static const char *log_header_out(request_rec * r, char *a) 202static const char *log_header_out(request_rec *r, char *a)
196{ 203{
197 const char *cp = table_get(r->headers_out, a); 204 const char *cp = table_get(r->headers_out, a);
198 if (!strcasecmp(a, "Content-type") && r->content_type) { 205 if (!strcasecmp(a, "Content-type") && r->content_type) {
@@ -204,7 +211,7 @@ static const char *log_header_out(request_rec * r, char *a)
204 return table_get(r->err_headers_out, a); 211 return table_get(r->err_headers_out, a);
205} 212}
206 213
207static const char *log_request_time(request_rec * r, char *a) 214static const char *log_request_time(request_rec *r, char *a)
208{ 215{
209 int timz; 216 int timz;
210 struct tm *t; 217 struct tm *t;
@@ -227,7 +234,7 @@ static const char *log_request_time(request_rec * r, char *a)
227 return pstrdup(r->pool, tstr); 234 return pstrdup(r->pool, tstr);
228} 235}
229 236
230static const char *log_request_duration(request_rec * r, char *a) 237static const char *log_request_duration(request_rec *r, char *a)
231{ 238{
232 char duration[22]; /* Long enough for 2^64 */ 239 char duration[22]; /* Long enough for 2^64 */
233 240
@@ -235,12 +242,12 @@ static const char *log_request_duration(request_rec * r, char *a)
235 return pstrdup(r->pool, duration); 242 return pstrdup(r->pool, duration);
236} 243}
237 244
238static const char *log_virtual_host(request_rec * r, char *a) 245static const char *log_virtual_host(request_rec *r, char *a)
239{ 246{
240 return pstrdup(r->pool, r->server->server_hostname); 247 return pstrdup(r->pool, r->server->server_hostname);
241} 248}
242 249
243static const char *log_server_port(request_rec * r, char *a) 250static const char *log_server_port(request_rec *r, char *a)
244{ 251{
245 char portnum[22]; 252 char portnum[22];
246 253
@@ -248,14 +255,14 @@ static const char *log_server_port(request_rec * r, char *a)
248 return pstrdup(r->pool, portnum); 255 return pstrdup(r->pool, portnum);
249} 256}
250 257
251static const char *log_child_pid(request_rec * r, char *a) 258static const char *log_child_pid(request_rec *r, char *a)
252{ 259{
253 char pidnum[22]; 260 char pidnum[22];
254 ap_snprintf(pidnum, sizeof(pidnum), "%ld", (long) getpid()); 261 ap_snprintf(pidnum, sizeof(pidnum), "%ld", (long) getpid());
255 return pstrdup(r->pool, pidnum); 262 return pstrdup(r->pool, pidnum);
256} 263}
257 264
258static const char *log_referer(request_rec * r, char *a) 265static const char *log_referer(request_rec *r, char *a)
259{ 266{
260 const char *tempref; 267 const char *tempref;
261 268
@@ -266,10 +273,9 @@ static const char *log_referer(request_rec * r, char *a)
266 } else { 273 } else {
267 return tempref; 274 return tempref;
268 } 275 }
269
270} 276}
271 277
272static const char *log_agent(request_rec * r, char *a) 278static const char *log_agent(request_rec *r, char *a)
273{ 279{
274 const char *tempag; 280 const char *tempag;
275 281
@@ -282,7 +288,54 @@ static const char *log_agent(request_rec * r, char *a)
282 } 288 }
283} 289}
284 290
285const char *log_request_timestamp(request_rec * r, char *a) 291static const char *log_cookie(request_rec *r, char *a)
292{
293 const char *cookiestr;
294 char *cookieend;
295
296 cookiestr = table_get(r->headers_in, "cookie");
297
298 /* First look for Cookie2: header */
299 if ( (cookiestr = table_get(r->headers_in, "cookie2")) ) {
300 cookieend = strchr(cookiestr, ';');
301 if (cookieend)
302 *cookieend = '\0'; /* Ignore anything after a ; */
303 return cookiestr;
304 }
305
306 /* Then try a Cookie: header */
307 else if ( (cookiestr = table_get(r->headers_in, "cookie")) ) {
308 cookieend = strchr(cookiestr, ';');
309 if (cookieend)
310 *cookieend = '\0';
311 return cookiestr;
312 }
313
314 /* Still none? Use the Set-Cookie: header. I feel a little
315 * guilty about this, because some clients refuse cookies. The
316 * log will in their cases log a ton of different Set-Cookie requests
317 * that aren't being honored. However, it's necessary to insert this
318 * check so that the first request of a series doesn't log a - ...
319 */
320 else if ( (cookiestr = table_get(r->headers_out, "set-cookie")) ) {
321 cookieend = strchr(cookiestr, ';');
322 if (cookieend)
323 *cookieend = '\0';
324 return cookiestr;
325 }
326
327 /* Okay, fine, no eligible headers. Return a - instead.
328 * I /could/ insert a look for the Set-Cookie2: header here, but I think
329 * it would be imprudent. It's apparent that the current browsers don't
330 * support Cookie2 cookies, so why bother logging a bunch of Set-Cookie2:
331 * requests that aren't even going to be honored?
332 */
333 else {
334 return "-";
335 }
336}
337
338const char *log_request_timestamp(request_rec *r, char *a)
286{ 339{
287 char tstr[32]; 340 char tstr[32];
288 341
@@ -290,51 +343,56 @@ const char *log_request_timestamp(request_rec * r, char *a)
290 return pstrdup(r->pool, tstr); 343 return pstrdup(r->pool, tstr);
291} 344}
292 345
293static const char *log_note(request_rec * r, char *a) 346static const char *log_note(request_rec *r, char *a)
294{ 347{
295 return table_get(r->notes, a); 348 return table_get(r->notes, a);
296} 349}
297 350
298static const char *log_env_var(request_rec * r, char *a) 351static const char *log_env_var(request_rec *r, char *a)
299{ 352{
300 return table_get(r->subprocess_env, a); 353 return table_get(r->subprocess_env, a);
301} 354}
302#endif 355#endif
303 356
357
358/* End declarations of various log_ functions */
359
360
304struct log_mysql_item_list { 361struct log_mysql_item_list {
305 char ch; 362 char ch;
306 item_key_func func; 363 item_key_func func;
307 const char *sql_field_name; 364 const char *sql_field_name;
308 int want_orig_default; 365 int want_orig_default;
309 int string_contents; 366 int string_contents;
310} log_mysql_item_keys[] = { 367 } log_mysql_item_keys[] = {
311 368
312 { 'h', log_remote_host, "remote_host", 0, 1 }, 369 { 'A', log_agent, "agent", 1, 1 },
313 { 'l', log_remote_logname, "remote_logname", 0, 1 }, 370 { 'b', log_bytes_sent, "bytes_sent", 0, 0 },
314 { 'u', log_remote_user, "remote_user", 0, 1 }, 371 { 'c', log_cookie, "cookie", 0, 1 },
315 { 't', log_request_time, "request_time", 0, 1 }, 372 { 'e', log_env_var, "env_var", 0, 1 },
316 { 'S', log_request_timestamp, "time_stamp", 0, 0 }, 373 { 'f', log_request_file, "request_file", 0, 1 },
317 { 'T', log_request_duration, "request_duration", 1, 0 }, 374 { 'h', log_remote_host, "remote_host", 0, 1 },
318 { 'r', log_request_line, "request_line", 1, 1 }, 375 { 'i', log_header_in, "header_in", 0, 1 },
319 { 'f', log_request_file, "request_file", 0, 1 }, 376 { 'l', log_remote_logname, "remote_logname", 0, 1 },
320 { 'U', log_request_uri, "request_uri", 1, 1 }, 377 { 'n', log_note, "note", 0, 1 },
321 { 's', log_status, "status", 1, 0 }, 378 { 'o', log_header_out, "header_out", 0, 1 },
322 { 'b', log_bytes_sent, "bytes_sent", 0, 0 }, 379 { 'P', log_child_pid, "child_pid", 0, 0 },
323 { 'i', log_header_in, "header_in", 0, 1 }, 380 { 'p', log_server_port, "server_port", 0, 0 },
324 { 'o', log_header_out, "header_out", 0, 1 }, 381 { 'R', log_referer, "referer", 1, 1 },
325 { 'n', log_note, "note", 0, 1 }, 382 { 'r', log_request_line, "request_line", 1, 1 },
326 { 'e', log_env_var, "env_var", 0, 1 }, 383 { 'S', log_request_timestamp, "time_stamp", 0, 0 },
327 { 'v', log_virtual_host, "virtual_host", 0, 1 }, 384 { 's', log_status, "status", 1, 0 },
328 { 'p', log_server_port, "server_port", 0, 0 }, 385 { 'T', log_request_duration, "request_duration", 1, 0 },
329 { 'P', log_child_pid, "child_pid", 0, 0 }, 386 { 't', log_request_time, "request_time", 0, 1 },
330 { 'R', log_referer, "referer", 0, 1 }, 387 { 'u', log_remote_user, "remote_user", 0, 1 },
331 { 'A', log_agent, "agent", 0, 1 }, 388 { 'U', log_request_uri, "request_uri", 1, 1 },
332 { '\0'} 389 { 'v', log_virtual_host, "virtual_host", 0, 1 },
390 {'\0'}
333}; 391};
334 392
335 393
336/* Routine to escape 'dangerous' characters that would otherwise 394/* Routine to escape 'dangerous' characters that would otherwise
337 * corrupt the INSERT string. 395 * corrupt the INSERT string: ', \, and "
338 */ 396 */
339const char *mysql_escape_log(const char *str, pool *p) 397const char *mysql_escape_log(const char *str, pool *p)
340{ 398{
@@ -344,10 +402,12 @@ const char *mysql_escape_log(const char *str, pool *p)
344 if (!str) { 402 if (!str) {
345 return NULL; 403 return NULL;
346 } 404 }
347 /* first find out if we need to escape */ 405
406 /* First find out if we need to escape. */
348 i = 0; 407 i = 0;
349 while (str[i]) { 408 while (str[i]) {
350 if (str[i] != '\'' || str[i] != '\\' || str[i] != '\"') { 409 /* WAS THIS WRONG in 1.05?!? if (str[i] != '\'' || str[i] != '\\' || str[i] != '\"') { */
410 if (str[i] == '\'' || str[i] == '\\' || str[i] == '\"') {
351 need_to_escape = 1; 411 need_to_escape = 1;
352 break; 412 break;
353 } 413 }
@@ -358,10 +418,15 @@ const char *mysql_escape_log(const char *str, pool *p)
358 char *tmp_str; 418 char *tmp_str;
359 int length = strlen(str); 419 int length = strlen(str);
360 420
361 tmp_str = (char *) palloc(p, length * 2 + 1); /* worst case situation, which wouldn't be a pretty sight :) */ 421 /* Pre-allocate a new string that could hold twice the original, which would only
422 * happen if the whole original string was 'dangerous' characters.
423 */
424 tmp_str = (char *) palloc(p, length *2 + 1);
362 if (!tmp_str) { 425 if (!tmp_str) {
363 return str; 426 return str;
364 } 427 }
428
429 /* Walk through character-by-character, escaping any dangerous characters found. */
365 for (i = 0, j = 0; i < length; i++, j++) { 430 for (i = 0, j = 0; i < length; i++, j++) {
366 switch (str[i]) { 431 switch (str[i]) {
367 case '\'': 432 case '\'':
@@ -373,7 +438,7 @@ const char *mysql_escape_log(const char *str, pool *p)
373 tmp_str[j] = str[i]; 438 tmp_str[j] = str[i];
374 } 439 }
375 } 440 }
376 tmp_str[j] = 0; 441 tmp_str[j] = '\0';
377 return tmp_str; 442 return tmp_str;
378 } else { 443 } else {
379 return str; 444 return str;
@@ -387,7 +452,6 @@ void open_log_dblink()
387 return; 452 return;
388 } 453 }
389 if (log_db_name) { /* open an SQL link */ 454 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); 455 mysql_log = mysql_connect(&log_sql_server, db_host, db_user, db_pwd);
392 if (mysql_log) { /* link opened */ 456 if (mysql_log) { /* link opened */
393 if (mysql_select_db(mysql_log, log_db_name) != 0) { /* unable to select database */ 457 if (mysql_select_db(mysql_log, log_db_name) != 0) { /* unable to select database */
@@ -399,7 +463,7 @@ void open_log_dblink()
399} 463}
400 464
401 465
402void *make_log_mysql_state(pool *p, server_rec * s) 466void *make_log_mysql_state(pool *p, server_rec *s)
403{ 467{
404 log_mysql_state *cls = (log_mysql_state *) palloc(p, sizeof(log_mysql_state)); 468 log_mysql_state *cls = (log_mysql_state *) palloc(p, sizeof(log_mysql_state));
405 469
@@ -411,7 +475,7 @@ void *make_log_mysql_state(pool *p, server_rec * s)
411 return (void *) cls; 475 return (void *) cls;
412} 476}
413 477
414const char *set_referer_log_mysql_table(cmd_parms * parms, void *dummy, char *arg) 478const char *set_referer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
415{ 479{
416 log_mysql_state *cls = get_module_config(parms->server->module_config, 480 log_mysql_state *cls = get_module_config(parms->server->module_config,
417 &mysql_log_module); 481 &mysql_log_module);
@@ -421,7 +485,7 @@ const char *set_referer_log_mysql_table(cmd_parms * parms, void *dummy, char *ar
421} 485}
422 486
423 487
424const char *set_agent_log_mysql_table(cmd_parms * parms, void *dummy, char *arg) 488const char *set_agent_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
425{ 489{
426 log_mysql_state *cls = get_module_config(parms->server->module_config, 490 log_mysql_state *cls = get_module_config(parms->server->module_config,
427 &mysql_log_module); 491 &mysql_log_module);
@@ -431,7 +495,7 @@ const char *set_agent_log_mysql_table(cmd_parms * parms, void *dummy, char *arg)
431} 495}
432 496
433 497
434const char *set_transfer_log_mysql_table(cmd_parms * parms, void *dummy, char *arg) 498const char *set_transfer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
435{ 499{
436 log_mysql_state *cls = get_module_config(parms->server->module_config, 500 log_mysql_state *cls = get_module_config(parms->server->module_config,
437 &mysql_log_module); 501 &mysql_log_module);
@@ -441,7 +505,7 @@ const char *set_transfer_log_mysql_table(cmd_parms * parms, void *dummy, char *a
441} 505}
442 506
443 507
444const char *set_transfer_log_format(cmd_parms * parms, void *dummy, char *arg) 508const char *set_transfer_log_format(cmd_parms *parms, void *dummy, char *arg)
445{ 509{
446 log_mysql_state *cls = get_module_config(parms->server->module_config, 510 log_mysql_state *cls = get_module_config(parms->server->module_config,
447 &mysql_log_module); 511 &mysql_log_module);
@@ -451,13 +515,13 @@ const char *set_transfer_log_format(cmd_parms * parms, void *dummy, char *arg)
451} 515}
452 516
453 517
454const char *set_log_mysql_db(cmd_parms * parms, void *dummy, char *arg) 518const char *set_log_mysql_db(cmd_parms *parms, void *dummy, char *arg)
455{ 519{
456 log_db_name = arg; 520 log_db_name = arg;
457 return NULL; 521 return NULL;
458} 522}
459 523
460const char *set_log_mysql_info(cmd_parms * parms, void *dummy, char *host, char *user, char *pwd) 524const char *set_log_mysql_info(cmd_parms *parms, void *dummy, char *host, char *user, char *pwd)
461{ 525{
462 if (*host != '.') { 526 if (*host != '.') {
463 db_host = host; 527 db_host = host;
@@ -472,7 +536,7 @@ const char *set_log_mysql_info(cmd_parms * parms, void *dummy, char *host, char
472} 536}
473 537
474 538
475const char *add_referer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg) 539const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
476{ 540{
477 char **addme; 541 char **addme;
478 log_mysql_state *cls = get_module_config(parms->server->module_config, 542 log_mysql_state *cls = get_module_config(parms->server->module_config,
@@ -483,7 +547,7 @@ const char *add_referer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg)
483 return NULL; 547 return NULL;
484} 548}
485 549
486const char *add_transfer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg) 550const char *add_transfer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
487{ 551{
488 char **addme; 552 char **addme;
489 log_mysql_state *cls = get_module_config(parms->server->module_config, 553 log_mysql_state *cls = get_module_config(parms->server->module_config,
@@ -494,7 +558,7 @@ const char *add_transfer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg)
494 return NULL; 558 return NULL;
495} 559}
496 560
497const char *add_remhost_mysql_ignore(cmd_parms * parms, void *dummy, char *arg) 561const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
498{ 562{
499 char **addme; 563 char **addme;
500 log_mysql_state *cls = get_module_config(parms->server->module_config, 564 log_mysql_state *cls = get_module_config(parms->server->module_config,
@@ -537,28 +601,7 @@ command_rec log_mysql_cmds[] = {
537}; 601};
538 602
539 603
540void log_mysql_child(void *cmd) 604int safe_mysql_query(request_rec *r, const char *query)
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{ 605{
563 int error = 1; 606 int error = 1;
564 struct timespec delay, remainder; 607 struct timespec delay, remainder;
@@ -566,8 +609,10 @@ int safe_mysql_query(request_rec * r, const char *query)
566 char *str; 609 char *str;
567 void (*handler) (int); 610 void (*handler) (int);
568 611
569 handler = signal(SIGPIPE, SIG_IGN); /* a failed mysql_query() may send a SIGPIPE */ 612 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
613 handler = signal(SIGPIPE, SIG_IGN);
570 614
615 /* If there's no DB link, or if we run the query and it gacks, try to be graceful */
571 if ( !mysql_log || 616 if ( !mysql_log ||
572 ( 617 (
573 (error = mysql_query(mysql_log, query)) && 618 (error = mysql_query(mysql_log, query)) &&
@@ -576,13 +621,12 @@ int safe_mysql_query(request_rec * r, const char *query)
576 ) 621 )
577 622
578 { /* We need to restart the server link */ 623 { /* We need to restart the server link */
579
580 mysql_log = NULL; 624 mysql_log = NULL;
581 log_error("MySQL: connection lost, attempting reconnect", r->server); 625 log_error("MySQL: connection lost, attempting reconnect", r->server);
582 626
583 open_log_dblink(); 627 open_log_dblink();
584 628
585 if (mysql_log == NULL) { /* unable to link */ 629 if (mysql_log == NULL) { /* still unable to link */
586 signal(SIGPIPE, handler); 630 signal(SIGPIPE, handler);
587 log_error("MySQL: reconnect failed.", r->server); 631 log_error("MySQL: reconnect failed.", r->server);
588 return error; 632 return error;
@@ -590,13 +634,13 @@ int safe_mysql_query(request_rec * r, const char *query)
590 634
591 log_error("MySQL: reconnect successful.", r->server); 635 log_error("MySQL: reconnect successful.", r->server);
592 error = mysql_query(mysql_log, query); 636 error = mysql_query(mysql_log, query);
593 } 637 }
594 638
639 /* Restore SIGPIPE to its original handler function */
595 signal(SIGPIPE, handler); 640 signal(SIGPIPE, handler);
596 641
597 if (error) { 642 if (error) {
598 /* Attempt a single re-try... First sleep for a tiny amount of time. */ 643 /* Attempt a single re-try... First sleep for a tiny amount of time. */
599
600 delay.tv_sec = 0; 644 delay.tv_sec = 0;
601 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */ 645 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */
602 ret = nanosleep(&delay, &remainder); 646 ret = nanosleep(&delay, &remainder);
@@ -622,7 +666,7 @@ int safe_mysql_query(request_rec * r, const char *query)
622/* Routine to perform the actual construction and execution of the relevant 666/* Routine to perform the actual construction and execution of the relevant
623 * INSERT statements. 667 * INSERT statements.
624 */ 668 */
625int log_mysql_transaction(request_rec * orig) 669int log_mysql_transaction(request_rec *orig)
626{ 670{
627 char **ptrptr, **ptrptr2; 671 char **ptrptr, **ptrptr2;
628 log_mysql_state *cls = get_module_config(orig->server->module_config, 672 log_mysql_state *cls = get_module_config(orig->server->module_config,
@@ -633,7 +677,7 @@ int log_mysql_transaction(request_rec * orig)
633 int retvalue = DECLINED; 677 int retvalue = DECLINED;
634 int referer_needed, agent_needed, transfer_needed; 678 int referer_needed, agent_needed, transfer_needed;
635 679
636 /* Are there configuration directives for these logs? For each found 680 /* Are there configuration directives for these SQL logs? For each found
637 * config directive that is found, mark that type as 'needed'. 681 * config directive that is found, mark that type as 'needed'.
638 */ 682 */
639 referer_needed = ((cls->referer_table_name[0] != '\0') ? 1 : 0); 683 referer_needed = ((cls->referer_table_name[0] != '\0') ? 1 : 0);
@@ -643,12 +687,14 @@ int log_mysql_transaction(request_rec * orig)
643 if (!referer_needed && !agent_needed && !transfer_needed) { 687 if (!referer_needed && !agent_needed && !transfer_needed) {
644 return OK; 688 return OK;
645 } 689 }
690
646 if (mysql_log == NULL) { /* mysql link not up, hopefully we can do something about it */ 691 if (mysql_log == NULL) { /* mysql link not up, hopefully we can do something about it */
647 open_log_dblink(); 692 open_log_dblink();
648 if (mysql_log == NULL) { 693 if (mysql_log == NULL) {
649 return OK; 694 return OK;
650 } 695 }
651 } 696 }
697
652 for (r = orig; r->next; r = r->next) { 698 for (r = orig; r->next; r = r->next) {
653 continue; 699 continue;
654 } 700 }
@@ -660,12 +706,12 @@ int log_mysql_transaction(request_rec * orig)
660 if (referer != NULL) { 706 if (referer != NULL) {
661 707
662 /* The following is an upsetting mess of pointers, I'm sorry 708 /* The following is an upsetting mess of pointers, I'm sorry
663 Anyone with the motiviation and/or the time should feel free 709 * Anyone with the motiviation and/or the time should feel free
664 to make this cleaner... */ 710 * to make this cleaner... */
665 ptrptr2 = (char **) (cls->referer_ignore_list->elts + (cls->referer_ignore_list->nelts * cls->referer_ignore_list->elt_size)); 711 ptrptr2 = (char **) (cls->referer_ignore_list->elts + (cls->referer_ignore_list->nelts * cls->referer_ignore_list->elt_size));
666 712
667 /* Go through each element of the ignore list and compare it to the 713 /* Go through each element of the ignore list and compare it to the
668 referer_host. If we get a match, return without logging */ 714 * 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)) { 715 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)) { 716 if (strstr(referer, *ptrptr)) {
671 return OK; 717 return OK;
@@ -679,8 +725,10 @@ int log_mysql_transaction(request_rec * orig)
679 /* Log the 'user agent' to its own log if configured to do so. */ 725 /* Log the 'user agent' to its own log if configured to do so. */
680 if (agent_needed) { 726 if (agent_needed) {
681 const char *agent, *str; 727 const char *agent, *str;
728
682 retvalue = OK; 729 retvalue = OK;
683 agent = table_get(orig->headers_in, "User-Agent"); 730 agent = table_get(orig->headers_in, "User-Agent");
731
684 if (agent != NULL) { 732 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); 733 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); 734 safe_mysql_query(orig, str);
@@ -699,12 +747,12 @@ int log_mysql_transaction(request_rec * orig)
699 747
700 748
701 /* The following is a stolen upsetting mess of pointers, I'm sorry 749 /* The following is a stolen upsetting mess of pointers, I'm sorry
702 Anyone with the motiviation and/or the time should feel free 750 * 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 :) */ 751 * 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)); 752 ptrptr2 = (char **) (cls->transfer_ignore_list->elts + (cls->transfer_ignore_list->nelts * cls->transfer_ignore_list->elt_size));
705 753
706 /* Go through each element of the ignore list and compare it to the 754 /* Go through each element of the ignore list and compare it to the
707 request_uri. If we get a match, return without logging */ 755 * request_uri. If we get a match, return without logging */
708 if (r->uri) { 756 if (r->uri) {
709 for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) { 757 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)) { 758 if (strstr(r->uri, *ptrptr)) {
@@ -713,9 +761,8 @@ int log_mysql_transaction(request_rec * orig)
713 } 761 }
714 } 762 }
715 763
716
717 /* Go through each element of the ignore list and compare it to the 764 /* Go through each element of the ignore list and compare it to the
718 remote host. If we get a match, return without logging */ 765 * 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)); 766 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); 767 thehost = get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME);
721 if (thehost) { 768 if (thehost) {
@@ -726,21 +773,23 @@ int log_mysql_transaction(request_rec * orig)
726 } 773 }
727 } 774 }
728 775
729 776 /* If not specified by the user, use the default format */
730 if (cls->transfer_log_format[0] == '\0') { 777 if (cls->transfer_log_format[0] == '\0') {
731 /* If not specified by the user, use the default format */
732 cls->transfer_log_format = "huSUsbTvRA"; 778 cls->transfer_log_format = "huSUsbTvRA";
733 } 779 }
734 length = strlen(cls->transfer_log_format); 780 length = strlen(cls->transfer_log_format);
735 781
736 /* Iterate through the characters and set up the INSERT string according to 782 /* Iterate through the format characters and set up the INSERT string according to
737 * what the user has configured. */ 783 * what the user has configured. */
738 for (i = 0; i < length; i++) { 784 for (i = 0; i < length; i++) {
739 j = 0; 785 j = 0;
740 while (log_mysql_item_keys[j].ch) { 786 while (log_mysql_item_keys[j].ch) {
741 if (log_mysql_item_keys[j].ch == cls->transfer_log_format[i]) { 787 if (log_mysql_item_keys[j].ch == cls->transfer_log_format[i]) {
742 /* Yes, this key is one of the configured keys */ 788 /* Yes, this key is one of the configured keys.
789 * Call the key's function and put the returned value into 'formatted_item' */
743 formatted_item = log_mysql_item_keys[j].func(log_mysql_item_keys[j].want_orig_default ? orig : r, ""); 790 formatted_item = log_mysql_item_keys[j].func(log_mysql_item_keys[j].want_orig_default ? orig : r, "");
791
792 /* Massage 'formatted_item' for proper SQL eligibility... */
744 if (!formatted_item) { 793 if (!formatted_item) {
745 formatted_item = ""; 794 formatted_item = "";
746 } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_mysql_item_keys[j].string_contents) { 795 } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_mysql_item_keys[j].string_contents) {
@@ -748,6 +797,8 @@ int log_mysql_transaction(request_rec * orig)
748 * because the database expects an integer. */ 797 * because the database expects an integer. */
749 formatted_item = "0"; 798 formatted_item = "0";
750 } 799 }
800
801 /* Append the fieldname and value-to-insert to teh appropriate strings, quoting stringvals with ' as appropriate */
751 fields = pstrcat(orig->pool, fields, (i > 0 ? "," : ""), log_mysql_item_keys[j].sql_field_name, NULL); 802 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); 803 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; 804 break;