Skip to content

Commit a7a9d81

Browse files
committed
fix header merging
Reviewed By: rpluem, jorton, ylavic git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927039 13f79535-47bb-0310-9956-ffa450edef68
1 parent e7fe55c commit a7a9d81

File tree

1 file changed

+128
-120
lines changed

1 file changed

+128
-120
lines changed

modules/http/http_filters.c

Lines changed: 128 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,107 +1300,10 @@ typedef struct header_filter_ctx {
13001300
int headers_sent;
13011301
} header_filter_ctx;
13021302

1303-
AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
1304-
apr_bucket_brigade *b)
1303+
static void merge_response_headers(request_rec *r, const char **protocol)
13051304
{
1306-
request_rec *r = f->r;
1307-
conn_rec *c = r->connection;
1308-
const char *clheader;
1309-
int header_only = (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status));
1310-
const char *protocol = NULL;
1311-
apr_bucket *e;
1312-
apr_bucket_brigade *b2;
1313-
header_struct h;
1314-
header_filter_ctx *ctx = f->ctx;
1315-
const char *ctype;
1316-
ap_bucket_error *eb = NULL;
1317-
apr_status_t rv = APR_SUCCESS;
1318-
int recursive_error = 0;
1319-
1320-
AP_DEBUG_ASSERT(!r->main);
1321-
1322-
if (!ctx) {
1323-
ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx));
1324-
}
1325-
else if (ctx->headers_sent) {
1326-
/* Eat body if response must not have one. */
1327-
if (header_only) {
1328-
/* Still next filters may be waiting for EOS, so pass it (alone)
1329-
* when encountered and be done with this filter.
1330-
*/
1331-
e = APR_BRIGADE_LAST(b);
1332-
if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
1333-
APR_BUCKET_REMOVE(e);
1334-
apr_brigade_cleanup(b);
1335-
APR_BRIGADE_INSERT_HEAD(b, e);
1336-
ap_remove_output_filter(f);
1337-
rv = ap_pass_brigade(f->next, b);
1338-
}
1339-
apr_brigade_cleanup(b);
1340-
return rv;
1341-
}
1342-
}
1343-
1344-
for (e = APR_BRIGADE_FIRST(b);
1345-
e != APR_BRIGADE_SENTINEL(b);
1346-
e = APR_BUCKET_NEXT(e))
1347-
{
1348-
if (AP_BUCKET_IS_ERROR(e) && !eb) {
1349-
eb = e->data;
1350-
continue;
1351-
}
1352-
/*
1353-
* If we see an EOC bucket it is a signal that we should get out
1354-
* of the way doing nothing.
1355-
*/
1356-
if (AP_BUCKET_IS_EOC(e)) {
1357-
ap_remove_output_filter(f);
1358-
return ap_pass_brigade(f->next, b);
1359-
}
1360-
}
1361-
1362-
if (!ctx->headers_sent && !check_headers(r)) {
1363-
/* We may come back here from ap_die() below,
1364-
* so clear anything from this response.
1365-
*/
1366-
apr_table_clear(r->headers_out);
1367-
apr_table_clear(r->err_headers_out);
1368-
r->content_type = r->content_encoding = NULL;
1369-
r->content_languages = NULL;
1370-
r->clength = r->chunked = 0;
1371-
apr_brigade_cleanup(b);
1372-
1373-
/* Don't recall ap_die() if we come back here (from its own internal
1374-
* redirect or error response), otherwise we can end up in infinite
1375-
* recursion; better fall through with 500, minimal headers and an
1376-
* empty body (EOS only).
1377-
*/
1378-
if (!check_headers_recursion(r)) {
1379-
ap_die(HTTP_INTERNAL_SERVER_ERROR, r);
1380-
return AP_FILTER_ERROR;
1381-
}
1382-
r->status = HTTP_INTERNAL_SERVER_ERROR;
1383-
e = ap_bucket_eoc_create(c->bucket_alloc);
1384-
APR_BRIGADE_INSERT_TAIL(b, e);
1385-
e = apr_bucket_eos_create(c->bucket_alloc);
1386-
APR_BRIGADE_INSERT_TAIL(b, e);
1387-
ap_set_content_length(r, 0);
1388-
recursive_error = 1;
1389-
}
1390-
else if (eb) {
1391-
int status;
1392-
status = eb->status;
1393-
apr_brigade_cleanup(b);
1394-
ap_die(status, r);
1395-
return AP_FILTER_ERROR;
1396-
}
1397-
1398-
if (r->assbackwards) {
1399-
r->sent_bodyct = 1;
1400-
ap_remove_output_filter(f);
1401-
rv = ap_pass_brigade(f->next, b);
1402-
goto out;
1403-
}
1305+
const char *ctype = NULL;
1306+
const char *clheader = NULL;
14041307

