diff options
Diffstat (limited to 'mod_log_sql.c')
-rw-r--r-- | mod_log_sql.c | 311 |
1 files changed, 181 insertions, 130 deletions
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 | ||
83 | module mysql_log_module; | 85 | module mysql_log_module; |
84 | MYSQL log_sql_server, *mysql_log = NULL; | 86 | MYSQL 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 |
100 | extern const char *log_remote_host(request_rec * r, char *a); | 102 | extern const char *log_remote_host(request_rec *r, char *a); |
101 | extern const char *log_remote_logname(request_rec * r, char *a); | 103 | extern const char *log_remote_logname(request_rec *r, char *a); |
102 | extern const char *log_remote_user(request_rec * r, char *a); | 104 | extern const char *log_remote_user(request_rec *r, char *a); |
103 | extern const char *log_request_time(request_rec * r, char *a); | 105 | extern const char *log_request_time(request_rec *r, char *a); |
104 | extern const char *log_request_timestamp(request_rec * r, char *a); | 106 | extern const char *log_request_timestamp(request_rec *r, char *a); |
105 | extern const char *log_request_duration(request_rec * r, char *a); | 107 | extern const char *log_request_duration(request_rec *r, char *a); |
106 | extern const char *log_request_line(request_rec * r, char *a); | 108 | extern const char *log_request_line(request_rec *r, char *a); |
107 | extern const char *log_request_file(request_rec * r, char *a); | 109 | extern const char *log_request_file(request_rec *r, char *a); |
108 | extern const char *log_request_uri(request_rec * r, char *a); | 110 | extern const char *log_request_uri(request_rec *r, char *a); |
109 | extern const char *log_status(request_rec * r, char *a); | 111 | extern const char *log_status(request_rec *r, char *a); |
110 | extern const char *log_bytes_sent(request_rec * r, char *a); | 112 | extern const char *log_bytes_sent(request_rec *r, char *a); |
111 | extern const char *log_header_in(request_rec * r, char *a); | 113 | extern const char *log_header_in(request_rec *r, char *a); |
112 | extern const char *log_header_out(request_rec * r, char *a); | 114 | extern const char *log_header_out(request_rec *r, char *a); |
113 | extern const char *log_note(request_rec * r, char *a); | 115 | extern const char *log_note(request_rec *r, char *a); |
114 | extern const char *log_env_var(request_rec * r, char *a); | 116 | extern const char *log_env_var(request_rec *r, char *a); |
115 | extern const char *log_virtual_host(request_rec * r, char *a); | 117 | extern const char *log_virtual_host(request_rec *r, char *a); |
116 | extern const char *log_server_port(request_rec * r, char *a); | 118 | extern const char *log_server_port(request_rec *r, char *a); |
117 | extern const char *log_child_pid(request_rec * r, char *a); | 119 | extern const char *log_child_pid(request_rec *r, char *a); |
118 | #else | 120 | #else |
119 | static char *format_integer(pool *p, int i) | 121 | static 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 | ||
135 | static 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 | |||
142 | static 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 | ||
140 | static const char *log_remote_logname(request_rec * r, char *a) | 147 | static 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 | ||
145 | static const char *log_remote_user(request_rec * r, char *a) | 152 | static 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 | ||
157 | static const char *log_request_line(request_rec * r, char *a) | 164 | static 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 | ||
162 | static const char *log_request_file(request_rec * r, char *a) | 169 | static const char *log_request_file(request_rec *r, char *a) |
163 | { | 170 | { |
164 | return r->filename; | 171 | return r->filename; |
165 | } | 172 | } |
166 | 173 | ||
167 | static const char *log_request_uri(request_rec * r, char *a) | 174 | static const char *log_request_uri(request_rec *r, char *a) |
168 | { | 175 | { |
169 | return r->uri; | 176 | return r->uri; |
170 | } | 177 | } |
171 | 178 | ||
172 | static const char *log_status(request_rec * r, char *a) | 179 | static 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 | ||
177 | static const char *log_bytes_sent(request_rec * r, char *a) | 184 | static 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 | ||
190 | static const char *log_header_in(request_rec * r, char *a) | 197 | static 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 | ||
195 | static const char *log_header_out(request_rec * r, char *a) | 202 | static 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 | ||
207 | static const char *log_request_time(request_rec * r, char *a) | 214 | static 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 | ||
230 | static const char *log_request_duration(request_rec * r, char *a) | 237 | static 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 | ||
238 | static const char *log_virtual_host(request_rec * r, char *a) | 245 | static 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 | ||
243 | static const char *log_server_port(request_rec * r, char *a) | 250 | static 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 | ||
251 | static const char *log_child_pid(request_rec * r, char *a) | 258 | static 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 | ||
258 | static const char *log_referer(request_rec * r, char *a) | 265 | static 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 | ||
272 | static const char *log_agent(request_rec * r, char *a) | 278 | static 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 | ||
285 | const char *log_request_timestamp(request_rec * r, char *a) | 291 | static 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 | |||
338 | const 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 | ||
293 | static const char *log_note(request_rec * r, char *a) | 346 | static 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 | ||
298 | static const char *log_env_var(request_rec * r, char *a) | 351 | static 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 | |||
304 | struct log_mysql_item_list { | 361 | struct 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 | */ |
339 | const char *mysql_escape_log(const char *str, pool *p) | 397 | const 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 | ||
402 | void *make_log_mysql_state(pool *p, server_rec * s) | 466 | void *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 | ||
414 | const char *set_referer_log_mysql_table(cmd_parms * parms, void *dummy, char *arg) | 478 | const 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 | ||
424 | const char *set_agent_log_mysql_table(cmd_parms * parms, void *dummy, char *arg) | 488 | const 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 | ||
434 | const char *set_transfer_log_mysql_table(cmd_parms * parms, void *dummy, char *arg) | 498 | const 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 | ||
444 | const char *set_transfer_log_format(cmd_parms * parms, void *dummy, char *arg) | 508 | const 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 | ||
454 | const char *set_log_mysql_db(cmd_parms * parms, void *dummy, char *arg) | 518 | const 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 | ||
460 | const char *set_log_mysql_info(cmd_parms * parms, void *dummy, char *host, char *user, char *pwd) | 524 | const 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 | ||
475 | const char *add_referer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg) | 539 | const 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 | ||
486 | const char *add_transfer_mysql_ignore(cmd_parms * parms, void *dummy, char *arg) | 550 | const 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 | ||
497 | const char *add_remhost_mysql_ignore(cmd_parms * parms, void *dummy, char *arg) | 561 | const 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 | ||
540 | void log_mysql_child(void *cmd) | 604 | int 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 | |||
561 | int 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 | */ |
625 | int log_mysql_transaction(request_rec * orig) | 669 | int 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; |