Loading CHANGES +2 −0 Changes for CHANGES: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ Changes with Apache 2.3.0 [Remove entries to the current 2.0 and 2.2 section below, when backported] *) mod_rewrite: support rewritemap by SQL query [Nick Kew] *) Fix issue which could cause piped loggers to be orphaned and never terminate after a graceful restart. PR 40651. [Joe Orton, Ruediger Pluem] Loading docs/manual/mod/mod_rewrite.xml +20 −0 Changes for docs/manual/mod/mod_rewrite.xml: 20 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -511,6 +511,26 @@ while (<STDIN>) { synchronization takes place.</li> </ol> </li> <li> <p><strong>SQL Query</strong><br /> MapType: <code>dbd</code> or <code>fastdbd</code>, MapSource: An SQL SELECT statement that takes a single argument and returns a single value.</p> <p>This uses <module>mod_dbd</module> to implement a rewritemap by lookup in an SQL database. There are two forms: <code>fastdbd</code> caches database lookups internally, <code>dbd</code> doesn't. So <code>dbd</code> incurs a performance penalty but responds immediately if the database contents are updated, while <code>fastdbd</code> is more efficient but won't re-read database contents until server restart.</p> <p>If a query returns more than one row, a random row from the result set is used.</p> <example> <title>Example</title> RewriteMap myquery "fastdbd:SELECT destination FROM rewrite WHERE source = %s" </example> </li> </ul> <p>The <directive>RewriteMap</directive> directive can occur more than once. For each mapping-function use one Loading modules/mappers/mod_rewrite.c +120 −0 Changes for modules/mappers/mod_rewrite.c: 120 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ #include "apr_signal.h" #include "apr_global_mutex.h" #include "apr_dbm.h" #include "apr_dbd.h" #include "mod_dbd.h" #if APR_HAS_THREADS #include "apr_thread_mutex.h" Loading Loading @@ -98,6 +100,9 @@ #include "unixd.h" #endif static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL; static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL; /* * in order to improve performance on running production systems, you * may strip all rewritelog code entirely from mod_rewrite by using the Loading Loading @@ -159,6 +164,8 @@ #define MAPTYPE_PRG 1<<2 #define MAPTYPE_INT 1<<3 #define MAPTYPE_RND 1<<4 #define MAPTYPE_DBD 1<<5 #define MAPTYPE_DBD_CACHE 1<<6 #define ENGINE_DISABLED 1<<0 #define ENGINE_ENABLED 1<<1 Loading Loading @@ -225,6 +232,7 @@ typedef struct { char *(*func)(request_rec *, /* function pointer for internal maps */ char *); char **argv; /* argv of the external rewrite map */ const char *dbdq; /* SQL SELECT statement for rewritemap */ } rewritemap_entry; /* special pattern types for RewriteCond */ Loading Loading @@ -1318,6 +1326,51 @@ static char *lookup_map_dbmfile(request_rec *r, const char *file, return value; } static char *lookup_map_dbd(request_rec *r, char *key, const char *label) { apr_status_t rv; apr_dbd_prepared_t *stmt; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; const char *ret = NULL; int n = 0; ap_dbd_t *db = dbd_acquire(r); stmt = apr_hash_get(db->prepared, label, APR_HASH_KEY_STRING); rv = apr_dbd_pvselect(db->driver, r->pool, db->handle, &res, stmt, 0, key, NULL); if (rv != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "rewritemap: error querying for %s", key); } while (rv = apr_dbd_get_row(db->driver, r->pool, res, &row, -1), rv == 0) { ++n; if (ret == NULL) { ret = apr_dbd_get_entry(db->driver, row, 0); } else { /* randomise crudely amongst multiple results */ if ((double)rand() < (double)RAND_MAX/(double)n) { ret = apr_dbd_get_entry(db->driver, row, 0); } } } if (rv != -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "rewritemap: error looking up %s", key); } switch (n) { case 0: return NULL; case 1: return apr_pstrdup(r->pool, ret); default: /* what's a fair rewritelog level for this? */ rewritelog((r, 3, NULL, "Multiple values found for %s", key)); return apr_pstrdup(r->pool, ret); } } static char *lookup_map_program(request_rec *r, apr_file_t *fpin, apr_file_t *fpout, char *key) Loading Loading @@ -1585,6 +1638,49 @@ static char *lookup_map(request_rec *r, char *name, char *key) name, key, value)); return *value ? value : NULL; /* * SQL map without cache */ case MAPTYPE_DBD: value = lookup_map_dbd(r, key, s->dbdq); if (!value) { rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", name, key)); return NULL; } rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", name, key, value)); return value; /* * SQL map with cache */ case MAPTYPE_DBD_CACHE: value = get_cache_value(s->cachename, st.mtime, key, r->pool); if (!value) { rewritelog((r, 6, NULL, "cache lookup FAILED, forcing new map lookup")); value = lookup_map_dbd(r, key, s->dbdq); if (!value) { rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", name, key)); return NULL; } rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", name, key, value)); set_cache_value(s->cachename, st.mtime, key, value); return value; } rewritelog((r, 5, NULL, "cache lookup OK: map=%s[SQL] key=%s, val=%s", name, key, value)); return *value ? value : NULL; /* * Program file map */ Loading Loading @@ -2871,6 +2967,24 @@ static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1, newmap->dbmtype, " is invalid", NULL); } } else if ((strncasecmp(a2, "dbd:", 4) == 0) || (strncasecmp(a2, "fastdbd:", 8) == 0)) { if (dbd_prepare == NULL) { return "RewriteMap types dbd and fastdbd require mod_dbd!"; } if ((a2[0] == 'd') || (a2[0] == 'D')) { newmap->type = MAPTYPE_DBD; fname = a2+4; } else { newmap->type = MAPTYPE_DBD_CACHE; fname = a2+8; newmap->cachename = apr_psprintf(cmd->pool, "%pp:%s", (void *)cmd->server, a1); } newmap->dbdq = a1; dbd_prepare(cmd->server, fname, newmap->dbdq); } else if (strncasecmp(a2, "prg:", 4) == 0) { apr_tokenize_to_argv(a2 + 4, &newmap->argv, cmd->pool); Loading Loading @@ -4796,6 +4910,11 @@ static void ap_register_rewrite_mapfunc(char *name, rewrite_mapfunc_t *func) apr_hash_set(mapfunc_hash, name, strlen(name), (const void *)func); } static void optional_fns(void) { dbd_acquire = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire); dbd_prepare = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_prepare); } static void register_hooks(apr_pool_t *p) { /* fixup after mod_proxy, so that the proxied url will not Loading @@ -4813,6 +4932,7 @@ static void register_hooks(apr_pool_t *p) ap_hook_fixups(hook_fixup, aszPre, NULL, APR_HOOK_FIRST); ap_hook_fixups(hook_mimetype, NULL, NULL, APR_HOOK_LAST); ap_hook_translate_name(hook_uri2file, NULL, NULL, APR_HOOK_FIRST); ap_hook_optional_fn_retrieve(optional_fns, NULL, NULL, APR_HOOK_MIDDLE); } /* the main config structure */ Loading Loading
CHANGES +2 −0 Changes for CHANGES: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ Changes with Apache 2.3.0 [Remove entries to the current 2.0 and 2.2 section below, when backported] *) mod_rewrite: support rewritemap by SQL query [Nick Kew] *) Fix issue which could cause piped loggers to be orphaned and never terminate after a graceful restart. PR 40651. [Joe Orton, Ruediger Pluem] Loading
docs/manual/mod/mod_rewrite.xml +20 −0 Changes for docs/manual/mod/mod_rewrite.xml: 20 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -511,6 +511,26 @@ while (<STDIN>) { synchronization takes place.</li> </ol> </li> <li> <p><strong>SQL Query</strong><br /> MapType: <code>dbd</code> or <code>fastdbd</code>, MapSource: An SQL SELECT statement that takes a single argument and returns a single value.</p> <p>This uses <module>mod_dbd</module> to implement a rewritemap by lookup in an SQL database. There are two forms: <code>fastdbd</code> caches database lookups internally, <code>dbd</code> doesn't. So <code>dbd</code> incurs a performance penalty but responds immediately if the database contents are updated, while <code>fastdbd</code> is more efficient but won't re-read database contents until server restart.</p> <p>If a query returns more than one row, a random row from the result set is used.</p> <example> <title>Example</title> RewriteMap myquery "fastdbd:SELECT destination FROM rewrite WHERE source = %s" </example> </li> </ul> <p>The <directive>RewriteMap</directive> directive can occur more than once. For each mapping-function use one Loading
modules/mappers/mod_rewrite.c +120 −0 Changes for modules/mappers/mod_rewrite.c: 120 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ #include "apr_signal.h" #include "apr_global_mutex.h" #include "apr_dbm.h" #include "apr_dbd.h" #include "mod_dbd.h" #if APR_HAS_THREADS #include "apr_thread_mutex.h" Loading Loading @@ -98,6 +100,9 @@ #include "unixd.h" #endif static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL; static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL; /* * in order to improve performance on running production systems, you * may strip all rewritelog code entirely from mod_rewrite by using the Loading Loading @@ -159,6 +164,8 @@ #define MAPTYPE_PRG 1<<2 #define MAPTYPE_INT 1<<3 #define MAPTYPE_RND 1<<4 #define MAPTYPE_DBD 1<<5 #define MAPTYPE_DBD_CACHE 1<<6 #define ENGINE_DISABLED 1<<0 #define ENGINE_ENABLED 1<<1 Loading Loading @@ -225,6 +232,7 @@ typedef struct { char *(*func)(request_rec *, /* function pointer for internal maps */ char *); char **argv; /* argv of the external rewrite map */ const char *dbdq; /* SQL SELECT statement for rewritemap */ } rewritemap_entry; /* special pattern types for RewriteCond */ Loading Loading @@ -1318,6 +1326,51 @@ static char *lookup_map_dbmfile(request_rec *r, const char *file, return value; } static char *lookup_map_dbd(request_rec *r, char *key, const char *label) { apr_status_t rv; apr_dbd_prepared_t *stmt; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; const char *ret = NULL; int n = 0; ap_dbd_t *db = dbd_acquire(r); stmt = apr_hash_get(db->prepared, label, APR_HASH_KEY_STRING); rv = apr_dbd_pvselect(db->driver, r->pool, db->handle, &res, stmt, 0, key, NULL); if (rv != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "rewritemap: error querying for %s", key); } while (rv = apr_dbd_get_row(db->driver, r->pool, res, &row, -1), rv == 0) { ++n; if (ret == NULL) { ret = apr_dbd_get_entry(db->driver, row, 0); } else { /* randomise crudely amongst multiple results */ if ((double)rand() < (double)RAND_MAX/(double)n) { ret = apr_dbd_get_entry(db->driver, row, 0); } } } if (rv != -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "rewritemap: error looking up %s", key); } switch (n) { case 0: return NULL; case 1: return apr_pstrdup(r->pool, ret); default: /* what's a fair rewritelog level for this? */ rewritelog((r, 3, NULL, "Multiple values found for %s", key)); return apr_pstrdup(r->pool, ret); } } static char *lookup_map_program(request_rec *r, apr_file_t *fpin, apr_file_t *fpout, char *key) Loading Loading @@ -1585,6 +1638,49 @@ static char *lookup_map(request_rec *r, char *name, char *key) name, key, value)); return *value ? value : NULL; /* * SQL map without cache */ case MAPTYPE_DBD: value = lookup_map_dbd(r, key, s->dbdq); if (!value) { rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", name, key)); return NULL; } rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", name, key, value)); return value; /* * SQL map with cache */ case MAPTYPE_DBD_CACHE: value = get_cache_value(s->cachename, st.mtime, key, r->pool); if (!value) { rewritelog((r, 6, NULL, "cache lookup FAILED, forcing new map lookup")); value = lookup_map_dbd(r, key, s->dbdq); if (!value) { rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", name, key)); return NULL; } rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", name, key, value)); set_cache_value(s->cachename, st.mtime, key, value); return value; } rewritelog((r, 5, NULL, "cache lookup OK: map=%s[SQL] key=%s, val=%s", name, key, value)); return *value ? value : NULL; /* * Program file map */ Loading Loading @@ -2871,6 +2967,24 @@ static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1, newmap->dbmtype, " is invalid", NULL); } } else if ((strncasecmp(a2, "dbd:", 4) == 0) || (strncasecmp(a2, "fastdbd:", 8) == 0)) { if (dbd_prepare == NULL) { return "RewriteMap types dbd and fastdbd require mod_dbd!"; } if ((a2[0] == 'd') || (a2[0] == 'D')) { newmap->type = MAPTYPE_DBD; fname = a2+4; } else { newmap->type = MAPTYPE_DBD_CACHE; fname = a2+8; newmap->cachename = apr_psprintf(cmd->pool, "%pp:%s", (void *)cmd->server, a1); } newmap->dbdq = a1; dbd_prepare(cmd->server, fname, newmap->dbdq); } else if (strncasecmp(a2, "prg:", 4) == 0) { apr_tokenize_to_argv(a2 + 4, &newmap->argv, cmd->pool); Loading Loading @@ -4796,6 +4910,11 @@ static void ap_register_rewrite_mapfunc(char *name, rewrite_mapfunc_t *func) apr_hash_set(mapfunc_hash, name, strlen(name), (const void *)func); } static void optional_fns(void) { dbd_acquire = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire); dbd_prepare = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_prepare); } static void register_hooks(apr_pool_t *p) { /* fixup after mod_proxy, so that the proxied url will not Loading @@ -4813,6 +4932,7 @@ static void register_hooks(apr_pool_t *p) ap_hook_fixups(hook_fixup, aszPre, NULL, APR_HOOK_FIRST); ap_hook_fixups(hook_mimetype, NULL, NULL, APR_HOOK_LAST); ap_hook_translate_name(hook_uri2file, NULL, NULL, APR_HOOK_FIRST); ap_hook_optional_fn_retrieve(optional_fns, NULL, NULL, APR_HOOK_MIDDLE); } /* the main config structure */ Loading