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