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;
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:
"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) {