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

(-)docs/manual/mod/mod_include.xml (-4 / +63 lines)
Lines 313-323 Link Here
313
      <glossary>MIME-type</glossary> (<code>text/plain</code>,
313
      <glossary>MIME-type</glossary> (<code>text/plain</code>,
314
      <code>text/html</code> etc.) will be included. Otherwise CGI
314
      <code>text/html</code> etc.) will be included. Otherwise CGI
315
      scripts are invoked as normal using the complete URL given in
315
      scripts are invoked as normal using the complete URL given in
316
      the command, including any query string.</p>
316
      the command, including any query string. POST data is not passed
317
      to the script by default.</p>
317
318
318
      <p>An attribute defines the location of the document; the
319
      <p>A location attribute defines the location of the document; the
319
      inclusion is done for each attribute given to the include
320
      inclusion is done for each location attribute given to the include
320
      command. The valid attributes are:</p>
321
      command. The valid location attributes are:</p>
321
322
322
      <dl>
323
      <dl>
323
      <dt><code>file</code></dt>
324
      <dt><code>file</code></dt>
Lines 353-358 Link Here
353
      into an HTML document.</p>
354
      into an HTML document.</p>
354
      </dd>
355
      </dd>
355
      </dl>
356
      </dl>
357
358
      <p>In addition to location attributes, the inclusion might also have 
359
      parameter attributes given after the location attribute.
360
      Valid parameter attribues are:</p>
361
362
      <dl>
363
      <dt><code>postconsumer</code></dt>
364
      <dd>The flag controls the passing of data sent by the client in POST request.
365
      By default, POST-data is not passed to the subrequest unless this flag is set to "yes".
366
      Only one subrequest can be the postconsumer and thus have the POST data.
367
      </dd>
368
369
      <dt><code>add-headers</code></dt>
370
      <dd><p>The value is a string containing whitespace separated list of expressions
371
       defining which headers should be added to the response.</p>
372
       <p>The syntax of one expression is following:</p>
373
       <note>
374
<pre>Expression :-&gt; Rangedef Header-name
375
Rangedef :-&gt; Range ":" | empty
376
Header-name :-> string
377
Range :-&gt; "*" | Value | Value "-" Value
378
Value :-&gt; "[0-9]+"</pre>
379
       </note>
380
       The header-name is the name of the header that is wanted to be added.
381
       Values in range is either all(*), first n elements, a range (n-m).
382
       If the range is omitted, first element is assumed.
383
      </dd>
384
385
      <dt><code>replace-headers</code></dt>
386
      <dd>Similar to add-headers, but instead of adding the headers, the original headers
387
      are replaced. <note>If a special header <strong>status</strong> is replaced, then
388
      the return status of the subrequest is passed to the main request. This is useful
389
      especially when doing redirections.</note>
390
      </dd>
391
      </dl>
392
393
      <example><title>Example</title>
394
        &lt;!--#include virtual="/cgi-bin/example.cgi" postconsumer="yes" add-headers="*:Set-cookie" replace-headers="location status" --&gt;
395
      </example>
396
356
    </section> <!-- /include -->
397
    </section> <!-- /include -->
357
398
358
    <section id="element.printenv"><title>The printenv Element</title>
399
    <section id="element.printenv"><title>The printenv Element</title>
Lines 745-750 Link Here
745
</directivesynopsis>
786
</directivesynopsis>
746
787
747
<directivesynopsis>
788
<directivesynopsis>
789
<name>SSIBuffering</name>
790
<description>Enables output buffering in SSI filtered
791
requests</description>
792
<syntax>SSIBuffering on|off</syntax>
793
<default>SSIBuffering off</default>
794
<contextlist><context>server config</context><context>virtual host</context>
795
<context>directory</context><context>.htaccess</context></contextlist>
796
<override>Options</override>
797
<usage>
798
  <p>The <directive>SSIBuffering</directive> directive controls the buffering
799
  of the output of SSI documents. You might want to enable buffering if you
