View | Details | Raw Unified | Return to bug 60330
Collapse All | Expand All

(-)modules/proxy/mod_proxy_http.c (-260 / +326 lines)
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
}
(-)server/protocol.c (-14 / +16 lines)
Lines 2108-2130 AP_DECLARE(void) ap_send_interim_response(request_ Link Here
2108
                      "Status is %d - not sending interim response", r->status);
2108
                      "Status is %d - not sending interim response", r->status);
2109
        return;
2109
        return;
2110
    }
2110
    }
2111
    if ((r->status == HTTP_CONTINUE) && !r->expecting_100) {
2111
    if (r->status == HTTP_CONTINUE) {
2112
        /*
2112
        if (!r->expecting_100) {
2113
         * Don't send 100-Continue when there was no Expect: 100-continue
2113
            /*
2114
         * in the request headers. For origin servers this is a SHOULD NOT
2114
             * Don't send 100-Continue when there was no Expect: 100-continue
2115
         * for proxies it is a MUST NOT according to RFC 2616 8.2.3
2115
             * in the request headers. For origin servers this is a SHOULD NOT
2116
             * for proxies it is a MUST NOT according to RFC 2616 8.2.3
2117
             */
2118
            return;
2119
        }
2120
2121
        /* if we send an interim response, we're no longer in a state of
2122
         * expecting one.  Also, this could feasibly be in a subrequest,
2123
         * so we need to propagate the fact that we responded.
2116
         */
2124
         */
2117
        return;
2125
        for (rr = r; rr != NULL; rr = rr->main) {
2126
            rr->expecting_100 = 0;
2127
        }
2118
    }
2128
    }
2119
2129
2120
    /* if we send an interim response, we're no longer in a state of
2121
     * expecting one.  Also, this could feasibly be in a subrequest,
2122
     * so we need to propagate the fact that we responded.
2123
     */
2124
    for (rr = r; rr != NULL; rr = rr->main) {
2125
        rr->expecting_100 = 0;
2126
    }
2127
2128
    status_line = apr_pstrcat(r->pool, AP_SERVER_PROTOCOL " ", r->status_line, CRLF, NULL);
2130
    status_line = apr_pstrcat(r->pool, AP_SERVER_PROTOCOL " ", r->status_line, CRLF, NULL);
2129
    ap_xlate_proto_to_ascii(status_line, strlen(status_line));
2131
    ap_xlate_proto_to_ascii(status_line, strlen(status_line));
2130
2132

Return to bug 60330