mod_session.c revision 5ae15cd9d22fb3bdfd2eb0b9761c4ef07fbf2f96
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd/* Licensed to the Apache Software Foundation (ASF) under one or more
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * contributor license agreements. See the NOTICE file distributed with
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * this work for additional information regarding copyright ownership.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * The ASF licenses this file to You under the Apache License, Version 2.0
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * (the "License"); you may not use this file except in compliance with
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * the License. You may obtain a copy of the License at
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * http://www.apache.org/licenses/LICENSE-2.0
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * Unless required by applicable law or agreed to in writing, software
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * distributed under the License is distributed on an "AS IS" BASIS,
2e545ce2450a9953665f701bb05350f0d3f26275nd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd#include "mod_session.h"
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen#include "apr_lib.h"
3f08db06526d6901aa08c110b5bc7dde6bc39905nd#include "apr_strings.h"
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd#include "util_filter.h"
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd#include "http_log.h"
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd#include "http_request.h"
3f08db06526d6901aa08c110b5bc7dde6bc39905nd#include "http_protocol.h"
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd#define SESSION_PREFIX "mod_session: "
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd#define SESSION_EXPIRY "expiry"
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd#define HTTP_SESSION "HTTP_SESSION"
ecc5150d35c0dc5ee5119c2717e6660fa331abbftakashi
c04f76acce77126cf88b09350e56ea8c6b4a064enilgunAPR_HOOK_STRUCT(
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd APR_HOOK_LINK(session_load)
63f06dce77bb2d9b1c5aa5deeb47a1069987fd1end APR_HOOK_LINK(session_save)
d474d8ef01ec5c2a09341cd148851ed383c3287crbowen APR_HOOK_LINK(session_encode)
d474d8ef01ec5c2a09341cd148851ed383c3287crbowen APR_HOOK_LINK(session_decode)
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd)
4b575a6b6704b516f22d65a3ad35696d7b9ba372rpluemAPR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ap, SESSION, int, session_load,
4b575a6b6704b516f22d65a3ad35696d7b9ba372rpluem (request_rec * r, session_rec ** z), (r, z), DECLINED)
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndAPR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ap, SESSION, int, session_save,
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd (request_rec * r, session_rec * z), (r, z), DECLINED)
3f08db06526d6901aa08c110b5bc7dde6bc39905ndAPR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap, SESSION, int, session_encode,
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd (request_rec * r, session_rec * z), (r, z), OK, DECLINED)
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndAPR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ap, SESSION, int, session_decode,
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd (request_rec * r, session_rec * z), (r, z), OK, DECLINED)
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndstatic int session_identity_encode(request_rec * r, session_rec * z);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndstatic int session_identity_decode(request_rec * r, session_rec * z);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndstatic int session_fixups(request_rec * r);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd/**
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * Should the session be included within this URL.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * This function tests whether a session is valid for this URL. It uses the
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * include and exclude arrays to determine whether they should be included.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd */
71fccc298df6a1540d408151a26aa22beed55d0bndstatic int session_included(request_rec * r, session_dir_conf * conf)
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd{
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd const char **includes = (const char **) conf->includes->elts;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd const char **excludes = (const char **) conf->excludes->elts;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd int included = 1; /* defaults to included */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd int i;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (conf->includes->nelts) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd included = 0;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd for (i = 0; !included && i < conf->includes->nelts; i++) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd const char *include = includes[i];
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (strncmp(r->parsed_uri.path, include, strlen(include))) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd included = 1;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (conf->excludes->nelts) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd for (i = 0; included && i < conf->includes->nelts; i++) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd const char *exclude = excludes[i];
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (strncmp(r->parsed_uri.path, exclude, strlen(exclude))) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd included = 0;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return included;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd}
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd/**
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * Load the session.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * If the session doesn't exist, a blank one will be created.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * @param r The request
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * @param z A pointer to where the session will be written.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndstatic int ap_session_load(request_rec * r, session_rec ** z)
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd{
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd &session_module);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd apr_time_t now;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd session_rec *zz = NULL;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd int rv = 0;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* is the session enabled? */
71fccc298df6a1540d408151a26aa22beed55d0bnd if (!dconf || !dconf->enabled) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return APR_SUCCESS;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* should the session be loaded at all? */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (!session_included(r, dconf)) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "excluded by configuration for: %s", r->uri);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return APR_SUCCESS;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* load the session from the session hook */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd rv = ap_run_session_load(r, &zz);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (DECLINED == rv) {
5652dbe450e4fcfdf36d4cfb42d7f2345ded29a4maczniak ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "session is enabled but no session modules have been configured, "
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "session not loaded: %s", r->uri);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return APR_EGENERAL;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd else if (OK != rv) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "error while loading the session, "
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "session not loaded: %s", r->uri);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return rv;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* found a session that hasn't expired? */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd now = apr_time_now();
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (!zz || (zz->expiry && zz->expiry < now)) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* no luck, create a blank session */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec));
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd zz->pool = r->pool;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd zz->entries = apr_table_make(zz->pool, 10);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd zz->uuid = (apr_uuid_t *) apr_pcalloc(zz->pool, sizeof(apr_uuid_t));
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd apr_uuid_get(zz->uuid);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
71fccc298df6a1540d408151a26aa22beed55d0bnd else {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd rv = ap_run_session_decode(r, zz);
a8703cfb67133446eef7af1043640e71486e9ecand if (OK != rv) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "error while decoding the session, "
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "session not loaded: %s", r->uri);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return rv;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* make sure the expiry is set, if present */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (!zz->expiry && dconf->maxage) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC;
71fccc298df6a1540d408151a26aa22beed55d0bnd zz->maxage = dconf->maxage;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *z = zz;
71fccc298df6a1540d408151a26aa22beed55d0bnd
71fccc298df6a1540d408151a26aa22beed55d0bnd return APR_SUCCESS;
71fccc298df6a1540d408151a26aa22beed55d0bnd
71fccc298df6a1540d408151a26aa22beed55d0bnd}
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd/**
b3c7a2279fa7a45f5807d9a404760b9b3760df50nd * Save the session.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
316f02e3836836c82e19019ff23f90a7ebc65289nilgun * In most implementations the session is only saved if the dirty flag is
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * true. This prevents the session being saved unnecessarily.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * @param r The request
22d5d84393d960a2027f472036f3fee15d7dbce9nd * @param z A pointer to where the session will be written.
22d5d84393d960a2027f472036f3fee15d7dbce9nd */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndstatic int ap_session_save(request_rec * r, session_rec * z)
4b311579b2c8aebac85fb7cb8ac89e6c37b4bc1asf{
50c04f297d76a57ead2fa6b73845f7563b1fc788sf if (z) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd apr_time_t now = apr_time_now();
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd int rv = 0;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
623eebe956d9c2d6d073ed3eae855b56030b40e9noodl session_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd &session_module);
ffb88a4885747797937e30a5ac8b1606da3cb4adnd
909ce17e2bd0faef7b1c294f2307f009793fd493nd /* sanity checks, should we try save at all? */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (z->written) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, SESSION_PREFIX
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe "attempt made to save the session twice, "
65a611af7093423efb91e5794b8887a527d4cf63trawick "session not saved: %s", r->uri);
42af92a661a06b3cebc88d585aad75064a309d51nd return APR_EGENERAL;
ffb88a4885747797937e30a5ac8b1606da3cb4adnd }
6fe26506780e73be2a412d758af77fafdf03291and if (z->expiry && z->expiry < now) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "attempt made to save a session when the session had already expired, "
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "session not saved: %s", r->uri);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return APR_EGENERAL;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
08cf4a15275e4cb65a424b3a1db5410bfb51085cjim /* reset the expiry back to maxage, if the expiry is present */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (dconf->maxage) {
78f97ce162b66a0dbfd7af4dcd9984f162569b04minfrin z->expiry = now + dconf->maxage * APR_USEC_PER_SEC;
f5a398cc8880978754903f9ece8e4beb63a81cedrbowen z->maxage = dconf->maxage;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* encode the session */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd rv = ap_run_session_encode(r, z);
7906201913b68fe78b9d6a22ab33bf21d82c490eminfrin if (OK != rv) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "error while encoding the session, "
05ede5110427cb9dc071cc671d5aaba5d3b88c79nd "session not saved: %s", r->uri);
e8b603fa9ccf7b17b11b42df6d8916fd97c2331dnd return rv;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
4ed26c413f67a5aae20b95909828f30bb5dc2286poirier
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd /* try the save */
611049e38bfbaeb173d2d7fab2e44a48753436a1nd rv = ap_run_session_save(r, z);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (DECLINED == rv) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "session is enabled but no session modules have been configured, "
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "session not saved: %s", r->uri);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return APR_EGENERAL;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
03a4ff9ac4c9b8009249010e7c53bb86ff05915and else if (OK != rv) {
5effc8b39fae5cd169d17f342bfc265705840014rbowen ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, SESSION_PREFIX
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd "error while saving the session, "
d0828c8a321dc5e9ea60550f052294669c08cf93jim "session not saved: %s", r->uri);
d0828c8a321dc5e9ea60550f052294669c08cf93jim return rv;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
4b5981e276e93df97c34e4da05ca5cf8bbd937dand else {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd z->written = 1;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
2704de98885368683621b01c8f8f4e4b01557611takashi
2704de98885368683621b01c8f8f4e4b01557611takashi return APR_SUCCESS;
2704de98885368683621b01c8f8f4e4b01557611takashi
d0828c8a321dc5e9ea60550f052294669c08cf93jim}
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd/**
c819c19c2f1ffbf3a3f12a4070cc6c3f4ea2a6f2sf * Get a particular value from the session.
d2b809e5d72658bff23819d8b77f20e4939af541nd * @param r The current request.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * @param z The current session. If this value is NULL, the session will be
a4687128d43515b5791a6efc6ba55314478f9552jim * looked up in the request, created if necessary, and saved to the request
04bab87733a0e93a926e82311c85cd8ac06a032fnd * notes.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * @param key The key to get.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * @param value The buffer to write the value to.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd */
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndstatic void ap_session_get(request_rec * r, session_rec * z, const char *key, const char **value)
5effc8b39fae5cd169d17f342bfc265705840014rbowen{
27d778df0b517e1578f907d2e51eb961cd8ee5fbjim if (!z) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_session_load(r, &z);
a43bfa789f4e52dde53ae8e53fa0427b5c1cf977nd }
a43bfa789f4e52dde53ae8e53fa0427b5c1cf977nd if (z && z->entries) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *value = apr_table_get(z->entries, key);
438b4817913a5ff55d9cad4c7ddf133330b4466ejim }
1d980e5489836e977ba59b419e27b0ec875c4bd3takashi}
50cb7e2b30597f481fee57bac945190f06ebcc58jorton
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd/**
4126704c4950bfd46d32ad54e3b106ac6d868a73sf * Set a particular value to the session.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
0a69d9bb491d9810892a9949c01403a1de3c7ac2nd * Using this method ensures that the dirty flag is set correctly, so that
245eb3a84b8bc2b350c3a39ba2599444d443b50ajim * the session can be saved efficiently.
4ed26c413f67a5aae20b95909828f30bb5dc2286poirier * @param r The current request.
6d20aeba2c4aa0938bc6e0659d13adc7670ff421poirier * @param z The current session. If this value is NULL, the session will be
5f4e50966b2b9b58436a1651cbe588d1b595657ewrowe * looked up in the request, created if necessary, and saved to the request
11495c9f0bd33e51a25b4d532beadfbcf9b944a3nilgun * notes.
ecc5150d35c0dc5ee5119c2717e6660fa331abbftakashi * @param key The key to set. The existing key value will be replaced.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * @param value The value to set.
79b024b81f6bb3c44dce77a7552191daf8b522d2jim */
f772e8f448c223e5ea306f1bf92d97d968f972d5jimstatic void ap_session_set(request_rec * r, session_rec * z,
f772e8f448c223e5ea306f1bf92d97d968f972d5jim const char *key, const char *value)
f772e8f448c223e5ea306f1bf92d97d968f972d5jim{
fac8c35bfb158112226ab43ddf84d59daca5dc30nd if (!z) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_session_load(r, &z);
1de1266f0ea387d6373be8415745dfd2ab876341jim }
1de1266f0ea387d6373be8415745dfd2ab876341jim if (z) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (value) {
5effc8b39fae5cd169d17f342bfc265705840014rbowen apr_table_set(z->entries, key, value);
5effc8b39fae5cd169d17f342bfc265705840014rbowen }
5effc8b39fae5cd169d17f342bfc265705840014rbowen else {
5effc8b39fae5cd169d17f342bfc265705840014rbowen apr_table_unset(z->entries, key);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd z->dirty = 1;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
898711b68797304101de0882fa576c8908acfae6nd}
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
4044e4b6cb07cf7fa8e90676fafffe543c1d439bjimstatic int identity_count(int *count, const char *key, const char *val)
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd{
50cb7e2b30597f481fee57bac945190f06ebcc58jorton *count += strlen(key) * 3 + strlen(val) * 3 + 1;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return 1;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd}
03c25fb6f628ac81f2ecb637d1e7502dcee783f3nd
6116c12fdd3ed06d388fe6572e50a22e9320dfa5ndstatic int identity_concat(char *buffer, const char *key, const char *val)
b43f840409794ed298e8634f6284741f193b6c4ftakashi{
4126704c4950bfd46d32ad54e3b106ac6d868a73sf char *slider = buffer;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd int length = strlen(slider);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd slider += length;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd if (length) {
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *slider = '&';
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd slider++;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd }
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_escape_path_segment_buffer(slider, key);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd slider += strlen(slider);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *slider = '=';
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd slider++;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd ap_escape_path_segment_buffer(slider, val);
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd return 1;
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd}
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd
71fccc298df6a1540d408151a26aa22beed55d0bnd/**
71fccc298df6a1540d408151a26aa22beed55d0bnd * Default identity encoding for the session.
71fccc298df6a1540d408151a26aa22beed55d0bnd *
71fccc298df6a1540d408151a26aa22beed55d0bnd * By default, the name value pairs in the session are URLEncoded, separated
71fccc298df6a1540d408151a26aa22beed55d0bnd * by equals, and then in turn separated by ampersand, in the format of an
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * html form.
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd *
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * This was chosen to make it easy for external code to unpack a session,
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd * should there be a need to do so.
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd *
ecc5150d35c0dc5ee5119c2717e6660fa331abbftakashi * @param r The request pointer.
c04f76acce77126cf88b09350e56ea8c6b4a064enilgun * @param z A pointer to where the session will be written.
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd */
63f06dce77bb2d9b1c5aa5deeb47a1069987fd1endstatic int session_identity_encode(request_rec * r, session_rec * z)
d474d8ef01ec5c2a09341cd148851ed383c3287crbowen{
d474d8ef01ec5c2a09341cd148851ed383c3287crbowen
727872d18412fc021f03969b8641810d8896820bhumbedooh char *buffer = NULL;
0d0ba3a410038e179b695446bb149cce6264e0abnd int length = 0;
727872d18412fc021f03969b8641810d8896820bhumbedooh if (z->expiry) {
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh char *expiry = apr_psprintf(r->pool, "%" APR_INT64_T_FMT, z->expiry);
0d0ba3a410038e179b695446bb149cce6264e0abnd apr_table_set(z->entries, SESSION_EXPIRY, expiry);
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh }
727872d18412fc021f03969b8641810d8896820bhumbedooh apr_table_do((int (*) (void *, const char *, const char *))
0d0ba3a410038e179b695446bb149cce6264e0abnd identity_count, &length, z->entries, NULL);;
0d0ba3a410038e179b695446bb149cce6264e0abnd buffer = apr_pcalloc(r->pool, length + 1);
0d0ba3a410038e179b695446bb149cce6264e0abnd apr_table_do((int (*) (void *, const char *, const char *))
ac082aefa89416cbdc9a1836eaf3bed9698201c8humbedooh identity_concat, buffer, z->entries, NULL);
0d0ba3a410038e179b695446bb149cce6264e0abnd z->encoded = buffer;
0d0ba3a410038e179b695446bb149cce6264e0abnd return OK;
0d0ba3a410038e179b695446bb149cce6264e0abnd
727872d18412fc021f03969b8641810d8896820bhumbedooh}
0d0ba3a410038e179b695446bb149cce6264e0abnd
0d0ba3a410038e179b695446bb149cce6264e0abnd/**
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh * Default identity decoding for the session.
07dc96d063d49299da433f84b5c5681da9bbdf68rbowen *
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * By default, the name value pairs in the session are URLEncoded, separated
0d0ba3a410038e179b695446bb149cce6264e0abnd * by equals, and then in turn separated by ampersand, in the format of an
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * html form.
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd *
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * This was chosen to make it easy for external code to unpack a session,
6116c12fdd3ed06d388fe6572e50a22e9320dfa5nd * should there be a need to do so.
*
* This function reverses that process, and populates the session table.
*
* Name / value pairs that are not encoded properly are ignored.
*
* @param r The request pointer.
* @param z A pointer to where the session will be written.
*/
static int session_identity_decode(request_rec * r, session_rec * z)
{
char *last = NULL;
char *encoded, *pair;
const char *sep = "&";
/* sanity check - anything to decode? */
if (!z->encoded) {
return OK;
}
/* decode what we have */
encoded = apr_pstrcat(r->pool, z->encoded, NULL);
pair = apr_strtok(encoded, sep, &last);
while (pair && pair[0]) {
char *plast = NULL;
const char *psep = "=";
char *key = apr_strtok(pair, psep, &plast);
char *val = apr_strtok(NULL, psep, &plast);
if (key && *key) {
if (!val || !*val) {
apr_table_unset(z->entries, key);
}
else if (!ap_unescape_all(key) && !ap_unescape_all(val)) {
if (!strcmp(SESSION_EXPIRY, key)) {
z->expiry = (apr_time_t) apr_atoi64(val);
}
else {
apr_table_set(z->entries, key, val);
}
}
}
pair = apr_strtok(NULL, sep, &last);
}
z->encoded = NULL;
return OK;
}
/**
* Ensure any changes to the session are committed.
*
* This is done in an output filter so that our options for where to
* store the session can include storing the session within a cookie:
* As an HTTP header, the cookie must be set before the output is
* written, but after the handler is run.
*
* NOTE: It is possible for internal redirects to cause more than one
* request to be present, and each request might have a session
* defined. We need to go through each session in turn, and save each
* one.
*
* The same session might appear in more than one request. The first
* attempt to save the session will be called
*/
static apr_status_t session_output_filter(ap_filter_t * f,
apr_bucket_brigade * in)
{
/* save all the sessions in all the requests */
request_rec *r = f->r->main;
if (!r) {
r = f->r;
}
while (r) {
session_rec *z = NULL;
session_dir_conf *conf = ap_get_module_config(r->per_dir_config,
&session_module);
/* load the session, or create one if necessary */
ap_session_load(r, &z);
if (!z || z->written) {
r = r->next;
continue;
}
/* if a header was specified, insert the new values from the header */
if (conf->header_set) {
const char *override = apr_table_get(r->err_headers_out, conf->header);
if (!override) {
override = apr_table_get(r->headers_out, conf->header);
}
if (override) {
z->encoded = override;
session_identity_decode(r, z);
}
}
/* save away the session, and we're done */
ap_session_save(r, z);
r = r->next;
}
/* remove ourselves from the filter chain */
ap_remove_output_filter(f);
/* send the data up the stack */
return ap_pass_brigade(f->next, in);
}
/**
* Insert the output filter.
*/
static void session_insert_output_filter(request_rec * r)
{
ap_add_output_filter("MOD_SESSION_OUT", NULL, r, r->connection);
}
/**
* Fixups hook.
*
* Load the session within a fixup - this ensures that the session is
* properly loaded prior to the handler being called.
*
* The fixup is also responsible for injecting the session into the CGI
* environment, should the admin have configured it so.
*
* @param r The request
*/
static int session_fixups(request_rec * r)
{
session_dir_conf *conf = ap_get_module_config(r->per_dir_config,
&session_module);
session_rec *z = NULL;
ap_session_load(r, &z);
if (conf->env) {
session_identity_encode(r, z);
if (z->encoded) {
apr_table_set(r->subprocess_env, HTTP_SESSION, z->encoded);
z->encoded = NULL;
}
}
return OK;
}
static void *create_session_dir_config(apr_pool_t * p, char *dummy)
{
session_dir_conf *new =
(session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));
new->includes = apr_array_make(p, 10, sizeof(const char **));
new->excludes = apr_array_make(p, 10, sizeof(const char **));
return (void *) new;
}
static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv)
{
session_dir_conf *new = (session_dir_conf *) apr_pcalloc(p, sizeof(session_dir_conf));
session_dir_conf *add = (session_dir_conf *) addv;
session_dir_conf *base = (session_dir_conf *) basev;
new->enabled = (add->enabled_set == 0) ? base->enabled : add->enabled;
new->enabled_set = add->enabled_set || base->enabled_set;
new->maxage = (add->maxage_set == 0) ? base->maxage : add->maxage;
new->maxage_set = add->maxage_set || base->maxage_set;
new->header = (add->header_set == 0) ? base->header : add->header;
new->header_set = add->header_set || base->header_set;
new->env = (add->env_set == 0) ? base->env : add->env;
new->env_set = add->env_set || base->env_set;
new->includes = apr_array_append(p, base->includes, add->includes);
new->excludes = apr_array_append(p, base->excludes, add->excludes);
return new;
}
static const char *
set_session_enable(cmd_parms * parms, void *dconf, int flag)
{
session_dir_conf *conf = dconf;
conf->enabled = flag;
conf->enabled_set = 1;
return NULL;
}
static const char *
set_session_maxage(cmd_parms * parms, void *dconf, const char *arg)
{
session_dir_conf *conf = dconf;
conf->maxage = atol(arg);
conf->maxage_set = 1;
return NULL;
}
static const char *
set_session_header(cmd_parms * parms, void *dconf, const char *arg)
{
session_dir_conf *conf = dconf;
conf->header = arg;
conf->header_set = 1;
return NULL;
}
static const char *
set_session_env(cmd_parms * parms, void *dconf, int flag)
{
session_dir_conf *conf = dconf;
conf->env = flag;
conf->env_set = 1;
return NULL;
}
static const char *add_session_include(cmd_parms * cmd, void *dconf, const char *f)
{
session_dir_conf *conf = dconf;
const char **new = apr_array_push(conf->includes);
*new = f;
return NULL;
}
static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char *f)
{
session_dir_conf *conf = dconf;
const char **new = apr_array_push(conf->excludes);
*new = f;
return NULL;
}
static const command_rec session_cmds[] =
{
AP_INIT_FLAG("Session", set_session_enable, NULL, RSRC_CONF|OR_AUTHCFG,
"on if a session should be maintained for these URLs"),
AP_INIT_TAKE1("SessionMaxAge", set_session_maxage, NULL, RSRC_CONF|OR_AUTHCFG,
"length of time for which a session should be valid. Zero to disable"),
AP_INIT_TAKE1("SessionHeader", set_session_header, NULL, RSRC_CONF|OR_AUTHCFG,
"output header, if present, whose contents will be injected into the session."),
AP_INIT_FLAG("SessionEnv", set_session_env, NULL, RSRC_CONF|OR_AUTHCFG,
"on if a session should be written to the CGI environment. Defaults to off"),
AP_INIT_TAKE1("SessionInclude", add_session_include, NULL, RSRC_CONF|OR_AUTHCFG,
"URL prefixes to include in the session. Defaults to all URLs"),
AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, RSRC_CONF|OR_AUTHCFG,
"URL prefixes to exclude from the session. Defaults to no URLs"),
{NULL}
};
static void register_hooks(apr_pool_t * p)
{
ap_register_output_filter("MOD_SESSION_OUT", session_output_filter,
NULL, AP_FTYPE_CONTENT_SET);
ap_hook_insert_filter(session_insert_output_filter, NULL, NULL,
APR_HOOK_MIDDLE);
ap_hook_insert_error_filter(session_insert_output_filter,
NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_fixups(session_fixups, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_session_encode(session_identity_encode, NULL, NULL,
APR_HOOK_REALLY_FIRST);
ap_hook_session_decode(session_identity_decode, NULL, NULL,
APR_HOOK_REALLY_LAST);
APR_REGISTER_OPTIONAL_FN(ap_session_get);
APR_REGISTER_OPTIONAL_FN(ap_session_set);
APR_REGISTER_OPTIONAL_FN(ap_session_load);
APR_REGISTER_OPTIONAL_FN(ap_session_save);
}
module AP_MODULE_DECLARE_DATA session_module =
{
STANDARD20_MODULE_STUFF,
create_session_dir_config, /* dir config creater */
merge_session_dir_config, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
session_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};