OSDN Git Service

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