Lines 229-258
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
229 |
|
229 |
|
230 |
#define MAX_MEM_SPOOL 16384 |
230 |
#define MAX_MEM_SPOOL 16384 |
231 |
|
231 |
|
232 |
static int stream_reqbody_chunked(apr_pool_t *p, |
232 |
typedef enum { |
233 |
request_rec *r, |
233 |
RB_INIT = 0, |
234 |
proxy_conn_rec *p_conn, |
234 |
RB_STREAM_CL, |
235 |
conn_rec *origin, |
235 |
RB_STREAM_CHUNKED, |
236 |
apr_bucket_brigade *header_brigade, |
236 |
RB_SPOOL_CL |
237 |
apr_bucket_brigade *input_brigade, |
237 |
} rb_methods; |
238 |
int flushall) |
238 |
|
|
|
239 |
typedef struct { |
240 |
apr_pool_t *p; |
241 |
request_rec *r; |
242 |
proxy_worker *worker; |
243 |
proxy_server_conf *sconf; |
244 |
|
245 |
char server_portstr[32]; |
246 |
proxy_conn_rec *backend; |
247 |
conn_rec *origin; |
248 |
|
249 |
rb_methods rb_method; |
250 |
apr_bucket_alloc_t *bucket_alloc; |
251 |
apr_bucket_brigade *header_brigade; |
252 |
apr_bucket_brigade *input_brigade; |
253 |
char *old_cl_val, *old_te_val; |
254 |
apr_off_t cl_val, bytes_spooled; |
255 |
|
256 |
int do_100_continue; |
257 |
int flushall; |
258 |
} proxy_http_req_t; |
259 |
|
260 |
static int stream_reqbody_chunked(proxy_http_req_t *req) |
239 |
{ |
261 |
{ |
|
|
262 |
request_rec *r = req->r; |
240 |
int seen_eos = 0, rv = OK; |
263 |
int seen_eos = 0, rv = OK; |
241 |
apr_size_t hdr_len; |
264 |
apr_size_t hdr_len; |
242 |
apr_off_t bytes; |
265 |
apr_off_t bytes; |
243 |
apr_status_t status; |
266 |
apr_status_t status; |
244 |
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; |
267 |
char chunk_hdr[20]; /* must be here due to transient bucket. */ |
|
|
268 |
proxy_conn_rec *p_conn = req->backend; |
269 |
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; |
270 |
apr_bucket_brigade *header_brigade = req->header_brigade; |
271 |
apr_bucket_brigade *input_brigade = req->input_brigade; |
245 |
apr_bucket_brigade *bb; |
272 |
apr_bucket_brigade *bb; |
246 |
apr_bucket *e; |
273 |
apr_bucket *e; |
247 |
|
274 |
|
248 |
add_te_chunked(p, bucket_alloc, header_brigade); |
|
|
249 |
terminate_headers(bucket_alloc, header_brigade); |
250 |
|
251 |
while (APR_BRIGADE_EMPTY(input_brigade) |
275 |
while (APR_BRIGADE_EMPTY(input_brigade) |
252 |
|| !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
276 |
|| !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
253 |
{ |
277 |
{ |
254 |
char chunk_hdr[20]; /* must be here due to transient bucket. */ |
278 |
int flush = req->flushall; |
255 |
int flush = flushall; |
|
|
256 |
|
279 |
|
257 |
if (!APR_BRIGADE_EMPTY(input_brigade)) { |
280 |
if (!APR_BRIGADE_EMPTY(input_brigade)) { |
258 |
/* If this brigade contains EOS, either stop or remove it. */ |
281 |
/* If this brigade contains EOS, either stop or remove it. */ |
Lines 259-267
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
259 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
282 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
260 |
seen_eos = 1; |
283 |
seen_eos = 1; |
261 |
|
284 |
|
262 |
/* The request is flushed below this loop with the EOS chunk */ |
|
|
263 |
flush = 0; |
264 |
|
265 |
/* We can't pass this EOS to the output_filters. */ |
285 |
/* We can't pass this EOS to the output_filters. */ |
266 |
e = APR_BRIGADE_LAST(input_brigade); |
286 |
e = APR_BRIGADE_LAST(input_brigade); |
267 |
apr_bucket_delete(e); |
287 |
apr_bucket_delete(e); |
Lines 269-274
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
269 |
|
289 |
|
270 |
apr_brigade_length(input_brigade, 1, &bytes); |
290 |
apr_brigade_length(input_brigade, 1, &bytes); |
271 |
|
291 |
|
|
|
292 |
/* Flush only if we did not get the requested #bytes. */ |
293 |
if (bytes < HUGE_STRING_LEN) { |
294 |
flush = 0; |
295 |
} |
296 |
|
272 |
hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr), |
297 |
hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr), |
273 |
"%" APR_UINT64_T_HEX_FMT CRLF, |
298 |
"%" APR_UINT64_T_HEX_FMT CRLF, |
274 |
(apr_uint64_t)bytes); |
299 |
(apr_uint64_t)bytes); |
Lines 285-323
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
285 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
310 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
286 |
} |
311 |
} |
287 |
|
312 |
|
288 |
if (header_brigade) { |
313 |
if (!APR_BRIGADE_EMPTY(header_brigade)) { |
289 |
/* we never sent the header brigade, so go ahead and |
314 |
/* we never sent the header brigade, so go ahead and |
290 |
* take care of that now |
315 |
* take care of that now |
291 |
*/ |
316 |
*/ |
292 |
bb = header_brigade; |
317 |
bb = header_brigade; |
|
|
318 |
APR_BRIGADE_CONCAT(bb, input_brigade); |
293 |
|
319 |
|
294 |
/* Flush now since we have the header and (enough of) the prefeched |
320 |
/* Flush now since we have the header and (enough of) the |
295 |
* body already, unless we are EOS since everything is to be |
321 |
* prefeched body, or racing KeepAliveTimeout on the backend |
296 |
* flushed below this loop with the EOS chunk. |
322 |
* side may kill our connection while we read more client data. |
297 |
*/ |
323 |
*/ |
298 |
flush = !seen_eos; |
324 |
flush = 1; |
299 |
|
|
|
300 |
/* |
301 |
* Save input_brigade in bb brigade. (At least) in the SSL case |
302 |
* input_brigade contains transient buckets whose data would get |
303 |
* overwritten during the next call of ap_get_brigade in the loop. |
304 |
* ap_save_brigade ensures these buckets to be set aside. |
305 |
* Calling ap_save_brigade with NULL as filter is OK, because |
306 |
* bb brigade already has been created and does not need to get |
307 |
* created by ap_save_brigade. |
308 |
*/ |
309 |
status = ap_save_brigade(NULL, &bb, &input_brigade, p); |
310 |
if (status != APR_SUCCESS) { |
311 |
return HTTP_INTERNAL_SERVER_ERROR; |
312 |
} |
313 |
|
314 |
header_brigade = NULL; |
315 |
} |
325 |
} |
316 |
else { |
326 |
else { |
317 |
bb = input_brigade; |
327 |
bb = input_brigade; |
318 |
} |
328 |
} |
319 |
|
329 |
|
320 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, flush); |
330 |
/* Once we hit EOS, flush below this loop with the EOS chunk. */ |
|
|
331 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, |
332 |
bb, flush && !seen_eos); |
321 |
if (rv != OK) { |
333 |
if (rv != OK) { |
322 |
return rv; |
334 |
return rv; |
323 |
} |
335 |
} |
Lines 341-347
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
341 |
} |
353 |
} |
342 |
} |
354 |
} |
343 |
|
355 |
|
344 |
if (header_brigade) { |
356 |
if (!APR_BRIGADE_EMPTY(header_brigade)) { |
345 |
/* we never sent the header brigade because there was no request body; |
357 |
/* we never sent the header brigade because there was no request body; |
346 |
* send it now |
358 |
* send it now |
347 |
*/ |
359 |
*/ |
Lines 369-426
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
369 |
} |
381 |
} |
370 |
|
382 |
|
371 |
/* Now we have headers-only, or the chunk EOS mark; flush it */ |
383 |
/* Now we have headers-only, or the chunk EOS mark; flush it */ |
372 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1); |
384 |
return ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, bb, 1); |
373 |
return rv; |
|
|
374 |
} |
385 |
} |
375 |
|
386 |
|
376 |
static int stream_reqbody_cl(apr_pool_t *p, |
387 |
static int stream_reqbody_cl(proxy_http_req_t *req) |
377 |
request_rec *r, |
|
|
378 |
proxy_conn_rec *p_conn, |
379 |
conn_rec *origin, |
380 |
apr_bucket_brigade *header_brigade, |
381 |
apr_bucket_brigade *input_brigade, |
382 |
char *old_cl_val, int flushall) |
383 |
{ |
388 |
{ |
|
|
389 |
request_rec *r = req->r; |
384 |
int seen_eos = 0, rv = 0; |
390 |
int seen_eos = 0, rv = 0; |
385 |
apr_status_t status = APR_SUCCESS; |
391 |
apr_status_t status = APR_SUCCESS; |
386 |
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; |
392 |
proxy_conn_rec *p_conn = req->backend; |
|
|
393 |
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; |
394 |
apr_bucket_brigade *header_brigade = req->header_brigade; |
395 |
apr_bucket_brigade *input_brigade = req->input_brigade; |
387 |
apr_bucket_brigade *bb; |
396 |
apr_bucket_brigade *bb; |
388 |
apr_bucket *e; |
397 |
apr_bucket *e; |
389 |
apr_off_t cl_val = 0; |
|
|
390 |
apr_off_t bytes; |
398 |
apr_off_t bytes; |
391 |
apr_off_t bytes_streamed = 0; |
399 |
apr_off_t bytes_streamed = 0; |
392 |
|
400 |
|
393 |
if (old_cl_val) { |
|
|
394 |
char *endstr; |
395 |
|
396 |
add_cl(p, bucket_alloc, header_brigade, old_cl_val); |
397 |
status = apr_strtoff(&cl_val, old_cl_val, &endstr, 10); |
398 |
|
399 |
if (status || *endstr || endstr == old_cl_val || cl_val < 0) { |
400 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085) |
401 |
"could not parse request Content-Length (%s)", |
402 |
old_cl_val); |
403 |
return HTTP_BAD_REQUEST; |
404 |
} |
405 |
} |
406 |
terminate_headers(bucket_alloc, header_brigade); |
407 |
|
408 |
while (APR_BRIGADE_EMPTY(input_brigade) |
401 |
while (APR_BRIGADE_EMPTY(input_brigade) |
409 |
|| !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
402 |
|| !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) |
410 |
{ |
403 |
{ |
411 |
int flush = flushall; |
404 |
int flush = req->flushall; |
412 |
|
405 |
|
413 |
if (!APR_BRIGADE_EMPTY(input_brigade)) { |
406 |
if (!APR_BRIGADE_EMPTY(input_brigade)) { |
414 |
apr_brigade_length(input_brigade, 1, &bytes); |
407 |
apr_brigade_length(input_brigade, 1, &bytes); |
415 |
bytes_streamed += bytes; |
408 |
bytes_streamed += bytes; |
416 |
|
409 |
|
|
|
410 |
/* Flush only if we did not get the requested #bytes. */ |
411 |
if (bytes < HUGE_STRING_LEN) { |
412 |
flush = 0; |
413 |
} |
414 |
|
417 |
/* If this brigade contains EOS, either stop or remove it. */ |
415 |
/* If this brigade contains EOS, either stop or remove it. */ |
418 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
416 |
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { |
419 |
seen_eos = 1; |
417 |
seen_eos = 1; |
420 |
|
418 |
|
421 |
/* Once we hit EOS, we are ready to flush. */ |
|
|
422 |
flush = 1; |
423 |
|
424 |
/* We can't pass this EOS to the output_filters. */ |
419 |
/* We can't pass this EOS to the output_filters. */ |
425 |
e = APR_BRIGADE_LAST(input_brigade); |
420 |
e = APR_BRIGADE_LAST(input_brigade); |
426 |
apr_bucket_delete(e); |
421 |
apr_bucket_delete(e); |
Lines 441-488
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
441 |
* |
436 |
* |
442 |
* Prevents HTTP Response Splitting. |
437 |
* Prevents HTTP Response Splitting. |
443 |
*/ |
438 |
*/ |
444 |
if (bytes_streamed > cl_val) { |
439 |
if (bytes_streamed > req->cl_val) { |
445 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01086) |
440 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01086) |
446 |
"read more bytes of request body than expected " |
441 |
"read more bytes of request body than expected " |
447 |
"(got %" APR_OFF_T_FMT ", expected " |
442 |
"(got %" APR_OFF_T_FMT ", expected " |
448 |
"%" APR_OFF_T_FMT ")", |
443 |
"%" APR_OFF_T_FMT ")", |
449 |
bytes_streamed, cl_val); |
444 |
bytes_streamed, req->cl_val); |
450 |
return HTTP_INTERNAL_SERVER_ERROR; |
445 |
return HTTP_INTERNAL_SERVER_ERROR; |
451 |
} |
446 |
} |
452 |
} |
447 |
} |
453 |
|
448 |
|
454 |
if (header_brigade) { |
449 |
if (!APR_BRIGADE_EMPTY(header_brigade)) { |
455 |
/* we never sent the header brigade, so go ahead and |
450 |
/* we never sent the header brigade, so go ahead and |
456 |
* take care of that now |
451 |
* take care of that now |
457 |
*/ |
452 |
*/ |
458 |
bb = header_brigade; |
453 |
bb = header_brigade; |
|
|
454 |
APR_BRIGADE_CONCAT(bb, input_brigade); |
459 |
|
455 |
|
460 |
/* Flush now since we have the header and (enough of) the prefeched |
456 |
/* Flush now since we have the header and (enough of) the |
461 |
* body already. |
457 |
* prefeched body, or racing KeepAliveTimeout on the backend |
|
|
458 |
* side may kill our connection while we read more client data. |
462 |
*/ |
459 |
*/ |
463 |
flush = 1; |
460 |
flush = 1; |
464 |
|
|
|
465 |
/* |
466 |
* Save input_brigade in bb brigade. (At least) in the SSL case |
467 |
* input_brigade contains transient buckets whose data would get |
468 |
* overwritten during the next call of ap_get_brigade in the loop. |
469 |
* ap_save_brigade ensures these buckets to be set aside. |
470 |
* Calling ap_save_brigade with NULL as filter is OK, because |
471 |
* bb brigade already has been created and does not need to get |
472 |
* created by ap_save_brigade. |
473 |
*/ |
474 |
status = ap_save_brigade(NULL, &bb, &input_brigade, p); |
475 |
if (status != APR_SUCCESS) { |
476 |
return HTTP_INTERNAL_SERVER_ERROR; |
477 |
} |
478 |
|
479 |
header_brigade = NULL; |
480 |
} |
461 |
} |
481 |
else { |
462 |
else { |
482 |
bb = input_brigade; |
463 |
bb = input_brigade; |
483 |
} |
464 |
} |
484 |
|
465 |
|
485 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, flush); |
466 |
/* Once we hit EOS, we are ready to flush. */ |
|
|
467 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, |
468 |
input_brigade, flush || seen_eos); |
486 |
if (rv != OK) { |
469 |
if (rv != OK) { |
487 |
return rv; |
470 |
return rv; |
488 |
} |
471 |
} |
Lines 506-512
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
506 |
} |
489 |
} |
507 |
} |
490 |
} |
508 |
|
491 |
|
509 |
if (bytes_streamed != cl_val) { |
492 |
if (bytes_streamed != req->cl_val) { |
510 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01087) |
493 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01087) |
511 |
"client %s given Content-Length did not match" |
494 |
"client %s given Content-Length did not match" |
512 |
" number of body bytes read", r->connection->client_ip); |
495 |
" number of body bytes read", r->connection->client_ip); |
Lines 513-541
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
513 |
return HTTP_BAD_REQUEST; |
496 |
return HTTP_BAD_REQUEST; |
514 |
} |
497 |
} |
515 |
|
498 |
|
516 |
if (header_brigade) { |
499 |
if (!APR_BRIGADE_EMPTY(header_brigade)) { |
517 |
/* we never sent the header brigade since there was no request |
500 |
/* we never sent the header brigade since there was no request |
518 |
* body; send it now with the flush flag |
501 |
* body; send it now with the flush flag |
519 |
*/ |
502 |
*/ |
520 |
bb = header_brigade; |
503 |
return ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, |
521 |
return(ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1)); |
504 |
header_brigade, 1); |
522 |
} |
505 |
} |
523 |
|
506 |
|
524 |
return OK; |
507 |
return OK; |
525 |
} |
508 |
} |
526 |
|
509 |
|
527 |
static int spool_reqbody_cl(apr_pool_t *p, |
510 |
static int spool_reqbody_cl(proxy_http_req_t *req) |
528 |
request_rec *r, |
|
|
529 |
apr_bucket_brigade *header_brigade, |
530 |
apr_bucket_brigade *input_brigade, |
531 |
int force_cl) |
532 |
{ |
511 |
{ |
|
|
512 |
apr_pool_t *p = req->p; |
513 |
request_rec *r = req->r; |
533 |
int seen_eos = 0; |
514 |
int seen_eos = 0; |
534 |
apr_status_t status = APR_SUCCESS; |
515 |
apr_status_t status = APR_SUCCESS; |
535 |
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; |
516 |
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; |
|
|
517 |
apr_bucket_brigade *input_brigade = req->input_brigade; |
536 |
apr_bucket_brigade *body_brigade; |
518 |
apr_bucket_brigade *body_brigade; |
537 |
apr_bucket *e; |
519 |
apr_bucket *e; |
538 |
apr_off_t bytes, bytes_spooled = 0, fsize = 0; |
520 |
apr_off_t bytes, fsize = 0; |
539 |
apr_file_t *tmpfile = NULL; |
521 |
apr_file_t *tmpfile = NULL; |
540 |
apr_off_t limit; |
522 |
apr_off_t limit; |
541 |
|
523 |
|
Lines 562-574
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
562 |
|
544 |
|
563 |
apr_brigade_length(input_brigade, 1, &bytes); |
545 |
apr_brigade_length(input_brigade, 1, &bytes); |
564 |
|
546 |
|
565 |
if (bytes_spooled + bytes > MAX_MEM_SPOOL) { |
547 |
if (req->bytes_spooled + bytes > MAX_MEM_SPOOL) { |
566 |
/* |
548 |
/* |
567 |
* LimitRequestBody does not affect Proxy requests (Should it?). |
549 |
* LimitRequestBody does not affect Proxy requests (Should it?). |
568 |
* Let it take effect if we decide to store the body in a |
550 |
* Let it take effect if we decide to store the body in a |
569 |
* temporary file on disk. |
551 |
* temporary file on disk. |
570 |
*/ |
552 |
*/ |
571 |
if (limit && (bytes_spooled + bytes > limit)) { |
553 |
if (limit && (req->bytes_spooled + bytes > limit)) { |
572 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088) |
554 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088) |
573 |
"Request body is larger than the configured " |
555 |
"Request body is larger than the configured " |
574 |
"limit of %" APR_OFF_T_FMT, limit); |
556 |
"limit of %" APR_OFF_T_FMT, limit); |
Lines 638-644
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
638 |
|
620 |
|
639 |
} |
621 |
} |
640 |
|
622 |
|
641 |
bytes_spooled += bytes; |
623 |
req->bytes_spooled += bytes; |
642 |
|
624 |
|
643 |
if (seen_eos) { |
625 |
if (seen_eos) { |
644 |
break; |
626 |
break; |
Lines 656-695
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
656 |
return ap_map_http_request_error(status, HTTP_BAD_REQUEST); |
638 |
return ap_map_http_request_error(status, HTTP_BAD_REQUEST); |
657 |
} |
639 |
} |
658 |
|
640 |
|
659 |
if (bytes_spooled || force_cl) { |
641 |
APR_BRIGADE_CONCAT(input_brigade, body_brigade); |
660 |
add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes_spooled)); |
|
|
661 |
} |
662 |
terminate_headers(bucket_alloc, header_brigade); |
663 |
APR_BRIGADE_CONCAT(header_brigade, body_brigade); |
664 |
if (tmpfile) { |
642 |
if (tmpfile) { |
665 |
apr_brigade_insert_file(header_brigade, tmpfile, 0, fsize, p); |
643 |
apr_brigade_insert_file(input_brigade, tmpfile, 0, fsize, p); |
666 |
} |
644 |
} |
667 |
if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) { |
645 |
if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) { |
668 |
e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); |
646 |
e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); |
669 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
647 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
670 |
} |
648 |
} |
671 |
return OK; |
649 |
return OK; |
672 |
} |
650 |
} |
673 |
|
651 |
|
674 |
enum rb_methods { |
652 |
static int ap_proxy_http_prefetch(proxy_http_req_t *req, |
675 |
RB_INIT = 0, |
653 |
apr_uri_t *uri, char *url) |
676 |
RB_STREAM_CL, |
|
|
677 |
RB_STREAM_CHUNKED, |
678 |
RB_SPOOL_CL |
679 |
}; |
680 |
|
681 |
static int ap_proxy_http_prefetch(apr_pool_t *p, request_rec *r, |
682 |
proxy_conn_rec *p_conn, proxy_worker *worker, |
683 |
proxy_server_conf *conf, |
684 |
apr_uri_t *uri, |
685 |
char *url, char *server_portstr, |
686 |
apr_bucket_brigade *header_brigade, |
687 |
apr_bucket_brigade *input_brigade, |
688 |
char **old_cl_val, char **old_te_val, |
689 |
enum rb_methods *rb_method, int flushall) |
690 |
{ |
654 |
{ |
|
|
655 |
apr_pool_t *p = req->p; |
656 |
request_rec *r = req->r; |
691 |
conn_rec *c = r->connection; |
657 |
conn_rec *c = r->connection; |
692 |
apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; |
658 |
proxy_conn_rec *p_conn = req->backend; |
|
|
659 |
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; |
660 |
apr_bucket_brigade *header_brigade = req->header_brigade; |
661 |
apr_bucket_brigade *input_brigade = req->input_brigade; |
693 |
apr_bucket_brigade *temp_brigade; |
662 |
apr_bucket_brigade *temp_brigade; |
694 |
apr_bucket *e; |
663 |
apr_bucket *e; |
695 |
char *buf; |
664 |
char *buf; |
Lines 709-716
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
709 |
} |
678 |
} |
710 |
|
679 |
|
711 |
rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, |
680 |
rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, |
712 |
worker, conf, uri, url, server_portstr, |
681 |
req->worker, req->sconf, |
713 |
old_cl_val, old_te_val); |
682 |
uri, url, req->server_portstr, |
|
|
683 |
&req->old_cl_val, &req->old_te_val); |
714 |
if (rv != OK) { |
684 |
if (rv != OK) { |
715 |
return rv; |
685 |
return rv; |
716 |
} |
686 |
} |
Lines 727-735
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
727 |
if (!r->kept_body && r->main) { |
697 |
if (!r->kept_body && r->main) { |
728 |
/* XXX: Why DON'T sub-requests use keepalives? */ |
698 |
/* XXX: Why DON'T sub-requests use keepalives? */ |
729 |
p_conn->close = 1; |
699 |
p_conn->close = 1; |
730 |
*old_cl_val = NULL; |
700 |
req->old_te_val = NULL; |
731 |
*old_te_val = NULL; |
701 |
req->old_cl_val = NULL; |
732 |
*rb_method = RB_STREAM_CL; |
702 |
req->rb_method = RB_STREAM_CL; |
733 |
e = apr_bucket_eos_create(input_brigade->bucket_alloc); |
703 |
e = apr_bucket_eos_create(input_brigade->bucket_alloc); |
734 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
704 |
APR_BRIGADE_INSERT_TAIL(input_brigade, e); |
735 |
goto skip_body; |
705 |
goto skip_body; |
Lines 743-760
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
743 |
* encoding has been done by the extensions' handler, and |
713 |
* encoding has been done by the extensions' handler, and |
744 |
* do not modify add_te_chunked's logic |
714 |
* do not modify add_te_chunked's logic |
745 |
*/ |
715 |
*/ |
746 |
if (*old_te_val && ap_cstr_casecmp(*old_te_val, "chunked") != 0) { |
716 |
if (req->old_te_val && ap_cstr_casecmp(req->old_te_val, "chunked") != 0) { |
747 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) |
717 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) |
748 |
"%s Transfer-Encoding is not supported", *old_te_val); |
718 |
"%s Transfer-Encoding is not supported", |
|
|
719 |
req->old_te_val); |
749 |
return HTTP_INTERNAL_SERVER_ERROR; |
720 |
return HTTP_INTERNAL_SERVER_ERROR; |
750 |
} |
721 |
} |
751 |
|
722 |
|
752 |
if (*old_cl_val && *old_te_val) { |
723 |
if (req->old_cl_val && req->old_te_val) { |
753 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) |
724 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) |
754 |
"client %s (%s) requested Transfer-Encoding " |
725 |
"client %s (%s) requested Transfer-Encoding " |
755 |
"chunked body with Content-Length (C-L ignored)", |
726 |
"chunked body with Content-Length (C-L ignored)", |
756 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
727 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
757 |
*old_cl_val = NULL; |
728 |
req->old_cl_val = NULL; |
758 |
p_conn->close = 1; |
729 |
p_conn->close = 1; |
759 |
} |
730 |
} |
760 |
|
731 |
|
Lines 767-773
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
767 |
* reasonable size. |
738 |
* reasonable size. |
768 |
*/ |
739 |
*/ |
769 |
temp_brigade = apr_brigade_create(p, bucket_alloc); |
740 |
temp_brigade = apr_brigade_create(p, bucket_alloc); |
770 |
block = (flushall) ? APR_NONBLOCK_READ : APR_BLOCK_READ; |
741 |
block = req->flushall ? APR_NONBLOCK_READ : APR_BLOCK_READ; |
771 |
do { |
742 |
do { |
772 |
status = ap_get_brigade(r->input_filters, temp_brigade, |
743 |
status = ap_get_brigade(r->input_filters, temp_brigade, |
773 |
AP_MODE_READBYTES, block, |
744 |
AP_MODE_READBYTES, block, |
Lines 818-824
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
818 |
*/ |
789 |
*/ |
819 |
} while ((bytes_read < MAX_MEM_SPOOL - 80) |
790 |
} while ((bytes_read < MAX_MEM_SPOOL - 80) |
820 |
&& !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)) |
791 |
&& !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)) |
821 |
&& block == APR_BLOCK_READ); |
792 |
&& !req->flushall); |
822 |
|
793 |
|
823 |
/* Use chunked request body encoding or send a content-length body? |
794 |
/* Use chunked request body encoding or send a content-length body? |
824 |
* |
795 |
* |
Lines 864-918
static void terminate_headers(apr_bucket_alloc_t *
Link Here
|
864 |
* If we expected no body, and read no body, do not set |
835 |
* If we expected no body, and read no body, do not set |
865 |
* the Content-Length. |
836 |
* the Content-Length. |
866 |
*/ |
837 |
*/ |
867 |
if (*old_cl_val || *old_te_val || bytes_read) { |
838 |
if (req->old_cl_val || req->old_te_val || bytes_read) { |
868 |
*old_cl_val = apr_off_t_toa(r->pool, bytes_read); |
839 |
req->old_cl_val = apr_off_t_toa(r->pool, bytes_read); |
|
|
840 |
req->cl_val = bytes_read; |
869 |
} |
841 |
} |
870 |
*rb_method = RB_STREAM_CL; |
842 |
req->rb_method = RB_STREAM_CL; |
871 |
} |
843 |
} |
872 |
else if (*old_te_val) { |
844 |
else if (req->old_te_val) { |
873 |
if (force10 |
845 |
if (force10 |
874 |
|| (apr_table_get(r->subprocess_env, "proxy-sendcl") |
846 |
|| (apr_table_get(r->subprocess_env, "proxy-sendcl") |
875 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunks") |
847 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunks") |
876 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { |
848 |
&& !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { |
877 |
*rb_method = RB_SPOOL_CL; |
849 |
req->rb_method = RB_SPOOL_CL; |
878 |
} |
850 |
} |
879 |
else { |
851 |
else { |
880 |
*rb_method = RB_STREAM_CHUNKED; |
852 |
req->rb_method = RB_STREAM_CHUNKED; |
881 |
} |
853 |
} |
882 |
} |
854 |
} |
883 |
else if (*old_cl_val) { |
855 |
else if (req->old_cl_val) { |
884 |
if (r->input_filters == r->proto_input_filters) { |
856 |
if (r->input_filters == r->proto_input_filters) { |
885 |
*rb_method = RB_STREAM_CL; |
857 |
char *endstr; |
|
|
858 |
status = apr_strtoff(&req->cl_val, req->old_cl_val, &endstr, 10); |
859 |
if (status != APR_SUCCESS || *endstr || req->cl_val < 0) { |
860 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085) |
861 |
"could not parse request Content-Length (%s)", |
862 |
req->old_cl_val); |
863 |
return HTTP_BAD_REQUEST; |
864 |
} |
865 |
req->rb_method = RB_STREAM_CL; |
886 |
} |
866 |
} |
887 |
else if (!force10 |
867 |
else if (!force10 |
888 |
&& (apr_table_get(r->subprocess_env, "proxy-sendchunks") |
868 |
&& (apr_table_get(r->subprocess_env, "proxy-sendchunks") |
889 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunked")) |
869 |
|| apr_table_get(r->subprocess_env, "proxy-sendchunked")) |
890 |
&& !apr_table_get(r->subprocess_env, "proxy-sendcl")) { |
870 |
&& !apr_table_get(r->subprocess_env, "proxy-sendcl")) { |
891 |
*rb_method = RB_STREAM_CHUNKED; |
871 |
req->rb_method = RB_STREAM_CHUNKED; |
892 |
} |
872 |
} |
893 |
else { |
873 |
else { |
894 |
*rb_method = RB_SPOOL_CL; |
874 |
req->rb_method = RB_SPOOL_CL; |
895 |
} |
875 |
} |
896 |
} |
876 |
} |
897 |
else { |
877 |
else { |
898 |
/* This is an appropriate default; very efficient for no-body |
878 |
/* This is an appropriate default; very efficient for no-body |
899 |
* requests, and has the behavior that it will not add any C-L |
879 |
* requests, and has the behavior that it will not add any C-L |
900 |
* when the *old_cl_val is NULL. |
880 |
* when the old_cl_val is NULL. |
901 |
*/ |
881 |
*/ |
902 |
*rb_method = RB_SPOOL_CL; |
882 |
req->rb_method = RB_SPOOL_CL; |
903 |
} |
883 |
} |
904 |
|
884 |
|
905 |
/* If we have to spool the body, do it now, before connecting or |
885 |
switch (req->rb_method) { |
906 |
* reusing the backend connection. |
886 |
case RB_STREAM_CHUNKED: |
907 |
*/ |
887 |
add_te_chunked(req->p, bucket_alloc, header_brigade); |
908 |
if (*rb_method == RB_SPOOL_CL) { |
888 |
break; |
909 |
rv = spool_reqbody_cl(p, r, header_brigade, input_brigade, |
889 |
|
910 |
(bytes_read > 0) |
890 |
case RB_STREAM_CL: |
911 |
|| (*old_cl_val != NULL) |
891 |
if (req->old_cl_val) { |
912 |
|| (*old_te_val != NULL)); |
892 |
add_cl(req->p, bucket_alloc, header_brigade, req->old_cl_val); |
|
|
893 |
} |
894 |
break; |
895 |
|
896 |
default: /* => RB_SPOOL_CL */ |
897 |
/* If we have to spool the body, do it now, before connecting or |
898 |
* reusing the backend connection. |
899 |
*/ |
900 |
rv = spool_reqbody_cl(req); |
913 |
if (rv != OK) { |
901 |
if (rv != OK) { |
914 |
return rv; |
902 |
return rv; |
915 |
} |
903 |
} |
|
|
904 |
if (bytes_read > 0 |
905 |
|| req->old_te_val |
906 |
|| req->old_cl_val |
907 |
|| req->bytes_spooled) { |
908 |
add_cl(p, bucket_alloc, header_brigade, |
909 |
apr_off_t_toa(p, req->bytes_spooled)); |
910 |
} |
916 |
} |
911 |
} |
917 |
|
912 |
|
918 |
/* Yes I hate gotos. This is the subrequest shortcut */ |
913 |
/* Yes I hate gotos. This is the subrequest shortcut */ |
Lines 933-970
skip_body:
Link Here
|
933 |
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); |
928 |
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); |
934 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
929 |
APR_BRIGADE_INSERT_TAIL(header_brigade, e); |
935 |
} |
930 |
} |
|
|
931 |
terminate_headers(bucket_alloc, header_brigade); |
936 |
|
932 |
|
937 |
return OK; |
933 |
return OK; |
938 |
} |
934 |
} |
939 |
|
935 |
|
940 |
static |
936 |
static int ap_proxy_http_request(proxy_http_req_t *req) |
941 |
int ap_proxy_http_request(apr_pool_t *p, request_rec *r, |
|
|
942 |
proxy_conn_rec *p_conn, |
943 |
apr_bucket_brigade *header_brigade, |
944 |
apr_bucket_brigade *input_brigade, |
945 |
char *old_cl_val, char *old_te_val, |
946 |
enum rb_methods rb_method, int flushall) |
947 |
{ |
937 |
{ |
948 |
int rv; |
938 |
int rv; |
949 |
conn_rec *origin = p_conn->connection; |
939 |
request_rec *r = req->r; |
|
|
940 |
apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; |
941 |
apr_bucket_brigade *header_brigade = req->header_brigade; |
942 |
apr_bucket_brigade *input_brigade = req->input_brigade; |
950 |
|
943 |
|
951 |
/* send the request body, if any. */ |
944 |
/* send the request header/body, if any. */ |
952 |
switch(rb_method) { |
945 |
switch (req->rb_method) { |
953 |
case RB_STREAM_CHUNKED: |
946 |
case RB_STREAM_CHUNKED: |
954 |
rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, |
947 |
if (req->do_100_continue) { |
955 |
input_brigade, flushall); |
948 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend, |
|
|
949 |
req->origin, header_brigade, 1); |
950 |
} |
951 |
else { |
952 |
rv = stream_reqbody_chunked(req); |
953 |
} |
956 |
break; |
954 |
break; |
|
|
955 |
|
957 |
case RB_STREAM_CL: |
956 |
case RB_STREAM_CL: |
958 |
rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, |
957 |
if (req->do_100_continue) { |
959 |
input_brigade, old_cl_val, flushall); |
958 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend, |
|
|
959 |
req->origin, header_brigade, 1); |
960 |
} |
961 |
else { |
962 |
rv = stream_reqbody_cl(req); |
963 |
} |
960 |
break; |
964 |
break; |
|
|
965 |
|
961 |
case RB_SPOOL_CL: |
966 |
case RB_SPOOL_CL: |
962 |
/* Prefetch has spooled the whole body, simply forward it now. |
967 |
/* Prefetch has built the header and spooled the whole body; |
963 |
* This is all a single brigade, pass with flush flagged. |
968 |
* if we don't expect 100-continue we can flush both all at once, |
|
|
969 |
* otherwise flush the header only. |
964 |
*/ |
970 |
*/ |
965 |
rv = ap_proxy_pass_brigade(r->connection->bucket_alloc, |
971 |
if (!req->do_100_continue) { |
966 |
r, p_conn, origin, header_brigade, 1); |
972 |
APR_BRIGADE_CONCAT(header_brigade, input_brigade); |
|
|
973 |
} |
974 |
rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend, |
975 |
req->origin, header_brigade, 1); |
967 |
break; |
976 |
break; |
|
|
977 |
|
968 |
default: |
978 |
default: |
969 |
/* shouldn't be possible */ |
979 |
/* shouldn't be possible */ |
970 |
rv = HTTP_INTERNAL_SERVER_ERROR; |
980 |
rv = HTTP_INTERNAL_SERVER_ERROR; |
Lines 976-982
skip_body:
Link Here
|
976 |
/* apr_status_t value has been logged in lower level method */ |
986 |
/* apr_status_t value has been logged in lower level method */ |
977 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) |
987 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) |
978 |
"pass request body failed to %pI (%s) from %s (%s)", |
988 |
"pass request body failed to %pI (%s) from %s (%s)", |
979 |
p_conn->addr, p_conn->hostname ? p_conn->hostname: "", |
989 |
req->backend->addr, |
|
|
990 |
req->backend->hostname ? req->backend->hostname: "", |
980 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
991 |
c->client_ip, c->remote_host ? c->remote_host: ""); |
981 |
return rv; |
992 |
return rv; |
982 |
} |
993 |
} |
Lines 1243-1254
static int add_trailers(void *data, const char *ke
Link Here
|
1243 |
return 1; |
1254 |
return 1; |
1244 |
} |
1255 |
} |
1245 |
|
1256 |
|
1246 |
static |
1257 |
static int ap_proxy_http_process_response(proxy_http_req_t *req) |
1247 |
int ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, |
|
|
1248 |
proxy_conn_rec **backend_ptr, proxy_worker *worker, |
1249 |
proxy_server_conf *conf, char *server_portstr) |
1250 |
{ |
1258 |
{ |
|
|
1259 |
apr_pool_t *p = req->p; |
1260 |
request_rec *r = req->r; |
1251 |
conn_rec *c = r->connection; |
1261 |
conn_rec *c = r->connection; |
|
|
1262 |
proxy_worker *worker = req->worker; |
1263 |
proxy_conn_rec *backend = req->backend; |
1264 |
conn_rec *origin = req->origin; |
1265 |
int do_100_continue = req->do_100_continue; |
1252 |
char buffer[HUGE_STRING_LEN]; |
1266 |
char buffer[HUGE_STRING_LEN]; |
1253 |
const char *buf; |
1267 |
const char *buf; |
1254 |
char keepchar; |
1268 |
char keepchar; |
Lines 1269-1289
static int add_trailers(void *data, const char *ke
Link Here
|
1269 |
int proxy_status = OK; |
1283 |
int proxy_status = OK; |
1270 |
const char *original_status_line = r->status_line; |
1284 |
const char *original_status_line = r->status_line; |
1271 |
const char *proxy_status_line = NULL; |
1285 |
const char *proxy_status_line = NULL; |
1272 |
proxy_conn_rec *backend = *backend_ptr; |
|
|
1273 |
conn_rec *origin = backend->connection; |
1274 |
apr_interval_time_t old_timeout = 0; |
1286 |
apr_interval_time_t old_timeout = 0; |
1275 |
proxy_dir_conf *dconf; |
1287 |
proxy_dir_conf *dconf; |
1276 |
int do_100_continue; |
|
|
1277 |
|
1288 |
|
1278 |
dconf = ap_get_module_config(r->per_dir_config, &proxy_module); |
1289 |
dconf = ap_get_module_config(r->per_dir_config, &proxy_module); |
1279 |
|
1290 |
|
1280 |
do_100_continue = PROXY_DO_100_CONTINUE(worker, r); |
|
|
1281 |
|
1282 |
bb = apr_brigade_create(p, c->bucket_alloc); |
1291 |
bb = apr_brigade_create(p, c->bucket_alloc); |
1283 |
pass_bb = apr_brigade_create(p, c->bucket_alloc); |
1292 |
pass_bb = apr_brigade_create(p, c->bucket_alloc); |
1284 |
|
1293 |
|
1285 |
/* Setup for 100-Continue timeout if appropriate */ |
1294 |
/* Setup for 100-Continue timeout if appropriate */ |
1286 |
if (do_100_continue) { |
1295 |
if (do_100_continue && worker->s->ping_timeout_set) { |
1287 |
apr_socket_timeout_get(backend->sock, &old_timeout); |
1296 |
apr_socket_timeout_get(backend->sock, &old_timeout); |
1288 |
if (worker->s->ping_timeout != old_timeout) { |
1297 |
if (worker->s->ping_timeout != old_timeout) { |
1289 |
apr_status_t rc; |
1298 |
apr_status_t rc; |
Lines 1308-1313
static int add_trailers(void *data, const char *ke
Link Here
|
1308 |
origin->local_addr->port)); |
1317 |
origin->local_addr->port)); |
1309 |
do { |
1318 |
do { |
1310 |
apr_status_t rc; |
1319 |
apr_status_t rc; |
|
|
1320 |
int major = 0, minor = 0; |
1321 |
int toclose = 0; |
1311 |
|
1322 |
|
1312 |
apr_brigade_cleanup(bb); |
1323 |
apr_brigade_cleanup(bb); |
1313 |
|
1324 |
|
Lines 1380-1388
static int add_trailers(void *data, const char *ke
Link Here
|
1380 |
* This is buggy if we ever see an HTTP/1.10 |
1391 |
* This is buggy if we ever see an HTTP/1.10 |
1381 |
*/ |
1392 |
*/ |
1382 |
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) { |
1393 |
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) { |
1383 |
int major, minor; |
|
|
1384 |
int toclose; |
1385 |
|
1386 |
major = buffer[5] - '0'; |
1394 |
major = buffer[5] - '0'; |
1387 |
minor = buffer[7] - '0'; |
1395 |
minor = buffer[7] - '0'; |
1388 |
|
1396 |
|
Lines 1433-1440
static int add_trailers(void *data, const char *ke
Link Here
|
1433 |
"Set-Cookie", NULL); |
1441 |
"Set-Cookie", NULL); |
1434 |
|
1442 |
|
1435 |
/* shove the headers direct into r->headers_out */ |
1443 |
/* shove the headers direct into r->headers_out */ |
1436 |
ap_proxy_read_headers(r, backend->r, buffer, sizeof(buffer), origin, |
1444 |
ap_proxy_read_headers(r, backend->r, buffer, sizeof(buffer), |
1437 |
&pread_len); |
1445 |
origin, &pread_len); |
1438 |
|
1446 |
|
1439 |
if (r->headers_out == NULL) { |
1447 |
if (r->headers_out == NULL) { |
1440 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01106) |
1448 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01106) |
Lines 1518-1524
static int add_trailers(void *data, const char *ke
Link Here
|
1518 |
r->headers_out = ap_proxy_clean_warnings(p, r->headers_out); |
1526 |
r->headers_out = ap_proxy_clean_warnings(p, r->headers_out); |
1519 |
|
1527 |
|
1520 |
/* handle Via header in response */ |
1528 |
/* handle Via header in response */ |
1521 |
if (conf->viaopt != via_off && conf->viaopt != via_block) { |
1529 |
if (req->sconf->viaopt != via_off |
|
|
1530 |
&& req->sconf->viaopt != via_block) { |
1522 |
const char *server_name = ap_get_server_name(r); |
1531 |
const char *server_name = ap_get_server_name(r); |
1523 |
/* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host, |
1532 |
/* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host, |
1524 |
* then the server name returned by ap_get_server_name() is the |
1533 |
* then the server name returned by ap_get_server_name() is the |
Lines 1529-1546
static int add_trailers(void *data, const char *ke
Link Here
|
1529 |
server_name = r->server->server_hostname; |
1538 |
server_name = r->server->server_hostname; |
1530 |
/* create a "Via:" response header entry and merge it */ |
1539 |
/* create a "Via:" response header entry and merge it */ |
1531 |
apr_table_addn(r->headers_out, "Via", |
1540 |
apr_table_addn(r->headers_out, "Via", |
1532 |
(conf->viaopt == via_full) |
1541 |
(req->sconf->viaopt == via_full) |
1533 |
? apr_psprintf(p, "%d.%d %s%s (%s)", |
1542 |
? apr_psprintf(p, "%d.%d %s%s (%s)", |
1534 |
HTTP_VERSION_MAJOR(r->proto_num), |
1543 |
HTTP_VERSION_MAJOR(r->proto_num), |
1535 |
HTTP_VERSION_MINOR(r->proto_num), |
1544 |
HTTP_VERSION_MINOR(r->proto_num), |
1536 |
server_name, |
1545 |
server_name, |
1537 |
server_portstr, |
1546 |
req->server_portstr, |
1538 |
AP_SERVER_BASEVERSION) |
1547 |
AP_SERVER_BASEVERSION) |
1539 |
: apr_psprintf(p, "%d.%d %s%s", |
1548 |
: apr_psprintf(p, "%d.%d %s%s", |
1540 |
HTTP_VERSION_MAJOR(r->proto_num), |
1549 |
HTTP_VERSION_MAJOR(r->proto_num), |
1541 |
HTTP_VERSION_MINOR(r->proto_num), |
1550 |
HTTP_VERSION_MINOR(r->proto_num), |
1542 |
server_name, |
1551 |
server_name, |
1543 |
server_portstr) |
1552 |
req->server_portstr) |
1544 |
); |
1553 |
); |
1545 |
} |
1554 |
} |
1546 |
|
1555 |
|
Lines 1558-1575
static int add_trailers(void *data, const char *ke
Link Here
|
1558 |
} |
1567 |
} |
1559 |
|
1568 |
|
1560 |
if (ap_is_HTTP_INFO(proxy_status)) { |
1569 |
if (ap_is_HTTP_INFO(proxy_status)) { |
1561 |
interim_response++; |
|
|
1562 |
/* Reset to old timeout iff we've adjusted it */ |
1563 |
if (do_100_continue |
1564 |
&& (r->status == HTTP_CONTINUE) |
1565 |
&& (worker->s->ping_timeout != old_timeout)) { |
1566 |
apr_socket_timeout_set(backend->sock, old_timeout); |
1567 |
} |
1568 |
} |
1569 |
else { |
1570 |
interim_response = 0; |
1571 |
} |
1572 |
if (interim_response) { |
1573 |
/* RFC2616 tells us to forward this. |
1570 |
/* RFC2616 tells us to forward this. |
1574 |
* |
1571 |
* |
1575 |
* OTOH, an interim response here may mean the backend |
1572 |
* OTOH, an interim response here may mean the backend |
Lines 1590-1596
static int add_trailers(void *data, const char *ke
Link Here
|
1590 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, |
1587 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, |
1591 |
"HTTP: received interim %d response", r->status); |
1588 |
"HTTP: received interim %d response", r->status); |
1592 |
if (!policy |
1589 |
if (!policy |
1593 |
|| (!strcasecmp(policy, "RFC") && ((r->expecting_100 = 1)))) { |
1590 |
|| (proxy_status == HTTP_CONTINUE |
|
|
1591 |
&& r->expecting_100) |
1592 |
|| (!strcasecmp(policy, "RFC") |
1593 |
&& (proxy_status != HTTP_CONTINUE |
1594 |
|| (r->expecting_100 = 1)))) { |
1594 |
ap_send_interim_response(r, 1); |
1595 |
ap_send_interim_response(r, 1); |
1595 |
} |
1596 |
} |
1596 |
/* FIXME: refine this to be able to specify per-response-status |
1597 |
/* FIXME: refine this to be able to specify per-response-status |
Lines 1600-1607
static int add_trailers(void *data, const char *ke
Link Here
|
1600 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01108) |
1601 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01108) |
1601 |
"undefined proxy interim response policy"); |
1602 |
"undefined proxy interim response policy"); |
1602 |
} |
1603 |
} |
|
|
1604 |
interim_response++; |
1603 |
} |
1605 |
} |
|
|
1606 |
else { |
1607 |
interim_response = 0; |
1608 |
} |
1604 |
|
1609 |
|
|
|
1610 |
/* If we still do 100-continue (end-to-end or ping), either the |
1611 |
* current response is the expected "100 Continue" and we are done |
1612 |
* with this mode, or this is another interim response and we'll wait |
1613 |
* for the next one, or this is a final response and hence the backend |
1614 |
* did not honor our expectation. |
1615 |
*/ |
1616 |
if (do_100_continue |
1617 |
&& (proxy_status == HTTP_CONTINUE || !interim_response)) { |
1618 |
/* Reset to old timeout iff we've adjusted it. */ |
1619 |
if (worker->s->ping_timeout_set) { |
1620 |
apr_socket_timeout_set(backend->sock, old_timeout); |
1621 |
} |
1622 |
/* RFC 7231 - Section 5.1.1 - Expect - Requirement for servers |
1623 |
* A server that responds with a final status code before |
1624 |
* reading the entire message body SHOULD indicate in that |
1625 |
* response whether it intends to close the connection or |
1626 |
* continue reading and discarding the request message. |
1627 |
* |
1628 |
* So, if this response is not an interim 100 Continue, we can |
1629 |
* avoid sending the request body if the backend responded with |
1630 |
* "Connection: close" or HTTP < 1.1, and either let the core |
1631 |
* discard it or the caller try another balancer member with the |
1632 |
* same body (given status 503, though not implemented yet). |
1633 |
*/ |
1634 |
if (proxy_status == HTTP_CONTINUE |
1635 |
|| (major > 0 && minor > 0 && !toclose)) { |
1636 |
int status; |
1637 |
|
1638 |
/* Send the request body (fully). */ |
1639 |
switch(req->rb_method) { |
1640 |
case RB_STREAM_CL: |
1641 |
status = stream_reqbody_cl(req); |
1642 |
break; |
1643 |
case RB_STREAM_CHUNKED: |
1644 |
status = stream_reqbody_chunked(req); |
1645 |
break; |
1646 |
case RB_SPOOL_CL: |
1647 |
/* Prefetch has spooled the whole body, flush it. */ |
1648 |
status = ap_proxy_pass_brigade(req->bucket_alloc, r, |
1649 |
backend, origin, |
1650 |
req->input_brigade, 1); |
1651 |
break; |
1652 |
default: |
1653 |
/* Shouldn't happen */ |
1654 |
status = HTTP_INTERNAL_SERVER_ERROR; |
1655 |
break; |
1656 |
} |
1657 |
if (status != OK) { |
1658 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
1659 |
APLOGNO() "pass request body failed " |
1660 |
"to %pI (%s) from %s (%s) with status %i", |
1661 |
backend->addr, |
1662 |
backend->hostname ? backend->hostname : "", |
1663 |
c->client_ip, |
1664 |
c->remote_host ? c->remote_host : "", |
1665 |
status); |
1666 |
backend->close = 1; |
1667 |
proxy_run_detach_backend(r, backend); |
1668 |
return status; |
1669 |
} |
1670 |
} |
1671 |
|
1672 |
/* Once only! */ |
1673 |
do_100_continue = 0; |
1674 |
} |
1675 |
|
1605 |
/* Moved the fixups of Date headers and those affected by |
1676 |
/* Moved the fixups of Date headers and those affected by |
1606 |
* ProxyPassReverse/etc from here to ap_proxy_read_headers |
1677 |
* ProxyPassReverse/etc from here to ap_proxy_read_headers |
1607 |
*/ |
1678 |
*/ |
Lines 1726-1732
static int add_trailers(void *data, const char *ke
Link Here
|
1726 |
|
1797 |
|
1727 |
rv = ap_get_brigade(backend->r->input_filters, bb, |
1798 |
rv = ap_get_brigade(backend->r->input_filters, bb, |
1728 |
AP_MODE_READBYTES, mode, |
1799 |
AP_MODE_READBYTES, mode, |
1729 |
conf->io_buffer_size); |
1800 |
req->sconf->io_buffer_size); |
1730 |
|
1801 |
|
1731 |
/* ap_get_brigade will return success with an empty brigade |
1802 |
/* ap_get_brigade will return success with an empty brigade |
1732 |
* for a non-blocking read which would block: */ |
1803 |
* for a non-blocking read which would block: */ |
Lines 1836-1842
static int add_trailers(void *data, const char *ke
Link Here
|
1836 |
ap_proxy_release_connection(backend->worker->s->scheme, |
1907 |
ap_proxy_release_connection(backend->worker->s->scheme, |
1837 |
backend, r->server); |
1908 |
backend, r->server); |
1838 |
/* Ensure that the backend is not reused */ |
1909 |
/* Ensure that the backend is not reused */ |
1839 |
*backend_ptr = NULL; |
1910 |
req->backend = NULL; |
1840 |
|
1911 |
|
1841 |
} |
1912 |
} |
1842 |
|
1913 |
|
Lines 1845-1856
static int add_trailers(void *data, const char *ke
Link Here
|
1845 |
|| c->aborted) { |
1916 |
|| c->aborted) { |
1846 |
/* Ack! Phbtt! Die! User aborted! */ |
1917 |
/* Ack! Phbtt! Die! User aborted! */ |
1847 |
/* Only close backend if we haven't got all from the |
1918 |
/* Only close backend if we haven't got all from the |
1848 |
* backend. Furthermore if *backend_ptr is NULL it is no |
1919 |
* backend. Furthermore if req->backend is NULL it is no |
1849 |
* longer safe to fiddle around with backend as it might |
1920 |
* longer safe to fiddle around with backend as it might |
1850 |
* be already in use by another thread. |
1921 |
* be already in use by another thread. |
1851 |
*/ |
1922 |
*/ |
1852 |
if (*backend_ptr) { |
1923 |
if (req->backend) { |
1853 |
backend->close = 1; /* this causes socket close below */ |
1924 |
/* this causes socket close below */ |
|
|
1925 |
req->backend->close = 1; |
1854 |
} |
1926 |
} |
1855 |
finish = TRUE; |
1927 |
finish = TRUE; |
1856 |
} |
1928 |
} |
Lines 1874-1880
static int add_trailers(void *data, const char *ke
Link Here
|
1874 |
proxy_run_detach_backend(r, backend); |
1946 |
proxy_run_detach_backend(r, backend); |
1875 |
ap_proxy_release_connection(backend->worker->s->scheme, |
1947 |
ap_proxy_release_connection(backend->worker->s->scheme, |
1876 |
backend, r->server); |
1948 |
backend, r->server); |
1877 |
*backend_ptr = NULL; |
1949 |
req->backend = NULL; |
1878 |
|
1950 |
|
1879 |
/* Pass EOS bucket down the filter chain. */ |
1951 |
/* Pass EOS bucket down the filter chain. */ |
1880 |
e = apr_bucket_eos_create(c->bucket_alloc); |
1952 |
e = apr_bucket_eos_create(c->bucket_alloc); |
Lines 1889-1896
static int add_trailers(void *data, const char *ke
Link Here
|
1889 |
* created from scpool and this pool can be freed before this brigade. */ |
1961 |
* created from scpool and this pool can be freed before this brigade. */ |
1890 |
apr_brigade_cleanup(bb); |
1962 |
apr_brigade_cleanup(bb); |
1891 |
|
1963 |
|
1892 |
if (*backend_ptr) { |
1964 |
if (req->backend) { |
1893 |
proxy_run_detach_backend(r, backend); |
1965 |
proxy_run_detach_backend(r, req->backend); |
1894 |
} |
1966 |
} |
1895 |
|
1967 |
|
1896 |
/* See define of AP_MAX_INTERIM_RESPONSES for why */ |
1968 |
/* See define of AP_MAX_INTERIM_RESPONSES for why */ |
Lines 1932-1951
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1932 |
apr_port_t proxyport) |
2004 |
apr_port_t proxyport) |
1933 |
{ |
2005 |
{ |
1934 |
int status; |
2006 |
int status; |
1935 |
char server_portstr[32]; |
|
|
1936 |
char *scheme; |
2007 |
char *scheme; |
1937 |
const char *proxy_function; |
2008 |
const char *proxy_function; |
1938 |
const char *u; |
2009 |
const char *u; |
1939 |
apr_bucket_brigade *header_brigade; |
2010 |
proxy_http_req_t *req; |
1940 |
apr_bucket_brigade *input_brigade; |
|
|
1941 |
proxy_conn_rec *backend = NULL; |
2011 |
proxy_conn_rec *backend = NULL; |
1942 |
int is_ssl = 0; |
2012 |
int is_ssl = 0; |
1943 |
conn_rec *c = r->connection; |
2013 |
conn_rec *c = r->connection; |
1944 |
int retry = 0; |
2014 |
int retry = 0; |
1945 |
char *old_cl_val = NULL, *old_te_val = NULL; |
|
|
1946 |
enum rb_methods rb_method = RB_INIT; |
1947 |
char *locurl = url; |
2015 |
char *locurl = url; |
1948 |
int flushall = 0; |
|
|
1949 |
int toclose = 0; |
2016 |
int toclose = 0; |
1950 |
/* |
2017 |
/* |
1951 |
* Use a shorter-lived pool to reduce memory usage |
2018 |
* Use a shorter-lived pool to reduce memory usage |
Lines 1987-1993
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1987 |
} |
2054 |
} |
1988 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "HTTP: serving URL %s", url); |
2055 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "HTTP: serving URL %s", url); |
1989 |
|
2056 |
|
1990 |
|
|
|
1991 |
/* create space for state information */ |
2057 |
/* create space for state information */ |
1992 |
if ((status = ap_proxy_acquire_connection(proxy_function, &backend, |
2058 |
if ((status = ap_proxy_acquire_connection(proxy_function, &backend, |
1993 |
worker, r->server)) != OK) |
2059 |
worker, r->server)) != OK) |
Lines 1995-2000
static int proxy_http_handler(request_rec *r, prox
Link Here
|
1995 |
|
2061 |
|
1996 |
backend->is_ssl = is_ssl; |
2062 |
backend->is_ssl = is_ssl; |
1997 |
|
2063 |
|
|
|
2064 |
req = apr_pcalloc(p, sizeof *req); |
2065 |
req->p = p; |
2066 |
req->r = r; |
2067 |
req->sconf = conf; |
2068 |
req->worker = worker; |
2069 |
req->backend = backend; |
2070 |
req->bucket_alloc = c->bucket_alloc; |
2071 |
if (r->expecting_100 || PROXY_DO_100_CONTINUE(worker, r)) { |
2072 |
req->do_100_continue = 1; |
2073 |
} |
2074 |
if (apr_table_get(r->subprocess_env, "proxy-flushall")) { |
2075 |
req->flushall = 1; |
2076 |
} |
2077 |
req->rb_method = RB_INIT; |
2078 |
|
1998 |
/* |
2079 |
/* |
1999 |
* In the case that we are handling a reverse proxy connection and this |
2080 |
* In the case that we are handling a reverse proxy connection and this |
2000 |
* is not a request that is coming over an already kept alive connection |
2081 |
* is not a request that is coming over an already kept alive connection |
Lines 2008-2023
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2008 |
backend->close = 1; |
2089 |
backend->close = 1; |
2009 |
} |
2090 |
} |
2010 |
|
2091 |
|
2011 |
if (apr_table_get(r->subprocess_env, "proxy-flushall")) { |
|
|
2012 |
flushall = 1; |
2013 |
} |
2014 |
|
2015 |
/* Step One: Determine Who To Connect To */ |
2092 |
/* Step One: Determine Who To Connect To */ |
2016 |
uri = apr_palloc(p, sizeof(*uri)); |
2093 |
uri = apr_palloc(p, sizeof(*uri)); |
2017 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, |
2094 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, |
2018 |
uri, &locurl, proxyname, |
2095 |
uri, &locurl, proxyname, |
2019 |
proxyport, server_portstr, |
2096 |
proxyport, req->server_portstr, |
2020 |
sizeof(server_portstr))) != OK) |
2097 |
sizeof req->server_portstr))) |
2021 |
goto cleanup; |
2098 |
goto cleanup; |
2022 |
|
2099 |
|
2023 |
/* Prefetch (nonlocking) the request body so to increase the chance to get |
2100 |
/* Prefetch (nonlocking) the request body so to increase the chance to get |
Lines 2030-2042
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2030 |
* to reduce to the minimum the unavoidable local is_socket_connected() vs |
2107 |
* to reduce to the minimum the unavoidable local is_socket_connected() vs |
2031 |
* remote keepalive race condition. |
2108 |
* remote keepalive race condition. |
2032 |
*/ |
2109 |
*/ |
2033 |
input_brigade = apr_brigade_create(p, c->bucket_alloc); |
2110 |
req->input_brigade = apr_brigade_create(p, req->bucket_alloc); |
2034 |
header_brigade = apr_brigade_create(p, c->bucket_alloc); |
2111 |
req->header_brigade = apr_brigade_create(p, req->bucket_alloc); |
2035 |
if ((status = ap_proxy_http_prefetch(p, r, backend, worker, conf, uri, |
2112 |
if ((status = ap_proxy_http_prefetch(req, uri, locurl)) != OK) |
2036 |
locurl, server_portstr, |
|
|
2037 |
header_brigade, input_brigade, |
2038 |
&old_cl_val, &old_te_val, &rb_method, |
2039 |
flushall)) != OK) |
2040 |
goto cleanup; |
2113 |
goto cleanup; |
2041 |
|
2114 |
|
2042 |
/* We need to reset backend->close now, since ap_proxy_http_prefetch() set |
2115 |
/* We need to reset backend->close now, since ap_proxy_http_prefetch() set |
Lines 2049-2056
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2049 |
backend->close = 0; |
2122 |
backend->close = 0; |
2050 |
|
2123 |
|
2051 |
while (retry < 2) { |
2124 |
while (retry < 2) { |
2052 |
conn_rec *backconn; |
|
|
2053 |
|
2054 |
if (retry) { |
2125 |
if (retry) { |
2055 |
char *newurl = url; |
2126 |
char *newurl = url; |
2056 |
|
2127 |
|
Lines 2057-2063
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2057 |
/* Step One (again): (Re)Determine Who To Connect To */ |
2128 |
/* Step One (again): (Re)Determine Who To Connect To */ |
2058 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, |
2129 |
if ((status = ap_proxy_determine_connection(p, r, conf, worker, |
2059 |
backend, uri, &newurl, proxyname, proxyport, |
2130 |
backend, uri, &newurl, proxyname, proxyport, |
2060 |
server_portstr, sizeof(server_portstr))) != OK) |
2131 |
req->server_portstr, sizeof req->server_portstr))) |
2061 |
break; |
2132 |
break; |
2062 |
|
2133 |
|
2063 |
/* The code assumes locurl is not changed during the loop, or |
2134 |
/* The code assumes locurl is not changed during the loop, or |
Lines 2080-2091
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2080 |
} |
2151 |
} |
2081 |
|
2152 |
|
2082 |
/* Step Three: Create conn_rec */ |
2153 |
/* Step Three: Create conn_rec */ |
2083 |
backconn = backend->connection; |
2154 |
req->origin = backend->connection; |
2084 |
if (!backconn) { |
2155 |
if (!req->origin) { |
2085 |
if ((status = ap_proxy_connection_create_ex(proxy_function, |
2156 |
if ((status = ap_proxy_connection_create_ex(proxy_function, |
2086 |
backend, r)) != OK) |
2157 |
backend, r)) != OK) |
2087 |
break; |
2158 |
break; |
2088 |
backconn = backend->connection; |
2159 |
req->origin = backend->connection; |
2089 |
|
2160 |
|
2090 |
/* |
2161 |
/* |
2091 |
* On SSL connections set a note on the connection what CN is |
2162 |
* On SSL connections set a note on the connection what CN is |
Lines 2102-2108
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2102 |
/* Don't recycle the connection if prefetch (above) told not to do so */ |
2173 |
/* Don't recycle the connection if prefetch (above) told not to do so */ |
2103 |
if (toclose) { |
2174 |
if (toclose) { |
2104 |
backend->close = 1; |
2175 |
backend->close = 1; |
2105 |
backconn->keepalive = AP_CONN_CLOSE; |
2176 |
req->origin->keepalive = AP_CONN_CLOSE; |
2106 |
} |
2177 |
} |
2107 |
|
2178 |
|
2108 |
/* Step Four: Send the Request |
2179 |
/* Step Four: Send the Request |
Lines 2109-2135
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2109 |
* On the off-chance that we forced a 100-Continue as a |
2180 |
* On the off-chance that we forced a 100-Continue as a |
2110 |
* kinda HTTP ping test, allow for retries |
2181 |
* kinda HTTP ping test, allow for retries |
2111 |
*/ |
2182 |
*/ |
2112 |
if ((status = ap_proxy_http_request(p, r, backend, |
2183 |
status = ap_proxy_http_request(req); |
2113 |
header_brigade, input_brigade, |
2184 |
if (status != OK) { |
2114 |
old_cl_val, old_te_val, rb_method, |
|
|
2115 |
flushall)) != OK) { |
2116 |
proxy_run_detach_backend(r, backend); |
2185 |
proxy_run_detach_backend(r, backend); |
2117 |
if ((status == HTTP_SERVICE_UNAVAILABLE) && |
2186 |
if (req->do_100_continue && status == HTTP_SERVICE_UNAVAILABLE) { |
2118 |
PROXY_DO_100_CONTINUE(worker, r)) { |
|
|
2119 |
backend->close = 1; |
2120 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO(01115) |
2187 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO(01115) |
2121 |
"HTTP: 100-Continue failed to %pI (%s)", |
2188 |
"HTTP: 100-Continue failed to %pI (%s)", |
2122 |
worker->cp->addr, worker->s->hostname); |
2189 |
worker->cp->addr, worker->s->hostname); |
|
|
2190 |
backend->close = 1; |
2123 |
retry++; |
2191 |
retry++; |
2124 |
continue; |
2192 |
continue; |
2125 |
} else { |
|
|
2126 |
break; |
2127 |
} |
2193 |
} |
|
|
2194 |
break; |
2128 |
} |
2195 |
} |
2129 |
|
2196 |
|
2130 |
/* Step Five: Receive the Response... Fall thru to cleanup */ |
2197 |
/* Step Five: Receive the Response... Fall thru to cleanup */ |
2131 |
status = ap_proxy_http_process_response(p, r, &backend, worker, |
2198 |
status = ap_proxy_http_process_response(req); |
2132 |
conf, server_portstr); |
|
|
2133 |
|
2199 |
|
2134 |
break; |
2200 |
break; |
2135 |
} |
2201 |
} |
Lines 2136-2145
static int proxy_http_handler(request_rec *r, prox
Link Here
|
2136 |
|
2202 |
|
2137 |
/* Step Six: Clean Up */ |
2203 |
/* Step Six: Clean Up */ |
2138 |
cleanup: |
2204 |
cleanup: |
2139 |
if (backend) { |
2205 |
if (req->backend) { |
2140 |
if (status != OK) |
2206 |
if (status != OK) |
2141 |
backend->close = 1; |
2207 |
req->backend->close = 1; |
2142 |
ap_proxy_http_cleanup(proxy_function, r, backend); |
2208 |
ap_proxy_http_cleanup(proxy_function, r, req->backend); |
2143 |
} |
2209 |
} |
2144 |
return status; |
2210 |
return status; |
2145 |
} |
2211 |
} |