OSDN Git Service

* Added features:
[modchxj/mod_chxj.git] / src / chxj_cookie.c
1 /*
2  * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <time.h>
18
19 #include "mod_chxj.h"
20 #include "chxj_cookie.h"
21 #include "chxj_url_encode.h"
22 #include "chxj_apply_convrule.h"
23
24 #include "ap_release.h"
25
26 #include "apu.h"
27 #include "apr_dbm.h"
28 #include "apr_uuid.h"
29 #include "apr_md5.h"
30 #include "apr_base64.h"
31 #include "apr_uri.h"
32
33 static char *s_get_hostname_from_url(request_rec *r, char *value);
34 static char *s_cut_until_end_hostname(request_rec *, char *value);
35
36 /*
37  *
38  */
39 cookie_t *
40 chxj_save_cookie(request_rec *r)
41 {
42   int                 ii;
43   apr_array_header_t *headers;
44   apr_table_entry_t   *hentryp;
45   apr_status_t        retval;
46   apr_datum_t         dbmkey;
47   apr_datum_t         dbmval;
48   apr_dbm_t           *f;
49   apr_uuid_t          uuid;
50   char                *uuid_string;
51   unsigned char       *md5_value;
52   char                *old_cookie_id;
53   char                *store_string;
54   mod_chxj_config     *dconf;
55   chxjconvrule_entry  *entryp;
56   apr_file_t          *file;
57   apr_table_t         *new_cookie_table;
58   int                 has_cookie = 0;
59   cookie_t            *cookie;
60   cookie_t            *old_cookie;
61   char                *refer_string;
62   apr_uri_t           parsed_uri;
63   int                 has_refer;
64
65
66   DBG(r, "start chxj_save_cookie()");
67
68   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
69   cookie->cookie_id = NULL;
70
71   has_cookie = 0;
72   has_refer = 0;
73
74   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
75   entryp = chxj_apply_convrule(r, dconf->convrules);
76   if (! entryp) {
77     DBG(r, "end chxj_save_cookie() no pattern");
78     return NULL;
79   }
80   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
81     DBG(r, "end chxj_save_cookie() CookieOff");
82     return NULL;
83   }
84
85
86
87   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
88   hentryp = (apr_table_entry_t*)headers->elts;
89
90
91   new_cookie_table = apr_table_make(r->pool, 0);
92
93   for (ii=0; ii<headers->nelts; ii++) {
94     if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
95       DBG(r, "=====================================");
96       DBG(r, "cookie=[%s:%s]", hentryp[ii].key, hentryp[ii].val);
97
98       char *key;
99       char *val;
100       char *buff;
101
102
103       buff = apr_pstrdup(r->pool, hentryp[ii].val);
104       val = strchr(buff, '=');
105       if (val) {
106         key = buff;
107         *val++ = 0;
108         apr_table_add(new_cookie_table, key, val);
109         if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
110         
111       }
112
113       has_cookie = 1;
114       DBG(r, "=====================================");
115     }
116   }
117   apr_table_unset(r->headers_out, "Set-Cookie");
118
119   if (! has_refer) {
120     apr_uri_parse(r->pool,r->uri, &parsed_uri);
121     refer_string = apr_psprintf(r->pool, 
122                                 "%s://%s%s", 
123 #if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER == 2
124                                 ap_run_http_scheme(r),
125 #else
126                                 ap_run_http_method(r),
127 #endif
128                                 r->hostname,
129                                 apr_uri_unparse(r->pool,
130                                                 &parsed_uri,
131                                                 APR_URI_UNP_OMITSITEPART));
132     if (r->args && strlen(r->args)) {
133       refer_string = apr_pstrcat(r->pool, refer_string, "?", r->args, NULL);
134     }
135     apr_table_setn(new_cookie_table, REFERER_COOKIE_KEY, refer_string);
136     DBG(r, "ADD REFER[%s]", refer_string);
137     has_cookie++;
138   }
139
140
141   /*
142    * check input parameters
143    */
144   old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
145   if (old_cookie_id) {
146     old_cookie = chxj_load_cookie(r, old_cookie_id); 
147     if (old_cookie && old_cookie->cookie_headers) {
148       hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
149       for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
150         if (hentryp && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
151           apr_table_add(new_cookie_table, hentryp[ii].key, hentryp[ii].val);
152           has_cookie = 1;
153         }
154       }
155       chxj_delete_cookie(r,        old_cookie_id);
156       chxj_delete_cookie_expire(r, old_cookie_id);
157     }
158   }
159
160   if (! has_cookie) {
161     DBG(r, "no cookie");
162     DBG(r, "end chxj_save_cookie()");
163     return NULL;
164   }
165
166   file = chxj_cookie_db_lock(r);
167   if (! file) {
168     ERR(r, "mod_chxj: Can't lock cookie db");
169     DBG(r, "end chxj_save_cookie()");
170     return NULL;
171   }
172
173   DBG(r, " ");
174
175   retval = apr_dbm_open_ex(&f, 
176                            "default", 
177                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir), 
178                            APR_DBM_RWCREATE, 
179                            APR_OS_DEFAULT, 
180                            r->pool);
181   if (retval != APR_SUCCESS) {
182     DBG(r, "end chxj_save_cookie()");
183     ERR(r, "could not open dbm (type %s) auth file: %s", 
184             "default", 
185             chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
186     chxj_cookie_db_unlock(r, file);
187     return NULL;
188   }
189
190   apr_uuid_get(&uuid);
191   uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
192   memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
193   apr_uuid_format(uuid_string, &uuid);;
194
195   md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
196   memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
197
198   retval = apr_md5(md5_value, 
199                    (const char*)uuid_string, 
200                    (apr_size_t)APR_UUID_FORMATTED_LENGTH);
201   if (retval != APR_SUCCESS) {
202     ERR(r, "md5 failed.");
203     goto on_error;
204   }
205
206   cookie->cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
207   memset(cookie->cookie_id, 0, APR_MD5_DIGESTSIZE+1);
208   apr_base64_encode(cookie->cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
209
210   DBG(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
211
212   cookie->cookie_id = chxj_url_encode(r,cookie->cookie_id);
213
214   DBG(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
215
216   /*
217    * create key
218    */
219
220   dbmkey.dptr  = cookie->cookie_id;
221   dbmkey.dsize = strlen(cookie->cookie_id);
222
223   /*
224    * create val
225    */
226   cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
227   store_string = apr_palloc(r->pool, 1);
228   store_string[0] = 0;
229   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
230
231   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
232     if (ii) store_string = apr_pstrcat(r->pool,
233                                store_string, 
234                                "\n",
235                                NULL);
236
237     store_string = apr_pstrcat(r->pool, 
238                                store_string, 
239                                hentryp[ii].key, 
240                                "=",
241                                hentryp[ii].val, 
242                                NULL);
243   }
244   dbmval.dptr  = store_string;
245   dbmval.dsize = strlen(store_string);
246
247   /*
248    * store to db
249    */
250   retval = apr_dbm_store(f, dbmkey, dbmval);
251   if (retval != APR_SUCCESS) {
252     ERR(r, "Cannot store Cookie data to DBM file `%s'",
253             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
254     goto on_error;
255   }
256
257   chxj_save_cookie_expire(r, cookie);
258
259
260 on_error:
261   apr_dbm_close(f);
262   chxj_cookie_db_unlock(r, file);
263
264   DBG(r, "end chxj_save_cookie()");
265   return cookie;
266 }
267
268 /*
269  *
270  */
271 cookie_t *
272 chxj_update_cookie(request_rec *r, cookie_t *old_cookie)
273 {
274   int                 ii;
275   apr_array_header_t  *headers;
276   apr_table_entry_t   *hentryp;
277   apr_status_t        retval;
278   apr_datum_t         dbmkey;
279   apr_datum_t         dbmval;
280   apr_dbm_t           *f;
281   apr_uuid_t          uuid;
282   char                *uuid_string;
283   unsigned char       *md5_value;
284   char                *store_string;
285   mod_chxj_config     *dconf;
286   chxjconvrule_entry  *entryp;
287   apr_file_t          *file;
288   cookie_t            *cookie;
289
290
291   DBG(r, "start chxj_update_cookie()");
292   if (!old_cookie || ! old_cookie->cookie_headers || ! old_cookie->cookie_id) {
293     DBG(r, "end chxj_update_cookie() (old_cookie is null)");
294     return  NULL;
295   }
296
297   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
298   cookie->cookie_id = NULL;
299
300
301   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
302   entryp = chxj_apply_convrule(r, dconf->convrules);
303   if (! entryp) {
304     DBG(r, "end chxj_update_cookie() no pattern");
305     return NULL;
306   }
307   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
308     DBG(r, "end chxj_update_cookie() CookieOff");
309     return NULL;
310   }
311
312
313   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
314   hentryp = (apr_table_entry_t*)headers->elts;
315
316
317   chxj_delete_cookie(r,        old_cookie->cookie_id);
318   chxj_delete_cookie_expire(r, old_cookie->cookie_id);
319
320   file = chxj_cookie_db_lock(r);
321   if (! file) {
322     ERR(r, "mod_chxj: Can't lock cookie db");
323     return NULL;
324   }
325
326   DBG(r, " ");
327
328   retval = apr_dbm_open_ex(&f, 
329                            "default", 
330                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir), 
331                            APR_DBM_RWCREATE, 
332                            APR_OS_DEFAULT, 
333                            r->pool);
334   if (retval != APR_SUCCESS) {
335     ERR(r, "could not open dbm (type %s) auth file: %s", 
336             "default", 
337             chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
338     chxj_cookie_db_unlock(r, file);
339     return NULL;
340   }
341   DBG(r, " ");
342
343   apr_uuid_get(&uuid);
344   uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
345   memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
346   apr_uuid_format(uuid_string, &uuid);;
347
348   md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
349   memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
350
351   retval = apr_md5(md5_value, 
352                    (const char*)uuid_string, 
353                    (apr_size_t)APR_UUID_FORMATTED_LENGTH);
354   if (retval != APR_SUCCESS) {
355     ERR(r, "md5 failed.");
356     goto on_error;
357   }
358   DBG(r, " ");
359
360   cookie->cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
361   memset(cookie->cookie_id, 0, APR_MD5_DIGESTSIZE+1);
362   apr_base64_encode(cookie->cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
363
364   cookie->cookie_id = chxj_url_encode(r,cookie->cookie_id);
365
366   DBG(r, " ");
367
368   /*
369    * create key
370    */
371
372   dbmkey.dptr  = cookie->cookie_id;
373   dbmkey.dsize = strlen(cookie->cookie_id);
374
375   /*
376    * create val
377    */
378   cookie->cookie_headers = old_cookie->cookie_headers;
379   store_string = apr_palloc(r->pool, 1);
380   store_string[0] = 0;
381   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
382
383   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
384     if (ii) store_string = apr_pstrcat(r->pool,
385                                store_string, 
386                                "\n",
387                                NULL);
388
389     DBG(r, "OLD COOKIE VALUE=[%s][%s]", hentryp[ii].key, hentryp[ii].val);
390     store_string = apr_pstrcat(r->pool, 
391                                store_string, 
392                                hentryp[ii].key, 
393                                "=",
394                                hentryp[ii].val, 
395                                NULL);
396   }
397   dbmval.dptr  = store_string;
398   dbmval.dsize = strlen(store_string);
399
400   /*
401    * store to db
402    */
403   retval = apr_dbm_store(f, dbmkey, dbmval);
404   if (retval != APR_SUCCESS) {
405     ERR(r, "Cannot store Cookie data to DBM file `%s'",
406             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
407     goto on_error;
408   }
409
410   chxj_save_cookie_expire(r, cookie);
411
412   apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
413
414
415 on_error:
416   apr_dbm_close(f);
417   chxj_cookie_db_unlock(r, file);
418
419   DBG(r, "end   chxj_update_cookie()");
420   return cookie;
421 }
422
423
424 /*
425  *
426  * @return loaded data.
427  */
428 cookie_t *
429 chxj_load_cookie(request_rec *r, char *cookie_id)
430 {
431   apr_status_t            retval;
432   apr_datum_t             dbmkey;
433   apr_datum_t             dbmval;
434   apr_dbm_t               *f;
435   mod_chxj_config         *dconf;
436   chxjconvrule_entry      *entryp;
437   apr_file_t              *file;
438   cookie_t                *cookie;
439   apr_table_t             *load_cookie_table;
440   char                    *load_string;
441   char                    *pstat;
442   char                    *key;
443   char                    *val;
444   char                    *pair;
445
446   DBG(r, "========================================================");
447   DBG(r, "========================================================");
448   DBG(r, "========================================================");
449   DBG(r, "========================================================");
450   DBG(r, "start chxj_load_cookie() cookie_id=[%s]", cookie_id);
451   chxj_cookie_expire_gc(r);
452
453   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
454   cookie->cookie_headers = NULL;
455   cookie->cookie_id = apr_pstrdup(r->pool, cookie_id);
456
457   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
458   entryp = chxj_apply_convrule(r, dconf->convrules);
459   if (! entryp) {
460     DBG(r, "end chxj_load_cookie() no pattern");
461     goto on_error0;
462   }
463   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
464     DBG(r, "end chxj_load_cookie() CookieOff");
465     goto on_error0;
466   }
467
468
469   file = chxj_cookie_db_lock(r);
470   if (! file) {
471     ERR(r, "mod_chxj: Can't lock cookie db");
472     goto on_error0;
473   }
474
475   retval = apr_dbm_open_ex(&f, 
476                            "default", 
477                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
478                            APR_DBM_RWCREATE, 
479                            APR_OS_DEFAULT, 
480                            r->pool);
481   if (retval != APR_SUCCESS) {
482     ERR(r, 
483         "could not open dbm (type %s) auth file: %s", 
484         "default", 
485         chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
486     goto on_error1;
487   }
488
489   /*
490    * create key
491    */
492   dbmkey.dptr  = apr_pstrdup(r->pool, cookie->cookie_id);
493   dbmkey.dsize = strlen(dbmkey.dptr);
494
495   if (apr_dbm_exists(f, dbmkey)) {
496   
497     retval = apr_dbm_fetch(f, dbmkey, &dbmval);
498     if (retval != APR_SUCCESS) {
499       ERR(r, 
500            "could not fetch dbm (type %s) auth file: %s", "default", 
501            chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
502       goto on_error2;
503     }
504     load_cookie_table = apr_table_make(r->pool, 0);
505     load_string = apr_palloc(r->pool, dbmval.dsize+1);
506
507     memset(load_string, 0, dbmval.dsize+1);
508     memcpy(load_string, dbmval.dptr, dbmval.dsize);
509
510     char *header_cookie = apr_palloc(r->pool, 1);
511
512     header_cookie[0] = 0;
513     for (;;) {
514       char *tmp_sem;
515       pair = apr_strtok(load_string, "\n", &pstat);  
516       load_string = NULL;
517       if (!pair) break;
518
519       DBG(r, "Cookie:[%s]", pair);
520       char *tmp_pair;
521
522       tmp_pair = apr_pstrdup(r->pool, pair);
523       val = strchr(tmp_pair, '=');
524       if (val) {
525         key = tmp_pair;
526         *val++ = 0;
527         apr_table_add(load_cookie_table, key, val);
528       }
529       tmp_sem = strchr(pair, ';'); 
530       if (tmp_sem)
531         *tmp_sem = '\0';
532
533       if (strlen(header_cookie)) 
534         header_cookie = apr_pstrcat(r->pool, header_cookie, ";", NULL);
535
536       header_cookie = apr_pstrcat(r->pool, header_cookie, pair, NULL);
537     }
538     if (strlen(header_cookie))
539       apr_table_add(r->headers_in, "Cookie", header_cookie);
540   
541     cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
542
543     if (apr_table_get(r->headers_in, "referer") == NULL) {
544       apr_table_setn(r->headers_in, 
545                      "referer",
546                      apr_table_get(load_cookie_table, REFERER_COOKIE_KEY));
547     }
548   
549     /*
550      * save cookie_id to request header.
551      */
552     apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
553   }
554   apr_dbm_close(f);
555   chxj_cookie_db_unlock(r, file);
556   DBG(r, "end   chxj_load_cookie()");
557   DBG(r, "========================================================");
558   DBG(r, "========================================================");
559   DBG(r, "========================================================");
560   DBG(r, "========================================================");
561
562   return cookie;
563
564
565 on_error2:
566   apr_dbm_close(f);
567
568 on_error1:
569   chxj_cookie_db_unlock(r, file);
570
571 on_error0:
572
573   DBG(r, "end   chxj_load_cookie()");
574   DBG(r, "========================================================");
575   DBG(r, "========================================================");
576   DBG(r, "========================================================");
577   DBG(r, "========================================================");
578   return NULL;
579 }
580
581
582 char *
583 chxj_add_cookie_parameter(request_rec *r, char *value, cookie_t *cookie)
584 {
585   char *qs;
586   char *dst;
587
588   DBG(r, "start chxj_add_cookie_parameter() cookie_id=[%s]", (cookie) ? cookie->cookie_id : NULL);
589
590   dst = apr_pstrdup(r->pool, value);
591
592   if (!cookie)
593     goto on_error;
594
595   if (!cookie->cookie_id)
596     goto on_error;
597
598   if (chxj_cookie_check_host(r, value) != 0) {
599     DBG(r, "end chxj_add_cookie_parameter()(check host)");
600     goto on_error;
601   }
602
603   qs = strchr(dst, '?');
604   if (qs) {
605     dst = apr_psprintf(r->pool, "%s&%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
606   }
607   else {
608     dst = apr_psprintf(r->pool, "%s?%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
609   }
610
611   DBG(r, "end   chxj_add_cookie_parameter() dst=[%s]", dst);
612
613   return dst;
614
615 on_error:
616   DBG(r, "end   chxj_add_cookie_parameter() (on_error)");
617   return dst;
618 }
619
620
621 int
622 chxj_cookie_check_host(request_rec *r, char *value) 
623 {
624   char *hostnm;
625
626   DBG(r, "hostname=[%s]", r->hostname);
627
628   hostnm = s_get_hostname_from_url(r, value);
629   if (hostnm) {
630     if (strcasecmp(hostnm, r->hostname) == 0)
631       return 0;
632     else
633       return 1;
634   }
635   return 0;
636 }
637
638
639 static char *
640 s_get_hostname_from_url(request_rec *r, char *value)
641 {
642   if (!value) 
643     return NULL; 
644
645   if (strncasecmp(value, "http://",  7) == 0 )
646     return s_cut_until_end_hostname(r, &value[7]);
647
648   if (strncasecmp(value, "https://", 8) == 0)
649     return s_cut_until_end_hostname(r, &value[8]);
650
651   return NULL;
652 }
653
654
655 static char *
656 s_cut_until_end_hostname(request_rec *r, char *value)
657 {
658   char *sp;
659   char *hostnm;
660
661   hostnm = sp = apr_pstrdup(r->pool, value);
662   for (;*sp; sp++) {
663     if (*sp == '/'|| *sp == '?') {
664       *sp = '\0';
665       break;
666     }
667   }
668   return hostnm;
669 }
670
671
672 apr_file_t *
673 chxj_cookie_db_lock(request_rec *r)
674 {
675   apr_file_t       *file;
676   apr_status_t     rv;
677   mod_chxj_config  *dconf;
678
679   dconf = (mod_chxj_config *)ap_get_module_config(r->per_dir_config, &chxj_module);
680
681   rv = apr_file_open(&file, 
682                      chxj_cookie_db_lock_name_create(r, dconf->cookie_db_dir),
683                      APR_CREATE|APR_WRITE, 
684                      APR_OS_DEFAULT, 
685                      r->pool);
686   if (rv != APR_SUCCESS) {
687     ERR(r, "cookie lock file open failed.");
688     return NULL;
689   }
690
691   rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
692   if (rv != APR_SUCCESS) {
693     ERR(r, "cookie lock file open failed.");
694     apr_file_close(file);
695     return NULL;
696   }
697
698   return file;
699 }
700
701
702 void
703 chxj_cookie_db_unlock(request_rec *r, apr_file_t *file)
704 {
705   apr_status_t rv;
706
707   rv = apr_file_unlock(file);
708   if (rv != APR_SUCCESS) {
709     ERR(r, "cookie lock file open failed.");
710     return;
711   }
712
713   apr_file_close(file);
714 }
715
716
717 void
718 chxj_delete_cookie(request_rec *r, char *cookie_id)
719 {
720   apr_status_t      retval;
721   apr_datum_t       dbmkey;
722   apr_dbm_t         *f;
723   apr_file_t        *file;
724   mod_chxj_config   *dconf;
725
726   DBG(r, "start chxj_delete_cookie()");
727
728   file = chxj_cookie_db_lock(r);
729   if (! file) {
730     ERR(r, "mod_chxj: Can't lock cookie db");
731     goto on_error0;
732   }
733   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
734
735   retval = apr_dbm_open_ex(&f,
736                            "default",
737                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
738                            APR_DBM_RWCREATE,
739                            APR_OS_DEFAULT,
740                            r->pool);
741   if (retval != APR_SUCCESS) {
742     ERR(r, 
743         "could not open dbm (type %s) auth file: %s", 
744         "default", 
745         chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
746     goto on_error1;
747   }
748
749   /*
750    * create key
751    */
752   dbmkey.dptr  = apr_pstrdup(r->pool, cookie_id);
753   dbmkey.dsize = strlen(dbmkey.dptr);
754   if (apr_dbm_exists(f, dbmkey)) {
755     apr_dbm_delete(f, dbmkey);
756   }
757   apr_dbm_close(f);
758   chxj_cookie_db_unlock(r, file);
759
760   DBG(r, "end   chxj_delete_cookie()");
761
762   return;
763
764 on_error1:
765   chxj_cookie_db_unlock(r, file);
766
767 on_error0:
768   return;
769
770 }
771
772
773 char *
774 chxj_cookie_db_name_create(request_rec *r, const char *dir)
775 {
776   char *dst;
777
778   if (!dir) {
779     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
780   }
781   else {
782     dst = apr_pstrdup(r->pool, dir);
783   }
784
785   if (dst[strlen(dst)-1] != '/') {
786     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_NAME, NULL);
787   }
788   else {
789     dst = apr_pstrcat(r->pool, dst, COOKIE_DB_NAME, NULL);
790   }
791
792   return dst;
793 }
794
795
796 char *
797 chxj_cookie_db_lock_name_create(request_rec *r, const char *dir)
798 {
799   char *dst;
800   DBG(r, "start  chxj_cookie_db_lock_name_create()");
801
802   if (!dir) {
803     DBG(r, " ");
804     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
805     DBG(r, " ");
806   }
807   else {
808     dst = apr_pstrdup(r->pool, dir);
809     DBG(r, " ");
810   }
811   DBG(r, "dst[strlen(dst)-1]=[%c]", dst[strlen(dst)-1]);
812   if (dst[strlen(dst)-1] != '/') {
813     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_LOCK_NAME, NULL);
814   }
815   else {
816     dst = apr_pstrcat(r->pool, dst, COOKIE_DB_LOCK_NAME, NULL);
817   }
818   DBG(r, "end  chxj_cookie_db_lock_name_create()");
819   return dst;
820 }
821 /*
822  *
823  */
824 void
825 chxj_save_cookie_expire(request_rec *r, cookie_t *cookie)
826 {
827   apr_status_t            retval;
828   apr_datum_t             dbmkey;
829   apr_datum_t             dbmval;
830   apr_dbm_t               *f;
831   apr_file_t              *file;
832   mod_chxj_config         *dconf;
833   char                    *store_string;
834
835   DBG(r, "start chxj_save_cookie_expire()");
836   if (!cookie) {
837     DBG(r, "cookie is NULL");
838     return;
839   }
840
841   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
842   if (!dconf) {
843     DBG(r, "dconf is NULL");
844     return;
845   }
846
847   file = chxj_cookie_expire_db_lock(r);
848   if (! file) {
849     ERR(r, "mod_chxj: Can't lock cookie db");
850     return;
851   }
852
853   DBG(r, " ");
854
855   retval = apr_dbm_open_ex(&f, 
856                            "default", 
857                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir), 
858                            APR_DBM_RWCREATE, 
859                            APR_OS_DEFAULT, 
860                            r->pool);
861   if (retval != APR_SUCCESS) {
862     ERR(r, "could not open dbm (type %s) auth file: %s", 
863            "default", 
864             chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
865     chxj_cookie_expire_db_unlock(r, file);
866     return;
867   }
868   /*
869    * create key
870    */
871
872   dbmkey.dptr  = cookie->cookie_id;
873   dbmkey.dsize = strlen(cookie->cookie_id);
874
875   /*
876    * create val
877    */
878   
879   store_string = apr_psprintf(r->pool, "%d", (int)time(NULL));
880   dbmval.dptr  = store_string;
881   dbmval.dsize = strlen(store_string);
882
883   /*
884    * store to db
885    */
886   retval = apr_dbm_store(f, dbmkey, dbmval);
887   if (retval != APR_SUCCESS) {
888     ERR(r, "Cannot store Cookie data to DBM file `%s'",
889             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
890   }
891
892
893   apr_dbm_close(f);
894   chxj_cookie_expire_db_unlock(r, file);
895
896   DBG(r, "end   chxj_save_cookie_expire()");
897 }
898
899
900 char *
901 chxj_cookie_expire_db_name_create(request_rec *r, const char *dir)
902 {
903   char *dst;
904
905   if (!dir) {
906     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
907   }
908   else {
909     dst = apr_pstrdup(r->pool, dir);
910   }
911
912   if (dst[strlen(dst)-1] != '/') {
913     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_NAME, NULL);
914   }
915   else {
916     dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_NAME, NULL);
917   }
918
919   return dst;
920 }
921
922
923 char *
924 chxj_cookie_expire_db_lock_name_create(request_rec *r, const char *dir)
925 {
926   char *dst;
927
928   if (!dir) {
929     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
930   }
931   else {
932     dst = apr_pstrdup(r->pool, dir);
933   }
934   if (dst[strlen(dst)-1] != '/') {
935     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
936   }
937   else {
938     dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
939   }
940
941   return dst;
942 }
943
944
945 apr_file_t *
946 chxj_cookie_expire_db_lock(request_rec *r)
947 {
948   apr_file_t       *file;
949   apr_status_t     rv;
950   mod_chxj_config  *dconf;
951
952   dconf = (mod_chxj_config *)ap_get_module_config(r->per_dir_config, &chxj_module);
953
954   rv = apr_file_open(&file, 
955                      chxj_cookie_expire_db_lock_name_create(r, dconf->cookie_db_dir),
956                      APR_CREATE|APR_WRITE, 
957                      APR_OS_DEFAULT, 
958                      r->pool);
959   if (rv != APR_SUCCESS) {
960     ERR(r, "cookie lock file open failed.");
961     return NULL;
962   }
963
964   rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
965   if (rv != APR_SUCCESS) {
966     ERR(r, "cookie lock file open failed.");
967     apr_file_close(file);
968     return NULL;
969   }
970
971   return file;
972 }
973
974
975 void
976 chxj_cookie_expire_db_unlock(request_rec *r, apr_file_t *file)
977 {
978   apr_status_t rv;
979
980   rv = apr_file_unlock(file);
981   if (rv != APR_SUCCESS) {
982     ERR(r, "cookie lock file open failed.");
983     return;
984   }
985
986   apr_file_close(file);
987 }
988
989 void
990 chxj_delete_cookie_expire(request_rec *r, char *cookie_id)
991 {
992   apr_status_t      retval;
993   apr_datum_t       dbmkey;
994   apr_dbm_t         *f;
995   apr_file_t        *file;
996   mod_chxj_config   *dconf;
997
998   DBG(r, "start chxj_delete_cookie_expire()");
999
1000   file = chxj_cookie_expire_db_lock(r);
1001   if (! file) {
1002     ERR(r, "mod_chxj: Can't lock cookie db");
1003     goto on_error0;
1004   }
1005   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
1006
1007   retval = apr_dbm_open_ex(&f,
1008                            "default",
1009                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
1010                            APR_DBM_RWCREATE,
1011                            APR_OS_DEFAULT,
1012                            r->pool);
1013   if (retval != APR_SUCCESS) {
1014     ERR(r, 
1015         "could not open dbm (type %s) auth file: %s", 
1016         "default", 
1017         chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
1018     goto on_error1;
1019   }
1020
1021   /*
1022    * create key
1023    */
1024   dbmkey.dptr  = apr_pstrdup(r->pool, cookie_id);
1025   dbmkey.dsize = strlen(dbmkey.dptr);
1026   if (apr_dbm_exists(f, dbmkey)) {
1027     apr_dbm_delete(f, dbmkey);
1028   }
1029   apr_dbm_close(f);
1030   chxj_cookie_expire_db_unlock(r, file);
1031
1032   DBG(r, "end   chxj_delete_cookie_expire()");
1033
1034   return;
1035
1036 on_error1:
1037   chxj_cookie_expire_db_unlock(r, file);
1038
1039 on_error0:
1040   return;
1041
1042 }
1043
1044
1045 void
1046 chxj_cookie_expire_gc(request_rec *r)
1047 {
1048   apr_status_t      retval;
1049   apr_datum_t       dbmkey;
1050   apr_datum_t       dbmval;
1051   apr_dbm_t         *f;
1052   apr_file_t        *file;
1053   mod_chxj_config   *dconf;
1054   time_t            now_time;
1055
1056   DBG(r, "start chxj_cookie_expire_gc()");
1057
1058   file = chxj_cookie_expire_db_lock(r);
1059   if (! file) {
1060     ERR(r, "mod_chxj: Can't lock cookie db");
1061     goto on_error0;
1062   }
1063   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
1064
1065   retval = apr_dbm_open_ex(&f,
1066                            "default",
1067                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
1068                            APR_DBM_RWCREATE,
1069                            APR_OS_DEFAULT,
1070                            r->pool);
1071   if (retval != APR_SUCCESS) {
1072     ERR(r, 
1073         "could not open dbm (type %s) auth file: %s", 
1074         "default", 
1075         chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
1076     goto on_error1;
1077   }
1078
1079   /*
1080    * create key
1081    */
1082   memset(&dbmkey, 0, sizeof(apr_datum_t));
1083
1084   now_time = time(NULL);
1085
1086   retval = apr_dbm_firstkey(f, &dbmkey);
1087   if (retval == APR_SUCCESS) {
1088     DBG(r, "firstkey=[%.*s]", (int)dbmkey.dsize, dbmkey.dptr);
1089     do {
1090       char *tmp;
1091       char *old_cookie_id;
1092       int   val_time;
1093       int   cmp_time;
1094
1095       retval = apr_dbm_fetch(f, dbmkey, &dbmval);
1096       if (retval != APR_SUCCESS) {
1097         break;
1098       }
1099       tmp = apr_palloc(r->pool, dbmval.dsize+1);
1100       memset(tmp, 0, dbmval.dsize+1);
1101       memcpy(tmp, dbmval.dptr, dbmval.dsize);
1102
1103
1104       val_time = atoi(tmp);
1105
1106       if (dconf->cookie_timeout == 0)
1107         cmp_time = now_time - DEFAULT_COOKIE_TIMEOUT;
1108       else
1109         cmp_time = now_time - dconf->cookie_timeout;
1110
1111       DBG(r, "dconf->cookie_timeout=[%d]", (int)dconf->cookie_timeout);
1112       DBG(r, "key=[%.*s] cmp_time=[%d] val_time=[%d]", (int)dbmkey.dsize, dbmkey.dptr, cmp_time, val_time);
1113       if (cmp_time >= val_time) {
1114         apr_dbm_delete(f, dbmkey);
1115
1116         old_cookie_id = apr_palloc(r->pool, dbmkey.dsize+1);
1117         memset(old_cookie_id, 0, dbmkey.dsize+1);
1118         memcpy(old_cookie_id, dbmkey.dptr, dbmkey.dsize);
1119
1120         chxj_delete_cookie(r,old_cookie_id);
1121         DBG(r, "detect timeout cookie [%s]", old_cookie_id);
1122       }
1123
1124       retval = apr_dbm_nextkey(f, &dbmkey);
1125     } while(retval == APR_SUCCESS && dbmkey.dptr != NULL);
1126   }
1127
1128   apr_dbm_close(f);
1129   chxj_cookie_expire_db_unlock(r, file);
1130
1131   DBG(r, "end   chxj_cookie_expire_gc()");
1132
1133   return;
1134
1135 on_error1:
1136   chxj_cookie_expire_db_unlock(r, file);
1137
1138 on_error0:
1139   return;
1140
1141 }
1142 /*
1143  * vim:ts=2 et
1144  */