800
  want to pass response headers from some of the included documents that
801
  are included in the middle of your document.</p>
802
</usage>
803
804
</directivesynopsis>
805
806
<directivesynopsis>
748
<name>XBitHack</name>
807
<name>XBitHack</name>
749
<description>Parse SSI directives in files with the execute bit
808
<description>Parse SSI directives in files with the execute bit
750
set</description>
809
set</description>
(-)modules/filters/mod_include.c (-21 / +302 lines)
Lines 114-119 Link Here
114
    const char *default_time_fmt;
114
    const char *default_time_fmt;
115
    const char *undefined_echo;
115
    const char *undefined_echo;
116
    xbithack_t  xbithack;
116
    xbithack_t  xbithack;
117
    int output_buffering;
117
} include_dir_config;
118
} include_dir_config;
118
119
119
typedef struct {
120
typedef struct {
Lines 1489-1494 Link Here
1489
}
1490
}
1490
1491
1491
1492
1493
/*  Loopback filter
1494
 *  An output filter that passes all output to a destination
1495
 *  bucket brigade given in the initialization phase.
1496
 */
1497
1498
struct loopback_ctx {
1499
    apr_bucket_brigade *pass_bb;
1500
};
1501
1502
static ap_filter_t *create_loopback_filter(request_rec *r,
1503
                                           apr_bucket_brigade * destination)
1504
{
1505
1506
    ap_filter_t *f = (ap_filter_t *) apr_palloc(r->pool, sizeof(ap_filter_t));
1507
    struct loopback_ctx *ctx =
1508
        (struct loopback_ctx *) apr_palloc(r->pool,
1509
                                           sizeof(struct loopback_ctx));
1510
    ctx->pass_bb = destination;
1511
    f->ctx = ctx;
1512
    f->r = r;
1513
    f->c = NULL;
1514
    f->next = NULL;
1515
    f->frec = ap_get_output_filter_handle("LOOPBACK");
1516
    return f;
1517
}
1518
1519
static apr_status_t loopback_filter(ap_filter_t * f, apr_bucket_brigade * b)
1520
{
1521
    request_rec *r = f->r;
1522
    struct loopback_ctx *ctx;
1523
    apr_bucket *e;
1524
    int eos = 0;
1525
    ctx = f->ctx;
1526
    ap_assert(ctx);
1527
    APR_BRIGADE_CONCAT(ctx->pass_bb, b);
1528
    return APR_SUCCESS;
1529
}
1530
1531
1532
1533
/* --------------------------- Header copier ------------------------------
1534
 * A callback functionset that copies some elements of the table.
1535
 *
1536
 */
1537
1538
1539
struct header_transfer_ctx {
1540
    apr_pool_t *pool;
1541
    apr_table_t *dst;           // Destination table where to write
1542
    apr_table_t *wanted;        //Table mapping key to entries wanted
1543
    void (*table_addsetfn) (apr_table_t *, const char *, const char *); // Function to add to table
1544
    //Internal state
1545
    apr_hash_t *seen;           //Hash mapping key to entries seen
1546
};
1547
1548
1549
static struct header_transfer_ctx *create_ht_ctx(apr_pool_t * pool,
1550
                                                 apr_table_t * dst,
1551
                                                 const char *str, int replace)
