mod_proxy_html.c revision 74a027db9e9476e96b37e22c0b06407e23335e3c
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/* 3.1.2 - trivial changes to fix compile on Windows */
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 {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* val;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int start;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int end;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* env;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* val;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct urlmap {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int regflags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* c;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* doctype;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* charset_out;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* encoding;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef enum { ATTR_IGNORE, ATTR_URI, ATTR_EVENT } rewrite_t;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* const fpi_html =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n";
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* const fpi_html_legacy =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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";
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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);
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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",
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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?)
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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 */
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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 */
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)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Bogus HTML attribute %s of %s dropped",
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]) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 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,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 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 */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "HTML element %s is missing %d required attributes",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* p;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* q;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!ap_regexec(seek_meta, buf+offs, 2, pmatch, 0)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!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) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (*p && isspace(*p))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (*p != '=')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (*p && isspace(*++p));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (q = p; *q != delim; ++q);
74a027db9e9476e96b37e22c0b06407e23335e3csf "Adding header [%s: %s] from HTML META",
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* interpolate_vars(request_rec* r, const char* str)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* start;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* end;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* delim;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* before;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* after;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* replacement;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 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);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* thisval;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq thisval = apr_table_get(r->subprocess_env, p->cond->env);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* required to be "anything" */
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) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 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;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic int proxy_html_filter(ap_filter_t* f, apr_bucket_brigade* bb)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 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)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* cenc;
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)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Error in bucket read");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /*ap_fflush(ctxt->f->next, ctxt->bb); // uncomment for debug */
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void* proxy_html_config(apr_pool_t* pool, char* x)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 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 */
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void* proxy_html_merge(apr_pool_t* pool, void* BASE, void* ADD)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 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)
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void comp_urlmap(apr_pool_t* pool, urlmap* newmap, const char* from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((newmap->flags & M_INTERPOLATE_FROM) || !(newmap->flags & M_REGEX)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->from.r = ap_pregcomp(pool, from, newmap->regflags);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond->env = cond_copy = apr_pstrdup(pool, cond+1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond->env = cond_copy = apr_pstrdup(pool, cond);
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_urlmap(cmd_parms* cmd, void* CFG, const char* args)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* usage =
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Usage: ProxyHTMLURLMap from-pattern to-pattern [flags] [cond]";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* from;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* the args look OK, so let's use them */
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_doctype(cmd_parms* cmd, void* CFG,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* t, const char* l)
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_flags(cmd_parms* cmd, void* CFG, const char* arg)
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_events(cmd_parms* cmd, void* CFG, const char* arg)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->events = apr_array_make(cmd->pool, 20, sizeof(tattr));
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"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic 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);
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.");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg = ap_get_module_config(r->per_dir_config, &proxy_html_module);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_add_output_filter("proxy-html", NULL, r, r->connection);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq static const char* aszSucc[] = { "mod_filter.c", NULL };
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_register_output_filter_protocol("proxy-html", proxy_html_filter,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_hook_post_config(mod_proxy_html, NULL, NULL, APR_HOOK_MIDDLE);