<commit_before>/*
 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
 * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * You may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address <EMAIL>.
 */

#include <util_filter.h>

#include "modsecurity.h"
#include "apache2.h"
#include "msc_crypt.h"

/* -- Input filter -- */

#if 0
static void dummy_free_func(void *data) {}
#endif

/**
 * This request filter will forward the previously stored
 * request body further down the chain (most likely to the
 * processing module).
 */
apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
        ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes)
{
    modsec_rec *msr = (modsec_rec *)f->ctx;
    msc_data_chunk *chunk = NULL;
    apr_bucket *bucket;
    apr_status_t rc;
    char *my_error_msg = NULL;

    if (msr == NULL) {
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
                "ModSecurity: Internal error in input filter: msr is null.");
        ap_remove_input_filter(f);
        return APR_EGENERAL;
    }

    /* Make sure we are using the current request */
    msr->r = f->r;

    if (msr->phase < PHASE_REQUEST_BODY) {
        msr_log(msr, 1, "Internal error: REQUEST_BODY phase incomplete for input filter in phase %d", msr->phase);
        return APR_EGENERAL;
    }

    if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) {
        if (msr->txcfg->debuglog_level >= 4) {
            msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %pp, r %pp).", f, f->r);
        }
        ap_remove_input_filter(f);
        return ap_get_brigade(f->next, bb_out, mode, block, nbytes);
    }

    if (msr->txcfg->debuglog_level >= 4) {
        msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT
                " (f %pp, r %pp).", mode, block, nbytes, f, f->r);
    }

    if (msr->if_started_forwarding == 0) {
        msr->if_started_forwarding = 1;
        rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
        if (rc == -1) {
            if (my_error_msg != NULL) {
                msr_log(msr, 1, "%s", my_error_msg);
            }
            return APR_EGENERAL;
        }
    }

    rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes, &my_error_msg);
    if (rc == -1) {
        if (my_error_msg != NULL) {
            msr_log(msr, 1, "%s", my_error_msg);
        }
        return APR_EGENERAL;
    }

    if (chunk && (!msr->txcfg->stream_inbody_inspection || (msr->txcfg->stream_inbody_inspection && msr->if_stream_changed == 0))) {
        /* Copy the data we received in the chunk */
        bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
                f->r->connection->bucket_alloc);

#if 0

        It would seem that we cannot prevent other filters in the chain
            from modifying data in-place. Hence we copy.

            if (chunk->is_permanent) {
                /* Do not make a copy of the data we received in the chunk. */
                bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func,
                        f->r->connection->bucket_alloc);
            } else {
                /* Copy the data we received in the chunk. */
                bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
                        f->r->connection->bucket_alloc);
            }

#endif

        if (bucket == NULL) return APR_EGENERAL;
        APR_BRIGADE_INSERT_TAIL(bb_out, bucket);

        if (msr->txcfg->debuglog_level >= 4) {
            msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length);
        }
    } else if (msr->stream_input_data != NULL) {

        msr->if_stream_changed = 0;

        bucket = apr_bucket_heap_create(msr->stream_input_data, msr->stream_input_length, NULL,
                f->r->connection->bucket_alloc);

        if (msr->txcfg->stream_inbody_inspection)  {
            if(msr->stream_input_data != NULL) {
                free(msr->stream_input_data);
                msr->stream_input_data = NULL;
            }
        }

        if (bucket == NULL) return APR_EGENERAL;
        APR_BRIGADE_INSERT_TAIL(bb_out, bucket);

        if (msr->txcfg->debuglog_level >= 4) {
            msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length);
        }

    }

    if (rc == 0) {
        modsecurity_request_body_retrieve_end(msr);

        if (msr->if_seen_eos) {
            bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc);
            if (bucket == NULL) return APR_EGENERAL;
            APR_BRIGADE_INSERT_TAIL(bb_out, bucket);

            if (msr->txcfg->debuglog_level >= 4) {
                msr_log(msr, 4, "Input filter: Sent EOS.");
            }
        }

        /* We're done */
        msr->if_status = IF_STATUS_COMPLETE;
        ap_remove_input_filter(f);

        if (msr->txcfg->debuglog_level >= 4) {
            msr_log(msr, 4, "Input filter: Input forwarding complete.");
        }
    }

    return APR_SUCCESS;
}

/**
 * Reads request body from a client.<commit_msg>Fix issues with uploading files over 8K : #142, #582 and #830<commit_after>/*
 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
 * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * You may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address <EMAIL>.
 */

#include <util_filter.h>

