Lines 234-240
static int stream_reqbody_chunked(apr_pool_t *p,
Link Here
|
234 |
proxy_conn_rec *p_conn, |
234 |
proxy_conn_rec *p_conn, |
235 |
conn_rec *origin, |
235 |
conn_rec *origin, |
236 |
apr_bucket_brigade *header_brigade, |
236 |
apr_bucket_brigade *header_brigade, |
237 |
apr_bucket_brigade *input_brigade) |
237 |
apr_bucket_brigade *input_brigade, |
|
|
238 |
int flushall) |
238 |
{ |
239 |
{ |
239 |
int seen_eos = 0, rv = OK; |
240 |
int seen_eos = 0, rv = OK; |
240 |
apr_size_t hdr_len; |
241 |
apr_size_t hdr_len; |
Lines 247-260
static int stream_reqbody_chunked(apr_pool_t *p,
Link Here
|
247 |
add_te_chunked(p, bucket_alloc, header_brigade); |
248 |
add_te_chunked(p, bucket_alloc, header_brigade); |
248 |
terminate_headers(bucket_alloc, header_brigade); |
249 |
terminate_headers(bucket_alloc, header_brigade); |
249 |
|
250 |
|
250 |
while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
251 |
while (APR_BRIGADE_EMPTY(input_brigade) || |
|
|
252 |
!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
251 |
{ |
253 |
{ |
|
|
254 |
int flush = flushall; |
255 |
|
256 |
if (!APR_BRIGADE_EMPTY(input_brigade)) { |
252 |
char chunk_hdr[20]; /* must be here due to transient bucket. */ |
257 |
char chunk_hdr[20]; /* must be here due to transient bucket. */ |
253 |
|
258 |
|
254 |
/* If this brigade contains EOS, either stop or remove it. */ |
259 |
/* If this brigade contains EOS, either stop or remove it. */ |
255 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
260 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
256 |
seen_eos = 1; |
261 |
seen_eos = 1; |
257 |
|
262 |
|
|
|
263 |
/* The request is flushed below this loop with the EOS chunk */ |
264 |
flush = 0; |
265 |
|
258 |
/* We can't pass this EOS to the output_filters. */ |
266 |
/* We can't pass this EOS to the output_filters. */ |
259 |
e = APR_BRIGADE_LAST(input_brigade); |
267 |
e = APR_BRIGADE_LAST(input_brigade); |
260 |
apr_bucket_delete(e); |
268 |
apr_bucket_delete(e); |
Lines 276-281
static int stream_reqbody_chunked(apr_pool_t *p,
Link Here
|
276 |
*/ |
284 |
*/ |
277 |
e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); |
285 |
e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); |
278 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
286 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
|
|
287 |
} |
279 |
|
288 |
|
280 |
if (header_brigade) { |
289 |
if (header_brigade) { |
281 |
/* we never sent the header brigade, so go ahead and |
290 |
/* we never sent the header brigade, so go ahead and |
Lines 283-288
static int stream_reqbody_chunked(apr_pool_t *p,
Link Here
|
283 |
*/ |
292 |
*/ |
284 |
bb = header_brigade; |
293 |
bb = header_brigade; |
285 |
|
294 |
|
|
|
295 |
/* Flush the prefeched data now to minimize the delay between |
296 |
* connect (or ap_proxy_is_socket_connected) and the first bytes |
297 |
* sent, unless it is done below this loop with the EOS chunk. |
298 |
*/ |
299 |
flush = !seen_eos; |
300 |
|
286 |
/* |
301 |
/* |
287 |
* Save input_brigade in bb brigade. (At least) in the SSL case |
302 |
* Save input_brigade in bb brigade. (At least) in the SSL case |
288 |
* input_brigade contains transient buckets whose data would get |
303 |
* input_brigade contains transient buckets whose data would get |
Lines 303-310
static int stream_reqbody_chunked(apr_pool_t *p,
Link Here
|
303 |
bb = input_brigade; |
318 |
bb = input_brigade; |
304 |
} |
319 |
} |
305 |
|
320 |
|
306 |
/* The request is flushed below this loop with chunk EOS header */ |
321 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, flush); |
307 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, 0); |
|
|
308 |
if (rv != OK) { |
322 |
if (rv != OK) { |
309 |
return rv; |
323 |
return rv; |
310 |
} |
324 |
} |
Lines 366-372
static int stream_reqbody_cl(apr_pool_t *p,
Link Here
|
366 |
conn_rec *origin, |
380 |
conn_rec *origin, |
367 |
apr_bucket_brigade *header_brigade, |
381 |
apr_bucket_brigade *header_brigade, |
368 |
apr_bucket_brigade *input_brigade, |
382 |
apr_bucket_brigade *input_brigade, |
369 |
char *old_cl_val) |
383 |
char *old_cl_val, int flushall) |
370 |
{ |
384 |
{ |
371 |
int seen_eos = 0, rv = 0; |
385 |
int seen_eos = 0, rv = 0; |
372 |
apr_status_t status = APR_SUCCESS; |
386 |
apr_status_t status = APR_SUCCESS; |
Lines 392-399
static int stream_reqbody_cl(apr_pool_t *p,
Link Here
|
392 |
} |
406 |
} |
393 |
terminate_headers(bucket_alloc, header_brigade); |
407 |
terminate_headers(bucket_alloc, header_brigade); |
394 |
|
408 |
|
395 |
while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
409 |
while (APR_BRIGADE_EMPTY(input_brigade) || |
|
|
410 |
!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
396 |
{ |
411 |
{ |
|
|
412 |
int flush = flushall; |
413 |
|
414 |
if (!APR_BRIGADE_EMPTY(input_brigade)) { |
397 |
apr_brigade_length(input_brigade, 1, &bytes); |
415 |
apr_brigade_length(input_brigade, 1, &bytes); |
398 |
bytes_streamed += bytes; |
416 |
bytes_streamed += bytes; |
399 |
|
417 |
|
Lines 401-406
static int stream_reqbody_cl(apr_pool_t *p,
Link Here
|
401 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
419 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
402 |
seen_eos = 1; |
420 |
seen_eos = 1; |
403 |
|
421 |
|
|
|
422 |
/* Once we hit EOS, we are ready to flush. */ |
423 |
flush = 1; |
424 |
|
404 |
/* We can't pass this EOS to the output_filters. */ |
425 |
/* We can't pass this EOS to the output_filters. */ |
405 |
e = APR_BRIGADE_LAST(input_brigade); |
426 |
e = APR_BRIGADE_LAST(input_brigade); |
406 |
apr_bucket_delete(e); |
427 |
apr_bucket_delete(e); |
Lines 427-432
static int stream_reqbody_cl(apr_pool_t *p,
Link Here
|
427 |
bytes_streamed, cl_val); |
448 |
bytes_streamed, cl_val); |
428 |
return HTTP_INTERNAL_SERVER_ERROR; |
449 |
return HTTP_INTERNAL_SERVER_ERROR; |
429 |
} |
450 |
} |
|
|
451 |
} |
430 |
|
452 |
|
431 |
if (header_brigade) { |
453 |
if (header_brigade) { |
432 |
/* we never sent the header brigade, so go ahead and |
454 |
/* we never sent the header brigade, so go ahead and |
Lines 434-439
static int stream_reqbody_cl(apr_pool_t *p,
Link Here
|
434 |
*/ |
456 |
*/ |
435 |
bb = header_brigade; |
457 |
bb = header_brigade; |
436 |
|
458 |
|
|
|
459 |
/* Flush prefeched data now to minimize the delay between connect, |
460 |
* or ap_proxy_is_socket_connected, and the first bytes sent. |
461 |
*/ |
462 |
flush = 1; |
463 |
|
437 |
/* |
464 |
/* |
438 |
* Save input_brigade in bb brigade. (At least) in the SSL case |
465 |
* Save input_brigade in bb brigade. (At least) in the SSL case |
439 |
* input_brigade contains transient buckets whose data would get |
466 |
* input_brigade contains transient buckets whose data would get |
Lines 454-463
static int stream_reqbody_cl(apr_pool_t *p,
Link Here
|
454 |
bb = input_brigade; |
481 |
bb = input_brigade; |
455 |
} |
482 |
} |
456 |
|
483 |
|
457 |
/* Once we hit EOS, we are ready to flush. */ |
484 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, flush); |
458 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, seen_eos); |
|
|
459 |
if (rv != OK) { |
485 |
if (rv != OK) { |
460 |
return rv ; |
486 |
return rv; |
461 |
} |
487 |
} |
462 |
|
488 |
|
463 |
if (seen_eos) { |
489 |
if (seen_eos) { |
Lines 499-506
static int stream_reqbody_cl(apr_pool_t *p,
Link Here
|
499 |
|
525 |
|
500 |
static int spool_reqbody_cl(apr_pool_t *p, |
526 |
static int spool_reqbody_cl(apr_pool_t *p, |
501 |
request_rec *r, |
527 |
request_rec *r, |
502 |
proxy_conn_rec *p_conn, |
|
|
503 |
conn_rec *origin, |
504 |
apr_bucket_brigade *header_brigade, |
528 |
apr_bucket_brigade *header_brigade, |
505 |
apr_bucket_brigade *input_brigade, |
529 |
apr_bucket_brigade *input_brigade, |
506 |
int force_cl) |
530 |
int force_cl) |
Lines 518-525
static int spool_reqbody_cl(apr_pool_t *p,
Link Here
|
518 |
|
542 |
|
519 |
limit = ap_get_limit_req_body(r); |
543 |
limit = ap_get_limit_req_body(r); |
520 |
|
544 |
|
521 |
while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
545 |
while (APR_BRIGADE_EMPTY(input_brigade) || |
|
|
546 |
!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
522 |
{ |
547 |
{ |
|
|
548 |
if (!APR_BRIGADE_EMPTY(input_brigade)) { |
523 |
/* If this brigade contains EOS, either stop or remove it. */ |
549 |
/* If this brigade contains EOS, either stop or remove it. */ |
524 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
550 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
525 |
seen_eos = 1; |
551 |
seen_eos = 1; |
Lines 612-617
static int spool_reqbody_cl(apr_pool_t *p,
Link Here
|
612 |
if (seen_eos) { |
638 |
if (seen_eos) { |
613 |
break; |
639 |
break; |
614 |
} |
640 |
} |
|
|
641 |
} |
615 |
|
642 |
|
616 |
status = ap_get_brigade(r->input_filters, input_brigade, |
643 |
status = ap_get_brigade(r->input_filters, input_brigade, |
617 |
AP_MODE_READBYTES, APR_BLOCK_READ, |
644 |
AP_MODE_READBYTES, APR_BLOCK_READ, |
Lines 620-628
static int spool_reqbody_cl(apr_pool_t *p,
Link Here
|
620 |
if (status != APR_SUCCESS) { |
647 |
if (status != APR_SUCCESS) { |
621 |
conn_rec *c = r->connection; |
648 |
conn_rec *c = r->connection; |
622 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02610) |
649 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02610) |
623 |
"read request body failed to %pI (%s)" |
650 |
"read request body failed from %s (%s)", |
624 |
" from %s (%s)", p_conn->addr, |
|
|
625 |
p_conn->hostname ? p_conn->hostname: "", |
626 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
651 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
627 |
return HTTP_BAD_REQUEST; |
652 |
return HTTP_BAD_REQUEST; |
628 |
} |
653 |
} |
Lines 640-647
static int spool_reqbody_cl(apr_pool_t *p,
Link Here
|
640 |
e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); |
665 |
e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); |
641 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
666 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
642 |
} |
667 |
} |
643 |
/* This is all a single brigade, pass with flush flagged */ |
668 |
return OK; |
644 |
return(ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1)); |
|
|
645 |
} |
669 |
} |
646 |
|
670 |
|
647 |
/* |
671 |
/* |
Lines 671-678
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
671 |
e != APR_BRIGADE_SENTINEL(from); |
695 |
e != APR_BRIGADE_SENTINEL(from); |
672 |
e = APR_BUCKET_NEXT(e)) { |
696 |
e = APR_BUCKET_NEXT(e)) { |
673 |
if (!APR_BUCKET_IS_METADATA(e)) { |
697 |
if (!APR_BUCKET_IS_METADATA(e)) { |
674 |
apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ); |
698 |
if (APR_BUCKET_IS_FILE(e) && |
675 |
new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc); |
699 |
e->list == r->connection->bucket_alloc) { |
|
|
700 |
apr_bucket_copy(e, &new); |
701 |
} |
702 |
else { |
703 |
apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ); |
704 |
new = apr_bucket_transient_create(data, bytes, |
705 |
r->connection->bucket_alloc); |
706 |
} |
676 |
APR_BRIGADE_INSERT_TAIL(to, new); |
707 |
APR_BRIGADE_INSERT_TAIL(to, new); |
677 |
} |
708 |
} |
678 |
else if (APR_BUCKET_IS_FLUSH(e)) { |
709 |
else if (APR_BUCKET_IS_FLUSH(e)) { |
Lines 694-721
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
694 |
return rv; |
725 |
return rv; |
695 |
} |
726 |
} |
696 |
|
727 |
|
697 |
static |
728 |
enum rb_methods { |
698 |
int ap_proxy_http_request(apr_pool_t *p, request_rec *r, |
729 |
RB_INIT, |
699 |
proxy_conn_rec *p_conn, proxy_worker *worker, |
730 |
RB_STREAM_CL, |
700 |
proxy_server_conf *conf, |
731 |
RB_STREAM_CHUNKED, |
701 |
apr_uri_t *uri, |
732 |
RB_SPOOL_CL |
702 |
char *url, char *server_portstr) |
733 |
}; |
|
|
734 |
|
735 |
static int ap_proxy_http_prefetch(apr_pool_t *p, request_rec *r, |
736 |
proxy_conn_rec *p_conn, proxy_worker *worker, |
737 |
proxy_server_conf *conf, |
738 |
apr_uri_t *uri, |
739 |
char *url, char *server_portstr, |
740 |
apr_bucket_brigade *header_brigade, |
741 |
apr_bucket_brigade *input_brigade, |
742 |
char **old_cl_val, char **old_te_val, |
743 |
enum rb_methods *rb_method, int flushall) |
703 |
{ |
744 |
{ |
704 |
conn_rec *c = r->connection; |
745 |
conn_rec *c = r->connection; |
705 |
apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; |
746 |
apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; |
706 |
apr_bucket_brigade *header_brigade; |
|
|
707 |
apr_bucket_brigade *input_brigade; |
708 |
apr_bucket_brigade *temp_brigade; |
747 |
apr_bucket_brigade *temp_brigade; |
709 |
apr_bucket *e; |
748 |
apr_bucket *e; |
710 |
char *buf; |
749 |
char *buf; |
711 |
apr_status_t status; |
750 |
apr_status_t status; |
712 |
enum rb_methods {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL}; |
|
|
713 |
enum rb_methods rb_method = RB_INIT; |
714 |
char *old_cl_val = NULL; |
715 |
char *old_te_val = NULL; |
716 |
apr_off_t bytes_read = 0; |
751 |
apr_off_t bytes_read = 0; |
717 |
apr_off_t bytes; |
752 |
apr_off_t bytes; |
718 |
int force10, rv; |
753 |
int force10, rv; |
|
|
754 |
apr_read_type_e block; |
719 |
conn_rec *origin = p_conn->connection; |
755 |
conn_rec *origin = p_conn->connection; |
720 |
|
756 |
|
721 |
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { |
757 |
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { |
Lines 727-743
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
727 |
force10 = 0; |
763 |
force10 = 0; |
728 |
} |
764 |
} |
729 |
|
765 |
|
730 |
header_brigade = apr_brigade_create(p, bucket_alloc); |
|
|
731 |
rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, |
766 |
rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, |
732 |
worker, conf, uri, url, server_portstr, |
767 |
worker, conf, uri, url, server_portstr, |
733 |
&old_cl_val, &old_te_val); |
768 |
old_cl_val, old_te_val); |
734 |
if (rv != OK) { |
769 |
if (rv != OK) { |
735 |
return rv; |
770 |
return rv; |
736 |
} |
771 |
} |
737 |
|
772 |
|
738 |
/* We have headers, let's figure out our request body... */ |
|
|
739 |
input_brigade = apr_brigade_create(p, bucket_alloc); |
740 |
|
741 |
/* sub-requests never use keepalives, and mustn't pass request bodies. |
773 |
/* sub-requests never use keepalives, and mustn't pass request bodies. |
742 |
* Because the new logic looks at input_brigade, we will self-terminate |
774 |
* Because the new logic looks at input_brigade, we will self-terminate |
743 |
* input_brigade and jump past all of the request body logic... |
775 |
* input_brigade and jump past all of the request body logic... |
Lines 750-764
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
750 |
if (!r->kept_body && r->main) { |
782 |
if (!r->kept_body && r->main) { |
751 |
/* XXX: Why DON'T sub-requests use keepalives? */ |
783 |
/* XXX: Why DON'T sub-requests use keepalives? */ |
752 |
p_conn->close = 1; |
784 |
p_conn->close = 1; |
753 |
if (old_cl_val) { |
785 |
*old_cl_val = NULL; |
754 |
old_cl_val = NULL; |
786 |
*old_te_val = NULL; |
755 |
apr_table_unset(r->headers_in, "Content-Length"); |
787 |
*rb_method = RB_STREAM_CL; |
756 |
} |
|
|
757 |
if (old_te_val) { |
758 |
old_te_val = NULL; |
759 |
apr_table_unset(r->headers_in, "Transfer-Encoding"); |
760 |
} |
761 |
rb_method = RB_STREAM_CL; |
762 |
e = apr_bucket_eos_create(input_brigade->bucket_alloc); |
788 |
e = apr_bucket_eos_create(input_brigade->bucket_alloc); |
763 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
789 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
764 |
goto skip_body; |
790 |
goto skip_body; |
Lines 772-790
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
772 |
* encoding has been done by the extensions' handler, and |
798 |
* encoding has been done by the extensions' handler, and |
773 |
* do not modify add_te_chunked's logic |
799 |
* do not modify add_te_chunked's logic |
774 |
*/ |
800 |
*/ |
775 |
if (old_te_val && strcasecmp(old_te_val, "chunked") != 0) { |
801 |
if (*old_te_val && strcasecmp(*old_te_val, "chunked") != 0) { |
776 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) |
802 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) |
777 |
"%s Transfer-Encoding is not supported", old_te_val); |
803 |
"%s Transfer-Encoding is not supported", *old_te_val); |
778 |
return HTTP_INTERNAL_SERVER_ERROR; |
804 |
return HTTP_INTERNAL_SERVER_ERROR; |
779 |
} |
805 |
} |
780 |
|
806 |
|
781 |
if (old_cl_val && old_te_val) { |
807 |
if (*old_cl_val && *old_te_val) { |
782 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) |
808 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) |
783 |
"client %s (%s) requested Transfer-Encoding " |
809 |
"client %s (%s) requested Transfer-Encoding " |
784 |
"chunked body with Content-Length (C-L ignored)", |
810 |
"chunked body with Content-Length (C-L ignored)", |
785 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
811 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
786 |
apr_table_unset(r->headers_in, "Content-Length"); |
812 |
apr_table_unset(r->headers_in, "Content-Length"); |
787 |
old_cl_val = NULL; |
813 |
*old_cl_val = NULL; |
788 |
origin->keepalive = AP_CONN_CLOSE; |
814 |
origin->keepalive = AP_CONN_CLOSE; |
789 |
p_conn->close = 1; |
815 |
p_conn->close = 1; |
790 |
} |
816 |
} |
Lines 798-807
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
798 |
* reasonable size. |
824 |
* reasonable size. |
799 |
*/ |
825 |
*/ |
800 |
temp_brigade = apr_brigade_create(p, bucket_alloc); |
826 |
temp_brigade = apr_brigade_create(p, bucket_alloc); |
|
|
827 |
block = (flushall) ? APR_NONBLOCK_READ : APR_BLOCK_READ; |
801 |
do { |
828 |
do { |
802 |
status = ap_get_brigade(r->input_filters, temp_brigade, |
829 |
status = ap_get_brigade(r->input_filters, temp_brigade, |
803 |
AP_MODE_READBYTES, APR_BLOCK_READ, |
830 |
AP_MODE_READBYTES, block, |
804 |
MAX_MEM_SPOOL - bytes_read); |
831 |
MAX_MEM_SPOOL - bytes_read); |
|
|
832 |
/* ap_get_brigade will return success with an empty brigade |
833 |
* for a non-blocking read which would block |
834 |
*/ |
835 |
if (block == APR_NONBLOCK_READ |
836 |
&& (APR_STATUS_IS_EAGAIN(rv) |
837 |
|| (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade)))) { |
838 |
status = APR_SUCCESS; |
839 |
break; |
840 |
} |
805 |
if (status != APR_SUCCESS) { |
841 |
if (status != APR_SUCCESS) { |
806 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095) |
842 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095) |
807 |
"prefetch request body failed to %pI (%s)" |
843 |
"prefetch request body failed to %pI (%s)" |
Lines 876-882
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
876 |
* is absent, and the filters are unchanged (the body won't |
912 |
* is absent, and the filters are unchanged (the body won't |
877 |
* be resized by another content filter). |
913 |
* be resized by another content filter). |
878 |
*/ |
914 |
*/ |
879 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
915 |
if (!APR_BRIGADE_EMPTY(input_brigade) && |
|
|
916 |
APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
880 |
/* The whole thing fit, so our decision is trivial, use |
917 |
/* The whole thing fit, so our decision is trivial, use |
881 |
* the filtered bytes read from the client for the request |
918 |
* the filtered bytes read from the client for the request |
882 |
* body Content-Length. |
919 |
* body Content-Length. |
Lines 884-927
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
884 |
* If we expected no body, and read no body, do not set |
921 |
* If we expected no body, and read no body, do not set |
885 |
* the Content-Length. |
922 |
* the Content-Length. |
886 |
*/ |
923 |
*/ |
887 |
if (old_cl_val || old_te_val || bytes_read) { |
924 |
if (*old_cl_val || *old_te_val || bytes_read) { |
888 |
old_cl_val = apr_off_t_toa(r->pool, bytes_read); |
925 |
*old_cl_val = apr_off_t_toa(r->pool, bytes_read); |
889 |
} |
926 |
} |
890 |
rb_method = RB_STREAM_CL; |
927 |
*rb_method = RB_STREAM_CL; |
891 |
} |
928 |
} |
892 |
else if (old_te_val) { |
929 |
else if (*old_te_val) { |
893 |
if (force10 |
930 |
if (force10 |
894 |
|| (apr_table_get(r->subprocess_env, "proxy-sendcl") |
931 |
|| (!flushall |
895 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunks") |
932 |
&& apr_table_get(r->subprocess_env, "proxy-sendcl") |
896 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { |
933 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunks") |
897 |
rb_method = RB_SPOOL_CL; |
934 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { |
|
|
935 |
*rb_method = RB_SPOOL_CL; |
898 |
} |
936 |
} |
899 |
else { |
937 |
else { |
900 |
rb_method = RB_STREAM_CHUNKED; |
938 |
*rb_method = RB_STREAM_CHUNKED; |
901 |
} |
939 |
} |
902 |
} |
940 |
} |
903 |
else if (old_cl_val) { |
941 |
else if (*old_cl_val) { |
904 |
if (r->input_filters == r->proto_input_filters) { |
942 |
if (r->input_filters == r->proto_input_filters) { |
905 |
rb_method = RB_STREAM_CL; |
943 |
*rb_method = RB_STREAM_CL; |
906 |
} |
944 |
} |
907 |
else if (!force10 |
945 |
else if (!force10 |
908 |
&& (apr_table_get(r->subprocess_env, "proxy-sendchunks") |
946 |
&& (flushall |
|
|
947 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunks") |
909 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunked")) |
948 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunked")) |
910 |
&& !apr_table_get(r->subprocess_env, "proxy-sendcl")) { |
949 |
&& !apr_table_get(r->subprocess_env, "proxy-sendcl")) { |
911 |
rb_method = RB_STREAM_CHUNKED; |
950 |
*rb_method = RB_STREAM_CHUNKED; |
912 |
} |
951 |
} |
913 |
else { |
952 |
else { |
914 |
rb_method = RB_SPOOL_CL; |
953 |
*rb_method = RB_SPOOL_CL; |
915 |
} |
954 |
} |
916 |
} |
955 |
} |
917 |
else { |
956 |
else { |
918 |
/* This is an appropriate default; very efficient for no-body |
957 |
/* This is an appropriate default; very efficient for no-body |
919 |
* requests, and has the behavior that it will not add any C-L |
958 |
* requests, and has the behavior that it will not add any C-L |
920 |
* when the old_cl_val is NULL. |
959 |
* when the *old_cl_val is NULL. |
921 |
*/ |
960 |
*/ |
922 |
rb_method = RB_SPOOL_CL; |
961 |
*rb_method = RB_SPOOL_CL; |
923 |
} |
962 |
} |
924 |
|
963 |
|
|
|
964 |
/* If we have to spool the body, do it now, before connecting/reusing |
965 |
* the backend connection, not in the connect/reuse-then-forward window. |
966 |
*/ |
967 |
if (*rb_method == RB_SPOOL_CL) { |
968 |
rv = spool_reqbody_cl(p, r, header_brigade, input_brigade, |
969 |
(*old_cl_val != NULL) |
970 |
|| (*old_te_val != NULL) |
971 |
|| (bytes_read > 0)); |
972 |
if (rv != OK) { |
973 |
return rv; |
974 |
} |
975 |
} |
976 |
|
925 |
/* Yes I hate gotos. This is the subrequest shortcut */ |
977 |
/* Yes I hate gotos. This is the subrequest shortcut */ |
926 |
skip_body: |
978 |
skip_body: |
927 |
/* |
979 |
/* |
Lines 941-961
skip_body:
Link Here
|
941 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
993 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
942 |
} |
994 |
} |
943 |
|
995 |
|
|
|
996 |
return OK; |
997 |
} |
998 |
|
999 |
static |
1000 |
int ap_proxy_http_request(apr_pool_t *p, request_rec *r, |
1001 |
proxy_conn_rec *p_conn, |
1002 |
apr_bucket_brigade *header_brigade, |
1003 |
apr_bucket_brigade *input_brigade, |
1004 |
char *old_cl_val, char *old_te_val, |
1005 |
enum rb_methods rb_method, int flushall) |
1006 |
{ |
1007 |
int rv; |
1008 |
conn_rec *origin = p_conn->connection; |
1009 |
|
944 |
/* send the request body, if any. */ |
1010 |
/* send the request body, if any. */ |
945 |
switch(rb_method) { |
1011 |
switch(rb_method) { |
946 |
case RB_STREAM_CHUNKED: |
1012 |
case RB_STREAM_CHUNKED: |
947 |
rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, |
1013 |
rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, |
948 |
input_brigade); |
1014 |
input_brigade, flushall); |
949 |
break; |
1015 |
break; |
950 |
case RB_STREAM_CL: |
1016 |
case RB_STREAM_CL: |
951 |
rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, |
1017 |
rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, |
952 |
input_brigade, old_cl_val); |
1018 |
input_brigade, old_cl_val, flushall); |
953 |
break; |
1019 |
break; |
954 |
case RB_SPOOL_CL: |
1020 |
case RB_SPOOL_CL: |
955 |
rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade, |
1021 |
/* This is all a single brigade, pass with flush flagged */ |
956 |
input_brigade, (old_cl_val != NULL) |
1022 |
rv = ap_proxy_pass_brigade(r->connection->bucket_alloc, |
957 |
|| (old_te_val != NULL) |
1023 |
r, p_conn, origin, header_brigade, 1); |
958 |
|| (bytes_read > 0)); |
|
|
959 |
break; |
1024 |
break; |
960 |
default: |
1025 |
default: |
961 |
/* shouldn't be possible */ |
1026 |
/* shouldn't be possible */ |
Lines 964-969
skip_body:
Link Here
|
964 |
} |
1029 |
} |
965 |
|
1030 |
|
966 |
if (rv != OK) { |
1031 |
if (rv != OK) { |
|
|
1032 |
conn_rec *c = r->connection; |
967 |
/* apr_status_t value has been logged in lower level method */ |
1033 |
/* apr_status_t value has been logged in lower level method */ |
968 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) |
1034 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) |
969 |
"pass request body failed to %pI (%s) from %s (%s)", |
1035 |
"pass request body failed to %pI (%s) from %s (%s)", |
Lines 1878-1887
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1878 |
char *scheme; |
1944 |
char *scheme; |
1879 |
const char *proxy_function; |
1945 |
const char *proxy_function; |
1880 |
const char *u; |
1946 |
const char *u; |
|
|
1947 |
apr_bucket_brigade *header_brigade, *header_bb; |
1948 |
apr_bucket_brigade *input_brigade, *input_bb; |
1881 |
proxy_conn_rec *backend = NULL; |
1949 |
proxy_conn_rec *backend = NULL; |
1882 |
int is_ssl = 0; |
1950 |
int is_ssl = 0; |
1883 |
conn_rec *c = r->connection; |
1951 |
conn_rec *c = r->connection; |
1884 |
int retry = 0; |
1952 |
int retry = 0; |
|
|
1953 |
char *old_cl_val = NULL, *old_te_val = NULL; |
1954 |
enum rb_methods rb_method = RB_INIT; |
1955 |
char *locurl = url; |
1956 |
int flushall = 0; |
1957 |
int toclose = 0; |
1885 |
/* |
1958 |
/* |
1886 |
* Use a shorter-lived pool to reduce memory usage |
1959 |
* Use a shorter-lived pool to reduce memory usage |
1887 |
* and avoid a memory leak |
1960 |
* and avoid a memory leak |
Lines 1948-1963
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1948 |
backend->close = 1; |
2021 |
backend->close = 1; |
1949 |
} |
2022 |
} |
1950 |
|
2023 |
|
|
|
2024 |
if (apr_table_get(r->subprocess_env, "proxy-flushall")) { |
2025 |
flushall = 1; |
2026 |
} |
2027 |
|
2028 |
/* Step One: Determine Who To Connect To */ |
2029 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, |
2030 |
uri, &locurl, proxyname, |
2031 |
proxyport, server_portstr, |
2032 |
sizeof(server_portstr))) != OK) |
2033 |
goto cleanup; |
2034 |
|
2035 |
/* Step Once: Prefetch (partially) the request body so to increase the |
2036 |
* chances to get whole (or enough) body and determine Content-Length vs |
2037 |
* chunked or spool. By doing this before connecting or reusing a backend |
2038 |
* connection, minimize the delay between checking whether this connection |
2039 |
* is still alive and the first packet sent, should the link be slow or |
2040 |
* some input filter retain the data. |
2041 |
*/ |
2042 |
input_brigade = apr_brigade_create(p, c->bucket_alloc); |
2043 |
header_brigade = apr_brigade_create(p, c->bucket_alloc); |
2044 |
if ((status = ap_proxy_http_prefetch(p, r, backend, worker, conf, uri, |
2045 |
locurl, server_portstr, header_brigade, input_brigade, |
2046 |
&old_cl_val, &old_te_val, &rb_method, flushall)) != OK) { |
2047 |
goto cleanup; |
2048 |
} |
2049 |
|
2050 |
/* XXX: Reset backend->close now, since ap_proxy_http_prefetch() sets it to |
2051 |
* disable the reuse of the connection after this request (no keep-alive), |
2052 |
* not to close any reusable connection before this request. However assure |
2053 |
* what is expected later by using a local flag and do the right thing when |
2054 |
* ap_proxy_connect_backend (below) provides the connection to close. |
2055 |
*/ |
2056 |
toclose = backend->close; |
2057 |
backend->close = 0; |
2058 |
|
1951 |
while (retry < 2) { |
2059 |
while (retry < 2) { |
1952 |
char *locurl = url; |
2060 |
conn_rec *backconn; |
1953 |
|
2061 |
|
1954 |
/* Step One: Determine Who To Connect To */ |
2062 |
if (retry) { |
1955 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, |
2063 |
char *newurl = url; |
1956 |
uri, &locurl, proxyname, |
|
|
1957 |
proxyport, server_portstr, |
1958 |
sizeof(server_portstr))) != OK) |
1959 |
break; |
1960 |
|
2064 |
|
|
|
2065 |
/* Step One-Retry: Redetermine Who To Connect To */ |
2066 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, |
2067 |
backend, uri, &newurl, proxyname, proxyport, |
2068 |
server_portstr, sizeof(server_portstr))) != OK) |
2069 |
break; |
2070 |
|
2071 |
/* XXX: the code assumes locurl is not changed during the loop, |
2072 |
* or ap_proxy_http_prefetch() would have to be called every time, |
2073 |
* and header_brigade be changed accordingly... |
2074 |
*/ |
2075 |
AP_DEBUG_ASSERT(strcmp(newurl, locurl) == 0); |
2076 |
} |
2077 |
|
1961 |
/* Step Two: Make the Connection */ |
2078 |
/* Step Two: Make the Connection */ |
1962 |
if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { |
2079 |
if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { |
1963 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114) |
2080 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114) |
Lines 1968-1977
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1968 |
} |
2085 |
} |
1969 |
|
2086 |
|
1970 |
/* Step Three: Create conn_rec */ |
2087 |
/* Step Three: Create conn_rec */ |
1971 |
if (!backend->connection) { |
2088 |
backconn = backend->connection; |
|
|
2089 |
if (!backconn) { |
1972 |
if ((status = ap_proxy_connection_create(proxy_function, backend, |
2090 |
if ((status = ap_proxy_connection_create(proxy_function, backend, |
1973 |
c, r->server)) != OK) |
2091 |
c, r->server)) != OK) |
1974 |
break; |
2092 |
break; |
|
|
2093 |
backconn = backend->connection; |
2094 |
|
1975 |
/* |
2095 |
/* |
1976 |
* On SSL connections set a note on the connection what CN is |
2096 |
* On SSL connections set a note on the connection what CN is |
1977 |
* requested, such that mod_ssl can check if it is requested to do |
2097 |
* requested, such that mod_ssl can check if it is requested to do |
Lines 1984-1995
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1984 |
} |
2104 |
} |
1985 |
} |
2105 |
} |
1986 |
|
2106 |
|
|
|
2107 |
/* Don't recycle the connection if prefetch (above) told not to do so */ |
2108 |
if (toclose) { |
2109 |
backend->close = 1; |
2110 |
backconn->keepalive = AP_CONN_CLOSE; |
2111 |
} |
2112 |
|
2113 |
/* Preserve the header/input brigades since they may be retried. */ |
2114 |
header_bb = apr_brigade_create(p, backconn->bucket_alloc); |
2115 |
proxy_buckets_lifetime_transform(r, header_brigade, header_bb); |
2116 |
input_bb = apr_brigade_create(p, backconn->bucket_alloc); |
2117 |
proxy_buckets_lifetime_transform(r, input_brigade, input_bb); |
2118 |
|
1987 |
/* Step Four: Send the Request |
2119 |
/* Step Four: Send the Request |
1988 |
* On the off-chance that we forced a 100-Continue as a |
2120 |
* On the off-chance that we forced a 100-Continue as a |
1989 |
* kinda HTTP ping test, allow for retries |
2121 |
* kinda HTTP ping test, allow for retries |
1990 |
*/ |
2122 |
*/ |
1991 |
if ((status = ap_proxy_http_request(p, r, backend, worker, |
2123 |
if ((status = ap_proxy_http_request(p, r, backend, header_bb, input_bb, |
1992 |
conf, uri, locurl, server_portstr)) != OK) { |
2124 |
old_cl_val, old_te_val, rb_method, |
|
|
2125 |
flushall)) != OK) { |
1993 |
if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->s->ping_timeout_set) { |
2126 |
if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->s->ping_timeout_set) { |
1994 |
backend->close = 1; |
2127 |
backend->close = 1; |
1995 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO(01115) |
2128 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO(01115) |
Lines 2000-2006
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2000 |
} else { |
2133 |
} else { |
2001 |
break; |
2134 |
break; |
2002 |
} |
2135 |
} |
2003 |
|
|
|
2004 |
} |
2136 |
} |
2005 |
|
2137 |
|
2006 |
/* Step Five: Receive the Response... Fall thru to cleanup */ |
2138 |
/* Step Five: Receive the Response... Fall thru to cleanup */ |