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

(-)server/protocol.c (-37 / +64 lines)
Lines 1708-1769 Link Here
1708
        ctx->tmpbb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1708
        ctx->tmpbb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1709
    }
1709
    }
1710
1710
1711
    /* Loop through this set of buckets to compute their length
1711
    /* Loop through the brigade to count the length. To avoid
1712
     */
1712
     * arbitrary memory consumption with morphing bucket types when
1713
     * finding the length, this loop will stop and pass on the brigade
1714
     * when necessary to read from additional buckets. */
1713
    e = APR_BRIGADE_FIRST(b);
1715
    e = APR_BRIGADE_FIRST(b);
1714
    while (e != APR_BRIGADE_SENTINEL(b)) {
1716
    while (e != APR_BRIGADE_SENTINEL(b)) {
1717
        apr_status_t rv;
1718
1715
        if (APR_BUCKET_IS_EOS(e)) {
1719
        if (APR_BUCKET_IS_EOS(e)) {
1716
            eos = 1;
1720
            eos = 1;
1717
            break;
1721
            break;
1718
        }
1722
        }
1719
        if (e->length == (apr_size_t)-1) {
1723
        /* For a flush bucket, fall through to pass the brigade and
1724
         * flush now. */
1725
        else if (APR_BUCKET_IS_FLUSH(e)) {
1726
            e = APR_BUCKET_NEXT(e);
1727
        }
1728
        /* For metadata bucket types other than FLUSH, loop. */
1729
        else if (APR_BUCKET_IS_METADATA(e)) {
1730
            e = APR_BUCKET_NEXT(e);
1731
            continue;
1732
        }
1733
        /* For determinate length data buckets, count the length and
1734
         * continue. */
1735
        else if (e->length != (apr_size_t)-1) {
1736
            r->bytes_sent += e->length;
1737
            e = APR_BUCKET_NEXT(e);
1738
            continue;
1739
        }
1740
        /* For indeterminate length data buckets, perform one read. */
1741
        else /* e->length == (apr_size_t)-1 */ {
1720
            apr_size_t len;
1742
            apr_size_t len;
1721
            const char *ignored;
1743
            const char *ignored;
1722
            apr_status_t rv;
1744
        
1723
1724
            /* This is probably a pipe bucket.  Send everything
1725
             * prior to this, and then read the data for this bucket.
1726
             */
1727
            rv = apr_bucket_read(e, &ignored, &len, eblock);
1745
            rv = apr_bucket_read(e, &ignored, &len, eblock);
1746
            if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) {
1747
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574)
1748
                              "ap_content_length_filter: "
1749
                              "apr_bucket_read() failed");
1750
                return rv;
1751
            }
1728
            if (rv == APR_SUCCESS) {
1752
            if (rv == APR_SUCCESS) {
1729
                /* Attempt a nonblocking read next time through */
1730
                eblock = APR_NONBLOCK_READ;
1753
                eblock = APR_NONBLOCK_READ;
1754
                e = APR_BUCKET_NEXT(e);
1731
                r->bytes_sent += len;
1755
                r->bytes_sent += len;
1756
1757
                /* Optimization: if the next bucket is now EOS after
1758
                 * this one morphed to a data bucket, take a short-cut
1759
                 * to handle EOS; this allows C-L to be determined for
1760
                 * content which is already entirely in memory. */
1761
                if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
1762
                    continue;
1763
                }
1732
            }
1764
            }
1733
            else if (APR_STATUS_IS_EAGAIN(rv)) {
1765
            else if (APR_STATUS_IS_EAGAIN(rv)) {
1734
                /* Output everything prior to this bucket, and then
1766
                apr_bucket *flush;
1735
                 * do a blocking read on the next batch.
1736
                 */
1737
                if (e != APR_BRIGADE_FIRST(b)) {
1738
                    apr_bucket *flush;
1739
                    apr_brigade_split_ex(b, e, ctx->tmpbb);
1740
                    flush = apr_bucket_flush_create(r->connection->bucket_alloc);
1741
1767
1742
                    APR_BRIGADE_INSERT_TAIL(b, flush);
1768
                /* Next read must block. */
1743
                    rv = ap_pass_brigade(f->next, b);
1769
                eblock = APR_BLOCK_READ;
1744
                    if (rv != APR_SUCCESS || f->c->aborted) {
1745
                        return rv;
1746
                    }
1747
                    apr_brigade_cleanup(b);
1748
                    APR_BRIGADE_CONCAT(b, ctx->tmpbb);
1749
                    e = APR_BRIGADE_FIRST(b);
1750
1770
1751
                    ctx->data_sent = 1;
1771
                /* Ensure the last bucket to pass down is a flush if
1752
                }
1772
                 * the next read will block. */
1753
                eblock = APR_BLOCK_READ;
1773
                flush = apr_bucket_flush_create(f->c->bucket_alloc);
1754
                continue;
1774
                APR_BUCKET_INSERT_BEFORE(e, flush);
1755
            }
1775
            }
1756
            else {
1757
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574)
1758
                              "ap_content_length_filter: "
1759
                              "apr_bucket_read() failed");
1760
                return rv;
1761
            }
1762
        }
1776
        }
1763
        else {
1777
1764
            r->bytes_sent += e->length;
1778
        /* On reaching here, pass on everything in the brigade up to
1779
         * this point. */
1780
        apr_brigade_split_ex(b, e, ctx->tmpbb);
1781
        
1782
        rv = ap_pass_brigade(f->next, b);
1783
        if (rv != APR_SUCCESS) {
1784
            return rv;
1765
        }
1785
        }
1766
        e = APR_BUCKET_NEXT(e);
1786
        else if (f->c->aborted) {
1787
            return APR_ECONNABORTED;
1788
        }
1789
        apr_brigade_cleanup(b);
1790
        APR_BRIGADE_CONCAT(b, ctx->tmpbb);
1791
        e = APR_BRIGADE_FIRST(b);
1792
        
1793
        ctx->data_sent = 1;
1767
    }
1794
    }
1768
1795
1769
    /* If we've now seen the entire response and it's otherwise
1796
    /* If we've now seen the entire response and it's otherwise

Return to bug 61222