From: Jim Jagielski Date: Fri, 1 Apr 2011 19:25:26 +0000 (+0000) Subject: *) mod_proxy_ajp: Add support for 'ProxyErrorOverride on'. PR 50945. X-Git-Tag: 2.3.12~114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8d9a25867676570decd5247f01b0e7e27fd9918;p=thirdparty%2Fapache%2Fhttpd.git *) mod_proxy_ajp: Add support for 'ProxyErrorOverride on'. PR 50945. [Peter Pramberger , Jim Jagielski] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1087864 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index b41ade54222..ef7c157182c 100644 --- a/CHANGES +++ b/CHANGES @@ -2,7 +2,10 @@ Changes with Apache 2.3.12 - *) mod_proxy_fcgi: Add support for 'ProxyErrorOverride on' PR 50913. + *) mod_proxy_ajp: Add support for 'ProxyErrorOverride on'. PR 50945. + [Peter Pramberger , Jim Jagielski] + + *) mod_proxy_fcgi: Add support for 'ProxyErrorOverride on'. PR 50913. [Mark Montague , Jim Jagielski] *) core: Change the APIs of ap_cfg_getline() and ap_cfg_getc() to return an diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index c154edbf4db..af78c60e923 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -190,6 +190,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, apr_size_t maxsize = AJP_MSG_BUFFER_SZ; int send_body = 0; apr_off_t content_length = 0; + int original_status = r->status; + const char *original_status_line = r->status_line; if (psf->io_buffer_size_set) maxsize = psf->io_buffer_size; @@ -430,71 +432,104 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, if (status != APR_SUCCESS) { backend_failed = 1; } + else if ((r->status == 401) && conf->error_override) { + const char *buf; + const char *wa = "WWW-Authenticate"; + if ((buf = apr_table_get(r->headers_out, wa))) { + apr_table_set(r->err_headers_out, wa, buf); + } else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "ap_proxy_ajp_request: origin server " + "sent 401 without WWW-Authenticate header"); + } + } headers_sent = 1; break; case CMD_AJP13_SEND_BODY_CHUNK: /* AJP13_SEND_BODY_CHUNK: piece of data */ status = ajp_parse_data(r, conn->data, &size, &send_body_chunk_buff); if (status == APR_SUCCESS) { - /* AJP13_SEND_BODY_CHUNK with zero length - * is explicit flush message + /* If we are overriding the errors, we can't put the content + * of the page into the brigade. */ - if (size == 0) { - if (headers_sent) { - e = apr_bucket_flush_create(r->connection->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(output_brigade, e); + if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) { + /* AJP13_SEND_BODY_CHUNK with zero length + * is explicit flush message + */ + if (size == 0) { + if (headers_sent) { + e = apr_bucket_flush_create(r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(output_brigade, e); + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Ignoring flush message received before headers"); + } } else { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "Ignoring flush message received before headers"); - } - } - else { - apr_status_t rv; - - e = apr_bucket_transient_create(send_body_chunk_buff, size, - r->connection->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(output_brigade, e); - - if ((conn->worker->s->flush_packets == flush_on) || - ((conn->worker->s->flush_packets == flush_auto) && - ((rv = apr_poll(conn_poll, 1, &conn_poll_fd, - conn->worker->s->flush_wait)) - != APR_SUCCESS) && - APR_STATUS_IS_TIMEUP(rv))) { - e = apr_bucket_flush_create(r->connection->bucket_alloc); + apr_status_t rv; + + /* Handle the case where the error document is itself reverse + * proxied and was successful. We must maintain any previous + * error status so that an underlying error (eg HTTP_NOT_FOUND) + * doesn't become an HTTP_OK. + */ + if (conf->error_override && !ap_is_HTTP_ERROR(r->status) + && ap_is_HTTP_ERROR(original_status)) { + r->status = original_status; + r->status_line = original_status_line; + } + + e = apr_bucket_transient_create(send_body_chunk_buff, size, + r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(output_brigade, e); + + if ((conn->worker->s->flush_packets == flush_on) || + ((conn->worker->s->flush_packets == flush_auto) && + ((rv = apr_poll(conn_poll, 1, &conn_poll_fd, + conn->worker->s->flush_wait)) + != APR_SUCCESS) && + APR_STATUS_IS_TIMEUP(rv))) { + e = apr_bucket_flush_create(r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(output_brigade, e); + } + apr_brigade_length(output_brigade, 0, &bb_len); + if (bb_len != -1) + conn->worker->s->read += bb_len; } - apr_brigade_length(output_brigade, 0, &bb_len); - if (bb_len != -1) - conn->worker->s->read += bb_len; - } - if (ap_pass_brigade(r->output_filters, - output_brigade) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "proxy: error processing body.%s", - r->connection->aborted ? - " Client aborted connection." : ""); - output_failed = 1; + if (ap_pass_brigade(r->output_filters, + output_brigade) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "proxy: error processing body.%s", + r->connection->aborted ? + " Client aborted connection." : ""); + output_failed = 1; + } + data_sent = 1; + apr_brigade_cleanup(output_brigade); } - data_sent = 1; - apr_brigade_cleanup(output_brigade); } else { backend_failed = 1; } break; case CMD_AJP13_END_RESPONSE: - e = apr_bucket_eos_create(r->connection->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(output_brigade, e); - if (ap_pass_brigade(r->output_filters, - output_brigade) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "proxy: error processing end"); - output_failed = 1; + /* If we are overriding the errors, we must not send anything to + * the client, especially as the brigade already contains headers. + * So do nothing here, and it will be cleaned up below. + */ + if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) { + e = apr_bucket_eos_create(r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(output_brigade, e); + if (ap_pass_brigade(r->output_filters, + output_brigade) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "proxy: error processing end"); + output_failed = 1; + } + /* XXX: what about flush here? See mod_jk */ + data_sent = 1; } - /* XXX: what about flush here? See mod_jk */ - data_sent = 1; request_ended = 1; break; default: @@ -569,7 +604,18 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, "proxy: got response from %pI (%s)", conn->worker->cp->addr, conn->worker->s->hostname); - rv = OK; + + if (conf->error_override && ap_is_HTTP_ERROR(r->status)) { + /* clear r->status for override error, otherwise ErrorDocument + * thinks that this is a recursive error, and doesn't find the + * custom error page + */ + rv = r->status; + r->status = HTTP_OK; + } + else { + rv = OK; + } } if (backend_failed) {