1552
{
1553
    struct header_transfer_ctx *ctx = apr_palloc(pool, sizeof *ctx);
1554
    ctx->dst = dst;
1555
    ctx->pool = pool;
1556
    ctx->seen = apr_hash_make(pool);
1557
    ctx->wanted = apr_table_make(pool, 1);
1558
1559
1560
    ctx->table_addsetfn = replace ? apr_table_set : apr_table_add;
1561
1562
    /*
1563
       Elements are of form:
1564
       '*:string' -- All elements
1565
       '[0-9]+-[0-9]+:string' -- Elements n-m
1566
       '[0-9]+:string' -- First n elements
1567
       String is of form:
1568
       '(element) (element) (element) ...'
1569
     */
1570
1571
    // Split element from strings
1572
    {
1573
        char *state;
1574
        char *s = apr_pstrdup(pool, str);
1575
        ap_regex_t *count_split =
1576
            ap_pregcomp(pool, "^(([^:]+):)?(.*)$", AP_REG_EXTENDED);
1577
        ap_regmatch_t m[4];
1578
        s = apr_strtok(s, " \t", &state);
1579
        // Split element further
1580
        do {
1581
            if (ap_regexec(count_split, s, 4, m, 0) != 0)
1582
                return NULL;
1583
            if (m[3].rm_so == -1 || m[3].rm_so == m[3].rm_eo)   // Errornenous pattern
1584
                return NULL;
1585
            char *key =
1586
                apr_pstrndup(pool, &s[m[3].rm_so], m[3].rm_eo - m[3].rm_so);
1587
1588
            if (m[2].rm_so == -1)       // No range spesified, pass only first one
1589
                apr_table_addn(ctx->wanted, key, "1");
1590
            else
1591
                apr_table_addn(ctx->wanted, key,
1592
                               apr_pstrndup(pool, &s[m[2].rm_so],
1593
                                            m[2].rm_eo - m[2].rm_so));
1594
        } while (NULL != (s = apr_strtok(NULL, " \t", &state)));
1595
    }
1596
    return ctx;
1597
}
1598
1599
static int transfer_headers(void *ctxptr, const char *key, const char *value)
1600
{
1601
    struct header_transfer_ctx *ctx = ctxptr;
1602
    /* Real implementation: */
1603
    const char *match = apr_table_get(ctx->wanted, key);
1604
    char *p;
1605
    int *count;
1606
    if (!match)
1607
        return TRUE;            // We will continue with new key
1608
1609
    if (match[0] == '*') {
1610
        ctx->table_addsetfn(ctx->dst, key, value);
1611
        return TRUE;
1612
    }
1613
1614
    // Some counting has to be done
1615
    count = apr_hash_get(ctx->seen, key, APR_HASH_KEY_STRING);
1616
    if (!count) {
1617
        count = apr_palloc(ctx->pool, sizeof(int));
1618
        *count = 1;
1619
        apr_hash_set(ctx->seen, key, APR_HASH_KEY_STRING, count);
1620
    }
1621
    else {
1622
        (*count)++;
1623
    }
1624
1625
1626
    // Figure out the match syntax further
1627
    if (NULL != (p = index(match, '-'))) {      // Has dash; patches between two numbers are accepted
1628
        if (*count < atoi(match) || *count > atoi(&p[1]))
1629
            return TRUE;
1630
1631
    }
1632
    else {                      // Only one number; patches <= number are accepted
1633
        if (*count > atoi(match))
1634
            return TRUE;
1635
    }
1636
1637
    ctx->table_addsetfn(ctx->dst, key, value);
1638
    return TRUE;
1639
}
1640
1641
/* --------------------------- Input-blocking filter ----------------------
1642
 * An input filter that blocks input by sending end of stream buckets as
1643
 * needed.
1644
 */
1645
1646
static int input_blocker(ap_filter_t * f, apr_bucket_brigade * bb,
1647
                         ap_input_mode_t mode, apr_read_type_e block,
1648
                         apr_off_t readbytes)
