mod_proxy_html.c revision 185aa71728867671e105178b4c66fbc22b65ae26
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* Copyright (c) 2003-11, WebThing Ltd
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * Copyright (c) 2011-, The Apache Software Foundation
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * Licensed to the Apache Software Foundation (ASF) under one or more
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * contributor license agreements. See the NOTICE file distributed with
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * this work for additional information regarding copyright ownership.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * The ASF licenses this file to You under the Apache License, Version 2.0
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * (the "License"); you may not use this file except in compliance with
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * the License. You may obtain a copy of the License at
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * Unless required by applicable law or agreed to in writing, software
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * distributed under the License is distributed on an "AS IS" BASIS,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * See the License for the specific language governing permissions and
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * limitations under the License.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* GO_FASTER
74a027db9e9476e96b37e22c0b06407e23335e3csf You can #define GO_FASTER to disable trace logging.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* libxml2 */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* globals set once at startup */
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic apr_status_t (*xml2enc_charset)(request_rec*, xmlCharEncoding*, const char**) = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic apr_status_t (*xml2enc_filter)(request_rec*, const char*, unsigned int) = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *val;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int start;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int end;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct urlmap {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int regflags;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *c;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *doctype;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *encoding;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef enum { ATTR_IGNORE, ATTR_URI, ATTR_EVENT } rewrite_t;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *const fpi_html =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n";
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *const fpi_html_legacy =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *const fpi_xhtml =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *const fpi_xhtml_legacy =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/*#define DEFAULT_DOCTYPE fpi_html */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (p = str; *p; ++p)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (p = ap_strchr(str, '\\'); p; p = ap_strchr(p+1, '\\'))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* This is always utf-8 on entry. We can convert charset within FLUSH */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define FLUSH AP_fwrite(ctx, (chars+begin), (i-begin), 0); begin = i+1
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void pcharacters(void *ctxt, const xmlChar *uchars, int length)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq switch (chars[i]) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '&' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&"); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '<' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "<"); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '>' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, ">"); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '"' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, """); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq default : break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (int(*)(void*))free);
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void pappend(saxctxt *ctx, const char *buf, const size_t len)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char c = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* parse the text for URLs */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!ap_regexec(m->from.r, ctx->buf+offs, nmatch, pmatch, 0)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
74a027db9e9476e96b37e22c0b06407e23335e3csf VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "C: matched %s, substituting %s",
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void pcdata(void *ctxt, const xmlChar *uchars, int length)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* not sure if this should force-flush
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * (i.e. can one cdata section come in multiple calls?)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void pcomment(void *ctxt, const xmlChar *uchars)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void pendElement(void *ctxt, const xmlChar *uname)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html legacy */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* TODO - implement HTML "allowed here" using the stack */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* nah. Keeping the stack is too much overhead */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->offset = 0; /* having dumped it, we can re-use the memory */
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void pstartElement(void *ctxt, const xmlChar *uname,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char** a;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const void** descp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html legacy */
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01416)
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01417)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* TODO - implement HTML "allowed here" */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((enforce > 0) && (desc != NULL) && (desc->attrs_req != NULL))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq linkattrs = apr_hash_get(ctx->cfg->links, name, APR_HASH_KEY_STRING);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq switch (htmlAttrAllowed(desc, (xmlChar*)*a, 2-enforce)) {
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01418)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Bogus HTML attribute %s of %s dropped",
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01419)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Deprecated HTML attribute %s of %s dropped",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq required_attrs--; /* cross off the number still needed */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* fallthrough - required implies valid */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (a[1]) {
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *f;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "H/RX: match at %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "H: matched %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else { /* it fits in the existing space */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* URIs only want one match unless overridden in the config */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq num_match = 0; /* reset here since we're working per-rule */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *f;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "E/RX: match at %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "E: matched %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!a[1])
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* write the attribute, using pcharacters to html-escape
9c4e79e1c3fce91054fd3d00750a48f79d123341niq anything that needs it in the value.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], "=\"", NULL);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pcharacters(ctx, (const xmlChar*)ctx->buf, strlen(ctx->buf));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* if there are more required attributes than we found then complain */
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01420)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "HTML element %s is missing %d required attributes",
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *p;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *q;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!ap_regexec(seek_meta, buf+offs, 2, pmatch, 0)) {
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton while (!apr_isalpha(*++p));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* find content=... string */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq p = apr_strmatch(seek_content, buf+offs+pmatch[0].rm_so,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* if it doesn't contain "content", ignore, don't crash! */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (p != NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (*p) {
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton while (*p && apr_isspace(*p))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (*p != '=')
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton while (*p && apr_isspace(*++p));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (q = p; *q != delim; ++q);
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton for (q = p; *q && !apr_isspace(*q) && (*q != '>'); ++q);
74a027db9e9476e96b37e22c0b06407e23335e3csf "Adding header [%s: %s] from HTML META",
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *interpolate_vars(request_rec *r, const char *str)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *start;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *end;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *delim;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *before;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *after;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *var;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (;;) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq replacement = apr_pstrndup(r->pool, delim+1, end-delim-1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq str = apr_pstrcat(r->pool, before, replacement, after, NULL);
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq const char *err;
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01421)
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq if (ok == 0) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue; /* condition is unsatisfied */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue; /* don't use empty from-pattern */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* evaluate p->cond; continue if unsatisfied */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* create new urlmap with memcpy and append to map */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* interpolate from if flagged to do so */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* interpolate to if flagged to do so */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!f->ctx) {
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *force;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg = ap_get_module_config(f->r->per_dir_config, &proxy_html_module);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq force = apr_table_get(f->r->subprocess_env, "PROXY_HTML_FORCE");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!f->r->proxyreq) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "Non-proxy request; not inserting proxy-html filter";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (!f->r->content_type) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "No content-type; bailing out of proxy-html filter";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (strncasecmp(f->r->content_type, "text/html", 9) &&
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "Non-HTML content; not inserting proxy-html filter";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "No links configured: nothing for proxy-html filter to do";
74a027db9e9476e96b37e22c0b06407e23335e3csf ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r, "%s", errmsg);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq fctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(saxctxt));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* defer dealing with charset_out until after sniffing charset_in
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * so we can support setting one to t'other.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return f->ctx;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic int proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *buf = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (APR_BUCKET_IS_FLUSH(b)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* pass on flush, except at start where it would cause
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * headers to be sent before doc sniffing
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *cenc;
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01422)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "No i18n support found. Install mod_xml2enc if required");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* if we wanted a non-default charset_out, insert the
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * xml2enc filter now that we've sniffed it
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "text/html;charset=",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else /* Normal case, everything worked, utf-8 output */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt, buf,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (int(*)(void*))htmlFreeParserCtxt,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (xmlopts = xmlCtxtUseOptions(ctxt->parser, xmlopts), xmlopts)
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01423)
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01424)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Error in bucket read");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /*ap_fflush(ctxt->f->next, ctxt->bb); // uncomment for debug */
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void *proxy_html_config(apr_pool_t *pool, char *x)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton proxy_html_conf *ret = apr_pcalloc(pool, sizeof(proxy_html_conf));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* ret->interp = 1; */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* don't initialise links and events until they get set/used */
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic void *proxy_html_merge(apr_pool_t *pool, void *BASE, void *ADD)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton proxy_html_conf *conf = apr_palloc(pool, sizeof(proxy_html_conf));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* don't merge declarations - just use the most specific */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->links = (add->links == NULL) ? base->links : add->links;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->events = (add->events == NULL) ? base->events : add->events;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->etag = (add->etag == DEFAULT_ETAG) ? base->etag : add->etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->strip_comments = base->strip_comments | add->strip_comments;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define REGFLAG(n,s,c) ((s&&(ap_strchr_c((s),(c))!=NULL)) ? (n) : 0)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define XREGFLAG(n,s,c) ((!s||(ap_strchr_c((s),(c))==NULL)) ? (n) : 0)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *comp_urlmap(cmd_parms *cmd, urlmap *newmap,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((newmap->flags & M_INTERPOLATE_FROM) || !(newmap->flags & M_REGEX)) {
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq newmap->from.r = ap_pregcomp(cmd->pool, from, newmap->regflags);
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq /* back-compatibility: support old-style ENV expressions
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq * by converting to ap_expr syntax.
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq * 1. var --> env(var)
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq * 2. var=val --> env(var)=val
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq * 3. !var --> !env(var)
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq * 4. !var=val --> env(var)!=val
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq if (ap_rxplus_exec(cmd->temp_pool, old_expr, cond, &newcond)) {
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq /* we got a substitution. Check for the case (3) above
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq * that the regexp gets wrong: a negation without a comparison.
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq newmap->cond = ap_expr_parse_cmd(cmd, cond, 0, &err, NULL);
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *set_urlmap(cmd_parms *cmd, void *CFG, const char *args)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *usage =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Usage: ProxyHTMLURLMap from-pattern to-pattern [flags] [cond]";
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *from;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *to;
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* the args look OK, so let's use them */
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *set_doctype(cmd_parms *cmd, void *CFG,
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton const char *t, const char *l)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *set_flags(cmd_parms *cmd, void *CFG, const char *arg)
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *set_events(cmd_parms *cmd, void *CFG, const char *arg)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->events = apr_array_make(cmd->pool, 20, sizeof(tattr));
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic const char *set_links(cmd_parms *cmd, void *CFG,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq attrs = apr_hash_get(cfg->links, elt, APR_HASH_KEY_STRING);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_hash_set(cfg->links, elt, APR_HASH_KEY_STRING, attrs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Strings to be treated as scripting events"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Options are lowercase, dospath"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Support interpolation and conditions in URLMaps"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Map URLs in Javascript and CSS"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_FLAG("ProxyHTMLStripComments", ap_set_flag_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_TAKE1("ProxyHTMLCharsetOut", ap_set_string_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Usage: ProxyHTMLCharsetOut charset"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Enable proxy-html and xml2enc filters"),
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jortonstatic int mod_proxy_html(apr_pool_t *p, apr_pool_t *p1, apr_pool_t *p2)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq seek_meta = ap_pregcomp(p, "<meta[^>]*(http-equiv)[^>]*>",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq seek_content = apr_strmatch_precompile(p, "content", 0);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq xml2enc_charset = APR_RETRIEVE_OPTIONAL_FN(xml2enc_charset);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq xml2enc_filter = APR_RETRIEVE_OPTIONAL_FN(xml2enc_filter);
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_perror(APLOG_MARK, APLOG_NOTICE, 0, p2, APLOGNO(01425)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "I18n support in mod_proxy_html requires mod_xml2enc. "
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Without it, non-ASCII characters in proxied pages are "
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "likely to display incorrectly.");
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq /* old_expr only needs to last the life of the config phase */
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq old_expr = ap_rxplus_compile(p1, "s/^(!)?(\\w+)((=)(.+))?$/reqenv('$2')$1$4'$5'/");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg = ap_get_module_config(r->per_dir_config, &proxy_html_module);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_add_output_filter("proxy-html", NULL, r, r->connection);
6449c17ae9e13c61628f5f4da8c9a95768f0e9e9jorton static const char *aszSucc[] = { "mod_filter.c", NULL };
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_register_output_filter_protocol("proxy-html", proxy_html_filter,
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq /* move this to pre_config so old_expr is available to interpret
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq * old-style conditions on URL maps.
1861c6caddf9043aff6d7b1a9e2ffb515be652ffniq ap_hook_pre_config(mod_proxy_html, NULL, NULL, APR_HOOK_MIDDLE);