2 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3 * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/)
5 * This product is released under the terms of the General Public Licence,
6 * version 2 (GPLv2). Please refer to the file LICENSE (included with this
7 * distribution) which contains the complete text of the licence.
9 * There are special exceptions to the terms and conditions of the GPL
10 * as it is applied to this software. View the full text of the exception in
11 * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
14 * If any of the files related to licensing are missing or if you have any
15 * other questions related to licensing please contact Breach Security, Inc.
16 * directly using the email address support@breach.com.
19 #include <util_filter.h>
21 #include "modsecurity.h"
25 /* -- Input filter -- */
28 static void dummy_free_func(void *data) {}
32 * This request filter will forward the previously stored
33 * request body further down the chain (most likely to the
36 apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
37 ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes)
39 modsec_rec *msr = (modsec_rec *)f->ctx;
40 msc_data_chunk *chunk = NULL;
43 char *my_error_msg = NULL;
46 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
47 "ModSecurity: Internal error in input filter: msr is null.");
48 ap_remove_input_filter(f);
52 /* Make sure we are using the current request */
55 if (msr->phase < PHASE_REQUEST_BODY) {
56 msr_log(msr, 1, "Internal error: REQUEST_BODY phase incomplete for input filter in phase %d", msr->phase);
60 if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) {
61 if (msr->txcfg->debuglog_level >= 4) {
62 msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %pp, r %pp).", f, f->r);
64 ap_remove_input_filter(f);
65 return ap_get_brigade(f->next, bb_out, mode, block, nbytes);
68 if (msr->txcfg->debuglog_level >= 4) {
69 msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT
70 " (f %pp, r %pp).", mode, block, nbytes, f, f->r);
73 if (msr->if_started_forwarding == 0) {
74 msr->if_started_forwarding = 1;
75 rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
77 if (my_error_msg != NULL) {
78 msr_log(msr, 1, "%s", my_error_msg);
84 rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes, &my_error_msg);
86 if (my_error_msg != NULL) {
87 msr_log(msr, 1, "%s", my_error_msg);
93 /* Copy the data we received in the chunk */
94 bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
95 f->r->connection->bucket_alloc);
99 It would seem that we cannot prevent other filters in the chain
100 from modifying data in-place. Hence we copy.
102 if (chunk->is_permanent) {
103 /* Do not make a copy of the data we received in the chunk. */
104 bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func,
105 f->r->connection->bucket_alloc);
107 /* Copy the data we received in the chunk. */
108 bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
109 f->r->connection->bucket_alloc);
114 if (bucket == NULL) return APR_EGENERAL;
115 APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
117 if (msr->txcfg->debuglog_level >= 4) {
118 msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length);
123 modsecurity_request_body_retrieve_end(msr);
125 bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc);
126 if (bucket == NULL) return APR_EGENERAL;
127 APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
129 if (msr->txcfg->debuglog_level >= 4) {
130 msr_log(msr, 4, "Input filter: Sent EOS.");
134 msr->if_status = IF_STATUS_COMPLETE;
135 ap_remove_input_filter(f);
137 if (msr->txcfg->debuglog_level >= 4) {
138 msr_log(msr, 4, "Input filter: Input forwarding complete.");
146 * Reads request body from a client.
148 apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
149 request_rec *r = msr->r;
150 unsigned int seen_eos;
151 apr_bucket_brigade *bb_in;
154 if (error_msg == NULL) return -1;
157 if (msr->reqbody_should_exist != 1) {
158 if (msr->txcfg->debuglog_level >= 4) {
159 msr_log(msr, 4, "Input filter: This request does not have a body.");
164 if (msr->txcfg->reqbody_access != 1) {
165 if (msr->txcfg->debuglog_level >= 4) {
166 msr_log(msr, 4, "Input filter: Request body access not enabled.");
171 if (msr->txcfg->debuglog_level >= 4) {
172 msr_log(msr, 4, "Input filter: Reading request body.");
175 if (modsecurity_request_body_start(msr, error_msg) < 0) {
180 bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc);
181 if (bb_in == NULL) return -1;
185 rc = ap_get_brigade(r->input_filters, bb_in, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN);
186 if (rc != APR_SUCCESS) {
187 /* NOTE Apache returns AP_FILTER_ERROR here when the request is
188 * too large and APR_EGENERAL when the client disconnects.
192 *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
194 case AP_FILTER_ERROR :
195 *error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)");
198 *error_msg = apr_psprintf(msr->mp, "Error reading request body: Client went away.");
201 *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
206 /* Loop through the buckets in the brigade in order
207 * to extract the size of the data available.
209 for(bucket = APR_BRIGADE_FIRST(bb_in);
210 bucket != APR_BRIGADE_SENTINEL(bb_in);
211 bucket = APR_BUCKET_NEXT(bucket))
216 rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
217 if (rc != APR_SUCCESS) {
218 *error_msg = apr_psprintf(msr->mp, "Failed reading input / bucket (%d): %s", rc, get_apr_error(msr->mp, rc));
222 if (msr->txcfg->debuglog_level >= 9) {
223 msr_log(msr, 9, "Input filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
224 bucket->type->name, buflen);
227 /* Check request body limit (should only trigger on chunked requests). */
228 if (msr->reqbody_length + buflen > (apr_size_t)msr->txcfg->reqbody_limit) {
229 *error_msg = apr_psprintf(msr->mp, "Request body is larger than the "
230 "configured limit (%ld).", msr->txcfg->reqbody_limit);
235 int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg);
238 *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
239 "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
246 msr->reqbody_length += buflen;
249 if (APR_BUCKET_IS_EOS(bucket)) {
254 apr_brigade_cleanup(bb_in);
257 // TODO: Why ignore the return code here?
258 modsecurity_request_body_end(msr, error_msg);
260 if (msr->txcfg->debuglog_level >= 4) {
261 msr_log(msr, 4, "Input filter: Completed receiving request body (length %" APR_SIZE_T_FMT ").",
262 msr->reqbody_length);
265 msr->if_status = IF_STATUS_WANTS_TO_RUN;
271 /* -- Output filter -- */
274 * Examines the configuration and the response MIME type
275 * in order to determine whether output buffering should
278 static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
279 char *content_type = NULL;
281 /* Check configuration. */
282 if (msr->txcfg->resbody_access != 1) {
283 if (msr->txcfg->debuglog_level >= 4) {
284 msr_log(msr, 4, "Output filter: Response body buffering is not enabled.");
290 /* Check MIME type. */
292 if ((msr->txcfg->of_mime_types == NULL)||(msr->txcfg->of_mime_types == NOT_SET_P)) {
293 msr_log(msr, 1, "Output filter: MIME type structures corrupted (internal error).");
297 if (r->content_type != NULL) {
300 content_type = apr_pstrdup(msr->mp, r->content_type);
301 if (content_type == NULL) {
302 msr_log(msr, 1, "Output filter: Failed to allocate memory for content type.");
306 /* Hide the character encoding information
307 * if present. Sometimes the content type header
308 * looks like this "text/html; charset=xyz" ...
310 p = strstr(content_type, ";");
315 strtolower_inplace((unsigned char *)content_type);
317 if (strcmp(content_type, "text/html") == 0) {
318 /* Useful information to have should we later
319 * decide to do something with the HTML output.
321 msr->resbody_contains_html = 1;
324 content_type = "null";
327 if (apr_table_get(msr->txcfg->of_mime_types, content_type) != NULL) return 1;
329 msr_log(msr, 4, "Output filter: Not buffering response body for unconfigured MIME type \"%s\".", content_type);
335 * Initialises the output filter.
337 static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
338 apr_bucket_brigade *bb_in)
340 request_rec *r = f->r;
341 const char *s_content_length = NULL;
344 msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc);
345 if (msr->of_brigade == NULL) {
346 msr_log(msr, 1, "Output filter: Failed to create brigade.");
349 msr->of_status = OF_STATUS_IN_PROGRESS;
351 rc = output_filter_should_run(msr, r);
352 if (rc < 0) return -1; /* output_filter_should_run() generates error msg */
353 if (rc == 0) return 0;
355 /* Do not check the output limit if we are willing to
356 * process partial response bodies.
359 if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_PARTIAL) {
363 /* Look up the Content-Length header to see if we know
364 * the amount of data coming our way. If we do and if
365 * it's too much we might want to stop processing right here.
367 s_content_length = apr_table_get(r->headers_out, "Content-Length");
368 if (s_content_length == NULL) {
369 /* Try this too, mod_cgi seems to put headers there. */
370 s_content_length = apr_table_get(r->err_headers_out, "Content-Length");
373 if (s_content_length != NULL) {
376 len = strtol(s_content_length, NULL, 10);
377 if ((len == LONG_MIN)||(len == LONG_MAX)||(len < 0)||(len >= 1073741824)) {
378 msr_log(msr, 1, "Output filter: Invalid Content-Length: %s", log_escape_nq(r->pool,
379 (char *)s_content_length));
380 return -1; /* Invalid. */
384 if (msr->txcfg->debuglog_level >= 4) {
385 msr_log(msr, 4, "Output filter: Skipping response since Content-Length is zero.");
391 if (len > msr->txcfg->of_limit) {
392 msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%ld).",
393 log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit);
394 return -2; /* Over the limit. */
402 * Send the accumulated content down the filter stream
405 static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
408 rc = ap_pass_brigade(f->next, msr->of_brigade);
409 if (rc != APR_SUCCESS) {
410 /* TODO: These need to move to flags in 2.6. For now log them
411 * at level 4 so that they are not confusing users.
415 if (msr->txcfg->debuglog_level >= log_level) {
417 case AP_NOBODY_WROTE :
418 msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): No data", rc);
420 case AP_FILTER_ERROR :
421 /* Look like this is caused by the error
422 * already being handled, so we should ignore it
424 msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): Filter error", rc);
428 msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): %s",
429 rc, get_apr_error(msr->mp, rc));
443 static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
444 if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) {
445 apr_bucket *bucket_ci = NULL;
447 bucket_ci = apr_bucket_heap_create(msr->content_prepend,
448 msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
449 APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci);
451 if (msr->txcfg->debuglog_level >= 9) {
452 msr_log(msr, 9, "Content Injection (b): Added content to top: %s",
453 log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
461 static int flatten_response_body(modsec_rec *msr) {
464 msr->resbody_status = RESBODY_STATUS_READ_BRIGADE;
466 if (msr->resbody_length + 1 <= 0) {
467 msr_log(msr, 1, "Output filter: Invalid response length: %" APR_SIZE_T_FMT, msr->resbody_length);
471 msr->resbody_data = apr_palloc(msr->mp, msr->resbody_length + 1);
472 if (msr->resbody_data == NULL) {
473 msr_log(msr, 1, "Output filter: Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
474 msr->resbody_length + 1);
478 rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
479 if (rc != APR_SUCCESS) {
480 msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", rc,
481 get_apr_error(msr->mp, rc));
485 msr->resbody_data[msr->resbody_length] = '\0';
486 msr->resbody_status = RESBODY_STATUS_READ;
494 apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
495 request_rec *r = f->r;
496 modsec_rec *msr = (modsec_rec *)f->ctx;
497 apr_bucket *bucket = NULL, *eos_bucket = NULL;
499 int start_skipping = 0;
501 /* Do we have the context? */
503 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
504 "ModSecurity: Internal Error: msr is null in output filter.");
505 ap_remove_output_filter(f);
506 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
511 if (msr->txcfg->debuglog_level >= 9) {
512 msr_log(msr, 9, "Output filter: Receiving output (f %pp, r %pp).", f, f->r);
515 /* Initialise on first invocation */
516 if (msr->of_status == OF_STATUS_NOT_STARTED) {
517 /* Update our context from the request structure. */
519 msr->response_status = r->status;
520 msr->status_line = ((r->status_line != NULL)
521 ? r->status_line : ap_get_status_line(r->status));
522 msr->response_protocol = get_response_protocol(r);
523 msr->response_headers = apr_table_overlay(msr->mp, r->err_headers_out, r->headers_out);
525 /* Process phase RESPONSE_HEADERS */
526 rc = modsecurity_process_phase(msr, PHASE_RESPONSE_HEADERS);
527 if (rc < 0) { /* error */
528 ap_remove_output_filter(f);
529 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
532 if (rc > 0) { /* transaction needs to be interrupted */
533 int status = perform_interception(msr);
534 if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
535 ap_remove_output_filter(f);
536 msr->of_status = OF_STATUS_COMPLETE;
537 msr->resbody_status = RESBODY_STATUS_ERROR;
538 return send_error_bucket(msr, f, status);
542 /* Decide whether to observe the response body. */
543 rc = output_filter_init(msr, f, bb_in);
545 case -2 : /* response too large */
546 case -1 : /* error */
547 /* there's something wrong with this response */
548 ap_remove_output_filter(f);
549 msr->of_status = OF_STATUS_COMPLETE;
550 msr->resbody_status = RESBODY_STATUS_ERROR;
551 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
553 /* We do not want to observe this response body
554 * but we need to remain attached to observe
555 * when it is completed so that we can run
556 * the RESPONSE_BODY phase.
558 msr->of_skipping = 1;
559 msr->resbody_status = RESBODY_STATUS_NOT_READ;
562 /* Continue (observe the response body). */
566 /* If injecting content unset headers now. */
567 if (msr->txcfg->content_injection_enabled == 0) {
568 if (msr->txcfg->debuglog_level >= 9) {
569 msr_log(msr, 9, "Content Injection: Not enabled.");
572 if ((msr->content_prepend) || (msr->content_append)) {
573 apr_table_unset(msr->r->headers_out, "Content-Length");
574 apr_table_unset(msr->r->headers_out, "Last-Modified");
575 apr_table_unset(msr->r->headers_out, "ETag");
576 apr_table_unset(msr->r->headers_out, "Expires");
578 if (msr->txcfg->debuglog_level >= 9) {
579 msr_log(msr, 9, "Content Injection: Removing headers (C-L, L-M, Etag, Expires).");
582 if (msr->txcfg->debuglog_level >= 9) {
583 msr_log(msr, 9, "Content Injection: Nothing to inject.");
588 /* Content injection (prepend & non-buffering). */
589 if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (msr->of_skipping)) {
590 apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend,
591 msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
592 APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci);
594 if (msr->txcfg->debuglog_level >= 9) {
595 msr_log(msr, 9, "Content Injection (nb): Added content to top: %s",
596 log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
600 if (msr->of_status == OF_STATUS_COMPLETE) {
601 msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked.");
602 ap_remove_output_filter(f);
607 /* Loop through the buckets in the brigade in order
608 * to extract the size of the data available.
610 for(bucket = APR_BRIGADE_FIRST(bb_in);
611 bucket != APR_BRIGADE_SENTINEL(bb_in);
612 bucket = APR_BUCKET_NEXT(bucket)) {
616 /* Look into response data if configured to do so,
617 * unless we've already processed a partial response.
619 if ((msr->of_skipping == 0)&&(!msr->of_partial)) { /* Observe the response data. */
620 /* Retrieve data from the bucket. */
621 rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
622 if (rc != APR_SUCCESS) {
623 msr->of_status = OF_STATUS_COMPLETE;
624 msr->resbody_status = RESBODY_STATUS_ERROR;
626 msr_log(msr, 1, "Output filter: Failed to read bucket (rc %d): %s",
627 rc, get_apr_error(r->pool, rc));
629 ap_remove_output_filter(f);
630 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
633 if (msr->txcfg->debuglog_level >= 9) {
634 msr_log(msr, 9, "Output filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
635 bucket->type->name, buflen);
638 /* Check the response size. */
639 if (msr->resbody_length > (apr_size_t)msr->txcfg->of_limit) {
640 /* The size of the response is larger than what we're
641 * ready to accept. We need to decide what we want to do
644 if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) {
645 /* Reject response. */
646 msr_log(msr, 1, "Output filter: Response body too large (over limit of %ld, "
647 "total not specified).", msr->txcfg->of_limit);
649 msr->of_status = OF_STATUS_COMPLETE;
650 msr->resbody_status = RESBODY_STATUS_PARTIAL;
652 ap_remove_output_filter(f);
653 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
655 /* Process partial response. */
657 msr->resbody_length = msr->txcfg->of_limit;
659 if (msr->txcfg->debuglog_level >= 4) {
660 msr_log(msr, 4, "Output filter: Processing partial response body (limit %ld)",
661 msr->txcfg->of_limit);
665 msr->resbody_length += buflen;
669 /* Have we reached the end of the response? */
670 if (APR_BUCKET_IS_EOS(bucket)) {
673 /* Inject content (append & non-buffering). */
674 if ((msr->txcfg->content_injection_enabled) && (msr->content_append)
675 && (msr->of_skipping || msr->of_partial || start_skipping))
677 apr_bucket *bucket_ci = NULL;
679 bucket_ci = apr_bucket_heap_create(msr->content_append,
680 msr->content_append_len, NULL, f->r->connection->bucket_alloc);
681 APR_BUCKET_INSERT_BEFORE(bucket, bucket_ci);
683 if (msr->txcfg->debuglog_level >= 9) {
684 msr_log(msr, 9, "Content-Injection (nb): Added content to bottom: %s",
685 log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
689 msr->of_done_reading = 1;
693 /* Add buckets in this brigade to the brigade
694 * we have in the context, but only if we actually
695 * want to keep the response body.
697 if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) {
698 ap_save_brigade(f, &msr->of_brigade, &bb_in, msr->mp);
700 /* Do we need to process a partial response? */
701 if (start_skipping) {
702 if (flatten_response_body(msr) < 0) {
703 ap_remove_output_filter(f);
704 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
707 /* Process phase RESPONSE_BODY */
708 rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY);
710 ap_remove_output_filter(f);
711 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
714 int status = perform_interception(msr);
715 if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
716 ap_remove_output_filter(f);
717 return send_error_bucket(msr, f, status);
721 /* Prepend content as necessary. */
722 prepend_content_to_of_brigade(msr, f);
724 if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) {
731 if (msr->of_done_reading == 0) {
732 /* We are done for now. We will be called again with more data. */
736 if (msr->txcfg->debuglog_level >= 4) {
737 msr_log(msr, 4, "Output filter: Completed receiving response body (buffered %s - %" APR_SIZE_T_FMT " bytes).",
738 (msr->of_partial ? "partial" : "full"), msr->resbody_length);
740 } else { /* Not looking at response data. */
741 if (msr->of_done_reading == 0) {
742 if (msr->txcfg->debuglog_level >= 9) {
743 msr_log(msr, 9, "Output filter: Sending input brigade directly.");
746 return ap_pass_brigade(f->next, bb_in);
749 if (msr->txcfg->debuglog_level >= 4) {
750 msr_log(msr, 4, "Output filter: Completed receiving response body (non-buffering).");
754 /* We've done our thing; remove us from the filter list. */
755 msr->of_status = OF_STATUS_COMPLETE;
756 ap_remove_output_filter(f);
758 /* Process phase RESPONSE_BODY, but
759 * only if it hasn't been processed already.
761 if (msr->phase < PHASE_RESPONSE_BODY) {
762 if (flatten_response_body(msr) < 0) {
763 ap_remove_output_filter(f);
764 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
767 rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY);
769 ap_remove_output_filter(f);
770 return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
773 int status = perform_interception(msr);
774 if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
775 ap_remove_output_filter(f);
776 return send_error_bucket(msr, f, status);
781 /* Now send data down the filter stream
782 * (full-buffering only).
784 if ((msr->of_skipping == 0)&&(!msr->of_partial)) {
785 record_time_checkpoint(msr, 3);
787 prepend_content_to_of_brigade(msr, f);
789 /* Inject content into response (append & buffering). */
790 if ((msr->txcfg->content_injection_enabled) && (msr->content_append)) {
791 apr_bucket *bucket_ci = NULL;
793 bucket_ci = apr_bucket_heap_create(msr->content_append,
794 msr->content_append_len, NULL, f->r->connection->bucket_alloc);
795 APR_BUCKET_INSERT_BEFORE(eos_bucket, bucket_ci);
797 if (msr->txcfg->debuglog_level >= 9) {
798 msr_log(msr, 9, "Content-Injection (b): Added content to bottom: %s",
799 log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
803 /* Send data down the filter stream. */
804 if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) {
809 /* Another job well done! */
810 if (msr->txcfg->debuglog_level >= 4) {
811 msr_log(msr, 4, "Output filter: Output forwarding complete.");
814 if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) {
817 if (msr->txcfg->debuglog_level >= 9) {
818 msr_log(msr, 9, "Output filter: Sending input brigade directly.");
821 return ap_pass_brigade(f->next, bb_in);