1649
{
1650
    if (f->r->proxyreq) {
1651
        return ap_get_brigade(f->next, bb, mode, block, readbytes);
1652
    }
1653
    APR_BRIGADE_INSERT_TAIL(bb,
1654
                            apr_bucket_eos_create(f->r->connection->
1655
                                                  bucket_alloc));
1656
    return APR_SUCCESS;
1657
}
1658
1659
static void drop_input_blocker(request_rec *r)
1660
{
1661
    ap_filter_rec_t *rec = ap_get_input_filter_handle("INCLUDES_IN");
1662
    while (r->input_filters->frec == rec && r->input_filters->r == r)
1663
        ap_remove_input_filter(r->input_filters);
1664
}
1665
1666
static void add_input_blocker(request_rec *r)
1667
{
1668
    ap_filter_rec_t *rec = ap_get_input_filter_handle("INCLUDES_IN");
1669
    if (r->input_filters->frec != rec) {
1670
        ap_add_input_filter_handle(rec, NULL, r, r->connection);
1671
    }
1672
1673
}
1674
1675
1492
/*
1676
/*
1493
 * +-------------------------------------------------------+
1677
 * +-------------------------------------------------------+
1494
 * |                                                       |
1678
 * |                                                       |
Lines 1602-1607 Link Here
1602
    }
1786
    }
1603
}
1787
}
1604
1788
1789
1790
1791
struct subrequest_t {
1792
    int type;
1793
    int is_postconsumer;
1794
    char *location;
1795
    char *add_headers;
1796
    char *replace_headers;
1797
};
1798
1799
static void handle_one_subrq(include_ctx_t * ctx, ap_filter_t * f,
1800
                             apr_bucket_brigade * bb,
1801
                             struct subrequest_t *sr);
1802
1803
1605
/*
1804
/*
1606
 * <!--#include virtual|file="..." [virtual|file="..."] ... -->
1805
 * <!--#include virtual|file="..." [virtual|file="..."] ... -->
1607
 */
1806
 */
Lines 1609-1614 Link Here
1609
                                   apr_bucket_brigade *bb)
1808
                                   apr_bucket_brigade *bb)
