Blame modules/session/mod_session.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include "mod_session.h"
Packit 90a5c9
#include "apr_lib.h"
Packit 90a5c9
#include "apr_strings.h"
Packit 90a5c9
#include "util_filter.h"
Packit 90a5c9
#include "http_log.h"
Packit 90a5c9
#include "http_request.h"
Packit 90a5c9
#include "http_protocol.h"
Packit 90a5c9
Packit 90a5c9
#define SESSION_EXPIRY "expiry"
Packit 90a5c9
#define HTTP_SESSION "HTTP_SESSION"
Packit 90a5c9
Packit 90a5c9
APR_HOOK_STRUCT(
Packit 90a5c9
                APR_HOOK_LINK(session_load)
Packit 90a5c9
                APR_HOOK_LINK(session_save)
Packit 90a5c9
                APR_HOOK_LINK(session_encode)
Packit 90a5c9
                APR_HOOK_LINK(session_decode)
Packit 90a5c9
)
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ap, SESSION, int, session_load,
Packit 90a5c9
                      (request_rec * r, session_rec ** z), (r, z), DECLINED)
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ap, SESSION, int, session_save,
Packit 90a5c9
                       (request_rec * r, session_rec * z), (r, z), DECLINED)
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap, SESSION, int, session_encode,
Packit 90a5c9
                   (request_rec * r, session_rec * z), (r, z), OK, DECLINED)
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap, SESSION, int, session_decode,
Packit 90a5c9
                   (request_rec * r, session_rec * z), (r, z), OK, DECLINED)
Packit 90a5c9
Packit 90a5c9
static int session_identity_encode(request_rec * r, session_rec * z);
Packit 90a5c9
static int session_identity_decode(request_rec * r, session_rec * z);
Packit 90a5c9
static int session_fixups(request_rec * r);
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Should the session be included within this URL.
Packit 90a5c9
 *
Packit 90a5c9
 * This function tests whether a session is valid for this URL. It uses the
Packit 90a5c9
 * include and exclude arrays to determine whether they should be included.
Packit 90a5c9
 */
Packit 90a5c9
static int session_included(request_rec * r, session_dir_conf * conf)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    const char **includes = (const char **) conf->includes->elts;
Packit 90a5c9
    const char **excludes = (const char **) conf->excludes->elts;
