mod_proxy_html.c revision 74a027db9e9476e96b37e22c0b06407e23335e3c
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* Copyright (c) 2003-11, WebThing Ltd
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * Copyright (c) 2011-, The Apache Software Foundation
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *
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 *
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * http://www.apache.org/licenses/LICENSE-2.0
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *
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 */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* GO_FASTER
74a027db9e9476e96b37e22c0b06407e23335e3csf You can #define GO_FASTER to disable trace logging.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq*/
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifdef GO_FASTER
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define VERBOSE(x)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define VERBOSEB(x)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define VERBOSE(x) if (verbose) x
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define VERBOSEB(x) if (verbose) {x}
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* 3.1.2 - trivial changes to fix compile on Windows */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define VERSION_STRING "proxy_html/3.1.2"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include <ctype.h>
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* libxml2 */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include <libxml/HTMLparser.h>
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "http_protocol.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "http_config.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "http_log.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "apr_strings.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "apr_hash.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "apr_strmatch.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "apr_optional.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "mod_xml2enc.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#include "http_request.h"
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/* globals set once at startup */
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic ap_regex_t* seek_meta;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const apr_strmatch_pattern* seek_content;
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;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niqmodule AP_MODULE_DECLARE_DATA proxy_html_module;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_HTML 0x01
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_EVENTS 0x02
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_CDATA 0x04
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_REGEX 0x08
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_ATSTART 0x10
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_ATEND 0x20
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_LAST 0x40
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_NOTLAST 0x80
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_INTERPOLATE_TO 0x100
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define M_INTERPOLATE_FROM 0x200
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* val;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq} tattr;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int start;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int end;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq} meta;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* env;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* val;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int rel;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq} rewritecond;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct urlmap {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq struct urlmap* next;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int regflags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq union {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* c;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_regex_t* r;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq } from;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq rewritecond* cond;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq} urlmap;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* doctype;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq unsigned int flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t bufsz;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_hash_t* links;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_array_header_t* events;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* charset_out;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int extfix;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int metafix;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int strip_comments;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int interp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int enabled;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq} proxy_html_conf;
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef struct {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_filter_t* f;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq htmlParserCtxtPtr parser;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_bucket_brigade* bb;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* buf;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t offset;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t avail;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* encoding;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq} saxctxt;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define NORM_LC 0x1
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define NORM_MSSLASH 0x2
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define NORM_RESET 0x4
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic htmlSAXHandler sax;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niqtypedef enum { ATTR_IGNORE, ATTR_URI, ATTR_EVENT } rewrite_t;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
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";
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* const html_etag = ">";
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* const xhtml_etag = " />";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq/*#define DEFAULT_DOCTYPE fpi_html */
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* const DEFAULT_DOCTYPE = "";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define DEFAULT_ETAG html_etag
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void normalise(unsigned int flags, char* str)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* p;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (flags & NORM_LC)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (p = str; *p; ++p)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (isupper(*p))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *p = tolower(*p);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (flags & NORM_MSSLASH)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (p = ap_strchr(str, '\\'); p; p = ap_strchr(p+1, '\\'))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *p = '/';
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define consume_buffer(ctx,inbuf,bytes,flag) \
9c4e79e1c3fce91054fd3d00750a48f79d123341niq htmlParseChunk(ctx->parser, inbuf, bytes, flag)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#define AP_fwrite(ctx,inbuf,bytes,flush) \
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fwrite(ctx->f->next, ctx->bb, inbuf, bytes);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
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{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* chars = (const char*) uchars;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq saxctxt* ctx = (saxctxt*) ctxt;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int i;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int begin;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (begin=i=0; i<length; i++) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq switch (chars[i]) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '&' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&amp;"); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '<' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&lt;"); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '>' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&gt;"); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case '"' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&quot;"); break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq default : break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq FLUSH;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void preserve(saxctxt* ctx, const size_t len)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* newbuf;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (len <= (ctx->avail - ctx->offset))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else while (len > (ctx->avail - ctx->offset))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->avail += ctx->cfg->bufsz;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newbuf = realloc(ctx->buf, ctx->avail);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (newbuf != ctx->buf) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctx->buf)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_pool_cleanup_kill(ctx->f->r->pool, ctx->buf,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (int(*)(void*))free);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_pool_cleanup_register(ctx->f->r->pool, newbuf,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (int(*)(void*))free, apr_pool_cleanup_null);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf = newbuf;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void pappend(saxctxt* ctx, const char* buf, const size_t len)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq preserve(ctx, len);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+ctx->offset, buf, len);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->offset += len;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void dump_content(saxctxt* ctx)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* m;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* found;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t s_from, s_to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char c = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int nmatch;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_regmatch_t pmatch[10];
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* subs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t len, offs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* themap = ctx->map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifndef GO_FASTER
74a027db9e9476e96b37e22c0b06407e23335e3csf int verbose = APLOGrtrace1(ctx->f->r);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pappend(ctx, &c, 1); /* append null byte */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* parse the text for URLs */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (m = themap; m; m = m->next) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!(m->flags & M_CDATA))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (m->flags & M_REGEX) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq nmatch = 10;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!ap_regexec(m->from.r, ctx->buf+offs, nmatch, pmatch, 0)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq match = pmatch[0].rm_so;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_from = pmatch[0].rm_eo - match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq nmatch, pmatch);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_to = strlen(subs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len = strlen(ctx->buf);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs += match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq VERBOSEB(
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* f = apr_pstrndup(ctx->f->r->pool,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf + offs, s_from);
74a027db9e9476e96b37e22c0b06407e23335e3csf ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "C/RX: match at %s, substituting %s", f, subs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq )
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (s_to > s_from) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq preserve(ctx, s_to - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - offs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+offs, subs, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf + offs, subs, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - offs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs += s_to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_from = strlen(m->from.c);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_to = strlen(m->to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (found = strstr(ctx->buf, m->from.c); found;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq found = strstr(ctx->buf+match+s_to, m->from.c)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq match = found - ctx->buf;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((m->flags & M_ATSTART) && (match != 0))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len = strlen(ctx->buf);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((m->flags & M_ATEND) && (match < (len - s_from)))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
74a027db9e9476e96b37e22c0b06407e23335e3csf VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "C: matched %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq m->from.c, m->to));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (s_to > s_from) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq preserve(ctx, s_to - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - match);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+match, m->to, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+match, m->to, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - match);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_fwrite(ctx, ctx->buf, strlen(ctx->buf), 1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void pcdata(void* ctxt, const xmlChar *uchars, int length)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* chars = (const char*) uchars;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq saxctxt* ctx = (saxctxt*) ctxt;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctx->cfg->extfix) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pappend(ctx, chars, length);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* not sure if this should force-flush
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * (i.e. can one cdata section come in multiple calls?)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_fwrite(ctx, chars, length, 0);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void pcomment(void* ctxt, const xmlChar *uchars)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* chars = (const char*) uchars;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq saxctxt* ctx = (saxctxt*) ctxt;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctx->cfg->strip_comments)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctx->cfg->extfix) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pappend(ctx, "<!--", 4);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pappend(ctx, chars, strlen(chars));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pappend(ctx, "-->", 3);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputs(ctx->f->next, ctx->bb, "<!--");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_fwrite(ctx, chars, strlen(chars), 1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputs(ctx->f->next, ctx->bb, "-->");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void pendElement(void* ctxt, const xmlChar* uname)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq saxctxt* ctx = (saxctxt*) ctxt;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* name = (const char*) uname;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const htmlElemDesc* desc = htmlTagLookup(uname);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!desc || desc->depr)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if ((ctx->cfg->doctype == fpi_html)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq || (ctx->cfg->doctype == fpi_xhtml)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html legacy */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!desc)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* TODO - implement HTML "allowed here" using the stack */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* nah. Keeping the stack is too much overhead */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctx->offset > 0) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq dump_content(ctx);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->offset = 0; /* having dumped it, we can re-use the memory */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!desc || !desc->empty) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fprintf(ctx->f->next, ctx->bb, "</%s>", name);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void pstartElement(void* ctxt, const xmlChar* uname,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const xmlChar** uattrs)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int required_attrs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int num_match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t offs, len;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* subs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq rewrite_t is_uri;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char** a;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* m;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t s_to, s_from, match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* found;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq saxctxt* ctx = (saxctxt*) ctxt;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t nmatch;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_regmatch_t pmatch[10];
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifndef GO_FASTER
74a027db9e9476e96b37e22c0b06407e23335e3csf int verbose = APLOGrtrace1(ctx->f->r);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_array_header_t *linkattrs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int i;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* name = (const char*) uname;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char** attrs = (const char**) uattrs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const htmlElemDesc* desc = htmlTagLookup(uname);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* themap = ctx->map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifdef HAVE_STACK
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const void** descp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int enforce = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq enforce = 2;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!desc || desc->depr)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if ((ctx->cfg->doctype == fpi_html)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq || (ctx->cfg->doctype == fpi_xhtml)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq enforce = 1;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* enforce html legacy */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!desc) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!desc && enforce) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Bogus HTML element %s dropped", name);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (desc && desc->depr && (enforce == 2)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Deprecated HTML element %s dropped", name);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifdef HAVE_STACK
9c4e79e1c3fce91054fd3d00750a48f79d123341niq descp = apr_array_push(ctx->stack);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *descp = desc;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* TODO - implement HTML "allowed here" */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputc(ctx->f->next, ctx->bb, '<');
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputs(ctx->f->next, ctx->bb, name);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq required_attrs = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((enforce > 0) && (desc != NULL) && (desc->attrs_req != NULL))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (a = desc->attrs_req; *a; a++)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ++required_attrs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (attrs) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq linkattrs = apr_hash_get(ctx->cfg->links, name, APR_HASH_KEY_STRING);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (a = attrs; *a; a += 2) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (desc && enforce > 0) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq switch (htmlAttrAllowed(desc, (xmlChar*)*a, 2-enforce)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case HTML_INVALID:
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Bogus HTML attribute %s of %s dropped",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *a, name);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case HTML_DEPRECATED:
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Deprecated HTML attribute %s of %s dropped",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *a, name);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case HTML_REQUIRED:
9c4e79e1c3fce91054fd3d00750a48f79d123341niq required_attrs--; /* cross off the number still needed */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* fallthrough - required implies valid */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq default:
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->offset = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (a[1]) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pappend(ctx, a[1], strlen(a[1])+1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq is_uri = ATTR_IGNORE;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (linkattrs) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq tattr* attrs = (tattr*) linkattrs->elts;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (i=0; i < linkattrs->nelts; ++i) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!strcmp(*a, attrs[i].val)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq is_uri = ATTR_URI;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((is_uri == ATTR_IGNORE) && ctx->cfg->extfix
9c4e79e1c3fce91054fd3d00750a48f79d123341niq && (ctx->cfg->events != NULL)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (i=0; i < ctx->cfg->events->nelts; ++i) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq tattr* attrs = (tattr*) ctx->cfg->events->elts;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!strcmp(*a, attrs[i].val)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq is_uri = ATTR_EVENT;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq switch (is_uri) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case ATTR_URI:
9c4e79e1c3fce91054fd3d00750a48f79d123341niq num_match = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (m = themap; m; m = m->next) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!(m->flags & M_HTML))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (m->flags & M_REGEX) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq nmatch = 10;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!ap_regexec(m->from.r, ctx->buf, nmatch,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pmatch, 0)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ++num_match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs = match = pmatch[0].rm_so;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_from = pmatch[0].rm_eo - match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq subs = ap_pregsub(ctx->f->r->pool, m->to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf, nmatch, pmatch);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq VERBOSE({
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* f;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq f = apr_pstrndup(ctx->f->r->pool,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf + offs, s_from);
74a027db9e9476e96b37e22c0b06407e23335e3csf ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "H/RX: match at %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq f, subs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq })
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_to = strlen(subs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len = strlen(ctx->buf);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (s_to > s_from) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq preserve(ctx, s_to - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+offs+s_to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf+offs+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - offs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+offs, subs, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf + offs, subs, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+offs+s_to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf+offs+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - offs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq } else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_from = strlen(m->from.c);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!strncasecmp(ctx->buf, m->from.c, s_from)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ++num_match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_to = strlen(m->to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len = strlen(ctx->buf);
74a027db9e9476e96b37e22c0b06407e23335e3csf VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "H: matched %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq m->from.c, m->to));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (s_to > s_from) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq preserve(ctx, s_to - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+s_to, ctx->buf+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf, m->to, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else { /* it fits in the existing space */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf, m->to, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+s_to, ctx->buf+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* URIs only want one match unless overridden in the config */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((num_match > 0) && !(m->flags & M_NOTLAST))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case ATTR_EVENT:
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (m = themap; m; m = m->next) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq num_match = 0; /* reset here since we're working per-rule */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!(m->flags & M_EVENTS))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (m->flags & M_REGEX) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq nmatch = 10;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!ap_regexec(m->from.r, ctx->buf+offs,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq nmatch, pmatch, 0)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq match = pmatch[0].rm_so;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_from = pmatch[0].rm_eo - match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq nmatch, pmatch);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq VERBOSE({
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* f;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq f = apr_pstrndup(ctx->f->r->pool,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf + offs, s_from);
74a027db9e9476e96b37e22c0b06407e23335e3csf ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "E/RX: match at %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq f, subs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq })
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_to = strlen(subs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs += match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len = strlen(ctx->buf);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (s_to > s_from) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq preserve(ctx, s_to - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+offs+s_to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf+offs+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - offs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+offs, subs, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf + offs, subs, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+offs+s_to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf+offs+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - offs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs += s_to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ++num_match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq found = strstr(ctx->buf, m->from.c);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((m->flags & M_ATSTART) && (found != ctx->buf))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (found) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_from = strlen(m->from.c);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq s_to = strlen(m->to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq match = found - ctx->buf;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((s_from < strlen(found))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq && (m->flags & M_ATEND)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq found = strstr(ctx->buf+match+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq m->from.c);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq found = strstr(ctx->buf+match+s_to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq m->from.c);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
74a027db9e9476e96b37e22c0b06407e23335e3csf VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "E: matched %s, substituting %s",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq m->from.c, m->to));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len = strlen(ctx->buf);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (s_to > s_from) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq preserve(ctx, s_to - s_from);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+match+s_to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf+match+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - match);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+match, m->to, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memcpy(ctx->buf+match, m->to, s_to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memmove(ctx->buf+match+s_to,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->buf+match+s_from,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq len + 1 - s_from - match);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ++num_match;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (num_match && (m->flags & M_LAST))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq case ATTR_IGNORE:
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!a[1])
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], NULL);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctx->cfg->flags != 0)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq normalise(ctx->cfg->flags, ctx->buf);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* write the attribute, using pcharacters to html-escape
9c4e79e1c3fce91054fd3d00750a48f79d123341niq anything that needs it in the value.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], "=\"", NULL);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pcharacters(ctx, (const xmlChar*)ctx->buf, strlen(ctx->buf));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputc(ctx->f->next, ctx->bb, '"');
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->offset = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (desc && desc->empty)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputs(ctx->f->next, ctx->bb, ctx->cfg->etag);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputc(ctx->f->next, ctx->bb, '>');
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((enforce > 0) && (required_attrs > 0)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* if there are more required attributes than we found then complain */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "HTML element %s is missing %d required attributes",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq name, required_attrs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
74a027db9e9476e96b37e22c0b06407e23335e3csfstatic meta* metafix(request_rec* r, const char* buf)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq meta* ret = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq size_t offs = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* p;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* q;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* header;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* content;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_regmatch_t pmatch[2];
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char delim;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!ap_regexec(seek_meta, buf+offs, 2, pmatch, 0)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq header = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq content = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq p = buf+offs+pmatch[1].rm_eo;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (!isalpha(*++p));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (q = p; isalnum(*q) || (*q == '-'); ++q);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq header = apr_pstrndup(r->pool, p, q-p);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (strncasecmp(header, "Content-", 8)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* find content=... string */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq p = apr_strmatch(seek_content, buf+offs+pmatch[0].rm_so,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq pmatch[0].rm_eo - pmatch[0].rm_so);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* if it doesn't contain "content", ignore, don't crash! */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (p != NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (*p) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq p += 7;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (*p && isspace(*p))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ++p;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (*p != '=')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq while (*p && isspace(*++p));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((*p == '\'') || (*p == '"')) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq delim = *p++;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (q = p; *q != delim; ++q);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq } else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (q = p; *q && !isspace(*q) && (*q != '>'); ++q);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq content = apr_pstrndup(r->pool, p, q-p);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (!strncasecmp(header, "Content-Type", 12)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ret = apr_palloc(r->pool, sizeof(meta));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ret->start = pmatch[0].rm_so;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ret->end = pmatch[0].rm_eo;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (header && content) {
74a027db9e9476e96b37e22c0b06407e23335e3csf#ifndef GO_FASTER
74a027db9e9476e96b37e22c0b06407e23335e3csf ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
74a027db9e9476e96b37e22c0b06407e23335e3csf "Adding header [%s: %s] from HTML META",
74a027db9e9476e96b37e22c0b06407e23335e3csf header, content);
74a027db9e9476e96b37e22c0b06407e23335e3csf#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_table_setn(r->headers_out, header, content);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq offs += pmatch[0].rm_eo;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return ret;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* interpolate_vars(request_rec* r, const char* str)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
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 start = str;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (start = ap_strstr_c(start, "${"), start == NULL)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (end = ap_strchr_c(start+2, '}'), end == NULL)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq break;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq delim = ap_strchr_c(start, '|');
9c4e79e1c3fce91054fd3d00750a48f79d123341niq before = apr_pstrndup(r->pool, str, start-str);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq after = end+1;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (delim) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq var = apr_pstrndup(r->pool, start+2, delim-start-2);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq var = apr_pstrndup(r->pool, start+2, end-start-2);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq replacement = apr_table_get(r->subprocess_env, var);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!replacement) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (delim)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq replacement = apr_pstrndup(r->pool, delim+1, end-delim-1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq replacement = "";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq str = apr_pstrcat(r->pool, before, replacement, after, NULL);
74a027db9e9476e96b37e22c0b06407e23335e3csf ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Interpolating %s => %s", var, replacement);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return str;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void fixup_rules(saxctxt* ctx)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* thisval;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* newp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* p;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* prev = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq request_rec* r = ctx->f->r;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int has_cond;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (p = ctx->cfg->map; p; p = p->next) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq has_cond = -1;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (p->cond != NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq thisval = apr_table_get(r->subprocess_env, p->cond->env);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!p->cond->val) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* required to be "anything" */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (thisval)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq has_cond = 1; /* satisfied */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq has_cond = 0; /* unsatisfied */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (thisval && !strcasecmp(p->cond->val, thisval)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq has_cond = 1; /* satisfied */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq has_cond = 0; /* unsatisfied */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (((has_cond == 0) && (p->cond->rel ==1))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq || ((has_cond == 1) && (p->cond->rel == -1))) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue; /* condition is unsatisfied */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newp = apr_pmemdup(r->pool, p, sizeof(urlmap));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (newp->flags & M_INTERPOLATE_FROM) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newp->from.c = interpolate_vars(r, newp->from.c);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!newp->from.c || !*newp->from.c)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq continue; /* don't use empty from-pattern */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (newp->flags & M_REGEX) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newp->from.r = ap_pregcomp(r->pool, newp->from.c,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newp->regflags);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (newp->flags & M_INTERPOLATE_TO) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newp->to = interpolate_vars(r, newp->to);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
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
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (prev != NULL)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq prev->next = newp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctx->map = newp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq prev = newp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (prev)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq prev->next = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic saxctxt* check_filter_init (ap_filter_t* f)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq saxctxt* fctx;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!f->ctx) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* force;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* errmsg = NULL;
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
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!force) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!f->r->proxyreq) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "Non-proxy request; not inserting proxy-html filter";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (!f->r->content_type) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "No content-type; bailing out of proxy-html filter";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (strncasecmp(f->r->content_type, "text/html", 9) &&
9c4e79e1c3fce91054fd3d00750a48f79d123341niq strncasecmp(f->r->content_type,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "application/xhtml+xml", 21)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "Non-HTML content; not inserting proxy-html filter";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!cfg->links) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq errmsg = "No links configured: nothing for proxy-html filter to do";
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (errmsg) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifndef GO_FASTER
74a027db9e9476e96b37e22c0b06407e23335e3csf ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r, "%s", errmsg);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_remove_output_filter(f);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq fctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(saxctxt));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq fctx->f = f;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq fctx->bb = apr_brigade_create(f->r->pool,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq f->r->connection->bucket_alloc);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq fctx->cfg = cfg;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_table_unset(f->r->headers_out, "Content-Length");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cfg->interp)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq fixup_rules(fctx);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq fctx->map = cfg->map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* defer dealing with charset_out until after sniffing charset_in
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * so we can support setting one to t'other.
9c4e79e1c3fce91054fd3d00750a48f79d123341niq */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return f->ctx;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic int proxy_html_filter(ap_filter_t* f, apr_bucket_brigade* bb)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_bucket* b;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq meta* m = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq xmlCharEncoding enc;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* buf = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_size_t bytes = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifndef USE_OLD_LIBXML2
9c4e79e1c3fce91054fd3d00750a48f79d123341niq int xmlopts = XML_PARSE_RECOVER | XML_PARSE_NONET |
9c4e79e1c3fce91054fd3d00750a48f79d123341niq XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq saxctxt* ctxt = check_filter_init(f);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!ctxt)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return ap_pass_brigade(f->next, bb);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (b = APR_BRIGADE_FIRST(bb);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq b != APR_BRIGADE_SENTINEL(bb);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq b = APR_BUCKET_NEXT(b)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (APR_BUCKET_IS_METADATA(b)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (APR_BUCKET_IS_EOS(b)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctxt->parser != NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq consume_buffer(ctxt, buf, 0, 1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq APR_BRIGADE_INSERT_TAIL(ctxt->bb,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_bucket_eos_create(ctxt->bb->bucket_alloc));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_pass_brigade(ctxt->f->next, ctxt->bb);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
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 */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctxt->parser != NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fflush(ctxt->f->next, ctxt->bb);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq == APR_SUCCESS) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctxt->parser == NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* cenc;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!xml2enc_charset ||
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (xml2enc_charset(f->r, &enc, &cenc) != APR_SUCCESS)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!xml2enc_charset)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "No i18n support found. Install mod_xml2enc if required");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq enc = XML_CHAR_ENCODING_NONE;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_set_content_type(f->r, "text/html;charset=utf-8");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* if we wanted a non-default charset_out, insert the
9c4e79e1c3fce91054fd3d00750a48f79d123341niq * xml2enc filter now that we've sniffed it
9c4e79e1c3fce91054fd3d00750a48f79d123341niq */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctxt->cfg->charset_out && xml2enc_filter) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (*ctxt->cfg->charset_out != '*')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cenc = ctxt->cfg->charset_out;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq xml2enc_filter(f->r, cenc, ENCIO_OUTPUT);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_set_content_type(f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_pstrcat(f->r->pool,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "text/html;charset=",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cenc, NULL));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else /* Normal case, everything worked, utf-8 output */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_set_content_type(f->r, "text/html;charset=utf-8");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt, buf,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq 4, 0, enc);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq buf += 4;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq bytes -= 4;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctxt->parser == NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_status_t rv = ap_pass_brigade(f->next, bb);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_remove_output_filter(f);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return rv;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_pool_cleanup_register(f->r->pool, ctxt->parser,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (int(*)(void*))htmlFreeParserCtxt,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_pool_cleanup_null);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#ifndef USE_OLD_LIBXML2
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (xmlopts = xmlCtxtUseOptions(ctxt->parser, xmlopts), xmlopts)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Unsupported parser opts %x", xmlopts);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq#endif
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (ctxt->cfg->metafix)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq m = metafix(f->r, buf);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (m) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq consume_buffer(ctxt, buf, m->start, 0);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq consume_buffer(ctxt, buf+m->end, bytes-m->end, 0);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq consume_buffer(ctxt, buf, bytes, 0);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq consume_buffer(ctxt, buf, bytes, 0);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Error in bucket read");
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /*ap_fflush(ctxt->f->next, ctxt->bb); // uncomment for debug */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_brigade_cleanup(bb);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return APR_SUCCESS;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void* proxy_html_config(apr_pool_t* pool, char* x)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* ret = apr_pcalloc(pool, sizeof(proxy_html_conf));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ret->doctype = DEFAULT_DOCTYPE;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ret->etag = DEFAULT_ETAG;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ret->bufsz = 8192;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* ret->interp = 1; */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* don't initialise links and events until they get set/used */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return ret;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void* proxy_html_merge(apr_pool_t* pool, void* BASE, void* ADD)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* base = (proxy_html_conf*) BASE;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* add = (proxy_html_conf*) ADD;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* conf = apr_palloc(pool, sizeof(proxy_html_conf));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
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
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->charset_out = (add->charset_out == NULL)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ? base->charset_out : add->charset_out;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (add->map && base->map) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* a;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->map = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (a = base->map; a; a = a->next) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* save = conf->map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->map->next = save;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (a = add->map; a; a = a->next) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* save = conf->map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->map->next = save;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->map = add->map ? add->map : base->map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->doctype = (add->doctype == DEFAULT_DOCTYPE)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ? base->doctype : add->doctype;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->etag = (add->etag == DEFAULT_ETAG) ? base->etag : add->etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->bufsz = add->bufsz;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (add->flags & NORM_RESET) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->flags = add->flags ^ NORM_RESET;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->metafix = add->metafix;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->extfix = add->extfix;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->interp = add->interp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->strip_comments = add->strip_comments;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->enabled = add->enabled;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->flags = base->flags | add->flags;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->metafix = base->metafix | add->metafix;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->extfix = base->extfix | add->extfix;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->interp = base->interp | add->interp;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->strip_comments = base->strip_comments | add->strip_comments;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq conf->enabled = add->enabled | base->enabled;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return conf;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
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 const char* to, const char* flags, const char* cond)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* eq;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->flags
9c4e79e1c3fce91054fd3d00750a48f79d123341niq = XREGFLAG(M_HTML,flags,'h')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | XREGFLAG(M_EVENTS,flags,'e')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | XREGFLAG(M_CDATA,flags,'c')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(M_ATSTART,flags,'^')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(M_ATEND,flags,'$')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(M_REGEX,flags,'R')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(M_LAST,flags,'L')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(M_NOTLAST,flags,'l')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(M_INTERPOLATE_TO,flags,'V')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(M_INTERPOLATE_FROM,flags,'v');
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if ((newmap->flags & M_INTERPOLATE_FROM) || !(newmap->flags & M_REGEX)) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->from.c = from;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->to = to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->regflags
9c4e79e1c3fce91054fd3d00750a48f79d123341niq = REGFLAG(AP_REG_EXTENDED,flags,'x')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(AP_REG_ICASE,flags,'i')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(AP_REG_NOSUB,flags,'n')
9c4e79e1c3fce91054fd3d00750a48f79d123341niq | REGFLAG(AP_REG_NEWLINE,flags,'s');
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->from.r = ap_pregcomp(pool, from, newmap->regflags);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->to = to;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cond != NULL) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq char* cond_copy;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond = apr_pcalloc(pool, sizeof(rewritecond));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cond[0] == '!') {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond->rel = -1;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond->env = cond_copy = apr_pstrdup(pool, cond+1);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq } else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond->rel = 1;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond->env = cond_copy = apr_pstrdup(pool, cond);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq eq = ap_strchr(++cond_copy, '=');
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (eq) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq *eq = 0;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond->val = eq+1;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->cond = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_urlmap(cmd_parms* cmd, void* CFG, const char* args)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg = (proxy_html_conf*)CFG;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* map;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_pool_t* pool = cmd->pool;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq urlmap* newmap;
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 const char* cond = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (from = ap_getword_conf(cmd->pool, &args), !from)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return usage;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (to = ap_getword_conf(cmd->pool, &args), !to)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return usage;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq flags = ap_getword_conf(cmd->pool, &args);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (flags && *flags)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cond = ap_getword_conf(cmd->pool, &args);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cond && !*cond)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cond = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq /* the args look OK, so let's use them */
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap = apr_palloc(pool, sizeof(urlmap));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq newmap->next = NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cfg->map) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq for (map = cfg->map; map->next; map = map->next);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq map->next = newmap;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->map = newmap;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq comp_urlmap(cmd->pool, newmap, from, to, flags, cond);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_doctype(cmd_parms* cmd, void* CFG,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* t, const char* l)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg = (proxy_html_conf*)CFG;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!strcasecmp(t, "xhtml")) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->etag = xhtml_etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (l && !strcasecmp(l, "legacy"))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->doctype = fpi_xhtml_legacy;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->doctype = fpi_xhtml;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (!strcasecmp(t, "html")) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->etag = html_etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (l && !strcasecmp(l, "legacy"))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->doctype = fpi_html_legacy;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->doctype = fpi_html;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->doctype = apr_pstrdup(cmd->pool, t);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (l && ((l[0] == 'x') || (l[0] == 'X')))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->etag = xhtml_etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->etag = html_etag;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_flags(cmd_parms* cmd, void* CFG, const char* arg)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg = CFG;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (arg && *arg) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!strcmp(arg, "lowercase"))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->flags |= NORM_LC;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (!strcmp(arg, "dospath"))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->flags |= NORM_MSSLASH;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq else if (!strcmp(arg, "reset"))
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->flags |= NORM_RESET;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_events(cmd_parms* cmd, void* CFG, const char* arg)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq tattr* attr;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg = CFG;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cfg->events == NULL)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->events = apr_array_make(cmd->pool, 20, sizeof(tattr));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq attr = apr_array_push(cfg->events);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq attr->val = arg;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const char* set_links(cmd_parms* cmd, void* CFG,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq const char* elt, const char* att)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_array_header_t* attrs;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq tattr* attr;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg = CFG;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cfg->links == NULL)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg->links = apr_hash_make(cmd->pool);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq
9c4e79e1c3fce91054fd3d00750a48f79d123341niq attrs = apr_hash_get(cfg->links, elt, APR_HASH_KEY_STRING);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!attrs) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq attrs = apr_array_make(cmd->pool, 2, sizeof(tattr*));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq apr_hash_set(cfg->links, elt, APR_HASH_KEY_STRING, attrs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq attr = apr_array_push(attrs);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq attr->val = att;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return NULL;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic const command_rec proxy_html_cmds[] = {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_ITERATE("ProxyHTMLEvents", set_events, NULL,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Strings to be treated as scripting events"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_ITERATE2("ProxyHTMLLinks", set_links, NULL,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Declare HTML Attributes"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_RAW_ARGS("ProxyHTMLURLMap", set_urlmap, NULL,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Map URL From To"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_TAKE12("ProxyHTMLDoctype", set_doctype, NULL,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "(HTML|XHTML) [Legacy]"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_ITERATE("ProxyHTMLFixups", set_flags, NULL,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Options are lowercase, dospath"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_FLAG("ProxyHTMLMeta", ap_set_flag_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (void*)APR_OFFSETOF(proxy_html_conf, metafix),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Fix META http-equiv elements"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_FLAG("ProxyHTMLInterp", ap_set_flag_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (void*)APR_OFFSETOF(proxy_html_conf, interp),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Support interpolation and conditions in URLMaps"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_FLAG("ProxyHTMLExtended", ap_set_flag_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (void*)APR_OFFSETOF(proxy_html_conf, extfix),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Map URLs in Javascript and CSS"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_FLAG("ProxyHTMLStripComments", ap_set_flag_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (void*)APR_OFFSETOF(proxy_html_conf, strip_comments),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Strip out comments"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_TAKE1("ProxyHTMLBufSize", ap_set_int_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (void*)APR_OFFSETOF(proxy_html_conf, bufsz),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Buffer size"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_TAKE1("ProxyHTMLCharsetOut", ap_set_string_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (void*)APR_OFFSETOF(proxy_html_conf, charset_out),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF, "Usage: ProxyHTMLCharsetOut charset"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_INIT_FLAG("ProxyHTMLEnable", ap_set_flag_slot,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq (void*)APR_OFFSETOF(proxy_html_conf, enabled),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq RSRC_CONF|ACCESS_CONF,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq "Enable proxy-html and xml2enc filters"),
9c4e79e1c3fce91054fd3d00750a48f79d123341niq { NULL }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq};
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic int mod_proxy_html(apr_pool_t* p, apr_pool_t* p1, apr_pool_t* p2,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq server_rec* s)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_add_version_component(p, VERSION_STRING);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq seek_meta = ap_pregcomp(p, "<meta[^>]*(http-equiv)[^>]*>",
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_REG_EXTENDED|AP_REG_ICASE);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq seek_content = apr_strmatch_precompile(p, "content", 0);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq memset(&sax, 0, sizeof(htmlSAXHandler));
9c4e79e1c3fce91054fd3d00750a48f79d123341niq sax.startElement = pstartElement;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq sax.endElement = pendElement;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq sax.characters = pcharacters;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq sax.comment = pcomment;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq sax.cdataBlock = pcdata;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq xml2enc_charset = APR_RETRIEVE_OPTIONAL_FN(xml2enc_charset);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq xml2enc_filter = APR_RETRIEVE_OPTIONAL_FN(xml2enc_filter);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (!xml2enc_charset) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_log_perror(APLOG_MARK, APLOG_NOTICE, 0, p2,
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 }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq return OK;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void proxy_html_insert(request_rec* r)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_conf* cfg;
9c4e79e1c3fce91054fd3d00750a48f79d123341niq cfg = ap_get_module_config(r->per_dir_config, &proxy_html_module);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (cfg->enabled) {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq if (xml2enc_filter)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq xml2enc_filter(r, NULL, ENCIO_INPUT_CHECKS);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_add_output_filter("proxy-html", NULL, r, r->connection);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq }
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqstatic void proxy_html_hooks(apr_pool_t* p)
9c4e79e1c3fce91054fd3d00750a48f79d123341niq{
9c4e79e1c3fce91054fd3d00750a48f79d123341niq static const char* aszSucc[] = { "mod_filter.c", NULL };
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_register_output_filter_protocol("proxy-html", proxy_html_filter,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq NULL, AP_FTYPE_RESOURCE,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_hook_post_config(mod_proxy_html, NULL, NULL, APR_HOOK_MIDDLE);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq ap_hook_insert_filter(proxy_html_insert, NULL, aszSucc, APR_HOOK_MIDDLE);
9c4e79e1c3fce91054fd3d00750a48f79d123341niq}
9c4e79e1c3fce91054fd3d00750a48f79d123341niqmodule AP_MODULE_DECLARE_DATA proxy_html_module = {
9c4e79e1c3fce91054fd3d00750a48f79d123341niq STANDARD20_MODULE_STUFF,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_config,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_merge,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq NULL,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq NULL,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_cmds,
9c4e79e1c3fce91054fd3d00750a48f79d123341niq proxy_html_hooks
9c4e79e1c3fce91054fd3d00750a48f79d123341niq};