1610
{
1809
{
1611
    request_rec *r = f->r;
1810
    request_rec *r = f->r;
1811
    struct subrequest_t sr = {0,0,NULL,NULL,NULL};
1612
1812
1613
    if (!ctx->argc) {
1813
    if (!ctx->argc) {
1614
        ap_log_rerror(APLOG_MARK,
1814
        ap_log_rerror(APLOG_MARK,
Lines 1630-1659 Link Here
1630
    while (1) {
1830
    while (1) {
1631
        char *tag     = NULL;
1831
        char *tag     = NULL;
1632
        char *tag_val = NULL;
1832
        char *tag_val = NULL;
1633
        request_rec *rr = NULL;
1634
        char *error_fmt = NULL;
1635
        char *parsed_string;
1636
1833
1637
        ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
1834
        ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
1638
        if (!tag || !tag_val) {
1835
        if (!tag || !tag_val) {
1836
            handle_one_subrq(ctx,f,bb,&sr);
1639
            break;
1837
            break;
1640
        }
1838
        }
1641
1839
1642
        if (strcmp(tag, "virtual") && strcmp(tag, "file")) {
1840
        if (!strcmp(tag, "virtual") || !strcmp(tag, "file")) {
1841
            handle_one_subrq(ctx, f, bb, &sr);
1842
            memset(&sr, 0, sizeof(sr));
1843
            sr.type = tag[0];
1844
            sr.location = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
1845
                                              SSI_EXPAND_DROP_NAME);
1846
        }
1847
        else if (!strcmp(tag, "postconsumer"))
1848
            sr.is_postconsumer = !strcasecmp(tag_val, "yes");
1849
        else if (!strcmp(tag, "add-headers"))
1850
            sr.add_headers = tag_val;
1851
        else if (!strcmp(tag, "replace_headers"))
1852
            sr.replace_headers = tag_val;
1853
        else {
1643
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
1854
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
1644
                          "\"%s\" to tag include in %s", tag, r->filename);
1855
                          "\"%s\" to tag include in %s", tag, r->filename);
1645
            SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
1856
            SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
1646
            break;
1857
            break;
1647
        }
1858
        }
1859
    }
1648
1860
1649
        parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
1861
    return APR_SUCCESS;
1650
                                            SSI_EXPAND_DROP_NAME);
1862
}
1651
        if (tag[0] == 'f') {
1863
1864
static void handle_one_subrq(include_ctx_t *ctx,ap_filter_t *f,
1865
                            apr_bucket_brigade *bb,
1866
                            struct subrequest_t *sr) {
1867
1868
    request_rec *r = f->r;
1869
    request_rec *rr = NULL;
1870
    char *error_fmt = NULL;
1871
    ap_filter_t *loopback;
1872
1873
1874
    if (sr->type) {
1875
        loopback = create_loopback_filter(r,bb);
1876
        if (sr->type == 'f') {
1652
            char *newpath;
1877
            char *newpath;
1653
            apr_status_t rv;
1878
            apr_status_t rv;
1654
1879
1655
            /* be safe; only files in this directory or below allowed */
1880
            /* be safe; only files in this directory or below allowed */
1656
            rv = apr_filepath_merge(&newpath, NULL, parsed_string,
1881
            rv = apr_filepath_merge(&newpath, NULL, sr->location,
1657
                                    APR_FILEPATH_SECUREROOTTEST |
1882
                                    APR_FILEPATH_SECUREROOTTEST |
1658
                                    APR_FILEPATH_NOTABSOLUTE, ctx->dpool);
1883
                                    APR_FILEPATH_NOTABSOLUTE, ctx->dpool);
1659
1884
Lines 1661-1671 Link Here
1661
                error_fmt = "unable to include file \"%s\" in parsed file %s";
1886
                error_fmt = "unable to include file \"%s\" in parsed file %s";
1662
            }
1887
            }
1663
            else {
1888
            else {
1664
                rr = ap_sub_req_lookup_file(newpath, r, f->next);
1889
                rr = ap_sub_req_lookup_file(newpath, r, loopback);
1665
            }
1890
            }
1666
        }
1891
        }
1667
        else {
1892
        else {
1668
            rr = ap_sub_req_lookup_uri(parsed_string, r, f->next);
1893
            if (sr->is_postconsumer)
1894
                drop_input_blocker(r);
1895
1896
            rr = ap_sub_req_method_uri(r->method, sr->location, r, loopback);
1897
            if (sr->is_postconsumer) {
1898
                /* Pass POST-related headers */
1899
                rr->headers_in = apr_table_copy(rr->pool, r->headers_in);
1900
1901
                /* Write Content-Length to clength-field.
1902
                 * This is required for mod-jk to function correctly.
1903
                 */
1904
                char *lenp = 
1905
                    (char *) apr_table_get(r->headers_in, "Content-Length");
1906
                if (lenp) {
1907
                    int rc = atoi(lenp);
1908
                    rr->clength= rc > 0 ? rc : 0;
1909
                }
1910
            }
1911
1669
        }
1912
        }
1670
1913
1671
        if (!error_fmt && rr->status != HTTP_OK) {
1914
        if (!error_fmt && rr->status != HTTP_OK) {
Lines 1691-1698 Link Here
1691
            error_fmt = "unable to include \"%s\" in parsed file %s";
1934
            error_fmt = "unable to include \"%s\" in parsed file %s";
1692
        }
1935
        }
1693
1936
1937
        if (!error_fmt && sr->replace_headers) {
1938
            struct header_transfer_ctx *hctx =
1939
                create_ht_ctx(r->pool, r->headers_out, sr->replace_headers,
1940
                              TRUE);
1941
            if (hctx) {
1942
                apr_table_do(transfer_headers, hctx, rr->headers_out, NULL);
1943
                if (apr_table_get(hctx->wanted, "status"))
1944
                    r->status = rr->status;
1945
            }
1946
            else
1947
                error_fmt = "unable to parse replace-headers of \"%s\" "
1948
                    "in parsed file %s";
1949
        }
1950
1951
        if (!error_fmt && sr->add_headers) {
1952
            struct header_transfer_ctx *hctx =
1953
                create_ht_ctx(r->pool, r->headers_out, sr->add_headers,
1954
                              FALSE);
1955
            if (hctx)
1956
                apr_table_do(transfer_headers, hctx, rr->headers_out, NULL);
1957
            else
1958
                error_fmt = "unable to parse add-headers of \"%s\""
1959
                    "in parsed file %s";
1960
        }
1961
1694
        if (error_fmt) {
1962
        if (error_fmt) {
1695
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error_fmt, tag_val,
1963
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error_fmt, sr->location,
1696
                          r->filename);
1964
                          r->filename);
1697
            SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
1965
            SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
1698
        }
1966
        }