14051308
/*
14061309
* Now that we are ready to send a response, we need to combine the two
@@ -1430,6 +1333,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
14301333
fixup_vary(r);
14311334
}
14321335

1336+
/* determine the protocol and whether we should use keepalives. */
1337+
basic_http_header_check(r, protocol);
1338+
ap_set_keepalive(r);
14331339

14341340
/*
14351341
* Control cachability for non-cacheable responses if not already set by
@@ -1449,10 +1355,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
14491355
apr_table_unset(r->headers_out, "ETag");
14501356
}
14511357

1452-
/* determine the protocol and whether we should use keepalives. */
1453-
basic_http_header_check(r, &protocol);
1454-
ap_set_keepalive(r);
1455-
14561358
/* 204/304 responses don't have content related headers */
14571359
if (AP_STATUS_IS_HEADER_ONLY(r->status)) {
14581360
apr_table_unset(r->headers_out, "Transfer-Encoding");
@@ -1513,30 +1415,136 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
15131415
&& !strcmp(clheader, "0")) {
15141416
apr_table_unset(r->headers_out, "Content-Length");
15151417
}
1418+
}
15161419

1517-
b2 = apr_brigade_create(r->pool, c->bucket_alloc);
1518-
basic_http_header(r, b2, protocol);
1519-
1520-
h.pool = r->pool;
1521-
h.bb = b2;
1420+
AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
1421+
apr_bucket_brigade *b)
1422+
{
1423+
request_rec *r = f->r;
1424+
conn_rec *c = r->connection;
1425+
int header_only = (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status));
1426+
apr_bucket *e;
1427+
apr_bucket_brigade *b2;
1428+
header_struct h;
1429+
header_filter_ctx *ctx = f->ctx;
1430+
ap_bucket_error *eb = NULL;
1431+
apr_status_t rv = APR_SUCCESS;
1432+
int recursive_error = 0;
1433+
const char *protocol;
15221434

1523-
send_all_header_fields(&h, r);
1435+
AP_DEBUG_ASSERT(!r->main);
15241436

1525-
terminate_header(b2);
1437+
if (!ctx) {
1438+
ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx));
1439+
}
1440+
else if (ctx->headers_sent) {
1441+
/* Eat body if response must not have one. */
1442+
if (header_only) {
1443+
/* Still next filters may be waiting for EOS, so pass it (alone)
1444+
* when encountered and be done with this filter.
1445+
*/
1446+
e = APR_BRIGADE_LAST(b);
1447+
if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
1448+
APR_BUCKET_REMOVE(e);
1449+
apr_brigade_cleanup(b);
1450+
APR_BRIGADE_INSERT_HEAD(b, e);
1451+
ap_remove_output_filter(f);
1452+
rv = ap_pass_brigade(f->next, b);
1453+
}
1454+
apr_brigade_cleanup(b);
1455+
return rv;
1456+
}
1457+
}
15261458

