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 654-661
static int spool_reqbody_cl(apr_pool_t *p,
Link Here
|
654 |
* FLUSH |
678 |
* FLUSH |
655 |
* EOS |
679 |
* EOS |
656 |
* |
680 |
* |
657 |
* If an other bucket type is found its type is logged as a debug message |
681 |
* If an other bucket type is found its type is logged as an error message |
658 |
* and APR_EGENERAL is returned. |
682 |
* and APR_INCOMPLETE is returned. |
659 |
*/ |
683 |
*/ |
660 |
static apr_status_t proxy_buckets_lifetime_transform(request_rec *r, |
684 |
static apr_status_t proxy_buckets_lifetime_transform(request_rec *r, |
661 |
apr_bucket_brigade *from, apr_bucket_brigade *to) |
685 |
apr_bucket_brigade *from, apr_bucket_brigade *to) |
Lines 664-721
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
664 |
apr_bucket *new; |
688 |
apr_bucket *new; |
665 |
const char *data; |
689 |
const char *data; |
666 |
apr_size_t bytes; |
690 |
apr_size_t bytes; |
667 |
apr_status_t rv = APR_SUCCESS; |
691 |
apr_status_t status, rv = APR_SUCCESS; |
|
|
692 |
int to_ancestor = apr_pool_is_ancestor(to->p, from->p); |
668 |
|
693 |
|
669 |
apr_brigade_cleanup(to); |
694 |
apr_brigade_cleanup(to); |
670 |
for (e = APR_BRIGADE_FIRST(from); |
695 |
for (e = APR_BRIGADE_FIRST(from); |
671 |
e != APR_BRIGADE_SENTINEL(from); |
696 |
e != APR_BRIGADE_SENTINEL(from); |
672 |
e = APR_BUCKET_NEXT(e)) { |
697 |
e = APR_BUCKET_NEXT(e)) { |
673 |
if (!APR_BUCKET_IS_METADATA(e)) { |
698 |
if (!APR_BUCKET_IS_METADATA(e)) { |
674 |
apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ); |
699 |
if (to_ancestor && e->list == to->bucket_alloc) { |
675 |
new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc); |
700 |
status = apr_bucket_copy(e, &new); |
|
|
701 |
if (status != APR_SUCCESS) { |
702 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() |
703 |
"Can't copy bucket of type %s in" |
704 |
" proxy_buckets_lifetime_transform", |
705 |
e->type->name); |
706 |
return status; |
707 |
} |
708 |
} |
709 |
else { |
710 |
status = apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ); |
711 |
if (status != APR_SUCCESS) { |
712 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() |
713 |
"Can't read bucket of type %s in" |
714 |
" proxy_buckets_lifetime_transform", |
715 |
e->type->name); |
716 |
return status; |
717 |
} |
718 |
new = apr_bucket_transient_create(data, bytes, |
719 |
to->bucket_alloc); |
720 |
} |
676 |
APR_BRIGADE_INSERT_TAIL(to, new); |
721 |
APR_BRIGADE_INSERT_TAIL(to, new); |
677 |
} |
722 |
} |
678 |
else if (APR_BUCKET_IS_FLUSH(e)) { |
723 |
else if (APR_BUCKET_IS_FLUSH(e)) { |
679 |
new = apr_bucket_flush_create(r->connection->bucket_alloc); |
724 |
new = apr_bucket_flush_create(to->bucket_alloc); |
680 |
APR_BRIGADE_INSERT_TAIL(to, new); |
725 |
APR_BRIGADE_INSERT_TAIL(to, new); |
681 |
} |
726 |
} |
682 |
else if (APR_BUCKET_IS_EOS(e)) { |
727 |
else if (APR_BUCKET_IS_EOS(e)) { |
683 |
new = apr_bucket_eos_create(r->connection->bucket_alloc); |
728 |
new = apr_bucket_eos_create(to->bucket_alloc); |
684 |
APR_BRIGADE_INSERT_TAIL(to, new); |
729 |
APR_BRIGADE_INSERT_TAIL(to, new); |
685 |
} |
730 |
} |
686 |
else { |
731 |
else { |
687 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964) |
732 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964) |
688 |
"Unhandled bucket type of type %s in" |
733 |
"Unhandled bucket of type %s in" |
689 |
" proxy_buckets_lifetime_transform", e->type->name); |
734 |
" proxy_buckets_lifetime_transform", |
|
|
735 |
e->type->name); |
690 |
apr_bucket_delete(e); |
736 |
apr_bucket_delete(e); |
691 |
rv = APR_EGENERAL; |
737 |
rv = APR_INCOMPLETE; |
692 |
} |
738 |
} |
693 |
} |
739 |
} |
694 |
return rv; |
740 |
return rv; |
695 |
} |
741 |
} |
696 |
|
742 |
|
697 |
static |
743 |
enum rb_methods { |
698 |
int ap_proxy_http_request(apr_pool_t *p, request_rec *r, |
744 |
RB_INIT, |
699 |
proxy_conn_rec *p_conn, proxy_worker *worker, |
745 |
RB_STREAM_CL, |
700 |
proxy_server_conf *conf, |
746 |
RB_STREAM_CHUNKED, |
701 |
apr_uri_t *uri, |
747 |
RB_SPOOL_CL |
702 |
char *url, char *server_portstr) |
748 |
}; |
|
|
749 |
|
750 |
static int ap_proxy_http_prefetch(apr_pool_t *p, request_rec *r, |
751 |
proxy_conn_rec *p_conn, proxy_worker *worker, |
752 |
proxy_server_conf *conf, |
753 |
apr_uri_t *uri, |
754 |
char *url, char *server_portstr, |
755 |
apr_bucket_brigade *header_brigade, |
756 |
apr_bucket_brigade *input_brigade, |
757 |
char **old_cl_val, char **old_te_val, |
758 |
enum rb_methods *rb_method, int flushall) |
703 |
{ |
759 |
{ |
704 |
conn_rec *c = r->connection; |
760 |
conn_rec *c = r->connection; |
705 |
apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; |
761 |
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; |
762 |
apr_bucket_brigade *temp_brigade; |
709 |
apr_bucket *e; |
763 |
apr_bucket *e; |
710 |
char *buf; |
764 |
char *buf; |
711 |
apr_status_t status; |
765 |
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; |
766 |
apr_off_t bytes_read = 0; |
717 |
apr_off_t bytes; |
767 |
apr_off_t bytes; |
718 |
int force10, rv; |
768 |
int force10, rv; |
|
|
769 |
apr_read_type_e block; |
719 |
conn_rec *origin = p_conn->connection; |
770 |
conn_rec *origin = p_conn->connection; |
720 |
|
771 |
|
721 |
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { |
772 |
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; |
778 |
force10 = 0; |
728 |
} |
779 |
} |
729 |
|
780 |
|
730 |
header_brigade = apr_brigade_create(p, bucket_alloc); |
|
|
731 |
rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, |
781 |
rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, |
732 |
worker, conf, uri, url, server_portstr, |
782 |
worker, conf, uri, url, server_portstr, |
733 |
&old_cl_val, &old_te_val); |
783 |
old_cl_val, old_te_val); |
734 |
if (rv != OK) { |
784 |
if (rv != OK) { |
735 |
return rv; |
785 |
return rv; |
736 |
} |
786 |
} |
737 |
|
787 |
|
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. |
788 |
/* sub-requests never use keepalives, and mustn't pass request bodies. |
742 |
* Because the new logic looks at input_brigade, we will self-terminate |
789 |
* Because the new logic looks at input_brigade, we will self-terminate |
743 |
* input_brigade and jump past all of the request body logic... |
790 |
* input_brigade and jump past all of the request body logic... |
Lines 750-758
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
750 |
if (!r->kept_body && r->main) { |
797 |
if (!r->kept_body && r->main) { |
751 |
/* XXX: Why DON'T sub-requests use keepalives? */ |
798 |
/* XXX: Why DON'T sub-requests use keepalives? */ |
752 |
p_conn->close = 1; |
799 |
p_conn->close = 1; |
753 |
old_cl_val = NULL; |
800 |
*old_cl_val = NULL; |
754 |
old_te_val = NULL; |
801 |
*old_te_val = NULL; |
755 |
rb_method = RB_STREAM_CL; |
802 |
*rb_method = RB_STREAM_CL; |
756 |
e = apr_bucket_eos_create(input_brigade->bucket_alloc); |
803 |
e = apr_bucket_eos_create(input_brigade->bucket_alloc); |
757 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
804 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
758 |
goto skip_body; |
805 |
goto skip_body; |
Lines 766-783
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
766 |
* encoding has been done by the extensions' handler, and |
813 |
* encoding has been done by the extensions' handler, and |
767 |
* do not modify add_te_chunked's logic |
814 |
* do not modify add_te_chunked's logic |
768 |
*/ |
815 |
*/ |
769 |
if (old_te_val && strcasecmp(old_te_val, "chunked") != 0) { |
816 |
if (*old_te_val && strcasecmp(*old_te_val, "chunked") != 0) { |
770 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) |
817 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) |
771 |
"%s Transfer-Encoding is not supported", old_te_val); |
818 |
"%s Transfer-Encoding is not supported", *old_te_val); |
772 |
return HTTP_INTERNAL_SERVER_ERROR; |
819 |
return HTTP_INTERNAL_SERVER_ERROR; |
773 |
} |
820 |
} |
774 |
|
821 |
|
775 |
if (old_cl_val && old_te_val) { |
822 |
if (*old_cl_val && *old_te_val) { |
776 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) |
823 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) |
777 |
"client %s (%s) requested Transfer-Encoding " |
824 |
"client %s (%s) requested Transfer-Encoding " |
778 |
"chunked body with Content-Length (C-L ignored)", |
825 |
"chunked body with Content-Length (C-L ignored)", |
779 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
826 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
780 |
old_cl_val = NULL; |
827 |
*old_cl_val = NULL; |
781 |
origin->keepalive = AP_CONN_CLOSE; |
828 |
origin->keepalive = AP_CONN_CLOSE; |
782 |
p_conn->close = 1; |
829 |
p_conn->close = 1; |
783 |
} |
830 |
} |
Lines 791-800
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
791 |
* reasonable size. |
838 |
* reasonable size. |
792 |
*/ |
839 |
*/ |
793 |
temp_brigade = apr_brigade_create(p, bucket_alloc); |
840 |
temp_brigade = apr_brigade_create(p, bucket_alloc); |
|
|
841 |
block = (flushall) ? APR_NONBLOCK_READ : APR_BLOCK_READ; |
794 |
do { |
842 |
do { |
795 |
status = ap_get_brigade(r->input_filters, temp_brigade, |
843 |
status = ap_get_brigade(r->input_filters, temp_brigade, |
796 |
AP_MODE_READBYTES, APR_BLOCK_READ, |
844 |
AP_MODE_READBYTES, block, |
797 |
MAX_MEM_SPOOL - bytes_read); |
845 |
MAX_MEM_SPOOL - bytes_read); |
|
|
846 |
/* ap_get_brigade will return success with an empty brigade |
847 |
* for a non-blocking read which would block |
848 |
*/ |
849 |
if (block == APR_NONBLOCK_READ |
850 |
&& (APR_STATUS_IS_EAGAIN(status) |
851 |
|| (status == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade)))) { |
852 |
status = APR_SUCCESS; |
853 |
break; |
854 |
} |
798 |
if (status != APR_SUCCESS) { |
855 |
if (status != APR_SUCCESS) { |
799 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095) |
856 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095) |
800 |
"prefetch request body failed to %pI (%s)" |
857 |
"prefetch request body failed to %pI (%s)" |
Lines 832-838
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
832 |
* (an arbitrary value.) |
889 |
* (an arbitrary value.) |
833 |
*/ |
890 |
*/ |
834 |
} while ((bytes_read < MAX_MEM_SPOOL - 80) |
891 |
} while ((bytes_read < MAX_MEM_SPOOL - 80) |
835 |
&& !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))); |
892 |
&& !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)) |
|
|
893 |
&& !flushall); |
836 |
|
894 |
|
837 |
/* Use chunked request body encoding or send a content-length body? |
895 |
/* Use chunked request body encoding or send a content-length body? |
838 |
* |
896 |
* |
Lines 869-875
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
869 |
* is absent, and the filters are unchanged (the body won't |
927 |
* is absent, and the filters are unchanged (the body won't |
870 |
* be resized by another content filter). |
928 |
* be resized by another content filter). |
871 |
*/ |
929 |
*/ |
872 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
930 |
if (!APR_BRIGADE_EMPTY(input_brigade) && |
|
|
931 |
APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
873 |
/* The whole thing fit, so our decision is trivial, use |
932 |
/* The whole thing fit, so our decision is trivial, use |
874 |
* the filtered bytes read from the client for the request |
933 |
* the filtered bytes read from the client for the request |
875 |
* body Content-Length. |
934 |
* body Content-Length. |
Lines 877-920
static apr_status_t proxy_buckets_lifetime_transfo
Link Here
|
877 |
* If we expected no body, and read no body, do not set |
936 |
* If we expected no body, and read no body, do not set |
878 |
* the Content-Length. |
937 |
* the Content-Length. |
879 |
*/ |
938 |
*/ |
880 |
if (old_cl_val || old_te_val || bytes_read) { |
939 |
if (*old_cl_val || *old_te_val || bytes_read) { |
881 |
old_cl_val = apr_off_t_toa(r->pool, bytes_read); |
940 |
*old_cl_val = apr_off_t_toa(r->pool, bytes_read); |
882 |
} |
941 |
} |
883 |
rb_method = RB_STREAM_CL; |
942 |
*rb_method = RB_STREAM_CL; |
884 |
} |
943 |
} |
885 |
else if (old_te_val) { |
944 |
else if (*old_te_val) { |
886 |
if (force10 |
945 |
if (force10 |
887 |
|| (apr_table_get(r->subprocess_env, "proxy-sendcl") |
946 |
|| (!flushall |
888 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunks") |
947 |
&& apr_table_get(r->subprocess_env, "proxy-sendcl") |
889 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { |
948 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunks") |
890 |
rb_method = RB_SPOOL_CL; |
949 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { |
|
|
950 |
*rb_method = RB_SPOOL_CL; |
891 |
} |
951 |
} |
892 |
else { |
952 |
else { |
893 |
rb_method = RB_STREAM_CHUNKED; |
953 |
*rb_method = RB_STREAM_CHUNKED; |
894 |
} |
954 |
} |
895 |
} |
955 |
} |
896 |
else if (old_cl_val) { |
956 |
else if (*old_cl_val) { |
897 |
if (r->input_filters == r->proto_input_filters) { |
957 |
if (r->input_filters == r->proto_input_filters) { |
898 |
rb_method = RB_STREAM_CL; |
958 |
*rb_method = RB_STREAM_CL; |
899 |
} |
959 |
} |
900 |
else if (!force10 |
960 |
else if (!force10 |
901 |
&& (apr_table_get(r->subprocess_env, "proxy-sendchunks") |
961 |
&& (flushall |
|
|
962 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunks") |
902 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunked")) |
963 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunked")) |
903 |
&& !apr_table_get(r->subprocess_env, "proxy-sendcl")) { |
964 |
&& !apr_table_get(r->subprocess_env, "proxy-sendcl")) { |
904 |
rb_method = RB_STREAM_CHUNKED; |
965 |
*rb_method = RB_STREAM_CHUNKED; |
905 |
} |
966 |
} |
906 |
else { |
967 |
else { |
907 |
rb_method = RB_SPOOL_CL; |
968 |
*rb_method = RB_SPOOL_CL; |
908 |
} |
969 |
} |
909 |
} |
970 |
} |
910 |
else { |
971 |
else { |
911 |
/* This is an appropriate default; very efficient for no-body |
972 |
/* This is an appropriate default; very efficient for no-body |
912 |
* requests, and has the behavior that it will not add any C-L |
973 |
* requests, and has the behavior that it will not add any C-L |
913 |
* when the old_cl_val is NULL. |
974 |
* when the *old_cl_val is NULL. |
914 |
*/ |
975 |
*/ |
915 |
rb_method = RB_SPOOL_CL; |
976 |
*rb_method = RB_SPOOL_CL; |
916 |
} |
977 |
} |
917 |
|
978 |
|
|
|
979 |
/* If we have to spool the body, do it now, before connecting/reusing |
980 |
* the backend connection, not in the connect/reuse-then-forward window. |
981 |
*/ |
982 |
if (*rb_method == RB_SPOOL_CL) { |
983 |
rv = spool_reqbody_cl(p, r, header_brigade, input_brigade, |
984 |
(bytes_read > 0) |
985 |
|| (*old_cl_val != NULL) |
986 |
|| (*old_te_val != NULL)); |
987 |
if (rv != OK) { |
988 |
return rv; |
989 |
} |
990 |
} |
991 |
|
918 |
/* Yes I hate gotos. This is the subrequest shortcut */ |
992 |
/* Yes I hate gotos. This is the subrequest shortcut */ |
919 |
skip_body: |
993 |
skip_body: |
920 |
/* |
994 |
/* |
Lines 934-954
skip_body:
Link Here
|
934 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
1008 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
935 |
} |
1009 |
} |
936 |
|
1010 |
|
|
|
1011 |
return OK; |
1012 |
} |
1013 |
|
1014 |
static |
1015 |
int ap_proxy_http_request(apr_pool_t *p, request_rec *r, |
1016 |
proxy_conn_rec *p_conn, |
1017 |
apr_bucket_brigade *header_brigade, |
1018 |
apr_bucket_brigade *input_brigade, |
1019 |
char *old_cl_val, char *old_te_val, |
1020 |
enum rb_methods rb_method, int flushall) |
1021 |
{ |
1022 |
int rv; |
1023 |
conn_rec *origin = p_conn->connection; |
1024 |
|
937 |
/* send the request body, if any. */ |
1025 |
/* send the request body, if any. */ |
938 |
switch(rb_method) { |
1026 |
switch(rb_method) { |
939 |
case RB_STREAM_CHUNKED: |
1027 |
case RB_STREAM_CHUNKED: |
940 |
rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, |
1028 |
rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, |
941 |
input_brigade); |
1029 |
input_brigade, flushall); |
942 |
break; |
1030 |
break; |
943 |
case RB_STREAM_CL: |
1031 |
case RB_STREAM_CL: |
944 |
rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, |
1032 |
rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, |
945 |
input_brigade, old_cl_val); |
1033 |
input_brigade, old_cl_val, flushall); |
946 |
break; |
1034 |
break; |
947 |
case RB_SPOOL_CL: |
1035 |
case RB_SPOOL_CL: |
948 |
rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade, |
1036 |
/* This is all a single brigade, pass with flush flagged */ |
949 |
input_brigade, (old_cl_val != NULL) |
1037 |
rv = ap_proxy_pass_brigade(r->connection->bucket_alloc, |
950 |
|| (old_te_val != NULL) |
1038 |
r, p_conn, origin, header_brigade, 1); |
951 |
|| (bytes_read > 0)); |
|
|
952 |
break; |
1039 |
break; |
953 |
default: |
1040 |
default: |
954 |
/* shouldn't be possible */ |
1041 |
/* shouldn't be possible */ |
Lines 957-962
skip_body:
Link Here
|
957 |
} |
1044 |
} |
958 |
|
1045 |
|
959 |
if (rv != OK) { |
1046 |
if (rv != OK) { |
|
|
1047 |
conn_rec *c = r->connection; |
960 |
/* apr_status_t value has been logged in lower level method */ |
1048 |
/* apr_status_t value has been logged in lower level method */ |
961 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) |
1049 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) |
962 |
"pass request body failed to %pI (%s) from %s (%s)", |
1050 |
"pass request body failed to %pI (%s) from %s (%s)", |
Lines 1881-1890
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1881 |
char *scheme; |
1969 |
char *scheme; |
1882 |
const char *proxy_function; |
1970 |
const char *proxy_function; |
1883 |
const char *u; |
1971 |
const char *u; |
|
|
1972 |
apr_bucket_brigade *header_brigade, *header_bb = NULL; |
1973 |
apr_bucket_brigade *input_brigade, *input_bb = NULL; |
1884 |
proxy_conn_rec *backend = NULL; |
1974 |
proxy_conn_rec *backend = NULL; |
1885 |
int is_ssl = 0; |
1975 |
int is_ssl = 0; |
1886 |
conn_rec *c = r->connection; |
1976 |
conn_rec *c = r->connection; |
1887 |
int retry = 0; |
1977 |
int retry = 0; |
|
|
1978 |
char *old_cl_val = NULL, *old_te_val = NULL; |
1979 |
enum rb_methods rb_method = RB_INIT; |
1980 |
char *locurl = url; |
1981 |
int flushall = 0; |
1982 |
int toclose = 0; |
1888 |
/* |
1983 |
/* |
1889 |
* Use a shorter-lived pool to reduce memory usage |
1984 |
* Use a shorter-lived pool to reduce memory usage |
1890 |
* and avoid a memory leak |
1985 |
* and avoid a memory leak |
Lines 1951-1966
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1951 |
backend->close = 1; |
2046 |
backend->close = 1; |
1952 |
} |
2047 |
} |
1953 |
|
2048 |
|
|
|
2049 |
if (apr_table_get(r->subprocess_env, "proxy-flushall")) { |
2050 |
flushall = 1; |
2051 |
} |
2052 |
|
2053 |
/* Step One: Determine Who To Connect To */ |
2054 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, |
2055 |
uri, &locurl, proxyname, |
2056 |
proxyport, server_portstr, |
2057 |
sizeof(server_portstr))) != OK) |
2058 |
goto cleanup; |
2059 |
|
2060 |
/* Step Once: Prefetch (partially) the request body so to increase the |
2061 |
* chances to get the whole (or enough) body and determine Content-Length |
2062 |
* vs chunked or spool. By doing this before connecting or reusing a |
2063 |
* backend connection, minimize the delay between checking whether this |
2064 |
* connection is still alive and the first packet sent, should the link be |
2065 |
* slow or some input filter retain the data. |
2066 |
*/ |
2067 |
input_brigade = apr_brigade_create(p, c->bucket_alloc); |
2068 |
header_brigade = apr_brigade_create(p, c->bucket_alloc); |
2069 |
if ((status = ap_proxy_http_prefetch(p, r, backend, worker, conf, uri, |
2070 |
locurl, server_portstr, |
2071 |
header_brigade, input_brigade, |
2072 |
&old_cl_val, &old_te_val, &rb_method, |
2073 |
flushall)) != OK) { |
2074 |
goto cleanup; |
2075 |
} |
2076 |
|
2077 |
/* XXX: Reset backend->close now, since ap_proxy_http_prefetch() sets it to |
2078 |
* disable the reuse of the connection after this request (no keep-alive), |
2079 |
* not to close any reusable connection before this request. However assure |
2080 |
* what is expected later by using a local flag and do the right thing when |
2081 |
* ap_proxy_connect_backend (below) provides the connection to close. |
2082 |
*/ |
2083 |
toclose = backend->close; |
2084 |
backend->close = 0; |
2085 |
|
1954 |
while (retry < 2) { |
2086 |
while (retry < 2) { |
1955 |
char *locurl = url; |
2087 |
conn_rec *backconn; |
1956 |
|
2088 |
|
1957 |
/* Step One: Determine Who To Connect To */ |
2089 |
if (retry) { |
1958 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, |
2090 |
char *newurl = url; |
1959 |
uri, &locurl, proxyname, |
|
|
1960 |
proxyport, server_portstr, |
1961 |
sizeof(server_portstr))) != OK) |
1962 |
break; |
1963 |
|
2091 |
|
|
|
2092 |
/* Step One-Retry: Redetermine Who To Connect To */ |
2093 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, |
2094 |
backend, uri, &newurl, proxyname, proxyport, |
2095 |
server_portstr, sizeof(server_portstr))) != OK) |
2096 |
break; |
2097 |
|
2098 |
/* XXX: the code assumes locurl is not changed during the loop, |
2099 |
* or ap_proxy_http_prefetch() would have to be called every time, |
2100 |
* and header_brigade be changed accordingly... |
2101 |
*/ |
2102 |
AP_DEBUG_ASSERT(strcmp(newurl, locurl) == 0); |
2103 |
} |
2104 |
|
1964 |
/* Step Two: Make the Connection */ |
2105 |
/* Step Two: Make the Connection */ |
1965 |
if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { |
2106 |
if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { |
1966 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114) |
2107 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114) |
Lines 1971-1980
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1971 |
} |
2112 |
} |
1972 |
|
2113 |
|
1973 |
/* Step Three: Create conn_rec */ |
2114 |
/* Step Three: Create conn_rec */ |
1974 |
if (!backend->connection) { |
2115 |
backconn = backend->connection; |
|
|
2116 |
if (!backconn) { |
1975 |
if ((status = ap_proxy_connection_create(proxy_function, backend, |
2117 |
if ((status = ap_proxy_connection_create(proxy_function, backend, |
1976 |
c, r->server)) != OK) |
2118 |
c, r->server)) != OK) |
1977 |
break; |
2119 |
break; |
|
|
2120 |
backconn = backend->connection; |
2121 |
|
1978 |
/* |
2122 |
/* |
1979 |
* On SSL connections set a note on the connection what CN is |
2123 |
* On SSL connections set a note on the connection what CN is |
1980 |
* requested, such that mod_ssl can check if it is requested to do |
2124 |
* requested, such that mod_ssl can check if it is requested to do |
Lines 2002-2013
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2002 |
} |
2146 |
} |
2003 |
} |
2147 |
} |
2004 |
|
2148 |
|
|
|
2149 |
/* Don't recycle the connection if prefetch (above) told not to do so */ |
2150 |
if (toclose) { |
2151 |
backend->close = 1; |
2152 |
backconn->keepalive = AP_CONN_CLOSE; |
2153 |
} |
2154 |
|
2155 |
/* Preserve the header/input brigades since they may be retried. */ |
2156 |
if (header_bb) { |
2157 |
apr_brigade_cleanup(header_bb); |
2158 |
apr_brigade_cleanup(input_bb); |
2159 |
} |
2160 |
else { |
2161 |
header_bb = apr_brigade_create(p, c->bucket_alloc); |
2162 |
input_bb = apr_brigade_create(p, c->bucket_alloc); |
2163 |
} |
2164 |
proxy_buckets_lifetime_transform(r, header_brigade, header_bb); |
2165 |
proxy_buckets_lifetime_transform(r, input_brigade, input_bb); |
2166 |
|
2005 |
/* Step Four: Send the Request |
2167 |
/* Step Four: Send the Request |
2006 |
* On the off-chance that we forced a 100-Continue as a |
2168 |
* On the off-chance that we forced a 100-Continue as a |
2007 |
* kinda HTTP ping test, allow for retries |
2169 |
* kinda HTTP ping test, allow for retries |
2008 |
*/ |
2170 |
*/ |
2009 |
if ((status = ap_proxy_http_request(p, r, backend, worker, |
2171 |
if ((status = ap_proxy_http_request(p, r, backend, header_bb, input_bb, |
2010 |
conf, uri, locurl, server_portstr)) != OK) { |
2172 |
old_cl_val, old_te_val, rb_method, |
|
|
2173 |
flushall)) != OK) { |
2011 |
proxy_run_detach_backend(r, backend); |
2174 |
proxy_run_detach_backend(r, backend); |
2012 |
if ((status == HTTP_SERVICE_UNAVAILABLE) && |
2175 |
if ((status == HTTP_SERVICE_UNAVAILABLE) && |
2013 |
worker->s->ping_timeout_set && |
2176 |
worker->s->ping_timeout_set && |
Lines 2021-2027
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2021 |
} else { |
2184 |
} else { |
2022 |
break; |
2185 |
break; |
2023 |
} |
2186 |
} |
2024 |
|
|
|
2025 |
} |
2187 |
} |
2026 |
|
2188 |
|
2027 |
/* Step Five: Receive the Response... Fall thru to cleanup */ |
2189 |
/* Step Five: Receive the Response... Fall thru to cleanup */ |
Lines 2032-2037
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2032 |
} |
2194 |
} |
2033 |
|
2195 |
|
2034 |
/* Step Six: Clean Up */ |
2196 |
/* Step Six: Clean Up */ |
|
|
2197 |
if (header_bb) { |
2198 |
apr_brigade_destroy(header_bb); |
2199 |
apr_brigade_destroy(input_bb); |
2200 |
} |
2035 |
cleanup: |
2201 |
cleanup: |
2036 |
if (backend) { |
2202 |
if (backend) { |
2037 |
if (status != OK) |
2203 |
if (status != OK) |