const failable internalRedirectRequest()

in modules/http/httpd.hpp [504:592]


const failable<request_rec*> internalRedirectRequest(const string& nr_uri, request_rec* const r) {
    if (ap_is_recursion_limit_exceeded(r))
        return mkfailure<request_rec*>("Redirect recursion limit exceeded", HTTP_INTERNAL_SERVER_ERROR);

    // Create a new request
    request_rec* nr = (request_rec*)apr_pcalloc(r->pool, sizeof(request_rec));
    nr->connection = r->connection;
    nr->server = r->server;
    nr->pool = r->pool;
    nr->method = r->method;
    nr->method_number = r->method_number;
    nr->allowed_methods = ap_make_method_list(nr->pool, 2);
    ap_parse_uri(nr, apr_pstrdup(nr->pool, c_str(nr_uri)));
    nr->parsed_uri.port_str = r->parsed_uri.port_str;
    nr->parsed_uri.port = r->parsed_uri.port;
    nr->filename = apr_pstrdup(nr->pool, c_str(string("/redirected:") + nr_uri));
    nr->request_config = ap_create_request_config(r->pool);
    nr->per_dir_config = r->server->lookup_defaults;
    nr->prev = r;
    r->next = nr;
    nr->useragent_addr = r->useragent_addr;
    nr->useragent_ip = r->useragent_ip;

    // Run create request hook
    ap_run_create_request(nr);

    // Inherit protocol info from the original request
    nr->the_request = r->the_request;
    nr->allowed = r->allowed;
    nr->status = r->status;
    nr->assbackwards = r->assbackwards;
    nr->header_only = r->header_only;
    nr->protocol = r->protocol;
    nr->proto_num = r->proto_num;
    nr->hostname = r->hostname;
    nr->request_time = r->request_time;
    nr->main = r->main;
    nr->headers_in = r->headers_in;
    nr->headers_out = apr_table_make(r->pool, 12);
    if (ap_is_HTTP_REDIRECT(nr->status)) {
        const char *location = apr_table_get(r->headers_out, "Location");
        if (location)
            apr_table_setn(nr->headers_out, "Location", location);
    }
    nr->err_headers_out = r->err_headers_out;
    nr->subprocess_env = r->subprocess_env;
    nr->subprocess_env  = internalRenameOriginalEnv(r->pool, r->subprocess_env);
    nr->notes = apr_table_make(r->pool, 5);
    nr->htaccess = r->htaccess;
    nr->no_cache = r->no_cache;
    nr->expecting_100 = r->expecting_100;
    nr->no_local_copy = r->no_local_copy;
    nr->read_length = r->read_length;
    nr->vlist_validator = r->vlist_validator;
    nr->user = r->user;

    // Setup input and output filters
    nr->proto_output_filters  = r->proto_output_filters;
    nr->proto_input_filters   = r->proto_input_filters;
    nr->output_filters  = nr->proto_output_filters;
    nr->input_filters   = nr->proto_input_filters;
    if (nr->main) {
        ap_filter_t *f, *nextf;
        nr->output_filters = r->output_filters;
        f = nr->output_filters;
        do {
            nextf = f->next;
            if (f->r == r && f->frec != ap_subreq_core_filter_handle) {
                f->r = nr;
                ap_remove_output_filter(f);
            }
            f = nextf;
        } while(f && f != nr->proto_output_filters);
    }
    else {
        nr->output_filters  = nr->proto_output_filters;
    }
    internalUpdateFilters(nr->input_filters, r, nr);
    internalUpdateFilters(nr->output_filters, r, nr);

    apr_table_setn(nr->subprocess_env, "REDIRECT_STATUS", apr_itoa(r->pool, r->status));
    nr->used_path_info = AP_REQ_DEFAULT_PATH_INFO;

    const int rrc = ap_run_post_read_request(nr);
    if (rrc != OK && rrc != DECLINED)
        return mkfailure<request_rec*>("Error handling internal redirect", rrc);

    return nr;
}