Lines 1701-1713 Link Here
1701
         * variables in this r->subprocess_env in the subrequest's
1969
         * variables in this r->subprocess_env in the subrequest's
1702
         * r->pool, so that pool must survive as long as this request.
1970
         * r->pool, so that pool must survive as long as this request.
1703
         * Yes, this is a memory leak. */
1971
         * Yes, this is a memory leak. */
1704
1705
        if (error_fmt) {
1706
            break;
1707
        }
1708
    }
1972
    }
1709
1973
1710
    return APR_SUCCESS;
1711
}
1974
}
1712
1975
1713
/*
1976
/*
Lines 3052-3058 Link Here
3052
/*
3315
/*
3053
 * This is the main loop over the current bucket brigade.
3316
 * This is the main loop over the current bucket brigade.
3054
 */
3317
 */
3055
static apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb)
3318
static apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb,int output_buffering)
3056
{
3319
{
3057
    include_ctx_t *ctx = f->ctx;
3320
    include_ctx_t *ctx = f->ctx;
3058
    struct ssi_internal_ctx *intern = ctx->intern;
3321
    struct ssi_internal_ctx *intern = ctx->intern;
Lines 3137-3144 Link Here
3137
        }
3400
        }
3138
3401
3139
        /* enough is enough ... */
3402
        /* enough is enough ... */
3140
        if (ctx->flush_now ||
3403
        if (!output_buffering &&
3141
            intern->bytes_read > AP_MIN_BYTES_TO_WRITE) {
3404
            ( ctx->flush_now || intern->bytes_read > AP_MIN_BYTES_TO_WRITE)) {
3142
3405
3143
            if (!APR_BRIGADE_EMPTY(pass_bb)) {
3406
            if (!APR_BRIGADE_EMPTY(pass_bb)) {
3144
                rv = ap_pass_brigade(f->next, pass_bb);
3407
                rv = ap_pass_brigade(f->next, pass_bb);
Lines 3195-3201 Link Here
3195
            }
3458
            }
3196
3459
3197
            newb = APR_BUCKET_NEXT(b);
3460
            newb = APR_BUCKET_NEXT(b);
3198
            if (ctx->flags & SSI_FLAG_PRINTING) {
3461
            if (ctx->flags & SSI_FLAG_PRINTING && index) {
3199
                APR_BUCKET_REMOVE(b);
3462
                APR_BUCKET_REMOVE(b);
3200
                APR_BRIGADE_INSERT_TAIL(pass_bb, b);
3463
                APR_BRIGADE_INSERT_TAIL(pass_bb, b);
3201
            }
3464
            }
Lines 3487-3492 Link Here
3487
     * a program - in either case a strong ETag header will likely be invalid.
3750
     * a program - in either case a strong ETag header will likely be invalid.
3488
     */
3751
     */
3489
    apr_table_setn(f->r->notes, "no-etag", "");
3752
    apr_table_setn(f->r->notes, "no-etag", "");
3753
    add_input_blocker(f->r);
3490
3754
3491
    return OK;
3755
    return OK;
3492
}
3756
}
Lines 3506-3511 Link Here
3506
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
3770
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
3507
                      "mod_include: Options +Includes (or IncludesNoExec) "
3771
                      "mod_include: Options +Includes (or IncludesNoExec) "
3508
                      "wasn't set, INCLUDES filter removed");
3772
                      "wasn't set, INCLUDES filter removed");
3773
        drop_input_blocker(f->r);
3509
        ap_remove_output_filter(f);
3774
        ap_remove_output_filter(f);
3510
        return ap_pass_brigade(f->next, b);
3775
        return ap_pass_brigade(f->next, b);
