OSDN Git Service

* add url encoding and charactor encoding for hdml and xhtml.
[modchxj/mod_chxj.git] / src / chxj_cookie.c
1 /*
2  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
3  * Copyright (C) 2005 Atsushi Konno 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 "apu.h"
25 #include "apr_dbm.h"
26 #include "apr_uuid.h"
27 #include "apr_md5.h"
28 #include "apr_base64.h"
29
30 static char* s_get_hostname_from_url(request_rec* r, char* value);
31 static char* s_cut_until_end_hostname(request_rec*, char* value);
32
33 /*
34  *
35  */
36 cookie_t*
37 chxj_save_cookie(request_rec* r)
38 {
39   int                 ii;
40   apr_array_header_t* headers;
41   apr_table_entry_t*  hentryp;
42   apr_status_t        retval;
43   apr_datum_t         dbmkey;
44   apr_datum_t         dbmval;
45   apr_dbm_t*          f;
46   apr_uuid_t          uuid;
47   char*               uuid_string;
48   unsigned char*      md5_value;
49   char*               old_cookie_id;
50   char*               store_string;
51   mod_chxj_config*    dconf;
52   chxjconvrule_entry* entryp;
53   apr_file_t*         file;
54   apr_table_t*        new_cookie_table;
55   int                 has_cookie = 0;
56   cookie_t*           cookie;
57   cookie_t*           old_cookie;
58
59
60   DBG(r, "start chxj_save_cookie()");
61
62   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
63   cookie->cookie_id = NULL;
64
65   has_cookie = 0;
66
67   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
68   entryp = chxj_apply_convrule(r, dconf->convrules);
69   if (! entryp) {
70     DBG(r, "end chxj_save_cookie() no pattern");
71     return NULL;
72   }
73   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
74     DBG(r, "end chxj_save_cookie() CookieOff");
75     return NULL;
76   }
77
78
79   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
80   hentryp = (apr_table_entry_t*)headers->elts;
81
82
83   new_cookie_table = apr_table_make(r->pool, 0);
84
85   for (ii=0; ii<headers->nelts; ii++) {
86     if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
87       DBG(r, "=====================================");
88       DBG2(r, "cookie=[%s:%s]", hentryp[ii].key, hentryp[ii].val);
89
90       char* key;
91       char* val;
92       char* buff;
93
94       buff = apr_pstrdup(r->pool, hentryp[ii].val);
95       val = strchr(buff, '=');
96       if (val) {
97         key = buff;
98         *val++ = 0;
99         apr_table_add(new_cookie_table, key, val);
100       }
101
102       has_cookie = 1;
103       DBG(r, "=====================================");
104     }
105   }
106
107   /*
108    * check input parameters
109    */
110   old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
111   if (old_cookie_id) {
112     old_cookie = chxj_load_cookie(r, old_cookie_id); 
113     if (old_cookie && old_cookie->cookie_headers) {
114       hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
115       for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
116         if (hentryp[ii].key && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
117           apr_table_setn(new_cookie_table, hentryp[ii].key, hentryp[ii].val);
118           has_cookie = 1;
119         }
120       }
121       chxj_delete_cookie(r,        old_cookie_id);
122       chxj_delete_cookie_expire(r, old_cookie_id);
123     }
124   }
125
126   if (! has_cookie) {
127     DBG(r, "no cookie");
128     return NULL;
129   }
130
131   file = chxj_cookie_db_lock(r);
132   if (! file) {
133     ERR(r, "mod_chxj: Can't lock cookie db");
134     return NULL;
135   }
136
137   DBG(r, " ");
138
139   retval = apr_dbm_open_ex(&f, 
140                            "default", 
141                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir), 
142                            APR_DBM_RWCREATE, 
143                            APR_OS_DEFAULT, 
144                            r->pool);
145   if (retval != APR_SUCCESS) {
146     ERR2(r, "could not open dbm (type %s) auth file: %s", 
147             "default", 
148             chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
149     chxj_cookie_db_unlock(r, file);
150     return NULL;
151   }
152
153   apr_uuid_get(&uuid);
154   uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
155   memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
156   apr_uuid_format(uuid_string, &uuid);;
157
158   md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
159   memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
160
161   retval = apr_md5(md5_value, 
162                    (const char*)uuid_string, 
163                    (apr_size_t)APR_UUID_FORMATTED_LENGTH);
164   if (retval != APR_SUCCESS) {
165     ERR(r, "md5 failed.");
166     goto on_error;
167   }
168
169   cookie->cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
170   memset(cookie->cookie_id, 0, APR_MD5_DIGESTSIZE+1);
171   apr_base64_encode(cookie->cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
172
173   DBG1(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
174
175   cookie->cookie_id = chxj_url_encode(r,cookie->cookie_id);
176
177   DBG1(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
178
179   /*
180    * create key
181    */
182
183   dbmkey.dptr  = cookie->cookie_id;
184   dbmkey.dsize = strlen(cookie->cookie_id);
185
186   /*
187    * create val
188    */
189   cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
190   store_string = apr_palloc(r->pool, 1);
191   store_string[0] = 0;
192   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
193
194   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
195     if (ii) store_string = apr_pstrcat(r->pool,
196                                store_string, 
197                                "\n",
198                                NULL);
199
200     store_string = apr_pstrcat(r->pool, 
201                                store_string, 
202                                hentryp[ii].key, 
203                                "=",
204                                hentryp[ii].val, 
205                                NULL);
206   }
207   dbmval.dptr  = store_string;
208   dbmval.dsize = strlen(store_string);
209
210   /*
211    * store to db
212    */
213   retval = apr_dbm_store(f, dbmkey, dbmval);
214   if (retval != APR_SUCCESS) {
215     ERR1(r, "Cannot store Cookie data to DBM file `%s'",
216             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
217     goto on_error;
218   }
219
220   chxj_save_cookie_expire(r, cookie);
221
222
223 on_error:
224   apr_dbm_close(f);
225   chxj_cookie_db_unlock(r, file);
226
227   DBG(r, "end   chxj_save_cookie()");
228   return cookie;
229 }
230
231
232 /*
233  *
234  * @return loaded data.
235  */
236 cookie_t*
237 chxj_load_cookie(request_rec* r, char* cookie_id)
238 {
239   apr_status_t            retval;
240   apr_datum_t             dbmkey;
241   apr_datum_t             dbmval;
242   apr_dbm_t*              f;
243   mod_chxj_config*        dconf;
244   chxjconvrule_entry*     entryp;
245   apr_file_t*             file;
246   cookie_t*               cookie;
247   apr_table_t*            load_cookie_table;
248   char*                   load_string;
249   char*                   pstat;
250   char*                   key;
251   char*                   val;
252   char*                   pair;
253
254   DBG1(r, "start chxj_load_cookie() cookie_id=[%s]", cookie_id);
255   chxj_cookie_expire_gc(r);
256
257   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
258   cookie->cookie_headers = NULL;
259   cookie->cookie_id = apr_pstrdup(r->pool, cookie_id);
260
261   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
262   entryp = chxj_apply_convrule(r, dconf->convrules);
263   if (! entryp) {
264     DBG(r, "end chxj_load_cookie() no pattern");
265     goto on_error0;
266   }
267   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
268     DBG(r, "end chxj_load_cookie() CookieOff");
269     goto on_error0;
270   }
271
272
273   file = chxj_cookie_db_lock(r);
274   if (! file) {
275     ERR(r, "mod_chxj: Can't lock cookie db");
276     goto on_error0;
277   }
278
279   retval = apr_dbm_open_ex(&f, 
280                            "default", 
281                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
282                            APR_DBM_RWCREATE, 
283                            APR_OS_DEFAULT, 
284                            r->pool);
285   if (retval != APR_SUCCESS) {
286     ERR2(r, 
287          "could not open dbm (type %s) auth file: %s", 
288          "default", 
289          chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
290     goto on_error1;
291   }
292
293   /*
294    * create key
295    */
296   dbmkey.dptr  = apr_pstrdup(r->pool, cookie->cookie_id);
297   dbmkey.dsize = strlen(dbmkey.dptr);
298   if (apr_dbm_exists(f, dbmkey)) {
299   
300     retval = apr_dbm_fetch(f, dbmkey, &dbmval);
301     if (retval != APR_SUCCESS) {
302       ERR2(r, 
303            "could not fetch dbm (type %s) auth file: %s", "default", 
304            chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
305       goto on_error2;
306     }
307     load_cookie_table = apr_table_make(r->pool, 0);
308     load_string = apr_palloc(r->pool, dbmval.dsize+1);
309
310     memset(load_string, 0, dbmval.dsize+1);
311     memcpy(load_string, dbmval.dptr, dbmval.dsize);
312     for (;;) {
313       char* tmp_sem;
314       pair = apr_strtok(load_string, "\n", &pstat);  
315       load_string = NULL;
316       if (!pair) break;
317
318       DBG1(r, "Cookie:[%s]", pair);
319       char* tmp_pair;
320
321       tmp_pair = apr_pstrdup(r->pool, pair);
322       val = strchr(tmp_pair, '=');
323       if (val) {
324         key = tmp_pair;
325         *val++ = 0;
326         apr_table_add(load_cookie_table, key, val);
327       }
328       tmp_sem = strchr(pair, ';'); 
329       if (tmp_sem)
330         *tmp_sem = '\0';
331
332       apr_table_setn(r->headers_in, "Cookie", pair);
333     }
334   
335     cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
336   
337     /*
338      * save cookie_id to request header.
339      */
340     apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
341   }
342   apr_dbm_close(f);
343   chxj_cookie_db_unlock(r, file);
344   DBG(r, "end   chxj_load_cookie()");
345
346   return cookie;
347
348
349 on_error2:
350   apr_dbm_close(f);
351
352 on_error1:
353   chxj_cookie_db_unlock(r, file);
354
355 on_error0:
356
357   DBG(r, "end   chxj_load_cookie()");
358   return NULL;
359 }
360
361
362 char*
363 chxj_add_cookie_parameter(request_rec* r, char* value, cookie_t* cookie)
364 {
365   char* qs;
366   char* dst;
367
368   DBG1(r, "start chxj_add_cookie_parameter() cookie_id=[%s]", (cookie) ? cookie->cookie_id : NULL);
369
370   dst = value;
371
372   if (!cookie)
373     goto on_error;
374
375   if (!cookie->cookie_id)
376     goto on_error;
377
378   if (chxj_cookie_check_host(r, value) != 0) {
379     DBG(r, "end chxj_add_cookie_parameter()(check host)");
380     goto on_error;
381   }
382
383
384   qs = strchr(dst, '?');
385   if (qs) {
386     dst = apr_psprintf(r->pool, "%s&%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
387   }
388   else {
389     dst = apr_psprintf(r->pool, "%s?%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
390   }
391
392   DBG1(r, "end   chxj_add_cookie_parameter() dst=[%s]", dst);
393
394   return dst;
395
396 on_error:
397   DBG(r, "end   chxj_add_cookie_parameter() (on_error)");
398   return dst;
399 }
400
401
402 int
403 chxj_cookie_check_host(request_rec* r, char* value) 
404 {
405   char* hostnm;
406
407   DBG1(r, "hostname=[%s]", r->hostname);
408
409   hostnm = s_get_hostname_from_url(r, value);
410   if (hostnm) {
411     if (strcasecmp(hostnm, r->hostname) == 0)
412       return 0;
413     else
414       return 1;
415   }
416   return 0;
417 }
418
419
420 static char*
421 s_get_hostname_from_url(request_rec* r, char* value)
422 {
423   if (!value) 
424     return NULL; 
425
426   if (strncasecmp(value, "http://",  7) == 0 )
427     return s_cut_until_end_hostname(r, &value[7]);
428
429   if (strncasecmp(value, "https://", 8) == 0)
430     return s_cut_until_end_hostname(r, &value[8]);
431
432   return NULL;
433 }
434
435
436 static char* 
437 s_cut_until_end_hostname(request_rec* r, char* value)
438 {
439   char* sp;
440   char* hostnm;
441
442   hostnm = sp = apr_pstrdup(r->pool, value);
443   for (;*sp; sp++) {
444     if (*sp == '/'|| *sp == '?') {
445       *sp = '\0';
446       break;
447     }
448   }
449   return hostnm;
450 }
451
452
453 apr_file_t*
454 chxj_cookie_db_lock(request_rec* r)
455 {
456   apr_file_t*      file;
457   apr_status_t     rv;
458   mod_chxj_config* dconf;
459
460   dconf = (mod_chxj_config*)ap_get_module_config(r->per_dir_config, &chxj_module);
461
462   rv = apr_file_open(&file, 
463                      chxj_cookie_db_lock_name_create(r, dconf->cookie_db_dir),
464                      APR_CREATE|APR_WRITE, 
465                      APR_OS_DEFAULT, 
466                      r->pool);
467   if (rv != APR_SUCCESS) {
468     ERR(r, "cookie lock file open failed.");
469     return NULL;
470   }
471
472   rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
473   if (rv != APR_SUCCESS) {
474     ERR(r, "cookie lock file open failed.");
475     apr_file_close(file);
476     return NULL;
477   }
478
479   return file;
480 }
481
482
483 void
484 chxj_cookie_db_unlock(request_rec* r, apr_file_t* file)
485 {
486   apr_status_t rv;
487
488   rv = apr_file_unlock(file);
489   if (rv != APR_SUCCESS) {
490     ERR(r, "cookie lock file open failed.");
491     return;
492   }
493
494   apr_file_close(file);
495 }
496
497
498 void
499 chxj_delete_cookie(request_rec* r, char* cookie_id)
500 {
501   apr_status_t      retval;
502   apr_datum_t       dbmkey;
503   apr_dbm_t*        f;
504   apr_file_t*       file;
505   mod_chxj_config*  dconf;
506
507   DBG(r, "start chxj_delete_cookie()");
508
509   file = chxj_cookie_db_lock(r);
510   if (! file) {
511     ERR(r, "mod_chxj: Can't lock cookie db");
512     goto on_error0;
513   }
514   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
515
516   retval = apr_dbm_open_ex(&f,
517                            "default",
518                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
519                            APR_DBM_RWCREATE,
520                            APR_OS_DEFAULT,
521                            r->pool);
522   if (retval != APR_SUCCESS) {
523     ERR2(r, 
524          "could not open dbm (type %s) auth file: %s", 
525          "default", 
526          chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
527     goto on_error1;
528   }
529
530   /*
531    * create key
532    */
533   dbmkey.dptr  = apr_pstrdup(r->pool, cookie_id);
534   dbmkey.dsize = strlen(dbmkey.dptr);
535   if (apr_dbm_exists(f, dbmkey)) {
536     apr_dbm_delete(f, dbmkey);
537   }
538   apr_dbm_close(f);
539   chxj_cookie_db_unlock(r, file);
540
541   DBG(r, "end   chxj_delete_cookie()");
542
543   return;
544
545 on_error1:
546   chxj_cookie_db_unlock(r, file);
547
548 on_error0:
549   return;
550
551 }
552
553
554 char*
555 chxj_cookie_db_name_create(request_rec* r, const char* dir)
556 {
557   char* dst;
558
559   if (!dir) {
560     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
561   }
562   else {
563     dst = apr_pstrdup(r->pool, dir);
564   }
565
566   if (dst[strlen(dst)-1] != '/') {
567     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_NAME, NULL);
568   }
569   else {
570     dst = apr_pstrcat(r->pool, dst, COOKIE_DB_NAME, NULL);
571   }
572
573   return dst;
574 }
575
576
577 char*
578 chxj_cookie_db_lock_name_create(request_rec* r, const char* dir)
579 {
580   char* dst;
581   DBG(r, "start  chxj_cookie_db_lock_name_create()");
582
583   if (!dir) {
584 DBG(r, " ");
585     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
586 DBG(r, " ");
587   }
588   else {
589 DBG1(r, " dir=[%x]", (unsigned int)dir);
590     dst = apr_pstrdup(r->pool, dir);
591 DBG(r, " ");
592   }
593 DBG1(r, "dst[strlen(dst)-1]=[%c]", dst[strlen(dst)-1]);
594   if (dst[strlen(dst)-1] != '/') {
595     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_LOCK_NAME, NULL);
596   }
597   else {
598     dst = apr_pstrcat(r->pool, dst, COOKIE_DB_LOCK_NAME, NULL);
599   }
600   DBG(r, "end  chxj_cookie_db_lock_name_create()");
601   return dst;
602 }
603 /*
604  *
605  */
606 void
607 chxj_save_cookie_expire(request_rec* r, cookie_t* cookie)
608 {
609   apr_status_t            retval;
610   apr_datum_t             dbmkey;
611   apr_datum_t             dbmval;
612   apr_dbm_t*              f;
613   apr_file_t*             file;
614   mod_chxj_config*        dconf;
615   char*                   store_string;
616
617   DBG(r, "start chxj_save_cookie_expire()");
618   if (!cookie) {
619     DBG(r, "cookie is NULL");
620     return;
621   }
622
623   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
624   if (!dconf) {
625     DBG(r, "dconf is NULL");
626     return;
627   }
628
629   file = chxj_cookie_expire_db_lock(r);
630   if (! file) {
631     ERR(r, "mod_chxj: Can't lock cookie db");
632     return;
633   }
634
635   DBG(r, " ");
636
637   retval = apr_dbm_open_ex(&f, 
638                            "default", 
639                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir), 
640                            APR_DBM_RWCREATE, 
641                            APR_OS_DEFAULT, 
642                            r->pool);
643   if (retval != APR_SUCCESS) {
644     ERR2(r, "could not open dbm (type %s) auth file: %s", 
645             "default", 
646             chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
647     chxj_cookie_expire_db_unlock(r, file);
648     return;
649   }
650   /*
651    * create key
652    */
653
654   dbmkey.dptr  = cookie->cookie_id;
655   dbmkey.dsize = strlen(cookie->cookie_id);
656
657   /*
658    * create val
659    */
660   
661   store_string = apr_psprintf(r->pool, "%d", (int)time(NULL));
662   dbmval.dptr  = store_string;
663   dbmval.dsize = strlen(store_string);
664
665   /*
666    * store to db
667    */
668   retval = apr_dbm_store(f, dbmkey, dbmval);
669   if (retval != APR_SUCCESS) {
670     ERR1(r, "Cannot store Cookie data to DBM file `%s'",
671             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
672   }
673
674
675   apr_dbm_close(f);
676   chxj_cookie_expire_db_unlock(r, file);
677
678   DBG(r, "end   chxj_save_cookie_expire()");
679 }
680
681
682 char*
683 chxj_cookie_expire_db_name_create(request_rec* r, const char* dir)
684 {
685   char* dst;
686
687   if (!dir) {
688     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
689   }
690   else {
691     dst = apr_pstrdup(r->pool, dir);
692   }
693
694   if (dst[strlen(dst)-1] != '/') {
695     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_NAME, NULL);
696   }
697   else {
698     dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_NAME, NULL);
699   }
700
701   return dst;
702 }
703
704
705 char*
706 chxj_cookie_expire_db_lock_name_create(request_rec* r, const char* dir)
707 {
708   char* dst;
709
710   if (!dir) {
711     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
712   }
713   else {
714     dst = apr_pstrdup(r->pool, dir);
715   }
716   if (dst[strlen(dst)-1] != '/') {
717     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
718   }
719   else {
720     dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
721   }
722
723   return dst;
724 }
725
726
727 apr_file_t*
728 chxj_cookie_expire_db_lock(request_rec* r)
729 {
730   apr_file_t*      file;
731   apr_status_t     rv;
732   mod_chxj_config* dconf;
733
734   dconf = (mod_chxj_config*)ap_get_module_config(r->per_dir_config, &chxj_module);
735
736   rv = apr_file_open(&file, 
737                      chxj_cookie_expire_db_lock_name_create(r, dconf->cookie_db_dir),
738                      APR_CREATE|APR_WRITE, 
739                      APR_OS_DEFAULT, 
740                      r->pool);
741   if (rv != APR_SUCCESS) {
742     ERR(r, "cookie lock file open failed.");
743     return NULL;
744   }
745
746   rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
747   if (rv != APR_SUCCESS) {
748     ERR(r, "cookie lock file open failed.");
749     apr_file_close(file);
750     return NULL;
751   }
752
753   return file;
754 }
755
756
757 void
758 chxj_cookie_expire_db_unlock(request_rec* r, apr_file_t* file)
759 {
760   apr_status_t rv;
761
762   rv = apr_file_unlock(file);
763   if (rv != APR_SUCCESS) {
764     ERR(r, "cookie lock file open failed.");
765     return;
766   }
767
768   apr_file_close(file);
769 }
770
771 void
772 chxj_delete_cookie_expire(request_rec* r, char* cookie_id)
773 {
774   apr_status_t      retval;
775   apr_datum_t       dbmkey;
776   apr_dbm_t*        f;
777   apr_file_t*       file;
778   mod_chxj_config*  dconf;
779
780   DBG(r, "start chxj_delete_cookie_expire()");
781
782   file = chxj_cookie_expire_db_lock(r);
783   if (! file) {
784     ERR(r, "mod_chxj: Can't lock cookie db");
785     goto on_error0;
786   }
787   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
788
789   retval = apr_dbm_open_ex(&f,
790                            "default",
791                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
792                            APR_DBM_RWCREATE,
793                            APR_OS_DEFAULT,
794                            r->pool);
795   if (retval != APR_SUCCESS) {
796     ERR2(r, 
797          "could not open dbm (type %s) auth file: %s", 
798          "default", 
799          chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
800     goto on_error1;
801   }
802
803   /*
804    * create key
805    */
806   dbmkey.dptr  = apr_pstrdup(r->pool, cookie_id);
807   dbmkey.dsize = strlen(dbmkey.dptr);
808   if (apr_dbm_exists(f, dbmkey)) {
809     apr_dbm_delete(f, dbmkey);
810   }
811   apr_dbm_close(f);
812   chxj_cookie_expire_db_unlock(r, file);
813
814   DBG(r, "end   chxj_delete_cookie_expire()");
815
816   return;
817
818 on_error1:
819   chxj_cookie_expire_db_unlock(r, file);
820
821 on_error0:
822   return;
823
824 }
825
826
827 void
828 chxj_cookie_expire_gc(request_rec* r)
829 {
830   apr_status_t      retval;
831   apr_datum_t       dbmkey;
832   apr_datum_t       dbmval;
833   apr_dbm_t*        f;
834   apr_file_t*       file;
835   mod_chxj_config*  dconf;
836   time_t            now_time;
837
838   DBG(r, "start chxj_cookie_expire_gc()");
839
840   file = chxj_cookie_expire_db_lock(r);
841   if (! file) {
842     ERR(r, "mod_chxj: Can't lock cookie db");
843     goto on_error0;
844   }
845   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
846
847   retval = apr_dbm_open_ex(&f,
848                            "default",
849                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
850                            APR_DBM_RWCREATE,
851                            APR_OS_DEFAULT,
852                            r->pool);
853   if (retval != APR_SUCCESS) {
854     ERR2(r, 
855          "could not open dbm (type %s) auth file: %s", 
856          "default", 
857          chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
858     goto on_error1;
859   }
860
861   /*
862    * create key
863    */
864   memset(&dbmkey, 0, sizeof(apr_datum_t));
865
866   now_time = time(NULL);
867
868   retval = apr_dbm_firstkey(f, &dbmkey);
869   if (retval == APR_SUCCESS) {
870     do {
871       char* tmp;
872       char* old_cookie_id;
873       int   val_time;
874       int   cmp_time;
875
876       retval = apr_dbm_fetch(f, dbmkey, &dbmval);
877       if (retval != APR_SUCCESS) {
878         break;
879       }
880       tmp = apr_palloc(r->pool, dbmval.dsize+1);
881       memset(tmp, 0, dbmval.dsize+1);
882       memcpy(tmp, dbmval.dptr, dbmval.dsize);
883
884
885       val_time = atoi(tmp);
886
887       if (dconf->cookie_timeout == 0)
888         cmp_time = now_time - DEFAULT_COOKIE_TIMEOUT;
889       else
890         cmp_time = now_time - dconf->cookie_timeout;
891
892       if (cmp_time >= val_time) {
893         apr_dbm_delete(f, dbmkey);
894
895         old_cookie_id = apr_palloc(r->pool, dbmkey.dsize+1);
896         memset(old_cookie_id, 0, dbmkey.dsize+1);
897         memcpy(old_cookie_id, dbmkey.dptr, dbmkey.dsize);
898
899         chxj_delete_cookie(r,old_cookie_id);
900       }
901
902       retval = apr_dbm_nextkey(f, &dbmkey);
903     } while(retval == APR_SUCCESS);
904   }
905
906   apr_dbm_close(f);
907   chxj_cookie_expire_db_unlock(r, file);
908
909   DBG(r, "end   chxj_cookie_expire_gc()");
910
911   return;
912
913 on_error1:
914   chxj_cookie_expire_db_unlock(r, file);
915
916 on_error0:
917   return;
918
919 }
920 /*
921  * vim:ts=2 et
922  */