From 538144cb4fbe448f77936aa474c58a2b04e93948 Mon Sep 17 00:00:00 2001
From: Yann Ylavic <ylavic@apache.org>
Date: Wed, 3 Jan 2018 13:37:50 +0000
Subject: [PATCH] mod_proxy_html: follow up to r1599012.

To determine whether or not HTML data are lower than 4 bytes, use a retain
buffer rather than assuming that all should be contained in a single bucket
with the next one being EOS (if any).



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1819969 13f79535-47bb-0310-9956-ffa450edef68
---
 modules/filters/mod_proxy_html.c | 59 ++++++++++++++++++++++++++------
 1 file changed, 48 insertions(+), 11 deletions(-)

diff --git a/modules/filters/mod_proxy_html.c b/modules/filters/mod_proxy_html.c
index c5cdb54bf7..08c73c4b76 100644
--- a/modules/filters/mod_proxy_html.c
+++ b/modules/filters/mod_proxy_html.c
@@ -109,6 +109,9 @@ typedef struct {
     const char *encoding;
     urlmap *map;
     const char *etag;
+    char rbuf[4];
+    apr_size_t rlen;
+    apr_size_t rmin;
 } saxctxt;
 
 
@@ -873,6 +876,17 @@ static saxctxt *check_filter_init (ap_filter_t *f)
     return f->ctx;
 }
 
+static void prepend_rbuf(saxctxt *ctxt, apr_bucket_brigade *bb)
+{
+    if (ctxt->rlen) {
+        apr_bucket *b = apr_bucket_transient_create(ctxt->rbuf,
+                                                    ctxt->rlen,
+                                                    bb->bucket_alloc);
+        APR_BRIGADE_INSERT_HEAD(bb, b);
+        ctxt->rlen = 0;
+    }
+}
+
 static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 {
     apr_bucket* b;
@@ -894,11 +908,15 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
         if (APR_BUCKET_IS_METADATA(b)) {
             if (APR_BUCKET_IS_EOS(b)) {
                 if (ctxt->parser != NULL) {
-                    consume_buffer(ctxt, buf, 0, 1);
+                    consume_buffer(ctxt, "", 0, 1);
+                }
+                else {
+                    prepend_rbuf(ctxt, ctxt->bb);
                 }
                 APR_BRIGADE_INSERT_TAIL(ctxt->bb,
-                apr_bucket_eos_create(ctxt->bb->bucket_alloc));
+                    apr_bucket_eos_create(ctxt->bb->bucket_alloc));
                 ap_pass_brigade(ctxt->f->next, ctxt->bb);
+                apr_brigade_cleanup(ctxt->bb);
             }
             else if (APR_BUCKET_IS_FLUSH(b)) {
                 /* pass on flush, except at start where it would cause
@@ -918,9 +936,18 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
                  * HTML rewriting. The URL schema (i.e. 'http') needs four bytes alone.
                  * And the HTML parser needs at least four bytes to initialise correctly.
                  */
-                if ((bytes < 4) && APR_BUCKET_IS_EOS(APR_BUCKET_NEXT(b))) {
-                    ap_remove_output_filter(f);
-                    return ap_pass_brigade(f->next, bb);
+                ctxt->rmin += bytes;
+                if (ctxt->rmin < sizeof(ctxt->rbuf)) {
+                    memcpy(ctxt->rbuf + ctxt->rlen, buf, bytes);
+                    ctxt->rlen += bytes;
+                    continue;
+                }
+                if (ctxt->rlen && ctxt->rlen < sizeof(ctxt->rbuf)) {
+                    apr_size_t rem = sizeof(ctxt->rbuf) - ctxt->rlen;
+                    memcpy(ctxt->rbuf + ctxt->rlen, buf, rem);
+                    ctxt->rlen += rem;
+                    buf += rem;
+                    bytes -= rem;
                 }
 
                 if (!xml2enc_charset ||
@@ -949,15 +976,25 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
                 }
 
                 ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
-                ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt, buf,
-                                                        4, 0, enc);
-                buf += 4;
-                bytes -= 4;
+
+                if (ctxt->rlen) {
+                    ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt,
+                                                            ctxt->rbuf,
+                                                            ctxt->rlen,
+                                                            NULL, enc);
+                }
+                else {
+                    ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt, buf, 4,
+                                                            NULL, enc);
+                    buf += 4;
+                    bytes -= 4;
+                }
                 if (ctxt->parser == NULL) {
-                    apr_status_t rv = ap_pass_brigade(f->next, bb);
+                    prepend_rbuf(ctxt, bb);
                     ap_remove_output_filter(f);
-                    return rv;
+                    return ap_pass_brigade(f->next, bb);
                 }
+                ctxt->rlen = 0;
                 apr_pool_cleanup_register(f->r->pool, ctxt->parser,
                                           (int(*)(void*))htmlFreeParserCtxt,
                                           apr_pool_cleanup_null);
-- 
2.40.0