1527-
if (header_only) {
1528-
e = APR_BRIGADE_LAST(b);
1529-
if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
1530-
APR_BUCKET_REMOVE(e);
1531-
APR_BRIGADE_INSERT_TAIL(b2, e);
1459+
for (e = APR_BRIGADE_FIRST(b);
1460+
e != APR_BRIGADE_SENTINEL(b);
1461+
e = APR_BUCKET_NEXT(e))
1462+
{
1463+
if (AP_BUCKET_IS_ERROR(e) && !eb) {
1464+
eb = e->data;
1465+
continue;
1466+
}
1467+
/*
1468+
* If we see an EOC bucket it is a signal that we should get out
1469+
* of the way doing nothing.
1470+
*/
1471+
if (AP_BUCKET_IS_EOC(e)) {
15321472
ap_remove_output_filter(f);
1473+
return ap_pass_brigade(f->next, b);
1474+
}
1475+
}
1476+
1477+
if (!ctx->headers_sent) {
1478+
merge_response_headers(r, &protocol);
1479+
if (!check_headers(r)) {
1480+
/* We may come back here from ap_die() below,
1481+
* so clear anything from this response.
1482+
*/
1483+
apr_table_clear(r->headers_out);
1484+
apr_table_clear(r->err_headers_out);
1485+
r->content_type = r->content_encoding = NULL;
1486+
r->content_languages = NULL;
1487+
r->clength = r->chunked = 0;
1488+
apr_brigade_cleanup(b);
1489+
1490+
/* Don't recall ap_die() if we come back here (from its own internal
1491+
* redirect or error response), otherwise we can end up in infinite
1492+
* recursion; better fall through with 500, minimal headers and an
1493+
* empty body (EOS only).
1494+
*/
1495+
if (!check_headers_recursion(r)) {
1496+
ap_die(HTTP_INTERNAL_SERVER_ERROR, r);
1497+
return AP_FILTER_ERROR;
1498+
}
1499+
r->status = HTTP_INTERNAL_SERVER_ERROR;
1500+
e = ap_bucket_eoc_create(c->bucket_alloc);
1501+
APR_BRIGADE_INSERT_TAIL(b, e);
1502+
e = apr_bucket_eos_create(c->bucket_alloc);
1503+
APR_BRIGADE_INSERT_TAIL(b, e);
1504+
ap_set_content_length(r, 0);
1505+
recursive_error = 1;
1506+
}
1507+
else if (eb) {
1508+
int status;
1509+
status = eb->status;
1510+
apr_brigade_cleanup(b);
1511+
ap_die(status, r);
1512+
return AP_FILTER_ERROR;
15331513
}
1534-
apr_brigade_cleanup(b);
15351514
}
15361515

1537-
rv = ap_pass_brigade(f->next, b2);
1538-
apr_brigade_cleanup(b2);
1539-
ctx->headers_sent = 1;
1516+
if (r->assbackwards) {
1517+
r->sent_bodyct = 1;
1518+
ap_remove_output_filter(f);
1519+
rv = ap_pass_brigade(f->next, b);
1520+
goto out;
1521+
}
1522+
1523+
if (!ctx->headers_sent) {
1524+
b2 = apr_brigade_create(r->pool, c->bucket_alloc);
1525+
basic_http_header(r, b2, protocol);
1526+
1527+
h.pool = r->pool;
1528+
h.bb = b2;
1529+
1530+
send_all_header_fields(&h, r);
1531+
1532+
terminate_header(b2);
1533+
1534+
if (header_only) {
1535+
e = APR_BRIGADE_LAST(b);
1536+
if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
1537+
APR_BUCKET_REMOVE(e);
1538+
APR_BRIGADE_INSERT_TAIL(b2, e);
1539+
ap_remove_output_filter(f);
1540+
}
1541+
apr_brigade_cleanup(b);
1542+
}
1543+
1544+
rv = ap_pass_brigade(f->next, b2);
1545+
apr_brigade_cleanup(b2);
1546+
ctx->headers_sent = 1;
1547+
}
15401548

15411549
if (rv != APR_SUCCESS || header_only) {
15421550
goto out;

0 commit comments

Comments
 (0)