/**
* After performing a successful regex match, you may use this function to
* perform a series of string substitutions based on subexpressions that were
- * matched during the call to ap_regexec
+ * matched during the call to ap_regexec. This function is limited to
+ * result strings of 64K. Consider using ap_pregsub_ex() instead.
* @param p The pool to allocate from
* @param input An arbitrary string containing $1 through $9. These are
* replaced with the corresponding matched sub-expressions
AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, const char *source,
size_t nmatch, ap_regmatch_t pmatch[]);
+/**
+ * After performing a successful regex match, you may use this function to
+ * perform a series of string substitutions based on subexpressions that were
+ * matched during the call to ap_regexec
+ * @param p The pool to allocate from
+ * @param result where to store the result, will be set to NULL on error
+ * @param input An arbitrary string containing $1 through $9. These are
+ * replaced with the corresponding matched sub-expressions
+ * @param source The string that was originally matched to the regex
+ * @param nmatch the nmatch returned from ap_pregex
+ * @param pmatch the pmatch array returned from ap_pregex
+ * @param maxlen the maximum string length to return
+ * @return The substituted string, or NULL on error
+ */
+AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
+ const char *input, const char *source,
+ size_t nmatch, ap_regmatch_t pmatch[],
+ apr_size_t maxlen);
+
/**
* We want to downcase the type/subtype for comparison purposes
* but nothing else because ;parameter=foo values are case sensitive.
* @param source The string that was originally matched to the regex
* @param nmatch the nmatch returned from ap_pregex
* @param pmatch the pmatch array returned from ap_pregex
+ * @param maxlen the maximum string length to append to vb
+ * @return APR_SUCCESS if successful
* @note Just like ap_pregsub(), this function does not copy the part of
* *source before the matching part (i.e. the first pmatch[0].rm_so
* characters).
*/
-AP_DECLARE(void) ap_varbuf_regsub(struct ap_varbuf *vb, const char *input,
- const char *source, size_t nmatch,
- ap_regmatch_t pmatch[]);
+AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
+ const char *input,
+ const char *source, size_t nmatch,
+ ap_regmatch_t pmatch[],
+ apr_size_t maxlen);
/** Read a line from an ap_configfile_t into an ap_varbuf.
* @param vb pointer to the ap_varbuf struct
* AT&T V8 regexp package.
*/
-static char *regsub_core(apr_pool_t *p, struct ap_varbuf *vb,
- const char *input, const char *source,
- size_t nmatch, ap_regmatch_t pmatch[])
+static apr_status_t regsub_core(apr_pool_t *p, char **result,
+ struct ap_varbuf *vb, const char *input,
+ const char *source, size_t nmatch,
+ ap_regmatch_t pmatch[], apr_size_t maxlen)
{
const char *src = input;
- char *dest, *dst;
+ char *dst;
char c;
size_t no;
- int len;
+ apr_size_t len = 0;
+ AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
if (!source)
- return NULL;
+ return APR_EINVAL;
if (!nmatch || nmatch>AP_MAX_REG_MATCH) {
+ len = strlen(src);
+ if (maxlen > 0 && len > maxlen)
+ return APR_ENOMEM;
if (!vb) {
- return apr_pstrdup(p, src);
+ *result = apr_pstrmemdup(p, src, len);
+ return APR_SUCCESS;
}
else {
- ap_varbuf_strcat(vb, src);
- return NULL;
+ ap_varbuf_strmemcat(vb, src, len);
+ return APR_SUCCESS;
}
}
/* First pass, find the size */
-
- len = 0;
-
while ((c = *src++) != '\0') {
if (c == '$' && apr_isdigit(*src))
no = *src++ - '0';
}
+ if (len > maxlen && maxlen > 0)
+ return APR_ENOMEM;
+
if (!vb) {
- dest = dst = apr_pcalloc(p, len + 1);
+ *result = dst = apr_pcalloc(p, len + 1);
}
else {
if (vb->buf && vb->strlen == AP_VARBUF_UNKNOWN)
vb->strlen = strlen(vb->buf);
ap_varbuf_grow(vb, vb->strlen + len);
- dest = dst = vb->buf + vb->strlen;
+ dst = vb->buf + vb->strlen;
vb->strlen += len;
}
}
*dst = '\0';
- return dest;
+ return APR_SUCCESS;
}
+#ifndef AP_PREGSUB_MAXLEN
+#define AP_PREGSUB_MAXLEN 65536
+#endif
AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
const char *source, size_t nmatch,
ap_regmatch_t pmatch[])
{
- return regsub_core(p, NULL, input, source, nmatch, pmatch);
+ char *result;
+ apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
+ pmatch, AP_PREGSUB_MAXLEN);
+ if (rc != APR_SUCCESS)
+ result = NULL;
+ return result;
+}
+
+AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
+ const char *input, const char *source,
+ size_t nmatch, ap_regmatch_t pmatch[],
+ apr_size_t maxlen)
+{
+ apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
+ pmatch, maxlen);
+ if (rc != APR_SUCCESS)
+ *result = NULL;
+ return rc;
}
/*
return "";
}
-AP_DECLARE(void) ap_varbuf_regsub(struct ap_varbuf *vb, const char *input,
- const char *source, size_t nmatch,
- ap_regmatch_t pmatch[])
+AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
+ const char *input,
+ const char *source, size_t nmatch,
+ ap_regmatch_t pmatch[],
+ apr_size_t maxlen)
{
- regsub_core(NULL, vb, input, source, nmatch, pmatch);
+ return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
}
static const char * const oom_message = "[crit] Memory allocation failed, "