Skip to content

Commit 8fe0ec8

Browse files
authored
Added support for "ProxyErrorOverride" directive in mod_proxy_http2. (#304)
1 parent c3a19c2 commit 8fe0ec8

File tree

7 files changed

+78
-7
lines changed

7 files changed

+78
-7
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* Added support for "ProxyErrorOverride" directive in mod_proxy_http2.
12
* Fix a bug in calculating the log2 value of integers, used in push
23
diaries and proxy window size calculations. Apache PR69741.
34
[Benjamin P. Kallus]

mod_http2/h2_proxy_session.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ typedef struct h2_proxy_stream {
4949
unsigned int waiting_on_ping : 1;
5050
unsigned int headers_ended : 1;
5151
uint32_t error_code;
52+
int proxy_status;
5253

5354
apr_bucket_brigade *input;
5455
apr_off_t data_sent;
@@ -310,6 +311,15 @@ static int on_frame_recv(nghttp2_session *ngh2, const nghttp2_frame *frame,
310311
ap_send_interim_response(r, 1);
311312
}
312313
}
314+
else if (r->status >= 400) {
315+
proxy_dir_conf *dconf;
316+
dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
317+
if (ap_proxy_should_override(dconf, r->status)) {
318+
apr_table_setn(r->notes, "proxy-error-override", "1");
319+
nghttp2_submit_rst_stream(ngh2, NGHTTP2_FLAG_NONE,
320+
frame->hd.stream_id, NGHTTP2_STREAM_CLOSED);
321+
}
322+
}
313323
stream_resume(stream);
314324
break;
315325
case NGHTTP2_PING:
@@ -856,8 +866,8 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url,
856866
* Host: header */
857867
authority = r->server->server_hostname;
858868
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10511)
859-
"HTTP/0.9 request (with no host line) "
860-
"on incoming request and preserve host set "
869+
"incoming HTTP/0.9 request (with no Host header) "
870+
"and preserve host set, "
861871
"forcing hostname to be %s for uri %s",
862872
authority, r->uri);
863873
apr_table_setn(r->headers_in, "Host", authority);

mod_http2/mod_proxy_http2.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,15 @@ static void request_done(h2_proxy_ctx *ctx, request_rec *r,
239239
ctx->id, touched, error_code);
240240
ctx->r_done = 1;
241241
if (touched) ctx->r_may_retry = 0;
242-
ctx->r_status = error_code? HTTP_BAD_GATEWAY :
243-
((status == APR_SUCCESS)? OK :
244-
ap_map_http_request_error(status, HTTP_SERVICE_UNAVAILABLE));
242+
if (apr_table_get(r->notes, "proxy-error-override")) {
243+
ctx->r_status = r->status;
244+
r->status = OK;
245+
}
246+
else {
247+
ctx->r_status = error_code? HTTP_BAD_GATEWAY :
248+
((status == APR_SUCCESS)? OK :
249+
ap_map_http_request_error(status, HTTP_SERVICE_UNAVAILABLE));
250+
}
245251
}
246252
}
247253