Packit 90a5c9
    int included = 1;                /* defaults to included */
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    if (conf->includes->nelts) {
Packit 90a5c9
        included = 0;
Packit 90a5c9
        for (i = 0; !included && i < conf->includes->nelts; i++) {
Packit 90a5c9
            const char *include = includes[i];
Packit 90a5c9
            if (strncmp(r->uri, include, strlen(include)) == 0) {
Packit 90a5c9
                included = 1;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (conf->excludes->nelts) {
Packit 90a5c9
        for (i = 0; included && i < conf->excludes->nelts; i++) {
Packit 90a5c9
            const char *exclude = excludes[i];
Packit 90a5c9
            if (strncmp(r->uri, exclude, strlen(exclude)) == 0) {
Packit 90a5c9
                included = 0;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return included;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Load the session.
Packit 90a5c9
 *
Packit 90a5c9
 * If the session doesn't exist, a blank one will be created.
Packit 90a5c9
 *
Packit 90a5c9
 * @param r The request
Packit 90a5c9
 * @param z A pointer to where the session will be written.
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t ap_session_load(request_rec * r, session_rec ** z)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
Packit 90a5c9
                                                   &session_module);
Packit 90a5c9
    apr_time_t now;
Packit 90a5c9
    session_rec *zz = NULL;
Packit 90a5c9
    int rv = 0;
Packit 90a5c9
Packit 90a5c9
    /* is the session enabled? */
Packit 90a5c9
    if (!dconf || !dconf->enabled) {
Packit 90a5c9
        return APR_SUCCESS;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* should the session be loaded at all? */
Packit 90a5c9
    if (!session_included(r, dconf)) {
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01814)
Packit 90a5c9
                      "excluded by configuration for: %s", r->uri);
Packit 90a5c9
        return APR_SUCCESS;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* load the session from the session hook */
Packit 90a5c9
    rv = ap_run_session_load(r, &zz;;
Packit 90a5c9
    if (DECLINED == rv) {
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01815)
Packit 90a5c9
                      "session is enabled but no session modules have been configured, "
Packit 90a5c9
                      "session not loaded: %s", r->uri);
Packit 90a5c9
        return APR_EGENERAL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (OK != rv) {
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01816)
Packit 90a5c9
                      "error while loading the session, "
Packit 90a5c9
                      "session not loaded: %s", r->uri);
Packit 90a5c9
        return rv;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* found a session that hasn't expired? */
Packit 90a5c9
    now = apr_time_now();
Packit 90a5c9
    if (zz) {
Packit 90a5c9
        if (zz->expiry && zz->expiry < now) {
Packit 90a5c9
            zz = NULL;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            /* having a session we cannot decode is just as good as having
Packit 90a5c9
               none at all */
Packit 90a5c9
            rv = ap_run_session_decode(r, zz);
Packit 90a5c9
            if (OK != rv) {
Packit 90a5c9
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817)
Packit 90a5c9
                              "error while decoding the session, "
Packit 90a5c9
                              "session not loaded: %s", r->uri);
Packit 90a5c9
                zz = NULL;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* no luck, create a blank session */
Packit 90a5c9
    if (!zz) {
Packit 90a5c9
        zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec));
Packit 90a5c9
        zz->pool = r->pool;
Packit 90a5c9
        zz->entries = apr_table_make(zz->pool, 10);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* make sure the expiry and maxage are set, if present */
Packit 90a5c9
    if (dconf->maxage) {
Packit 90a5c9
        if (!zz->expiry) {
Packit 90a5c9
            zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC;
Packit 90a5c9
        }
Packit 90a5c9
        zz->maxage = dconf->maxage;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    *z = zz;
Packit 90a5c9
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Save the session.
Packit 90a5c9
 *
Packit 90a5c9
 * In most implementations the session is only saved if the dirty flag is
Packit 90a5c9
 * true. This prevents the session being saved unnecessarily.
Packit 90a5c9
 *
Packit 90a5c9
 * @param r The request
Packit 90a5c9
 * @param z A pointer to where the session will be written.
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t ap_session_save(request_rec * r, session_rec * z)
Packit 90a5c9
{
Packit 90a5c9
    if (z) {
Packit 90a5c9
        apr_time_t now = apr_time_now();
Packit 682164
        apr_time_t initialExpiry = z->expiry;
Packit 90a5c9
        int rv = 0;
Packit 90a5c9
Packit 90a5c9
        session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
Packit 90a5c9
                                                       &session_module);
Packit 90a5c9
Packit 90a5c9
        /* sanity checks, should we try save at all? */
Packit 90a5c9
        if (z->written) {
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01818)
Packit 90a5c9
                          "attempt made to save the session twice, "
Packit 90a5c9
                          "session not saved: %s", r->uri);
Packit 90a5c9
            return APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
        if (z->expiry && z->expiry < now) {
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01819)
Packit 90a5c9
                          "attempt made to save a session when the session had already expired, "
Packit 90a5c9
                          "session not saved: %s", r->uri);
Packit 90a5c9
            return APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* reset the expiry back to maxage, if the expiry is present */
Packit 90a5c9
        if (dconf->maxage) {
Packit 90a5c9
            z->expiry = now + dconf->maxage * APR_USEC_PER_SEC;
Packit 90a5c9
            z->maxage = dconf->maxage;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* reset the expiry before saving if present */
Packit 90a5c9
        if (z->dirty && z->maxage) {
Packit 90a5c9
            z->expiry = now + z->maxage * APR_USEC_PER_SEC;
Packit 90a5c9
        } 
Packit 90a5c9
Packit 682164
        /* don't save if the only change is the expiry by a small amount */
Packit 682164
        if (!z->dirty && dconf->expiry_update_time
Packit 682164
                && (z->expiry - initialExpiry < dconf->expiry_update_time)) {
Packit 682164
            return APR_SUCCESS;
Packit 682164
        }
Packit 682164
Packit 682164
        /* also don't save sessions that didn't change at all */
Packit 682164
        if (!z->dirty && !z->maxage) {
Packit 682164
            return APR_SUCCESS;
Packit 682164
        }
Packit 682164
Packit 90a5c9
        /* encode the session */
Packit 90a5c9
        rv = ap_run_session_encode(r, z);
Packit 90a5c9
        if (OK != rv) {
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01820)
Packit 90a5c9
                          "error while encoding the session, "
Packit 90a5c9
                          "session not saved: %s", r->uri);
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* try the save */
Packit 90a5c9
        rv = ap_run_session_save(r, z);
Packit 90a5c9
        if (DECLINED == rv) {
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01821)
Packit 90a5c9
                          "session is enabled but no session modules have been configured, "
Packit 90a5c9
                          "session not saved: %s", r->uri);
Packit 90a5c9
            return APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
        else if (OK != rv) {
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01822)
Packit 90a5c9
                          "error while saving the session, "
Packit 90a5c9
                          "session not saved: %s", r->uri);
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            z->written = 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Get a particular value from the session.
Packit 90a5c9
 * @param r The current request.
Packit 90a5c9
 * @param z The current session. If this value is NULL, the session will be
Packit 90a5c9
 * looked up in the request, created if necessary, and saved to the request
Packit 90a5c9
 * notes.
Packit 90a5c9
 * @param key The key to get.
Packit 90a5c9
 * @param value The buffer to write the value to.
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t ap_session_get(request_rec * r, session_rec * z,
Packit 90a5c9
        const char *key, const char **value)
Packit 90a5c9
{
Packit 90a5c9
    if (!z) {
Packit 90a5c9
        apr_status_t rv;
Packit 90a5c9
        rv = ap_session_load(r, &z);
Packit 90a5c9
        if (APR_SUCCESS != rv) {
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    if (z && z->entries) {
Packit 90a5c9
        *value = apr_table_get(z->entries, key);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Set a particular value to the session.
Packit 90a5c9
 *
Packit 90a5c9
 * Using this method ensures that the dirty flag is set correctly, so that
Packit 90a5c9
 * the session can be saved efficiently.
Packit 90a5c9
 * @param r The current request.
Packit 90a5c9
 * @param z The current session. If this value is NULL, the session will be
Packit 90a5c9
 * looked up in the request, created if necessary, and saved to the request
Packit 90a5c9
 * notes.
Packit 90a5c9
 * @param key The key to set. The existing key value will be replaced.
Packit 90a5c9
 * @param value The value to set.
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t ap_session_set(request_rec * r, session_rec * z,
Packit 90a5c9
        const char *key, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    if (!z) {
Packit 90a5c9
        apr_status_t rv;
Packit 90a5c9
        rv = ap_session_load(r, &z);
Packit 90a5c9
        if (APR_SUCCESS != rv) {
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    if (z) {
Packit 90a5c9
        if (value) {
Packit 90a5c9
            apr_table_set(z->entries, key, value);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            apr_table_unset(z->entries, key);
Packit 90a5c9
        }
Packit 90a5c9
        z->dirty = 1;
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int identity_count(void *v, const char *key, const char *val)
Packit 90a5c9
{
Packit 90a5c9
    int *count = v;
Packit 90a5c9
    *count += strlen(key) * 3 + strlen(val) * 3 + 1;
Packit 90a5c9
    return 1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int identity_concat(void *v, const char *key, const char *val)
Packit 90a5c9
{
Packit 90a5c9
    char *slider = v;
Packit 90a5c9
    int length = strlen(slider);
Packit 90a5c9
    slider += length;
Packit 90a5c9
    if (length) {
Packit 90a5c9
        *slider = '&';
Packit 90a5c9
        slider++;
Packit 90a5c9
    }
Packit 90a5c9
    ap_escape_urlencoded_buffer(slider, key);
Packit 90a5c9
    slider += strlen(slider);
Packit 90a5c9
    *slider = '=';
Packit 90a5c9
    slider++;
Packit 90a5c9
    ap_escape_urlencoded_buffer(slider, val);
Packit 90a5c9
    return 1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Default identity encoding for the session.
Packit 90a5c9
 *
Packit 90a5c9
 * By default, the name value pairs in the session are URLEncoded, separated
Packit 90a5c9
 * by equals, and then in turn separated by ampersand, in the format of an
Packit 90a5c9
 * html form.
Packit 90a5c9
 *
Packit 90a5c9
 * This was chosen to make it easy for external code to unpack a session,
Packit 90a5c9
 * should there be a need to do so.
Packit 90a5c9
 *
Packit 90a5c9
 * @param r The request pointer.
Packit 90a5c9
 * @param z A pointer to where the session will be written.
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t session_identity_encode(request_rec * r, session_rec * z)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    char *buffer = NULL;
Packit 90a5c9
    int length = 0;
Packit 90a5c9
    if (z->expiry) {
Packit 90a5c9
        char *expiry = apr_psprintf(z->pool, "%" APR_INT64_T_FMT, z->expiry);
Packit 90a5c9
        apr_table_setn(z->entries, SESSION_EXPIRY, expiry);
Packit 90a5c9
    }
Packit 90a5c9
    apr_table_do(identity_count, &length, z->entries, NULL);
Packit 90a5c9
    buffer = apr_pcalloc(r->pool, length + 1);
Packit 90a5c9
    apr_table_do(identity_concat, buffer, z->entries, NULL);
Packit 90a5c9
    z->encoded = buffer;
Packit 90a5c9
    return OK;
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Default identity decoding for the session.
Packit 90a5c9
 *
Packit 90a5c9
 * By default, the name value pairs in the session are URLEncoded, separated
Packit 90a5c9
 * by equals, and then in turn separated by ampersand, in the format of an
Packit 90a5c9
 * html form.
Packit 90a5c9
 *
Packit 90a5c9
 * This was chosen to make it easy for external code to unpack a session,
Packit 90a5c9
 * should there be a need to do so.
Packit 90a5c9
 *
Packit 90a5c9
 * This function reverses that process, and populates the session table.
Packit 90a5c9
 *
Packit 90a5c9
 * Name / value pairs that are not encoded properly are ignored.
Packit 90a5c9
 *
Packit 90a5c9
 * @param r The request pointer.
Packit 90a5c9
 * @param z A pointer to where the session will be written.
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t session_identity_decode(request_rec * r, session_rec * z)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    char *last = NULL;
Packit 90a5c9
    char *encoded, *pair;
Packit 90a5c9
    const char *sep = "&";
Packit 90a5c9
Packit 90a5c9
    /* sanity check - anything to decode? */
Packit 90a5c9
    if (!z->encoded) {
Packit 90a5c9
        return OK;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* decode what we have */
Packit 90a5c9
    encoded = apr_pstrdup(r->pool, z->encoded);
Packit 90a5c9
    pair = apr_strtok(encoded, sep, &last);
Packit 90a5c9
    while (pair && pair[0]) {
Packit 90a5c9
        char *plast = NULL;
Packit 90a5c9
        const char *psep = "=";
Packit 90a5c9
        char *key = apr_strtok(pair, psep, &plast);
Packit 90a5c9
        char *val = apr_strtok(NULL, psep, &plast);
Packit 90a5c9
        if (key && *key) {
Packit 90a5c9
            if (!val || !*val) {
Packit 90a5c9
                apr_table_unset(z->entries, key);
Packit 90a5c9
            }
Packit 90a5c9
            else if (!ap_unescape_urlencoded(key) && !ap_unescape_urlencoded(val)) {
Packit 90a5c9
                if (!strcmp(SESSION_EXPIRY, key)) {
Packit 90a5c9
                    z->expiry = (apr_time_t) apr_atoi64(val);
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    apr_table_set(z->entries, key, val);
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        pair = apr_strtok(NULL, sep, &last);
Packit 90a5c9
    }
Packit 90a5c9
    z->encoded = NULL;
Packit 90a5c9
    return OK;
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Ensure any changes to the session are committed.
Packit 90a5c9
 *
Packit 90a5c9
 * This is done in an output filter so that our options for where to
Packit 90a5c9
 * store the session can include storing the session within a cookie:
Packit 90a5c9
 * As an HTTP header, the cookie must be set before the output is
Packit 90a5c9
 * written, but after the handler is run.
Packit 90a5c9
 *
Packit 90a5c9
 * NOTE: It is possible for internal redirects to cause more than one
Packit 90a5c9
 * request to be present, and each request might have a session
Packit 90a5c9
 * defined. We need to go through each session in turn, and save each
Packit 90a5c9
 * one.
Packit 90a5c9
 *
Packit 90a5c9
 * The same session might appear in more than one request. The first
Packit 90a5c9
 * attempt to save the session will be called
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t session_output_filter(ap_filter_t * f,
Packit 90a5c9
        apr_bucket_brigade * in)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    /* save all the sessions in all the requests */
Packit 90a5c9
    request_rec *r = f->r->main;
Packit 90a5c9
    if (!r) {
Packit 90a5c9
        r = f->r;
Packit 90a5c9
    }
Packit 90a5c9
    while (r) {
Packit 90a5c9
        session_rec *z = NULL;
Packit 90a5c9
        session_dir_conf *conf = ap_get_module_config(r->per_dir_config,
Packit 90a5c9
                                                      &session_module);
Packit 90a5c9
Packit 90a5c9
        /* load the session, or create one if necessary */
Packit 90a5c9
        /* when unset or on error, z will be NULL */
Packit 90a5c9
        ap_session_load(r, &z);
Packit 90a5c9
        if (!z || z->written) {
Packit 90a5c9
            r = r->next;
Packit 90a5c9
            continue;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* if a header was specified, insert the new values from the header */
Packit 90a5c9
        if (conf->header_set) {
Packit 90a5c9
            const char *override = apr_table_get(r->err_headers_out, conf->header);
Packit 90a5c9
            if (!override) {
Packit 90a5c9
                override = apr_table_get(r->headers_out, conf->header);
Packit 90a5c9
            }
Packit 90a5c9
            if (override) {
Packit 90a5c9
                apr_table_unset(r->err_headers_out, conf->header);
Packit 90a5c9
                apr_table_unset(r->headers_out, conf->header);
Packit 90a5c9
                z->encoded = override;
Packit 90a5c9
                z->dirty = 1;
Packit 90a5c9
                session_identity_decode(r, z);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* save away the session, and we're done */
Packit 90a5c9
        /* when unset or on error, we've complained to the log */
Packit 90a5c9
        ap_session_save(r, z);
Packit 90a5c9
Packit 90a5c9
        r = r->next;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* remove ourselves from the filter chain */
Packit 90a5c9
    ap_remove_output_filter(f);
Packit 90a5c9
Packit 90a5c9
    /* send the data up the stack */
Packit 90a5c9
    return ap_pass_brigade(f->next, in);
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Insert the output filter.
Packit 90a5c9
 */
Packit 90a5c9
static void session_insert_output_filter(request_rec * r)
Packit 90a5c9
{
Packit 90a5c9
    ap_add_output_filter("MOD_SESSION_OUT", NULL, r, r->connection);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Fixups hook.
Packit 90a5c9
 *
Packit 90a5c9
 * Load the session within a fixup - this ensures that the session is
Packit 90a5c9
 * properly loaded prior to the handler being called.
Packit 90a5c9
 *
Packit 90a5c9
 * The fixup is also responsible for injecting the session into the CGI
Packit 90a5c9
 * environment, should the admin have configured it so.
Packit 90a5c9
 *
Packit 90a5c9
 * @param r The request
Packit 90a5c9
 */
Packit 90a5c9
static int session_fixups(request_rec * r)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *conf = ap_get_module_config(r->per_dir_config,
Packit 90a5c9
                                                  &session_module);
Packit 90a5c9
Packit 90a5c9
    session_rec *z = NULL;
Packit 90a5c9
Packit 90a5c9
    /* if an error occurs or no session has been configured, we ignore
Packit 90a5c9
     * the broken session and allow it to be recreated from scratch on save
Packit 90a5c9
     * if necessary.
Packit 90a5c9
     */
Packit 90a5c9
    ap_session_load(r, &z);
Packit 90a5c9
Packit 90a5c9
    if (conf->env) {
Packit 90a5c9
        if (z) {
Packit 90a5c9
            session_identity_encode(r, z);
Packit 90a5c9
            if (z->encoded) {
Packit 90a5c9
                apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded);
Packit 90a5c9
                z->encoded = NULL;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        apr_table_unset(r->headers_in, "Session");
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static void *create_session_dir_config(apr_pool_t * p, char *dummy)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *new =
Packit 90a5c9
    (session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));
Packit 90a5c9
Packit 90a5c9
    new->includes = apr_array_make(p, 10, sizeof(const char **));
Packit 90a5c9
    new->excludes = apr_array_make(p, 10, sizeof(const char **));
Packit 90a5c9
Packit 90a5c9
    return (void *) new;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *new = (session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));
Packit 90a5c9
    session_dir_conf *add = (session_dir_conf *) addv;
Packit 90a5c9
    session_dir_conf *base = (session_dir_conf *) basev;
Packit 90a5c9
Packit 90a5c9
    new->enabled = (add->enabled_set == 0) ? base->enabled : add->enabled;
Packit 90a5c9
    new->enabled_set = add->enabled_set || base->enabled_set;
Packit 90a5c9
    new->maxage = (add->maxage_set == 0) ? base->maxage : add->maxage;
Packit 90a5c9
    new->maxage_set = add->maxage_set || base->maxage_set;
Packit 90a5c9
    new->header = (add->header_set == 0) ? base->header : add->header;
Packit 90a5c9
    new->header_set = add->header_set || base->header_set;
Packit 90a5c9
    new->env = (add->env_set == 0) ? base->env : add->env;
Packit 90a5c9
    new->env_set = add->env_set || base->env_set;
Packit 90a5c9
    new->includes = apr_array_append(p, base->includes, add->includes);
Packit 90a5c9
    new->excludes = apr_array_append(p, base->excludes, add->excludes);
Packit 682164
    new->expiry_update_time = (add->expiry_update_set == 0)
Packit 682164
                                ? base->expiry_update_time
Packit 682164
                                : add->expiry_update_time;
Packit 682164
    new->expiry_update_set = add->expiry_update_set || base->expiry_update_set;
Packit 90a5c9
Packit 90a5c9
    return new;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
     set_session_enable(cmd_parms * parms, void *dconf, int flag)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    conf->enabled = flag;
Packit 90a5c9
    conf->enabled_set = 1;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
     set_session_maxage(cmd_parms * parms, void *dconf, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    conf->maxage = atol(arg);
Packit 90a5c9
    conf->maxage_set = 1;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
     set_session_header(cmd_parms * parms, void *dconf, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    conf->header = arg;
Packit 90a5c9
    conf->header_set = 1;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
     set_session_env(cmd_parms * parms, void *dconf, int flag)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    conf->env = flag;
Packit 90a5c9
    conf->env_set = 1;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *add_session_include(cmd_parms * cmd, void *dconf, const char *f)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    const char **new = apr_array_push(conf->includes);
Packit 90a5c9
    *new = f;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char *f)
Packit 90a5c9
{
Packit 90a5c9
    session_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    const char **new = apr_array_push(conf->excludes);
Packit 90a5c9
    *new = f;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 682164
static const char *
Packit 682164
     set_session_expiry_update(cmd_parms * parms, void *dconf, const char *arg)
Packit 682164
{
Packit 682164
    session_dir_conf *conf = dconf;
Packit 682164
Packit 682164
    conf->expiry_update_time = atoi(arg);
Packit 682164
    if (conf->expiry_update_time < 0) {
Packit 682164
        return "SessionExpiryUpdateInterval must be positive or nul";
Packit 682164
    }
Packit 682164
    conf->expiry_update_time = apr_time_from_sec(conf->expiry_update_time);
Packit 682164
    conf->expiry_update_set = 1;
Packit 682164
Packit 682164
    return NULL;
Packit 682164
}
Packit 682164
Packit 90a5c9
Packit 90a5c9
static const command_rec session_cmds[] =
Packit 90a5c9
{
Packit 90a5c9
    AP_INIT_FLAG("Session", set_session_enable, NULL, RSRC_CONF|OR_AUTHCFG,
Packit 90a5c9
                 "on if a session should be maintained for these URLs"),
Packit 90a5c9
    AP_INIT_TAKE1("SessionMaxAge", set_session_maxage, NULL, RSRC_CONF|OR_AUTHCFG,
Packit 90a5c9
                  "length of time for which a session should be valid. Zero to disable"),
Packit 90a5c9
    AP_INIT_TAKE1("SessionHeader", set_session_header, NULL, RSRC_CONF|OR_AUTHCFG,
Packit 90a5c9
                  "output header, if present, whose contents will be injected into the session."),
Packit 90a5c9
    AP_INIT_FLAG("SessionEnv", set_session_env, NULL, RSRC_CONF|OR_AUTHCFG,
Packit 90a5c9
                 "on if a session should be written to the CGI environment. Defaults to off"),
Packit 90a5c9
    AP_INIT_TAKE1("SessionInclude", add_session_include, NULL, RSRC_CONF|OR_AUTHCFG,
Packit 90a5c9
                  "URL prefixes to include in the session. Defaults to all URLs"),
Packit 90a5c9
    AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, RSRC_CONF|OR_AUTHCFG,
Packit 90a5c9
                  "URL prefixes to exclude from the session. Defaults to no URLs"),
Packit 682164
    AP_INIT_TAKE1("SessionExpiryUpdateInterval", set_session_expiry_update, NULL, RSRC_CONF|OR_AUTHCFG,
Packit 682164
                  "time interval for which a session's expiry time may change "
Packit 682164
                  "without having to be rewritten. Zero to disable"),
Packit 90a5c9
    {NULL}
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static void register_hooks(apr_pool_t * p)
Packit 90a5c9
{
Packit 90a5c9
    ap_register_output_filter("MOD_SESSION_OUT", session_output_filter,
Packit 90a5c9
                              NULL, AP_FTYPE_CONTENT_SET);
Packit 90a5c9
    ap_hook_insert_filter(session_insert_output_filter, NULL, NULL,
Packit 90a5c9
                          APR_HOOK_MIDDLE);
Packit 90a5c9
    ap_hook_insert_error_filter(session_insert_output_filter,
Packit 90a5c9
                                NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
    ap_hook_fixups(session_fixups, NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
    ap_hook_session_encode(session_identity_encode, NULL, NULL,
Packit 90a5c9
                           APR_HOOK_REALLY_FIRST);
Packit 90a5c9
    ap_hook_session_decode(session_identity_decode, NULL, NULL,
Packit 90a5c9
                           APR_HOOK_REALLY_LAST);
Packit 90a5c9
    APR_REGISTER_OPTIONAL_FN(ap_session_get);
Packit 90a5c9
    APR_REGISTER_OPTIONAL_FN(ap_session_set);
Packit 90a5c9
    APR_REGISTER_OPTIONAL_FN(ap_session_load);
Packit 90a5c9
    APR_REGISTER_OPTIONAL_FN(ap_session_save);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE_MODULE(session) =
Packit 90a5c9
{
Packit 90a5c9
    STANDARD20_MODULE_STUFF,
Packit 90a5c9
    create_session_dir_config,   /* dir config creater */
Packit 90a5c9
    merge_session_dir_config,    /* dir merger --- default is to override */
Packit 90a5c9
    NULL,                        /* server config */
Packit 90a5c9
    NULL,                        /* merge server config */
Packit 90a5c9
    session_cmds,                /* command apr_table_t */
Packit 90a5c9
    register_hooks               /* register hooks */
Packit 90a5c9
};