OSDN Git Service

756f09cc0d213111ee9bf51153987cca68c8477a
[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
296   {
297     int done_proc = 0;
298 #if defined(USE_MYSQL_COOKIE)
299     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
300       if (! chxj_save_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
301         ERR(r, "%s:%d faild: chxj_save_cookie_mysql() cookie_id:[%s]", APLOG_MARK,cookie->cookie_id);
302         cookie = NULL;
303         goto on_error;
304       }
305       done_proc = 1;
306     }
307 #endif
308 #if defined(USE_MEMCACHE_COOKIE)
309     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
310       if (! chxj_save_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
311         ERR(r, "%s:%d failed: chxj_save_cookie_memcache() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
312         cookie = NULL;
313         goto on_error;
314       }
315       done_proc = 1;
316     }
317 #endif
318     if (IS_COOKIE_STORE_DBM(dconf->cookie_store_type) || ! done_proc) {
319       if (! chxj_save_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
320         ERR(r, "%s:%d failed: chxj_save_cookie_dbm() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
321         cookie = NULL;
322         goto on_error;
323       }
324     }
325   }
326   apr_table_unset(r->headers_out, "Set-Cookie");
327   apr_table_unset(r->err_headers_out, "Set-Cookie");
328
329   if (cookie) {
330     chxj_save_cookie_expire(r, cookie);
331   }
332
333 on_error:
334   DBG(r, "end chxj_save_cookie()");
335   return cookie;
336 }
337
338
339
340 /*
341  *
342  */
343 cookie_t *
344 chxj_update_cookie(request_rec *r, cookie_t *old_cookie)
345 {
346   int                 ii;
347   apr_array_header_t  *headers;
348   apr_table_entry_t   *hentryp;
349   char                *store_string;
350   mod_chxj_config     *dconf;
351   chxjconvrule_entry  *entryp;
352   cookie_t            *cookie;
353
354
355   DBG(r, "start chxj_update_cookie()");
356   if (!old_cookie || ! old_cookie->cookie_headers || ! old_cookie->cookie_id) {
357     DBG(r, "end chxj_update_cookie() (old_cookie is null)");
358     return  NULL;
359   }
360
361   cookie = (cookie_t *)apr_palloc(r->pool, sizeof(cookie_t));
362   cookie->cookie_id = NULL;
363
364   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
365   entryp = chxj_apply_convrule(r, dconf->convrules);
366   if (! entryp) {
367     DBG(r, "end chxj_update_cookie() no pattern");
368     return NULL;
369   }
370   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
371     DBG(r, "end chxj_update_cookie() CookieOff");
372     return NULL;
373   }
374
375   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
376   hentryp = (apr_table_entry_t*)headers->elts;
377
378   chxj_delete_cookie(r,        old_cookie->cookie_id);
379   chxj_delete_cookie_expire(r, old_cookie->cookie_id);
380
381   if (IS_COOKIE_LAZY(dconf)) {
382     DBG(r, "LAZY MODE");
383     cookie->cookie_id = apr_pstrdup(r->pool, old_cookie->cookie_id);
384   }
385   else {
386     DBG(r, "NO LAZY MODE");
387     cookie->cookie_id = alloc_cookie_id(r);
388   }
389
390   cookie->cookie_headers = old_cookie->cookie_headers;
391   store_string = apr_palloc(r->pool, 1);
392   store_string[0] = 0;
393   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
394
395   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
396     if (ii) store_string = apr_pstrcat(r->pool,
397                                store_string, 
398                                "\n",
399                                NULL);
400
401     DBG(r, "OLD COOKIE VALUE=[%s][%s]", hentryp[ii].key, hentryp[ii].val);
402     store_string = apr_pstrcat(r->pool, 
403                                store_string, 
404                                hentryp[ii].key, 
405                                "=",
406                                hentryp[ii].val, 
407                                NULL);
408   }
409
410   {
411     int done_proc = 0;
412 #if defined(USE_MYSQL_COOKIE)
413     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
414       if (!chxj_update_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
415         ERR(r, "failed: chxj_update_cookie_mysql() cookie_id:[%s]", cookie->cookie_id);
416         goto on_error;
417       }
418       done_proc = 1;
419     }
420 #endif
421
422 #if defined(USE_MEMCACHE_COOKIE)
423     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
424       if (! chxj_update_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
425         ERR(r, "failed: chxj_update_cookie_memcache() cookie_id:[%s]", cookie->cookie_id);
426         goto on_error;
427       }
428       done_proc = 1;
429     }
430 #endif
431     if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
432       if (! chxj_update_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
433         ERR(r, "failed: chxj_update_cookie_dbm() cookie_id:[%s]", cookie->cookie_id);
434         goto on_error;
435       }
436     }
437   }
438
439   chxj_save_cookie_expire(r, cookie);
440
441   apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
442
443
444 on_error:
445   DBG(r, "end   chxj_update_cookie()");
446   return cookie;
447 }
448
449
450 /*
451  *
452  * @return loaded data.
453  */
454 cookie_t *
455 chxj_load_cookie(request_rec *r, char *cookie_id)
456 {
457   mod_chxj_config         *dconf;
458   chxjconvrule_entry      *entryp;
459   cookie_t                *cookie;
460   apr_table_t             *load_cookie_table;
461   char                    *load_string = NULL;
462   char                    *pstat;
463   char                    *key;
464   char                    *val;
465   char                    *pair;
466   char                    *header_cookie;
467
468   DBG(r, "REQ[%X] start chxj_load_cookie() cookie_id=[%s]", TO_ADDR(r), cookie_id);
469   chxj_cookie_expire_gc(r);
470
471   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
472   cookie->cookie_headers = NULL;
473   cookie->cookie_id = chxj_url_decode(r->pool, apr_pstrdup(r->pool, cookie_id));
474   cookie->cookie_id = chxj_url_encode(r->pool, cookie->cookie_id);
475
476
477   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
478   entryp = chxj_apply_convrule(r, dconf->convrules);
479   if (! entryp) {
480     DBG(r, "REQ[%X] end chxj_load_cookie() no pattern", TO_ADDR(r));
481     goto on_error0;
482   }
483   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
484     DBG(r, "REQ[%X] end chxj_load_cookie() CookieOff", TO_ADDR(r));
485     goto on_error0;
486   }
487   load_cookie_table = apr_table_make(r->pool, 0);
488
489   {
490     int done_proc = 0;
491 #if defined(USE_MYSQL_COOKIE)
492     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
493       if (! (load_string = chxj_load_cookie_mysql(r, dconf, cookie->cookie_id))) {
494         ERR(r, "%s:%d failed: chxj_load_cookie_mysql() cookie_id:[%s]", APLOG_MARK, cookie_id);
495         goto on_error0;
496       }
497       done_proc = 1;
498     }
499 #endif
500 #if defined(USE_MEMCACHE_COOKIE)
501     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
502       if (! (load_string = chxj_load_cookie_memcache(r, dconf, cookie->cookie_id))) {
503         ERR(r, "%s:%d failed: chxj_load_cookie_memcache() cookie_id:[%s]", APLOG_MARK,cookie_id);
504         goto on_error0;
505       }
506       done_proc = 1;
507     }
508 #endif
509     if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
510       if (! (load_string = chxj_load_cookie_dbm(r, dconf, cookie->cookie_id))) {
511         ERR(r, "%s:%d failed: chxj_load_cookie_dbm() cookie_id:[%s]", APLOG_MARK,cookie_id);
512         goto on_error0;
513       }
514     }
515   }
516
517   if (load_string) {
518     DBG(r, "REQ[%X] load_string=[%s]", TO_ADDR(r), load_string);
519     header_cookie = apr_palloc(r->pool, 1);
520     header_cookie[0] = 0;
521     for (;;) {
522       char *tmp_sem;
523       char *tmp_pair;
524       pair = apr_strtok(load_string, "\n", &pstat);  
525       load_string = NULL;
526       if (!pair) break;
527
528       DBG(r, "REQ[%X] Cookie:[%s]", TO_ADDR(r), pair);
529
530       tmp_pair = apr_pstrdup(r->pool, pair);
531       val = strchr(tmp_pair, '=');
532       if (val) {
533         key = tmp_pair;
534         *val++ = 0;
535         apr_table_add(load_cookie_table, key, val);
536         DBG(r, "REQ[%X] ADD key:[%s] val:[%s]", TO_ADDR(r), key, val);
537       }
538       tmp_pair = apr_pstrdup(r->pool, pair);
539       tmp_sem = strchr(tmp_pair, ';'); 
540       if (tmp_sem)
541         *tmp_sem = '\0';
542
543       if (check_valid_cookie_attribute(r, pair)) {
544         if (strlen(header_cookie)) 
545           header_cookie = apr_pstrcat(r->pool, header_cookie, ";", NULL);
546   
547         header_cookie = apr_pstrcat(r->pool, header_cookie, tmp_pair, NULL);
548       }
549     }
550     if (strlen(header_cookie)) {
551       DBG(r, "REQ[%X] ADD COOKIE to REQUEST HEADER:[%s]", TO_ADDR(r), header_cookie);
552       apr_table_add(r->headers_in, "Cookie", header_cookie);
553     }
554   
555     cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
556
557     if (apr_table_get(r->headers_in, "referer") == NULL) {
558       apr_table_setn(r->headers_in, 
559                      "referer",
560                      apr_table_get(load_cookie_table, REFERER_COOKIE_KEY));
561     }
562   
563     /*
564      * save cookie_id to request header.
565      */
566     apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
567   }
568
569   DBG(r, "REQ[%X] end   chxj_load_cookie()", TO_ADDR(r));
570   return cookie;
571
572
573 on_error0:
574
575   DBG(r, "REQ[%X] end   chxj_load_cookie()", TO_ADDR(r));
576   return NULL;
577 }
578
579 static int
580 check_valid_cookie_attribute(request_rec *r, const char *value)
581 {
582   char *pstat;
583   char *pair;
584   char *first_pair;
585   char *domain_pair;
586   char *path_pair;
587   char *expire_pair;
588   char *secure_pair;
589   char *p;
590
591   DBG(r, "start check_valid_cookie_attribute() value:[%s]", value);
592
593   domain_pair = path_pair = expire_pair = secure_pair = NULL;
594   p = apr_pstrdup(r->pool, value);
595
596   /* pass first pair */
597   first_pair = apr_strtok(p, ";", &pstat);  
598
599   for (;;) {
600     pair = apr_strtok(NULL, ";", &pstat);
601     if (! pair) break;
602     pair = qs_trim_string(r->pool, pair);
603     if (STRNCASEEQ('d','D',"domain", pair, sizeof("domain")-1)) {
604       domain_pair = apr_pstrdup(r->pool, pair);
605     }
606     else if (STRNCASEEQ('p','P',"path", pair, sizeof("path")-1)) {
607       path_pair = apr_pstrdup(r->pool, pair);
608     }
609     else if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
610       expire_pair = apr_pstrdup(r->pool, pair);
611     }
612     else if (STRNCASEEQ('s','S',"secure", pair, sizeof("secure")-1)) {
613       secure_pair = apr_pstrdup(r->pool, pair);
614     }
615   }
616
617   if (domain_pair) {
618     if (!valid_domain(r, domain_pair)) {
619       DBG(r, "invalid domain. domain_pair:[%s]", domain_pair);
620       return CHXJ_FALSE;
621     }
622   }
623   if (path_pair) {
624     if (!valid_path(r, path_pair)) {
625       DBG(r, "invalid path. path_pair:[%s]", path_pair);
626       return CHXJ_FALSE;
627     }
628   }
629   if (expire_pair) {
630     if (!valid_expires(r, expire_pair)) {
631       DBG(r, "invalid expire. expire_pair:[%s]", expire_pair);
632       return CHXJ_FALSE;
633     }
634   }
635   if (secure_pair) {
636     if (!valid_secure(r, secure_pair)) {
637       DBG(r, "invalid secure. secure_pair:[%s]", secure_pair);
638       return CHXJ_FALSE;
639     }
640   }
641   DBG(r, "end check_valid_cookie_attribute() value:[%s]", value);
642   return CHXJ_TRUE;
643 }
644
645
646 static int
647 check_valid_cookie_attribute_expires_only(request_rec *r, const char *value)
648 {
649   char *pstat;
650   char *pair;
651   char *first_pair;
652   char *expire_pair = NULL;
653   char *p;
654
655   DBG(r, "REQ[%X] start check_valid_cookie_attribute_expires_only() value:[%s]", (unsigned int)(apr_size_t)r, value);
656
657   expire_pair = NULL;
658   p = apr_pstrdup(r->pool, value);
659
660   /* pass first pair */
661   first_pair = apr_strtok(p, ";", &pstat);
662
663   for (;;) {
664     pair = apr_strtok(NULL, ";", &pstat);
665     if (! pair) break;
666     pair = qs_trim_string(r->pool, pair);
667     if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
668       expire_pair = apr_pstrdup(r->pool, pair);
669     }
670   }
671
672   if (expire_pair) {
673     if (!valid_expires(r, expire_pair)) {
674       DBG(r, "REQ[%X] invalid expire. expire_pair:[%s]", (unsigned int)(apr_size_t)r, expire_pair);
675       return CHXJ_FALSE;
676     }
677   }
678   DBG(r, "REQ[%X] end check_valid_cookie_attribute_expires_only() value:[%s]", (unsigned int)(apr_size_t)r, value);
679   return CHXJ_TRUE;
680 }
681
682
683 static int
684 valid_domain(request_rec *r, const char *value)
685 {
686   int  len;
687   char *name;
688   char *val;
689   char *pstat;
690   char *p = apr_pstrdup(r->pool, value);
691   const char *host = apr_table_get(r->headers_in, HTTP_HOST);
692
693   DBG(r, "REQ[%X] start valid_domain() value:[%s]", TO_ADDR(r), value);
694   DBG(r, "REQ[%X] host:[%s]", TO_ADDR(r), host);
695   host = s_cut_until_end_hostname(r, host);
696   DBG(r, "REQ[%X] host:[%s](after s_cut_until_end_hostname())", TO_ADDR(r), host);
697   if (!host) {
698     DBG(r, "REQ[%X] end valid_domain() value:[%s]", TO_ADDR(r), value);
699     return CHXJ_TRUE;
700   }
701
702   name = apr_strtok(p,"=", &pstat);
703   name = qs_trim_string(r->pool, name);
704   val = apr_strtok(NULL, "=", &pstat);
705   val = qs_trim_string(r->pool, val);
706   len = strlen(host);
707   if (len) {
708     if (chxj_strcasenrcmp(r->pool, host, val, strlen(val))) {
709       DBG(r, "REQ[%X] not match domain. host domain:[%s] vs value:[%s]", TO_ADDR(r), host, val);
710       DBG(r, "REQ[%X] end valid_domain() value:[%s]", TO_ADDR(r), value);
711       return CHXJ_FALSE;
712     }
713   }
714   DBG(r, "REQ[%X] end valid_domain() value:[%s]", TO_ADDR(r), value);
715   return CHXJ_TRUE;
716 }
717
718
719 static int
720 valid_path(request_rec *r, const char *value)
721 {
722   char *p = apr_pstrdup(r->pool, value);
723   char *uri;
724   char *tmp;
725   char *name;
726   char *val;
727   char *pstat;
728
729   DBG(r, "start valid_path() unparsed_uri:[%s] value:[%s]", r->unparsed_uri, value);
730   if (chxj_starts_with(r->unparsed_uri, "http://")) {
731     uri = strchr(&r->unparsed_uri[sizeof("http://")], '/');
732     if (uri != NULL) {
733       uri = apr_pstrdup(r->pool, uri);
734     }
735   }
736   else if (chxj_starts_with(r->unparsed_uri, "https://")) {
737     uri = strchr(&r->unparsed_uri[sizeof("https://")], '/');
738     if (uri != NULL) {
739       uri = apr_pstrdup(r->pool, uri);
740     }
741   }
742   else if (chxj_starts_with(r->unparsed_uri, "/")) {
743     uri = apr_pstrdup(r->pool, r->unparsed_uri);
744   }
745   else {
746     uri = apr_pstrdup(r->pool, "/");
747   }
748   
749   if ((tmp = strchr(uri, '?'))) {
750     *tmp = '\0';
751   }
752   DBG(r, "uri=[%s]", uri);
753   name = apr_strtok(p, "=", &pstat);
754   val = apr_strtok(NULL, "=", &pstat);
755   name = qs_trim_string(r->pool, name);
756   val = qs_trim_string(r->pool, val);
757   DBG(r, "name=[%s] val=[%s]", name, val);
758   
759   DBG(r, "val:[%s] vs uri:[%s]", val, uri);
760   if (! chxj_starts_with(uri, val)) {
761     DBG(r, "end valid_path() unparsed_uri:[%s] value:[%s] (false)", r->unparsed_uri, value);
762     return CHXJ_FALSE;
763   }
764   DBG(r, "end valid_path() unparsed_uri:[%s] value:[%s] (true)", r->unparsed_uri, value);
765   return CHXJ_TRUE;
766 }
767
768
769 static int
770 valid_expires(request_rec *r, const char *value)
771 {
772   char       *name;
773   char       *val;
774   char       *p = apr_pstrdup(r->pool, value);
775   char       *pstat;
776   apr_time_t expires;
777   apr_time_t now;
778
779   DBG(r, "start valid_expire() value:[%s]", value);
780   name = apr_strtok(p, "=", &pstat);
781   val  = apr_strtok(NULL, "=", &pstat);
782   DBG(r, "name=[%s] val=[%s]", name, val);
783   now = apr_time_now();
784   expires = chxj_parse_cookie_expires(val);
785   if (expires < now) {
786     DBG(r, "end valid_expire() value:[%s] (expired)", value);
787     return CHXJ_FALSE;
788   }
789   
790   DBG(r, "end valid_expire() value:[%s] (non expired)", value);
791   return CHXJ_TRUE;
792 }
793
794
795 static int
796 valid_secure(request_rec *r, const char *value)
797 {
798   const char *scheme;
799   DBG(r, "start valid_secure() value:[%s]", value);
800   scheme = chxj_apache_run_http_scheme(r);
801   if (strcasecmp("https", scheme)) {
802     DBG(r, "end valid_secure() value:[%s] (non secure)", value);
803     return CHXJ_FALSE;
804   }
805   DBG(r, "end valid_secure() value:[%s] (secure)", value);
806   return CHXJ_TRUE;
807 }
808
809
810 char *
811 chxj_add_cookie_parameter(request_rec *r, char *value, cookie_t *cookie)
812 {
813   char *qs;
814   char *dst;
815   char *name = "";
816
817   DBG(r, "REQ[%X] start chxj_add_cookie_parameter() cookie_id=[%s]", TO_ADDR(r), (cookie) ? cookie->cookie_id : NULL);
818
819   dst = apr_pstrdup(r->pool, value);
820
821   if (!cookie)
822     goto on_error;
823
824   if (!cookie->cookie_id)
825     goto on_error;
826
827   if (chxj_cookie_check_host(r, value) != 0) {
828     DBG(r, "REQ[%X] end chxj_add_cookie_parameter()(check host)", TO_ADDR(r));
829     goto on_error;
830   }
831
832   qs = strchr(dst, '#');
833   if (qs) {
834     name = apr_pstrdup(r->pool, qs);
835     *qs = 0;
836   }
837
838   qs = strchr(dst, '?');
839   if (qs) {
840     char *sv_qs = qs;
841     qs = chxj_delete_chxj_cc_param(r, ++qs);
842     DBG(r, "REQ[%X] qs:[%s]",TO_ADDR(r), qs);
843     *sv_qs = 0;
844     if (qs && strlen(qs)) {
845       dst = apr_psprintf(r->pool, "%s?%s", dst, qs);
846     }
847   }
848   if (qs) {
849     dst = apr_psprintf(r->pool, "%s&%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
850   }
851   else {
852     dst = apr_psprintf(r->pool, "%s?%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
853   }
854
855   DBG(r, "REQ[%X] end   chxj_add_cookie_parameter() dst=[%s]", TO_ADDR(r), dst);
856
857   return dst;
858
859 on_error:
860   DBG(r, "REQ[%X] end   chxj_add_cookie_parameter() (on_error)", TO_ADDR(r));
861   return dst;
862 }
863
864
865 char *
866 chxj_add_cookie_no_update_parameter(request_rec *r, char *value)
867 {
868   char *qs;
869   char *dst;
870   char *name = "";
871
872   DBG(r, "REQ[%X] start chxj_add_cookie_no_update_parameter()", (unsigned int)(apr_size_t)r);
873
874   if (! value || ! *value) {
875     DBG(r, "REQ[%X] end chxj_add_cookie_parameter()(void value)", (unsigned int)(apr_size_t)r);
876     return apr_pstrdup(r->pool, "");
877   }
878
879   dst = apr_pstrdup(r->pool, value);
880
881   if (chxj_cookie_check_host(r, value) != 0) {
882     DBG(r, "REQ[%X] end chxj_add_cookie_parameter()(check host)", (unsigned int)(apr_size_t)r);
883     goto on_error;
884   }
885
886   qs = strchr(dst, '#');
887   if (qs) {
888     name = apr_pstrdup(r->pool, qs);
889     *qs = 0;
890   }
891   dst = apr_psprintf(r->pool, "%s%c%s=true%s", dst, (strchr(dst,'?')) ? '&' : '?',CHXJ_COOKIE_NOUPDATE_PARAM, name);
892   DBG(r, "REQ[%X] end   chxj_add_cookie_no_update_parameter() dst=[%s]", (unsigned int)(apr_size_t)r, dst);
893   return dst;
894
895 on_error:
896   DBG(r, "REQ[%X] end   chxj_add_cookie_no_update_parameter() (on_error)", (unsigned int)(apr_size_t)r);
897   return dst;
898 }
899
900
901 int
902 chxj_cookie_check_host(request_rec *r, char *value) 
903 {
904   char *hostnm;
905   mod_chxj_config *dconf;
906
907   DBG(r, "REQ[%X] start chxj_cookie_check_host()", (unsigned int)(apr_size_t)r);
908   DBG(r, "REQ[%X] hostname=[%s] vs Location:[%s]", (unsigned int)(apr_size_t)r, r->hostname, value);
909
910   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
911
912   hostnm = s_get_hostname_from_url(r, value);
913   if (hostnm) {
914     if (dconf->allowed_cookie_domain) {
915       DBG(r, "REQ[%X] allowed_domain[%s] vs Location:[%s]", (unsigned int)(apr_size_t)r, dconf->allowed_cookie_domain, value);
916       if (chxj_strcasenrcmp(r->pool, hostnm, dconf->allowed_cookie_domain, strlen(dconf->allowed_cookie_domain))) {
917         DBG(r, "REQ[%X] end chxj_cookie_check_host() (false/allowed_domain)", (unsigned int)(apr_size_t)r);
918         return 1;
919       }
920       else {
921         DBG(r, "REQ[%X] end chxj_cookie_check_host() (true/allowed_domain)", (unsigned int)(apr_size_t)r);
922         return 0;
923       }
924     }
925     else {
926       if (strcasecmp(hostnm, r->hostname) == 0) {
927         DBG(r, "REQ[%X] end chxj_cookie_check_host() (true)", (unsigned int)(apr_size_t)r);
928         return 0;
929       }
930       else {
931         DBG(r, "REQ[%X] end chxj_cookie_check_host() (false)", (unsigned int)(apr_size_t)r);
932         return 1;
933       }
934     }
935   }
936   DBG(r, "REQ[%X] end chxj_cookie_check_host() (true)", (unsigned int)(apr_size_t)r);
937   return 0;
938 }
939
940
941 static char *
942 s_get_hostname_from_url(request_rec *r, char *value)
943 {
944   if (!value) 
945     return NULL; 
946
947   if (strncasecmp(value, "http://",  7) == 0 )
948     return s_cut_until_end_hostname(r, &value[7]);
949
950   if (strncasecmp(value, "https://", 8) == 0)
951     return s_cut_until_end_hostname(r, &value[8]);
952
953   return NULL;
954 }
955
956
957 static char *
958 s_cut_until_end_hostname(request_rec *r, char *value)
959 {
960   char *sp;
961   char *hostnm;
962
963   hostnm = sp = apr_pstrdup(r->pool, value);
964   for (;*sp; sp++) {
965     if (*sp == '/'|| *sp == '?' || *sp == ':') {
966       *sp = '\0';
967       break;
968     }
969   }
970   return hostnm;
971 }
972
973
974
975 void
976 chxj_delete_cookie(request_rec *r, const char *cookie_id)
977 {
978   int done_proc = 0;
979   mod_chxj_config *dconf;
980
981   DBG(r, "start chxj_delete_cookie()");
982   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
983
984 #if defined(USE_MYSQL_COOKIE)
985   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
986     if (! chxj_delete_cookie_mysql(r, dconf, cookie_id)) {
987       ERR(r, "failed: chxj_delete_cookie_mysql() cookie_id:[%s]", cookie_id);
988       DBG(r, "end   chxj_delete_cookie()");
989       return;
990     }
991     done_proc = 1;
992   }
993 #endif
994 #if defined(USE_MEMCACHE_COOKIE)
995   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
996     if (! chxj_delete_cookie_memcache(r, dconf, cookie_id)) {
997       ERR(r, "failed: chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
998       DBG(r, "end   chxj_delete_cookie()");
999       return;
1000     }
1001     done_proc = 1;
1002   }
1003 #endif
1004   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1005     if (! chxj_delete_cookie_dbm(r, dconf, cookie_id)) {
1006       ERR(r, "failed: chxj_delete_cookie_dbm() cookie_id:[%s]", cookie_id);
1007       DBG(r, "end   chxj_delete_cookie()");
1008       return;
1009     }
1010   }
1011
1012   DBG(r, "end   chxj_delete_cookie()");
1013 }
1014
1015
1016 /*
1017  *
1018  */
1019 void
1020 chxj_save_cookie_expire(request_rec *r, cookie_t *cookie)
1021 {
1022   int done_proc = 0;
1023   mod_chxj_config         *dconf;
1024
1025   DBG(r, "start chxj_save_cookie_expire()");
1026   if (!cookie) {
1027     DBG(r, "cookie is NULL");
1028     return;
1029   }
1030   if (!cookie->cookie_id) {
1031     DBG(r, "cookie->cookie_id is NULL");
1032     return;
1033   }
1034
1035   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1036   if (!dconf) {
1037     DBG(r, "dconf is NULL");
1038     return;
1039   }
1040
1041 #if defined(USE_MYSQL_COOKIE)
1042   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1043     if (! chxj_save_cookie_expire_mysql(r, dconf, cookie->cookie_id)) {
1044       ERR(r, "failed: chxj_save_cookie_expire_mysql() cookie_id:[%s]", cookie->cookie_id);
1045       DBG(r, "end   chxj_save_cookie_expire()");
1046       return;
1047     }
1048     done_proc = 1;
1049   }
1050 #endif
1051 #if defined(USE_MEMCACHE_COOKIE)
1052   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1053     if (! chxj_save_cookie_expire_memcache(r, dconf, cookie->cookie_id)) {
1054       ERR(r, "failed: chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie->cookie_id);
1055       DBG(r, "end   chxj_save_cookie_expire()");
1056       return;
1057     }
1058     done_proc = 1;
1059   }
1060 #endif
1061   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1062     if (! chxj_save_cookie_expire_dbm(r, dconf, cookie->cookie_id)) {
1063       ERR(r, "failed: chxj_save_cookie_expire_dbm() cookie_id:[%s]", cookie->cookie_id);
1064       DBG(r, "end   chxj_save_cookie_expire()");
1065       return;
1066     }
1067   }
1068
1069   DBG(r, "end   chxj_save_cookie_expire()");
1070 }
1071
1072
1073 void
1074 chxj_delete_cookie_expire(request_rec *r, char *cookie_id)
1075 {
1076   int done_proc = 0;
1077   mod_chxj_config *dconf;
1078
1079   DBG(r, "start chxj_delete_cookie_expire()");
1080
1081   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1082
1083 #if defined(USE_MYSQL_COOKIE)
1084   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1085     if (! chxj_delete_cookie_expire_mysql(r, dconf, cookie_id)) {
1086       ERR(r, "failed: chxj_delete_cookie_expire_mysql() cookie_id:[%s]", cookie_id);
1087       return;
1088     }
1089     done_proc = 1;
1090   }
1091 #endif
1092 #if defined(USE_MEMCACHE_COOKIE)
1093   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1094     if (!chxj_delete_cookie_expire_memcache(r, dconf, cookie_id)) {
1095       ERR(r, "failed: chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
1096       return;
1097     } 
1098     done_proc = 1;
1099   }
1100 #endif
1101   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1102     if (!chxj_delete_cookie_expire_dbm(r, dconf, cookie_id)) {
1103       ERR(r, "failed: chxj_delete_cookie_expire_dbm() cookie_id:[%s]", cookie_id);
1104       return;
1105     } 
1106   }
1107
1108   DBG(r, "end   chxj_delete_cookie_expire()");
1109 }
1110
1111
1112 void
1113 chxj_cookie_expire_gc(request_rec *r)
1114 {
1115   mod_chxj_config   *dconf;
1116   int done_proc = 0;
1117
1118   DBG(r, "start chxj_cookie_expire_gc()");
1119
1120   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1121 #if defined(USE_MYSQL_COOKIE)
1122   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1123     if (! chxj_cookie_expire_gc_mysql(r, dconf)) {
1124       ERR(r, "%s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_mysql()", APLOG_MARK);
1125       return;
1126     }
1127     done_proc = 1;
1128   } 
1129 #endif
1130 #if defined(USE_MEMCACHE_COOKIE)
1131   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1132     if (! chxj_cookie_expire_gc_memcache(r, dconf)) {
1133       ERR(r, "%s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_memcache()", APLOG_MARK);
1134       return;
1135     }
1136     done_proc = 1;
1137   } 
1138 #endif
1139   if (!done_proc) {
1140     if (! chxj_cookie_expire_gc_dbm(r, dconf)) {
1141       ERR(r, "%s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_dbm()", APLOG_MARK);
1142       return;
1143     }
1144   }
1145   DBG(r, "end   chxj_cookie_expire_gc()");
1146 }
1147
1148 apr_time_t
1149 chxj_parse_cookie_expires(const char *s)
1150 {
1151   if (!s) return (apr_time_t)0;
1152   return apr_date_parse_rfc(s);
1153 }
1154
1155
1156 cookie_lock_t *
1157 __chxj_cookie_lock(request_rec *r, const char *filename, int line)
1158 {
1159   mod_chxj_config *dconf;
1160   apr_status_t rv;
1161   int done_proc = 0;
1162   cookie_lock_t *ret = NULL;
1163
1164   DBG(r, "start chxj_cookie_lock() call from %s:%d", filename, line);
1165   if ((rv = apr_proc_mutex_lock(global_cookie_mutex)) != APR_SUCCESS) {
1166     char errstr[255];
1167     ERR(r, "%s:%d apr_proc_mutex_lock failure.(%d:%s)", APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1168     return NULL;
1169   }
1170   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1171 #if defined(USE_MYSQL_COOKIE)
1172   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1173     if (! chxj_cookie_lock_mysql(r, dconf)) {
1174       ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_mysql()", APLOG_MARK);
1175       return NULL;
1176     }
1177     done_proc = 1;
1178     ret = apr_palloc(r->pool, sizeof(*ret));
1179     memset(ret, 0, sizeof(*ret));
1180   }
1181 #endif
1182 #if defined(USE_MEMCACHE_COOKIE)
1183   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1184     if (! chxj_cookie_lock_memcache(r, dconf)) {
1185       ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_memcache()", APLOG_MARK);
1186       return NULL;
1187     }
1188     done_proc = 1;
1189     ret = apr_palloc(r->pool, sizeof(*ret));
1190     memset(ret, 0, sizeof(*ret));
1191   }
1192 #endif
1193   if (!done_proc) {
1194     if (!(ret = chxj_cookie_lock_dbm(r, dconf))) {
1195       ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_dbm()", APLOG_MARK);
1196       DBG(r, "end chxj_cookie_lock() call from %s:%d", filename, line);
1197       return NULL;
1198     }
1199   }
1200   DBG(r, "REQ:[%X] end chxj_cookie_lock() call from %s:%d", (unsigned int)(apr_size_t)r, filename, line);
1201   return ret;
1202 }
1203
1204
1205 int
1206 __chxj_cookie_unlock(request_rec *r, cookie_lock_t *lock, const char *filename, int line)
1207 {
1208   mod_chxj_config *dconf;
1209   int done_proc = 0;
1210   apr_status_t rv;
1211   int rtn = 1;
1212
1213   DBG(r, "start chxj_cookie_unlock() call from %s:%d", filename, line);
1214
1215   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1216 #if defined(USE_MYSQL_COOKIE)
1217   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1218     if (! chxj_cookie_unlock_mysql(r, dconf)) {
1219       ERR(r, "failed: chxj_cookie_unlock_mysql()");
1220       rtn = 0;
1221       goto end_chxj_cookie_unlock;
1222     }
1223     done_proc = 1;
1224   }
1225 #endif
1226 #if defined(USE_MEMCACHE_COOKIE)
1227   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1228     if (! chxj_cookie_unlock_memcache(r, dconf)) {
1229       ERR(r, "failed: chxj_cookie_unlock_memcache()");
1230       rtn = 0;
1231       goto end_chxj_cookie_unlock;
1232     }
1233     done_proc = 1;
1234   }
1235 #endif
1236   if (!done_proc) {
1237     if (! chxj_cookie_unlock_dbm(r, lock, dconf)) {
1238       ERR(r, "failed: chxj_cookie_unlock_dbm()");
1239       rtn = 0;
1240       goto end_chxj_cookie_unlock;
1241     }
1242   }
1243 end_chxj_cookie_unlock:
1244   if ((rv = apr_proc_mutex_unlock(global_cookie_mutex)) != APR_SUCCESS) {
1245     char errstr[255];
1246     ERR(r, "%s:%d apr_proc_mutex_unlock failure.(%d:%s)", APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1247     DBG(r, "end chxj_cookie_unlock() call from %s:%d", filename, line);
1248     return 0;
1249   }
1250   DBG(r, "end chxj_cookie_unlock() call from %s:%d", filename, line);
1251
1252   return rtn;
1253 }
1254 /*
1255  * vim:ts=2 et
1256  */