#include "modsecurity.h"
#include "apache2.h"
#include "msc_crypt.h"

/* -- Input filter -- */

#if 0
static void dummy_free_func(void *data) {}
#endif

/**
 * This request filter will forward the previously stored
 * request body further down the chain (most likely to the
 * processing module).
 */
apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
        ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes)
{
    modsec_rec *msr = (modsec_rec *)f->ctx;
    msc_data_chunk *chunk = NULL;
    apr_bucket *bucket;
    apr_status_t rc;
    char *my_error_msg = NULL;

    if (msr == NULL) {
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
                "ModSecurity: Internal error in input filter: msr is null.");
        ap_remove_input_filter(f);
        return APR_EGENERAL;
    }

    /* Make sure we are using the current request */
    msr->r = f->r;

    if (msr->phase < PHASE_REQUEST_BODY) {
        msr_log(msr, 1, "Internal error: REQUEST_BODY phase incomplete for input filter in phase %d", msr->phase);
        return APR_EGENERAL;
    }

    if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) {
        if (msr->txcfg->debuglog_level >= 4) {
            msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %pp, r %pp).", f, f->r);
        }
        ap_remove_input_filter(f);
        return ap_get_brigade(f->next, bb_out, mode, block, nbytes);
    }

    if (msr->txcfg->debuglog_level >= 4) {
        msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT
                " (f %pp, r %pp).", mode, block, nbytes, f, f->r);
    }

    if (msr->if_started_forwarding == 0) {
        msr->if_started_forwarding = 1;
        rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
        if (rc == -1) {
            if (my_error_msg != NULL) {
                msr_log(msr, 1, "%s", my_error_msg);
            }
            return APR_EGENERAL;
        }
    }

    do{
      rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes, &my_error_msg);
      if (rc == -1) {
        if (my_error_msg != NULL) {
            msr_log(msr, 1, "%s", my_error_msg);
        }
        return APR_EGENERAL;
      }

      if (chunk && (!msr->txcfg->stream_inbody_inspection || (msr->txcfg->stream_inbody_inspection && msr->if_stream_changed == 0))) {
        /* Copy the data we received in the chunk */
        bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
                f->r->connection->bucket_alloc);

#if 0

        It would seem that we cannot prevent other filters in the chain
            from modifying data in-place. Hence we copy.

            if (chunk->is_permanent) {
                /* Do not make a copy of the data we received in the chunk. */
                bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func,
                        f->r->connection->bucket_alloc);
            } else {
                /* Copy the data we received in the chunk. */
                bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
                        f->r->connection->bucket_alloc);
            }

#endif

        if (bucket == NULL) return APR_EGENERAL;
        APR_BRIGADE_INSERT_TAIL(bb_out, bucket);

        if (msr->txcfg->debuglog_level >= 4) {
            msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length);
        }
      } else if (msr->stream_input_data != NULL) {

        msr->if_stream_changed = 0;

        bucket = apr_bucket_heap_create(msr->stream_input_data, msr->stream_input_length, NULL,
                f->r->connection->bucket_alloc);

        if (msr->txcfg->stream_inbody_inspection)  {
            if(msr->stream_input_data != NULL) {
                free(msr->stream_input_data);
                msr->stream_input_data = NULL;
            }
        }

        if (msr->if_seen_eos) {
            if (bucket == NULL) return APR_EGENERAL;
            APR_BRIGADE_INSERT_TAIL(bb_out, bucket);

            if (msr->txcfg->debuglog_level >= 4) {
                msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length);
            }
        }
      }
    } while (rc != 0);

    modsecurity_request_body_retrieve_end(msr);

    bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc);
    if (bucket == NULL) return APR_EGENERAL;
    APR_BRIGADE_INSERT_TAIL(bb_out, bucket);

    if (msr->txcfg->debuglog_level >= 4) {
        msr_log(msr, 4, "Input filter: Sent EOS.");
    }

    /* We're done */
    msr->if_status = IF_STATUS_COMPLETE;
    ap_remove_input_filter(f);

    if (msr->txcfg->debuglog_level >= 4) {
        msr_log(msr, 4, "Input filter: Input forwarding complete.");
    }

    return APR_SUCCESS;
}

/**
 * Reads request body from a client.
{'fraction_non_alphanumeric': 0.1220326744291001, 'fraction_numerical': 0.007581911724884917, 'mean_word_length': 2.383206106870229, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 151, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5680371', 'n_tokens_mistral': 3864, 'n_tokens_neox': 3675, 'n_words': 898}