OSDN Git Service

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