~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/proxy/mod_proxy_http.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

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