Apache HTTPD
mod_session.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "mod_session.h"
18#include "apr_lib.h"
19#include "apr_strings.h"
20#include "util_filter.h"
21#include "http_log.h"
22#include "http_request.h"
23#include "http_protocol.h"
24
25#define SESSION_EXPIRY "expiry"
26#define HTTP_SESSION "HTTP_SESSION"
27
42
46
54{
55
56 const char **includes = (const char **) conf->includes->elts;
57 const char **excludes = (const char **) conf->excludes->elts;
58 int included = 1; /* defaults to included */
59 int i;
60
61 if (conf->includes->nelts) {
62 included = 0;
63 for (i = 0; !included && i < conf->includes->nelts; i++) {
64 const char *include = includes[i];
65 if (strncmp(r->uri, include, strlen(include)) == 0) {
66 included = 1;
67 }
68 }
69 }
70
71 if (conf->excludes->nelts) {
72 for (i = 0; included && i < conf->excludes->nelts; i++) {
73 const char *exclude = excludes[i];
74 if (strncmp(r->uri, exclude, strlen(exclude)) == 0) {
75 included = 0;
76 }
77 }
78 }
79
80 return included;
81}
82
92{
93
95 &session_module);
98 int rv = 0;
99
100 /* is the session enabled? */
101 if (!dconf || !dconf->enabled) {
102 return APR_SUCCESS;
103 }
104
105 /* should the session be loaded at all? */
106 if (!session_included(r, dconf)) {
108 "excluded by configuration for: %s", r->uri);
109 return APR_SUCCESS;
110 }
111
112 /* load the session from the session hook */
113 rv = ap_run_session_load(r, &zz);
114 if (DECLINED == rv) {
116 "session is enabled but no session modules have been configured, "
117 "session not loaded: %s", r->uri);
118 return APR_EGENERAL;
119 }
120 else if (OK != rv) {
122 "error while loading the session, "
123 "session not loaded: %s", r->uri);
124 return rv;
125 }
126
127 /* found a session that hasn't expired? */
128 now = apr_time_now();
129
130 if (zz) {
131 /* load the session attributes */
133
134 /* having a session we cannot decode is just as good as having
135 none at all */
136 if (OK != rv) {
138 "error while decoding the session, "
139 "session not loaded: %s", r->uri);
140 zz = NULL;
141 }
142
143 /* invalidate session if session is expired */
144 if (zz && zz->expiry && zz->expiry < now) {
145 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "session is expired");
146 zz = NULL;
147 }
148 }
149
150 /* no luck, create a blank session */
151 if (!zz) {
152 zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec));
153 zz->pool = r->pool;
154 zz->entries = apr_table_make(zz->pool, 10);
155 }
156
157 /* make sure the expiry and maxage are set, if present */
158 if (dconf->maxage) {
159 if (!zz->expiry) {
160 zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC;
161 }
162 zz->maxage = dconf->maxage;
163 }
164
165 *z = zz;
166
167 return APR_SUCCESS;
168
169}
170
181{
182 if (z) {
184 apr_time_t initialExpiry = z->expiry;
185 int rv = 0;
186
188 &session_module);
189
190 /* sanity checks, should we try save at all? */
191 if (z->written) {
193 "attempt made to save the session twice, "
194 "session not saved: %s", r->uri);
195 return APR_EGENERAL;
196 }
197 if (z->expiry && z->expiry < now) {
199 "attempt made to save a session when the session had already expired, "
200 "session not saved: %s", r->uri);
201 return APR_EGENERAL;
202 }
203
204 /* reset the expiry back to maxage, if the expiry is present */
205 if (dconf->maxage) {
206 z->expiry = now + dconf->maxage * APR_USEC_PER_SEC;
207 z->maxage = dconf->maxage;
208 }
209
210 /* reset the expiry before saving if present */
211 if (z->dirty && z->maxage) {
212 z->expiry = now + z->maxage * APR_USEC_PER_SEC;
213 }
214
215 /* don't save if the only change is the expiry by a small amount */
216 if (!z->dirty && dconf->expiry_update_time
217 && (z->expiry - initialExpiry < dconf->expiry_update_time)) {
218 return APR_SUCCESS;
219 }
220
221 /* also don't save sessions that didn't change at all */
222 if (!z->dirty && !z->maxage) {
223 return APR_SUCCESS;
224 }
225
226 /* encode the session */
228 if (OK != rv) {
230 "error while encoding the session, "
231 "session not saved: %s", r->uri);
232 return rv;
233 }
234
235 /* try the save */
236 rv = ap_run_session_save(r, z);
237 if (DECLINED == rv) {
239 "session is enabled but no session modules have been configured, "
240 "session not saved: %s", r->uri);
241 return APR_EGENERAL;
242 }
243 else if (OK != rv) {
245 "error while saving the session, "
246 "session not saved: %s", r->uri);
247 return rv;
248 }
249 else {
250 z->written = 1;
251 }
252 }
253
254 return APR_SUCCESS;
255
256}
257
268 const char *key, const char **value)
269{
270 if (!z) {
271 apr_status_t rv;
272 rv = ap_session_load(r, &z);
273 if (APR_SUCCESS != rv) {
274 return rv;
275 }
276 }
277 if (z && z->entries) {
278 *value = apr_table_get(z->entries, key);
279 }
280
281 return OK;
282}
283
297 const char *key, const char *value)
298{
299 if (!z) {
300 apr_status_t rv;
301 rv = ap_session_load(r, &z);
302 if (APR_SUCCESS != rv) {
303 return rv;
304 }
305 }
306 if (z) {
307 if (value) {
308 apr_table_set(z->entries, key, value);
309 }
310 else {
311 apr_table_unset(z->entries, key);
312 }
313 z->dirty = 1;
314 }
315 return APR_SUCCESS;
316}
317
318static int identity_count(void *v, const char *key, const char *val)
319{
320 apr_size_t *count = v;
321
322 *count += strlen(key) * 3 + strlen(val) * 3 + 2;
323 return 1;
324}
325
326static int identity_concat(void *v, const char *key, const char *val)
327{
328 char *slider = v;
329 apr_size_t length = strlen(slider);
330
331 slider += length;
332 if (length) {
333 *slider = '&';
334 slider++;
335 }
337 slider += strlen(slider);
338 *slider = '=';
339 slider++;
341 return 1;
342}
343
358{
359 char *buffer = NULL;
360 apr_size_t length = 0;
361
362 if (z->expiry) {
363 char *expiry = apr_psprintf(z->pool, "%" APR_INT64_T_FMT, z->expiry);
364 apr_table_setn(z->entries, SESSION_EXPIRY, expiry);
365 }
367 buffer = apr_pcalloc(r->pool, length + 1);
369 z->encoded = buffer;
370 return OK;
371
372}
373
392{
393
394 char *last = NULL;
395 char *encoded, *pair;
396 const char *sep = "&";
397
398 /* sanity check - anything to decode? */
399 if (!z->encoded) {
400 return OK;
401 }
402
403 /* decode what we have */
404 encoded = apr_pstrdup(r->pool, z->encoded);
405 pair = apr_strtok(encoded, sep, &last);
406 while (pair && pair[0]) {
407 char *plast = NULL;
408 const char *psep = "=";
409 char *key = apr_strtok(pair, psep, &plast);
410 if (key && *key) {
411 char *val = apr_strtok(NULL, sep, &plast);
412 if (!val || !*val) {
413 apr_table_unset(z->entries, key);
414 }
416 if (!strcmp(SESSION_EXPIRY, key)) {
417 z->expiry = (apr_time_t) apr_atoi64(val);
418 }
419 else {
420 apr_table_set(z->entries, key, val);
421 }
422 }
423 }
425 }
426 z->encoded = NULL;
427 return OK;
428
429}
430
449{
450
451 /* save all the sessions in all the requests */
452 request_rec *r = f->r->main;
453 if (!r) {
454 r = f->r;
455 }
456 while (r) {
457 session_rec *z = NULL;
459 &session_module);
460
461 /* load the session, or create one if necessary */
462 /* when unset or on error, z will be NULL */
464 if (!z || z->written) {
465 r = r->next;
466 continue;
467 }
468
469 /* if a header was specified, insert the new values from the header */
470 if (conf->header_set) {
471 const char *override = apr_table_get(r->err_headers_out, conf->header);
472 if (!override) {
473 override = apr_table_get(r->headers_out, conf->header);
474 }
475 if (override) {
478 z->encoded = override;
479 z->dirty = 1;
481 }
482 }
483
484 /* save away the session, and we're done */
485 /* when unset or on error, we've complained to the log */
487
488 r = r->next;
489 }
490
491 /* remove ourselves from the filter chain */
493
494 /* send the data up the stack */
495 return ap_pass_brigade(f->next, in);
496
497}
498
503{
504 ap_add_output_filter("MOD_SESSION_OUT", NULL, r, r->connection);
505}
506
519{
521 &session_module);
522
523 session_rec *z = NULL;
524
525 /* if an error occurs or no session has been configured, we ignore
526 * the broken session and allow it to be recreated from scratch on save
527 * if necessary.
528 */
530
531 if (conf->env) {
532 if (z) {
534 if (z->encoded) {
536 z->encoded = NULL;
537 }
538 }
539 apr_table_unset(r->headers_in, "Session");
540 }
541
542 return OK;
543
544}
545
546
548{
549 session_dir_conf *new =
551
552 new->includes = apr_array_make(p, 10, sizeof(const char **));
553 new->excludes = apr_array_make(p, 10, sizeof(const char **));
554
555 return (void *) new;
556}
557
558static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv)
559{
563
564 new->enabled = (add->enabled_set == 0) ? base->enabled : add->enabled;
565 new->enabled_set = add->enabled_set || base->enabled_set;
566 new->maxage = (add->maxage_set == 0) ? base->maxage : add->maxage;
567 new->maxage_set = add->maxage_set || base->maxage_set;
568 new->header = (add->header_set == 0) ? base->header : add->header;
569 new->header_set = add->header_set || base->header_set;
570 new->env = (add->env_set == 0) ? base->env : add->env;
571 new->env_set = add->env_set || base->env_set;
572 new->includes = apr_array_append(p, base->includes, add->includes);
573 new->excludes = apr_array_append(p, base->excludes, add->excludes);
574 new->expiry_update_time = (add->expiry_update_set == 0)
575 ? base->expiry_update_time
576 : add->expiry_update_time;
577 new->expiry_update_set = add->expiry_update_set || base->expiry_update_set;
578
579 return new;
580}
581
582
583static const char *
585{
586 session_dir_conf *conf = dconf;
587
588 conf->enabled = flag;
589 conf->enabled_set = 1;
590
591 return NULL;
592}
593
594static const char *
595 set_session_maxage(cmd_parms * parms, void *dconf, const char *arg)
596{
597 session_dir_conf *conf = dconf;
598
599 conf->maxage = atol(arg);
600 conf->maxage_set = 1;
601
602 return NULL;
603}
604
605static const char *
606 set_session_header(cmd_parms * parms, void *dconf, const char *arg)
607{
608 session_dir_conf *conf = dconf;
609
610 conf->header = arg;
611 conf->header_set = 1;
612
613 return NULL;
614}
615
616static const char *
617 set_session_env(cmd_parms * parms, void *dconf, int flag)
618{
619 session_dir_conf *conf = dconf;
620
621 conf->env = flag;
622 conf->env_set = 1;
623
624 return NULL;
625}
626
627static const char *add_session_include(cmd_parms * cmd, void *dconf, const char *f)
628{
629 session_dir_conf *conf = dconf;
630
631 const char **new = apr_array_push(conf->includes);
632 *new = f;
633
634 return NULL;
635}
636
637static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char *f)
638{
639 session_dir_conf *conf = dconf;
640
641 const char **new = apr_array_push(conf->excludes);
642 *new = f;
643
644 return NULL;
645}
646
647static const char *
648 set_session_expiry_update(cmd_parms * parms, void *dconf, const char *arg)
649{
650 session_dir_conf *conf = dconf;
651
652 conf->expiry_update_time = atoi(arg);
653 if (conf->expiry_update_time < 0) {
654 return "SessionExpiryUpdateInterval must be zero (disable) or a positive value";
655 }
657 conf->expiry_update_set = 1;
658
659 return NULL;
660}
661
662
663static const command_rec session_cmds[] =
664{
666 "on if a session should be maintained for these URLs"),
668 "length of time for which a session should be valid. Zero to disable"),
670 "output header, if present, whose contents will be injected into the session."),
672 "on if a session should be written to the CGI environment. Defaults to off"),
674 "URL prefixes to include in the session. Defaults to all URLs"),
676 "URL prefixes to exclude from the session. Defaults to no URLs"),
677 AP_INIT_TAKE1("SessionExpiryUpdateInterval", set_session_expiry_update, NULL, RSRC_CONF|OR_AUTHCFG,
678 "time interval for which a session's expiry time may change "
679 "without having to be rewritten. Zero to disable"),
680 {NULL}
681};
682
701
703{
705 create_session_dir_config, /* dir config creater */
706 merge_session_dir_config, /* dir merger --- default is to override */
707 NULL, /* server config */
708 NULL, /* merge server config */
709 session_cmds, /* command apr_table_t */
710 register_hooks /* register hooks */
711};
static int exclude
Definition abts.c:25
APR general purpose library routines.
APR Strings library.
apr_array_append(apr_pool_t *p, const apr_array_header_t *first, const apr_array_header_t *second)
Definition apr_tables.c:213
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
ap_conf_vector_t * base
request_rec * r
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
ap_filter_rec_t * ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
ap_filter_t * ap_add_output_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
void ap_remove_output_filter(ap_filter_t *f)
@ AP_FTYPE_CONTENT_SET
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_DEBUG
Definition http_log.h:71
void ap_hook_insert_error_filter(ap_HOOK_insert_error_filter_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
void ap_hook_fixups(ap_HOOK_fixups_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:87
void ap_hook_insert_filter(ap_HOOK_insert_filter_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:96
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define APR_EGENERAL
Definition apr_errno.h:313
unsigned int count
Definition apr_md5.h:152
apr_file_t * f
int apr_off_t * length
#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ns, link, ret, name, args_decl, args_use, decline)
Definition apr_hooks.h:267
#define APR_HOOK_LINK(name)
Definition apr_hooks.h:139
#define APR_HOOK_STRUCT(members)
Definition apr_hooks.h:135
#define APR_HOOK_REALLY_FIRST
Definition apr_hooks.h:299
#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ns, link, ret, name, args_decl, args_use, ok, decline)
Definition apr_hooks.h:222
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_HOOK_REALLY_LAST
Definition apr_hooks.h:307
#define APR_REGISTER_OPTIONAL_FN(name)
#define RSRC_CONF
#define OR_AUTHCFG
int ap_run_session_load(request_rec *r, session_rec **z)
Definition mod_session.c:35
int ap_run_session_save(request_rec *r, session_rec *z)
Definition mod_session.c:37
void ap_hook_session_encode(ap_HOOK_session_encode_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_session.c:39
int ap_run_session_decode(request_rec *r, session_rec *z)
Definition mod_session.c:41
void ap_hook_session_decode(ap_HOOK_session_decode_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_session.c:41
int ap_run_session_encode(request_rec *r, session_rec *z)
Definition mod_session.c:39
#define STANDARD20_MODULE_STUFF
char * ap_escape_urlencoded_buffer(char *c, const char *s)
Definition util.c:2102
int ap_unescape_urlencoded(char *query)
Definition util.c:1977
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
const char apr_int32_t flag
char * buffer
apr_vformatter_buff_t const char va_list ap
Definition apr_lib.h:176
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * sep
const char char ** last
apr_int32_t in
apr_cmdtype_e cmd
#define APR_USEC_PER_SEC
Definition apr_time.h:60
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_from_sec(sec)
Definition apr_time.h:78
Apache Logging library.
HTTP protocol handling.
Apache Request library.
apr_pool_t * p
Definition md_event.c:32
static int session_fixups(request_rec *r)
static const char * add_session_exclude(cmd_parms *cmd, void *dconf, const char *f)
static apr_status_t ap_session_load(request_rec *r, session_rec **z)
Definition mod_session.c:91
static const char * set_session_env(cmd_parms *parms, void *dconf, int flag)
static void * merge_session_dir_config(apr_pool_t *p, void *basev, void *addv)
static const char * set_session_enable(cmd_parms *parms, void *dconf, int flag)
static apr_status_t ap_session_get(request_rec *r, session_rec *z, const char *key, const char **value)
static int session_identity_encode(request_rec *r, session_rec *z)
static const command_rec session_cmds[]
static const char * set_session_expiry_update(cmd_parms *parms, void *dconf, const char *arg)
static apr_status_t ap_session_save(request_rec *r, session_rec *z)
static void session_insert_output_filter(request_rec *r)
#define SESSION_EXPIRY
Definition mod_session.c:25
static int identity_count(void *v, const char *key, const char *val)
static int session_identity_decode(request_rec *r, session_rec *z)
static void register_hooks(apr_pool_t *p)
static int identity_concat(void *v, const char *key, const char *val)
static const char * set_session_maxage(cmd_parms *parms, void *dconf, const char *arg)
static void * create_session_dir_config(apr_pool_t *p, char *dummy)
static apr_status_t session_output_filter(ap_filter_t *f, apr_bucket_brigade *in)
static const char * set_session_header(cmd_parms *parms, void *dconf, const char *arg)
static int session_included(request_rec *r, session_dir_conf *conf)
Definition mod_session.c:53
static const char * add_session_include(cmd_parms *cmd, void *dconf, const char *f)
static apr_status_t ap_session_set(request_rec *r, session_rec *z, const char *key, const char *value)
#define HTTP_SESSION
Definition mod_session.c:26
Session Module for Apache.
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
The representation of a filter chain.
A structure that represents the current request.
Definition httpd.h:845
char * uri
Definition httpd.h:1016
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
apr_table_t * err_headers_out
Definition httpd.h:981
apr_table_t * headers_in
Definition httpd.h:976
apr_table_t * subprocess_env
Definition httpd.h:983
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
request_rec * next
Definition httpd.h:854
apr_table_t * headers_out
Definition httpd.h:978
apr_time_t expiry_update_time
apr_array_header_t * includes
const char * header
apr_array_header_t * excludes
static apr_time_t now
Definition testtime.c:33
Apache filter library.