OSDN Git Service

* for KANTAN LOGIN with Cookie
[modchxj/mod_chxj.git] / src / chxj_cookie.c
1 /*
2  * Copyright (C) 2005-2011 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,"REQ[%X] cookie_id=[%s]", TO_ADDR(r),cookie_id);
96
97   cookie_id = chxj_url_encode(r->pool,cookie_id);
98
99   DBG(r, "REQ[%X] cookie_id=[%s]", TO_ADDR(r),cookie_id);
100   return cookie_id;
101 }
102
103
104
105 /*
106  *
107  */
108 cookie_t *
109 chxj_save_cookie(request_rec *r)
110 {
111   int                 ii;
112   apr_array_header_t  *headers;
113   apr_table_entry_t   *hentryp;
114   apr_array_header_t  *err_headers;
115   apr_table_entry_t   *err_hentryp;
116   char                *old_cookie_id;
117   char                *store_string;
118   mod_chxj_config     *dconf;
119   mod_chxj_req_config *req_conf;
120   chxjconvrule_entry  *entryp;
121   apr_table_t         *new_cookie_table;
122   int                 has_cookie = 0;
123   cookie_t            *cookie;
124   cookie_t            *old_cookie;
125   char                *refer_string;
126   apr_uri_t           parsed_uri;
127   int                 has_refer;
128   apr_pool_t          *pool;
129
130
131   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
132
133   apr_pool_create(&pool, r->pool);
134
135   cookie = (cookie_t*)apr_palloc(pool, sizeof(cookie_t));
136   cookie->cookie_id = NULL;
137
138   has_cookie = 0;
139   has_refer = 0;
140
141   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
142   req_conf = chxj_get_req_config(r);
143   /*-------------------------------------------------------------------------*/
144   /* already setup entryp if request_conf->user_agent is not null            */
145   /*-------------------------------------------------------------------------*/
146   if (req_conf->user_agent) {
147     entryp = req_conf->entryp;
148   }
149   else {
150     entryp = chxj_apply_convrule(r, dconf->convrules);
151   }
152   if (! entryp) {
153     DBG(r,"REQ[%X] end %s() no pattern",TO_ADDR(r),__func__);
154     return NULL;
155   }
156   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT) && ! (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
157     DBG(r,"REQ[%X] end %s() CookieOff",TO_ADDR(r),__func__);
158     return NULL;
159   }
160
161
162
163   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
164   hentryp = (apr_table_entry_t*)headers->elts;
165   err_headers = (apr_array_header_t*)apr_table_elts(r->err_headers_out);
166   err_hentryp = (apr_table_entry_t*)err_headers->elts;
167
168
169   new_cookie_table = apr_table_make(pool, 0);
170
171   for (ii=0; ii<headers->nelts; ii++) {
172     if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
173       DBG(r, "REQ[%X] cookie=[%s:%s]", TO_ADDR(r), hentryp[ii].key, hentryp[ii].val);
174
175       char* key;
176       char* val;
177       char* buff;
178
179       char *pair = apr_psprintf(pool, "%s:%s", hentryp[ii].key, hentryp[ii].val);
180       if (check_valid_cookie_attribute_expires_only(r, pair)) {
181         buff = apr_pstrdup(pool, hentryp[ii].val);
182         val = strchr(buff, '=');
183         if (val) {
184           key = buff;
185           *val++ = 0;
186           apr_table_set(new_cookie_table, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
187           if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
188         }
189         has_cookie = 1;
190       }
191     }
192   }
193   for (ii=0; ii<err_headers->nelts; ii++) {
194     if (strcasecmp(err_hentryp[ii].key, "Set-Cookie") == 0) {
195       DBG(r, "REQ[%X] cookie=[%s:%s]", TO_ADDR(r), err_hentryp[ii].key, err_hentryp[ii].val);
196
197       char* key;
198       char* val;
199       char* buff;
200
201       char *pair = apr_psprintf(pool, "%s:%s", err_hentryp[ii].key, err_hentryp[ii].val);
202       if (check_valid_cookie_attribute_expires_only(r, pair)) {
203         buff = apr_pstrdup(pool, err_hentryp[ii].val);
204         val = strchr(buff, '=');
205         if (val) {
206           key = buff;
207           *val++ = 0;
208           apr_table_set(new_cookie_table, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
209           if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
210         }
211         has_cookie = 1;
212       }
213     }
214   }
215 #if 0
216   apr_table_unset(r->headers_out, "Set-Cookie");
217   apr_table_unset(r->err_headers_out, "Set-Cookie");
218 #endif
219
220   if (! has_refer) {
221     apr_uri_parse(pool,r->uri, &parsed_uri);
222     refer_string = apr_psprintf(pool, 
223                                 "%s://%s%s", 
224                                 chxj_run_http_scheme(r),
225                                 r->hostname,
226                                 apr_uri_unparse(pool,
227                                                 &parsed_uri,
228                                                 APR_URI_UNP_OMITSITEPART));
229     if (r->args && strlen(r->args)) {
230       refer_string = apr_pstrcat(pool, refer_string, "?", r->args, NULL);
231     }
232     apr_table_setn(new_cookie_table, REFERER_COOKIE_KEY, refer_string);
233     DBG(r, "REQ[%X] ADD REFER[%s]", TO_ADDR(r),refer_string);
234     has_cookie++;
235   }
236
237
238   /*
239    * check input parameters
240    */
241   old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
242   if (old_cookie_id) {
243     old_cookie = chxj_load_cookie(r, old_cookie_id); 
244     if (old_cookie && old_cookie->cookie_headers) {
245       hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
246       for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
247         if (hentryp && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
248           apr_table_add(new_cookie_table, apr_pstrdup(pool, hentryp[ii].key), apr_pstrdup(pool, hentryp[ii].val));
249         }
250       }
251       if (has_cookie) {
252         chxj_delete_cookie(r,        old_cookie_id);
253         chxj_delete_cookie_expire(r, old_cookie_id);
254       }
255     }
256   }
257
258
259
260   if (! has_cookie) {
261     DBG(r,"REQ[%X] end %s() (no cookie)",TO_ADDR(r),__func__);
262     return NULL;
263   }
264
265   /*
266    * create val
267    */
268   cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
269   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
270   apr_size_t store_string_len = 0;
271   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
272     if (ii) store_string_len++;
273     store_string_len += (strlen(hentryp[ii].key) + strlen(hentryp[ii].val) + 1);
274   }
275   store_string = apr_palloc(pool, store_string_len + 1);
276   memset(store_string, 0, store_string_len + 1);
277   apr_size_t npos = 0;
278
279   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
280     if (ii) store_string[npos++] = '\n';
281     memcpy(&store_string[npos], hentryp[ii].key, strlen(hentryp[ii].key));
282     npos += strlen(hentryp[ii].key);
283     store_string[npos++] = '=';
284     memcpy(&store_string[npos], hentryp[ii].val, strlen(hentryp[ii].val));
285     npos += strlen(hentryp[ii].val);
286   }
287
288   if (old_cookie_id && IS_COOKIE_LAZY(dconf)) {
289     DBG(r, "REQ[%X] LAZY COOKIE save",TO_ADDR(r));
290     cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
291   }
292   else if (old_cookie_id && apr_table_get(r->headers_in, "X-Chxj-Cookie-No-Update")) {
293     DBG(r, "REQ[%X] NO UPDATE MODE",TO_ADDR(r));
294     cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
295   }
296   else {
297     if (old_cookie_id && apr_table_get(r->headers_in, "X-Chxj-Forward")) {
298       DBG(r, "REQ[%X] NO LAZY COOKIE(X-Chxj-Forward)  save",TO_ADDR(r));
299       cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
300     }
301     else {
302       DBG(r, "REQ[%X] NO LAZY COOKIE save",TO_ADDR(r));
303       cookie->cookie_id = alloc_cookie_id(r);
304     }
305   }
306
307   DBG(r,"REQ[%X] TYPE:[%d]", TO_ADDR(r), dconf->cookie_store_type);
308   DBG(r,"REQ[%X] STORE STRING:=======================================================", TO_ADDR(r));
309   DBG(r,"REQ[%X] [%s]", TO_ADDR(r), store_string);
310   DBG(r,"REQ[%X] =======================================================:STORE STRING", TO_ADDR(r));
311
312   {
313     int done_proc = 0;
314 #if defined(USE_MYSQL_COOKIE)
315     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
316       if (! chxj_save_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
317         ERR(r, "%s:%d faild: chxj_save_cookie_mysql() cookie_id:[%s]", APLOG_MARK,cookie->cookie_id);
318         cookie = NULL;
319         goto on_error;
320       }
321       done_proc = 1;
322     }
323 #endif
324 #if defined(USE_MEMCACHE_COOKIE)
325     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
326       if (! chxj_save_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
327         ERR(r, "%s:%d failed: chxj_save_cookie_memcache() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
328         cookie = NULL;
329         goto on_error;
330       }
331       done_proc = 1;
332     }
333 #endif
334     if (IS_COOKIE_STORE_DBM(dconf->cookie_store_type) || ! done_proc) {
335       if (! chxj_save_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
336         ERR(r, "%s:%d failed: chxj_save_cookie_dbm() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
337         cookie = NULL;
338         goto on_error;
339       }
340     }
341   }
342 #if 0
343   apr_table_unset(r->headers_out, "Set-Cookie");
344   apr_table_unset(r->err_headers_out, "Set-Cookie");
345 #endif
346
347   if (cookie) {
348     chxj_save_cookie_expire(r, cookie);
349   }
350
351 on_error:
352   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
353   return cookie;
354 }
355
356
357
358 /*
359  *
360  */
361 cookie_t *
362 chxj_update_cookie(request_rec *r, cookie_t *old_cookie)
363 {
364   int                 ii;
365   apr_array_header_t  *headers;
366   apr_table_entry_t   *hentryp;
367   char                *store_string;
368   mod_chxj_config     *dconf;
369   mod_chxj_req_config *req_conf;
370   chxjconvrule_entry  *entryp;
371   cookie_t            *cookie;
372
373
374   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
375   if (!old_cookie || ! old_cookie->cookie_headers || ! old_cookie->cookie_id) {
376     DBG(r,"REQ[%X] old_cookie is null",TO_ADDR(r));
377     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
378     return  NULL;
379   }
380
381   cookie = (cookie_t *)apr_palloc(r->pool, sizeof(cookie_t));
382   cookie->cookie_id = NULL;
383
384   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
385   req_conf = chxj_get_req_config(r);
386   /*-------------------------------------------------------------------------*/
387   /* already setup entryp if request_conf->user_agent is not null            */
388   /*-------------------------------------------------------------------------*/
389   if (req_conf->user_agent) {
390     entryp = req_conf->entryp;
391   }
392   else {
393     entryp = chxj_apply_convrule(r, dconf->convrules);
394   }
395   if (! entryp) {
396     DBG(r,"REQ[%X] no pattern",TO_ADDR(r));
397     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
398     return NULL;
399   }
400   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
401     DBG(r,"REQ[%X] CookieOff",TO_ADDR(r));
402     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
403     return NULL;
404   }
405
406   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
407   hentryp = (apr_table_entry_t*)headers->elts;
408
409   chxj_delete_cookie(r,        old_cookie->cookie_id);
410   chxj_delete_cookie_expire(r, old_cookie->cookie_id);
411
412   if (IS_COOKIE_LAZY(dconf)) {
413     DBG(r,"REQ[%X] LAZY MODE",TO_ADDR(r));
414     cookie->cookie_id = apr_pstrdup(r->pool, old_cookie->cookie_id);
415   }
416   else {
417     DBG(r,"REQ[%X] NO LAZY MODE",TO_ADDR(r));
418     cookie->cookie_id = alloc_cookie_id(r);
419   }
420
421   cookie->cookie_headers = old_cookie->cookie_headers;
422   store_string = apr_palloc(r->pool, 1);
423   store_string[0] = 0;
424   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
425
426   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
427     if (ii) store_string = apr_pstrcat(r->pool,
428                                store_string, 
429                                "\n",
430                                NULL);
431
432     DBG(r,"REQ[%X] OLD COOKIE VALUE=[%s][%s]",TO_ADDR(r), hentryp[ii].key, hentryp[ii].val);
433     store_string = apr_pstrcat(r->pool, 
434                                store_string, 
435                                hentryp[ii].key, 
436                                "=",
437                                hentryp[ii].val, 
438                                NULL);
439   }
440
441   {
442     int done_proc = 0;
443 #if defined(USE_MYSQL_COOKIE)
444     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
445       if (!chxj_update_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
446         ERR(r,"REQ[%X] failed: chxj_update_cookie_mysql() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
447         goto on_error;
448       }
449       done_proc = 1;
450     }
451 #endif
452
453 #if defined(USE_MEMCACHE_COOKIE)
454     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
455       if (! chxj_update_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
456         ERR(r, "REQ[%X] failed: chxj_update_cookie_memcache() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
457         goto on_error;
458       }
459       done_proc = 1;
460     }
461 #endif
462     if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
463       if (! chxj_update_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
464         ERR(r, "REQ[%X] failed: chxj_update_cookie_dbm() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
465         goto on_error;
466       }
467     }
468   }
469
470   chxj_save_cookie_expire(r, cookie);
471
472   apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
473
474
475 on_error:
476   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
477   return cookie;
478 }
479
480
481 /*
482  *
483  * @return loaded data.
484  */
485 cookie_t *
486 chxj_load_cookie(request_rec *r, char *cookie_id)
487 {
488   mod_chxj_config         *dconf;
489   mod_chxj_req_config     *req_conf;
490   chxjconvrule_entry      *entryp;
491   cookie_t                *cookie;
492   apr_table_t             *load_cookie_table;
493   char                    *load_string = NULL;
494   char                    *pstat;
495   char                    *key;
496   char                    *val;
497   char                    *pair;
498   char                    *header_cookie;
499
500   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
501   DBG(r,"REQ[%X] cookie_id=[%s]", TO_ADDR(r), cookie_id);
502   chxj_cookie_expire_gc(r);
503
504   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
505   cookie->cookie_headers = NULL;
506   cookie->cookie_id = chxj_url_decode(r->pool, apr_pstrdup(r->pool, cookie_id));
507   cookie->cookie_id = chxj_url_encode(r->pool, cookie->cookie_id);
508
509
510   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
511   req_conf = chxj_get_req_config(r);
512   /*-------------------------------------------------------------------------*/
513   /* already setup entryp if request_conf->user_agent is not null            */
514   /*-------------------------------------------------------------------------*/
515   if (req_conf->user_agent) {
516     entryp = req_conf->entryp;
517   }
518   else {
519     entryp = chxj_apply_convrule(r, dconf->convrules);
520   }
521   if (! entryp) {
522     DBG(r,"REQ[%X] pattern", TO_ADDR(r));
523     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
524     goto on_error0;
525   }
526   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT) && ! (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
527     DBG(r,"REQ[%X] CookieOff", TO_ADDR(r));
528     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
529     goto on_error0;
530   }
531   load_cookie_table = apr_table_make(r->pool, 0);
532
533   {
534     int done_proc = 0;
535 #if defined(USE_MYSQL_COOKIE)
536     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
537       if (! (load_string = chxj_load_cookie_mysql(r, dconf, cookie->cookie_id))) {
538         ERR(r, "REQ[%X] %s:%d failed: chxj_load_cookie_mysql() cookie_id:[%s]", TO_ADDR(r),APLOG_MARK, cookie_id);
539         goto on_error0;
540       }
541       done_proc = 1;
542     }
543 #endif
544 #if defined(USE_MEMCACHE_COOKIE)
545     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
546       if (! (load_string = chxj_load_cookie_memcache(r, dconf, cookie->cookie_id))) {
547         ERR(r, "REQ[%X] %s:%d failed: chxj_load_cookie_memcache() cookie_id:[%s]", TO_ADDR(r),APLOG_MARK,cookie_id);
548         goto on_error0;
549       }
550       done_proc = 1;
551     }
552 #endif
553     if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
554       if (! (load_string = chxj_load_cookie_dbm(r, dconf, cookie->cookie_id))) {
555         ERR(r, "REQ[%X] %s:%d failed: chxj_load_cookie_dbm() cookie_id:[%s]", TO_ADDR(r),APLOG_MARK,cookie_id);
556         goto on_error0;
557       }
558     }
559   }
560
561   if (load_string) {
562     DBG(r, "REQ[%X] load_string=[%s]", TO_ADDR(r), load_string);
563     header_cookie = apr_palloc(r->pool, 1);
564     header_cookie[0] = 0;
565     for (;;) {
566       char *tmp_sem;
567       char *tmp_pair;
568       pair = apr_strtok(load_string, "\n", &pstat);  
569       load_string = NULL;
570       if (!pair) break;
571
572       DBG(r,"REQ[%X] Cookie:[%s]", TO_ADDR(r), pair);
573
574       tmp_pair = apr_pstrdup(r->pool, pair);
575       val = strchr(tmp_pair, '=');
576       if (val) {
577         key = tmp_pair;
578         *val++ = 0;
579         apr_table_add(load_cookie_table, key, val);
580         DBG(r,"REQ[%X] ADD key:[%s] val:[%s]", TO_ADDR(r), key, val);
581       }
582       tmp_pair = apr_pstrdup(r->pool, pair);
583       tmp_sem = strchr(tmp_pair, ';'); 
584       if (tmp_sem)
585         *tmp_sem = '\0';
586
587       if (check_valid_cookie_attribute(r, pair)) {
588         if (strlen(header_cookie)) 
589           header_cookie = apr_pstrcat(r->pool, header_cookie, ";", NULL);
590   
591         header_cookie = apr_pstrcat(r->pool, header_cookie, tmp_pair, NULL);
592       }
593     }
594     if (strlen(header_cookie)) {
595       DBG(r,"REQ[%X] ADD COOKIE to REQUEST HEADER:[%s]", TO_ADDR(r), header_cookie);
596       apr_table_add(r->headers_in, "Cookie", header_cookie);
597     }
598   
599     cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
600
601     if (apr_table_get(r->headers_in, "referer") == NULL) {
602       apr_table_setn(r->headers_in, 
603                      "referer",
604                      apr_table_get(load_cookie_table, REFERER_COOKIE_KEY));
605     }
606   
607     /*
608      * save cookie_id to request header.
609      */
610     apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
611   }
612
613   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
614   return cookie;
615
616
617 on_error0:
618
619   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
620   return NULL;
621 }
622
623 static int
624 check_valid_cookie_attribute(request_rec *r, const char *value)
625 {
626   char *pstat;
627   char *pair;
628   char *first_pair;
629   char *domain_pair;
630   char *path_pair;
631   char *expire_pair;
632   char *secure_pair;
633   char *p;
634
635   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
636   DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r),value);
637
638   domain_pair = path_pair = expire_pair = secure_pair = NULL;
639   p = apr_pstrdup(r->pool, value);
640
641   /* pass first pair */
642   first_pair = apr_strtok(p, ";", &pstat);  
643
644   for (;;) {
645     pair = apr_strtok(NULL, ";", &pstat);
646     if (! pair) break;
647     pair = qs_trim_string(r->pool, pair);
648     if (STRNCASEEQ('d','D',"domain", pair, sizeof("domain")-1)) {
649       domain_pair = apr_pstrdup(r->pool, pair);
650     }
651     else if (STRNCASEEQ('p','P',"path", pair, sizeof("path")-1)) {
652       path_pair = apr_pstrdup(r->pool, pair);
653     }
654     else if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
655       expire_pair = apr_pstrdup(r->pool, pair);
656     }
657     else if (STRNCASEEQ('s','S',"secure", pair, sizeof("secure")-1)) {
658       secure_pair = apr_pstrdup(r->pool, pair);
659     }
660   }
661
662   if (domain_pair) {
663     if (!valid_domain(r, domain_pair)) {
664       DBG(r,"REQ[%X] invalid domain. domain_pair:[%s]", TO_ADDR(r),domain_pair);
665       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
666       return CHXJ_FALSE;
667     }
668   }
669   if (path_pair) {
670     if (!valid_path(r, path_pair)) {
671       DBG(r,"REQ[%X] invalid path. path_pair:[%s]", TO_ADDR(r),path_pair);
672       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
673       return CHXJ_FALSE;
674     }
675   }
676   if (expire_pair) {
677     if (!valid_expires(r, expire_pair)) {
678       DBG(r,"REQ[%X] invalid expire. expire_pair:[%s]", TO_ADDR(r),expire_pair);
679       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
680       return CHXJ_FALSE;
681     }
682   }
683   if (secure_pair) {
684     if (!valid_secure(r, secure_pair)) {
685       DBG(r,"REQ[%X] invalid secure. secure_pair:[%s]", TO_ADDR(r),secure_pair);
686       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
687       return CHXJ_FALSE;
688     }
689   }
690   DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r),value);
691   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
692   return CHXJ_TRUE;
693 }
694
695
696 static int
697 check_valid_cookie_attribute_expires_only(request_rec *r, const char *value)
698 {
699   char *pstat;
700   char *pair;
701   char *first_pair;
702   char *expire_pair = NULL;
703   char *p;
704
705   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
706   DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
707
708   expire_pair = NULL;
709   p = apr_pstrdup(r->pool, value);
710
711   /* pass first pair */
712   first_pair = apr_strtok(p, ";", &pstat);
713
714   for (;;) {
715     pair = apr_strtok(NULL, ";", &pstat);
716     if (! pair) break;
717     pair = qs_trim_string(r->pool, pair);
718     if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
719       expire_pair = apr_pstrdup(r->pool, pair);
720     }
721   }
722
723   if (expire_pair) {
724     if (!valid_expires(r, expire_pair)) {
725       DBG(r,"REQ[%X] invalid expire. expire_pair:[%s]", TO_ADDR(r), expire_pair);
726       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
727       return CHXJ_FALSE;
728     }
729   }
730   DBG(r,"REQ[%X] value:[%s]",TO_ADDR(r), value);
731   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
732   return CHXJ_TRUE;
733 }
734
735
736 static int
737 valid_domain(request_rec *r, const char *value)
738 {
739   int  len;
740   char *name;
741   char *val;
742   char *pstat;
743   char *p = apr_pstrdup(r->pool, value);
744   char *host = (char *)apr_table_get(r->headers_in, HTTP_HOST);
745
746   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
747   DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
748   if (!host) {
749     DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
750     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
751     return CHXJ_TRUE;
752   }
753   DBG(r, "REQ[%X] host:[%s]", TO_ADDR(r), host);
754   host = s_cut_until_end_hostname(r, apr_pstrdup(r->pool, host));
755   DBG(r, "REQ[%X] host:[%s](after s_cut_until_end_hostname())", TO_ADDR(r), host);
756
757   name = apr_strtok(p,"=", &pstat);
758   name = qs_trim_string(r->pool, name);
759   val = apr_strtok(NULL, "=", &pstat);
760   val = qs_trim_string(r->pool, val);
761   len = strlen(host);
762   if (len) {
763     if (chxj_strcasenrcmp(r->pool, host, val, strlen(val))) {
764       DBG(r,"REQ[%X] not match domain. host domain:[%s] vs value:[%s]", TO_ADDR(r), host, val);
765       DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
766       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
767       return CHXJ_FALSE;
768     }
769   }
770   DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
771   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
772   return CHXJ_TRUE;
773 }
774
775
776 static int
777 valid_path(request_rec *r, const char *value)
778 {
779   char *p = apr_pstrdup(r->pool, value);
780   char *uri;
781   char *tmp;
782   char *name;
783   char *val;
784   char *pstat;
785
786   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
787   DBG(r,"REQ[%X] unparsed_uri:[%s] value:[%s]", TO_ADDR(r),r->unparsed_uri, value);
788   if (chxj_starts_with(r->unparsed_uri, "http://")) {
789     uri = strchr(&r->unparsed_uri[sizeof("http://")], '/');
790     if (uri != NULL) {
791       uri = apr_pstrdup(r->pool, uri);
792     }
793   }
794   else if (chxj_starts_with(r->unparsed_uri, "https://")) {
795     uri = strchr(&r->unparsed_uri[sizeof("https://")], '/');
796     if (uri != NULL) {
797       uri = apr_pstrdup(r->pool, uri);
798     }
799   }
800   else if (chxj_starts_with(r->unparsed_uri, "/")) {
801     uri = apr_pstrdup(r->pool, r->unparsed_uri);
802   }
803   else {
804     uri = apr_pstrdup(r->pool, "/");
805   }
806   
807   if ((tmp = strchr(uri, '?'))) {
808     *tmp = '\0';
809   }
810   DBG(r,"REQ[%X] uri=[%s]", TO_ADDR(r),uri);
811   name = apr_strtok(p, "=", &pstat);
812   val = apr_strtok(NULL, "=", &pstat);
813   name = qs_trim_string(r->pool, name);
814   val = qs_trim_string(r->pool, val);
815   DBG(r,"REQ[%X] name=[%s] val=[%s]", TO_ADDR(r),name, val);
816   
817   DBG(r, "REQ[%X] val:[%s] vs uri:[%s]", TO_ADDR(r),val, uri);
818   if (! chxj_starts_with(uri, val)) {
819     DBG(r,"REQ[%X] unparsed_uri:[%s] value:[%s] (false)",TO_ADDR(r), r->unparsed_uri, value);
820     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
821     return CHXJ_FALSE;
822   }
823   DBG(r,"REQ[%X] unparsed_uri:[%s] value:[%s] (true)", TO_ADDR(r),r->unparsed_uri, value);
824   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
825   return CHXJ_TRUE;
826 }
827
828
829 static int
830 valid_expires(request_rec *r, const char *value)
831 {
832   char       *name;
833   char       *val;
834   char       *p = apr_pstrdup(r->pool, value);
835   char       *pstat;
836   apr_time_t expires;
837   apr_time_t now;
838
839   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
840   DBG(r,"REQ[%X] value:[%s]",TO_ADDR(r),value);
841   name = apr_strtok(p, "=", &pstat);
842   val  = apr_strtok(NULL, "=", &pstat);
843   DBG(r,"REQ[%X] name=[%s] val=[%s]", TO_ADDR(r),name, val);
844   now = apr_time_now();
845   expires = chxj_parse_cookie_expires(val);
846   if (expires < now) {
847     DBG(r,"REQ[%X] value:[%s] (expired)", TO_ADDR(r),value);
848     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
849     return CHXJ_FALSE;
850   }
851   
852   DBG(r,"REQ[%X] value:[%s] (non expired)", TO_ADDR(r),value);
853   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
854   return CHXJ_TRUE;
855 }
856
857
858 static int
859 valid_secure(request_rec *r, const char *value)
860 {
861   const char *scheme;
862   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
863   DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r),value);
864   scheme = chxj_apache_run_http_scheme(r);
865   if (strcasecmp("https", scheme)) {
866     DBG(r,"REQ[%X] value:[%s] (non secure)", TO_ADDR(r),value);
867     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
868     return CHXJ_FALSE;
869   }
870   DBG(r,"REQ[%X] value:[%s] (secure)", TO_ADDR(r),value);
871   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
872   return CHXJ_TRUE;
873 }
874
875
876 char *
877 chxj_add_cookie_parameter(request_rec *r, char *value, cookie_t *cookie)
878 {
879   char *qs;
880   char *dst;
881   char *name = "";
882
883   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
884   DBG(r,"REQ[%X] cookie_id=[%s]", TO_ADDR(r), (cookie) ? cookie->cookie_id : NULL);
885
886   dst = apr_pstrdup(r->pool, value);
887
888   if (!cookie)
889     goto on_error;
890
891   if (!cookie->cookie_id)
892     goto on_error;
893
894   if (chxj_cookie_check_host(r, value) != 0) {
895     DBG(r,"REQ[%X] (check host)", TO_ADDR(r));
896     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
897     goto on_error;
898   }
899
900   qs = strchr(dst, '#');
901   if (qs) {
902     name = apr_pstrdup(r->pool, qs);
903     *qs = 0;
904   }
905
906   qs = strchr(dst, '?');
907   if (qs) {
908     char *sv_qs = qs;
909     qs = chxj_delete_chxj_cc_param(r, ++qs);
910     DBG(r, "REQ[%X] qs:[%s]",TO_ADDR(r), qs);
911     *sv_qs = 0;
912     if (qs && strlen(qs)) {
913       dst = apr_psprintf(r->pool, "%s?%s", dst, qs);
914     }
915   }
916   if (qs) {
917     dst = apr_psprintf(r->pool, "%s&%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
918   }
919   else {
920     dst = apr_psprintf(r->pool, "%s?%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
921   }
922
923   DBG(r,"REQ[%X] dst=[%s]", TO_ADDR(r), dst);
924   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
925
926   return dst;
927
928 on_error:
929   DBG(r,"REQ[%X] (on_error)", TO_ADDR(r));
930   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
931   return dst;
932 }
933
934
935 char *
936 chxj_add_cookie_no_update_parameter(request_rec *r, char *value, int xmlflag)
937 {
938   char *qs;
939   char *dst;
940   char *name = "";
941
942   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
943
944   if (! value || ! *value) {
945     DBG(r,"REQ[%X] (void value)", TO_ADDR(r));
946     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
947     return apr_pstrdup(r->pool, "");
948   }
949
950   dst = apr_pstrdup(r->pool, value);
951
952   if (chxj_cookie_check_host(r, value) != 0) {
953     DBG(r,"REQ[%X] (check host)", TO_ADDR(r));
954     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
955     goto on_error;
956   }
957
958   qs = strchr(dst, '#');
959   if (qs) {
960     name = apr_pstrdup(r->pool, qs);
961     *qs = 0;
962   }
963   char *amp = "&";
964   if (xmlflag) {
965     amp = "&amp;";
966   }
967   dst = apr_psprintf(r->pool, "%s%s%s=true%s", dst, (strchr(dst,'?')) ? amp : "?",CHXJ_COOKIE_NOUPDATE_PARAM, name);
968   DBG(r,"REQ[%X] dst=[%s]", TO_ADDR(r), dst);
969   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
970   return dst;
971
972 on_error:
973   DBG(r,"REQ[%X] (on_error)", TO_ADDR(r));
974   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
975   return dst;
976 }
977
978
979 int
980 chxj_cookie_check_host(request_rec *r, char *value) 
981 {
982   char *hostnm;
983   mod_chxj_config *dconf;
984
985   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
986   DBG(r,"REQ[%X] hostname=[%s] vs Location:[%s]", TO_ADDR(r), r->hostname, value);
987
988   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
989
990   hostnm = s_get_hostname_from_url(r, value);
991   if (hostnm) {
992     if (dconf->allowed_cookie_domain) {
993       DBG(r, "REQ[%X] allowed_domain[%s] vs Location:[%s]", TO_ADDR(r), dconf->allowed_cookie_domain, value);
994       if (chxj_strcasenrcmp(r->pool, hostnm, dconf->allowed_cookie_domain, strlen(dconf->allowed_cookie_domain))) {
995         DBG(r,"REQ[%X] (false/allowed_domain)", TO_ADDR(r));
996         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
997         return 1;
998       }
999       else {
1000         DBG(r,"REQ[%X] (true/allowed_domain)", TO_ADDR(r));
1001         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1002         return 0;
1003       }
1004     }
1005     else {
1006       if (strcasecmp(hostnm, r->hostname) == 0) {
1007         DBG(r,"REQ[%X] (true)", TO_ADDR(r));
1008         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1009         return 0;
1010       }
1011       else {
1012         DBG(r,"REQ[%X] (false)", TO_ADDR(r));
1013         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1014         return 1;
1015       }
1016     }
1017   }
1018   DBG(r,"REQ[%X] (true)", TO_ADDR(r));
1019   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1020   return 0;
1021 }
1022
1023
1024 static char *
1025 s_get_hostname_from_url(request_rec *r, char *value)
1026 {
1027   if (!value) 
1028     return NULL; 
1029
1030   if (strncasecmp(value, "http://",  7) == 0 )
1031     return s_cut_until_end_hostname(r, &value[7]);
1032
1033   if (strncasecmp(value, "https://", 8) == 0)
1034     return s_cut_until_end_hostname(r, &value[8]);
1035
1036   return NULL;
1037 }
1038
1039
1040 static char *
1041 s_cut_until_end_hostname(request_rec *r, char *value)
1042 {
1043   char *sp;
1044   char *hostnm;
1045
1046   hostnm = sp = apr_pstrdup(r->pool, value);
1047   for (;*sp; sp++) {
1048     if (*sp == '/'|| *sp == '?' || *sp == ':') {
1049       *sp = '\0';
1050       break;
1051     }
1052   }
1053   return hostnm;
1054 }
1055
1056
1057
1058 void
1059 chxj_delete_cookie(request_rec *r, const char *cookie_id)
1060 {
1061   int done_proc = 0;
1062   mod_chxj_config *dconf;
1063
1064   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1065   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1066
1067 #if defined(USE_MYSQL_COOKIE)
1068   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1069     if (! chxj_delete_cookie_mysql(r, dconf, cookie_id)) {
1070       ERR(r,"REQ[%X] failed: chxj_delete_cookie_mysql() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1071       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1072       return;
1073     }
1074     done_proc = 1;
1075   }
1076 #endif
1077 #if defined(USE_MEMCACHE_COOKIE)
1078   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1079     if (! chxj_delete_cookie_memcache(r, dconf, cookie_id)) {
1080       ERR(r,"REQ[%X] failed: chxj_delete_cookie_memcache() cookie_id:[%s]", TO_ADDR(r), cookie_id);
1081       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1082       return;
1083     }
1084     done_proc = 1;
1085   }
1086 #endif
1087   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1088     if (! chxj_delete_cookie_dbm(r, dconf, cookie_id)) {
1089       ERR(r,"REQ[%X] failed: chxj_delete_cookie_dbm() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1090       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1091       return;
1092     }
1093   }
1094
1095   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1096 }
1097
1098
1099 /*
1100  *
1101  */
1102 void
1103 chxj_save_cookie_expire(request_rec *r, cookie_t *cookie)
1104 {
1105   int done_proc = 0;
1106   mod_chxj_config         *dconf;
1107
1108   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1109   if (!cookie) {
1110     DBG(r,"REQ[%X] cookie is NULL",TO_ADDR(r));
1111     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1112     return;
1113   }
1114   if (!cookie->cookie_id) {
1115     DBG(r,"REQ[%X] cookie->cookie_id is NULL",TO_ADDR(r));
1116     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1117     return;
1118   }
1119
1120   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1121   if (!dconf) {
1122     DBG(r,"REQ[%X] dconf is NULL",TO_ADDR(r));
1123     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1124     return;
1125   }
1126
1127 #if defined(USE_MYSQL_COOKIE)
1128   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1129     if (! chxj_save_cookie_expire_mysql(r, dconf, cookie->cookie_id)) {
1130       ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_mysql() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1131       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1132       return;
1133     }
1134     done_proc = 1;
1135   }
1136 #endif
1137 #if defined(USE_MEMCACHE_COOKIE)
1138   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1139     if (! chxj_save_cookie_expire_memcache(r, dconf, cookie->cookie_id)) {
1140       ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_memcache() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1141       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1142       return;
1143     }
1144     done_proc = 1;
1145   }
1146 #endif
1147   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1148     if (! chxj_save_cookie_expire_dbm(r, dconf, cookie->cookie_id)) {
1149       ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_dbm() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1150       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1151       return;
1152     }
1153   }
1154
1155   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1156 }
1157
1158
1159 void
1160 chxj_delete_cookie_expire(request_rec *r, char *cookie_id)
1161 {
1162   int done_proc = 0;
1163   mod_chxj_config *dconf;
1164
1165   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1166
1167   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1168
1169 #if defined(USE_MYSQL_COOKIE)
1170   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1171     if (! chxj_delete_cookie_expire_mysql(r, dconf, cookie_id)) {
1172       ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_mysql() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1173       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1174       return;
1175     }
1176     done_proc = 1;
1177   }
1178 #endif
1179 #if defined(USE_MEMCACHE_COOKIE)
1180   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1181     if (!chxj_delete_cookie_expire_memcache(r, dconf, cookie_id)) {
1182       ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_memcache() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1183       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1184       return;
1185     } 
1186     done_proc = 1;
1187   }
1188 #endif
1189   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1190     if (!chxj_delete_cookie_expire_dbm(r, dconf, cookie_id)) {
1191       ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_dbm() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1192       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1193       return;
1194     } 
1195   }
1196
1197   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1198 }
1199
1200
1201 void
1202 chxj_cookie_expire_gc(request_rec *r)
1203 {
1204   mod_chxj_config   *dconf;
1205   int done_proc = 0;
1206
1207   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1208
1209   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1210 #if defined(USE_MYSQL_COOKIE)
1211   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1212     if (! chxj_cookie_expire_gc_mysql(r, dconf)) {
1213       ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_mysql()", TO_ADDR(r),APLOG_MARK);
1214       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1215       return;
1216     }
1217     done_proc = 1;
1218   } 
1219 #endif
1220 #if defined(USE_MEMCACHE_COOKIE)
1221   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1222     if (! chxj_cookie_expire_gc_memcache(r, dconf)) {
1223       ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_memcache()", TO_ADDR(r),APLOG_MARK);
1224       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1225       return;
1226     }
1227     done_proc = 1;
1228   } 
1229 #endif
1230   if (!done_proc) {
1231     if (! chxj_cookie_expire_gc_dbm(r, dconf)) {
1232       ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_dbm()", TO_ADDR(r),APLOG_MARK);
1233       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1234       return;
1235     }
1236   }
1237   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1238 }
1239
1240 apr_time_t
1241 chxj_parse_cookie_expires(const char *s)
1242 {
1243   if (!s) return (apr_time_t)0;
1244   return apr_date_parse_rfc(s);
1245 }
1246
1247
1248 cookie_lock_t *
1249 __chxj_cookie_lock(request_rec *r, const char *filename, int line)
1250 {
1251   mod_chxj_config *dconf;
1252   apr_status_t rv;
1253   int done_proc = 0;
1254   cookie_lock_t *ret = NULL;
1255
1256   DBG(r,"REQ[%X] start %s() call from %s:%d",TO_ADDR(r),__func__, filename,line);
1257   if ((rv = apr_proc_mutex_lock(global_cookie_mutex)) != APR_SUCCESS) {
1258     char errstr[255];
1259     ERR(r,"REQ[%X] %s:%d apr_proc_mutex_lock failure.(%d:%s)", TO_ADDR(r),APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1260     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1261     return NULL;
1262   }
1263   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1264 #if defined(USE_MYSQL_COOKIE)
1265   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1266     if (! chxj_cookie_lock_mysql(r, dconf)) {
1267       ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_mysql()", TO_ADDR(r),APLOG_MARK);
1268       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1269       return NULL;
1270     }
1271     done_proc = 1;
1272     ret = apr_palloc(r->pool, sizeof(*ret));
1273     memset(ret, 0, sizeof(*ret));
1274   }
1275 #endif
1276 #if defined(USE_MEMCACHE_COOKIE)
1277   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1278     if (! chxj_cookie_lock_memcache(r, dconf)) {
1279       ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_memcache()", TO_ADDR(r),APLOG_MARK);
1280       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1281       return NULL;
1282     }
1283     done_proc = 1;
1284     ret = apr_palloc(r->pool, sizeof(*ret));
1285     memset(ret, 0, sizeof(*ret));
1286   }
1287 #endif
1288   if (!done_proc) {
1289     if (!(ret = chxj_cookie_lock_dbm(r, dconf))) {
1290       ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_dbm()", TO_ADDR(r),APLOG_MARK);
1291       DBG(r,"REQ[%X] end %s() call from %s:%d",TO_ADDR(r),__func__,filename,line);
1292       return NULL;
1293     }
1294   }
1295   DBG(r,"REQ[%X] end %s() call from %s:%d",TO_ADDR(r),__func__,filename,line);
1296   return ret;
1297 }
1298
1299
1300 int
1301 __chxj_cookie_unlock(request_rec *r, cookie_lock_t *lock, const char *filename, int line)
1302 {
1303   mod_chxj_config *dconf;
1304   int done_proc = 0;
1305   apr_status_t rv;
1306   int rtn = 1;
1307
1308   DBG(r,"REQ[%X] start %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1309
1310   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1311 #if defined(USE_MYSQL_COOKIE)
1312   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1313     if (! chxj_cookie_unlock_mysql(r, dconf)) {
1314       ERR(r,"REQ[%X] failed: chxj_cookie_unlock_mysql()",TO_ADDR(r));
1315       rtn = 0;
1316       goto end_chxj_cookie_unlock;
1317     }
1318     done_proc = 1;
1319   }
1320 #endif
1321 #if defined(USE_MEMCACHE_COOKIE)
1322   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1323     if (! chxj_cookie_unlock_memcache(r, dconf)) {
1324       ERR(r,"REQ[%X] failed: chxj_cookie_unlock_memcache()",TO_ADDR(r));
1325       rtn = 0;
1326       goto end_chxj_cookie_unlock;
1327     }
1328     done_proc = 1;
1329   }
1330 #endif
1331   if (!done_proc) {
1332     if (! chxj_cookie_unlock_dbm(r, lock, dconf)) {
1333       ERR(r,"REQ[%X] failed: chxj_cookie_unlock_dbm()",TO_ADDR(r));
1334       rtn = 0;
1335       goto end_chxj_cookie_unlock;
1336     }
1337   }
1338 end_chxj_cookie_unlock:
1339   if ((rv = apr_proc_mutex_unlock(global_cookie_mutex)) != APR_SUCCESS) {
1340     char errstr[255];
1341     ERR(r,"REQ[%X] %s:%d apr_proc_mutex_unlock failure.(%d:%s)", TO_ADDR(r),APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1342     DBG(r,"REQ[%X] end %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1343     return 0;
1344   }
1345   DBG(r,"REQ[%X] end %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1346
1347   return rtn;
1348 }
1349
1350
1351 #include "chxj_encoding.h"
1352 char *
1353 s_convert_a_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1354 {
1355   apr_pool_t *pool;
1356   ap_regex_t *regexp = NULL;
1357   int   nowpos = 0;
1358   Doc       doc;
1359   char *dst = NULL;
1360
1361   apr_pool_create(&pool, r->pool);
1362   regexp = ap_pregcomp(pool, "(<a[^>]*>)", AP_REG_EXTENDED|AP_REG_ICASE);
1363   doc.r = r;
1364   qs_init_malloc(&doc);
1365   qs_init_root_node(&doc);
1366
1367   while(1) {
1368     ap_regmatch_t        match[10];
1369     if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1370       apr_size_t plen = match[1].rm_so;
1371       if (plen > 0) {
1372         char *tmpstr = apr_palloc(pool, plen + 1);
1373         memset(tmpstr, 0, plen + 1);
1374         memcpy(tmpstr, &s[nowpos], plen);
1375         dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1376       }
1377       else {
1378         plen = 0;
1379       }
1380       char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1381       if (matchstr) {
1382         Node *node = qs_parse_tag(&doc, matchstr, strlen(matchstr) - 1);
1383         Attr *attr;
1384
1385         DBG(r,"REQ[%X] matchstr:[%s]", TO_ADDR(r),matchstr);
1386         dst = apr_pstrcat(pool, (dst) ? dst : "", "<a ", NULL);
1387         for (attr = qs_get_attr(&doc,node);
1388              attr;
1389              attr = qs_get_next_attr(&doc,attr)) {
1390           char *name  = qs_get_attr_name(&doc,attr);
1391           char *value = qs_get_attr_value(&doc,attr);
1392           DBG(r,"REQ[%X] name:[%s] value=[%s]",TO_ADDR(r), name, value);
1393           if (STRCASEEQ('h', 'H', "href", name)
1394               && ! chxj_starts_with(value, "mailto:") 
1395               && ! chxj_starts_with(value, "tel:")) {
1396             char *flgp = strchr(value, '#');
1397             char *flgsv = NULL;
1398             if (flgp) {
1399               int flgl = strlen(flgp);
1400               flgsv = apr_palloc(pool, flgl+1);
1401               memset(flgsv, 0, flgl + 1);
1402               memcpy(flgsv, flgp, flgl);
1403               *flgp = 0;
1404             }
1405             if (strchr(value, '?') != 0) {
1406               value = apr_pstrcat(pool, value, "&_chxj_cc=", cookie->cookie_id, NULL);
1407             }
1408             else {
1409               value = apr_pstrcat(pool, value, "?_chxj_cc=", cookie->cookie_id, NULL);
1410             }
1411             if (flgsv) {
1412               value = apr_pstrcat(pool, value, flgsv, NULL);
1413             }
1414             dst = apr_pstrcat(pool, (dst) ? dst : "", "href='", value, "' ", NULL);
1415           }
1416           else {
1417             dst = apr_pstrcat(pool, (dst) ? dst : "", name, "='", value, "' ", NULL);
1418           }
1419         }
1420         dst = apr_pstrcat(pool, (dst) ? dst : "", ">", NULL);
1421         plen += strlen(matchstr);
1422       }
1423       nowpos += plen;
1424     }
1425     else {
1426       break;
1427     }
1428   }
1429
1430   if ((apr_size_t)nowpos < *len) {
1431     apr_size_t plen = *len - nowpos;
1432     char *tmpstr = apr_palloc(pool, plen + 1);
1433     memset(tmpstr, 0, plen+1);
1434     memcpy(tmpstr, &s[nowpos], plen);
1435     dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1436   }
1437
1438   *len = strlen(dst);
1439   return dst;
1440 }
1441 char *
1442 s_convert_img_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1443 {
1444   apr_pool_t *pool;
1445   ap_regex_t *regexp = NULL;
1446   int   nowpos = 0;
1447   Doc       doc;
1448   char *dst = NULL;
1449
1450   apr_pool_create(&pool, r->pool);
1451   regexp = ap_pregcomp(pool, "(<img[^>]*>)", AP_REG_EXTENDED|AP_REG_ICASE);
1452   doc.r = r;
1453   qs_init_malloc(&doc);
1454   qs_init_root_node(&doc);
1455
1456   while(1) {
1457     ap_regmatch_t        match[10];
1458     if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1459       apr_size_t plen = match[1].rm_so;
1460       if (plen > 0) {
1461         char *tmpstr = apr_palloc(pool, plen + 1);
1462         memset(tmpstr, 0, plen + 1);
1463         memcpy(tmpstr, &s[nowpos], plen);
1464         dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1465       }
1466       else {
1467         plen = 0;
1468       }
1469       char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1470       if (matchstr) {
1471         Node *node = qs_parse_tag(&doc, matchstr, strlen(matchstr) - 1);
1472         Attr *attr;
1473
1474         DBG(r,"REQ[%X] matchstr:[%s]", TO_ADDR(r),matchstr);
1475         dst = apr_pstrcat(pool, (dst) ? dst : "", "<img ", NULL);
1476         for (attr = qs_get_attr(&doc,node);
1477              attr;
1478              attr = qs_get_next_attr(&doc,attr)) {
1479           char *name  = qs_get_attr_name(&doc,attr);
1480           char *value = qs_get_attr_value(&doc,attr);
1481           DBG(r,"REQ[%X] name:[%s] value=[%s]", TO_ADDR(r),name, value);
1482           if (STRCASEEQ('s', 'S', "src", name)) {
1483             if (strchr(value, '?') != 0) {
1484               value = apr_pstrcat(pool, value, "&_chxj_cc=", cookie->cookie_id, "&_chxj_nc=true", NULL);
1485             }
1486             else {
1487               value = apr_pstrcat(pool, value, "?_chxj_cc=", cookie->cookie_id, "&_chxj_nc=true", NULL);
1488             }
1489             dst = apr_pstrcat(pool, (dst) ? dst : "", "src='", value, "' ", NULL);
1490           }
1491           else {
1492             dst = apr_pstrcat(pool, (dst) ? dst : "", name, "='", value, "' ", NULL);
1493           }
1494         }
1495         dst = apr_pstrcat(pool, (dst) ? dst : "", "/>", NULL);
1496         plen += strlen(matchstr);
1497       }
1498       nowpos += plen;
1499     }
1500     else {
1501       break;
1502     }
1503   }
1504
1505   if ((apr_size_t)nowpos < *len) {
1506     apr_size_t plen = *len - nowpos;
1507     char *tmpstr = apr_palloc(pool, plen + 1);
1508     memset(tmpstr, 0, plen+1);
1509     memcpy(tmpstr, &s[nowpos], plen);
1510     dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1511   }
1512
1513   *len = strlen(dst);
1514   return dst;
1515 }
1516 char *
1517 s_convert_form_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1518 {
1519   apr_pool_t *pool;
1520   ap_regex_t *regexp = NULL;
1521   int   nowpos = 0;
1522   Doc       doc;
1523   char *dst = NULL;
1524   char *cookie_id;
1525
1526   apr_pool_create(&pool, r->pool);
1527   regexp = ap_pregcomp(pool, "(</form>)", AP_REG_EXTENDED|AP_REG_ICASE);
1528   doc.r = r;
1529   qs_init_malloc(&doc);
1530   qs_init_root_node(&doc);
1531   cookie_id = chxj_url_decode(pool, cookie->cookie_id);
1532
1533   while(1) {
1534     ap_regmatch_t        match[10];
1535     if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1536       apr_size_t plen = match[1].rm_so;
1537       if (plen > 0) {
1538         char *tmpstr = apr_palloc(pool, plen + 1);
1539         memset(tmpstr, 0, plen + 1);
1540         memcpy(tmpstr, &s[nowpos], plen);
1541         dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1542       }
1543       else {
1544         plen = 0;
1545       }
1546       char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1547       if (matchstr) {
1548         DBG(r,"REQ[%X] matchstr:[%s]",TO_ADDR(r),matchstr);
1549         dst = apr_pstrcat(pool, (dst) ? dst : "", "<input type='hidden' name='_chxj_cc' value='", cookie_id, "' />", matchstr, NULL);
1550         plen += strlen(matchstr);
1551       }
1552       nowpos += plen;
1553     }
1554     else {
1555       break;
1556     }
1557   }
1558
1559   if ((apr_size_t)nowpos < *len) {
1560     apr_size_t plen = *len - nowpos;
1561     char *tmpstr = apr_palloc(pool, plen + 1);
1562     memset(tmpstr, 0, plen + 1);
1563     memcpy(tmpstr, &s[nowpos], plen);
1564     dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1565   }
1566
1567   *len = strlen(dst);
1568   return dst;
1569 }
1570
1571 char *
1572 chxj_cookie_only_mode(request_rec *r, const char *src, apr_size_t *len, cookie_t* cookie)
1573 {
1574   char *s;
1575   char *result;
1576   char *dst = NULL;
1577
1578   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1579   s = chxj_encoding(r, src, len);
1580
1581   dst = s_convert_a_tag(r, s, len, cookie);
1582   dst = s_convert_img_tag(r, dst, len, cookie);
1583   dst = s_convert_form_tag(r, dst, len, cookie);
1584
1585   result = chxj_rencoding(r, dst, len, NULL);
1586   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1587   return result;
1588 }
1589 /*
1590  * vim:ts=2 et
1591  */