1
0
mirror of https://github.com/apache/httpd.git synced 2026-10-23 22:49:01 +03:00

* modules/filters/mod_sed.c (sed_request_filter): Fix handling of the

Content-Length request header; unset it after reading from the next
  filter.

* test/pyhttpd/mod_aptest/mod_aptest.c (aptest_getline_echo): Buffer
  the body, and return the Content-Length request header left after
  reading it in an AP-Test-Content-Length response header.

* test/modules/filters/test_003_sed.py (test_filters_003_34): New test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub: PR #791


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1938964 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Joe Orton
2026-10-09 19:37:05 +00:00
parent f16faef3c2
commit 968022ebc5
3 changed files with 48 additions and 8 deletions

View File

@@ -516,6 +516,11 @@ static apr_status_t sed_request_filter(ap_filter_t *f,
if (status != APR_SUCCESS) {
return status;
}
/* The body passed on is not the length the request gave. Only
* drop the header after this read: HTTP_IN takes the length from
* it on the first.
*/
apr_table_unset(f->r->headers_in, "Content-Length");
for (b = APR_BRIGADE_FIRST(bbinp); b != APR_BRIGADE_SENTINEL(bbinp);
b = APR_BUCKET_NEXT(b)) {
const char *buf = NULL;

View File

@@ -386,6 +386,27 @@ class TestSed:
assert r.response["status"] == 200
assert r.response["body"] == b"one MON two\nMON MON\n"
# The request Content-Length is the length of the body before it was
# filtered, so once mod_sed has started reading the body it is removed:
# a handler must not find the original length.
def test_filters_003_34(self, env):
self.configure(env, "s/monday/MONDAYMONDAY/g", input_sed=True,
extra="""
<Location "/getline">
SetHandler aptest-getline-echo
SetInputFilter SED
</Location>
""")
data = "one monday two\nmonday monday\n"
r = env.curl_post_data(env.mkurl("http", "test1", "/getline"),
data=data)
assert r.response, "no response"
assert r.response["status"] == 200
assert r.response["body"] == \
data.replace("monday", "MONDAYMONDAY").encode()
assert "ap-test-content-length" not in r.response["header"], \
r.response["header"]
# --- interval expressions ---------------------------------------------
# \{m,n\} repeats a character or a bracket expression.

View File

@@ -76,11 +76,16 @@ static int aptest_allow_methods(request_rec *r)
/*
* Handler "aptest-getline-echo": echo the request body back, reading it
* with AP_MODE_GETLINE rather than AP_MODE_READBYTES.
* with AP_MODE_GETLINE rather than AP_MODE_READBYTES. The Content-Length
* request header left once the body has been read, if any, is returned in
* an "AP-Test-Content-Length" response header.
*/
static int aptest_getline_echo(request_rec *r)
{
apr_bucket_brigade *bb;
apr_bucket_brigade *bb, *body;
const char *clen;
char *data;
apr_size_t len;
apr_status_t rv;
int seen_eos = 0;
@@ -88,12 +93,9 @@ static int aptest_getline_echo(request_rec *r)
return DECLINED;
}
ap_set_content_type(r, "text/plain");
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
body = apr_brigade_create(r->pool, r->connection->bucket_alloc);
while (!seen_eos) {
char *line;
apr_size_t len;
rv = ap_get_brigade(r->input_filters, bb, AP_MODE_GETLINE,
APR_BLOCK_READ, HUGE_STRING_LEN);
if (rv != APR_SUCCESS) {
@@ -105,14 +107,26 @@ static int aptest_getline_echo(request_rec *r)
&& APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
seen_eos = 1;
}
rv = apr_brigade_pflatten(bb, &line, &len, r->pool);
rv = apr_brigade_pflatten(bb, &data, &len, r->pool);
if (rv == APR_SUCCESS) {
rv = apr_brigade_write(body, NULL, NULL, data, len);
}
if (rv != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
}
ap_rwrite(line, len, r);
apr_brigade_cleanup(bb);
}
clen = apr_table_get(r->headers_in, "Content-Length");
if (clen) {
apr_table_setn(r->headers_out, "AP-Test-Content-Length", clen);
}
ap_set_content_type(r, "text/plain");
if (apr_brigade_pflatten(body, &data, &len, r->pool) != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
}
ap_rwrite(data, len, r);
return OK;
}