"Fossies" - the Fresh Open Source Software Archive

Member "mod_log_sql-1.101/mod_log_sql.c" (7 Nov 2006, 46559 Bytes) of package /linux/www/apache_httpd_modules/old/mod_log_sql-1.101.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "mod_log_sql.c": 1.100_vs_1.101.

    1 /* $Id: mod_log_sql.c 170 2006-11-07 02:31:26Z urkle@drip.ws $ */
    2 
    3 #if defined(WITH_APACHE20)
    4 #   include "apache20.h"
    5 #elif defined(WITH_APACHE13)
    6 #   include "apache13.h"
    7 #else
    8 #   error Unsupported Apache version
    9 #endif
   10 
   11 #ifdef HAVE_CONFIG_H
   12 /* Undefine these to prevent conflicts between Apache ap_config_auto.h and
   13  * my config.h. Only really needed for Apache < 2.0.48, but it can't hurt.
   14  */
   15 #undef PACKAGE_BUGREPORT
   16 #undef PACKAGE_NAME
   17 #undef PACKAGE_STRING
   18 #undef PACKAGE_TARNAME
   19 #undef PACKAGE_VERSION
   20 
   21 #include "config.h"
   22 #endif
   23 
   24 #if APR_HAVE_UNISTD_H
   25 #include <unistd.h>
   26 #endif
   27 #ifdef HAVE_LIMITS_H
   28 #include <limits.h>
   29 #endif
   30 
   31 #include "mod_log_sql.h"
   32 
   33 /* Configuratino Defaults */
   34 #define DEFAULT_TRANSFER_LOG_FMT    "AbHhmRSsTUuv"
   35 #define DEFAULT_NOTES_TABLE_NAME    "notes"
   36 #define DEFAULT_HIN_TABLE_NAME      "headers_in"
   37 #define DEFAULT_HOUT_TABLE_NAME     "headers_out"
   38 #define DEFAULT_COOKIE_TABLE_NAME   "cookies"
   39 #define DEFAULT_PRESERVE_FILE       "logs/mod_log_sql-preserve"
   40 
   41 /* -------------*
   42  * DECLARATIONS *
   43  * -------------*/
   44 
   45 /* Declare ourselves so the configuration routines can find and know us. */
   46 module AP_MODULE_DECLARE_DATA log_sql_module;
   47 
   48 /* The contents of these are known 'Apache wide' and are not variable
   49  * on a per-virtual-server basis.  Every virtual server 'knows' the
   50  * same versions of these variables.
   51  */
   52 
   53 typedef struct {
   54     int massvirtual;
   55     int createtables;
   56     int forcepreserve;
   57     int disablepreserve;
   58     char *machid;
   59     int announce;
   60     logsql_dbconnection db;
   61     logsql_dbdriver *driver;
   62 } global_config_t;
   63 
   64 static global_config_t global_config;
   65 
   66 /* structure to hold helper function info */
   67 typedef struct {
   68     char key;                   /* item letter character */
   69     logsql_item_func *func; /* its extraction function */
   70     const char *sql_field_name; /* its column in SQL */
   71     int want_orig_default;      /* if it requires the original request prior to internal redirection */
   72     int string_contents;        /* if it returns a string */
   73 } logsql_item;
   74 
   75 /* But the contents of this structure will vary by virtual server.
   76  * This permits each virtual server to vary its configuration slightly
   77  * for per-server customization.
   78  *
   79  * Each child process has its own segregated copy of this structure.
   80  */
   81 typedef struct {
   82     apr_array_header_t *transfer_ignore_list;
   83     apr_array_header_t *transfer_accept_list;
   84     apr_array_header_t *remhost_ignore_list;
   85     apr_array_header_t *notes_list;
   86     apr_array_header_t *hout_list;
   87     apr_array_header_t *hin_list;
   88     apr_array_header_t *cookie_list;
   89     const char *notes_table_name;
   90     const char *hout_table_name;
   91     const char *hin_table_name;
   92     const char *cookie_table_name;
   93     const char *transfer_table_name;
   94     const char *transfer_log_format;
   95     apr_pool_t *parsed_pool;
   96     logsql_item **parsed_log_format;
   97     const char *preserve_file;
   98     const char *cookie_name;
   99 } logsql_state;
  100 
  101 
  102 /* list of "handlers" for log types */
  103 static apr_array_header_t *logsql_item_list;
  104 
  105 /* Registration function for extract functions *
  106  * and update parse cache for transfer_log_format *
  107  * this is exported from the module */
  108 LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p,
  109         char key, logsql_item_func *func, const char *sql_field_name,
  110         int want_orig_default, int string_contents)
  111 {
  112     server_rec *ts;
  113     logsql_item *item;
  114     if (!logsql_item_list)
  115         logsql_item_list = apr_array_make(p,10, sizeof(logsql_item));
  116 
  117     item= apr_array_push(logsql_item_list);
  118     item->key = key;
  119     item->func = func;
  120     item->sql_field_name = sql_field_name;
  121     item->want_orig_default = want_orig_default;
  122     item->string_contents = string_contents;
  123     /* some voodoo here to post parse logitems in all servers *
  124      * so a "cached" list is used in the main logging loop for speed */
  125     for (ts = s; ts; ts = ts->next) {
  126         logsql_state *cfg = ap_get_module_config(ts->module_config,
  127                                 &log_sql_module);
  128         char *pos;
  129 
  130         if (cfg->transfer_log_format) {
  131             if ( (pos = ap_strchr_c(cfg->transfer_log_format,key))!=NULL) {
  132                 cfg->parsed_log_format[pos - cfg->transfer_log_format] = item;
  133             }
  134         }
  135     }
  136 }
  137 
  138 /* Registration function for database drivers */
  139 LOGSQL_DECLARE(void) log_sql_register_driver(apr_pool_t *p,
  140         logsql_dbdriver *driver)
  141 {
  142     global_config.driver = driver;
  143 }
  144 
  145 /* Include all the core extract functions */
  146 #include "functions.h"
  147 #if defined(WITH_APACHE13)
  148 #   include "functions13.h"
  149 #elif defined(WITH_APACHE20)
  150 #   include "functions20.h"
  151 #endif
  152 
  153 static logsql_opendb_ret log_sql_opendb_link(server_rec* s)
  154 {
  155     logsql_opendb_ret result;
  156     if (global_config.driver == NULL) {
  157         return LOGSQL_OPENDB_FAIL;
  158     }
  159     if (global_config.forcepreserve) {
  160         //global_config.db.connected = 1;
  161         return LOGSQL_OPENDB_PRESERVE;
  162     }
  163     if (global_config.db.connected) {
  164         return LOGSQL_OPENDB_ALREADY;
  165     }
  166     /* database
  167         host
  168         user
  169         passwd
  170     */
  171     if (global_config.db.parms) {
  172         result = global_config.driver->connect(s, &global_config.db);
  173         if (result==LOGSQL_OPENDB_FAIL) {
  174             global_config.db.connected = 0;
  175         } else {
  176             global_config.db.connected = 1;
  177         }
  178         return result;
  179     } else {
  180         log_error(APLOG_MARK, APLOG_ERR, 0, s,
  181             "mod_log_sql: insufficient configuration info to establish database link");
  182         return LOGSQL_OPENDB_FAIL;
  183     }
  184 }
  185 
  186 static void preserve_entry(request_rec *r, const char *query)
  187 {
  188     logsql_state *cls = ap_get_module_config(r->server->module_config,
  189                                             &log_sql_module);
  190     #if defined(WITH_APACHE20)
  191         apr_file_t *fp;
  192         apr_status_t result;
  193     #elif defined(WITH_APACHE13)
  194         FILE *fp;
  195         int result;
  196     #endif
  197     /* If preserve file is disabled bail out */
  198     if (global_config.disablepreserve)
  199        return;
  200     #if defined(WITH_APACHE20)
  201         result = apr_file_open(&fp, cls->preserve_file,APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, r->pool);
  202     #elif defined(WITH_APACHE13)
  203         fp = ap_pfopen(r->pool, cls->preserve_file, "a");
  204         result = (fp)?0:errno;
  205     #endif
  206     if (result != APR_SUCCESS) {
  207         log_error(APLOG_MARK, APLOG_ERR, result, r->server,
  208             "attempted append of local preserve file '%s' but failed.",cls->preserve_file);
  209     } else {
  210         #if defined(WITH_APACHE20)
  211             apr_file_printf(fp,"%s;\n", query);
  212             apr_file_close(fp);
  213         #elif defined(WITH_APACHE13)
  214             fprintf(fp,"%s;\n", query);
  215             ap_pfclose(r->pool, fp);
  216         #endif
  217         log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
  218             "mod_log_sql: entry preserved in %s", cls->preserve_file);
  219     }
  220 }
  221 
  222 
  223 /* ------------------------------------------------*
  224  * Command handlers that are called according      *
  225  * to the directives found at Apache runtime.      *
  226  * ------------------------------------------------*/
  227 
  228 
  229 static const char *set_global_flag_slot(cmd_parms *cmd,
  230                                         void *struct_ptr,
  231                                         int flag)
  232 {
  233     void *ptr = &global_config;
  234     int offset = (int)(long)cmd->info;
  235 
  236     *(int *)((char *)ptr + offset) = flag ? 1 : 0;
  237 
  238     return NULL;
  239 }
  240 
  241 static const char *set_global_nmv_flag_slot(cmd_parms *cmd,
  242                                             void *struct_ptr,
  243                                             int flag)
  244 {
  245     if (global_config.massvirtual) {
  246         return apr_psprintf(cmd->pool,
  247             "mod_log_sql: do not set %s when LogSQLMassVirtualHosting(%d) is On.%d:%d",
  248             cmd->cmd->name, global_config.massvirtual,
  249                 (int)(long)&global_config, (int)(long)struct_ptr);
  250     } else {
  251         return set_global_flag_slot(cmd,struct_ptr,flag);
  252     }
  253 }
  254 
  255 static const char *set_global_string_slot(cmd_parms *cmd,
  256                                           void *struct_ptr,
  257                                           const char *arg)
  258 {
  259     void *ptr = &global_config;
  260     int offset = (int)(long)cmd->info;
  261 
  262     *(const char **)((char *)ptr + offset) = apr_pstrdup(cmd->pool,arg);
  263     return NULL;
  264 }
  265 static const char *set_server_string_slot(cmd_parms *cmd,
  266                                              void *struct_ptr,
  267                                              const char *arg)
  268 {
  269     void *ptr = ap_get_module_config(cmd->server->module_config,
  270             &log_sql_module);
  271     int offset = (int)(long)cmd->info;
  272 
  273     *(const char **)((char *)ptr + offset) = arg;
  274 
  275     return NULL;
  276 }
  277 
  278 static const char *set_server_file_slot(cmd_parms *cmd,
  279                                              void *struct_ptr,
  280                                              const char *arg)
  281 {
  282     void *ptr = ap_get_module_config(cmd->server->module_config,
  283             &log_sql_module);
  284     int offset = (int)(long)cmd->info;
  285     const char *path;
  286 
  287     path = ap_server_root_relative(cmd->pool, (char *)arg);
  288 
  289     if (!path) {
  290         return apr_pstrcat(cmd->pool, "Invalid file path ",
  291                            arg, NULL);
  292     }
  293 
  294     *(const char **)((char*)ptr + offset) = path;
  295 
  296     return NULL;
  297 }
  298 
  299 static const char *set_logformat_slot(cmd_parms *cmd,
  300                                              void *struct_ptr,
  301                                              const char *arg)
  302 {
  303     logsql_state *cfg = ap_get_module_config(cmd->server->module_config,
  304                     &log_sql_module);
  305 
  306     cfg->transfer_log_format = arg;
  307 /*  apr_pool_clear(cfg->parsed_pool);*/
  308     cfg->parsed_log_format = apr_pcalloc(cfg->parsed_pool,
  309         strlen(arg) * sizeof(logsql_item *));
  310     return NULL;
  311 }
  312 
  313 static const char *set_server_nmv_string_slot(cmd_parms *parms,
  314                                             void *struct_ptr,
  315                                             const char *arg)
  316 {
  317     if (global_config.massvirtual)
  318         return apr_psprintf(parms->pool,
  319             "mod_log_sql: do not set %s when LogSQLMassVirtualHosting is On.",
  320             parms->cmd->name);
  321     else
  322         return set_server_string_slot(parms,struct_ptr,arg);
  323 }
  324 
  325 /* Set a DB connection parameter */
  326 static const char *set_dbparam(cmd_parms *cmd,
  327                                 void *struct_ptr,
  328                                 const char *key,
  329                                 const char *val)
  330 {
  331     if (!global_config.db.parms) {
  332         global_config.db.parms = apr_table_make(cmd->pool,5);
  333     }
  334     apr_table_set(global_config.db.parms,key,val);
  335     return NULL;
  336 }
  337 
  338 static const char *set_dbparam_slot(cmd_parms *cmd,
  339                                 void *struct_ptr,
  340                                 const char *arg)
  341 {
  342     const char *param = (char *)cmd->info;
  343     set_dbparam(cmd,NULL,param,arg);
  344     return NULL;
  345 }
  346 
  347 /* Sets basic connection info */
  348 static const char *set_log_sql_info(cmd_parms *cmd, void *dummy,
  349                         const char *host, const char *user, const char *pwd)
  350 {
  351     if (!user) { /* user is null, so only one arg passed */
  352         /* TODO: to more error checking/force all params to be set */
  353         apr_uri_t uri;
  354         apr_uri_parse(cmd->pool, host, &uri);
  355         if (uri.scheme) {
  356             set_dbparam(cmd, NULL, "driver", uri.scheme);
  357         }
  358         if (uri.hostname) {
  359             set_dbparam(cmd, NULL, "hostname", uri.hostname);
  360         }
  361         if (uri.user) {
  362             set_dbparam(cmd, NULL, "username", uri.user);
  363         }
  364         if (uri.password) {
  365             set_dbparam(cmd, NULL, "password", uri.password);
  366         }
  367         if (uri.port_str) {
  368             set_dbparam(cmd, NULL, "port", uri.port_str);
  369         }
  370         if (uri.path) {
  371             /* extract Database name */
  372             char *off = ap_strchr(++uri.path,'/');
  373             if (off)
  374                 *off='\0';
  375             set_dbparam(cmd, NULL, "database", uri.path);
  376 
  377         }
  378     } else {
  379         if (*host != '.') {
  380             set_dbparam(cmd, NULL, "hostname", host);
  381         }
  382         if (*user != '.') {
  383             set_dbparam(cmd, NULL, "username", user);
  384         }
  385         if (*pwd != '.') {
  386             set_dbparam(cmd, NULL, "password", pwd);
  387         }
  388     }
  389     return NULL;
  390 }
  391 
  392 static const char *add_server_string_slot(cmd_parms *cmd,
  393                                              void *struct_ptr,
  394                                              const char *arg)
  395 {
  396     char **addme;
  397     void *ptr = ap_get_module_config(cmd->server->module_config,
  398             &log_sql_module);
  399     int offset = (int)(long)cmd->info;
  400     apr_array_header_t *ary = *(apr_array_header_t **)((char *)ptr + offset);
  401     addme = apr_array_push(ary);
  402     *addme = apr_pstrdup(ary->pool, arg);
  403 
  404     return NULL;
  405 }
  406 
  407 /*------------------------------------------------------------*
  408  * Apache-specific hooks into the module code                 *
  409  * that are defined in the array 'mysql_lgog_module' (at EOF) *
  410  *------------------------------------------------------------*/
  411 /* Closing mysql link: child_exit(1.3), pool registration(2.0) */
  412 #if defined(WITH_APACHE20)
  413 static apr_status_t log_sql_close_link(void *data)
  414 {
  415     if (global_config.driver)
  416         global_config.driver->disconnect(&global_config.db);
  417     return APR_SUCCESS;
  418 }
  419 #elif defined(WITH_APACHE13)
  420 static void log_sql_child_exit(server_rec *s, apr_pool_t *p)
  421 {
  422     if (global_config.driver)
  423         global_config.driver->disconnect(&global_config.db);
  424 }
  425 #endif
  426 
  427 /* Child Init */
  428 #if defined(WITH_APACHE20)
  429 static void log_sql_child_init(apr_pool_t *p, server_rec *s)
  430 #elif defined(WITH_APACHE13)
  431 static void log_sql_child_init(server_rec *s, apr_pool_t *p)
  432 #endif
  433 {
  434     logsql_opendb_ret retval;
  435 #   if defined(WITH_APACHE20)
  436     /* Register cleanup hook to close DDB connection (apache 2 doesn't have child_exit) */
  437     apr_pool_cleanup_register(p, NULL, log_sql_close_link, log_sql_close_link);
  438 #   endif
  439     /* Open a link to the database */
  440     retval = log_sql_opendb_link(s);
  441     switch (retval) {
  442     case LOGSQL_OPENDB_FAIL:
  443         if (global_config.driver==NULL) {
  444             log_error(APLOG_MARK, APLOG_ERR, 0, s,
  445                 "mod_log_sql: Driver module not loaded");
  446         } else {
  447             log_error(APLOG_MARK, APLOG_ERR, 0, s,
  448                 "mod_log_sql: child spawned but unable to open database link");
  449         }
  450         break;
  451     case LOGSQL_OPENDB_SUCCESS:
  452     case LOGSQL_OPENDB_ALREADY:
  453         log_error(APLOG_MARK,APLOG_DEBUG,0, s,
  454             "mod_log_sql: open_logdb_link successful");
  455         break;
  456     case LOGSQL_OPENDB_PRESERVE:
  457         log_error(APLOG_MARK,APLOG_DEBUG, 0, s,
  458             "mod_log_sql: open_logdb_link said that preservation is forced");
  459         break;
  460     }
  461 }
  462 
  463 /* post_config / module_init */
  464 #if defined(WITH_APACHE20)
  465 static int log_sql_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
  466 #elif defined(WITH_APACHE13)
  467 static void log_sql_module_init(server_rec *s, apr_pool_t *p)
  468 #endif
  469 {
  470     /* TODO: Add local_address, remote_address, server_name, connection_status */
  471     /* Register handlers */
  472     log_sql_register_item(s,p,'A', extract_agent,             "agent",            1, 1);
  473     log_sql_register_item(s,p,'a', extract_request_query,     "request_args",     1, 1);
  474     log_sql_register_item(s,p,'b', extract_bytes_sent,        "bytes_sent",       0, 0);
  475     log_sql_register_item(s,p,'c', extract_cookie,            "cookie",           0, 1);
  476     /* TODO: Document */
  477     log_sql_register_item(s,p,'f', extract_request_file,      "request_file",     0, 1);
  478     log_sql_register_item(s,p,'H', extract_request_protocol,  "request_protocol", 0, 1);
  479     log_sql_register_item(s,p,'h', extract_remote_host,       "remote_host",      0, 1);
  480     log_sql_register_item(s,p,'I', extract_unique_id,         "id",               0, 1);
  481     log_sql_register_item(s,p,'l', extract_remote_logname,    "remote_logname",   0, 1);
  482     log_sql_register_item(s,p,'m', extract_request_method,    "request_method",   0, 1);
  483     log_sql_register_item(s,p,'M', extract_machine_id,        "machine_id",       0, 1);
  484     log_sql_register_item(s,p,'P', extract_child_pid,         "child_pid",        0, 0);
  485     log_sql_register_item(s,p,'p', extract_server_port,       "server_port",      0, 0);
  486     log_sql_register_item(s,p,'R', extract_referer,           "referer",          1, 1);
  487     log_sql_register_item(s,p,'r', extract_request_line,      "request_line",     1, 1);
  488     log_sql_register_item(s,p,'S', extract_request_timestamp, "time_stamp",       0, 0);
  489     log_sql_register_item(s,p,'s', extract_status,            "status",           1, 0);
  490     log_sql_register_item(s,p,'T', extract_request_duration,  "request_duration", 1, 0);
  491     log_sql_register_item(s,p,'t', extract_request_time,      "request_time",     0, 1);
  492     log_sql_register_item(s,p,'u', extract_remote_user,       "remote_user",      0, 1);
  493     log_sql_register_item(s,p,'U', extract_request_uri,       "request_uri",      1, 1);
  494     log_sql_register_item(s,p,'v', extract_virtual_host,      "virtual_host",     0, 1);
  495     log_sql_register_item(s,p,'V', extract_server_name,       "virtual_host",     0, 1);
  496 
  497     if (global_config.announce) {
  498         ap_add_version_component(p, PACKAGE_NAME"/"PACKAGE_VERSION);
  499     }
  500     /* ap_server_root_relative any default preserve file locations */
  501     {
  502         server_rec *cur_s;
  503         const char *default_p = ap_server_root_relative(p, DEFAULT_PRESERVE_FILE);
  504         for (cur_s = s; cur_s != NULL; cur_s= cur_s->next) {
  505              logsql_state *cls = ap_get_module_config(cur_s->module_config,
  506                                     &log_sql_module);
  507              if (cls->preserve_file == DEFAULT_PRESERVE_FILE)
  508                  cls->preserve_file = default_p;
  509         }
  510     }
  511     global_config.db.p = p;
  512 
  513 #if defined(WITH_APACHE20)
  514     return OK;
  515 #endif
  516 }
  517 
  518 /* This function handles calling the DB module,  handling errors
  519  * of missing tables and lost DB connections, and falling back to
  520  * preserving the DB query.
  521  *
  522  * Parms: request record, table type, table name, and the full SQL command
  523  */
  524 
  525 static logsql_query_ret safe_sql_insert(request_rec *r, logsql_tabletype table_type,
  526         const char *table_name, const char *query) {
  527 
  528     logsql_query_ret result;
  529     logsql_state *cls = ap_get_module_config(r->server->module_config,
  530                                     &log_sql_module);
  531 
  532     if (!global_config.db.connected || global_config.driver == NULL) {
  533         /* preserve query */
  534         return LOGSQL_QUERY_NOLINK;
  535     }
  536 
  537     result = global_config.driver->insert(r,&global_config.db,query);
  538 
  539     /* If we ran the query and it returned an error, try to be robust.
  540     * (After all, the module thought it had a valid mysql_log connection but the query
  541     * could have failed for a number of reasons, so we have to be extra-safe and check.) */
  542     switch (result) {
  543     case LOGSQL_QUERY_SUCCESS:
  544         return LOGSQL_QUERY_SUCCESS;
  545     case LOGSQL_QUERY_NOLINK:
  546         return LOGSQL_QUERY_FAIL;
  547         /* TODO: What do we do here */
  548     case LOGSQL_QUERY_FAIL:
  549         global_config.driver->disconnect(&global_config.db);
  550         global_config.db.connected = 0;
  551         /* re-open the connection and try again */
  552         if (log_sql_opendb_link(r->server) != LOGSQL_OPENDB_FAIL) {
  553             log_error(APLOG_MARK,APLOG_NOTICE,0, r->server,"db reconnect successful");
  554 #           if defined(WITH_APACHE20)
  555             apr_sleep(apr_time_from_sec(0.25)); /* pause for a quarter second */
  556 #           elif defined(WITH_APACHE13)
  557 #            if defined(WIN32)
  558             Sleep((DWORD)0.25);
  559 #            else
  560             {
  561                 struct timespec delay, remainder;
  562                 int nanoret;
  563                 delay.tv_sec = 0;
  564                 delay.tv_nsec = 250000000; /* pause for a quarter second */
  565                 nanoret = nanosleep(&delay, &remainder);
  566                 if (nanoret && errno != EINTR) {
  567                     log_error(APLOG_MARK,APLOG_ERR, errno, r->server,"nanosleep unsuccessful");
  568                 }
  569             }
  570 #            endif /* win32 */
  571 #           endif
  572             result = global_config.driver->insert(r,&global_config.db,query);
  573             if (result == LOGSQL_QUERY_SUCCESS) {
  574                 return LOGSQL_QUERY_SUCCESS;
  575             } else {
  576                 log_error(APLOG_MARK,APLOG_ERR,0,r->server,"second attempt failed");
  577                 preserve_entry(r, query);
  578                 return LOGSQL_QUERY_PRESERVED;
  579             }
  580         } else {
  581             log_error(APLOG_MARK,APLOG_ERR,0,r->server,
  582                 "reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection.");
  583             log_error(APLOG_MARK,APLOG_ERR,0,r->server,
  584                 "log entries are being preserved in %s",cls->preserve_file);
  585             preserve_entry(r, query);
  586             return LOGSQL_QUERY_PRESERVED;
  587         }
  588         break;
  589     case LOGSQL_QUERY_NOTABLE:
  590         if (global_config.createtables) {
  591             log_error(APLOG_MARK,APLOG_ERR,0,r->server,
  592                     "table doesn't exist...creating now");
  593             if ((result = global_config.driver->create_table(r, &global_config.db, table_type,
  594                 table_name))!=LOGSQL_TABLE_SUCCESS) {
  595                 log_error(APLOG_MARK,APLOG_ERR,result,r->server,
  596                     "child attempted but failed to create one or more tables for %s, preserving query", ap_get_server_name(r));
  597                 preserve_entry(r, query);
  598                 return LOGSQL_QUERY_PRESERVED;
  599             } else {
  600                 log_error(APLOG_MARK,APLOG_ERR,result, r->server,
  601                     "tables successfully created - retrying query");
  602                 if ((result = global_config.driver->insert(r,&global_config.db,query))!=LOGSQL_QUERY_SUCCESS) {
  603                     log_error(APLOG_MARK,APLOG_ERR,result, r->server,
  604                         "giving up, preserving query");
  605                     preserve_entry(r, query);
  606                     return LOGSQL_QUERY_PRESERVED;
  607                 } else {
  608                     log_error(APLOG_MARK,APLOG_NOTICE,0, r->server,
  609                         "query successful after table creation");
  610                     return LOGSQL_QUERY_SUCCESS;
  611                 }
  612             }
  613         } else {
  614             log_error(APLOG_MARK,APLOG_ERR,0,r->server,
  615                 "table doesn't exist, creation denied by configuration, preserving query");
  616             preserve_entry(r, query);
  617             return LOGSQL_QUERY_PRESERVED;
  618         }
  619         break;
  620     default:
  621         log_error(APLOG_MARK,APLOG_ERR,0, r->server,
  622                 "Invalid return code from mog_log_query");
  623         return LOGSQL_QUERY_FAIL;
  624         break;
  625     }
  626     return LOGSQL_QUERY_FAIL;
  627 }
  628 
  629 /* This function gets called to create a per-server configuration
  630  * record.  It will always be called for the main server and
  631  * for each virtual server that is established.  Each server maintains
  632  * its own state that is separate from the others' states.
  633  *
  634  * The return value is a pointer to the created module-specific
  635  * structure.
  636  */
  637 static void *log_sql_make_state(apr_pool_t *p, server_rec *s)
  638 {
  639     logsql_state *cls = (logsql_state *) apr_pcalloc(p, sizeof(logsql_state));
  640 
  641     /* These defaults are overridable in the httpd.conf file. */
  642     cls->transfer_log_format = DEFAULT_TRANSFER_LOG_FMT;
  643     apr_pool_create(&cls->parsed_pool, p);
  644     cls->parsed_log_format = apr_pcalloc(cls->parsed_pool,
  645             strlen(cls->transfer_log_format) * sizeof(logsql_item *));
  646     cls->notes_table_name = DEFAULT_NOTES_TABLE_NAME;
  647     cls->hin_table_name = DEFAULT_HIN_TABLE_NAME;
  648     cls->hout_table_name = DEFAULT_HOUT_TABLE_NAME;
  649     cls->cookie_table_name = DEFAULT_COOKIE_TABLE_NAME;
  650     cls->preserve_file = DEFAULT_PRESERVE_FILE;
  651 
  652     cls->transfer_ignore_list = apr_array_make(p, 1, sizeof(char *));
  653     cls->transfer_accept_list = apr_array_make(p, 1, sizeof(char *));
  654     cls->remhost_ignore_list  = apr_array_make(p, 1, sizeof(char *));
  655     cls->notes_list           = apr_array_make(p, 1, sizeof(char *));
  656     cls->hin_list             = apr_array_make(p, 1, sizeof(char *));
  657     cls->hout_list            = apr_array_make(p, 1, sizeof(char *));
  658     cls->cookie_list          = apr_array_make(p, 1, sizeof(char *));
  659 
  660     return (void *) cls;
  661 }
  662 
  663 
  664 /* Iterates through an array of char* and searches for a matching element
  665  * Returns 0 if not found, 1 if found */
  666 static int in_array(apr_array_header_t *ary, const char *elem)
  667 {
  668     int itr;
  669     for (itr = 0; itr < ary->nelts; itr++) {
  670         if (!strcmp(elem,((char **)ary->elts)[itr])) {
  671             return 1;
  672         }
  673     }
  674     return 0;
  675 }
  676 
  677 
  678 /* Parse through cookie lists and merge based on +/- prefixes */
  679 /* TODO: rewrite as a function */
  680 #define DO_MERGE_ARRAY(parent,child,pool) \
  681 if (apr_is_empty_array(child)) { \
  682     apr_array_cat(child, parent); \
  683 } else { \
  684     apr_array_header_t *addlist, *dellist; \
  685     char **elem, **ptr = (char **)(child->elts); \
  686     int itr, overwrite = 0; \
  687     addlist = apr_array_make(pool,5,sizeof(char *)); \
  688     dellist = apr_array_make(subp,5,sizeof(char *)); \
  689 \
  690     for (itr=0; itr<child->nelts; itr++) { \
  691         if (*ptr[itr] == '+') { \
  692             elem = (char **)apr_array_push(addlist); \
  693             *elem = (ptr[itr]+1); \
  694         } else if (*ptr[itr] == '-') { \
  695             elem = (char **)apr_array_push(dellist); \
  696             *elem = (ptr[itr]+1); \
  697         } else { \
  698             overwrite = 1; \
  699             elem = (char **)apr_array_push(addlist); \
  700             *elem = ptr[itr]; \
  701         } \
  702     } \
  703     child = apr_array_make(p,1,sizeof(char *)); \
  704     ptr = (char **)(parent->elts); \
  705     if (overwrite==0) { \
  706         /* if we are not overwriting the existing then prepare for merge */ \
  707         for (itr=0; itr<parent->nelts; itr++) { \
  708             if (!in_array(addlist, ptr[itr]) && !in_array(dellist,ptr[itr])) { \
  709                 elem = apr_array_push(child); \
  710                 *elem = apr_pstrdup(p, ptr[itr]); \
  711             } \
  712         } \
  713     } \
  714     apr_array_cat(child, addlist); \
  715 }
  716 
  717 static void *log_sql_merge_state(apr_pool_t *p, void *basev, void *addv)
  718 {
  719     /* Fetch the two states to merge */
  720     logsql_state *parent = (logsql_state *) basev;
  721     logsql_state *child = (logsql_state *) addv;
  722 
  723     apr_pool_t *subp;
  724 
  725     apr_pool_create(&subp,p);
  726 
  727     /* Child can override these, otherwise they default to parent's choice.
  728      * If the parent didn't set them, create reasonable defaults for the
  729      * ones that should have such default settings.  Leave the others null. */
  730 
  731     /* No default for transfer_table_name because we want its absence
  732      * to disable logging. */
  733     if (!child->transfer_table_name) {
  734         child->transfer_table_name = parent->transfer_table_name;
  735     }
  736 
  737     if (child->transfer_log_format == DEFAULT_TRANSFER_LOG_FMT) {
  738         child->transfer_log_format = parent->transfer_log_format;
  739         /*apr_pool_clear(child->parsed_pool);*/
  740         child->parsed_log_format = apr_pcalloc(child->parsed_pool,
  741             strlen(child->transfer_log_format) * sizeof(logsql_item *));
  742     }
  743 
  744     if (child->preserve_file == DEFAULT_PRESERVE_FILE)
  745         child->preserve_file = parent->preserve_file;
  746     /* server_root_relative the preserve file location */
  747     if (child->preserve_file == DEFAULT_PRESERVE_FILE)
  748         child->preserve_file = ap_server_root_relative(p, DEFAULT_PRESERVE_FILE);
  749 
  750     if (child->notes_table_name == DEFAULT_NOTES_TABLE_NAME)
  751         child->notes_table_name = parent->notes_table_name;
  752 
  753     if (child->hin_table_name == DEFAULT_HIN_TABLE_NAME)
  754         child->hin_table_name = parent->hin_table_name;
  755 
  756     if (child->hout_table_name == DEFAULT_HOUT_TABLE_NAME)
  757         child->hout_table_name = parent->hout_table_name;
  758 
  759     if (child->cookie_table_name == DEFAULT_COOKIE_TABLE_NAME)
  760         child->cookie_table_name = parent->cookie_table_name;
  761 
  762     DO_MERGE_ARRAY(parent->transfer_ignore_list, child->transfer_ignore_list, subp);
  763     DO_MERGE_ARRAY(parent->transfer_accept_list, child->transfer_accept_list, subp);
  764     DO_MERGE_ARRAY(parent->remhost_ignore_list, child->remhost_ignore_list, subp);
  765     DO_MERGE_ARRAY(parent->notes_list, child->notes_list, subp);
  766     DO_MERGE_ARRAY(parent->hin_list, child->hin_list, subp);
  767     DO_MERGE_ARRAY(parent->hout_list, child->hout_list, subp);
  768     DO_MERGE_ARRAY(parent->cookie_list,child->cookie_list, subp);
  769 
  770     apr_pool_destroy(subp);
  771 
  772     if (!child->cookie_name)
  773         child->cookie_name = parent->cookie_name;
  774 
  775 
  776     return (void*) child;
  777 }
  778 
  779 /* Routine to perform the actual construction and execution of the relevant
  780  * INSERT statements.
  781  */
  782 static int log_sql_transaction(request_rec *orig)
  783 {
  784     char **ptrptr, **ptrptr2;
  785     logsql_state *cls = ap_get_module_config(orig->server->module_config, &log_sql_module);
  786     const char *access_query;
  787     request_rec *r;
  788     const char *transfer_tablename = cls->transfer_table_name;
  789     const char *notes_tablename = cls->notes_table_name;
  790     const char *hout_tablename = cls->hout_table_name;
  791     const char *hin_tablename = cls->hin_table_name;
  792     const char *cookie_tablename = cls->cookie_table_name;
  793     if (global_config.driver == NULL) {
  794         return OK;
  795     }
  796     /* We handle mass virtual hosting differently.  Dynamically determine the name
  797      * of the table from the virtual server's name, and flag it for creation.
  798      */
  799     if (global_config.massvirtual) {
  800         /* TODO: Make these configurable? */
  801         char *access_base = "access_";
  802         char *notes_base  = "notes_";
  803         char *hout_base   = "headout_";
  804         char *hin_base    = "headin_";
  805         char *cookie_base = "cookies_";
  806 
  807 
  808         /* Determine the hostname and convert it to all lower-case; */
  809         char *servername = apr_pstrdup(orig->pool,(char *)ap_get_server_name(orig));
  810 
  811         char *p=servername;
  812         while (*p) {
  813             *p = apr_tolower(*p);
  814             if (*p == '.') *p = '_';
  815             if (*p == '-') *p = '_';
  816             ++p;
  817         }
  818 
  819         /* Find memory long enough to hold the table name + \0. */
  820         transfer_tablename = apr_pstrcat(orig->pool, access_base, servername, NULL);
  821         notes_tablename = apr_pstrcat(orig->pool, notes_base,  servername, NULL);
  822         hin_tablename = apr_pstrcat(orig->pool, hin_base,    servername, NULL);
  823         hout_tablename = apr_pstrcat(orig->pool, hout_base,   servername, NULL);
  824         cookie_tablename = apr_pstrcat(orig->pool, cookie_base, servername, NULL);
  825 
  826         /* Tell this virtual server its transfer table name, and
  827          * turn on create_tables, which is implied by massvirtual.
  828          */
  829 
  830         global_config.createtables = 1;
  831     }
  832 
  833     /* Do we have enough info to log? */
  834     if (!transfer_tablename) {
  835         return DECLINED;
  836     } else {
  837         const char *thehost;
  838         const char *theitem;
  839         char *fields = "", *values = "";
  840         char *itemsets = "";
  841         char *note_query = NULL;
  842         char *hin_query = NULL;
  843         char *hout_query = NULL;
  844         char *cookie_query = NULL;
  845         const char *unique_id;
  846         const char *formatted_item;
  847         int i,length;
  848         int proceed;
  849 
  850         for (r = orig; r->next; r = r->next) {
  851             continue;
  852         }
  853 
  854         /* The following is a stolen upsetting mess of pointers, I'm sorry.
  855          * Anyone with the motiviation and/or the time should feel free
  856          * to make this cleaner. :) */
  857         ptrptr2 = (char **) (cls->transfer_accept_list->elts + (cls->transfer_accept_list->nelts * cls->transfer_accept_list->elt_size));
  858 
  859         /* Go through each element of the accept list and compare it to the
  860          * request_uri.  If we don't get a match, return without logging */
  861         if ((r->uri) && (cls->transfer_accept_list->nelts)) {
  862             proceed = 0;
  863             for (ptrptr = (char **) cls->transfer_accept_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_accept_list->elt_size))
  864                 if (ap_strstr(r->uri, *ptrptr)) {
  865                     proceed = 1;
  866                     break;
  867                 }
  868             if (!proceed)
  869                 return OK;
  870         }
  871 
  872         /* Go through each element of the ignore list and compare it to the
  873          * request_uri.  If we get a match, return without logging */
  874         ptrptr2 = (char **) (cls->transfer_ignore_list->elts + (cls->transfer_ignore_list->nelts * cls->transfer_ignore_list->elt_size));
  875         if (r->uri) {
  876             for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size))
  877                 if (ap_strstr(r->uri, *ptrptr)) {
  878                     return OK;
  879                 }
  880         }
  881 
  882         /* Go through each element of the ignore list and compare it to the
  883          * remote host.  If we get a match, return without logging */
  884         ptrptr2 = (char **) (cls->remhost_ignore_list->elts + (cls->remhost_ignore_list->nelts * cls->remhost_ignore_list->elt_size));
  885         thehost = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME, NULL);
  886         if (thehost) {
  887             for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size))
  888                 if (ap_strstr(thehost, *ptrptr)) {
  889                     return OK;
  890                 }
  891         }
  892 
  893 
  894         /* Iterate through the format characters and set up the INSERT string according to
  895          * what the user has configured. */
  896         length = strlen(cls->transfer_log_format);
  897         for (i = 0; i<length; i++) {
  898             logsql_item *item = cls->parsed_log_format[i];
  899             if (item==NULL) {
  900                 log_error(APLOG_MARK, APLOG_ERR, 0, orig->server,
  901                     "Log Format '%c' unknown",cls->transfer_log_format[i]);
  902                 continue;
  903             }
  904 
  905             /* Yes, this key is one of the configured keys.
  906              * Call the key's function and put the returned value into 'formatted_item' */
  907             formatted_item = item->func(item->want_orig_default ? orig : r, "");
  908 
  909             /* Massage 'formatted_item' for proper SQL eligibility... */
  910             if (!formatted_item) {
  911                 formatted_item = "";
  912             } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !item->string_contents) {
  913                 /* If apache tried to log a '-' character for a numeric field, convert that to a zero
  914                  * because the database expects a numeral and will reject the '-' character. */
  915                 formatted_item = "0";
  916             }
  917 
  918              /* Append the fieldname and value-to-insert to the appropriate strings, quoting stringvals with ' as appropriate */
  919             fields = apr_pstrcat(r->pool, fields, (i ? "," : ""),
  920                          item->sql_field_name, NULL);
  921             values = apr_pstrcat(r->pool, values, (i ? "," : ""),
  922                          global_config.driver->escape(formatted_item, r->pool,&global_config.db), NULL);
  923         }
  924 
  925         /* Work through the list of notes defined by LogSQLWhichNotes */
  926         i = 0;
  927         unique_id = extract_unique_id(r, "");
  928 
  929         ptrptr2 = (char **) (cls->notes_list->elts + (cls->notes_list->nelts * cls->notes_list->elt_size));
  930         for (ptrptr = (char **) cls->notes_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->notes_list->elt_size)) {
  931             /* If the specified note (*ptrptr) exists for the current request... */
  932             if ((theitem = apr_table_get(r->notes, *ptrptr))) {
  933                 itemsets = apr_pstrcat(r->pool, itemsets,
  934                                       (i > 0 ? "," : ""),
  935                                       "(",
  936                                       global_config.driver->escape(unique_id, r->pool, &global_config.db),
  937                                       ",",
  938                                       global_config.driver->escape(*ptrptr, r->pool,&global_config.db),
  939                                       ",",
  940                                       global_config.driver->escape(theitem, r->pool,&global_config.db),
  941                                       ")",
  942                                       NULL);
  943                 i++;
  944             }
  945         }
  946         if ( *itemsets != '\0' ) {
  947             note_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s",
  948                 /*global_config.insertdelayed?"delayed":*/"", notes_tablename, itemsets);
  949 
  950             log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: note string: %s", note_query);
  951         }
  952 
  953         /* Work through the list of headers-out defined by LogSQLWhichHeadersOut*/
  954         i = 0;
  955         itemsets = "";
  956 
  957         ptrptr2 = (char **) (cls->hout_list->elts + (cls->hout_list->nelts * cls->hout_list->elt_size));
  958         for (ptrptr = (char **) cls->hout_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->hout_list->elt_size)) {
  959             /* If the specified header (*ptrptr) exists for the current request... */
  960             if ((theitem = apr_table_get(r->headers_out, *ptrptr))) {
  961                 itemsets = apr_pstrcat(r->pool, itemsets,
  962                                       (i > 0 ? "," : ""),
  963                                       "(",
  964                                       global_config.driver->escape(unique_id, r->pool, &global_config.db),
  965                                       ",",
  966                                       global_config.driver->escape(*ptrptr, r->pool,&global_config.db),
  967                                       ",",
  968                                       global_config.driver->escape(theitem, r->pool,&global_config.db),
  969                                       ")",
  970                                       NULL);
  971                 i++;
  972             }
  973         }
  974         if ( *itemsets != '\0' ) {
  975             hout_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s",
  976                 /*global_config.insertdelayed?"delayed":*/"", hout_tablename, itemsets);
  977 
  978             log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: header_out string: %s", hout_query);
  979         }
  980 
  981 
  982         /* Work through the list of headers-in defined by LogSQLWhichHeadersIn */
  983         i = 0;
  984         itemsets = "";
  985 
  986         ptrptr2 = (char **) (cls->hin_list->elts + (cls->hin_list->nelts * cls->hin_list->elt_size));
  987         for (ptrptr = (char **) cls->hin_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->hin_list->elt_size)) {
  988             /* If the specified header (*ptrptr) exists for the current request... */
  989             if ((theitem = apr_table_get(r->headers_in, *ptrptr))) {
  990                 itemsets = apr_pstrcat(r->pool, itemsets,
  991                                       (i > 0 ? "," : ""),
  992                                       "(",
  993                                       global_config.driver->escape(unique_id, r->pool, &global_config.db),
  994                                       ",",
  995                                       global_config.driver->escape(*ptrptr, r->pool,&global_config.db),
  996                                       ",",
  997                                       global_config.driver->escape(theitem, r->pool,&global_config.db),
  998                                       ")",
  999                                       NULL);
 1000                 i++;
 1001             }
 1002         }
 1003         if ( *itemsets != '\0' ) {
 1004             hin_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s",
 1005                 /*global_config.insertdelayed?"delayed":*/"", hin_tablename, itemsets);
 1006 
 1007             log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: header_in string: %s", hin_query);
 1008         }
 1009 
 1010 
 1011         /* Work through the list of cookies defined by LogSQLWhichCookies */
 1012         i = 0;
 1013         itemsets = "";
 1014 
 1015         ptrptr2 = (char **) (cls->cookie_list->elts + (cls->cookie_list->nelts * cls->cookie_list->elt_size));
 1016         for (ptrptr = (char **) cls->cookie_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->cookie_list->elt_size)) {
 1017             /* If the specified cookie (*ptrptr) exists for the current request... */
 1018             if ( strncmp((theitem = extract_specific_cookie(r, *ptrptr)), "-", 1) ) {
 1019                 itemsets = apr_pstrcat(r->pool, itemsets,
 1020                                       (i > 0 ? "," : ""),
 1021                                       "(",
 1022                                       global_config.driver->escape(unique_id, r->pool, &global_config.db),
 1023                                       ",",
 1024                                       global_config.driver->escape(*ptrptr, r->pool,&global_config.db),
 1025                                       ",",
 1026                                       global_config.driver->escape(theitem, r->pool,&global_config.db),
 1027                                       ")",
 1028                                       NULL);
 1029                 i++;
 1030             }
 1031 
 1032         }
 1033         if ( *itemsets != '\0' ) {
 1034             cookie_query = apr_psprintf(r->pool, "insert %s into %s (id, item, val) values %s",
 1035                 /*global_config.insertdelayed?"delayed":*/"", cookie_tablename, itemsets);
 1036 
 1037             log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: cookie string: %s", cookie_query);
 1038         }
 1039 
 1040 
 1041         /* Set up the actual INSERT statement */
 1042         access_query = apr_psprintf(r->pool, "insert %s into %s (%s) values (%s)",
 1043             /*global_config.insertdelayed?"delayed":*/"", transfer_tablename, fields, values);
 1044 
 1045         log_error(APLOG_MARK,APLOG_DEBUG,0, r->server,"mod_log_sql: access string: %s", access_query);
 1046 
 1047         /* If the person activated force-preserve, go ahead and push all the entries
 1048          * into the preserve file, then return.
 1049          */
 1050         if (global_config.forcepreserve) {
 1051             log_error(APLOG_MARK,APLOG_DEBUG,0, orig->server,"mod_log_sql: preservation forced");
 1052             preserve_entry(orig, access_query);
 1053             if ( note_query != NULL )
 1054                 preserve_entry(orig, note_query);
 1055             if ( hin_query != NULL )
 1056                 preserve_entry(orig, hin_query);
 1057             if ( hout_query != NULL )
 1058                 preserve_entry(orig, hout_query);
 1059             if ( cookie_query != NULL )
 1060                 preserve_entry(orig, cookie_query);
 1061             return OK;
 1062         }
 1063 
 1064         /* How's our mysql link integrity? */
 1065         if (!global_config.db.connected) {
 1066             if (!global_config.forcepreserve) {
 1067                 /* Make a try to establish the link */
 1068                 log_sql_opendb_link(r->server);
 1069             }
 1070             if (!global_config.db.connected) {
 1071                 /* Unable to re-establish a DB link, so assume that it's really
 1072                  * gone and send the entry to the preserve file instead.
 1073                  * This short-circuits safe_sql_query() during a db outage and therefore
 1074                  * we don't keep logging the db error over and over.
 1075                  */
 1076                 preserve_entry(orig, access_query);
 1077                 if ( note_query != NULL )
 1078                     preserve_entry(orig, note_query);
 1079                 if ( hin_query != NULL )
 1080                     preserve_entry(orig, hin_query);
 1081                 if ( hout_query != NULL )
 1082                     preserve_entry(orig, hout_query);
 1083                 if ( cookie_query != NULL )
 1084                     preserve_entry(orig, cookie_query);
 1085 
 1086                 return OK;
 1087             } else {
 1088                 /* Whew, we got the DB link back */
 1089                 log_error(APLOG_MARK,APLOG_NOTICE,0, orig->server,"mod_log_sql: child established database connection");
 1090             }
 1091         }
 1092 
 1093 
 1094         /* ---> So as of here we have a non-null value of mysql_log. <--- */
 1095         /* ---> i.e. we have a good MySQL connection.                <--- */
 1096 
 1097         /* Make the access-table insert */
 1098         safe_sql_insert(orig,LOGSQL_TABLE_ACCESS,transfer_tablename,access_query);
 1099 
 1100         /* Log the optional notes, headers, etc. */
 1101         if (note_query)
 1102             safe_sql_insert(orig, LOGSQL_TABLE_NOTES,notes_tablename,note_query);
 1103 
 1104         if (hout_query)
 1105             safe_sql_insert(orig, LOGSQL_TABLE_HEADERSOUT,hout_tablename,hout_query);
 1106 
 1107         if (hin_query)
 1108             safe_sql_insert(orig, LOGSQL_TABLE_HEADERSIN,hin_tablename,hin_query);
 1109 
 1110         if (cookie_query)
 1111             safe_sql_insert(orig, LOGSQL_TABLE_COOKIES,cookie_tablename,cookie_query);
 1112 
 1113         return OK;
 1114     }
 1115 }
 1116 
 1117 
 1118 /* Setup of the available httpd.conf configuration commands.
 1119  * Structure: command, function called, NULL, where available, how many arguments, verbose description
 1120  */
 1121 static const command_rec log_sql_cmds[] = {
 1122     AP_INIT_FLAG("LogSQLAnnounce", set_global_flag_slot,
 1123      (void *)APR_OFFSETOF(global_config_t, announce), RSRC_CONF,
 1124      "Whether to announce that mod_log_sql is loaded in the server header")
 1125     ,
 1126     /* DB connection parameters */
 1127     AP_INIT_TAKE13("LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF,
 1128      "The database connection URI in the form &quot;driver://user:password@hostname:port/database&quot;")
 1129     ,
 1130     AP_INIT_TAKE2("LogSQLDBParam", set_dbparam, NULL, RSRC_CONF,
 1131      "First argument is the DB parameter, second is the value to assign")
 1132     ,
 1133     AP_INIT_FLAG("LogSQLForcePreserve", set_global_flag_slot,
 1134      (void *)APR_OFFSETOF(global_config_t, forcepreserve), RSRC_CONF,
 1135      "Forces logging to preserve file and bypasses database")
 1136     ,
 1137     AP_INIT_FLAG("LogSQLDisablePreserve", set_global_flag_slot,
 1138      (void *)APR_OFFSETOF(global_config_t, disablepreserve), RSRC_CONF,
 1139      "Completely disables use of the preserve file")
 1140     ,
 1141     AP_INIT_TAKE1("LogSQLPreserveFile", set_server_file_slot,
 1142      (void *)APR_OFFSETOF(logsql_state,preserve_file), RSRC_CONF,
 1143      "Name of the file to use for data preservation during database downtime")
 1144     ,
 1145     AP_INIT_FLAG("LogSQLCreateTables", set_global_nmv_flag_slot,
 1146      (void *)APR_OFFSETOF(global_config_t, createtables), RSRC_CONF,
 1147      "Turn on module's capability to create its SQL tables on the fly")
 1148     ,
 1149     /* Table names */
 1150     AP_INIT_FLAG("LogSQLMassVirtualHosting", set_global_flag_slot,
 1151      (void *)APR_OFFSETOF(global_config_t, massvirtual), RSRC_CONF,
 1152      "Activates option(s) useful for ISPs performing mass virutal hosting")
 1153     ,
 1154     AP_INIT_TAKE1("LogSQLTransferLogTable", set_server_nmv_string_slot,
 1155      (void *)APR_OFFSETOF(logsql_state, transfer_table_name), RSRC_CONF,
 1156      "The database table that holds the transfer log")
 1157     ,
 1158     AP_INIT_TAKE1("LogSQLNotesLogTable", set_server_nmv_string_slot,
 1159      (void *)APR_OFFSETOF(logsql_state, notes_table_name), RSRC_CONF,
 1160      "The database table that holds the notes")
 1161     ,
 1162     AP_INIT_TAKE1("LogSQLHeadersOutLogTable", set_server_nmv_string_slot,
 1163      (void *)APR_OFFSETOF(logsql_state, hout_table_name), RSRC_CONF,
 1164      "The database table that holds the outbound headers")
 1165     ,
 1166     AP_INIT_TAKE1("LogSQLHeadersInLogTable", set_server_nmv_string_slot,
 1167      (void *)APR_OFFSETOF(logsql_state, hin_table_name), RSRC_CONF,
 1168      "The database table that holds the inbound headers")
 1169     ,
 1170     AP_INIT_TAKE1("LogSQLCookieLogTable", set_server_nmv_string_slot,
 1171      (void *)APR_OFFSETOF(logsql_state, cookie_table_name), RSRC_CONF,
 1172      "The database table that holds the cookie info")
 1173     ,
 1174     /* Log format */
 1175     AP_INIT_TAKE1("LogSQLTransferLogFormat", set_logformat_slot,
 1176      NULL, RSRC_CONF,
 1177      "Instruct the module what information to log to the database transfer log")
 1178     ,
 1179     /* Machine ID */
 1180     AP_INIT_TAKE1("LogSQLMachineID", set_global_string_slot,
 1181      (void *)APR_OFFSETOF(global_config_t, machid), RSRC_CONF,
 1182      "Machine ID that the module will log, useful in web clusters to differentiate machines")
 1183     ,
 1184     /* Limits on logging */
 1185     AP_INIT_ITERATE("LogSQLRequestAccept", add_server_string_slot,
 1186      (void *)APR_OFFSETOF(logsql_state, transfer_accept_list), RSRC_CONF,
 1187      "List of URIs to accept for logging. Accesses that don't match will not be logged")
 1188     ,
 1189     AP_INIT_ITERATE("LogSQLRequestIgnore", add_server_string_slot,
 1190      (void *)APR_OFFSETOF(logsql_state, transfer_ignore_list), RSRC_CONF,
 1191      "List of URIs to ignore. Accesses that match will not be logged to database")
 1192     ,
 1193     AP_INIT_ITERATE("LogSQLRemhostIgnore", add_server_string_slot,
 1194      (void *)APR_OFFSETOF(logsql_state, remhost_ignore_list), RSRC_CONF,
 1195      "List of remote hosts to ignore. Accesses that match will not be logged to database")
 1196     ,
 1197     /* Special loggin table configuration */
 1198     AP_INIT_TAKE1("LogSQLWhichCookie", set_server_string_slot,
 1199      (void *)APR_OFFSETOF(logsql_state, cookie_name), RSRC_CONF,
 1200      "The single cookie that you want logged in the access_log when using the 'c' config directive")
 1201     ,
 1202     AP_INIT_ITERATE("LogSQLWhichNotes", add_server_string_slot,
 1203      (void *)APR_OFFSETOF(logsql_state, notes_list), RSRC_CONF,
 1204      "Notes that you would like to log in a separate table")
 1205     ,
 1206     AP_INIT_ITERATE("LogSQLWhichHeadersOut", add_server_string_slot,
 1207      (void *)APR_OFFSETOF(logsql_state, hout_list), RSRC_CONF,
 1208      "Outbound headers that you would like to log in a separate table")
 1209     ,
 1210     AP_INIT_ITERATE("LogSQLWhichHeadersIn", add_server_string_slot,
 1211      (void *)APR_OFFSETOF(logsql_state, hin_list), RSRC_CONF,
 1212      "Inbound headers that you would like to log in a separate table")
 1213     ,
 1214     AP_INIT_ITERATE("LogSQLWhichCookies", add_server_string_slot,
 1215      (void *)APR_OFFSETOF(logsql_state, cookie_list), RSRC_CONF,
 1216      "The cookie(s) that you would like to log in a separate table")
 1217     ,
 1218     AP_INIT_RAW_ARGS("LogSQLDeprecated", ap_set_deprecated, NULL, RSRC_CONF,
 1219      "<br><b>Deprecated</b><br>The following Commands are deprecated and should not be used.. <br>Read the documentation for more information<br><b>Deprecated</b>")
 1220     ,
 1221     /* Deprecated commands */
 1222     AP_INIT_TAKE1("LogSQLDatabase", set_dbparam_slot,
 1223      (void *)"database", RSRC_CONF,
 1224      "<b>(Deprecated) Use LogSQLDBParam database dbname.</b> The name of the database database for logging")
 1225     ,
 1226     AP_INIT_TAKE1("LogSQLTableType", set_dbparam_slot,
 1227      (void *)"tabletype", RSRC_CONF,
 1228      "<b>(Deprecated) Use LogSQLDBParam tabletype type.</b> What kind of table to create (MyISAM, InnoDB,...) when creating tables")
 1229     ,
 1230     AP_INIT_TAKE1("LogSQLSocketFile", set_dbparam_slot,
 1231      (void *)"socketfile", RSRC_CONF,
 1232      "<b>(Deprecated) Use LogSQLDBParam socketfile socket.</b> Name of the file to employ for socket connections to database")
 1233     ,
 1234     AP_INIT_TAKE1("LogSQLTCPPort", set_dbparam_slot,
 1235      (void *)"port", RSRC_CONF,
 1236      "<b>(Deprecated) Use LogSQLDBParam port port.</b> Port number to use for TCP connections to database, defaults to 3306 if not set")
 1237     ,
 1238     {NULL}
 1239 };
 1240 /* The configuration array that sets up the hooks into the module. */
 1241 #if defined(WITH_APACHE20)
 1242 static void register_hooks(apr_pool_t *p) {
 1243     ap_hook_post_config(log_sql_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
 1244     ap_hook_child_init(log_sql_child_init, NULL, NULL, APR_HOOK_MIDDLE);
 1245     ap_hook_log_transaction(log_sql_transaction, NULL, NULL, APR_HOOK_MIDDLE);
 1246 }
 1247 
 1248 module AP_MODULE_DECLARE_DATA log_sql_module = {
 1249     STANDARD20_MODULE_STUFF,
 1250     NULL,       /* create per-directory config structures */
 1251     NULL,       /* merge per-directory config structures */
 1252     log_sql_make_state,     /* create per-server config structures */
 1253     log_sql_merge_state,        /* merge per-server config structures     */
 1254     log_sql_cmds,   /* command handlers */
 1255     register_hooks  /* register hooks */
 1256 };
 1257 #elif defined(WITH_APACHE13)
 1258 module MODULE_VAR_EXPORT log_sql_module = {
 1259     STANDARD_MODULE_STUFF,
 1260     log_sql_module_init,     /* module initializer              */
 1261     NULL,                    /* create per-dir config           */
 1262     NULL,                    /* merge per-dir config            */
 1263     log_sql_make_state,      /* create server config            */
 1264     log_sql_merge_state,     /* merge server config             */
 1265     log_sql_cmds,            /* config directive table          */
 1266     NULL,                    /* [9] content handlers            */
 1267     NULL,                    /* [2] URI-to-filename translation */
 1268     NULL,                    /* [5] check/validate user_id      */
 1269     NULL,                    /* [6] check authorization         */
 1270     NULL,                    /* [4] check access by host        */
 1271     NULL,                    /* [7] MIME type checker/setter    */
 1272     NULL,                    /* [8] fixups                      */
 1273     log_sql_transaction,     /* [10] logger                     */
 1274     NULL                     /* [3] header parser               */
 1275 #if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */
 1276     ,log_sql_child_init,   /* child process initializer         */
 1277     log_sql_child_exit,    /* process exit/cleanup          */
 1278     NULL                     /* [1] post read-request           */
 1279 #endif
 1280 
 1281 };
 1282 #endif