@@ -428,7 +434,12 @@ static int proxy_http2_handler(request_rec *r,
428434
if (ctx->cfront->aborted) goto cleanup;
429435
status = ctx_run(ctx);
430436

431-
if (ctx->r_status != APR_SUCCESS && ctx->r_may_retry && !ctx->cfront->aborted) {
437+
if (apr_table_get(r->notes, "proxy-error-override")) {
438+
/* pass on out */
439+
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->cfront,
440+
"proxy-error-override status %d", ctx->r_status);
441+
}
442+
else if (ctx->r_status != APR_SUCCESS && ctx->r_may_retry && !ctx->cfront->aborted) {
432443
/* Not successfully processed, but may retry, tear down old conn and start over */
433444
if (ctx->p_conn) {
434445
ctx->p_conn->close = 1;
@@ -463,7 +474,7 @@ static int proxy_http2_handler(request_rec *r,
463474

464475
ap_set_module_config(ctx->cfront->conn_config, &proxy_http2_module, NULL);
465476
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->cfront,
466-
APLOGNO(03377) "leaving handler");
477+
APLOGNO(03377) "leaving handler -> %d", ctx->r_status);
467478
return ctx->r_status;
468479
}
469480

test/modules/http2/env.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ def __init__(self, env: HttpdTestEnv, extras: Dict[str, Any] = None):
116116
"<Location \"/h2test/tweak\">",
117117
" SetHandler h2test-tweak",
118118
"</Location>",
119+
'ErrorDocument 405 "*waggles finger*"',
120+
'ErrorDocument 406 "*not acceptable*"',
121+
'<Location "/proxy/">',
122+
' ErrorDocument 405 "*proxy waggles finger*"',
123+
' ProxyErrorOverride On 405',
124+
'</Location>',
125+
'<Location "/h2proxy/">',
126+
' ErrorDocument 405 "*h2proxy waggles finger*"',
127+
' ProxyErrorOverride On 405',
128+
'</Location>',
119129
]
120130
}))
121131

test/modules/http2/mod_h2test/mod_h2test.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,13 @@ static int h2test_error_handler(request_rec *r)
517517
if (error != APR_SUCCESS) {
518518
return ap_map_http_request_error(error, HTTP_BAD_REQUEST);
519519
}
520+
if (r->status >= 400) {
521+
b = ap_bucket_error_create(r->status, NULL, r->pool, c->bucket_alloc);
522+
APR_BRIGADE_INSERT_TAIL(bb, b);
523+
ap_pass_brigade(r->output_filters, bb);
524+
return OK;
525+
}
526+
520527
/* flush response */
521528
b = apr_bucket_flush_create(c->bucket_alloc);
522529
APR_BRIGADE_INSERT_TAIL(bb, b);

test/modules/http2/test_500_proxy.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,11 @@ def test_h2_500_32(self, env, repeat):
167167
"AH01110" # Network error reading response
168168
]
169169
)
170+
171+
# produce a HTTP error on the proxied end, check that ProxyErrorOverride works
172+
def test_h2_500_33(self, env, repeat):
173+
url = env.mkurl("https", "cgi", "/proxy/h2test/error?status=405")
174+
r = env.curl_get(url)
175+
assert r.exit_code == 0
176+
assert r.response['status'] == 405, f'{r}'
177+
assert r.stdout == '*proxy waggles finger*', f'{r}'

test/modules/http2/test_600_h2proxy.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,27 @@ def test_h2_600_32(self, env, repeat):
198198
# stream (exit_code != 0) or give a 503 response.
199199
if r.exit_code == 0:
200200
assert r.response['status'] in [502, 503]
201+
202+
# produce a HTTP error on the proxied end, check we see orig error doc
203+
def test_h2_600_33(self, env, repeat):
204+
conf = H2Conf(env)
205+
conf.add_vhost_cgi(h2proxy_self=True)
206+
conf.install()
207+
assert env.apache_restart() == 0
208+
url = env.mkurl("https", "cgi", "/h2proxy/h2test/error?status=406")
209+
r = env.curl_get(url)
210+
assert r.exit_code == 0
211+
assert r.response['status'] == 406, f'{r}'
212+
assert r.stdout == '*not acceptable*', f'{r}'
213+
214+
# produce a HTTP error on the proxied end, check that ProxyErrorOverride works
215+
def test_h2_600_34(self, env, repeat):
216+
conf = H2Conf(env)
217+
conf.add_vhost_cgi(h2proxy_self=True)
218+
conf.install()
219+
assert env.apache_restart() == 0
220+
url = env.mkurl("https", "cgi", "/h2proxy/h2test/error?status=405")
221+
r = env.curl_get(url)
222+
assert r.exit_code == 0
223+
assert r.response['status'] == 405, f'{r}'
224+
assert r.stdout == '*h2proxy waggles finger*', f'{r}'

0 commit comments

Comments
 (0)