Apache HTTPD
mod_proxy_html.c
Go to the documentation of this file.
1/* Copyright (c) 2003-11, WebThing Ltd
2 * Copyright (c) 2011-, The Apache Software Foundation
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20/* GO_FASTER
21 You can #define GO_FASTER to disable trace logging.
22*/
23
24#ifdef GO_FASTER
25#define VERBOSE(x)
26#define VERBOSEB(x)
27#else
28#define VERBOSE(x) if (verbose) x
29#define VERBOSEB(x) if (verbose) {x}
30#endif
31
32/* libxml2 includes unicode/[...].h files which uses C++ comments */
33#if defined(__clang__)
34#pragma clang diagnostic push
35#pragma clang diagnostic warning "-Wcomment"
36#elif defined(__GNUC__)
37#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
38#pragma GCC diagnostic push
39#pragma GCC diagnostic warning "-Wcomment"
40#endif
41#endif
42
43/* libxml2 */
44#include <libxml/HTMLparser.h>
45
46#if defined(__clang__)
47#pragma clang diagnostic pop
48#elif defined(__GNUC__)
49#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
50#pragma GCC diagnostic pop
51#endif
52#endif
53
54#include "http_protocol.h"
55#include "http_config.h"
56#include "http_log.h"
57#include "apr_strings.h"
58#include "apr_hash.h"
59#include "apr_strmatch.h"
60#include "apr_lib.h"
61
62#include "apr_optional.h"
63#include "mod_xml2enc.h"
64#include "http_request.h"
65#include "ap_expr.h"
66
67/* globals set once at startup */
72static apr_status_t (*xml2enc_filter)(request_rec*, const char*, unsigned int) = NULL;
73
74module AP_MODULE_DECLARE_DATA proxy_html_module;
75
76#define M_HTML 0x01
77#define M_EVENTS 0x02
78#define M_CDATA 0x04
79#define M_REGEX 0x08
80#define M_ATSTART 0x10
81#define M_ATEND 0x20
82#define M_LAST 0x40
83#define M_NOTLAST 0x80
84#define M_INTERPOLATE_TO 0x100
85#define M_INTERPOLATE_FROM 0x200
86
87typedef struct {
88 const char *val;
89} tattr;
90typedef struct {
91 unsigned int start;
92 unsigned int end;
93} meta;
94typedef struct urlmap {
95 struct urlmap *next;
96 unsigned int flags;
97 unsigned int regflags;
98 union {
99 const char *c;
102 const char *to;
105typedef struct {
107 const char *doctype;
108 const char *etag;
109 unsigned int flags;
110 int bufsz;
113 const char *charset_out;
134
135
136#define NORM_LC 0x1
137#define NORM_MSSLASH 0x2
138#define NORM_RESET 0x4
140
142
143static const char *const fpi_html =
144 "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n";
145static const char *const fpi_html_legacy =
146 "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
147static const char *const fpi_xhtml =
148 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
149static const char *const fpi_xhtml_legacy =
150 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
151static const char *const fpi_html5 = "<!DOCTYPE html>\n";
152static const char *const html_etag = ">";
153static const char *const xhtml_etag = " />";
154/*#define DEFAULT_DOCTYPE fpi_html */
155static const char *const DEFAULT_DOCTYPE = "";
156#define DEFAULT_ETAG html_etag
157
158static void normalise(unsigned int flags, char *str)
159{
160 char *p;
161 if (flags & NORM_LC)
162 for (p = str; *p; ++p)
163 if (isupper(*p))
164 *p = tolower(*p);
165
166 if (flags & NORM_MSSLASH)
167 for (p = ap_strchr(str, '\\'); p; p = ap_strchr(p+1, '\\'))
168 *p = '/';
169
170}
171#define consume_buffer(ctx,inbuf,bytes,flag) \
172 htmlParseChunk(ctx->parser, inbuf, bytes, flag)
173
174#define AP_fwrite(ctx,inbuf,bytes,flush) \
175 ap_fwrite(ctx->f->next, ctx->bb, inbuf, bytes);
176
177/* This is always utf-8 on entry. We can convert charset within FLUSH */
178#define FLUSH AP_fwrite(ctx, (chars+begin), (i-begin), 0); begin = i+1
179static void pcharacters(void *ctxt, const xmlChar *uchars, int length)
180{
181 const char *chars = (const char*) uchars;
182 saxctxt *ctx = (saxctxt*) ctxt;
183 int i;
184 int begin;
185 for (begin=i=0; i<length; i++) {
186 switch (chars[i]) {
187 case '&' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&amp;"); break;
188 case '<' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&lt;"); break;
189 case '>' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&gt;"); break;
190 case '"' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&quot;"); break;
191 default : break;
192 }
193 }
194 FLUSH;
195}
196
197static void preserve(saxctxt *ctx, const size_t len)
198{
199 char *newbuf;
200 if (len <= (ctx->avail - ctx->offset))
201 return;
202 else while (len > (ctx->avail - ctx->offset))
203 ctx->avail += ctx->cfg->bufsz;
204
205 newbuf = realloc(ctx->buf, ctx->avail);
206 if (newbuf != ctx->buf) {
207 if (ctx->buf)
208 apr_pool_cleanup_kill(ctx->f->r->pool, ctx->buf,
209 (int(*)(void*))free);
211 (int(*)(void*))free, apr_pool_cleanup_null);
212 ctx->buf = newbuf;
213 }
214}
215
216static void pappend(saxctxt *ctx, const char *buf, const size_t len)
217{
218 preserve(ctx, len);
219 memcpy(ctx->buf+ctx->offset, buf, len);
220 ctx->offset += len;
221}
222
224{
225 urlmap *m;
226 char *found;
227 size_t s_from, s_to;
228 size_t match;
229 char c = 0;
230 int nmatch;
232 char *subs;
233 size_t len, offs;
234 urlmap *themap = ctx->map;
235#ifndef GO_FASTER
236 int verbose = APLOGrtrace1(ctx->f->r);
237#endif
238
239 pappend(ctx, &c, 1); /* append null byte */
240 /* parse the text for URLs */
241 for (m = themap; m; m = m->next) {
242 if (!(m->flags & M_CDATA))
243 continue;
244 if (m->flags & M_REGEX) {
245 nmatch = 10;
246 offs = 0;
247 while (!ap_regexec(m->from.r, ctx->buf+offs, nmatch, pmatch, 0)) {
248 match = pmatch[0].rm_so;
249 s_from = pmatch[0].rm_eo - match;
250 subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
251 nmatch, pmatch);
252 s_to = strlen(subs);
253 len = strlen(ctx->buf);
254 offs += match;
255 VERBOSEB(
256 const char *f = apr_pstrndup(ctx->f->r->pool,
257 ctx->buf + offs, s_from);
259 "C/RX: match at %s, substituting %s", f, subs);
260 )
261 if (s_to > s_from) {
263 memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
264 len + 1 - s_from - offs);
265 memcpy(ctx->buf+offs, subs, s_to);
266 }
267 else {
268 memcpy(ctx->buf + offs, subs, s_to);
269 memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
270 len + 1 - s_from - offs);
271 }
272 offs += s_to;
273 }
274 }
275 else {
276 s_from = strlen(m->from.c);
277 s_to = strlen(m->to);
278 for (found = strstr(ctx->buf, m->from.c); found;
279 found = strstr(ctx->buf+match+s_to, m->from.c)) {
280 match = found - ctx->buf;
281 if ((m->flags & M_ATSTART) && (match != 0))
282 break;
283 len = strlen(ctx->buf);
284 if ((m->flags & M_ATEND) && (match < (len - s_from)))
285 continue;
287 "C: matched %s, substituting %s",
288 m->from.c, m->to));
289 if (s_to > s_from) {
291 memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
292 len + 1 - s_from - match);
293 memcpy(ctx->buf+match, m->to, s_to);
294 }
295 else {
296 memcpy(ctx->buf+match, m->to, s_to);
297 memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
298 len + 1 - s_from - match);
299 }
300 }
301 }
302 }
303 AP_fwrite(ctx, ctx->buf, strlen(ctx->buf), 1);
304}
305static void pcdata(void *ctxt, const xmlChar *uchars, int length)
306{
307 const char *chars = (const char*) uchars;
308 saxctxt *ctx = (saxctxt*) ctxt;
309 if (ctx->cfg->extfix) {
311 }
312 else {
313 /* not sure if this should force-flush
314 * (i.e. can one cdata section come in multiple calls?)
315 */
317 }
318}
319static void pcomment(void *ctxt, const xmlChar *uchars)
320{
321 const char *chars = (const char*) uchars;
322 saxctxt *ctx = (saxctxt*) ctxt;
323 if (ctx->cfg->strip_comments)
324 return;
325
326 if (ctx->cfg->extfix) {
327 pappend(ctx, "<!--", 4);
328 pappend(ctx, chars, strlen(chars));
329 pappend(ctx, "-->", 3);
330 }
331 else {
332 ap_fputs(ctx->f->next, ctx->bb, "<!--");
333 AP_fwrite(ctx, chars, strlen(chars), 1);
334 ap_fputs(ctx->f->next, ctx->bb, "-->");
336 }
337}
338static void pendElement(void *ctxt, const xmlChar *uname)
339{
340 saxctxt *ctx = (saxctxt*) ctxt;
341 const char *name = (const char*) uname;
342 const htmlElemDesc* desc = htmlTagLookup(uname);
343
344 if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
345 /* enforce html */
346 if (!desc || desc->depr)
347 return;
348
349 }
350 else if ((ctx->cfg->doctype == fpi_html_legacy)
351 || (ctx->cfg->doctype == fpi_xhtml_legacy)) {
352 /* enforce html legacy */
353 if (!desc)
354 return;
355 }
356 /* TODO - implement HTML "allowed here" using the stack */
357 /* nah. Keeping the stack is too much overhead */
358
359 if (ctx->offset > 0) {
361 ctx->offset = 0; /* having dumped it, we can re-use the memory */
362 }
363 if (!desc || !desc->empty) {
364 ap_fprintf(ctx->f->next, ctx->bb, "</%s>", name);
365 }
366}
367
368static void pstartElement(void *ctxt, const xmlChar *uname,
369 const xmlChar** uattrs)
370{
371 int required_attrs;
372 int num_match;
373 size_t offs, len;
374 char *subs;
376 const char** a;
377 urlmap *m;
378 size_t s_to, s_from, match;
379 char *found;
380 saxctxt *ctx = (saxctxt*) ctxt;
381 size_t nmatch;
383#ifndef GO_FASTER
384 int verbose = APLOGrtrace1(ctx->f->r);
385#endif
387 int i;
388 const char *name = (const char*) uname;
389 const char** attrs = (const char**) uattrs;
390 const htmlElemDesc* desc = htmlTagLookup(uname);
391 urlmap *themap = ctx->map;
392#ifdef HAVE_STACK
393 const void** descp;
394#endif
395 int enforce = 0;
396 if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
397 /* enforce html */
398 if (!desc || desc->depr) {
400 "Bogus HTML element %s dropped", name);
401 return;
402 }
403 enforce = 2;
404 }
405 else if ((ctx->cfg->doctype == fpi_html_legacy)
406 || (ctx->cfg->doctype == fpi_xhtml_legacy)) {
407 /* enforce html legacy */
408 if (!desc) {
410 "Deprecated HTML element %s dropped", name);
411 return;
412 }
413 enforce = 1;
414 }
415#ifdef HAVE_STACK
416 descp = apr_array_push(ctx->stack);
417 *descp = desc;
418 /* TODO - implement HTML "allowed here" */
419#endif
420
421 ap_fputc(ctx->f->next, ctx->bb, '<');
422 ap_fputs(ctx->f->next, ctx->bb, name);
423
424 required_attrs = 0;
425 if ((enforce > 0) && (desc != NULL) && (desc->attrs_req != NULL))
426 for (a = desc->attrs_req; *a; a++)
428
429 if (attrs) {
431 for (a = attrs; *a; a += 2) {
432 if (desc && enforce > 0) {
433 switch (htmlAttrAllowed(desc, (xmlChar*)*a, 2-enforce)) {
434 case HTML_INVALID:
436 "Bogus HTML attribute %s of %s dropped",
437 *a, name);
438 continue;
439 case HTML_DEPRECATED:
441 "Deprecated HTML attribute %s of %s dropped",
442 *a, name);
443 continue;
444 case HTML_REQUIRED:
445 required_attrs--; /* cross off the number still needed */
446 /* fallthrough - required implies valid */
447 default:
448 break;
449 }
450 }
451 ctx->offset = 0;
452 if (a[1]) {
453 pappend(ctx, a[1], strlen(a[1])+1);
455 if (linkattrs) {
456 tattr *attrs = (tattr*) linkattrs->elts;
457 for (i=0; i < linkattrs->nelts; ++i) {
458 if (!strcmp(*a, attrs[i].val)) {
460 break;
461 }
462 }
463 }
464 if ((is_uri == ATTR_IGNORE) && ctx->cfg->extfix
465 && (ctx->cfg->events != NULL)) {
466 for (i=0; i < ctx->cfg->events->nelts; ++i) {
467 tattr *attrs = (tattr*) ctx->cfg->events->elts;
468 if (!strcmp(*a, attrs[i].val)) {
470 break;
471 }
472 }
473 }
474 switch (is_uri) {
475 case ATTR_URI:
476 num_match = 0;
477 for (m = themap; m; m = m->next) {
478 if (!(m->flags & M_HTML))
479 continue;
480 if (m->flags & M_REGEX) {
481 nmatch = 10;
482 if (!ap_regexec(m->from.r, ctx->buf, nmatch,
483 pmatch, 0)) {
484 ++num_match;
485 offs = match = pmatch[0].rm_so;
486 s_from = pmatch[0].rm_eo - match;
487 subs = ap_pregsub(ctx->f->r->pool, m->to,
488 ctx->buf, nmatch, pmatch);
489 VERBOSE({
490 const char *f;
491 f = apr_pstrndup(ctx->f->r->pool,
492 ctx->buf + offs, s_from);
494 ctx->f->r,
495 "H/RX: match at %s, substituting %s",
496 f, subs);
497 })
498 s_to = strlen(subs);
499 len = strlen(ctx->buf);
500 if (s_to > s_from) {
502 memmove(ctx->buf+offs+s_to,
503 ctx->buf+offs+s_from,
504 len + 1 - s_from - offs);
505 memcpy(ctx->buf+offs, subs, s_to);
506 }
507 else {
508 memcpy(ctx->buf + offs, subs, s_to);
509 memmove(ctx->buf+offs+s_to,
510 ctx->buf+offs+s_from,
511 len + 1 - s_from - offs);
512 }
513 }
514 } else {
515 s_from = strlen(m->from.c);
516 if (!strncasecmp(ctx->buf, m->from.c, s_from)) {
517 ++num_match;
518 s_to = strlen(m->to);
519 len = strlen(ctx->buf);
521 0, ctx->f->r,
522 "H: matched %s, substituting %s",
523 m->from.c, m->to));
524 if (s_to > s_from) {
526 memmove(ctx->buf+s_to, ctx->buf+s_from,
527 len + 1 - s_from);
528 memcpy(ctx->buf, m->to, s_to);
529 }
530 else { /* it fits in the existing space */
531 memcpy(ctx->buf, m->to, s_to);
532 memmove(ctx->buf+s_to, ctx->buf+s_from,
533 len + 1 - s_from);
534 }
535 break;
536 }
537 }
538 /* URIs only want one match unless overridden in the config */
539 if ((num_match > 0) && !(m->flags & M_NOTLAST))
540 break;
541 }
542 break;
543 case ATTR_EVENT:
544 for (m = themap; m; m = m->next) {
545 num_match = 0; /* reset here since we're working per-rule */
546 if (!(m->flags & M_EVENTS))
547 continue;
548 if (m->flags & M_REGEX) {
549 nmatch = 10;
550 offs = 0;
551 while (!ap_regexec(m->from.r, ctx->buf+offs,
552 nmatch, pmatch, 0)) {
553 match = pmatch[0].rm_so;
554 s_from = pmatch[0].rm_eo - match;
555 subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
556 nmatch, pmatch);
557 VERBOSE({
558 const char *f;
559 f = apr_pstrndup(ctx->f->r->pool,
560 ctx->buf + offs, s_from);
562 ctx->f->r,
563 "E/RX: match at %s, substituting %s",
564 f, subs);
565 })
566 s_to = strlen(subs);
567 offs += match;
568 len = strlen(ctx->buf);
569 if (s_to > s_from) {
571 memmove(ctx->buf+offs+s_to,
572 ctx->buf+offs+s_from,
573 len + 1 - s_from - offs);
574 memcpy(ctx->buf+offs, subs, s_to);
575 }
576 else {
577 memcpy(ctx->buf + offs, subs, s_to);
578 memmove(ctx->buf+offs+s_to,
579 ctx->buf+offs+s_from,
580 len + 1 - s_from - offs);
581 }
582 offs += s_to;
583 ++num_match;
584 }
585 }
586 else {
587 found = strstr(ctx->buf, m->from.c);
588 if ((m->flags & M_ATSTART) && (found != ctx->buf))
589 continue;
590 while (found) {
591 s_from = strlen(m->from.c);
592 s_to = strlen(m->to);
593 match = found - ctx->buf;
594 if ((s_from < strlen(found))
595 && (m->flags & M_ATEND)) {
596 found = strstr(ctx->buf+match+s_from,
597 m->from.c);
598 continue;
599 }
600 else {
601 found = strstr(ctx->buf+match+s_to,
602 m->from.c);
603 }
605 0, ctx->f->r,
606 "E: matched %s, substituting %s",
607 m->from.c, m->to));
608 len = strlen(ctx->buf);
609 if (s_to > s_from) {
611 memmove(ctx->buf+match+s_to,
612 ctx->buf+match+s_from,
613 len + 1 - s_from - match);
614 memcpy(ctx->buf+match, m->to, s_to);
615 }
616 else {
617 memcpy(ctx->buf+match, m->to, s_to);
618 memmove(ctx->buf+match+s_to,
619 ctx->buf+match+s_from,
620 len + 1 - s_from - match);
621 }
622 ++num_match;
623 }
624 }
625 if (num_match && (m->flags & M_LAST))
626 break;
627 }
628 break;
629 case ATTR_IGNORE:
630 break;
631 }
632 }
633 if (!a[1])
634 ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], NULL);
635 else {
636
637 if (ctx->cfg->flags != 0)
638 normalise(ctx->cfg->flags, ctx->buf);
639
640 /* write the attribute, using pcharacters to html-escape
641 anything that needs it in the value.
642 */
643 ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], "=\"", NULL);
644 pcharacters(ctx, (const xmlChar*)ctx->buf, strlen(ctx->buf));
645 ap_fputc(ctx->f->next, ctx->bb, '"');
646 }
647 }
648 }
649 ctx->offset = 0;
650 if (desc && desc->empty)
651 ap_fputs(ctx->f->next, ctx->bb, ctx->cfg->etag);
652 else
653 ap_fputc(ctx->f->next, ctx->bb, '>');
654
655 if ((enforce > 0) && (required_attrs > 0)) {
656 /* if there are more required attributes than we found then complain */
658 "HTML element %s is missing %d required attributes",
660 }
661}
662
663static meta *metafix(request_rec *r, const char *buf, apr_size_t len)
664{
665 meta *ret = NULL;
666 size_t offs = 0;
667 const char *p;
668 const char *q;
669 char *header;
670 char *content;
672 char delim;
673
674 while (offs < len &&
675 !ap_regexec_len(seek_meta, buf + offs, len - offs, 2, pmatch, 0)) {
676 header = NULL;
677 content = NULL;
678 p = buf+offs+pmatch[1].rm_eo;
679 while (!apr_isalpha(*++p));
680 for (q = p; apr_isalnum(*q) || (*q == '-'); ++q);
681 header = apr_pstrmemdup(r->pool, p, q-p);
682 if (ap_cstr_casecmpn(header, "Content-", 8)) {
683 /* find content=... string */
685 pmatch[0].rm_eo - pmatch[0].rm_so);
686 /* if it doesn't contain "content", ignore, don't crash! */
687 if (p != NULL) {
688 while (*p) {
689 p += 7;
690 while (apr_isspace(*p))
691 ++p;
692 /* XXX Should we search for another content= pattern? */
693 if (*p != '=')
694 break;
695 while (*p && apr_isspace(*++p));
696 if ((*p == '\'') || (*p == '"')) {
697 delim = *p++;
698 for (q = p; *q && *q != delim; ++q);
699 /* No terminating delimiter found? Skip the bogus directive */
700 if (*q != delim)
701 break;
702 } else {
703 for (q = p; *q && !apr_isspace(*q) && (*q != '>'); ++q);
704 }
705 content = apr_pstrmemdup(r->pool, p, q-p);
706 break;
707 }
708 }
709 }
710 else if (!ap_cstr_casecmpn(header, "Content-Type", 12)) {
711 ret = apr_palloc(r->pool, sizeof(meta));
712 ret->start = offs+pmatch[0].rm_so;
713 ret->end = offs+pmatch[0].rm_eo;
714 }
715 if (header && content) {
716#ifndef GO_FASTER
718 "Adding header [%s: %s] from HTML META",
719 header, content);
720#endif
722 }
723 offs += pmatch[0].rm_eo;
724 }
725 return ret;
726}
727
728static const char *interpolate_vars(request_rec *r, const char *str)
729{
730 const char *start;
731 const char *end;
732 const char *delim;
733 const char *before;
734 const char *after;
735 const char *replacement;
736 const char *var;
737 for (;;) {
738 if ((start = ap_strstr_c(str, "${")) == NULL)
739 break;
740
741 if ((end = ap_strchr_c(start+2, '}')) == NULL)
742 break;
743
744 delim = ap_strchr_c(start+2, '|');
745
746 /* Restrict delim to ${...} */
747 if (delim && delim >= end) {
748 delim = NULL;
749 }
750
752 after = end+1;
753 if (delim) {
755 }
756 else {
758 }
759 replacement = apr_table_get(r->subprocess_env, var);
760 if (!replacement) {
761 if (delim)
762 replacement = apr_pstrmemdup(r->pool, delim+1, end-delim-1);
763 else
764 replacement = "";
765 }
766 str = apr_pstrcat(r->pool, before, replacement, after, NULL);
768 "Interpolating %s => %s", var, replacement);
769 }
770 return str;
771}
773{
774 urlmap *newp;
775 urlmap *p;
776 urlmap *prev = NULL;
777 request_rec *r = ctx->f->r;
778
779 for (p = ctx->cfg->map; p; p = p->next) {
780 if (p->cond != NULL) {
781 const char *err;
782 int ok = ap_expr_exec(r, p->cond, &err);
783 if (err) {
785 "Error evaluating expr: %s", err);
786 }
787 if (ok == 0) {
788 continue; /* condition is unsatisfied */
789 }
790 }
791
792 newp = apr_pmemdup(r->pool, p, sizeof(urlmap));
793
794 if (newp->flags & M_INTERPOLATE_FROM) {
795 newp->from.c = interpolate_vars(r, newp->from.c);
796 if (!newp->from.c || !*newp->from.c)
797 continue; /* don't use empty from-pattern */
798 if (newp->flags & M_REGEX) {
799 newp->from.r = ap_pregcomp(r->pool, newp->from.c,
800 newp->regflags);
801 }
802 }
803 if (newp->flags & M_INTERPOLATE_TO) {
804 newp->to = interpolate_vars(r, newp->to);
805 }
806 /* evaluate p->cond; continue if unsatisfied */
807 /* create new urlmap with memcpy and append to map */
808 /* interpolate from if flagged to do so */
809 /* interpolate to if flagged to do so */
810
811 if (prev != NULL)
812 prev->next = newp;
813 else
814 ctx->map = newp;
815 prev = newp;
816 }
817
818 if (prev)
819 prev->next = NULL;
820}
821
823{
824 saxctxt *fctx;
825 if (!f->ctx) {
826 proxy_html_conf *cfg;
827 const char *force;
828 const char *errmsg = NULL;
829 cfg = ap_get_module_config(f->r->per_dir_config, &proxy_html_module);
830 force = apr_table_get(f->r->subprocess_env, "PROXY_HTML_FORCE");
831
832 if (!force) {
833 if (!f->r->proxyreq) {
834 errmsg = "Non-proxy request; not inserting proxy-html filter";
835 }
836 else if (!f->r->content_type) {
837 errmsg = "No content-type; bailing out of proxy-html filter";
838 }
839 else if (ap_cstr_casecmpn(f->r->content_type, "text/html", 9) &&
840 ap_cstr_casecmpn(f->r->content_type,
841 "application/xhtml+xml", 21)) {
842 errmsg = "Non-HTML content; not inserting proxy-html filter";
843 }
844 }
845 if (!cfg->links) {
846 errmsg = "No links configured: nothing for proxy-html filter to do";
847 }
848
849 if (errmsg) {
850#ifndef GO_FASTER
851 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r, "%s", errmsg);
852#endif
854 return NULL;
855 }
856
857 fctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(saxctxt));
858 fctx->f = f;
859 fctx->bb = apr_brigade_create(f->r->pool,
860 f->r->connection->bucket_alloc);
861 fctx->cfg = cfg;
862 apr_table_unset(f->r->headers_out, "Content-Length");
863
864 if (cfg->interp)
865 fixup_rules(fctx);
866 else
867 fctx->map = cfg->map;
868 /* defer dealing with charset_out until after sniffing charset_in
869 * so we can support setting one to t'other.
870 */
871 }
872 return f->ctx;
873}
874
876{
877 if (ctxt->rlen) {
879 ctxt->rlen,
880 bb->bucket_alloc);
882 ctxt->rlen = 0;
883 }
884}
885
887{
888 apr_bucket* b;
889 meta *m = NULL;
890 xmlCharEncoding enc;
891 const char *buf = 0;
892 apr_size_t bytes = 0;
893#ifndef USE_OLD_LIBXML2
896#endif
897
899 if (!ctxt)
900 return ap_pass_brigade(f->next, bb);
901 for (b = APR_BRIGADE_FIRST(bb);
902 b != APR_BRIGADE_SENTINEL(bb);
903 b = APR_BUCKET_NEXT(b)) {
905 if (APR_BUCKET_IS_EOS(b)) {
906 if (ctxt->parser != NULL) {
907 consume_buffer(ctxt, "", 0, 1);
908 }
909 else {
910 prepend_rbuf(ctxt, ctxt->bb);
911 }
913 apr_bucket_eos_create(ctxt->bb->bucket_alloc));
914 ap_pass_brigade(ctxt->f->next, ctxt->bb);
916 }
917 else if (APR_BUCKET_IS_FLUSH(b)) {
918 /* pass on flush, except at start where it would cause
919 * headers to be sent before doc sniffing
920 */
921 if (ctxt->parser != NULL) {
922 ap_fflush(ctxt->f->next, ctxt->bb);
923 }
924 }
925 }
927 == APR_SUCCESS) {
928 if (ctxt->parser == NULL) {
929 const char *cenc;
930
931 /* For documents smaller than four bytes, there is no reason to do
932 * HTML rewriting. The URL schema (i.e. 'http') needs four bytes alone.
933 * And the HTML parser needs at least four bytes to initialise correctly.
934 */
935 ctxt->rmin += bytes;
936 if (ctxt->rmin < sizeof(ctxt->rbuf)) {
937 memcpy(ctxt->rbuf + ctxt->rlen, buf, bytes);
938 ctxt->rlen += bytes;
939 continue;
940 }
941 if (ctxt->rlen && ctxt->rlen < sizeof(ctxt->rbuf)) {
942 apr_size_t rem = sizeof(ctxt->rbuf) - ctxt->rlen;
943 memcpy(ctxt->rbuf + ctxt->rlen, buf, rem);
944 ctxt->rlen += rem;
945 buf += rem;
946 bytes -= rem;
947 }
948
949 if (!xml2enc_charset ||
950 (xml2enc_charset(f->r, &enc, &cenc) != APR_SUCCESS)) {
951 if (!xml2enc_charset)
953 "No i18n support found. Install mod_xml2enc if required");
955 ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
956 }
957 else {
958 /* if we wanted a non-default charset_out, insert the
959 * xml2enc filter now that we've sniffed it
960 */
961 if (ctxt->cfg->charset_out && xml2enc_filter) {
962 if (*ctxt->cfg->charset_out != '*')
963 cenc = ctxt->cfg->charset_out;
966 apr_pstrcat(f->r->pool,
967 "text/html;charset=",
968 cenc, NULL));
969 }
970 else /* Normal case, everything worked, utf-8 output */
971 ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
972 }
973
974 ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
975
976 if (ctxt->rlen) {
978 ctxt->rbuf,
979 ctxt->rlen,
980 NULL, enc);
981 }
982 else {
983 ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt, buf, 4,
984 NULL, enc);
985 buf += 4;
986 bytes -= 4;
987 }
988 if (ctxt->parser == NULL) {
989 prepend_rbuf(ctxt, bb);
991 return ap_pass_brigade(f->next, bb);
992 }
993 ctxt->rlen = 0;
995 (int(*)(void*))htmlFreeParserCtxt,
997#ifndef USE_OLD_LIBXML2
1000 "Unsupported parser opts %x", xmlopts);
1001#endif
1002 if (ctxt->cfg->metafix)
1003 m = metafix(f->r, buf, bytes);
1004 if (m) {
1005 consume_buffer(ctxt, buf, m->start, 0);
1006 consume_buffer(ctxt, buf+m->end, bytes-m->end, 0);
1007 }
1008 else {
1010 }
1011 }
1012 else {
1014 }
1015 }
1016 else {
1018 "Error in bucket read");
1019 }
1020 }
1021 /*ap_fflush(ctxt->f->next, ctxt->bb); // uncomment for debug */
1023 return APR_SUCCESS;
1024}
1025
1026static void *proxy_html_config(apr_pool_t *pool, char *x)
1027{
1029 ret->doctype = DEFAULT_DOCTYPE;
1030 ret->etag = DEFAULT_ETAG;
1031 ret->bufsz = 8192;
1032 /* ret->interp = 1; */
1033 /* don't initialise links and events until they get set/used */
1034 return ret;
1035}
1036
1037static void *proxy_html_merge(apr_pool_t *pool, void *BASE, void *ADD)
1038{
1042
1043 /* don't merge declarations - just use the most specific */
1044 conf->links = (add->links == NULL) ? base->links : add->links;
1045 conf->events = (add->events == NULL) ? base->events : add->events;
1046
1047 conf->charset_out = (add->charset_out == NULL)
1048 ? base->charset_out : add->charset_out;
1049
1050 if (add->map && base->map) {
1051 urlmap *a;
1052 conf->map = NULL;
1053 for (a = base->map; a; a = a->next) {
1054 urlmap *save = conf->map;
1055 conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
1056 conf->map->next = save;
1057 }
1058 for (a = add->map; a; a = a->next) {
1059 urlmap *save = conf->map;
1060 conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
1061 conf->map->next = save;
1062 }
1063 }
1064 else
1065 conf->map = add->map ? add->map : base->map;
1066
1067 conf->doctype = (add->doctype == DEFAULT_DOCTYPE)
1068 ? base->doctype : add->doctype;
1069 conf->etag = (add->etag == DEFAULT_ETAG) ? base->etag : add->etag;
1070 conf->bufsz = add->bufsz;
1071 if (add->flags & NORM_RESET) {
1072 conf->flags = add->flags ^ NORM_RESET;
1073 conf->metafix = add->metafix;
1074 conf->extfix = add->extfix;
1075 conf->interp = add->interp;
1076 conf->strip_comments = add->strip_comments;
1077 conf->enabled = add->enabled;
1078 }
1079 else {
1080 conf->flags = base->flags | add->flags;
1081 conf->metafix = base->metafix | add->metafix;
1082 conf->extfix = base->extfix | add->extfix;
1083 conf->interp = base->interp | add->interp;
1084 conf->strip_comments = base->strip_comments | add->strip_comments;
1085 conf->enabled = add->enabled | base->enabled;
1086 }
1087 return conf;
1088}
1089#define REGFLAG(n,s,c) ((s&&(ap_strchr_c((s),(c))!=NULL)) ? (n) : 0)
1090#define XREGFLAG(n,s,c) ((!s||(ap_strchr_c((s),(c))==NULL)) ? (n) : 0)
1091static const char *comp_urlmap(cmd_parms *cmd, urlmap *newmap,
1092 const char *from, const char *to,
1093 const char *flags, const char *cond)
1094{
1095 const char *err = NULL;
1096 newmap->flags
1097 = XREGFLAG(M_HTML,flags,'h')
1098 | XREGFLAG(M_EVENTS,flags,'e')
1099 | XREGFLAG(M_CDATA,flags,'c')
1100 | REGFLAG(M_ATSTART,flags,'^')
1101 | REGFLAG(M_ATEND,flags,'$')
1102 | REGFLAG(M_REGEX,flags,'R')
1103 | REGFLAG(M_LAST,flags,'L')
1104 | REGFLAG(M_NOTLAST,flags,'l')
1107
1108 if ((newmap->flags & M_INTERPOLATE_FROM) || !(newmap->flags & M_REGEX)) {
1109 newmap->from.c = from;
1110 newmap->to = to;
1111 }
1112 else {
1113 newmap->regflags
1118 newmap->from.r = ap_pregcomp(cmd->pool, from, newmap->regflags);
1119 newmap->to = to;
1120 }
1121 if (cond != NULL) {
1122 /* back-compatibility: support old-style ENV expressions
1123 * by converting to ap_expr syntax.
1124 *
1125 * 1. var --> env(var)
1126 * 2. var=val --> env(var)=val
1127 * 3. !var --> !env(var)
1128 * 4. !var=val --> env(var)!=val
1129 */
1130 char *newcond = NULL;
1131 if (ap_rxplus_exec(cmd->temp_pool, old_expr, cond, &newcond)) {
1132 /* we got a substitution. Check for the case (3) above
1133 * that the regexp gets wrong: a negation without a comparison.
1134 */
1135 if ((cond[0] == '!') && !ap_strchr_c(cond, '=')) {
1136 memmove(newcond+1, newcond, strlen(newcond)-1);
1137 newcond[0] = '!';
1138 }
1139 cond = newcond;
1140 }
1141 newmap->cond = ap_expr_parse_cmd(cmd, cond, 0, &err, NULL);
1142 }
1143 else {
1144 newmap->cond = NULL;
1145 }
1146 return err;
1147}
1148
1149static const char *set_urlmap(cmd_parms *cmd, void *CFG, const char *args)
1150{
1152 urlmap *map;
1153 apr_pool_t *pool = cmd->pool;
1154 urlmap *newmap;
1155 const char *usage =
1156 "Usage: ProxyHTMLURLMap from-pattern to-pattern [flags] [cond]";
1157 const char *from;
1158 const char *to;
1159 const char *flags;
1160 const char *cond = NULL;
1161
1162 if (from = ap_getword_conf(cmd->pool, &args), !from)
1163 return usage;
1164 if (to = ap_getword_conf(cmd->pool, &args), !to)
1165 return usage;
1166 flags = ap_getword_conf(cmd->pool, &args);
1167 if (flags && *flags)
1168 cond = ap_getword_conf(cmd->pool, &args);
1169 if (cond && !*cond)
1170 cond = NULL;
1171
1172 /* the args look OK, so let's use them */
1173 newmap = apr_palloc(pool, sizeof(urlmap));
1174 newmap->next = NULL;
1175 if (cfg->map) {
1176 for (map = cfg->map; map->next; map = map->next);
1177 map->next = newmap;
1178 }
1179 else
1180 cfg->map = newmap;
1181
1182 return comp_urlmap(cmd, newmap, from, to, flags, cond);
1183}
1184
1185static const char *set_doctype(cmd_parms *cmd, void *CFG,
1186 const char *t, const char *l)
1187{
1189 if (!strcasecmp(t, "xhtml")) {
1190 cfg->etag = xhtml_etag;
1191 if (l && !strcasecmp(l, "legacy"))
1193 else
1194 cfg->doctype = fpi_xhtml;
1195 }
1196 else if (!strcasecmp(t, "html")) {
1197 cfg->etag = html_etag;
1198 if (l && !strcasecmp(l, "legacy"))
1199 cfg->doctype = fpi_html_legacy;
1200 else
1201 cfg->doctype = fpi_html;
1202 }
1203 else if (!strcasecmp(t, "html5")) {
1204 cfg->etag = html_etag;
1205 cfg->doctype = fpi_html5;
1206 }
1207 else {
1208 cfg->doctype = t;
1209 if (l && ((l[0] == 'x') || (l[0] == 'X')))
1210 cfg->etag = xhtml_etag;
1211 else
1212 cfg->etag = html_etag;
1213 }
1214 return NULL;
1215}
1216
1217static const char *set_flags(cmd_parms *cmd, void *CFG, const char *arg)
1218{
1219 proxy_html_conf *cfg = CFG;
1220 if (arg && *arg) {
1221 if (!strcasecmp(arg, "lowercase"))
1222 cfg->flags |= NORM_LC;
1223 else if (!strcasecmp(arg, "dospath"))
1224 cfg->flags |= NORM_MSSLASH;
1225 else if (!strcasecmp(arg, "reset"))
1226 cfg->flags |= NORM_RESET;
1227 }
1228 return NULL;
1229}
1230
1231static const char *set_events(cmd_parms *cmd, void *CFG, const char *arg)
1232{
1233 tattr *attr;
1234 proxy_html_conf *cfg = CFG;
1235 if (cfg->events == NULL)
1236 cfg->events = apr_array_make(cmd->pool, 20, sizeof(tattr));
1237 attr = apr_array_push(cfg->events);
1238 attr->val = arg;
1239 return NULL;
1240}
1241
1242static const char *set_links(cmd_parms *cmd, void *CFG,
1243 const char *elt, const char *att)
1244{
1246 tattr *attr;
1247 proxy_html_conf *cfg = CFG;
1248
1249 if (cfg->links == NULL)
1250 cfg->links = apr_hash_make(cmd->pool);
1251
1253 if (!attrs) {
1254 attrs = apr_array_make(cmd->pool, 2, sizeof(tattr*));
1256 }
1258 attr->val = att;
1259 return NULL;
1260}
1262 AP_INIT_ITERATE("ProxyHTMLEvents", set_events, NULL,
1264 "Strings to be treated as scripting events"),
1265 AP_INIT_ITERATE2("ProxyHTMLLinks", set_links, NULL,
1266 RSRC_CONF|ACCESS_CONF, "Declare HTML Attributes"),
1267 AP_INIT_RAW_ARGS("ProxyHTMLURLMap", set_urlmap, NULL,
1268 RSRC_CONF|ACCESS_CONF, "Map URL From To"),
1269 AP_INIT_TAKE12("ProxyHTMLDoctype", set_doctype, NULL,
1270 RSRC_CONF|ACCESS_CONF, "(HTML|XHTML) [Legacy]"),
1271 AP_INIT_ITERATE("ProxyHTMLFixups", set_flags, NULL,
1272 RSRC_CONF|ACCESS_CONF, "Options are lowercase, dospath"),
1273 AP_INIT_FLAG("ProxyHTMLMeta", ap_set_flag_slot,
1275 RSRC_CONF|ACCESS_CONF, "Fix META http-equiv elements"),
1276 AP_INIT_FLAG("ProxyHTMLInterp", ap_set_flag_slot,
1277 (void*)APR_OFFSETOF(proxy_html_conf, interp),
1279 "Support interpolation and conditions in URLMaps"),
1280 AP_INIT_FLAG("ProxyHTMLExtended", ap_set_flag_slot,
1281 (void*)APR_OFFSETOF(proxy_html_conf, extfix),
1282 RSRC_CONF|ACCESS_CONF, "Map URLs in Javascript and CSS"),
1283 AP_INIT_FLAG("ProxyHTMLStripComments", ap_set_flag_slot,
1284 (void*)APR_OFFSETOF(proxy_html_conf, strip_comments),
1285 RSRC_CONF|ACCESS_CONF, "Strip out comments"),
1286 AP_INIT_TAKE1("ProxyHTMLBufSize", ap_set_int_slot,
1287 (void*)APR_OFFSETOF(proxy_html_conf, bufsz),
1288 RSRC_CONF|ACCESS_CONF, "Buffer size"),
1289 AP_INIT_TAKE1("ProxyHTMLCharsetOut", ap_set_string_slot,
1290 (void*)APR_OFFSETOF(proxy_html_conf, charset_out),
1291 RSRC_CONF|ACCESS_CONF, "Usage: ProxyHTMLCharsetOut charset"),
1292 AP_INIT_FLAG("ProxyHTMLEnable", ap_set_flag_slot,
1295 "Enable proxy-html and xml2enc filters"),
1296 { NULL }
1297};
1299{
1300 seek_meta = ap_pregcomp(p, "<meta[^>]*(http-equiv)[^>]*>",
1302 seek_content = apr_strmatch_precompile(p, "content", 0);
1303 memset(&sax, 0, sizeof(htmlSAXHandler));
1304 sax.startElement = pstartElement;
1305 sax.endElement = pendElement;
1306 sax.characters = pcharacters;
1307 sax.comment = pcomment;
1308 sax.cdataBlock = pcdata;
1311 if (!xml2enc_charset) {
1313 "I18n support in mod_proxy_html requires mod_xml2enc. "
1314 "Without it, non-ASCII characters in proxied pages are "
1315 "likely to display incorrectly.");
1316 }
1317
1318 /* old_expr only needs to last the life of the config phase */
1319 old_expr = ap_rxplus_compile(p1, "s/^(!)?(\\w+)((=)(.+))?$/reqenv('$2')$1$4'$5'/");
1320 return OK;
1321}
1323{
1324 proxy_html_conf *cfg;
1325 cfg = ap_get_module_config(r->per_dir_config, &proxy_html_module);
1326 if (cfg->enabled) {
1327 if (xml2enc_filter)
1329 ap_add_output_filter("proxy-html", NULL, r, r->connection);
1330 }
1331}
1333{
1334 static const char *aszSucc[] = { "mod_filter.c", NULL };
1338 /* move this to pre_config so old_expr is available to interpret
1339 * old-style conditions on URL maps.
1340 */
1343}
1344
1349 NULL,
1350 NULL,
1353};
Expression parser.
int int const char ** match
Definition ap_regex.h:279
#define AP_REG_ICASE
Definition ap_regex.h:73
const char apr_size_t ap_regmatch_t * pmatch
Definition ap_regex.h:172
#define AP_REG_NOSUB
Definition ap_regex.h:79
const char apr_size_t len
Definition ap_regex.h:187
#define AP_REG_NEWLINE
Definition ap_regex.h:74
const char apr_size_t nmatch
Definition ap_regex.h:172
#define AP_REG_EXTENDED
Definition ap_regex.h:78
static int verbose
Definition abts.c:24
char * strstr(char *s1, char *s2)
APR Hash Tables.
APR general purpose library routines.
APR-UTIL registration of functions exported by modules.
APR Strings library.
APR-UTIL string matching routines.
return found
Definition core.c:2840
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
#define AP_INIT_ITERATE2(directive, func, mconfig, where, help)
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
ap_conf_vector_t * base
#define AP_INIT_ITERATE(directive, func, mconfig, where, help)
const char * ap_set_int_slot(cmd_parms *cmd, void *struct_ptr, const char *arg)
Definition config.c:1480
#define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help)
const char * ap_set_string_slot(cmd_parms *cmd, void *struct_ptr, const char *arg)
Definition config.c:1469
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
#define AP_INIT_TAKE12(directive, func, mconfig, where, help)
const char * ap_set_flag_slot(cmd_parms *cmd, void *struct_ptr, int arg)
Definition config.c:1512
request_rec * r
#define OK
Definition httpd.h:456
#define AP_FILTER_PROTO_CHANGE
apr_status_t ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb)
ap_filter_rec_t * ap_register_output_filter_protocol(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype, unsigned int proto_flags)
#define ap_fputs(f, bb, str)
#define AP_FILTER_PROTO_CHANGE_LENGTH
#define ap_fputc(f, bb, c)
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
ap_filter_t * ap_add_output_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_fputstrs(ap_filter_t *f, apr_bucket_brigade *bb,...)
apr_status_t ap_fprintf(ap_filter_t *f, apr_bucket_brigade *bb, const char *fmt,...) __attribute__((format(printf
void ap_remove_output_filter(ap_filter_t *f)
@ AP_FTYPE_RESOURCE
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_TRACE3
Definition http_log.h:74
#define APLOG_MARK
Definition http_log.h:283
#define ap_log_perror
Definition http_log.h:412
#define APLOGrtrace1(r)
Definition http_log.h:246
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
void ap_set_content_type_ex(request_rec *r, const char *ct, int trusted)
void ap_set_content_type(request_rec *r, const char *ct)
void ap_hook_insert_filter(ap_HOOK_insert_filter_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:96
void const char * arg
Definition http_vhost.h:63
int enabled
apr_file_t * f
#define APR_BUCKET_IS_FLUSH(e)
#define APR_BUCKET_IS_METADATA(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_file_t apr_off_t start
#define APR_BRIGADE_INSERT_HEAD(b, e)
#define APR_BUCKET_NEXT(e)
#define APR_BRIGADE_SENTINEL(b)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
apr_bucket apr_bucket_brigade * a
#define APR_BRIGADE_FIRST(b)
#define apr_bucket_read(e, str, len, block)
int apr_off_t * length
@ APR_BLOCK_READ
Definition apr_buckets.h:58
const char apr_ssize_t int flags
Definition apr_encode.h:168
const char *const const char *const * aszSucc
Definition apr_hooks.h:346
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define apr_strmatch(pattern, s, slen)
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
int ap_expr_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
#define ACCESS_CONF
#define RSRC_CONF
#define STANDARD20_MODULE_STUFF
#define ap_strchr(s, c)
Definition httpd.h:2351
#define ap_strstr_c(s, c)
Definition httpd.h:2361
#define ap_strchr_c(s, c)
Definition httpd.h:2353
char * ap_pregsub(apr_pool_t *p, const char *input, const char *source, apr_size_t nmatch, ap_regmatch_t pmatch[])
Definition util.c:457
int ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
Definition util.c:3559
ap_regex_t * ap_pregcomp(apr_pool_t *p, const char *pattern, int cflags)
Definition util.c:262
char * ap_getword_conf(apr_pool_t *p, const char **line)
Definition util.c:833
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define apr_isspace(c)
Definition apr_lib.h:225
#define apr_isalnum(c)
Definition apr_lib.h:203
#define apr_isalpha(c)
Definition apr_lib.h:205
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
int strcasecmp(const char *a, const char *b)
int strncasecmp(const char *a, const char *b, size_t n)
#define memmove(a, b, c)
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_interval_time_t t
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const void apr_size_t bytes
Definition apr_random.h:91
int to
const char char ** end
const void * m
apr_int32_t apr_int32_t apr_int32_t err
const char const char *const const char *const apr_procattr_t * attr
apr_cmdtype_e cmd
const char const char *const * args
apr_time_t apr_int32_t offs
Definition apr_time.h:142
Apache Configuration.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
static void usage(process_rec *process)
Definition main.c:376
apr_pool_t * p
Definition md_event.c:32
md_subscription * subs
Definition md_event.c:33
static const char * set_flags(cmd_parms *cmd, void *CFG, const char *arg)
static ap_rxplus_t * old_expr
static const char * set_events(cmd_parms *cmd, void *CFG, const char *arg)
static void prepend_rbuf(saxctxt *ctxt, apr_bucket_brigade *bb)
static const char *const html_etag
static void proxy_html_insert(request_rec *r)
static const char * set_links(cmd_parms *cmd, void *CFG, const char *elt, const char *att)
#define AP_fwrite(ctx, inbuf, bytes, flush)
static apr_status_t(* xml2enc_filter)(request_rec *, const char *, unsigned int)
#define XREGFLAG(n, s, c)
#define FLUSH
#define NORM_MSSLASH
static const char * comp_urlmap(cmd_parms *cmd, urlmap *newmap, const char *from, const char *to, const char *flags, const char *cond)
#define VERBOSEB(x)
static void normalise(unsigned int flags, char *str)
static void pcharacters(void *ctxt, const xmlChar *uchars, int length)
static const apr_strmatch_pattern * seek_content
static saxctxt * check_filter_init(ap_filter_t *f)
static const char *const fpi_html5
static void dump_content(saxctxt *ctx)
#define M_INTERPOLATE_FROM
rewrite_t
@ ATTR_EVENT
@ ATTR_IGNORE
@ ATTR_URI
#define M_CDATA
#define NORM_LC
#define M_NOTLAST
static const char *const DEFAULT_DOCTYPE
static const char * set_doctype(cmd_parms *cmd, void *CFG, const char *t, const char *l)
static const char *const fpi_html
#define M_ATSTART
static void pappend(saxctxt *ctx, const char *buf, const size_t len)
static void fixup_rules(saxctxt *ctx)
#define M_REGEX
static const char *const fpi_xhtml_legacy
static apr_status_t(* xml2enc_charset)(request_rec *, xmlCharEncoding *, const char **)
static void proxy_html_hooks(apr_pool_t *p)
#define M_INTERPOLATE_TO
static void * proxy_html_merge(apr_pool_t *pool, void *BASE, void *ADD)
static void pstartElement(void *ctxt, const xmlChar *uname, const xmlChar **uattrs)
#define consume_buffer(ctx, inbuf, bytes, flag)
#define M_EVENTS
#define DEFAULT_ETAG
static htmlSAXHandler sax
#define NORM_RESET
static const char * interpolate_vars(request_rec *r, const char *str)
#define M_HTML
static int mod_proxy_html(apr_pool_t *p, apr_pool_t *p1, apr_pool_t *p2)
#define VERBOSE(x)
static const char * set_urlmap(cmd_parms *cmd, void *CFG, const char *args)
#define M_ATEND
static void pcomment(void *ctxt, const xmlChar *uchars)
static const char *const xhtml_etag
static void pendElement(void *ctxt, const xmlChar *uname)
static meta * metafix(request_rec *r, const char *buf, apr_size_t len)
#define M_LAST
static void pcdata(void *ctxt, const xmlChar *uchars, int length)
static const char *const fpi_xhtml
static const command_rec proxy_html_cmds[]
#define REGFLAG(n, s, c)
static void preserve(saxctxt *ctx, const size_t len)
static const char *const fpi_html_legacy
static ap_regex_t * seek_meta
static void * proxy_html_config(apr_pool_t *pool, char *x)
static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
#define ENCIO_INPUT_CHECKS
Definition mod_xml2enc.h:22
#define ENCIO_OUTPUT
Definition mod_xml2enc.h:21
char * name
The representation of a filter chain.
apr_bucket_alloc_t * bucket_alloc
struct apr_bucket *volatile next
apr_pool_t * pool
unsigned int start
unsigned int end
unsigned int flags
apr_hash_t * links
const char * doctype
const char * charset_out
apr_array_header_t * events
const char * etag
A structure that represents the current request.
Definition httpd.h:845
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
apr_table_t * subprocess_env
Definition httpd.h:983
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
apr_table_t * headers_out
Definition httpd.h:978
proxy_html_conf * cfg
htmlParserCtxtPtr parser
size_t offset
ap_filter_t * f
apr_size_t rmin
const char * encoding
apr_size_t rlen
size_t avail
apr_bucket_brigade * bb
urlmap * map
const char * val
const char * to
struct urlmap * next
unsigned int regflags
const char * c
ap_regex_t * r
union urlmap::@16 from
unsigned int flags
ap_expr_info_t * cond
#define var
#define str
int ap_rxplus_exec(apr_pool_t *pool, ap_rxplus_t *rx, const char *pattern, char **newpattern)
Definition util_regex.c:141
ap_rxplus_t * ap_rxplus_compile(apr_pool_t *pool, const char *pattern)
Definition util_regex.c:31
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray