1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* HTTP routines for Apache proxy */
18
19#include "mod_proxy.h"
20#include "ap_regex.h"
21
22module AP_MODULE_DECLARE_DATA proxy_http_module;
23
24static apr_status_t ap_proxy_http_cleanup(const char *scheme,
25                                          request_rec *r,
26                                          proxy_conn_rec *backend);
27
28/*
29 * Canonicalise http-like URLs.
30 *  scheme is the scheme for the URL
31 *  url    is the URL starting with the first '/'
32 *  def_port is the default port for this scheme.
33 */
34static int proxy_http_canon(request_rec *r, char *url)
35{
36    char *host, *path, sport[7];
37    char *search = NULL;
38    const char *err;
39    const char *scheme;
40    apr_port_t port, def_port;
41
42    /* ap_port_of_scheme() */
43    if (strncasecmp(url, "http:", 5) == 0) {
44        url += 5;
45        scheme = "http";
46    }
47    else if (strncasecmp(url, "https:", 6) == 0) {
48        url += 6;
49        scheme = "https";
50    }
51    else {
52        return DECLINED;
53    }
54    def_port = apr_uri_port_of_scheme(scheme);
55
56    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
57             "proxy: HTTP: canonicalising URL %s", url);
58
59    /* do syntatic check.
60     * We break the URL into host, port, path, search
61     */
62    port = def_port;
63    err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
64    if (err) {
65        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
66                      "error parsing URL %s: %s",
67                      url, err);
68        return HTTP_BAD_REQUEST;
69    }
70
71    /*
72     * now parse path/search args, according to rfc1738:
73     * process the path.
74     *
75     * In a reverse proxy, our URL has been processed, so canonicalise
76     * unless proxy-nocanon is set to say it's raw
77     * In a forward proxy, we have and MUST NOT MANGLE the original.
78     */
79    switch (r->proxyreq) {
80    default: /* wtf are we doing here? */
81    case PROXYREQ_REVERSE:
82        if (apr_table_get(r->notes, "proxy-nocanon")) {
83            path = url;   /* this is the raw path */
84        }
85        else {
86            path = ap_proxy_canonenc(r->pool, url, strlen(url),
87                                     enc_path, 0, r->proxyreq);
88            search = r->args;
89        }
90        break;
91    case PROXYREQ_PROXY:
92        path = url;
93        break;
94    }
95
96    if (path == NULL)
97        return HTTP_BAD_REQUEST;
98
99    if (port != def_port)
100        apr_snprintf(sport, sizeof(sport), ":%d", port);
101    else
102        sport[0] = '\0';
103
104    if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
105        host = apr_pstrcat(r->pool, "[", host, "]", NULL);
106    }
107    r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
108            "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
109    return OK;
110}
111
112/* Clear all connection-based headers from the incoming headers table */
113typedef struct header_dptr {
114    apr_pool_t *pool;
115    apr_table_t *table;
116    apr_time_t time;
117} header_dptr;
118static ap_regex_t *warn_rx;
119static int clean_warning_headers(void *data, const char *key, const char *val)
120{
121    apr_table_t *headers = ((header_dptr*)data)->table;
122    apr_pool_t *pool = ((header_dptr*)data)->pool;
123    char *warning;
124    char *date;
125    apr_time_t warn_time;
126    const int nmatch = 3;
127    ap_regmatch_t pmatch[3];
128
129    if (headers == NULL) {
130        ((header_dptr*)data)->table = headers = apr_table_make(pool, 2);
131    }
132/*
133 * Parse this, suckers!
134 *
135 *    Warning    = "Warning" ":" 1#warning-value
136 *
137 *    warning-value = warn-code SP warn-agent SP warn-text
138 *                                             [SP warn-date]
139 *
140 *    warn-code  = 3DIGIT
141 *    warn-agent = ( host [ ":" port ] ) | pseudonym
142 *                    ; the name or pseudonym of the server adding
143 *                    ; the Warning header, for use in debugging
144 *    warn-text  = quoted-string
145 *    warn-date  = <"> HTTP-date <">
146 *
147 * Buggrit, use a bloomin' regexp!
148 * (\d{3}\s+\S+\s+\".*?\"(\s+\"(.*?)\")?)  --> whole in $1, date in $3
149 */
150    while (!ap_regexec(warn_rx, val, nmatch, pmatch, 0)) {
151        warning = apr_pstrndup(pool, val+pmatch[0].rm_so,
152                               pmatch[0].rm_eo - pmatch[0].rm_so);
153        warn_time = 0;
154        if (pmatch[2].rm_eo > pmatch[2].rm_so) {
155            /* OK, we have a date here */
156            date = apr_pstrndup(pool, val+pmatch[2].rm_so,
157                                pmatch[2].rm_eo - pmatch[2].rm_so);
158            warn_time = apr_date_parse_http(date);
159        }
160        if (!warn_time || (warn_time == ((header_dptr*)data)->time)) {
161            apr_table_addn(headers, key, warning);
162        }
163        val += pmatch[0].rm_eo;
164    }
165    return 1;
166}
167static apr_table_t *ap_proxy_clean_warnings(apr_pool_t *p, apr_table_t *headers)
168{
169   header_dptr x;
170   x.pool = p;
171   x.table = NULL;
172   x.time = apr_date_parse_http(apr_table_get(headers, "Date"));
173   apr_table_do(clean_warning_headers, &x, headers, "Warning", NULL);
174   if (x.table != NULL) {
175       apr_table_unset(headers, "Warning");
176       return apr_table_overlay(p, headers, x.table);
177   }
178   else {
179        return headers;
180   }
181}
182static int clear_conn_headers(void *data, const char *key, const char *val)
183{
184    apr_table_t *headers = ((header_dptr*)data)->table;
185    apr_pool_t *pool = ((header_dptr*)data)->pool;
186    const char *name;
187    char *next = apr_pstrdup(pool, val);
188    while (*next) {
189        name = next;
190        while (*next && !apr_isspace(*next) && (*next != ',')) {
191            ++next;
192        }
193        while (*next && (apr_isspace(*next) || (*next == ','))) {
194            *next++ = '\0';
195        }
196        apr_table_unset(headers, name);
197    }
198    return 1;
199}
200static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
201{
202    header_dptr x;
203    x.pool = p;
204    x.table = headers;
205    apr_table_unset(headers, "Proxy-Connection");
206    apr_table_do(clear_conn_headers, &x, headers, "Connection", NULL);
207    apr_table_unset(headers, "Connection");
208}
209static void add_te_chunked(apr_pool_t *p,
210                           apr_bucket_alloc_t *bucket_alloc,
211                           apr_bucket_brigade *header_brigade)
212{
213    apr_bucket *e;
214    char *buf;
215    const char te_hdr[] = "Transfer-Encoding: chunked" CRLF;
216
217    buf = apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1);
218    ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1);
219
220    e = apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, bucket_alloc);
221    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
222}
223
224static void add_cl(apr_pool_t *p,
225                   apr_bucket_alloc_t *bucket_alloc,
226                   apr_bucket_brigade *header_brigade,
227                   const char *cl_val)
228{
229    apr_bucket *e;
230    char *buf;
231
232    buf = apr_pstrcat(p, "Content-Length: ",
233                      cl_val,
234                      CRLF,
235                      NULL);
236    ap_xlate_proto_to_ascii(buf, strlen(buf));
237    e = apr_bucket_pool_create(buf, strlen(buf), p, bucket_alloc);
238    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
239}
240
241#define ASCII_CRLF  "\015\012"
242#define ASCII_ZERO  "\060"
243
244static void terminate_headers(apr_bucket_alloc_t *bucket_alloc,
245                              apr_bucket_brigade *header_brigade)
246{
247    apr_bucket *e;
248
249    /* add empty line at the end of the headers */
250    e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc);
251    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
252}
253
254static int pass_brigade(apr_bucket_alloc_t *bucket_alloc,
255                                 request_rec *r, proxy_conn_rec *conn,
256                                 conn_rec *origin, apr_bucket_brigade *bb,
257                                 int flush)
258{
259    apr_status_t status;
260    apr_off_t transferred;
261
262    if (flush) {
263        apr_bucket *e = apr_bucket_flush_create(bucket_alloc);
264        APR_BRIGADE_INSERT_TAIL(bb, e);
265    }
266    apr_brigade_length(bb, 0, &transferred);
267    if (transferred != -1)
268        conn->worker->s->transferred += transferred;
269    status = ap_pass_brigade(origin->output_filters, bb);
270    if (status != APR_SUCCESS) {
271        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
272                     "proxy: pass request body failed to %pI (%s)",
273                     conn->addr, conn->hostname);
274        if (origin->aborted) {
275            const char *ssl_note;
276
277            if (((ssl_note = apr_table_get(origin->notes, "SSL_connect_rv"))
278                != NULL) && (strcmp(ssl_note, "err") == 0)) {
279                return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
280                                     "Error during SSL Handshake with"
281                                     " remote server");
282            }
283            return APR_STATUS_IS_TIMEUP(status) ? HTTP_GATEWAY_TIME_OUT : HTTP_BAD_GATEWAY;
284        }
285        else {
286            return HTTP_BAD_REQUEST;
287        }
288    }
289    apr_brigade_cleanup(bb);
290    return OK;
291}
292
293#define MAX_MEM_SPOOL 16384
294
295static int stream_reqbody_chunked(apr_pool_t *p,
296                                           request_rec *r,
297                                           proxy_conn_rec *p_conn,
298                                           conn_rec *origin,
299                                           apr_bucket_brigade *header_brigade,
300                                           apr_bucket_brigade *input_brigade)
301{
302    int seen_eos = 0, rv = OK;
303    apr_size_t hdr_len;
304    apr_off_t bytes;
305    apr_status_t status;
306    apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
307    apr_bucket_brigade *bb;
308    apr_bucket *e;
309
310    add_te_chunked(p, bucket_alloc, header_brigade);
311    terminate_headers(bucket_alloc, header_brigade);
312
313    while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
314    {
315        char chunk_hdr[20];  /* must be here due to transient bucket. */
316
317        /* If this brigade contains EOS, either stop or remove it. */
318        if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
319            seen_eos = 1;
320
321            /* We can't pass this EOS to the output_filters. */
322            e = APR_BRIGADE_LAST(input_brigade);
323            apr_bucket_delete(e);
324        }
325
326        apr_brigade_length(input_brigade, 1, &bytes);
327
328        hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
329                               "%" APR_UINT64_T_HEX_FMT CRLF,
330                               (apr_uint64_t)bytes);
331
332        ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
333        e = apr_bucket_transient_create(chunk_hdr, hdr_len,
334                                        bucket_alloc);
335        APR_BRIGADE_INSERT_HEAD(input_brigade, e);
336
337        /*
338         * Append the end-of-chunk CRLF
339         */
340        e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc);
341        APR_BRIGADE_INSERT_TAIL(input_brigade, e);
342
343        if (header_brigade) {
344            /* we never sent the header brigade, so go ahead and
345             * take care of that now
346             */
347            bb = header_brigade;
348
349            /*
350             * Save input_brigade in bb brigade. (At least) in the SSL case
351             * input_brigade contains transient buckets whose data would get
352             * overwritten during the next call of ap_get_brigade in the loop.
353             * ap_save_brigade ensures these buckets to be set aside.
354             * Calling ap_save_brigade with NULL as filter is OK, because
355             * bb brigade already has been created and does not need to get
356             * created by ap_save_brigade.
357             */
358            status = ap_save_brigade(NULL, &bb, &input_brigade, p);
359            if (status != APR_SUCCESS) {
360                return HTTP_INTERNAL_SERVER_ERROR;
361            }
362
363            header_brigade = NULL;
364        }
365        else {
366            bb = input_brigade;
367        }
368
369        /* The request is flushed below this loop with chunk EOS header */
370        rv = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 0);
371        if (rv != OK) {
372            return rv;
373        }
374
375        if (seen_eos) {
376            break;
377        }
378
379        status = ap_get_brigade(r->input_filters, input_brigade,
380                                AP_MODE_READBYTES, APR_BLOCK_READ,
381                                HUGE_STRING_LEN);
382
383        if (status != APR_SUCCESS) {
384            return HTTP_BAD_REQUEST;
385        }
386    }
387
388    if (header_brigade) {
389        /* we never sent the header brigade because there was no request body;
390         * send it now
391         */
392        bb = header_brigade;
393    }
394    else {
395        if (!APR_BRIGADE_EMPTY(input_brigade)) {
396            /* input brigade still has an EOS which we can't pass to the output_filters. */
397            e = APR_BRIGADE_LAST(input_brigade);
398            AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(e));
399            apr_bucket_delete(e);
400        }
401        bb = input_brigade;
402    }
403
404    e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
405                                   /* <trailers> */
406                                   ASCII_CRLF,
407                                   5, bucket_alloc);
408    APR_BRIGADE_INSERT_TAIL(bb, e);
409
410    /* Now we have headers-only, or the chunk EOS mark; flush it */
411    rv = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1);
412    return rv;
413}
414
415static int stream_reqbody_cl(apr_pool_t *p,
416                                      request_rec *r,
417                                      proxy_conn_rec *p_conn,
418                                      conn_rec *origin,
419                                      apr_bucket_brigade *header_brigade,
420                                      apr_bucket_brigade *input_brigade,
421                                      const char *old_cl_val)
422{
423    int seen_eos = 0, rv = 0;
424    apr_status_t status = APR_SUCCESS;
425    apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
426    apr_bucket_brigade *bb;
427    apr_bucket *e;
428    apr_off_t cl_val = 0;
429    apr_off_t bytes;
430    apr_off_t bytes_streamed = 0;
431
432    if (old_cl_val) {
433        char *endstr;
434
435        add_cl(p, bucket_alloc, header_brigade, old_cl_val);
436        status = apr_strtoff(&cl_val, old_cl_val, &endstr, 10);
437
438        if (status || *endstr || endstr == old_cl_val || cl_val < 0) {
439            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
440                          "proxy: could not parse request Content-Length (%s)",
441                          old_cl_val);
442            return HTTP_BAD_REQUEST;
443        }
444    }
445    terminate_headers(bucket_alloc, header_brigade);
446
447    while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
448    {
449        apr_brigade_length(input_brigade, 1, &bytes);
450        bytes_streamed += bytes;
451
452        /* If this brigade contains EOS, either stop or remove it. */
453        if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
454            seen_eos = 1;
455
456            /* We can't pass this EOS to the output_filters. */
457            e = APR_BRIGADE_LAST(input_brigade);
458            apr_bucket_delete(e);
459        }
460
461        /* C-L < bytes streamed?!?
462         * We will error out after the body is completely
463         * consumed, but we can't stream more bytes at the
464         * back end since they would in part be interpreted
465         * as another request!  If nothing is sent, then
466         * just send nothing.
467         *
468         * Prevents HTTP Response Splitting.
469         */
470        if (bytes_streamed > cl_val) {
471            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
472                          "proxy: read more bytes of request body than expected "
473                          "(got %" APR_OFF_T_FMT ", expected %" APR_OFF_T_FMT ")",
474                          bytes_streamed, cl_val);
475            return HTTP_INTERNAL_SERVER_ERROR;
476        }
477
478        if (header_brigade) {
479            /* we never sent the header brigade, so go ahead and
480             * take care of that now
481             */
482            bb = header_brigade;
483
484            /*
485             * Save input_brigade in bb brigade. (At least) in the SSL case
486             * input_brigade contains transient buckets whose data would get
487             * overwritten during the next call of ap_get_brigade in the loop.
488             * ap_save_brigade ensures these buckets to be set aside.
489             * Calling ap_save_brigade with NULL as filter is OK, because
490             * bb brigade already has been created and does not need to get
491             * created by ap_save_brigade.
492             */
493            status = ap_save_brigade(NULL, &bb, &input_brigade, p);
494            if (status != APR_SUCCESS) {
495                return HTTP_INTERNAL_SERVER_ERROR;
496            }
497
498            header_brigade = NULL;
499        }
500        else {
501            bb = input_brigade;
502        }
503
504        /* Once we hit EOS, we are ready to flush. */
505        rv = pass_brigade(bucket_alloc, r, p_conn, origin, bb, seen_eos);
506        if (rv != OK) {
507            return rv ;
508        }
509
510        if (seen_eos) {
511            break;
512        }
513
514        status = ap_get_brigade(r->input_filters, input_brigade,
515                                AP_MODE_READBYTES, APR_BLOCK_READ,
516                                HUGE_STRING_LEN);
517
518        if (status != APR_SUCCESS) {
519            return HTTP_BAD_REQUEST;
520        }
521    }
522
523    if (bytes_streamed != cl_val) {
524        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
525                     "proxy: client %s given Content-Length did not match"
526                     " number of body bytes read", r->connection->remote_ip);
527        return HTTP_BAD_REQUEST;
528    }
529
530    if (header_brigade) {
531        /* we never sent the header brigade since there was no request
532         * body; send it now with the flush flag
533         */
534        bb = header_brigade;
535        return(pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1));
536    }
537
538    return OK;
539}
540
541static int spool_reqbody_cl(apr_pool_t *p,
542                                     request_rec *r,
543                                     proxy_conn_rec *p_conn,
544                                     conn_rec *origin,
545                                     apr_bucket_brigade *header_brigade,
546                                     apr_bucket_brigade *input_brigade,
547                                     int force_cl)
548{
549    int seen_eos = 0;
550    apr_status_t status;
551    apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
552    apr_bucket_brigade *body_brigade;
553    apr_bucket *e;
554    apr_off_t bytes, bytes_spooled = 0, fsize = 0;
555    apr_file_t *tmpfile = NULL;
556
557    body_brigade = apr_brigade_create(p, bucket_alloc);
558
559    while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
560    {
561        /* If this brigade contains EOS, either stop or remove it. */
562        if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
563            seen_eos = 1;
564
565            /* We can't pass this EOS to the output_filters. */
566            e = APR_BRIGADE_LAST(input_brigade);
567            apr_bucket_delete(e);
568        }
569
570        apr_brigade_length(input_brigade, 1, &bytes);
571
572        if (bytes_spooled + bytes > MAX_MEM_SPOOL) {
573            /* can't spool any more in memory; write latest brigade to disk */
574            if (tmpfile == NULL) {
575                const char *temp_dir;
576                char *template;
577
578                status = apr_temp_dir_get(&temp_dir, p);
579                if (status != APR_SUCCESS) {
580                    ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
581                                 "proxy: search for temporary directory failed");
582                    return HTTP_INTERNAL_SERVER_ERROR;
583                }
584                apr_filepath_merge(&template, temp_dir,
585                                   "modproxy.tmp.XXXXXX",
586                                   APR_FILEPATH_NATIVE, p);
587                status = apr_file_mktemp(&tmpfile, template, 0, p);
588                if (status != APR_SUCCESS) {
589                    ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
590                                 "proxy: creation of temporary file in directory %s failed",
591                                 temp_dir);
592                    return HTTP_INTERNAL_SERVER_ERROR;
593                }
594            }
595            for (e = APR_BRIGADE_FIRST(input_brigade);
596                 e != APR_BRIGADE_SENTINEL(input_brigade);
597                 e = APR_BUCKET_NEXT(e)) {
598                const char *data;
599                apr_size_t bytes_read, bytes_written;
600
601                apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ);
602                status = apr_file_write_full(tmpfile, data, bytes_read, &bytes_written);
603                if (status != APR_SUCCESS) {
604                    const char *tmpfile_name;
605
606                    if (apr_file_name_get(&tmpfile_name, tmpfile) != APR_SUCCESS) {
607                        tmpfile_name = "(unknown)";
608                    }
609                    ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
610                                 "proxy: write to temporary file %s failed",
611                                 tmpfile_name);
612                    return HTTP_INTERNAL_SERVER_ERROR;
613                }
614                AP_DEBUG_ASSERT(bytes_read == bytes_written);
615                fsize += bytes_written;
616            }
617            apr_brigade_cleanup(input_brigade);
618        }
619        else {
620
621            /*
622             * Save input_brigade in body_brigade. (At least) in the SSL case
623             * input_brigade contains transient buckets whose data would get
624             * overwritten during the next call of ap_get_brigade in the loop.
625             * ap_save_brigade ensures these buckets to be set aside.
626             * Calling ap_save_brigade with NULL as filter is OK, because
627             * body_brigade already has been created and does not need to get
628             * created by ap_save_brigade.
629             */
630            status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p);
631            if (status != APR_SUCCESS) {
632                return HTTP_INTERNAL_SERVER_ERROR;
633            }
634
635        }
636
637        bytes_spooled += bytes;
638
639        if (seen_eos) {
640            break;
641        }
642
643        status = ap_get_brigade(r->input_filters, input_brigade,
644                                AP_MODE_READBYTES, APR_BLOCK_READ,
645                                HUGE_STRING_LEN);
646
647        if (status != APR_SUCCESS) {
648            return HTTP_BAD_REQUEST;
649        }
650    }
651
652    if (bytes_spooled || force_cl) {
653        add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes_spooled));
654    }
655    terminate_headers(bucket_alloc, header_brigade);
656    APR_BRIGADE_CONCAT(header_brigade, body_brigade);
657    if (tmpfile) {
658        /* For platforms where the size of the file may be larger than
659         * that which can be stored in a single bucket (where the
660         * length field is an apr_size_t), split it into several
661         * buckets: */
662        if (sizeof(apr_off_t) > sizeof(apr_size_t)
663            && fsize > AP_MAX_SENDFILE) {
664            e = apr_bucket_file_create(tmpfile, 0, AP_MAX_SENDFILE, p,
665                                       bucket_alloc);
666            while (fsize > AP_MAX_SENDFILE) {
667                apr_bucket *ce;
668                apr_bucket_copy(e, &ce);
669                APR_BRIGADE_INSERT_TAIL(header_brigade, ce);
670                e->start += AP_MAX_SENDFILE;
671                fsize -= AP_MAX_SENDFILE;
672            }
673            e->length = (apr_size_t)fsize; /* Resize just the last bucket */
674        }
675        else {
676            e = apr_bucket_file_create(tmpfile, 0, (apr_size_t)fsize, p,
677                                       bucket_alloc);
678        }
679        APR_BRIGADE_INSERT_TAIL(header_brigade, e);
680    }
681    /* This is all a single brigade, pass with flush flagged */
682    return(pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1));
683}
684
685static
686int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
687                                   proxy_conn_rec *p_conn, conn_rec *origin,
688                                   proxy_server_conf *conf,
689                                   apr_uri_t *uri,
690                                   char *url, char *server_portstr)
691{
692    conn_rec *c = r->connection;
693    apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc;
694    apr_bucket_brigade *header_brigade;
695    apr_bucket_brigade *input_brigade;
696    apr_bucket_brigade *temp_brigade;
697    apr_bucket *e;
698    char *buf;
699    const apr_array_header_t *headers_in_array;
700    const apr_table_entry_t *headers_in;
701    int counter;
702    apr_status_t status;
703    enum rb_methods {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL};
704    enum rb_methods rb_method = RB_INIT;
705    const char *old_cl_val = NULL;
706    const char *old_te_val = NULL;
707    apr_off_t bytes_read = 0;
708    apr_off_t bytes;
709    int force10, rv;
710    apr_table_t *headers_in_copy;
711
712    header_brigade = apr_brigade_create(p, origin->bucket_alloc);
713
714    /*
715     * Send the HTTP/1.1 request to the remote server
716     */
717
718    if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
719        buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
720        force10 = 1;
721        /*
722         * According to RFC 2616 8.2.3 we are not allowed to forward an
723         * Expect: 100-continue to an HTTP/1.0 server. Instead we MUST return
724         * a HTTP_EXPECTATION_FAILED
725         */
726        if (r->expecting_100) {
727            return HTTP_EXPECTATION_FAILED;
728        }
729        p_conn->close++;
730    } else {
731        buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
732        force10 = 0;
733    }
734    if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
735        origin->keepalive = AP_CONN_CLOSE;
736        p_conn->close++;
737    }
738    ap_xlate_proto_to_ascii(buf, strlen(buf));
739    e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
740    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
741    if (conf->preserve_host == 0) {
742        if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
743            if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
744                buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:",
745                                  uri->port_str, CRLF, NULL);
746            } else {
747                buf = apr_pstrcat(p, "Host: [", uri->hostname, "]", CRLF, NULL);
748            }
749        } else {
750            if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
751                buf = apr_pstrcat(p, "Host: ", uri->hostname, ":",
752                                  uri->port_str, CRLF, NULL);
753            } else {
754                buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
755            }
756        }
757    }
758    else {
759        /* don't want to use r->hostname, as the incoming header might have a
760         * port attached
761         */
762        const char* hostname = apr_table_get(r->headers_in,"Host");
763        if (!hostname) {
764            hostname =  r->server->server_hostname;
765            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
766                          "proxy: no HTTP 0.9 request (with no host line) "
767                          "on incoming request and preserve host set "
768                          "forcing hostname to be %s for uri %s",
769                          hostname,
770                          r->uri );
771        }
772        buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL);
773    }
774    ap_xlate_proto_to_ascii(buf, strlen(buf));
775    e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
776    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
777
778    /* handle Via */
779    if (conf->viaopt == via_block) {
780        /* Block all outgoing Via: headers */
781        apr_table_unset(r->headers_in, "Via");
782    } else if (conf->viaopt != via_off) {
783        const char *server_name = ap_get_server_name(r);
784        /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
785         * then the server name returned by ap_get_server_name() is the
786         * origin server name (which does make too much sense with Via: headers)
787         * so we use the proxy vhost's name instead.
788         */
789        if (server_name == r->hostname)
790            server_name = r->server->server_hostname;
791        /* Create a "Via:" request header entry and merge it */
792        /* Generate outgoing Via: header with/without server comment: */
793        apr_table_mergen(r->headers_in, "Via",
794                         (conf->viaopt == via_full)
795                         ? apr_psprintf(p, "%d.%d %s%s (%s)",
796                                        HTTP_VERSION_MAJOR(r->proto_num),
797                                        HTTP_VERSION_MINOR(r->proto_num),
798                                        server_name, server_portstr,
799                                        AP_SERVER_BASEVERSION)
800                         : apr_psprintf(p, "%d.%d %s%s",
801                                        HTTP_VERSION_MAJOR(r->proto_num),
802                                        HTTP_VERSION_MINOR(r->proto_num),
803                                        server_name, server_portstr)
804        );
805    }
806
807    /* X-Forwarded-*: handling
808     *
809     * XXX Privacy Note:
810     * -----------------
811     *
812     * These request headers are only really useful when the mod_proxy
813     * is used in a reverse proxy configuration, so that useful info
814     * about the client can be passed through the reverse proxy and on
815     * to the backend server, which may require the information to
816     * function properly.
817     *
818     * In a forward proxy situation, these options are a potential
819     * privacy violation, as information about clients behind the proxy
820     * are revealed to arbitrary servers out there on the internet.
821     *
822     * The HTTP/1.1 Via: header is designed for passing client
823     * information through proxies to a server, and should be used in
824     * a forward proxy configuation instead of X-Forwarded-*. See the
825     * ProxyVia option for details.
826     */
827
828    if (PROXYREQ_REVERSE == r->proxyreq) {
829        const char *buf;
830
831        /* Add X-Forwarded-For: so that the upstream has a chance to
832         * determine, where the original request came from.
833         */
834        apr_table_mergen(r->headers_in, "X-Forwarded-For",
835                         c->remote_ip);
836
837        /* Add X-Forwarded-Host: so that upstream knows what the
838         * original request hostname was.
839         */
840        if ((buf = apr_table_get(r->headers_in, "Host"))) {
841            apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
842        }
843
844        /* Add X-Forwarded-Server: so that upstream knows what the
845         * name of this proxy server is (if there are more than one)
846         * XXX: This duplicates Via: - do we strictly need it?
847         */
848        apr_table_mergen(r->headers_in, "X-Forwarded-Server",
849                         r->server->server_hostname);
850    }
851
852    proxy_run_fixups(r);
853    /*
854     * Make a copy of the headers_in table before clearing the connection
855     * headers as we need the connection headers later in the http output
856     * filter to prepare the correct response headers.
857     *
858     * Note: We need to take r->pool for apr_table_copy as the key / value
859     * pairs in r->headers_in have been created out of r->pool and
860     * p might be (and actually is) a longer living pool.
861     * This would trigger the bad pool ancestry abort in apr_table_copy if
862     * apr is compiled with APR_POOL_DEBUG.
863     */
864    headers_in_copy = apr_table_copy(r->pool, r->headers_in);
865    ap_proxy_clear_connection(p, headers_in_copy);
866    /* send request headers */
867    headers_in_array = apr_table_elts(headers_in_copy);
868    headers_in = (const apr_table_entry_t *) headers_in_array->elts;
869    for (counter = 0; counter < headers_in_array->nelts; counter++) {
870        if (headers_in[counter].key == NULL
871             || headers_in[counter].val == NULL
872
873            /* Already sent */
874             || !strcasecmp(headers_in[counter].key, "Host")
875
876            /* Clear out hop-by-hop request headers not to send
877             * RFC2616 13.5.1 says we should strip these headers
878             */
879             || !strcasecmp(headers_in[counter].key, "Keep-Alive")
880             || !strcasecmp(headers_in[counter].key, "TE")
881             || !strcasecmp(headers_in[counter].key, "Trailer")
882             || !strcasecmp(headers_in[counter].key, "Upgrade")
883
884             ) {
885            continue;
886        }
887        /* Do we want to strip Proxy-Authorization ?
888         * If we haven't used it, then NO
889         * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
890         * So let's make it configurable by env.
891         */
892        if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) {
893            if (r->user != NULL) { /* we've authenticated */
894                if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
895                    continue;
896                }
897            }
898        }
899
900        /* Skip Transfer-Encoding and Content-Length for now.
901         */
902        if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
903            old_te_val = headers_in[counter].val;
904            continue;
905        }
906        if (!strcasecmp(headers_in[counter].key, "Content-Length")) {
907            old_cl_val = headers_in[counter].val;
908            continue;
909        }
910
911        /* for sub-requests, ignore freshness/expiry headers */
912        if (r->main) {
913            if (    !strcasecmp(headers_in[counter].key, "If-Match")
914                 || !strcasecmp(headers_in[counter].key, "If-Modified-Since")
915                 || !strcasecmp(headers_in[counter].key, "If-Range")
916                 || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
917                 || !strcasecmp(headers_in[counter].key, "If-None-Match")) {
918                continue;
919            }
920        }
921
922        buf = apr_pstrcat(p, headers_in[counter].key, ": ",
923                          headers_in[counter].val, CRLF,
924                          NULL);
925        ap_xlate_proto_to_ascii(buf, strlen(buf));
926        e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
927        APR_BRIGADE_INSERT_TAIL(header_brigade, e);
928    }
929
930    /* We have headers, let's figure out our request body... */
931    input_brigade = apr_brigade_create(p, bucket_alloc);
932
933    /* sub-requests never use keepalives, and mustn't pass request bodies.
934     * Because the new logic looks at input_brigade, we will self-terminate
935     * input_brigade and jump past all of the request body logic...
936     * Reading anything with ap_get_brigade is likely to consume the
937     * main request's body or read beyond EOS - which would be unplesant.
938     */
939    if (r->main) {
940        /* XXX: Why DON'T sub-requests use keepalives? */
941        p_conn->close++;
942        if (old_cl_val) {
943            old_cl_val = NULL;
944            apr_table_unset(r->headers_in, "Content-Length");
945        }
946        if (old_te_val) {
947            old_te_val = NULL;
948            apr_table_unset(r->headers_in, "Transfer-Encoding");
949        }
950        rb_method = RB_STREAM_CL;
951        e = apr_bucket_eos_create(input_brigade->bucket_alloc);
952        APR_BRIGADE_INSERT_TAIL(input_brigade, e);
953        goto skip_body;
954    }
955
956    /* WE only understand chunked.  Other modules might inject
957     * (and therefore, decode) other flavors but we don't know
958     * that the can and have done so unless they they remove
959     * their decoding from the headers_in T-E list.
960     * XXX: Make this extensible, but in doing so, presume the
961     * encoding has been done by the extensions' handler, and
962     * do not modify add_te_chunked's logic
963     */
964    if (old_te_val && strcasecmp(old_te_val, "chunked") != 0) {
965        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
966                     "proxy: %s Transfer-Encoding is not supported",
967                     old_te_val);
968        return HTTP_INTERNAL_SERVER_ERROR;
969    }
970
971    if (old_cl_val && old_te_val) {
972        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_ENOTIMPL, r->server,
973                     "proxy: client %s (%s) requested Transfer-Encoding "
974                     "chunked body with Content-Length (C-L ignored)",
975                     c->remote_ip, c->remote_host ? c->remote_host: "");
976        apr_table_unset(r->headers_in, "Content-Length");
977        old_cl_val = NULL;
978        origin->keepalive = AP_CONN_CLOSE;
979        p_conn->close++;
980    }
981
982    /* Prefetch MAX_MEM_SPOOL bytes
983     *
984     * This helps us avoid any election of C-L v.s. T-E
985     * request bodies, since we are willing to keep in
986     * memory this much data, in any case.  This gives
987     * us an instant C-L election if the body is of some
988     * reasonable size.
989     */
990    temp_brigade = apr_brigade_create(p, bucket_alloc);
991    do {
992        status = ap_get_brigade(r->input_filters, temp_brigade,
993                                AP_MODE_READBYTES, APR_BLOCK_READ,
994                                MAX_MEM_SPOOL - bytes_read);
995        if (status != APR_SUCCESS) {
996            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
997                         "proxy: prefetch request body failed to %pI (%s)"
998                         " from %s (%s)",
999                         p_conn->addr, p_conn->hostname ? p_conn->hostname: "",
1000                         c->remote_ip, c->remote_host ? c->remote_host: "");
1001            return HTTP_BAD_REQUEST;
1002        }
1003
1004        apr_brigade_length(temp_brigade, 1, &bytes);
1005        bytes_read += bytes;
1006
1007        /*
1008         * Save temp_brigade in input_brigade. (At least) in the SSL case
1009         * temp_brigade contains transient buckets whose data would get
1010         * overwritten during the next call of ap_get_brigade in the loop.
1011         * ap_save_brigade ensures these buckets to be set aside.
1012         * Calling ap_save_brigade with NULL as filter is OK, because
1013         * input_brigade already has been created and does not need to get
1014         * created by ap_save_brigade.
1015         */
1016        status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p);
1017        if (status != APR_SUCCESS) {
1018            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
1019                         "proxy: processing prefetched request body failed"
1020                         " to %pI (%s) from %s (%s)",
1021                         p_conn->addr, p_conn->hostname ? p_conn->hostname: "",
1022                         c->remote_ip, c->remote_host ? c->remote_host: "");
1023            return HTTP_INTERNAL_SERVER_ERROR;
1024        }
1025
1026    /* Ensure we don't hit a wall where we have a buffer too small
1027     * for ap_get_brigade's filters to fetch us another bucket,
1028     * surrender once we hit 80 bytes less than MAX_MEM_SPOOL
1029     * (an arbitrary value.)
1030     */
1031    } while ((bytes_read < MAX_MEM_SPOOL - 80)
1032              && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)));
1033
1034    /* Use chunked request body encoding or send a content-length body?
1035     *
1036     * Prefer C-L when:
1037     *
1038     *   We have no request body (handled by RB_STREAM_CL)
1039     *
1040     *   We have a request body length <= MAX_MEM_SPOOL
1041     *
1042     *   The administrator has setenv force-proxy-request-1.0
1043     *
1044     *   The client sent a C-L body, and the administrator has
1045     *   not setenv proxy-sendchunked or has set setenv proxy-sendcl
1046     *
1047     *   The client sent a T-E body, and the administrator has
1048     *   setenv proxy-sendcl, and not setenv proxy-sendchunked
1049     *
1050     * If both proxy-sendcl and proxy-sendchunked are set, the
1051     * behavior is the same as if neither were set, large bodies
1052     * that can't be read will be forwarded in their original
1053     * form of C-L, or T-E.
1054     *
1055     * To ensure maximum compatibility, setenv proxy-sendcl
1056     * To reduce server resource use,   setenv proxy-sendchunked
1057     *
1058     * Then address specific servers with conditional setenv
1059     * options to restore the default behavior where desireable.
1060     *
1061     * We have to compute content length by reading the entire request
1062     * body; if request body is not small, we'll spool the remaining
1063     * input to a temporary file.  Chunked is always preferable.
1064     *
1065     * We can only trust the client-provided C-L if the T-E header
1066     * is absent, and the filters are unchanged (the body won't
1067     * be resized by another content filter).
1068     */
1069    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
1070        /* The whole thing fit, so our decision is trivial, use
1071         * the filtered bytes read from the client for the request
1072         * body Content-Length.
1073         *
1074         * If we expected no body, and read no body, do not set
1075         * the Content-Length.
1076         */
1077        if (old_cl_val || old_te_val || bytes_read) {
1078            old_cl_val = apr_off_t_toa(r->pool, bytes_read);
1079        }
1080        rb_method = RB_STREAM_CL;
1081    }
1082    else if (old_te_val) {
1083        if (force10
1084             || (apr_table_get(r->subprocess_env, "proxy-sendcl")
1085                  && !apr_table_get(r->subprocess_env, "proxy-sendchunks")
1086                  && !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) {
1087            rb_method = RB_SPOOL_CL;
1088        }
1089        else {
1090            rb_method = RB_STREAM_CHUNKED;
1091        }
1092    }
1093    else if (old_cl_val) {
1094        if (r->input_filters == r->proto_input_filters) {
1095            rb_method = RB_STREAM_CL;
1096        }
1097        else if (!force10
1098                  && (apr_table_get(r->subprocess_env, "proxy-sendchunks")
1099                      || apr_table_get(r->subprocess_env, "proxy-sendchunked"))
1100                  && !apr_table_get(r->subprocess_env, "proxy-sendcl")) {
1101            rb_method = RB_STREAM_CHUNKED;
1102        }
1103        else {
1104            rb_method = RB_SPOOL_CL;
1105        }
1106    }
1107    else {
1108        /* This is an appropriate default; very efficient for no-body
1109         * requests, and has the behavior that it will not add any C-L
1110         * when the old_cl_val is NULL.
1111         */
1112        rb_method = RB_SPOOL_CL;
1113    }
1114
1115/* Yes I hate gotos.  This is the subrequest shortcut */
1116skip_body:
1117    /*
1118     * Handle Connection: header if we do HTTP/1.1 request:
1119     * If we plan to close the backend connection sent Connection: close
1120     * otherwise sent Connection: Keep-Alive.
1121     */
1122    if (!force10) {
1123        if (p_conn->close || p_conn->close_on_recycle) {
1124            buf = apr_pstrdup(p, "Connection: close" CRLF);
1125        }
1126        else {
1127            buf = apr_pstrdup(p, "Connection: Keep-Alive" CRLF);
1128        }
1129        ap_xlate_proto_to_ascii(buf, strlen(buf));
1130        e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
1131        APR_BRIGADE_INSERT_TAIL(header_brigade, e);
1132    }
1133
1134    /* send the request body, if any. */
1135    switch(rb_method) {
1136    case RB_STREAM_CHUNKED:
1137        rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade,
1138                                        input_brigade);
1139        break;
1140    case RB_STREAM_CL:
1141        rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade,
1142                                   input_brigade, old_cl_val);
1143        break;
1144    case RB_SPOOL_CL:
1145        rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade,
1146                                  input_brigade, (old_cl_val != NULL)
1147                                              || (old_te_val != NULL)
1148                                              || (bytes_read > 0));
1149        break;
1150    default:
1151        /* shouldn't be possible */
1152        rv = HTTP_INTERNAL_SERVER_ERROR ;
1153        break;
1154    }
1155
1156    if (rv != OK) {
1157        /* apr_errno value has been logged in lower level method */
1158        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
1159                     "proxy: pass request body failed to %pI (%s)"
1160                     " from %s (%s)",
1161                     p_conn->addr,
1162                     p_conn->hostname ? p_conn->hostname: "",
1163                     c->remote_ip,
1164                     c->remote_host ? c->remote_host: "");
1165        return rv;
1166    }
1167
1168    return OK;
1169}
1170
1171static void process_proxy_header(request_rec* r, proxy_dir_conf* c,
1172                      const char* key, const char* value)
1173{
1174    static const char* date_hdrs[]
1175        = { "Date", "Expires", "Last-Modified", NULL } ;
1176    static const struct {
1177        const char* name;
1178        ap_proxy_header_reverse_map_fn func;
1179    } transform_hdrs[] = {
1180        { "Location", ap_proxy_location_reverse_map } ,
1181        { "Content-Location", ap_proxy_location_reverse_map } ,
1182        { "URI", ap_proxy_location_reverse_map } ,
1183        { "Destination", ap_proxy_location_reverse_map } ,
1184        { "Set-Cookie", ap_proxy_cookie_reverse_map } ,
1185        { NULL, NULL }
1186    } ;
1187    int i ;
1188    for ( i = 0 ; date_hdrs[i] ; ++i ) {
1189        if ( !strcasecmp(date_hdrs[i], key) ) {
1190            apr_table_add(r->headers_out, key,
1191                ap_proxy_date_canon(r->pool, value)) ;
1192            return ;
1193        }
1194    }
1195    for ( i = 0 ; transform_hdrs[i].name ; ++i ) {
1196        if ( !strcasecmp(transform_hdrs[i].name, key) ) {
1197            apr_table_add(r->headers_out, key,
1198                (*transform_hdrs[i].func)(r, c, value)) ;
1199            return ;
1200       }
1201    }
1202    apr_table_add(r->headers_out, key, value) ;
1203    return ;
1204}
1205
1206/*
1207 * Note: pread_len is the length of the response that we've  mistakenly
1208 * read (assuming that we don't consider that an  error via
1209 * ProxyBadHeader StartBody). This depends on buffer actually being
1210 * local storage to the calling code in order for pread_len to make
1211 * any sense at all, since we depend on buffer still containing
1212 * what was read by ap_getline() upon return.
1213 */
1214static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
1215                                  char *buffer, int size,
1216                                  conn_rec *c, int *pread_len)
1217{
1218    int len;
1219    char *value, *end;
1220    char field[MAX_STRING_LEN];
1221    int saw_headers = 0;
1222    void *sconf = r->server->module_config;
1223    proxy_server_conf *psc;
1224    proxy_dir_conf *dconf;
1225
1226    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
1227    psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
1228
1229    r->headers_out = apr_table_make(r->pool, 20);
1230    *pread_len = 0;
1231
1232    /*
1233     * Read header lines until we get the empty separator line, a read error,
1234     * the connection closes (EOF), or we timeout.
1235     */
1236    while ((len = ap_getline(buffer, size, rr, 1)) > 0) {
1237
1238        if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */
1239
1240            /* We may encounter invalid headers, usually from buggy
1241             * MS IIS servers, so we need to determine just how to handle
1242             * them. We can either ignore them, assume that they mark the
1243             * start-of-body (eg: a missing CRLF) or (the default) mark
1244             * the headers as totally bogus and return a 500. The sole
1245             * exception is an extra "HTTP/1.0 200, OK" line sprinkled
1246             * in between the usual MIME headers, which is a favorite
1247             * IIS bug.
1248             */
1249             /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */
1250
1251            if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
1252                if (psc->badopt == bad_error) {
1253                    /* Nope, it wasn't even an extra HTTP header. Give up. */
1254                    r->headers_out = NULL;
1255                    return ;
1256                }
1257                else if (psc->badopt == bad_body) {
1258                    /* if we've already started loading headers_out, then
1259                     * return what we've accumulated so far, in the hopes
1260                     * that they are useful; also note that we likely pre-read
1261                     * the first line of the response.
1262                     */
1263                    if (saw_headers) {
1264                        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
1265                         "proxy: Starting body due to bogus non-header in headers "
1266                         "returned by %s (%s)", r->uri, r->method);
1267                        *pread_len = len;
1268                        return ;
1269                    } else {
1270                         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
1271                         "proxy: No HTTP headers "
1272                         "returned by %s (%s)", r->uri, r->method);
1273                        return ;
1274                    }
1275                }
1276            }
1277            /* this is the psc->badopt == bad_ignore case */
1278            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
1279                         "proxy: Ignoring bogus HTTP header "
1280                         "returned by %s (%s)", r->uri, r->method);
1281            continue;
1282        }
1283
1284        *value = '\0';
1285        ++value;
1286        /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
1287         * wrong... and so are many others probably.
1288         */
1289        while (apr_isspace(*value))
1290            ++value;            /* Skip to start of value   */
1291
1292        /* should strip trailing whitespace as well */
1293        for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --
1294end)
1295            *end = '\0';
1296
1297        /* make sure we add so as not to destroy duplicated headers
1298         * Modify headers requiring canonicalisation and/or affected
1299         * by ProxyPassReverse and family with process_proxy_header
1300         */
1301        process_proxy_header(r, dconf, buffer, value) ;
1302        saw_headers = 1;
1303
1304        /* the header was too long; at the least we should skip extra data */
1305        if (len >= size - 1) {
1306            while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1))
1307                    >= MAX_STRING_LEN - 1) {
1308                /* soak up the extra data */
1309            }
1310            if (len == 0) /* time to exit the larger loop as well */
1311                break;
1312        }
1313    }
1314}
1315
1316
1317
1318static int addit_dammit(void *v, const char *key, const char *val)
1319{
1320    apr_table_addn(v, key, val);
1321    return 1;
1322}
1323
1324static
1325apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r,
1326                             int fold, int *writen)
1327{
1328    char *tmp_s = s;
1329    apr_status_t rv;
1330    apr_size_t len;
1331
1332    rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb);
1333    apr_brigade_cleanup(bb);
1334
1335    if (rv == APR_SUCCESS) {
1336        *writen = (int) len;
1337    } else if (rv == APR_ENOSPC) {
1338        *writen = n;
1339    } else {
1340        *writen = -1;
1341    }
1342
1343    return rv;
1344}
1345
1346/*
1347 * Limit the number of interim respones we sent back to the client. Otherwise
1348 * we suffer from a memory build up. Besides there is NO sense in sending back
1349 * an unlimited number of interim responses to the client. Thus if we cross
1350 * this limit send back a 502 (Bad Gateway).
1351 */
1352#ifndef AP_MAX_INTERIM_RESPONSES
1353#define AP_MAX_INTERIM_RESPONSES 10
1354#endif
1355
1356static
1357apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
1358                                            proxy_conn_rec *backend,
1359                                            conn_rec *origin,
1360                                            proxy_server_conf *conf,
1361                                            char *server_portstr) {
1362    conn_rec *c = r->connection;
1363    char buffer[HUGE_STRING_LEN];
1364    const char *buf;
1365    char keepchar;
1366    request_rec *rp;
1367    apr_bucket *e;
1368    apr_bucket_brigade *bb, *tmp_bb;
1369    apr_bucket_brigade *pass_bb;
1370    int len, backasswards;
1371    int interim_response = 0; /* non-zero whilst interim 1xx responses
1372                               * are being read. */
1373    int pread_len = 0;
1374    apr_table_t *save_table;
1375    int backend_broke = 0;
1376    static const char *hop_by_hop_hdrs[] =
1377        {"Keep-Alive", "Proxy-Authenticate", "TE", "Trailer", "Upgrade", NULL};
1378    int i;
1379    const char *te = NULL;
1380    int original_status = r->status;
1381    int proxy_status = OK;
1382    const char *original_status_line = r->status_line;
1383    const char *proxy_status_line = NULL;
1384
1385    bb = apr_brigade_create(p, c->bucket_alloc);
1386    pass_bb = apr_brigade_create(p, c->bucket_alloc);
1387
1388    /* Get response from the remote server, and pass it up the
1389     * filter chain
1390     */
1391
1392    rp = ap_proxy_make_fake_req(origin, r);
1393    /* In case anyone needs to know, this is a fake request that is really a
1394     * response.
1395     */
1396    rp->proxyreq = PROXYREQ_RESPONSE;
1397    tmp_bb = apr_brigade_create(p, c->bucket_alloc);
1398    do {
1399        apr_status_t rc;
1400
1401        apr_brigade_cleanup(bb);
1402
1403        rc = ap_proxygetline(tmp_bb, buffer, sizeof(buffer), rp, 0, &len);
1404        if (len == 0) {
1405            /* handle one potential stray CRLF */
1406            rc = ap_proxygetline(tmp_bb, buffer, sizeof(buffer), rp, 0, &len);
1407        }
1408        if (len <= 0) {
1409            ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
1410                          "proxy: error reading status line from remote "
1411                          "server %s:%d", backend->hostname, backend->port);
1412            if (APR_STATUS_IS_TIMEUP(rc)) {
1413                apr_table_set(r->notes, "proxy_timedout", "1");
1414                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1415                              "proxy: read timeout");
1416            }
1417            /*
1418             * If we are a reverse proxy request shutdown the connection
1419             * WITHOUT ANY response to trigger a retry by the client
1420             * if allowed (as for idempotent requests).
1421             * BUT currently we should not do this if the request is the
1422             * first request on a keepalive connection as browsers like
1423             * seamonkey only display an empty page in this case and do
1424             * not do a retry. We should also not do this on a
1425             * connection which times out; instead handle as
1426             * we normally would handle timeouts
1427             */
1428            if (r->proxyreq == PROXYREQ_REVERSE && c->keepalives &&
1429                !APR_STATUS_IS_TIMEUP(rc)) {
1430                apr_bucket *eos;
1431
1432                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1433                              "proxy: Closing connection to client because"
1434                              " reading from backend server %s:%d failed."
1435                              " Number of keepalives %i", backend->hostname,
1436                              backend->port, c->keepalives);
1437                ap_proxy_backend_broke(r, bb);
1438                /*
1439                 * Add an EOC bucket to signal the ap_http_header_filter
1440                 * that it should get out of our way, BUT ensure that the
1441                 * EOC bucket is inserted BEFORE an EOS bucket in bb as
1442                 * some resource filters like mod_deflate pass everything
1443                 * up to the EOS down the chain immediately and sent the
1444                 * remainder of the brigade later (or even never). But in
1445                 * this case the ap_http_header_filter does not get out of
1446                 * our way soon enough.
1447                 */
1448                e = ap_bucket_eoc_create(c->bucket_alloc);
1449                eos = APR_BRIGADE_LAST(bb);
1450                while ((APR_BRIGADE_SENTINEL(bb) != eos)
1451                       && !APR_BUCKET_IS_EOS(eos)) {
1452                    eos = APR_BUCKET_PREV(eos);
1453                }
1454                if (eos == APR_BRIGADE_SENTINEL(bb)) {
1455                    APR_BRIGADE_INSERT_TAIL(bb, e);
1456                }
1457                else {
1458                    APR_BUCKET_INSERT_BEFORE(eos, e);
1459                }
1460                ap_pass_brigade(r->output_filters, bb);
1461                /* Mark the backend connection for closing */
1462                backend->close = 1;
1463                /* Need to return OK to avoid sending an error message */
1464                return OK;
1465            }
1466            else if (!c->keepalives) {
1467                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1468                                   "proxy: NOT Closing connection to client"
1469                                   " although reading from backend server %s:%d"
1470                                   " failed.", backend->hostname,
1471                                   backend->port);
1472            }
1473            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
1474                                 "Error reading from remote server");
1475        }
1476        /* XXX: Is this a real headers length send from remote? */
1477        backend->worker->s->read += len;
1478
1479        /* Is it an HTTP/1 response?
1480         * This is buggy if we ever see an HTTP/1.10
1481         */
1482        if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
1483            int major, minor;
1484
1485            major = buffer[5] - '0';
1486            minor = buffer[7] - '0';
1487
1488            /* If not an HTTP/1 message or
1489             * if the status line was > 8192 bytes
1490             */
1491            if ((major != 1) || (len >= sizeof(buffer)-1)) {
1492                return ap_proxyerror(r, HTTP_BAD_GATEWAY,
1493                apr_pstrcat(p, "Corrupt status line returned by remote "
1494                            "server: ", buffer, NULL));
1495            }
1496            backasswards = 0;
1497
1498            keepchar = buffer[12];
1499            buffer[12] = '\0';
1500            proxy_status = atoi(&buffer[9]);
1501
1502            if (keepchar != '\0') {
1503                buffer[12] = keepchar;
1504            } else {
1505                /* 2616 requires the space in Status-Line; the origin
1506                 * server may have sent one but ap_rgetline_core will
1507                 * have stripped it. */
1508                buffer[12] = ' ';
1509                buffer[13] = '\0';
1510            }
1511            proxy_status_line = apr_pstrdup(p, &buffer[9]);
1512
1513            /* The status out of the front is the same as the status coming in
1514             * from the back, until further notice.
1515             */
1516            r->status = proxy_status;
1517            r->status_line = proxy_status_line;
1518
1519            /* read the headers. */
1520            /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/
1521            /* Also, take care with headers with multiple occurences. */
1522
1523            /* First, tuck away all already existing cookies */
1524            save_table = apr_table_make(r->pool, 2);
1525            apr_table_do(addit_dammit, save_table, r->headers_out,
1526                         "Set-Cookie", NULL);
1527
1528            /* shove the headers direct into r->headers_out */
1529            ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin,
1530                                  &pread_len);
1531
1532            if (r->headers_out == NULL) {
1533                ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
1534                             r->server, "proxy: bad HTTP/%d.%d header "
1535                             "returned by %s (%s)", major, minor, r->uri,
1536                             r->method);
1537                backend->close += 1;
1538                /*
1539                 * ap_send_error relies on a headers_out to be present. we
1540                 * are in a bad position here.. so force everything we send out
1541                 * to have nothing to do with the incoming packet
1542                 */
1543                r->headers_out = apr_table_make(r->pool,1);
1544                r->status = HTTP_BAD_GATEWAY;
1545                r->status_line = "bad gateway";
1546                return r->status;
1547            }
1548
1549            /* Now, add in the just read cookies */
1550            apr_table_do(addit_dammit, save_table, r->headers_out,
1551                         "Set-Cookie", NULL);
1552
1553            /* and now load 'em all in */
1554            if (!apr_is_empty_table(save_table)) {
1555                apr_table_unset(r->headers_out, "Set-Cookie");
1556                r->headers_out = apr_table_overlay(r->pool,
1557                                                   r->headers_out,
1558                                                   save_table);
1559            }
1560
1561            /* can't have both Content-Length and Transfer-Encoding */
1562            if (apr_table_get(r->headers_out, "Transfer-Encoding")
1563                    && apr_table_get(r->headers_out, "Content-Length")) {
1564                /*
1565                 * 2616 section 4.4, point 3: "if both Transfer-Encoding
1566                 * and Content-Length are received, the latter MUST be
1567                 * ignored";
1568                 *
1569                 * To help mitigate HTTP Splitting, unset Content-Length
1570                 * and shut down the backend server connection
1571                 * XXX: We aught to treat such a response as uncachable
1572                 */
1573                apr_table_unset(r->headers_out, "Content-Length");
1574                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1575                             "proxy: server %s:%d returned Transfer-Encoding"
1576                             " and Content-Length", backend->hostname,
1577                             backend->port);
1578                backend->close += 1;
1579            }
1580
1581            /*
1582             * Save a possible Transfer-Encoding header as we need it later for
1583             * ap_http_filter to know where to end.
1584             */
1585            te = apr_table_get(r->headers_out, "Transfer-Encoding");
1586            /* strip connection listed hop-by-hop headers from response */
1587            backend->close += ap_proxy_liststr(apr_table_get(r->headers_out,
1588                                                             "Connection"),
1589                                              "close");
1590            ap_proxy_clear_connection(p, r->headers_out);
1591            if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
1592                ap_set_content_type(r, apr_pstrdup(p, buf));
1593            }
1594            if (!ap_is_HTTP_INFO(proxy_status)) {
1595                ap_proxy_pre_http_request(origin, rp);
1596            }
1597
1598            /* Clear hop-by-hop headers */
1599            for (i=0; hop_by_hop_hdrs[i]; ++i) {
1600                apr_table_unset(r->headers_out, hop_by_hop_hdrs[i]);
1601            }
1602            /* Delete warnings with wrong date */
1603            r->headers_out = ap_proxy_clean_warnings(p, r->headers_out);
1604
1605            /* handle Via header in response */
1606            if (conf->viaopt != via_off && conf->viaopt != via_block) {
1607                const char *server_name = ap_get_server_name(r);
1608                /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
1609                 * then the server name returned by ap_get_server_name() is the
1610                 * origin server name (which does make too much sense with Via: headers)
1611                 * so we use the proxy vhost's name instead.
1612                 */
1613                if (server_name == r->hostname)
1614                    server_name = r->server->server_hostname;
1615                /* create a "Via:" response header entry and merge it */
1616                apr_table_addn(r->headers_out, "Via",
1617                               (conf->viaopt == via_full)
1618                                     ? apr_psprintf(p, "%d.%d %s%s (%s)",
1619                                           HTTP_VERSION_MAJOR(r->proto_num),
1620                                           HTTP_VERSION_MINOR(r->proto_num),
1621                                           server_name,
1622                                           server_portstr,
1623                                           AP_SERVER_BASEVERSION)
1624                                     : apr_psprintf(p, "%d.%d %s%s",
1625                                           HTTP_VERSION_MAJOR(r->proto_num),
1626                                           HTTP_VERSION_MINOR(r->proto_num),
1627                                           server_name,
1628                                           server_portstr)
1629                );
1630            }
1631
1632            /* cancel keepalive if HTTP/1.0 or less */
1633            if ((major < 1) || (minor < 1)) {
1634                backend->close += 1;
1635                origin->keepalive = AP_CONN_CLOSE;
1636            }
1637        } else {
1638            /* an http/0.9 response */
1639            backasswards = 1;
1640            r->status = 200;
1641            r->status_line = "200 OK";
1642            backend->close += 1;
1643        }
1644
1645        if (ap_is_HTTP_INFO(proxy_status)) {
1646            interim_response++;
1647        }
1648        else {
1649            interim_response = 0;
1650        }
1651        if (interim_response) {
1652            /* RFC2616 tells us to forward this.
1653             *
1654             * OTOH, an interim response here may mean the backend
1655             * is playing sillybuggers.  The Client didn't ask for
1656             * it within the defined HTTP/1.1 mechanisms, and if
1657             * it's an extension, it may also be unsupported by us.
1658             *
1659             * There's also the possibility that changing existing
1660             * behaviour here might break something.
1661             *
1662             * So let's make it configurable.
1663             */
1664            const char *policy = apr_table_get(r->subprocess_env,
1665                                               "proxy-interim-response");
1666            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1667                         "proxy: HTTP: received interim %d response",
1668                         r->status);
1669            if (!policy || !strcasecmp(policy, "RFC")) {
1670                ap_send_interim_response(r, 1);
1671            }
1672            /* FIXME: refine this to be able to specify per-response-status
1673             * policies and maybe also add option to bail out with 502
1674             */
1675            else if (strcasecmp(policy, "Suppress")) {
1676                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
1677                             "undefined proxy interim response policy");
1678            }
1679        }
1680        /* Moved the fixups of Date headers and those affected by
1681         * ProxyPassReverse/etc from here to ap_proxy_read_headers
1682         */
1683
1684        if ((proxy_status == 401) && (conf->error_override)) {
1685            const char *buf;
1686            const char *wa = "WWW-Authenticate";
1687            if ((buf = apr_table_get(r->headers_out, wa))) {
1688                apr_table_set(r->err_headers_out, wa, buf);
1689            } else {
1690                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1691                             "proxy: origin server sent 401 without WWW-Authenticate header");
1692            }
1693        }
1694
1695        r->sent_bodyct = 1;
1696        /*
1697         * Is it an HTTP/0.9 response or did we maybe preread the 1st line of
1698         * the response? If so, load the extra data. These are 2 mutually
1699         * exclusive possibilities, that just happen to require very
1700         * similar behavior.
1701         */
1702        if (backasswards || pread_len) {
1703            apr_ssize_t cntr = (apr_ssize_t)pread_len;
1704            if (backasswards) {
1705                /*@@@FIXME:
1706                 * At this point in response processing of a 0.9 response,
1707                 * we don't know yet whether data is binary or not.
1708                 * mod_charset_lite will get control later on, so it cannot
1709                 * decide on the conversion of this buffer full of data.
1710                 * However, chances are that we are not really talking to an
1711                 * HTTP/0.9 server, but to some different protocol, therefore
1712                 * the best guess IMHO is to always treat the buffer as "text/x":
1713                 */
1714                ap_xlate_proto_to_ascii(buffer, len);
1715                cntr = (apr_ssize_t)len;
1716            }
1717            e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc);
1718            APR_BRIGADE_INSERT_TAIL(bb, e);
1719        }
1720
1721        /* send body - but only if a body is expected */
1722        if ((!r->header_only) &&                   /* not HEAD request */
1723            !interim_response &&                   /* not any 1xx response */
1724            (proxy_status != HTTP_NO_CONTENT) &&      /* not 204 */
1725            (proxy_status != HTTP_NOT_MODIFIED)) {    /* not 304 */
1726
1727            /* We need to copy the output headers and treat them as input
1728             * headers as well.  BUT, we need to do this before we remove
1729             * TE, so that they are preserved accordingly for
1730             * ap_http_filter to know where to end.
1731             */
1732            rp->headers_in = apr_table_copy(r->pool, r->headers_out);
1733            /*
1734             * Restore Transfer-Encoding header from response if we saved
1735             * one before and there is none left. We need it for the
1736             * ap_http_filter. See above.
1737             */
1738            if (te && !apr_table_get(rp->headers_in, "Transfer-Encoding")) {
1739                apr_table_add(rp->headers_in, "Transfer-Encoding", te);
1740            }
1741
1742            apr_table_unset(r->headers_out,"Transfer-Encoding");
1743
1744            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1745                         "proxy: start body send");
1746
1747            /*
1748             * if we are overriding the errors, we can't put the content
1749             * of the page into the brigade
1750             */
1751            if (!conf->error_override || !ap_is_HTTP_ERROR(proxy_status)) {
1752                /* read the body, pass it to the output filters */
1753                apr_read_type_e mode = APR_NONBLOCK_READ;
1754                int finish = FALSE;
1755
1756                /* Handle the case where the error document is itself reverse
1757                 * proxied and was successful. We must maintain any previous
1758                 * error status so that an underlying error (eg HTTP_NOT_FOUND)
1759                 * doesn't become an HTTP_OK.
1760                 */
1761                if (conf->error_override && !ap_is_HTTP_ERROR(proxy_status)
1762                        && ap_is_HTTP_ERROR(original_status)) {
1763                    r->status = original_status;
1764                    r->status_line = original_status_line;
1765                }
1766
1767                do {
1768                    apr_off_t readbytes;
1769                    apr_status_t rv;
1770
1771                    rv = ap_get_brigade(rp->input_filters, bb,
1772                                        AP_MODE_READBYTES, mode,
1773                                        conf->io_buffer_size);
1774
1775                    /* ap_get_brigade will return success with an empty brigade
1776                     * for a non-blocking read which would block: */
1777                    if (APR_STATUS_IS_EAGAIN(rv)
1778                        || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
1779                        /* flush to the client and switch to blocking mode */
1780                        e = apr_bucket_flush_create(c->bucket_alloc);
1781                        APR_BRIGADE_INSERT_TAIL(bb, e);
1782                        if (ap_pass_brigade(r->output_filters, bb)
1783                            || c->aborted) {
1784                            backend->close = 1;
1785                            break;
1786                        }
1787                        apr_brigade_cleanup(bb);
1788                        mode = APR_BLOCK_READ;
1789                        continue;
1790                    }
1791                    else if (rv == APR_EOF) {
1792                        break;
1793                    }
1794                    else if (rv != APR_SUCCESS) {
1795                        /* In this case, we are in real trouble because
1796                         * our backend bailed on us. Pass along a 502 error
1797                         * error bucket
1798                         */
1799                        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
1800                                      "proxy: error reading response");
1801                        ap_proxy_backend_broke(r, bb);
1802                        ap_pass_brigade(r->output_filters, bb);
1803                        backend_broke = 1;
1804                        backend->close = 1;
1805                        break;
1806                    }
1807                    /* next time try a non-blocking read */
1808                    mode = APR_NONBLOCK_READ;
1809
1810                    apr_brigade_length(bb, 0, &readbytes);
1811                    backend->worker->s->read += readbytes;
1812#if DEBUGGING
1813                    {
1814                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
1815                                 r->server, "proxy (PID %d): readbytes: %#x",
1816                                 getpid(), readbytes);
1817                    }
1818#endif
1819                    /* sanity check */
1820                    if (APR_BRIGADE_EMPTY(bb)) {
1821                        apr_brigade_cleanup(bb);
1822                        break;
1823                    }
1824
1825                    /* Switch the allocator lifetime of the buckets */
1826                    ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
1827
1828                    /* found the last brigade? */
1829                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
1830                        /* signal that we must leave */
1831                        finish = TRUE;
1832                    }
1833
1834                    /* try send what we read */
1835                    if (ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS
1836                        || c->aborted) {
1837                        /* Ack! Phbtt! Die! User aborted! */
1838                        backend->close = 1;  /* this causes socket close below */
1839                        finish = TRUE;
1840                    }
1841
1842                    /* make sure we always clean up after ourselves */
1843                    apr_brigade_cleanup(bb);
1844                    apr_brigade_cleanup(pass_bb);
1845
1846                } while (!finish);
1847            }
1848            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1849                         "proxy: end body send");
1850        }
1851        else if (!interim_response) {
1852            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1853                         "proxy: header only");
1854
1855            /* Pass EOS bucket down the filter chain. */
1856            e = apr_bucket_eos_create(c->bucket_alloc);
1857            APR_BRIGADE_INSERT_TAIL(bb, e);
1858            if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS
1859                || c->aborted) {
1860                /* Ack! Phbtt! Die! User aborted! */
1861                backend->close = 1;  /* this causes socket close below */
1862            }
1863
1864            apr_brigade_cleanup(bb);
1865        }
1866    } while (interim_response && (interim_response < AP_MAX_INTERIM_RESPONSES));
1867
1868    /* See define of AP_MAX_INTERIM_RESPONSES for why */
1869    if (interim_response >= AP_MAX_INTERIM_RESPONSES) {
1870        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
1871                             apr_psprintf(p,
1872                             "Too many (%d) interim responses from origin server",
1873                             interim_response));
1874    }
1875
1876    /* If our connection with the client is to be aborted, return DONE. */
1877    if (c->aborted || backend_broke) {
1878        return DONE;
1879    }
1880
1881    if (conf->error_override) {
1882        /* the code above this checks for 'OK' which is what the hook expects */
1883        if (!ap_is_HTTP_ERROR(proxy_status)) {
1884            return OK;
1885        }
1886        else {
1887            /* clear r->status for override error, otherwise ErrorDocument
1888             * thinks that this is a recursive error, and doesn't find the
1889             * custom error page
1890             */
1891            r->status = HTTP_OK;
1892            /* Discard body, if one is expected */
1893            if (!r->header_only && /* not HEAD request */
1894                (proxy_status != HTTP_NO_CONTENT) && /* not 204 */
1895                (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */
1896                ap_discard_request_body(rp);
1897            }
1898            return proxy_status;
1899        }
1900    }
1901    else {
1902        return OK;
1903    }
1904}
1905
1906static
1907apr_status_t ap_proxy_http_cleanup(const char *scheme, request_rec *r,
1908                                   proxy_conn_rec *backend)
1909{
1910    ap_proxy_release_connection(scheme, backend, r->server);
1911    return OK;
1912}
1913
1914/*
1915 * This handles http:// URLs, and other URLs using a remote proxy over http
1916 * If proxyhost is NULL, then contact the server directly, otherwise
1917 * go via the proxy.
1918 * Note that if a proxy is used, then URLs other than http: can be accessed,
1919 * also, if we have trouble which is clearly specific to the proxy, then
1920 * we return DECLINED so that we can try another proxy. (Or the direct
1921 * route.)
1922 */
1923static int proxy_http_handler(request_rec *r, proxy_worker *worker,
1924                              proxy_server_conf *conf,
1925                              char *url, const char *proxyname,
1926                              apr_port_t proxyport)
1927{
1928    int status;
1929    char server_portstr[32];
1930    char *scheme;
1931    const char *proxy_function;
1932    const char *u;
1933    proxy_conn_rec *backend = NULL;
1934    int is_ssl = 0;
1935    conn_rec *c = r->connection;
1936    /*
1937     * Use a shorter-lived pool to reduce memory usage
1938     * and avoid a memory leak
1939     */
1940    apr_pool_t *p = r->pool;
1941    apr_uri_t *uri = apr_palloc(p, sizeof(*uri));
1942
1943    /* find the scheme */
1944    u = strchr(url, ':');
1945    if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0')
1946       return DECLINED;
1947    if ((u - url) > 14)
1948        return HTTP_BAD_REQUEST;
1949    scheme = apr_pstrndup(p, url, u - url);
1950    /* scheme is lowercase */
1951    ap_str_tolower(scheme);
1952    /* is it for us? */
1953    if (strcmp(scheme, "https") == 0) {
1954        if (!ap_proxy_ssl_enable(NULL)) {
1955            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1956                         "proxy: HTTPS: declining URL %s"
1957                         " (mod_ssl not configured?)", url);
1958            return DECLINED;
1959        }
1960        is_ssl = 1;
1961        proxy_function = "HTTPS";
1962    }
1963    else if (!(strcmp(scheme, "http") == 0 || (strcmp(scheme, "ftp") == 0 && proxyname))) {
1964        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1965                     "proxy: HTTP: declining URL %s", url);
1966        return DECLINED; /* only interested in HTTP, or FTP via proxy */
1967    }
1968    else {
1969        if (*scheme == 'h')
1970            proxy_function = "HTTP";
1971        else
1972            proxy_function = "FTP";
1973    }
1974    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1975             "proxy: HTTP: serving URL %s", url);
1976
1977
1978    /* create space for state information */
1979    if ((status = ap_proxy_acquire_connection(proxy_function, &backend,
1980                                              worker, r->server)) != OK)
1981        goto cleanup;
1982
1983
1984    backend->is_ssl = is_ssl;
1985    if (is_ssl) {
1986        ap_proxy_ssl_connection_cleanup(backend, r);
1987    }
1988
1989    /*
1990     * In the case that we are handling a reverse proxy connection and this
1991     * is not a request that is coming over an already kept alive connection
1992     * with the client, do NOT reuse the connection to the backend, because
1993     * we cannot forward a failure to the client in this case as the client
1994     * does NOT expects this in this situation.
1995     * Yes, this creates a performance penalty.
1996     */
1997    if ((r->proxyreq == PROXYREQ_REVERSE) && (!c->keepalives)
1998        && (apr_table_get(r->subprocess_env, "proxy-initial-not-pooled"))) {
1999        backend->close = 1;
2000    }
2001
2002    /* Step One: Determine Who To Connect To */
2003    if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend,
2004                                                uri, &url, proxyname,
2005                                                proxyport, server_portstr,
2006                                                sizeof(server_portstr))) != OK)
2007        goto cleanup;
2008
2009    /* Step Two: Make the Connection */
2010    if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
2011        status = HTTP_SERVICE_UNAVAILABLE;
2012        goto cleanup;
2013    }
2014
2015    /* Step Three: Create conn_rec */
2016    if (!backend->connection) {
2017        if ((status = ap_proxy_connection_create(proxy_function, backend,
2018                                                 c, r->server)) != OK)
2019            goto cleanup;
2020        /*
2021         * On SSL connections set a note on the connection what CN is
2022         * requested, such that mod_ssl can check if it is requested to do
2023         * so.
2024         */
2025        if (is_ssl) {
2026            const char *ssl_hostname;
2027
2028            /*
2029             * In the case of ProxyPreserveHost on use the hostname of
2030             * the request if present otherwise use the one from the
2031             * backend request URI.
2032             */
2033            if ((conf->preserve_host != 0) && (r->hostname != NULL)) {
2034                ssl_hostname = r->hostname;
2035            }
2036            else {
2037                ssl_hostname = uri->hostname;
2038            }
2039
2040            apr_table_set(backend->connection->notes, "proxy-request-hostname",
2041                          ssl_hostname);
2042        }
2043    }
2044
2045    /* Step Four: Send the Request */
2046    if ((status = ap_proxy_http_request(p, r, backend, backend->connection,
2047                                        conf, uri, url, server_portstr)) != OK)
2048        goto cleanup;
2049
2050    /* Step Five: Receive the Response */
2051    if ((status = ap_proxy_http_process_response(p, r, backend,
2052                                                 backend->connection,
2053                                                 conf, server_portstr)) != OK)
2054        goto cleanup;
2055
2056    /* Step Six: Clean Up */
2057
2058cleanup:
2059    if (backend) {
2060        if (status != OK)
2061            backend->close = 1;
2062        ap_proxy_http_cleanup(proxy_function, r, backend);
2063    }
2064    return status;
2065}
2066static apr_status_t warn_rx_free(void *p)
2067{
2068    ap_pregfree((apr_pool_t*)p, warn_rx);
2069    return APR_SUCCESS;
2070}
2071static void ap_proxy_http_register_hook(apr_pool_t *p)
2072{
2073    proxy_hook_scheme_handler(proxy_http_handler, NULL, NULL, APR_HOOK_FIRST);
2074    proxy_hook_canon_handler(proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);
2075    warn_rx = ap_pregcomp(p, "[0-9]{3}[ \t]+[^ \t]+[ \t]+\"[^\"]*\"([ \t]+\"([^\"]+)\")?", 0);
2076    apr_pool_cleanup_register(p, p, warn_rx_free, apr_pool_cleanup_null);
2077}
2078
2079module AP_MODULE_DECLARE_DATA proxy_http_module = {
2080    STANDARD20_MODULE_STUFF,
2081    NULL,              /* create per-directory config structure */
2082    NULL,              /* merge per-directory config structures */
2083    NULL,              /* create per-server config structure */
2084    NULL,              /* merge per-server config structures */
2085    NULL,              /* command apr_table_t */
2086    ap_proxy_http_register_hook/* register hooks */
2087};
2088
2089