3511
    }
3776
    }
Lines 3598-3604 Link Here
3598
                  ap_escape_shell_cmd(r->pool, arg_copy));
3863
                  ap_escape_shell_cmd(r->pool, arg_copy));
3599
    }
3864
    }
3600
3865
3601
    return send_parsed_content(f, b);
3866
    apr_status_t rc= send_parsed_content(f, b,conf->output_buffering);
3867
    drop_input_blocker(f->r);
3868
    return rc;
3602
}
3869
}
3603
3870
3604
static int include_fixup(request_rec *r)
3871
static int include_fixup(request_rec *r)
Lines 3660-3665 Link Here
3660
    result->default_time_fmt  = DEFAULT_TIME_FORMAT;
3927
    result->default_time_fmt  = DEFAULT_TIME_FORMAT;
3661
    result->undefined_echo    = DEFAULT_UNDEFINED_ECHO;
3928
    result->undefined_echo    = DEFAULT_UNDEFINED_ECHO;
3662
    result->xbithack          = DEFAULT_XBITHACK;
3929
    result->xbithack          = DEFAULT_XBITHACK;
3930
    result->output_buffering  = FALSE;
3663
3931
3664
    return result;
3932
    return result;
3665
}
3933
}
Lines 3762-3767 Link Here
3762
    return NULL;
4030
    return NULL;
3763
}
4031
}
3764
4032
4033
static const char *set_output_buffering(cmd_parms *cmd,void *mconfig,int arg)
4034
{
4035
    include_dir_config *conf = (include_dir_config *) mconfig;
4036
    conf->output_buffering = arg;
4037
    return NULL;
4038
}
3765
4039
3766
/*
4040
/*
3767
 * +-------------------------------------------------------+
4041
 * +-------------------------------------------------------+
Lines 3801-3806 Link Here
3801
                  "Off, On, or Full"),
4075
                  "Off, On, or Full"),
3802
    AP_INIT_TAKE1("SSIErrorMsg", set_default_error_msg, NULL, OR_ALL,
4076
    AP_INIT_TAKE1("SSIErrorMsg", set_default_error_msg, NULL, OR_ALL,
3803
                  "a string"),
4077
                  "a string"),
4078
    AP_INIT_FLAG("SSIBuffering", set_output_buffering, NULL,
4079
                 OR_OPTIONS | RSRC_CONF,
4080
                 "On or Off"),
3804
    AP_INIT_TAKE1("SSITimeFormat", set_default_time_fmt, NULL, OR_ALL,
4081
    AP_INIT_TAKE1("SSITimeFormat", set_default_time_fmt, NULL, OR_ALL,
3805
                  "a strftime(3) formatted string"),
4082
                  "a strftime(3) formatted string"),
3806
    AP_INIT_TAKE1("SSIStartTag", set_default_start_tag, NULL, RSRC_CONF,
4083
    AP_INIT_TAKE1("SSIStartTag", set_default_start_tag, NULL, RSRC_CONF,
Lines 3826-3831 Link Here
3826
    ap_hook_fixups(include_fixup, NULL, NULL, APR_HOOK_LAST);
4103
    ap_hook_fixups(include_fixup, NULL, NULL, APR_HOOK_LAST);
3827
    ap_register_output_filter("INCLUDES", includes_filter, includes_setup,
4104
    ap_register_output_filter("INCLUDES", includes_filter, includes_setup,
3828
                              AP_FTYPE_RESOURCE);
4105
                              AP_FTYPE_RESOURCE);
4106
    ap_register_input_filter("INCLUDES_IN", input_blocker, NULL,
4107
                             AP_FTYPE_RESOURCE);
4108
    ap_register_output_filter("LOOPBACK", loopback_filter,NULL,
4109
                              AP_FTYPE_PROTOCOL);
3829
}
4110
}
3830
4111
3831
module AP_MODULE_DECLARE_DATA include_module =
4112
module AP_MODULE_DECLARE_DATA include_module =

Return to bug 39748