From 2a463b3cd73c32ee9dcd508248d0194923f435f4 Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Sat, 29 Mar 2014 21:56:19 +0100 Subject: Imported Upstream version 2.4.9 --- server/core.c | 16 ++++++ server/log.c | 8 +-- server/mpm/event/event.c | 14 +++--- server/mpm/event/fdqueue.c | 47 +++++++++-------- server/mpm/winnt/child.c | 9 ++-- server/mpm_unix.c | 5 ++ server/protocol.c | 41 ++++++++++++--- server/request.c | 122 +++++++++++++++++++++++++++++++++++++++++---- server/util.c | 20 ++++---- server/util_ebcdic.c | 2 +- server/util_pcre.c | 42 +++++++++++++++- server/util_regex.c | 3 +- 12 files changed, 254 insertions(+), 75 deletions(-) (limited to 'server') diff --git a/server/core.c b/server/core.c index 936bf47f..da895ab0 100644 --- a/server/core.c +++ b/server/core.c @@ -209,6 +209,7 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) conf->d_is_fnmatch = new->d_is_fnmatch; conf->d_components = new->d_components; conf->r = new->r; + conf->refs = new->refs; conf->condition = new->condition; if (new->opts & OPT_UNSET) { @@ -2159,6 +2160,11 @@ static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg) conf->d = cmd->path; conf->d_is_fnmatch = (apr_fnmatch_test(conf->d) != 0); + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); + ap_regname(r, conf->refs, AP_REG_MATCH, 1); + } + /* Make this explicit - the "/" root has 0 elements, that is, we * will always merge it, and it will always sort and merge first. * All others are sorted and tested by the number of slashes. @@ -2235,6 +2241,11 @@ static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg) conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0; conf->r = r; + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); + ap_regname(r, conf->refs, AP_REG_MATCH, 1); + } + ap_add_per_url_conf(cmd->server, new_url_conf); if (*arg != '\0') { @@ -2317,6 +2328,11 @@ static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg) conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0; conf->r = r; + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); + ap_regname(r, conf->refs, AP_REG_MATCH, 1); + } + ap_add_file_conf(cmd->pool, (core_dir_config *)mconfig, new_file_conf); if (*arg != '\0') { diff --git a/server/log.c b/server/log.c index bcfdcdb6..9a15d24d 100644 --- a/server/log.c +++ b/server/log.c @@ -331,10 +331,8 @@ static int log_child(apr_pool_t *p, const char *progname, && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) == APR_SUCCESS)) { char **args; - const char *pname; apr_tokenize_to_argv(progname, &args, p); - pname = apr_pstrdup(p, args[0]); procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew)); if (dummy_stderr) { @@ -342,7 +340,7 @@ static int log_child(apr_pool_t *p, const char *progname, rc = apr_procattr_child_err_set(procattr, errfile, NULL); } - rc = apr_proc_create(procnew, pname, (const char * const *)args, + rc = apr_proc_create(procnew, args[0], (const char * const *)args, NULL, procattr, p); if (rc == APR_SUCCESS) { @@ -1566,12 +1564,10 @@ static apr_status_t piped_log_spawn(piped_log *pl) } else { char **args; - const char *pname; apr_tokenize_to_argv(pl->program, &args, pl->p); - pname = apr_pstrdup(pl->p, args[0]); procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t)); - status = apr_proc_create(procnew, pname, (const char * const *) args, + status = apr_proc_create(procnew, args[0], (const char * const *) args, NULL, procattr, pl->p); if (status == APR_SUCCESS) { diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 306837db..7a95498e 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -2866,16 +2866,14 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog, } ++retained->module_loads; if (retained->module_loads == 2) { - int i; - static apr_uint32_t foo = 0; + /* test for correct operation of fdqueue */ + static apr_uint32_t foo1, foo2; - apr_atomic_inc32(&foo); - apr_atomic_dec32(&foo); - apr_atomic_dec32(&foo); - i = apr_atomic_dec32(&foo); - if (i >= 0) { + apr_atomic_set32(&foo1, 100); + foo2 = apr_atomic_add32(&foo1, -10); + if (foo2 != 100 || foo1 != 90) { ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(02405) - "atomics not working as expected"); + "atomics not working as expected - add32 of negative number"); return HTTP_INTERNAL_SERVER_ERROR; } rv = apr_pollset_create(&event_pollset, 1, plog, diff --git a/server/mpm/event/fdqueue.c b/server/mpm/event/fdqueue.c index 028bca10..2fa7e1e5 100644 --- a/server/mpm/event/fdqueue.c +++ b/server/mpm/event/fdqueue.c @@ -17,18 +17,20 @@ #include "fdqueue.h" #include "apr_atomic.h" -typedef struct recycled_pool +static apr_uint32_t zero_pt = APR_UINT32_MAX/2; + +struct recycled_pool { apr_pool_t *pool; struct recycled_pool *next; -} recycled_pool; +}; struct fd_queue_info_t { - apr_int32_t idlers; /** - * 0 or positive: number of idle worker threads - * negative: number of threads blocked waiting - * for an idle worker + apr_uint32_t idlers; /** + * >= zero_pt: number of idle worker threads + * < zero_pt: number of threads blocked waiting + * for an idle worker */ apr_thread_mutex_t *idlers_mutex; apr_thread_cond_t *wait_for_idler; @@ -36,7 +38,7 @@ struct fd_queue_info_t int max_idlers; int max_recycled_pools; apr_uint32_t recycled_pools_count; - recycled_pool *recycled_pools; + struct recycled_pool *recycled_pools; }; static apr_status_t queue_info_cleanup(void *data_) @@ -82,6 +84,7 @@ apr_status_t ap_queue_info_create(fd_queue_info_t ** queue_info, qi->recycled_pools = NULL; qi->max_recycled_pools = max_recycled_pools; qi->max_idlers = max_idlers; + qi->idlers = zero_pt; apr_pool_cleanup_register(pool, qi, queue_info_cleanup, apr_pool_cleanup_null); @@ -94,17 +97,12 @@ apr_status_t ap_queue_info_set_idle(fd_queue_info_t * queue_info, apr_pool_t * pool_to_recycle) { apr_status_t rv; - int prev_idlers; + apr_int32_t prev_idlers; ap_push_pool(queue_info, pool_to_recycle); /* Atomically increment the count of idle workers */ - /* - * TODO: The atomics expect unsigned whereas we're using signed. - * Need to double check that they work as expected or else - * rework how we determine blocked. - */ - prev_idlers = apr_atomic_inc32((apr_uint32_t *)&(queue_info->idlers)); + prev_idlers = apr_atomic_inc32(&(queue_info->idlers)) - zero_pt; /* If other threads are waiting on a worker, wake one up */ if (prev_idlers < 0) { @@ -129,10 +127,10 @@ apr_status_t ap_queue_info_set_idle(fd_queue_info_t * queue_info, apr_status_t ap_queue_info_try_get_idler(fd_queue_info_t * queue_info) { - int prev_idlers; - prev_idlers = apr_atomic_dec32((apr_uint32_t *)&(queue_info->idlers)); - if (prev_idlers <= 0) { - apr_atomic_inc32((apr_uint32_t *)&(queue_info->idlers)); /* back out dec */ + apr_int32_t new_idlers; + new_idlers = apr_atomic_add32(&(queue_info->idlers), -1) - zero_pt; + if (--new_idlers <= 0) { + apr_atomic_inc32(&(queue_info->idlers)); /* back out dec */ return APR_EAGAIN; } return APR_SUCCESS; @@ -142,11 +140,11 @@ apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t * queue_info, int *had_to_block) { apr_status_t rv; - int prev_idlers; + apr_int32_t prev_idlers; /* Atomically decrement the idle worker count, saving the old value */ /* See TODO in ap_queue_info_set_idle() */ - prev_idlers = apr_atomic_add32((apr_uint32_t *)&(queue_info->idlers), -1); + prev_idlers = apr_atomic_add32(&(queue_info->idlers), -1) - zero_pt; /* Block if there weren't any idle workers */ if (prev_idlers <= 0) { @@ -154,7 +152,7 @@ apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t * queue_info, if (rv != APR_SUCCESS) { AP_DEBUG_ASSERT(0); /* See TODO in ap_queue_info_set_idle() */ - apr_atomic_inc32((apr_uint32_t *)&(queue_info->idlers)); /* back out dec */ + apr_atomic_inc32(&(queue_info->idlers)); /* back out dec */ return rv; } /* Re-check the idle worker count to guard against a @@ -173,10 +171,11 @@ apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t * queue_info, * now non-negative, it's safe for this function to * return immediately. * - * A negative value in queue_info->idlers tells how many + * A "negative value" (relative to zero_pt) in + * queue_info->idlers tells how many * threads are waiting on an idle worker. */ - if (queue_info->idlers < 0) { + if (queue_info->idlers < zero_pt) { *had_to_block = 1; rv = apr_thread_cond_wait(queue_info->wait_for_idler, queue_info->idlers_mutex); @@ -207,7 +206,7 @@ apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t * queue_info, apr_uint32_t ap_queue_info_get_idlers(fd_queue_info_t * queue_info) { apr_int32_t val; - val = (apr_int32_t)apr_atomic_read32((apr_uint32_t *)&queue_info->idlers); + val = (apr_int32_t)apr_atomic_read32(&queue_info->idlers) - zero_pt; if (val < 0) return 0; return val; diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index c9168b08..6879179f 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -878,12 +878,13 @@ static DWORD __stdcall worker_main(void *thread_num_val) if (!c->aborted) { ap_run_process_connection(c); + } - apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED, - &disconnected); + apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED, &disconnected); - if (!disconnected) { - context->accept_socket = INVALID_SOCKET; + if (!disconnected) { + context->accept_socket = INVALID_SOCKET; + if (!c->aborted) { ap_lingering_close(c); } } diff --git a/server/mpm_unix.c b/server/mpm_unix.c index 063af725..0000cb66 100644 --- a/server/mpm_unix.c +++ b/server/mpm_unix.c @@ -742,7 +742,12 @@ void ap_mpm_pod_killpg(ap_pod_t *pod, int num) * readers stranded (a number of them could be tied up for * a while serving time-consuming requests) */ + /* Recall: we only worry about IDLE child processes here */ for (i = 0; i < num && rv == APR_SUCCESS; i++) { + if (ap_scoreboard_image->servers[i][0].status != SERVER_READY || + ap_scoreboard_image->servers[i][0].pid == 0) { + continue; + } rv = dummy_connection(pod); } } diff --git a/server/protocol.c b/server/protocol.c index a0b32464..bf915a0a 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -997,6 +997,8 @@ request_rec *ap_read_request(conn_rec *conn) } if (!r->assbackwards) { + const char *tenc; + ap_get_mime_headers_core(r, tmp_bb); if (r->status != HTTP_OK) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00567) @@ -1008,12 +1010,34 @@ request_rec *ap_read_request(conn_rec *conn) goto traceout; } - if (apr_table_get(r->headers_in, "Transfer-Encoding") - && apr_table_get(r->headers_in, "Content-Length")) { - /* 2616 section 4.4, point 3: "if both Transfer-Encoding - * and Content-Length are received, the latter MUST be - * ignored"; so unset it here to prevent any confusion - * later. */ + tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); + if (tenc) { + /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 + * Section 3.3.3.3: "If a Transfer-Encoding header field is + * present in a request and the chunked transfer coding is not + * the final encoding ...; the server MUST respond with the 400 + * (Bad Request) status code and then close the connection". + */ + if (!(strcasecmp(tenc, "chunked") == 0 /* fast path */ + || ap_find_last_token(r->pool, tenc, "chunked"))) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02539) + "client sent unknown Transfer-Encoding " + "(%s): %s", tenc, r->uri); + r->status = HTTP_BAD_REQUEST; + conn->keepalive = AP_CONN_CLOSE; + ap_send_error_response(r, 0); + ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); + ap_run_log_transaction(r); + apr_brigade_destroy(tmp_bb); + goto traceout; + } + + /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 + * Section 3.3.3.3: "If a message is received with both a + * Transfer-Encoding and a Content-Length header field, the + * Transfer-Encoding overrides the Content-Length. ... A sender + * MUST remove the received Content-Length field". + */ apr_table_unset(r->headers_in, "Content-Length"); } } @@ -1557,7 +1581,8 @@ struct ap_vrprintf_data { char *buff; }; -static apr_status_t r_flush(apr_vformatter_buff_t *buff) +/* Flush callback for apr_vformatter; returns -1 on error. */ +static int r_flush(apr_vformatter_buff_t *buff) { /* callback function passed to ap_vformatter to be called when * vformatter needs to write into buff and buff.curpos > buff.endpos */ @@ -1578,7 +1603,7 @@ static apr_status_t r_flush(apr_vformatter_buff_t *buff) vd->vbuff.curpos = vd->buff; vd->vbuff.endpos = vd->buff + AP_IOBUFSIZE; - return APR_SUCCESS; + return 0; } AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va) diff --git a/server/request.c b/server/request.c index 1f4d9927..af0a697a 100644 --- a/server/request.c +++ b/server/request.c @@ -737,6 +737,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) apr_size_t buflen; char *buf; unsigned int seg, startseg; + apr_pool_t *rxpool = NULL; /* Invariant: from the first time filename_len is set until * it goes out of scope, filename_len==strlen(r->filename) @@ -1192,6 +1193,10 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) */ for (; sec_idx < num_sec; ++sec_idx) { + int nmatch = 0; + int i; + ap_regmatch_t *pmatch = NULL; + core_dir_config *entry_core; entry_core = ap_get_core_module_config(sec_ent[sec_idx]); @@ -1199,10 +1204,29 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) continue; } - if (ap_regexec(entry_core->r, r->filename, 0, NULL, 0)) { + if (entry_core->refs && entry_core->refs->nelts) { + if (!rxpool) { + apr_pool_create(&rxpool, r->pool); + } + nmatch = entry_core->refs->nelts; + pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); + } + + if (ap_regexec(entry_core->r, r->filename, nmatch, pmatch, 0)) { continue; } + for (i = 0; i < nmatch; i++) { + if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && + ((const char **)entry_core->refs->elts)[i]) { + apr_table_setn(r->subprocess_env, + ((const char **)entry_core->refs->elts)[i], + apr_pstrndup(r->pool, + r->filename + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); + } + } + /* If we haven't already continue'd above, we have a match. * * Calculate our full-context core opts & override. @@ -1241,6 +1265,10 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) last_walk->merged = now_merged; } + if (rxpool) { + apr_pool_destroy(rxpool); + } + /* Whoops - everything matched in sequence, but either the original * walk found some additional matches (which we need to truncate), or * this walk found some additional matches. @@ -1378,6 +1406,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) int matches = cache->walked->nelts; int cached_matches = matches; walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts; + apr_pool_t *rxpool = NULL; cached &= auth_internal_per_conf; cache->cached = entry_uri; @@ -1399,16 +1428,48 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) * not slash terminated, then this uri must be slash * terminated (or at the end of the string) to match. */ - if (entry_core->r - ? ap_regexec(entry_core->r, r->uri, 0, NULL, 0) - : (entry_core->d_is_fnmatch + if (entry_core->r) { + + int nmatch = 0; + int i; + ap_regmatch_t *pmatch = NULL; + + if (entry_core->refs && entry_core->refs->nelts) { + if (!rxpool) { + apr_pool_create(&rxpool, r->pool); + } + nmatch = entry_core->refs->nelts; + pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); + } + + if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) { + continue; + } + + for (i = 0; i < nmatch; i++) { + if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && + ((const char **)entry_core->refs->elts)[i]) { + apr_table_setn(r->subprocess_env, + ((const char **)entry_core->refs->elts)[i], + apr_pstrndup(r->pool, + r->uri + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); + } + } + + } + else { + + if ((entry_core->d_is_fnmatch ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME) : (strncmp(entry_core->d, cache->cached, len) || (len > 0 && entry_core->d[len - 1] != '/' && cache->cached[len] != '/' && cache->cached[len] != '\0')))) { - continue; + continue; + } + } /* If we merged this same section last time, reuse it @@ -1443,6 +1504,10 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) last_walk->merged = now_merged; } + if (rxpool) { + apr_pool_destroy(rxpool); + } + /* Whoops - everything matched in sequence, but either the original * walk found some additional matches (which we need to truncate), or * this walk found some additional matches. @@ -1552,6 +1617,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) int matches = cache->walked->nelts; int cached_matches = matches; walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts; + apr_pool_t *rxpool = NULL; cached &= auth_internal_per_conf; cache->cached = test_file; @@ -1564,12 +1630,42 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) core_dir_config *entry_core; entry_core = ap_get_core_module_config(sec_ent[sec_idx]); - if (entry_core->r - ? ap_regexec(entry_core->r, cache->cached , 0, NULL, 0) - : (entry_core->d_is_fnmatch - ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME) - : strcmp(entry_core->d, cache->cached))) { - continue; + if (entry_core->r) { + + int nmatch = 0; + int i; + ap_regmatch_t *pmatch = NULL; + + if (entry_core->refs && entry_core->refs->nelts) { + if (!rxpool) { + apr_pool_create(&rxpool, r->pool); + } + nmatch = entry_core->refs->nelts; + pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); + } + + if (ap_regexec(entry_core->r, cache->cached, nmatch, pmatch, 0)) { + continue; + } + + for (i = 0; i < nmatch; i++) { + if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && + ((const char **)entry_core->refs->elts)[i]) { + apr_table_setn(r->subprocess_env, + ((const char **)entry_core->refs->elts)[i], + apr_pstrndup(r->pool, + cache->cached + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); + } + } + + } + else { + if ((entry_core->d_is_fnmatch + ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME) + : strcmp(entry_core->d, cache->cached))) { + continue; + } } /* If we merged this same section last time, reuse it @@ -1604,6 +1700,10 @@ AP_DECLARE(int) ap_file_walk(request_rec *r) last_walk->merged = now_merged; } + if (rxpool) { + apr_pool_destroy(rxpool); + } + /* Whoops - everything matched in sequence, but either the original * walk found some additional matches (which we need to truncate), or * this walk found some additional matches. diff --git a/server/util.c b/server/util.c index e0ba5c28..2b603000 100644 --- a/server/util.c +++ b/server/util.c @@ -115,7 +115,7 @@ AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype) while ((semi > intype) && apr_isspace(semi[-1])) { semi--; } - return apr_pstrndup(p, intype, semi - intype); + return apr_pstrmemdup(p, intype, semi - intype); } } @@ -736,7 +736,7 @@ AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line, return res; } - res = apr_pstrndup(atrans, *line, pos - *line); + res = apr_pstrmemdup(atrans, *line, pos - *line); ++pos; @@ -956,13 +956,15 @@ AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp) AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp, apr_status_t rc) { - char buf[MAX_STRING_LEN]; if (rc == APR_SUCCESS) return NULL; - return apr_psprintf(p, "Error reading %s at line %d: %s", - cfp->name, cfp->line_number, - rc == APR_ENOSPC ? "Line too long" - : apr_strerror(rc, buf, sizeof(buf))); + + if (rc == APR_ENOSPC) + return apr_psprintf(p, "Error reading %s at line %d: Line too long", + cfp->name, cfp->line_number); + + return apr_psprintf(p, "Error reading %s at line %d: %pm", + cfp->name, cfp->line_number, &rc); } /* Read one line from open ap_configfile_t, strip LF, increase line number */ @@ -1461,7 +1463,6 @@ AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line, const char *ptr = *accept_line; const char *tok_start; char *token; - int tok_len; /* Find first non-white byte */ @@ -1482,8 +1483,7 @@ AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line, break; } - tok_len = ptr - tok_start; - token = apr_pstrndup(p, tok_start, tok_len); + token = apr_pstrmemdup(p, tok_start, ptr - tok_start); /* Advance accept_line pointer to the next non-white byte */ diff --git a/server/util_ebcdic.c b/server/util_ebcdic.c index 1a8c0ba3..7faae794 100644 --- a/server/util_ebcdic.c +++ b/server/util_ebcdic.c @@ -102,7 +102,7 @@ int ap_rvputs_proto_in_ascii(request_rec *r, ...) if (s == NULL) break; len = strlen(s); - ascii_s = apr_pstrndup(r->pool, s, len); + ascii_s = apr_pstrmemdup(r->pool, s, len); ap_xlate_proto_to_ascii(ascii_s, len); if (ap_rputs(ascii_s, r) < 0) return -1; diff --git a/server/util_pcre.c b/server/util_pcre.c index 1e83cad0..4d2adef2 100644 --- a/server/util_pcre.c +++ b/server/util_pcre.c @@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "httpd.h" #include "apr_strings.h" +#include "apr_tables.h" #include "pcre.h" #define APR_WANT_STRFUNC @@ -124,7 +125,7 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags) const char *errorptr; int erroffset; int errcode = 0; - int options = 0; + int options = PCRE_DUPNAMES; if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS; @@ -256,4 +257,43 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff, } } +AP_DECLARE(int) ap_regname(const ap_regex_t *preg, + apr_array_header_t *names, const char *prefix, + int upper) +{ + int namecount; + int nameentrysize; + int i; + char *nametable; + + pcre_fullinfo((const pcre *)preg->re_pcre, NULL, + PCRE_INFO_NAMECOUNT, &namecount); + pcre_fullinfo((const pcre *)preg->re_pcre, NULL, + PCRE_INFO_NAMEENTRYSIZE, &nameentrysize); + pcre_fullinfo((const pcre *)preg->re_pcre, NULL, + PCRE_INFO_NAMETABLE, &nametable); + + for (i = 0; i < namecount; i++) { + const char *offset = nametable + i * nameentrysize; + int capture = ((offset[0] << 8) + offset[1]); + while (names->nelts <= capture) { + apr_array_push(names); + } + if (upper || prefix) { + char *name = ((char **) names->elts)[capture] = + prefix ? apr_pstrcat(names->pool, prefix, offset + 2, + NULL) : + apr_pstrdup(names->pool, offset + 2); + if (upper) { + ap_str_toupper(name); + } + } + else { + ((const char **)names->elts)[capture] = offset + 2; + } + } + + return namecount; +} + /* End of pcreposix.c */ diff --git a/server/util_regex.c b/server/util_regex.c index 73eccec7..81eac530 100644 --- a/server/util_regex.c +++ b/server/util_regex.c @@ -162,7 +162,6 @@ AP_DECLARE(int) ap_rxplus_exec(apr_pool_t *pool, ap_rxplus_t *rx, remainder = pattern + startl + oldl; if (rx->flags & AP_REG_MULTI) { /* recurse to do any further matches */ - char *subs; ret += ap_rxplus_exec(pool, rx, remainder, &subs); if (ret > 1) { /* a further substitution happened */ @@ -206,5 +205,5 @@ AP_DECLARE(char*) ap_rxplus_pmatch(apr_pool_t *pool, ap_rxplus_t *rx, int n) int len; const char *match; ap_rxplus_match(rx, n, &len, &match); - return (match != NULL) ? apr_pstrndup(pool, match, len) : NULL; + return apr_pstrndup(pool, match, len); } -- cgit v1.2.3