|
Packit |
90a5c9 |
/* Copyright (c) 2003-11, WebThing Ltd
|
|
Packit |
90a5c9 |
* Copyright (c) 2011-, The Apache Software Foundation
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* GO_FASTER
|
|
Packit |
90a5c9 |
You can #define GO_FASTER to disable trace logging.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#ifdef GO_FASTER
|
|
Packit |
90a5c9 |
#define VERBOSE(x)
|
|
Packit |
90a5c9 |
#define VERBOSEB(x)
|
|
Packit |
90a5c9 |
#else
|
|
Packit |
90a5c9 |
#define VERBOSE(x) if (verbose) x
|
|
Packit |
90a5c9 |
#define VERBOSEB(x) if (verbose) {x}
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* libxml2 */
|
|
Packit |
90a5c9 |
#include <libxml/HTMLparser.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "http_protocol.h"
|
|
Packit |
90a5c9 |
#include "http_config.h"
|
|
Packit |
90a5c9 |
#include "http_log.h"
|
|
Packit |
90a5c9 |
#include "apr_strings.h"
|
|
Packit |
90a5c9 |
#include "apr_hash.h"
|
|
Packit |
90a5c9 |
#include "apr_strmatch.h"
|
|
Packit |
90a5c9 |
#include "apr_lib.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "apr_optional.h"
|
|
Packit |
90a5c9 |
#include "mod_xml2enc.h"
|
|
Packit |
90a5c9 |
#include "http_request.h"
|
|
Packit |
90a5c9 |
#include "ap_expr.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* globals set once at startup */
|
|
Packit |
90a5c9 |
static ap_rxplus_t *old_expr;
|
|
Packit |
90a5c9 |
static ap_regex_t *seek_meta;
|
|
Packit |
90a5c9 |
static const apr_strmatch_pattern* seek_content;
|
|
Packit |
90a5c9 |
static apr_status_t (*xml2enc_charset)(request_rec*, xmlCharEncoding*, const char**) = NULL;
|
|
Packit |
90a5c9 |
static apr_status_t (*xml2enc_filter)(request_rec*, const char*, unsigned int) = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
module AP_MODULE_DECLARE_DATA proxy_html_module;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define M_HTML 0x01
|
|
Packit |
90a5c9 |
#define M_EVENTS 0x02
|
|
Packit |
90a5c9 |
#define M_CDATA 0x04
|
|
Packit |
90a5c9 |
#define M_REGEX 0x08
|
|
Packit |
90a5c9 |
#define M_ATSTART 0x10
|
|
Packit |
90a5c9 |
#define M_ATEND 0x20
|
|
Packit |
90a5c9 |
#define M_LAST 0x40
|
|
Packit |
90a5c9 |
#define M_NOTLAST 0x80
|
|
Packit |
90a5c9 |
#define M_INTERPOLATE_TO 0x100
|
|
Packit |
90a5c9 |
#define M_INTERPOLATE_FROM 0x200
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
const char *val;
|
|
Packit |
90a5c9 |
} tattr;
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
unsigned int start;
|
|
Packit |
90a5c9 |
unsigned int end;
|
|
Packit |
90a5c9 |
} meta;
|
|
Packit |
90a5c9 |
typedef struct urlmap {
|
|
Packit |
90a5c9 |
struct urlmap *next;
|
|
Packit |
90a5c9 |
unsigned int flags;
|
|
Packit |
90a5c9 |
unsigned int regflags;
|
|
Packit |
90a5c9 |
union {
|
|
Packit |
90a5c9 |
const char *c;
|
|
Packit |
90a5c9 |
ap_regex_t *r;
|
|
Packit |
90a5c9 |
} from;
|
|
Packit |
90a5c9 |
const char *to;
|
|
Packit |
90a5c9 |
ap_expr_info_t *cond;
|
|
Packit |
90a5c9 |
} urlmap;
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
urlmap *map;
|
|
Packit |
90a5c9 |
const char *doctype;
|
|
Packit |
90a5c9 |
const char *etag;
|
|
Packit |
90a5c9 |
unsigned int flags;
|
|
Packit |
90a5c9 |
size_t bufsz;
|
|
Packit |
90a5c9 |
apr_hash_t *links;
|
|
Packit |
90a5c9 |
apr_array_header_t *events;
|
|
Packit |
90a5c9 |
const char *charset_out;
|
|
Packit |
90a5c9 |
int extfix;
|
|
Packit |
90a5c9 |
int metafix;
|
|
Packit |
90a5c9 |
int strip_comments;
|
|
Packit |
90a5c9 |
int interp;
|
|
Packit |
90a5c9 |
int enabled;
|
|
Packit |
90a5c9 |
} proxy_html_conf;
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
ap_filter_t *f;
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg;
|
|
Packit |
90a5c9 |
htmlParserCtxtPtr parser;
|
|
Packit |
90a5c9 |
apr_bucket_brigade *bb;
|
|
Packit |
90a5c9 |
char *buf;
|
|
Packit |
90a5c9 |
size_t offset;
|
|
Packit |
90a5c9 |
size_t avail;
|
|
Packit |
90a5c9 |
const char *encoding;
|
|
Packit |
90a5c9 |
urlmap *map;
|
|
Packit |
90a5c9 |
char rbuf[4];
|
|
Packit |
90a5c9 |
apr_size_t rlen;
|
|
Packit |
90a5c9 |
apr_size_t rmin;
|
|
Packit |
90a5c9 |
} saxctxt;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define NORM_LC 0x1
|
|
Packit |
90a5c9 |
#define NORM_MSSLASH 0x2
|
|
Packit |
90a5c9 |
#define NORM_RESET 0x4
|
|
Packit |
90a5c9 |
static htmlSAXHandler sax;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef enum { ATTR_IGNORE, ATTR_URI, ATTR_EVENT } rewrite_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *const fpi_html =
|
|
Packit |
90a5c9 |
"\n";
|
|
Packit |
90a5c9 |
static const char *const fpi_html_legacy =
|
|
Packit |
90a5c9 |
"\n";
|
|
Packit |
90a5c9 |
static const char *const fpi_xhtml =
|
|
Packit |
90a5c9 |
"\n";
|
|
Packit |
90a5c9 |
static const char *const fpi_xhtml_legacy =
|
|
Packit |
90a5c9 |
"\n";
|
|
Packit |
90a5c9 |
static const char *const fpi_html5 = "\n";
|
|
Packit |
90a5c9 |
static const char *const html_etag = ">";
|
|
Packit |
90a5c9 |
static const char *const xhtml_etag = " />";
|
|
Packit |
90a5c9 |
/*#define DEFAULT_DOCTYPE fpi_html */
|
|
Packit |
90a5c9 |
static const char *const DEFAULT_DOCTYPE = "";
|
|
Packit |
90a5c9 |
#define DEFAULT_ETAG html_etag
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void normalise(unsigned int flags, char *str)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *p;
|
|
Packit |
90a5c9 |
if (flags & NORM_LC)
|
|
Packit |
90a5c9 |
for (p = str; *p; ++p)
|
|
Packit |
90a5c9 |
if (isupper(*p))
|
|
Packit |
90a5c9 |
*p = tolower(*p);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (flags & NORM_MSSLASH)
|
|
Packit |
90a5c9 |
for (p = ap_strchr(str, '\\'); p; p = ap_strchr(p+1, '\\'))
|
|
Packit |
90a5c9 |
*p = '/';
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
#define consume_buffer(ctx,inbuf,bytes,flag) \
|
|
Packit |
90a5c9 |
htmlParseChunk(ctx->parser, inbuf, bytes, flag)
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define AP_fwrite(ctx,inbuf,bytes,flush) \
|
|
Packit |
90a5c9 |
ap_fwrite(ctx->f->next, ctx->bb, inbuf, bytes);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* This is always utf-8 on entry. We can convert charset within FLUSH */
|
|
Packit |
90a5c9 |
#define FLUSH AP_fwrite(ctx, (chars+begin), (i-begin), 0); begin = i+1
|
|
Packit |
90a5c9 |
static void pcharacters(void *ctxt, const xmlChar *uchars, int length)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *chars = (const char*) uchars;
|
|
Packit |
90a5c9 |
saxctxt *ctx = (saxctxt*) ctxt;
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
int begin;
|
|
Packit |
90a5c9 |
for (begin=i=0; i
|
|
Packit |
90a5c9 |
switch (chars[i]) {
|
|
Packit |
90a5c9 |
case '&' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&"); break;
|
|
Packit |
90a5c9 |
case '<' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "<"); break;
|
|
Packit |
90a5c9 |
case '>' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, ">"); break;
|
|
Packit |
90a5c9 |
case '"' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, """); break;
|
|
Packit |
90a5c9 |
default : break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
FLUSH;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void preserve(saxctxt *ctx, const size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *newbuf;
|
|
Packit |
90a5c9 |
if (len <= (ctx->avail - ctx->offset))
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
else while (len > (ctx->avail - ctx->offset))
|
|
Packit |
90a5c9 |
ctx->avail += ctx->cfg->bufsz;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
newbuf = realloc(ctx->buf, ctx->avail);
|
|
Packit |
90a5c9 |
if (newbuf != ctx->buf) {
|
|
Packit |
90a5c9 |
if (ctx->buf)
|
|
Packit |
90a5c9 |
apr_pool_cleanup_kill(ctx->f->r->pool, ctx->buf,
|
|
Packit |
90a5c9 |
(int(*)(void*))free);
|
|
Packit |
90a5c9 |
apr_pool_cleanup_register(ctx->f->r->pool, newbuf,
|
|
Packit |
90a5c9 |
(int(*)(void*))free, apr_pool_cleanup_null);
|
|
Packit |
90a5c9 |
ctx->buf = newbuf;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void pappend(saxctxt *ctx, const char *buf, const size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
preserve(ctx, len);
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+ctx->offset, buf, len);
|
|
Packit |
90a5c9 |
ctx->offset += len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void dump_content(saxctxt *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
urlmap *m;
|
|
Packit |
90a5c9 |
char *found;
|
|
Packit |
90a5c9 |
size_t s_from, s_to;
|
|
Packit |
90a5c9 |
size_t match;
|
|
Packit |
90a5c9 |
char c = 0;
|
|
Packit |
90a5c9 |
int nmatch;
|
|
Packit |
90a5c9 |
ap_regmatch_t pmatch[10];
|
|
Packit |
90a5c9 |
char *subs;
|
|
Packit |
90a5c9 |
size_t len, offs;
|
|
Packit |
90a5c9 |
urlmap *themap = ctx->map;
|
|
Packit |
90a5c9 |
#ifndef GO_FASTER
|
|
Packit |
90a5c9 |
int verbose = APLOGrtrace1(ctx->f->r);
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
pappend(ctx, &c, 1); /* append null byte */
|
|
Packit |
90a5c9 |
/* parse the text for URLs */
|
|
Packit |
90a5c9 |
for (m = themap; m; m = m->next) {
|
|
Packit |
90a5c9 |
if (!(m->flags & M_CDATA))
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
if (m->flags & M_REGEX) {
|
|
Packit |
90a5c9 |
nmatch = 10;
|
|
Packit |
90a5c9 |
offs = 0;
|
|
Packit |
90a5c9 |
while (!ap_regexec(m->from.r, ctx->buf+offs, nmatch, pmatch, 0)) {
|
|
Packit |
90a5c9 |
match = pmatch[0].rm_so;
|
|
Packit |
90a5c9 |
s_from = pmatch[0].rm_eo - match;
|
|
Packit |
90a5c9 |
subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
|
|
Packit |
90a5c9 |
nmatch, pmatch);
|
|
Packit |
90a5c9 |
s_to = strlen(subs);
|
|
Packit |
90a5c9 |
len = strlen(ctx->buf);
|
|
Packit |
90a5c9 |
offs += match;
|
|
Packit |
90a5c9 |
VERBOSEB(
|
|
Packit |
90a5c9 |
const char *f = apr_pstrndup(ctx->f->r->pool,
|
|
Packit |
90a5c9 |
ctx->buf + offs, s_from);
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r,
|
|
Packit |
90a5c9 |
"C/RX: match at %s, substituting %s", f, subs);
|
|
Packit |
90a5c9 |
)
|
|
Packit |
90a5c9 |
if (s_to > s_from) {
|
|
Packit |
90a5c9 |
preserve(ctx, s_to - s_from);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - offs);
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+offs, subs, s_to);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
memcpy(ctx->buf + offs, subs, s_to);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - offs);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
offs += s_to;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
s_from = strlen(m->from.c);
|
|
Packit |
90a5c9 |
s_to = strlen(m->to);
|
|
Packit |
90a5c9 |
for (found = strstr(ctx->buf, m->from.c); found;
|
|
Packit |
90a5c9 |
found = strstr(ctx->buf+match+s_to, m->from.c)) {
|
|
Packit |
90a5c9 |
match = found - ctx->buf;
|
|
Packit |
90a5c9 |
if ((m->flags & M_ATSTART) && (match != 0))
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
len = strlen(ctx->buf);
|
|
Packit |
90a5c9 |
if ((m->flags & M_ATEND) && (match < (len - s_from)))
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r,
|
|
Packit |
90a5c9 |
"C: matched %s, substituting %s",
|
|
Packit |
90a5c9 |
m->from.c, m->to));
|
|
Packit |
90a5c9 |
if (s_to > s_from) {
|
|
Packit |
90a5c9 |
preserve(ctx, s_to - s_from);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - match);
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+match, m->to, s_to);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+match, m->to, s_to);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - match);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
AP_fwrite(ctx, ctx->buf, strlen(ctx->buf), 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
static void pcdata(void *ctxt, const xmlChar *uchars, int length)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *chars = (const char*) uchars;
|
|
Packit |
90a5c9 |
saxctxt *ctx = (saxctxt*) ctxt;
|
|
Packit |
90a5c9 |
if (ctx->cfg->extfix) {
|
|
Packit |
90a5c9 |
pappend(ctx, chars, length);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* not sure if this should force-flush
|
|
Packit |
90a5c9 |
* (i.e. can one cdata section come in multiple calls?)
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
AP_fwrite(ctx, chars, length, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
static void pcomment(void *ctxt, const xmlChar *uchars)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *chars = (const char*) uchars;
|
|
Packit |
90a5c9 |
saxctxt *ctx = (saxctxt*) ctxt;
|
|
Packit |
90a5c9 |
if (ctx->cfg->strip_comments)
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ctx->cfg->extfix) {
|
|
Packit |
90a5c9 |
pappend(ctx, "
|
|
Packit |
90a5c9 |
pappend(ctx, chars, strlen(chars));
|
|
Packit |
90a5c9 |
pappend(ctx, "-->", 3);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_fputs(ctx->f->next, ctx->bb, "
|
|
Packit |
90a5c9 |
AP_fwrite(ctx, chars, strlen(chars), 1);
|
|
Packit |
90a5c9 |
ap_fputs(ctx->f->next, ctx->bb, "-->");
|
|
Packit |
90a5c9 |
dump_content(ctx);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
static void pendElement(void *ctxt, const xmlChar *uname)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
saxctxt *ctx = (saxctxt*) ctxt;
|
|
Packit |
90a5c9 |
const char *name = (const char*) uname;
|
|
Packit |
90a5c9 |
const htmlElemDesc* desc = htmlTagLookup(uname);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
|
|
Packit |
90a5c9 |
/* enforce html */
|
|
Packit |
90a5c9 |
if (!desc || desc->depr)
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if ((ctx->cfg->doctype == fpi_html_legacy)
|
|
Packit |
90a5c9 |
|| (ctx->cfg->doctype == fpi_xhtml_legacy)) {
|
|
Packit |
90a5c9 |
/* enforce html legacy */
|
|
Packit |
90a5c9 |
if (!desc)
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
/* TODO - implement HTML "allowed here" using the stack */
|
|
Packit |
90a5c9 |
/* nah. Keeping the stack is too much overhead */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ctx->offset > 0) {
|
|
Packit |
90a5c9 |
dump_content(ctx);
|
|
Packit |
90a5c9 |
ctx->offset = 0; /* having dumped it, we can re-use the memory */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!desc || !desc->empty) {
|
|
Packit |
90a5c9 |
ap_fprintf(ctx->f->next, ctx->bb, "</%s>", name);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void pstartElement(void *ctxt, const xmlChar *uname,
|
|
Packit |
90a5c9 |
const xmlChar** uattrs)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int required_attrs;
|
|
Packit |
90a5c9 |
int num_match;
|
|
Packit |
90a5c9 |
size_t offs, len;
|
|
Packit |
90a5c9 |
char *subs;
|
|
Packit |
90a5c9 |
rewrite_t is_uri;
|
|
Packit |
90a5c9 |
const char** a;
|
|
Packit |
90a5c9 |
urlmap *m;
|
|
Packit |
90a5c9 |
size_t s_to, s_from, match;
|
|
Packit |
90a5c9 |
char *found;
|
|
Packit |
90a5c9 |
saxctxt *ctx = (saxctxt*) ctxt;
|
|
Packit |
90a5c9 |
size_t nmatch;
|
|
Packit |
90a5c9 |
ap_regmatch_t pmatch[10];
|
|
Packit |
90a5c9 |
#ifndef GO_FASTER
|
|
Packit |
90a5c9 |
int verbose = APLOGrtrace1(ctx->f->r);
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
apr_array_header_t *linkattrs;
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
const char *name = (const char*) uname;
|
|
Packit |
90a5c9 |
const char** attrs = (const char**) uattrs;
|
|
Packit |
90a5c9 |
const htmlElemDesc* desc = htmlTagLookup(uname);
|
|
Packit |
90a5c9 |
urlmap *themap = ctx->map;
|
|
Packit |
90a5c9 |
#ifdef HAVE_STACK
|
|
Packit |
90a5c9 |
const void** descp;
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
int enforce = 0;
|
|
Packit |
90a5c9 |
if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
|
|
Packit |
90a5c9 |
/* enforce html */
|
|
Packit |
90a5c9 |
if (!desc || desc->depr) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01416)
|
|
Packit |
90a5c9 |
"Bogus HTML element %s dropped", name);
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
enforce = 2;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if ((ctx->cfg->doctype == fpi_html_legacy)
|
|
Packit |
90a5c9 |
|| (ctx->cfg->doctype == fpi_xhtml_legacy)) {
|
|
Packit |
90a5c9 |
/* enforce html legacy */
|
|
Packit |
90a5c9 |
if (!desc) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01417)
|
|
Packit |
90a5c9 |
"Deprecated HTML element %s dropped", name);
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
enforce = 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
#ifdef HAVE_STACK
|
|
Packit |
90a5c9 |
descp = apr_array_push(ctx->stack);
|
|
Packit |
90a5c9 |
*descp = desc;
|
|
Packit |
90a5c9 |
/* TODO - implement HTML "allowed here" */
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_fputc(ctx->f->next, ctx->bb, '<');
|
|
Packit |
90a5c9 |
ap_fputs(ctx->f->next, ctx->bb, name);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
required_attrs = 0;
|
|
Packit |
90a5c9 |
if ((enforce > 0) && (desc != NULL) && (desc->attrs_req != NULL))
|
|
Packit |
90a5c9 |
for (a = desc->attrs_req; *a; a++)
|
|
Packit |
90a5c9 |
++required_attrs;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (attrs) {
|
|
Packit |
90a5c9 |
linkattrs = apr_hash_get(ctx->cfg->links, name, APR_HASH_KEY_STRING);
|
|
Packit |
90a5c9 |
for (a = attrs; *a; a += 2) {
|
|
Packit |
90a5c9 |
if (desc && enforce > 0) {
|
|
Packit |
90a5c9 |
switch (htmlAttrAllowed(desc, (xmlChar*)*a, 2-enforce)) {
|
|
Packit |
90a5c9 |
case HTML_INVALID:
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01418)
|
|
Packit |
90a5c9 |
"Bogus HTML attribute %s of %s dropped",
|
|
Packit |
90a5c9 |
*a, name);
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
case HTML_DEPRECATED:
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01419)
|
|
Packit |
90a5c9 |
"Deprecated HTML attribute %s of %s dropped",
|
|
Packit |
90a5c9 |
*a, name);
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
case HTML_REQUIRED:
|
|
Packit |
90a5c9 |
required_attrs--; /* cross off the number still needed */
|
|
Packit |
90a5c9 |
/* fallthrough - required implies valid */
|
|
Packit |
90a5c9 |
default:
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ctx->offset = 0;
|
|
Packit |
90a5c9 |
if (a[1]) {
|
|
Packit |
90a5c9 |
pappend(ctx, a[1], strlen(a[1])+1);
|
|
Packit |
90a5c9 |
is_uri = ATTR_IGNORE;
|
|
Packit |
90a5c9 |
if (linkattrs) {
|
|
Packit |
90a5c9 |
tattr *attrs = (tattr*) linkattrs->elts;
|
|
Packit |
90a5c9 |
for (i=0; i < linkattrs->nelts; ++i) {
|
|
Packit |
90a5c9 |
if (!strcmp(*a, attrs[i].val)) {
|
|
Packit |
90a5c9 |
is_uri = ATTR_URI;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if ((is_uri == ATTR_IGNORE) && ctx->cfg->extfix
|
|
Packit |
90a5c9 |
&& (ctx->cfg->events != NULL)) {
|
|
Packit |
90a5c9 |
for (i=0; i < ctx->cfg->events->nelts; ++i) {
|
|
Packit |
90a5c9 |
tattr *attrs = (tattr*) ctx->cfg->events->elts;
|
|
Packit |
90a5c9 |
if (!strcmp(*a, attrs[i].val)) {
|
|
Packit |
90a5c9 |
is_uri = ATTR_EVENT;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
switch (is_uri) {
|
|
Packit |
90a5c9 |
case ATTR_URI:
|
|
Packit |
90a5c9 |
num_match = 0;
|
|
Packit |
90a5c9 |
for (m = themap; m; m = m->next) {
|
|
Packit |
90a5c9 |
if (!(m->flags & M_HTML))
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
if (m->flags & M_REGEX) {
|
|
Packit |
90a5c9 |
nmatch = 10;
|
|
Packit |
90a5c9 |
if (!ap_regexec(m->from.r, ctx->buf, nmatch,
|
|
Packit |
90a5c9 |
pmatch, 0)) {
|
|
Packit |
90a5c9 |
++num_match;
|
|
Packit |
90a5c9 |
offs = match = pmatch[0].rm_so;
|
|
Packit |
90a5c9 |
s_from = pmatch[0].rm_eo - match;
|
|
Packit |
90a5c9 |
subs = ap_pregsub(ctx->f->r->pool, m->to,
|
|
Packit |
90a5c9 |
ctx->buf, nmatch, pmatch);
|
|
Packit |
90a5c9 |
VERBOSE({
|
|
Packit |
90a5c9 |
const char *f;
|
|
Packit |
90a5c9 |
f = apr_pstrndup(ctx->f->r->pool,
|
|
Packit |
90a5c9 |
ctx->buf + offs, s_from);
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0,
|
|
Packit |
90a5c9 |
ctx->f->r,
|
|
Packit |
90a5c9 |
"H/RX: match at %s, substituting %s",
|
|
Packit |
90a5c9 |
f, subs);
|
|
Packit |
90a5c9 |
})
|
|
Packit |
90a5c9 |
s_to = strlen(subs);
|
|
Packit |
90a5c9 |
len = strlen(ctx->buf);
|
|
Packit |
90a5c9 |
if (s_to > s_from) {
|
|
Packit |
90a5c9 |
preserve(ctx, s_to - s_from);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+offs+s_to,
|
|
Packit |
90a5c9 |
ctx->buf+offs+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - offs);
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+offs, subs, s_to);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
memcpy(ctx->buf + offs, subs, s_to);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+offs+s_to,
|
|
Packit |
90a5c9 |
ctx->buf+offs+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - offs);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
} else {
|
|
Packit |
90a5c9 |
s_from = strlen(m->from.c);
|
|
Packit |
90a5c9 |
if (!strncasecmp(ctx->buf, m->from.c, s_from)) {
|
|
Packit |
90a5c9 |
++num_match;
|
|
Packit |
90a5c9 |
s_to = strlen(m->to);
|
|
Packit |
90a5c9 |
len = strlen(ctx->buf);
|
|
Packit |
90a5c9 |
VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3,
|
|
Packit |
90a5c9 |
0, ctx->f->r,
|
|
Packit |
90a5c9 |
"H: matched %s, substituting %s",
|
|
Packit |
90a5c9 |
m->from.c, m->to));
|
|
Packit |
90a5c9 |
if (s_to > s_from) {
|
|
Packit |
90a5c9 |
preserve(ctx, s_to - s_from);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+s_to, ctx->buf+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from);
|
|
Packit |
90a5c9 |
memcpy(ctx->buf, m->to, s_to);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else { /* it fits in the existing space */
|
|
Packit |
90a5c9 |
memcpy(ctx->buf, m->to, s_to);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+s_to, ctx->buf+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
/* URIs only want one match unless overridden in the config */
|
|
Packit |
90a5c9 |
if ((num_match > 0) && !(m->flags & M_NOTLAST))
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
case ATTR_EVENT:
|
|
Packit |
90a5c9 |
for (m = themap; m; m = m->next) {
|
|
Packit |
90a5c9 |
num_match = 0; /* reset here since we're working per-rule */
|
|
Packit |
90a5c9 |
if (!(m->flags & M_EVENTS))
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
if (m->flags & M_REGEX) {
|
|
Packit |
90a5c9 |
nmatch = 10;
|
|
Packit |
90a5c9 |
offs = 0;
|
|
Packit |
90a5c9 |
while (!ap_regexec(m->from.r, ctx->buf+offs,
|
|
Packit |
90a5c9 |
nmatch, pmatch, 0)) {
|
|
Packit |
90a5c9 |
match = pmatch[0].rm_so;
|
|
Packit |
90a5c9 |
s_from = pmatch[0].rm_eo - match;
|
|
Packit |
90a5c9 |
subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
|
|
Packit |
90a5c9 |
nmatch, pmatch);
|
|
Packit |
90a5c9 |
VERBOSE({
|
|
Packit |
90a5c9 |
const char *f;
|
|
Packit |
90a5c9 |
f = apr_pstrndup(ctx->f->r->pool,
|
|
Packit |
90a5c9 |
ctx->buf + offs, s_from);
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0,
|
|
Packit |
90a5c9 |
ctx->f->r,
|
|
Packit |
90a5c9 |
"E/RX: match at %s, substituting %s",
|
|
Packit |
90a5c9 |
f, subs);
|
|
Packit |
90a5c9 |
})
|
|
Packit |
90a5c9 |
s_to = strlen(subs);
|
|
Packit |
90a5c9 |
offs += match;
|
|
Packit |
90a5c9 |
len = strlen(ctx->buf);
|
|
Packit |
90a5c9 |
if (s_to > s_from) {
|
|
Packit |
90a5c9 |
preserve(ctx, s_to - s_from);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+offs+s_to,
|
|
Packit |
90a5c9 |
ctx->buf+offs+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - offs);
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+offs, subs, s_to);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
memcpy(ctx->buf + offs, subs, s_to);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+offs+s_to,
|
|
Packit |
90a5c9 |
ctx->buf+offs+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - offs);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
offs += s_to;
|
|
Packit |
90a5c9 |
++num_match;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
found = strstr(ctx->buf, m->from.c);
|
|
Packit |
90a5c9 |
if ((m->flags & M_ATSTART) && (found != ctx->buf))
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
while (found) {
|
|
Packit |
90a5c9 |
s_from = strlen(m->from.c);
|
|
Packit |
90a5c9 |
s_to = strlen(m->to);
|
|
Packit |
90a5c9 |
match = found - ctx->buf;
|
|
Packit |
90a5c9 |
if ((s_from < strlen(found))
|
|
Packit |
90a5c9 |
&& (m->flags & M_ATEND)) {
|
|
Packit |
90a5c9 |
found = strstr(ctx->buf+match+s_from,
|
|
Packit |
90a5c9 |
m->from.c);
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
found = strstr(ctx->buf+match+s_to,
|
|
Packit |
90a5c9 |
m->from.c);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3,
|
|
Packit |
90a5c9 |
0, ctx->f->r,
|
|
Packit |
90a5c9 |
"E: matched %s, substituting %s",
|
|
Packit |
90a5c9 |
m->from.c, m->to));
|
|
Packit |
90a5c9 |
len = strlen(ctx->buf);
|
|
Packit |
90a5c9 |
if (s_to > s_from) {
|
|
Packit |
90a5c9 |
preserve(ctx, s_to - s_from);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+match+s_to,
|
|
Packit |
90a5c9 |
ctx->buf+match+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - match);
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+match, m->to, s_to);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
memcpy(ctx->buf+match, m->to, s_to);
|
|
Packit |
90a5c9 |
memmove(ctx->buf+match+s_to,
|
|
Packit |
90a5c9 |
ctx->buf+match+s_from,
|
|
Packit |
90a5c9 |
len + 1 - s_from - match);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
++num_match;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (num_match && (m->flags & M_LAST))
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
case ATTR_IGNORE:
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!a[1])
|
|
Packit |
90a5c9 |
ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], NULL);
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ctx->cfg->flags != 0)
|
|
Packit |
90a5c9 |
normalise(ctx->cfg->flags, ctx->buf);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* write the attribute, using pcharacters to html-escape
|
|
Packit |
90a5c9 |
anything that needs it in the value.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], "=\"", NULL);
|
|
Packit |
90a5c9 |
pcharacters(ctx, (const xmlChar*)ctx->buf, strlen(ctx->buf));
|
|
Packit |
90a5c9 |
ap_fputc(ctx->f->next, ctx->bb, '"');
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ctx->offset = 0;
|
|
Packit |
90a5c9 |
if (desc && desc->empty)
|
|
Packit |
90a5c9 |
ap_fputs(ctx->f->next, ctx->bb, ctx->cfg->etag);
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
ap_fputc(ctx->f->next, ctx->bb, '>');
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((enforce > 0) && (required_attrs > 0)) {
|
|
Packit |
90a5c9 |
/* if there are more required attributes than we found then complain */
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01420)
|
|
Packit |
90a5c9 |
"HTML element %s is missing %d required attributes",
|
|
Packit |
90a5c9 |
name, required_attrs);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static meta *metafix(request_rec *r, const char *buf, apr_size_t len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
meta *ret = NULL;
|
|
Packit |
90a5c9 |
size_t offs = 0;
|
|
Packit |
90a5c9 |
const char *p;
|
|
Packit |
90a5c9 |
const char *q;
|
|
Packit |
90a5c9 |
char *header;
|
|
Packit |
90a5c9 |
char *content;
|
|
Packit |
90a5c9 |
ap_regmatch_t pmatch[2];
|
|
Packit |
90a5c9 |
char delim;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (offs < len &&
|
|
Packit |
90a5c9 |
!ap_regexec_len(seek_meta, buf + offs, len - offs, 2, pmatch, 0)) {
|
|
Packit |
90a5c9 |
header = NULL;
|
|
Packit |
90a5c9 |
content = NULL;
|
|
Packit |
90a5c9 |
p = buf+offs+pmatch[1].rm_eo;
|
|
Packit |
90a5c9 |
while (!apr_isalpha(*++p));
|
|
Packit |
90a5c9 |
for (q = p; apr_isalnum(*q) || (*q == '-'); ++q);
|
|
Packit |
90a5c9 |
header = apr_pstrmemdup(r->pool, p, q-p);
|
|
Packit |
90a5c9 |
if (strncasecmp(header, "Content-", 8)) {
|
|
Packit |
90a5c9 |
/* find content=... string */
|
|
Packit |
90a5c9 |
p = apr_strmatch(seek_content, buf+offs+pmatch[0].rm_so,
|
|
Packit |
90a5c9 |
pmatch[0].rm_eo - pmatch[0].rm_so);
|
|
Packit |
90a5c9 |
/* if it doesn't contain "content", ignore, don't crash! */
|
|
Packit |
90a5c9 |
if (p != NULL) {
|
|
Packit |
90a5c9 |
while (*p) {
|
|
Packit |
90a5c9 |
p += 7;
|
|
Packit |
90a5c9 |
while (apr_isspace(*p))
|
|
Packit |
90a5c9 |
++p;
|
|
Packit |
90a5c9 |
/* XXX Should we search for another content= pattern? */
|
|
Packit |
90a5c9 |
if (*p != '=')
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
while (*p && apr_isspace(*++p));
|
|
Packit |
90a5c9 |
if ((*p == '\'') || (*p == '"')) {
|
|
Packit |
90a5c9 |
delim = *p++;
|
|
Packit |
90a5c9 |
for (q = p; *q && *q != delim; ++q);
|
|
Packit |
90a5c9 |
/* No terminating delimiter found? Skip the boggus directive */
|
|
Packit |
90a5c9 |
if (*q != delim)
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
} else {
|
|
Packit |
90a5c9 |
for (q = p; *q && !apr_isspace(*q) && (*q != '>'); ++q);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
content = apr_pstrmemdup(r->pool, p, q-p);
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (!strncasecmp(header, "Content-Type", 12)) {
|
|
Packit |
90a5c9 |
ret = apr_palloc(r->pool, sizeof(meta));
|
|
Packit |
90a5c9 |
ret->start = offs+pmatch[0].rm_so;
|
|
Packit |
90a5c9 |
ret->end = offs+pmatch[0].rm_eo;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (header && content) {
|
|
Packit |
90a5c9 |
#ifndef GO_FASTER
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
|
|
Packit |
90a5c9 |
"Adding header [%s: %s] from HTML META",
|
|
Packit |
90a5c9 |
header, content);
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
apr_table_setn(r->headers_out, header, content);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
offs += pmatch[0].rm_eo;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *interpolate_vars(request_rec *r, const char *str)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *start;
|
|
Packit |
90a5c9 |
const char *end;
|
|
Packit |
90a5c9 |
const char *delim;
|
|
Packit |
90a5c9 |
const char *before;
|
|
Packit |
90a5c9 |
const char *after;
|
|
Packit |
90a5c9 |
const char *replacement;
|
|
Packit |
90a5c9 |
const char *var;
|
|
Packit |
90a5c9 |
for (;;) {
|
|
Packit |
90a5c9 |
if ((start = ap_strstr_c(str, "${")) == NULL)
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((end = ap_strchr_c(start+2, '}')) == NULL)
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
delim = ap_strchr_c(start+2, '|');
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Restrict delim to ${...} */
|
|
Packit |
90a5c9 |
if (delim && delim >= end) {
|
|
Packit |
90a5c9 |
delim = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
before = apr_pstrmemdup(r->pool, str, start-str);
|
|
Packit |
90a5c9 |
after = end+1;
|
|
Packit |
90a5c9 |
if (delim) {
|
|
Packit |
90a5c9 |
var = apr_pstrmemdup(r->pool, start+2, delim-start-2);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
var = apr_pstrmemdup(r->pool, start+2, end-start-2);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
replacement = apr_table_get(r->subprocess_env, var);
|
|
Packit |
90a5c9 |
if (!replacement) {
|
|
Packit |
90a5c9 |
if (delim)
|
|
Packit |
90a5c9 |
replacement = apr_pstrmemdup(r->pool, delim+1, end-delim-1);
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
replacement = "";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
str = apr_pstrcat(r->pool, before, replacement, after, NULL);
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
|
Packit |
90a5c9 |
"Interpolating %s => %s", var, replacement);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return str;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
static void fixup_rules(saxctxt *ctx)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
urlmap *newp;
|
|
Packit |
90a5c9 |
urlmap *p;
|
|
Packit |
90a5c9 |
urlmap *prev = NULL;
|
|
Packit |
90a5c9 |
request_rec *r = ctx->f->r;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (p = ctx->cfg->map; p; p = p->next) {
|
|
Packit |
90a5c9 |
if (p->cond != NULL) {
|
|
Packit |
90a5c9 |
const char *err;
|
|
Packit |
90a5c9 |
int ok = ap_expr_exec(r, p->cond, &err;;
|
|
Packit |
90a5c9 |
if (err) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01421)
|
|
Packit |
90a5c9 |
"Error evaluating expr: %s", err);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (ok == 0) {
|
|
Packit |
90a5c9 |
continue; /* condition is unsatisfied */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
newp = apr_pmemdup(r->pool, p, sizeof(urlmap));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (newp->flags & M_INTERPOLATE_FROM) {
|
|
Packit |
90a5c9 |
newp->from.c = interpolate_vars(r, newp->from.c);
|
|
Packit |
90a5c9 |
if (!newp->from.c || !*newp->from.c)
|
|
Packit |
90a5c9 |
continue; /* don't use empty from-pattern */
|
|
Packit |
90a5c9 |
if (newp->flags & M_REGEX) {
|
|
Packit |
90a5c9 |
newp->from.r = ap_pregcomp(r->pool, newp->from.c,
|
|
Packit |
90a5c9 |
newp->regflags);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (newp->flags & M_INTERPOLATE_TO) {
|
|
Packit |
90a5c9 |
newp->to = interpolate_vars(r, newp->to);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
/* evaluate p->cond; continue if unsatisfied */
|
|
Packit |
90a5c9 |
/* create new urlmap with memcpy and append to map */
|
|
Packit |
90a5c9 |
/* interpolate from if flagged to do so */
|
|
Packit |
90a5c9 |
/* interpolate to if flagged to do so */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (prev != NULL)
|
|
Packit |
90a5c9 |
prev->next = newp;
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
ctx->map = newp;
|
|
Packit |
90a5c9 |
prev = newp;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (prev)
|
|
Packit |
90a5c9 |
prev->next = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static saxctxt *check_filter_init (ap_filter_t *f)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
saxctxt *fctx;
|
|
Packit |
90a5c9 |
if (!f->ctx) {
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg;
|
|
Packit |
90a5c9 |
const char *force;
|
|
Packit |
90a5c9 |
const char *errmsg = NULL;
|
|
Packit |
90a5c9 |
cfg = ap_get_module_config(f->r->per_dir_config, &proxy_html_module);
|
|
Packit |
90a5c9 |
force = apr_table_get(f->r->subprocess_env, "PROXY_HTML_FORCE");
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!force) {
|
|
Packit |
90a5c9 |
if (!f->r->proxyreq) {
|
|
Packit |
90a5c9 |
errmsg = "Non-proxy request; not inserting proxy-html filter";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (!f->r->content_type) {
|
|
Packit |
90a5c9 |
errmsg = "No content-type; bailing out of proxy-html filter";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (strncasecmp(f->r->content_type, "text/html", 9) &&
|
|
Packit |
90a5c9 |
strncasecmp(f->r->content_type,
|
|
Packit |
90a5c9 |
"application/xhtml+xml", 21)) {
|
|
Packit |
90a5c9 |
errmsg = "Non-HTML content; not inserting proxy-html filter";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!cfg->links) {
|
|
Packit |
90a5c9 |
errmsg = "No links configured: nothing for proxy-html filter to do";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (errmsg) {
|
|
Packit |
90a5c9 |
#ifndef GO_FASTER
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r, "%s", errmsg);
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
ap_remove_output_filter(f);
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
fctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(saxctxt));
|
|
Packit |
90a5c9 |
fctx->f = f;
|
|
Packit |
90a5c9 |
fctx->bb = apr_brigade_create(f->r->pool,
|
|
Packit |
90a5c9 |
f->r->connection->bucket_alloc);
|
|
Packit |
90a5c9 |
fctx->cfg = cfg;
|
|
Packit |
90a5c9 |
apr_table_unset(f->r->headers_out, "Content-Length");
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (cfg->interp)
|
|
Packit |
90a5c9 |
fixup_rules(fctx);
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
fctx->map = cfg->map;
|
|
Packit |
90a5c9 |
/* defer dealing with charset_out until after sniffing charset_in
|
|
Packit |
90a5c9 |
* so we can support setting one to t'other.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return f->ctx;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void prepend_rbuf(saxctxt *ctxt, apr_bucket_brigade *bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (ctxt->rlen) {
|
|
Packit |
90a5c9 |
apr_bucket *b = apr_bucket_transient_create(ctxt->rbuf,
|
|
Packit |
90a5c9 |
ctxt->rlen,
|
|
Packit |
90a5c9 |
bb->bucket_alloc);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_HEAD(bb, b);
|
|
Packit |
90a5c9 |
ctxt->rlen = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket* b;
|
|
Packit |
90a5c9 |
meta *m = NULL;
|
|
Packit |
90a5c9 |
xmlCharEncoding enc;
|
|
Packit |
90a5c9 |
const char *buf = 0;
|
|
Packit |
90a5c9 |
apr_size_t bytes = 0;
|
|
Packit |
90a5c9 |
#ifndef USE_OLD_LIBXML2
|
|
Packit |
90a5c9 |
int xmlopts = XML_PARSE_RECOVER | XML_PARSE_NONET |
|
|
Packit |
90a5c9 |
XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
saxctxt *ctxt = check_filter_init(f);
|
|
Packit |
90a5c9 |
if (!ctxt)
|
|
Packit |
90a5c9 |
return ap_pass_brigade(f->next, bb);
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
b != APR_BRIGADE_SENTINEL(bb);
|
|
Packit |
90a5c9 |
b = APR_BUCKET_NEXT(b)) {
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_METADATA(b)) {
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_EOS(b)) {
|
|
Packit |
90a5c9 |
if (ctxt->parser != NULL) {
|
|
Packit |
90a5c9 |
consume_buffer(ctxt, "", 0, 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
prepend_rbuf(ctxt, ctxt->bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(ctxt->bb,
|
|
Packit |
90a5c9 |
apr_bucket_eos_create(ctxt->bb->bucket_alloc));
|
|
Packit |
90a5c9 |
ap_pass_brigade(ctxt->f->next, ctxt->bb);
|
|
Packit |
90a5c9 |
apr_brigade_cleanup(ctxt->bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (APR_BUCKET_IS_FLUSH(b)) {
|
|
Packit |
90a5c9 |
/* pass on flush, except at start where it would cause
|
|
Packit |
90a5c9 |
* headers to be sent before doc sniffing
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (ctxt->parser != NULL) {
|
|
Packit |
90a5c9 |
ap_fflush(ctxt->f->next, ctxt->bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
|
|
Packit |
90a5c9 |
== APR_SUCCESS) {
|
|
Packit |
90a5c9 |
if (ctxt->parser == NULL) {
|
|
Packit |
90a5c9 |
const char *cenc;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* For documents smaller than four bytes, there is no reason to do
|
|
Packit |
90a5c9 |
* HTML rewriting. The URL schema (i.e. 'http') needs four bytes alone.
|
|
Packit |
90a5c9 |
* And the HTML parser needs at least four bytes to initialise correctly.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
ctxt->rmin += bytes;
|
|
Packit |
90a5c9 |
if (ctxt->rmin < sizeof(ctxt->rbuf)) {
|
|
Packit |
90a5c9 |
memcpy(ctxt->rbuf + ctxt->rlen, buf, bytes);
|
|
Packit |
90a5c9 |
ctxt->rlen += bytes;
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (ctxt->rlen && ctxt->rlen < sizeof(ctxt->rbuf)) {
|
|
Packit |
90a5c9 |
apr_size_t rem = sizeof(ctxt->rbuf) - ctxt->rlen;
|
|
Packit |
90a5c9 |
memcpy(ctxt->rbuf + ctxt->rlen, buf, rem);
|
|
Packit |
90a5c9 |
ctxt->rlen += rem;
|
|
Packit |
90a5c9 |
buf += rem;
|
|
Packit |
90a5c9 |
bytes -= rem;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!xml2enc_charset ||
|
|
Packit |
90a5c9 |
(xml2enc_charset(f->r, &enc, &cenc) != APR_SUCCESS)) {
|
|
Packit |
90a5c9 |
if (!xml2enc_charset)
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01422)
|
|
Packit |
90a5c9 |
"No i18n support found. Install mod_xml2enc if required");
|
|
Packit |
90a5c9 |
enc = XML_CHAR_ENCODING_NONE;
|
|
Packit |
90a5c9 |
ap_set_content_type(f->r, "text/html;charset=utf-8");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* if we wanted a non-default charset_out, insert the
|
|
Packit |
90a5c9 |
* xml2enc filter now that we've sniffed it
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (ctxt->cfg->charset_out && xml2enc_filter) {
|
|
Packit |
90a5c9 |
if (*ctxt->cfg->charset_out != '*')
|
|
Packit |
90a5c9 |
cenc = ctxt->cfg->charset_out;
|
|
Packit |
90a5c9 |
xml2enc_filter(f->r, cenc, ENCIO_OUTPUT);
|
|
Packit |
90a5c9 |
ap_set_content_type(f->r,
|
|
Packit |
90a5c9 |
apr_pstrcat(f->r->pool,
|
|
Packit |
90a5c9 |
"text/html;charset=",
|
|
Packit |
90a5c9 |
cenc, NULL));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else /* Normal case, everything worked, utf-8 output */
|
|
Packit |
90a5c9 |
ap_set_content_type(f->r, "text/html;charset=utf-8");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ctxt->rlen) {
|
|
Packit |
90a5c9 |
ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt,
|
|
Packit |
90a5c9 |
ctxt->rbuf,
|
|
Packit |
90a5c9 |
ctxt->rlen,
|
|
Packit |
90a5c9 |
NULL, enc);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt, buf, 4,
|
|
Packit |
90a5c9 |
NULL, enc);
|
|
Packit |
90a5c9 |
buf += 4;
|
|
Packit |
90a5c9 |
bytes -= 4;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (ctxt->parser == NULL) {
|
|
Packit |
90a5c9 |
prepend_rbuf(ctxt, bb);
|
|
Packit |
90a5c9 |
ap_remove_output_filter(f);
|
|
Packit |
90a5c9 |
return ap_pass_brigade(f->next, bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ctxt->rlen = 0;
|
|
Packit |
90a5c9 |
apr_pool_cleanup_register(f->r->pool, ctxt->parser,
|
|
Packit |
90a5c9 |
(int(*)(void*))htmlFreeParserCtxt,
|
|
Packit |
90a5c9 |
apr_pool_cleanup_null);
|
|
Packit |
90a5c9 |
#ifndef USE_OLD_LIBXML2
|
|
Packit |
90a5c9 |
if (xmlopts = xmlCtxtUseOptions(ctxt->parser, xmlopts), xmlopts)
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01423)
|
|
Packit |
90a5c9 |
"Unsupported parser opts %x", xmlopts);
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
if (ctxt->cfg->metafix)
|
|
Packit |
90a5c9 |
m = metafix(f->r, buf, bytes);
|
|
Packit |
90a5c9 |
if (m) {
|
|
Packit |
90a5c9 |
consume_buffer(ctxt, buf, m->start, 0);
|
|
Packit |
90a5c9 |
consume_buffer(ctxt, buf+m->end, bytes-m->end, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
consume_buffer(ctxt, buf, bytes, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
consume_buffer(ctxt, buf, bytes, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01424)
|
|
Packit |
90a5c9 |
"Error in bucket read");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
/*ap_fflush(ctxt->f->next, ctxt->bb); // uncomment for debug */
|
|
Packit |
90a5c9 |
apr_brigade_cleanup(bb);
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *proxy_html_config(apr_pool_t *pool, char *x)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
proxy_html_conf *ret = apr_pcalloc(pool, sizeof(proxy_html_conf));
|
|
Packit |
90a5c9 |
ret->doctype = DEFAULT_DOCTYPE;
|
|
Packit |
90a5c9 |
ret->etag = DEFAULT_ETAG;
|
|
Packit |
90a5c9 |
ret->bufsz = 8192;
|
|
Packit |
90a5c9 |
/* ret->interp = 1; */
|
|
Packit |
90a5c9 |
/* don't initialise links and events until they get set/used */
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *proxy_html_merge(apr_pool_t *pool, void *BASE, void *ADD)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
proxy_html_conf *base = (proxy_html_conf *) BASE;
|
|
Packit |
90a5c9 |
proxy_html_conf *add = (proxy_html_conf *) ADD;
|
|
Packit |
90a5c9 |
proxy_html_conf *conf = apr_palloc(pool, sizeof(proxy_html_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* don't merge declarations - just use the most specific */
|
|
Packit |
90a5c9 |
conf->links = (add->links == NULL) ? base->links : add->links;
|
|
Packit |
90a5c9 |
conf->events = (add->events == NULL) ? base->events : add->events;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf->charset_out = (add->charset_out == NULL)
|
|
Packit |
90a5c9 |
? base->charset_out : add->charset_out;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (add->map && base->map) {
|
|
Packit |
90a5c9 |
urlmap *a;
|
|
Packit |
90a5c9 |
conf->map = NULL;
|
|
Packit |
90a5c9 |
for (a = base->map; a; a = a->next) {
|
|
Packit |
90a5c9 |
urlmap *save = conf->map;
|
|
Packit |
90a5c9 |
conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
|
|
Packit |
90a5c9 |
conf->map->next = save;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
for (a = add->map; a; a = a->next) {
|
|
Packit |
90a5c9 |
urlmap *save = conf->map;
|
|
Packit |
90a5c9 |
conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
|
|
Packit |
90a5c9 |
conf->map->next = save;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
conf->map = add->map ? add->map : base->map;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf->doctype = (add->doctype == DEFAULT_DOCTYPE)
|
|
Packit |
90a5c9 |
? base->doctype : add->doctype;
|
|
Packit |
90a5c9 |
conf->etag = (add->etag == DEFAULT_ETAG) ? base->etag : add->etag;
|
|
Packit |
90a5c9 |
conf->bufsz = add->bufsz;
|
|
Packit |
90a5c9 |
if (add->flags & NORM_RESET) {
|
|
Packit |
90a5c9 |
conf->flags = add->flags ^ NORM_RESET;
|
|
Packit |
90a5c9 |
conf->metafix = add->metafix;
|
|
Packit |
90a5c9 |
conf->extfix = add->extfix;
|
|
Packit |
90a5c9 |
conf->interp = add->interp;
|
|
Packit |
90a5c9 |
conf->strip_comments = add->strip_comments;
|
|
Packit |
90a5c9 |
conf->enabled = add->enabled;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
conf->flags = base->flags | add->flags;
|
|
Packit |
90a5c9 |
conf->metafix = base->metafix | add->metafix;
|
|
Packit |
90a5c9 |
conf->extfix = base->extfix | add->extfix;
|
|
Packit |
90a5c9 |
conf->interp = base->interp | add->interp;
|
|
Packit |
90a5c9 |
conf->strip_comments = base->strip_comments | add->strip_comments;
|
|
Packit |
90a5c9 |
conf->enabled = add->enabled | base->enabled;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return conf;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
#define REGFLAG(n,s,c) ((s&&(ap_strchr_c((s),(c))!=NULL)) ? (n) : 0)
|
|
Packit |
90a5c9 |
#define XREGFLAG(n,s,c) ((!s||(ap_strchr_c((s),(c))==NULL)) ? (n) : 0)
|
|
Packit |
90a5c9 |
static const char *comp_urlmap(cmd_parms *cmd, urlmap *newmap,
|
|
Packit |
90a5c9 |
const char *from, const char *to,
|
|
Packit |
90a5c9 |
const char *flags, const char *cond)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *err = NULL;
|
|
Packit |
90a5c9 |
newmap->flags
|
|
Packit |
90a5c9 |
= XREGFLAG(M_HTML,flags,'h')
|
|
Packit |
90a5c9 |
| XREGFLAG(M_EVENTS,flags,'e')
|
|
Packit |
90a5c9 |
| XREGFLAG(M_CDATA,flags,'c')
|
|
Packit |
90a5c9 |
| REGFLAG(M_ATSTART,flags,'^')
|
|
Packit |
90a5c9 |
| REGFLAG(M_ATEND,flags,'$')
|
|
Packit |
90a5c9 |
| REGFLAG(M_REGEX,flags,'R')
|
|
Packit |
90a5c9 |
| REGFLAG(M_LAST,flags,'L')
|
|
Packit |
90a5c9 |
| REGFLAG(M_NOTLAST,flags,'l')
|
|
Packit |
90a5c9 |
| REGFLAG(M_INTERPOLATE_TO,flags,'V')
|
|
Packit |
90a5c9 |
| REGFLAG(M_INTERPOLATE_FROM,flags,'v');
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((newmap->flags & M_INTERPOLATE_FROM) || !(newmap->flags & M_REGEX)) {
|
|
Packit |
90a5c9 |
newmap->from.c = from;
|
|
Packit |
90a5c9 |
newmap->to = to;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
newmap->regflags
|
|
Packit |
90a5c9 |
= REGFLAG(AP_REG_EXTENDED,flags,'x')
|
|
Packit |
90a5c9 |
| REGFLAG(AP_REG_ICASE,flags,'i')
|
|
Packit |
90a5c9 |
| REGFLAG(AP_REG_NOSUB,flags,'n')
|
|
Packit |
90a5c9 |
| REGFLAG(AP_REG_NEWLINE,flags,'s');
|
|
Packit |
90a5c9 |
newmap->from.r = ap_pregcomp(cmd->pool, from, newmap->regflags);
|
|
Packit |
90a5c9 |
newmap->to = to;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (cond != NULL) {
|
|
Packit |
90a5c9 |
/* back-compatibility: support old-style ENV expressions
|
|
Packit |
90a5c9 |
* by converting to ap_expr syntax.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* 1. var --> env(var)
|
|
Packit |
90a5c9 |
* 2. var=val --> env(var)=val
|
|
Packit |
90a5c9 |
* 3. !var --> !env(var)
|
|
Packit |
90a5c9 |
* 4. !var=val --> env(var)!=val
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
char *newcond = NULL;
|
|
Packit |
90a5c9 |
if (ap_rxplus_exec(cmd->temp_pool, old_expr, cond, &newcond)) {
|
|
Packit |
90a5c9 |
/* we got a substitution. Check for the case (3) above
|
|
Packit |
90a5c9 |
* that the regexp gets wrong: a negation without a comparison.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if ((cond[0] == '!') && !ap_strchr_c(cond, '=')) {
|
|
Packit |
90a5c9 |
memmove(newcond+1, newcond, strlen(newcond)-1);
|
|
Packit |
90a5c9 |
newcond[0] = '!';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
cond = newcond;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
newmap->cond = ap_expr_parse_cmd(cmd, cond, 0, &err, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
newmap->cond = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return err;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_urlmap(cmd_parms *cmd, void *CFG, const char *args)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg = (proxy_html_conf *)CFG;
|
|
Packit |
90a5c9 |
urlmap *map;
|
|
Packit |
90a5c9 |
apr_pool_t *pool = cmd->pool;
|
|
Packit |
90a5c9 |
urlmap *newmap;
|
|
Packit |
90a5c9 |
const char *usage =
|
|
Packit |
90a5c9 |
"Usage: ProxyHTMLURLMap from-pattern to-pattern [flags] [cond]";
|
|
Packit |
90a5c9 |
const char *from;
|
|
Packit |
90a5c9 |
const char *to;
|
|
Packit |
90a5c9 |
const char *flags;
|
|
Packit |
90a5c9 |
const char *cond = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (from = ap_getword_conf(cmd->pool, &args), !from)
|
|
Packit |
90a5c9 |
return usage;
|
|
Packit |
90a5c9 |
if (to = ap_getword_conf(cmd->pool, &args), !to)
|
|
Packit |
90a5c9 |
return usage;
|
|
Packit |
90a5c9 |
flags = ap_getword_conf(cmd->pool, &args);
|
|
Packit |
90a5c9 |
if (flags && *flags)
|
|
Packit |
90a5c9 |
cond = ap_getword_conf(cmd->pool, &args);
|
|
Packit |
90a5c9 |
if (cond && !*cond)
|
|
Packit |
90a5c9 |
cond = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* the args look OK, so let's use them */
|
|
Packit |
90a5c9 |
newmap = apr_palloc(pool, sizeof(urlmap));
|
|
Packit |
90a5c9 |
newmap->next = NULL;
|
|
Packit |
90a5c9 |
if (cfg->map) {
|
|
Packit |
90a5c9 |
for (map = cfg->map; map->next; map = map->next);
|
|
Packit |
90a5c9 |
map->next = newmap;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
cfg->map = newmap;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return comp_urlmap(cmd, newmap, from, to, flags, cond);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_doctype(cmd_parms *cmd, void *CFG,
|
|
Packit |
90a5c9 |
const char *t, const char *l)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg = (proxy_html_conf *)CFG;
|
|
Packit |
90a5c9 |
if (!strcasecmp(t, "xhtml")) {
|
|
Packit |
90a5c9 |
cfg->etag = xhtml_etag;
|
|
Packit |
90a5c9 |
if (l && !strcasecmp(l, "legacy"))
|
|
Packit |
90a5c9 |
cfg->doctype = fpi_xhtml_legacy;
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
cfg->doctype = fpi_xhtml;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (!strcasecmp(t, "html")) {
|
|
Packit |
90a5c9 |
cfg->etag = html_etag;
|
|
Packit |
90a5c9 |
if (l && !strcasecmp(l, "legacy"))
|
|
Packit |
90a5c9 |
cfg->doctype = fpi_html_legacy;
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
cfg->doctype = fpi_html;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (!strcasecmp(t, "html5")) {
|
|
Packit |
90a5c9 |
cfg->etag = html_etag;
|
|
Packit |
90a5c9 |
cfg->doctype = fpi_html5;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
cfg->doctype = t;
|
|
Packit |
90a5c9 |
if (l && ((l[0] == 'x') || (l[0] == 'X')))
|
|
Packit |
90a5c9 |
cfg->etag = xhtml_etag;
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
cfg->etag = html_etag;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_flags(cmd_parms *cmd, void *CFG, const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg = CFG;
|
|
Packit |
90a5c9 |
if (arg && *arg) {
|
|
Packit |
90a5c9 |
if (!strcasecmp(arg, "lowercase"))
|
|
Packit |
90a5c9 |
cfg->flags |= NORM_LC;
|
|
Packit |
90a5c9 |
else if (!strcasecmp(arg, "dospath"))
|
|
Packit |
90a5c9 |
cfg->flags |= NORM_MSSLASH;
|
|
Packit |
90a5c9 |
else if (!strcasecmp(arg, "reset"))
|
|
Packit |
90a5c9 |
cfg->flags |= NORM_RESET;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_events(cmd_parms *cmd, void *CFG, const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
tattr *attr;
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg = CFG;
|
|
Packit |
90a5c9 |
if (cfg->events == NULL)
|
|
Packit |
90a5c9 |
cfg->events = apr_array_make(cmd->pool, 20, sizeof(tattr));
|
|
Packit |
90a5c9 |
attr = apr_array_push(cfg->events);
|
|
Packit |
90a5c9 |
attr->val = arg;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_links(cmd_parms *cmd, void *CFG,
|
|
Packit |
90a5c9 |
const char *elt, const char *att)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_array_header_t *attrs;
|
|
Packit |
90a5c9 |
tattr *attr;
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg = CFG;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (cfg->links == NULL)
|
|
Packit |
90a5c9 |
cfg->links = apr_hash_make(cmd->pool);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
attrs = apr_hash_get(cfg->links, elt, APR_HASH_KEY_STRING);
|
|
Packit |
90a5c9 |
if (!attrs) {
|
|
Packit |
90a5c9 |
attrs = apr_array_make(cmd->pool, 2, sizeof(tattr*));
|
|
Packit |
90a5c9 |
apr_hash_set(cfg->links, elt, APR_HASH_KEY_STRING, attrs);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
attr = apr_array_push(attrs);
|
|
Packit |
90a5c9 |
attr->val = att;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
static const command_rec proxy_html_cmds[] = {
|
|
Packit |
90a5c9 |
AP_INIT_ITERATE("ProxyHTMLEvents", set_events, NULL,
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF,
|
|
Packit |
90a5c9 |
"Strings to be treated as scripting events"),
|
|
Packit |
90a5c9 |
AP_INIT_ITERATE2("ProxyHTMLLinks", set_links, NULL,
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Declare HTML Attributes"),
|
|
Packit |
90a5c9 |
AP_INIT_RAW_ARGS("ProxyHTMLURLMap", set_urlmap, NULL,
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Map URL From To"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE12("ProxyHTMLDoctype", set_doctype, NULL,
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "(HTML|XHTML) [Legacy]"),
|
|
Packit |
90a5c9 |
AP_INIT_ITERATE("ProxyHTMLFixups", set_flags, NULL,
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Options are lowercase, dospath"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("ProxyHTMLMeta", ap_set_flag_slot,
|
|
Packit |
90a5c9 |
(void*)APR_OFFSETOF(proxy_html_conf, metafix),
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Fix META http-equiv elements"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("ProxyHTMLInterp", ap_set_flag_slot,
|
|
Packit |
90a5c9 |
(void*)APR_OFFSETOF(proxy_html_conf, interp),
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF,
|
|
Packit |
90a5c9 |
"Support interpolation and conditions in URLMaps"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("ProxyHTMLExtended", ap_set_flag_slot,
|
|
Packit |
90a5c9 |
(void*)APR_OFFSETOF(proxy_html_conf, extfix),
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Map URLs in Javascript and CSS"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("ProxyHTMLStripComments", ap_set_flag_slot,
|
|
Packit |
90a5c9 |
(void*)APR_OFFSETOF(proxy_html_conf, strip_comments),
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Strip out comments"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("ProxyHTMLBufSize", ap_set_int_slot,
|
|
Packit |
90a5c9 |
(void*)APR_OFFSETOF(proxy_html_conf, bufsz),
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Buffer size"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("ProxyHTMLCharsetOut", ap_set_string_slot,
|
|
Packit |
90a5c9 |
(void*)APR_OFFSETOF(proxy_html_conf, charset_out),
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF, "Usage: ProxyHTMLCharsetOut charset"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("ProxyHTMLEnable", ap_set_flag_slot,
|
|
Packit |
90a5c9 |
(void*)APR_OFFSETOF(proxy_html_conf, enabled),
|
|
Packit |
90a5c9 |
RSRC_CONF|ACCESS_CONF,
|
|
Packit |
90a5c9 |
"Enable proxy-html and xml2enc filters"),
|
|
Packit |
90a5c9 |
{ NULL }
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
static int mod_proxy_html(apr_pool_t *p, apr_pool_t *p1, apr_pool_t *p2)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
seek_meta = ap_pregcomp(p, "<meta[^>]*(http-equiv)[^>]*>",
|
|
Packit |
90a5c9 |
AP_REG_EXTENDED|AP_REG_ICASE);
|
|
Packit |
90a5c9 |
seek_content = apr_strmatch_precompile(p, "content", 0);
|
|
Packit |
90a5c9 |
memset(&sax, 0, sizeof(htmlSAXHandler));
|
|
Packit |
90a5c9 |
sax.startElement = pstartElement;
|
|
Packit |
90a5c9 |
sax.endElement = pendElement;
|
|
Packit |
90a5c9 |
sax.characters = pcharacters;
|
|
Packit |
90a5c9 |
sax.comment = pcomment;
|
|
Packit |
90a5c9 |
sax.cdataBlock = pcdata;
|
|
Packit |
90a5c9 |
xml2enc_charset = APR_RETRIEVE_OPTIONAL_FN(xml2enc_charset);
|
|
Packit |
90a5c9 |
xml2enc_filter = APR_RETRIEVE_OPTIONAL_FN(xml2enc_filter);
|
|
Packit |
90a5c9 |
if (!xml2enc_charset) {
|
|
Packit |
90a5c9 |
ap_log_perror(APLOG_MARK, APLOG_NOTICE, 0, p2, APLOGNO(01425)
|
|
Packit |
90a5c9 |
"I18n support in mod_proxy_html requires mod_xml2enc. "
|
|
Packit |
90a5c9 |
"Without it, non-ASCII characters in proxied pages are "
|
|
Packit |
90a5c9 |
"likely to display incorrectly.");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* old_expr only needs to last the life of the config phase */
|
|
Packit |
90a5c9 |
old_expr = ap_rxplus_compile(p1, "s/^(!)?(\\w+)((=)(.+))?$/reqenv('$2')$1$4'$5'/");
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
static void proxy_html_insert(request_rec *r)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
proxy_html_conf *cfg;
|
|
Packit |
90a5c9 |
cfg = ap_get_module_config(r->per_dir_config, &proxy_html_module);
|
|
Packit |
90a5c9 |
if (cfg->enabled) {
|
|
Packit |
90a5c9 |
if (xml2enc_filter)
|
|
Packit |
90a5c9 |
xml2enc_filter(r, NULL, ENCIO_INPUT_CHECKS);
|
|
Packit |
90a5c9 |
ap_add_output_filter("proxy-html", NULL, r, r->connection);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
static void proxy_html_hooks(apr_pool_t *p)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
static const char *aszSucc[] = { "mod_filter.c", NULL };
|
|
Packit |
90a5c9 |
ap_register_output_filter_protocol("proxy-html", proxy_html_filter,
|
|
Packit |
90a5c9 |
NULL, AP_FTYPE_RESOURCE,
|
|
Packit |
90a5c9 |
AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH);
|
|
Packit |
90a5c9 |
/* move this to pre_config so old_expr is available to interpret
|
|
Packit |
90a5c9 |
* old-style conditions on URL maps.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
ap_hook_pre_config(mod_proxy_html, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_insert_filter(proxy_html_insert, NULL, aszSucc, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
AP_DECLARE_MODULE(proxy_html) = {
|
|
Packit |
90a5c9 |
STANDARD20_MODULE_STUFF,
|
|
Packit |
90a5c9 |
proxy_html_config,
|
|
Packit |
90a5c9 |
proxy_html_merge,
|
|
Packit |
90a5c9 |
NULL,
|
|
Packit |
90a5c9 |
NULL,
|
|
Packit |
90a5c9 |
proxy_html_cmds,
|
|
Packit |
90a5c9 |
proxy_html_hooks
|
|
Packit |
90a5c9 |
};
|