OSDN Git Service

* updated ChangeLog
[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     if (dst[0] == '\0') {
921       /* No adding cookie parameter if flagment only. 2011.06.22 */
922       dst = apr_psprintf(r->pool, "%s", name);
923     }
924     else {
925       dst = apr_psprintf(r->pool, "%s?%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
926     }
927   }
928
929   DBG(r,"REQ[%X] dst=[%s]", TO_ADDR(r), dst);
930   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
931
932   return dst;
933
934 on_error:
935   DBG(r,"REQ[%X] (on_error)", TO_ADDR(r));
936   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
937   return dst;
938 }
939
940
941 char *
942 chxj_add_cookie_no_update_parameter(request_rec *r, char *value, int xmlflag)
943 {
944   char *qs;
945   char *dst;
946   char *name = "";
947
948   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
949
950   if (! value || ! *value) {
951     DBG(r,"REQ[%X] (void value)", TO_ADDR(r));
952     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
953     return apr_pstrdup(r->pool, "");
954   }
955
956   dst = apr_pstrdup(r->pool, value);
957
958   if (chxj_cookie_check_host(r, value) != 0) {
959     DBG(r,"REQ[%X] (check host)", TO_ADDR(r));
960     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
961     goto on_error;
962   }
963
964   qs = strchr(dst, '#');
965   if (qs) {
966     name = apr_pstrdup(r->pool, qs);
967     *qs = 0;
968   }
969   char *amp = "&";
970   if (xmlflag) {
971     amp = "&amp;";
972   }
973   dst = apr_psprintf(r->pool, "%s%s%s=true%s", dst, (strchr(dst,'?')) ? amp : "?",CHXJ_COOKIE_NOUPDATE_PARAM, name);
974   DBG(r,"REQ[%X] dst=[%s]", TO_ADDR(r), dst);
975   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
976   return dst;
977
978 on_error:
979   DBG(r,"REQ[%X] (on_error)", TO_ADDR(r));
980   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
981   return dst;
982 }
983
984
985 int
986 chxj_cookie_check_host(request_rec *r, char *value) 
987 {
988   char *hostnm;
989   mod_chxj_config *dconf;
990
991   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
992   DBG(r,"REQ[%X] hostname=[%s] vs Location:[%s]", TO_ADDR(r), r->hostname, value);
993
994   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
995
996   hostnm = s_get_hostname_from_url(r, value);
997   if (hostnm) {
998     if (dconf->allowed_cookie_domain) {
999       DBG(r, "REQ[%X] allowed_domain[%s] vs Location:[%s]", TO_ADDR(r), dconf->allowed_cookie_domain, value);
1000       if (chxj_strcasenrcmp(r->pool, hostnm, dconf->allowed_cookie_domain, strlen(dconf->allowed_cookie_domain))) {
1001         DBG(r,"REQ[%X] (false/allowed_domain)", TO_ADDR(r));
1002         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1003         return 1;
1004       }
1005       else {
1006         DBG(r,"REQ[%X] (true/allowed_domain)", TO_ADDR(r));
1007         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1008         return 0;
1009       }
1010     }
1011     else {
1012       if (strcasecmp(hostnm, r->hostname) == 0) {
1013         DBG(r,"REQ[%X] (true)", TO_ADDR(r));
1014         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1015         return 0;
1016       }
1017       else {
1018         DBG(r,"REQ[%X] (false)", TO_ADDR(r));
1019         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1020         return 1;
1021       }
1022     }
1023   }
1024   DBG(r,"REQ[%X] (true)", TO_ADDR(r));
1025   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1026   return 0;
1027 }
1028
1029
1030 static char *
1031 s_get_hostname_from_url(request_rec *r, char *value)
1032 {
1033   if (!value) 
1034     return NULL; 
1035
1036   if (strncasecmp(value, "http://",  7) == 0 )
1037     return s_cut_until_end_hostname(r, &value[7]);
1038
1039   if (strncasecmp(value, "https://", 8) == 0)
1040     return s_cut_until_end_hostname(r, &value[8]);
1041
1042   return NULL;
1043 }
1044
1045
1046 static char *
1047 s_cut_until_end_hostname(request_rec *r, char *value)
1048 {
1049   char *sp;
1050   char *hostnm;
1051
1052   hostnm = sp = apr_pstrdup(r->pool, value);
1053   for (;*sp; sp++) {
1054     if (*sp == '/'|| *sp == '?' || *sp == ':') {
1055       *sp = '\0';
1056       break;
1057     }
1058   }
1059   return hostnm;
1060 }
1061
1062
1063
1064 void
1065 chxj_delete_cookie(request_rec *r, const char *cookie_id)
1066 {
1067   int done_proc = 0;
1068   mod_chxj_config *dconf;
1069
1070   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1071   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1072
1073 #if defined(USE_MYSQL_COOKIE)
1074   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1075     if (! chxj_delete_cookie_mysql(r, dconf, cookie_id)) {
1076       ERR(r,"REQ[%X] failed: chxj_delete_cookie_mysql() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1077       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1078       return;
1079     }
1080     done_proc = 1;
1081   }
1082 #endif
1083 #if defined(USE_MEMCACHE_COOKIE)
1084   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1085     if (! chxj_delete_cookie_memcache(r, dconf, cookie_id)) {
1086       ERR(r,"REQ[%X] failed: chxj_delete_cookie_memcache() cookie_id:[%s]", TO_ADDR(r), cookie_id);
1087       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1088       return;
1089     }
1090     done_proc = 1;
1091   }
1092 #endif
1093   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1094     if (! chxj_delete_cookie_dbm(r, dconf, cookie_id)) {
1095       ERR(r,"REQ[%X] failed: chxj_delete_cookie_dbm() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1096       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1097       return;
1098     }
1099   }
1100
1101   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1102 }
1103
1104
1105 /*
1106  *
1107  */
1108 void
1109 chxj_save_cookie_expire(request_rec *r, cookie_t *cookie)
1110 {
1111   int done_proc = 0;
1112   mod_chxj_config         *dconf;
1113
1114   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1115   if (!cookie) {
1116     DBG(r,"REQ[%X] cookie is NULL",TO_ADDR(r));
1117     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1118     return;
1119   }
1120   if (!cookie->cookie_id) {
1121     DBG(r,"REQ[%X] cookie->cookie_id is NULL",TO_ADDR(r));
1122     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1123     return;
1124   }
1125
1126   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1127   if (!dconf) {
1128     DBG(r,"REQ[%X] dconf is NULL",TO_ADDR(r));
1129     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1130     return;
1131   }
1132
1133 #if defined(USE_MYSQL_COOKIE)
1134   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1135     if (! chxj_save_cookie_expire_mysql(r, dconf, cookie->cookie_id)) {
1136       ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_mysql() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1137       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1138       return;
1139     }
1140     done_proc = 1;
1141   }
1142 #endif
1143 #if defined(USE_MEMCACHE_COOKIE)
1144   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1145     if (! chxj_save_cookie_expire_memcache(r, dconf, cookie->cookie_id)) {
1146       ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_memcache() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1147       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1148       return;
1149     }
1150     done_proc = 1;
1151   }
1152 #endif
1153   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1154     if (! chxj_save_cookie_expire_dbm(r, dconf, cookie->cookie_id)) {
1155       ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_dbm() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1156       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1157       return;
1158     }
1159   }
1160
1161   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1162 }
1163
1164
1165 void
1166 chxj_delete_cookie_expire(request_rec *r, char *cookie_id)
1167 {
1168   int done_proc = 0;
1169   mod_chxj_config *dconf;
1170
1171   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1172
1173   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1174
1175 #if defined(USE_MYSQL_COOKIE)
1176   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1177     if (! chxj_delete_cookie_expire_mysql(r, dconf, cookie_id)) {
1178       ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_mysql() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1179       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1180       return;
1181     }
1182     done_proc = 1;
1183   }
1184 #endif
1185 #if defined(USE_MEMCACHE_COOKIE)
1186   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1187     if (!chxj_delete_cookie_expire_memcache(r, dconf, cookie_id)) {
1188       ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_memcache() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1189       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1190       return;
1191     } 
1192     done_proc = 1;
1193   }
1194 #endif
1195   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1196     if (!chxj_delete_cookie_expire_dbm(r, dconf, cookie_id)) {
1197       ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_dbm() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1198       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1199       return;
1200     } 
1201   }
1202
1203   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1204 }
1205
1206
1207 void
1208 chxj_cookie_expire_gc(request_rec *r)
1209 {
1210   mod_chxj_config   *dconf;
1211   int done_proc = 0;
1212
1213   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
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_expire_gc_mysql(r, dconf)) {
1219       ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_mysql()", TO_ADDR(r),APLOG_MARK);
1220       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1221       return;
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_expire_gc_memcache(r, dconf)) {
1229       ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_memcache()", TO_ADDR(r),APLOG_MARK);
1230       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1231       return;
1232     }
1233     done_proc = 1;
1234   } 
1235 #endif
1236   if (!done_proc) {
1237     if (! chxj_cookie_expire_gc_dbm(r, dconf)) {
1238       ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_dbm()", TO_ADDR(r),APLOG_MARK);
1239       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1240       return;
1241     }
1242   }
1243   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1244 }
1245
1246 apr_time_t
1247 chxj_parse_cookie_expires(const char *s)
1248 {
1249   if (!s) return (apr_time_t)0;
1250   return apr_date_parse_rfc(s);
1251 }
1252
1253
1254 cookie_lock_t *
1255 __chxj_cookie_lock(request_rec *r, const char *filename, int line)
1256 {
1257   mod_chxj_config *dconf;
1258   apr_status_t rv;
1259   int done_proc = 0;
1260   cookie_lock_t *ret = NULL;
1261
1262   DBG(r,"REQ[%X] start %s() call from %s:%d",TO_ADDR(r),__func__, filename,line);
1263   if ((rv = apr_proc_mutex_lock(global_cookie_mutex)) != APR_SUCCESS) {
1264     char errstr[255];
1265     ERR(r,"REQ[%X] %s:%d apr_proc_mutex_lock failure.(%d:%s)", TO_ADDR(r),APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1266     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1267     return NULL;
1268   }
1269   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1270 #if defined(USE_MYSQL_COOKIE)
1271   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1272     if (! chxj_cookie_lock_mysql(r, dconf)) {
1273       ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_mysql()", TO_ADDR(r),APLOG_MARK);
1274       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1275       return NULL;
1276     }
1277     done_proc = 1;
1278     ret = apr_palloc(r->pool, sizeof(*ret));
1279     memset(ret, 0, sizeof(*ret));
1280   }
1281 #endif
1282 #if defined(USE_MEMCACHE_COOKIE)
1283   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1284     if (! chxj_cookie_lock_memcache(r, dconf)) {
1285       ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_memcache()", TO_ADDR(r),APLOG_MARK);
1286       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1287       return NULL;
1288     }
1289     done_proc = 1;
1290     ret = apr_palloc(r->pool, sizeof(*ret));
1291     memset(ret, 0, sizeof(*ret));
1292   }
1293 #endif
1294   if (!done_proc) {
1295     if (!(ret = chxj_cookie_lock_dbm(r, dconf))) {
1296       ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_dbm()", TO_ADDR(r),APLOG_MARK);
1297       DBG(r,"REQ[%X] end %s() call from %s:%d",TO_ADDR(r),__func__,filename,line);
1298       return NULL;
1299     }
1300   }
1301   DBG(r,"REQ[%X] end %s() call from %s:%d",TO_ADDR(r),__func__,filename,line);
1302   return ret;
1303 }
1304
1305
1306 int
1307 __chxj_cookie_unlock(request_rec *r, cookie_lock_t *lock, const char *filename, int line)
1308 {
1309   mod_chxj_config *dconf;
1310   int done_proc = 0;
1311   apr_status_t rv;
1312   int rtn = 1;
1313
1314   DBG(r,"REQ[%X] start %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1315
1316   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1317 #if defined(USE_MYSQL_COOKIE)
1318   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1319     if (! chxj_cookie_unlock_mysql(r, dconf)) {
1320       ERR(r,"REQ[%X] failed: chxj_cookie_unlock_mysql()",TO_ADDR(r));
1321       rtn = 0;
1322       goto end_chxj_cookie_unlock;
1323     }
1324     done_proc = 1;
1325   }
1326 #endif
1327 #if defined(USE_MEMCACHE_COOKIE)
1328   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1329     if (! chxj_cookie_unlock_memcache(r, dconf)) {
1330       ERR(r,"REQ[%X] failed: chxj_cookie_unlock_memcache()",TO_ADDR(r));
1331       rtn = 0;
1332       goto end_chxj_cookie_unlock;
1333     }
1334     done_proc = 1;
1335   }
1336 #endif
1337   if (!done_proc) {
1338     if (! chxj_cookie_unlock_dbm(r, lock, dconf)) {
1339       ERR(r,"REQ[%X] failed: chxj_cookie_unlock_dbm()",TO_ADDR(r));
1340       rtn = 0;
1341       goto end_chxj_cookie_unlock;
1342     }
1343   }
1344 end_chxj_cookie_unlock:
1345   if ((rv = apr_proc_mutex_unlock(global_cookie_mutex)) != APR_SUCCESS) {
1346     char errstr[255];
1347     ERR(r,"REQ[%X] %s:%d apr_proc_mutex_unlock failure.(%d:%s)", TO_ADDR(r),APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1348     DBG(r,"REQ[%X] end %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1349     return 0;
1350   }
1351   DBG(r,"REQ[%X] end %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1352
1353   return rtn;
1354 }
1355
1356
1357 #include "chxj_encoding.h"
1358 char *
1359 s_convert_a_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1360 {
1361   apr_pool_t *pool;
1362   ap_regex_t *regexp = NULL;
1363   int   nowpos = 0;
1364   Doc       doc;
1365   char *dst = NULL;
1366
1367   apr_pool_create(&pool, r->pool);
1368   regexp = ap_pregcomp(pool, "(<a[^>]*>)", AP_REG_EXTENDED|AP_REG_ICASE);
1369   doc.r = r;
1370   qs_init_malloc(&doc);
1371   qs_init_root_node(&doc);
1372
1373   while(1) {
1374     ap_regmatch_t        match[10];
1375     if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1376       apr_size_t plen = match[1].rm_so;
1377       if (plen > 0) {
1378         char *tmpstr = apr_palloc(pool, plen + 1);
1379         memset(tmpstr, 0, plen + 1);
1380         memcpy(tmpstr, &s[nowpos], plen);
1381         dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1382       }
1383       else {
1384         plen = 0;
1385       }
1386       char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1387       if (matchstr) {
1388         Node *node = qs_parse_tag(&doc, matchstr, strlen(matchstr) - 1);
1389         Attr *attr;
1390
1391         DBG(r,"REQ[%X] matchstr:[%s]", TO_ADDR(r),matchstr);
1392         dst = apr_pstrcat(pool, (dst) ? dst : "", "<a ", NULL);
1393         for (attr = qs_get_attr(&doc,node);
1394              attr;
1395              attr = qs_get_next_attr(&doc,attr)) {
1396           char *name  = qs_get_attr_name(&doc,attr);
1397           char *value = qs_get_attr_value(&doc,attr);
1398           DBG(r,"REQ[%X] name:[%s] value=[%s]",TO_ADDR(r), name, value);
1399           if (STRCASEEQ('h', 'H', "href", name)
1400               && ! chxj_starts_with(value, "mailto:") 
1401               && ! chxj_starts_with(value, "tel:")) {
1402             char *flgp = strchr(value, '#');
1403             char *flgsv = NULL;
1404             if (flgp) {
1405               int flgl = strlen(flgp);
1406               flgsv = apr_palloc(pool, flgl+1);
1407               memset(flgsv, 0, flgl + 1);
1408               memcpy(flgsv, flgp, flgl);
1409               *flgp = 0;
1410             }
1411             if (strchr(value, '?') != 0) {
1412               value = apr_pstrcat(pool, value, "&_chxj_cc=", cookie->cookie_id, NULL);
1413             }
1414             else {
1415               value = apr_pstrcat(pool, value, "?_chxj_cc=", cookie->cookie_id, NULL);
1416             }
1417             if (flgsv) {
1418               value = apr_pstrcat(pool, value, flgsv, NULL);
1419             }
1420             dst = apr_pstrcat(pool, (dst) ? dst : "", "href='", value, "' ", NULL);
1421           }
1422           else {
1423             dst = apr_pstrcat(pool, (dst) ? dst : "", name, "='", value, "' ", NULL);
1424           }
1425         }
1426         dst = apr_pstrcat(pool, (dst) ? dst : "", ">", NULL);
1427         plen += strlen(matchstr);
1428       }
1429       nowpos += plen;
1430     }
1431     else {
1432       break;
1433     }
1434   }
1435
1436   if ((apr_size_t)nowpos < *len) {
1437     apr_size_t plen = *len - nowpos;
1438     char *tmpstr = apr_palloc(pool, plen + 1);
1439     memset(tmpstr, 0, plen+1);
1440     memcpy(tmpstr, &s[nowpos], plen);
1441     dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1442   }
1443
1444   *len = strlen(dst);
1445   return dst;
1446 }
1447 char *
1448 s_convert_img_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1449 {
1450   apr_pool_t *pool;
1451   ap_regex_t *regexp = NULL;
1452   int   nowpos = 0;
1453   Doc       doc;
1454   char *dst = NULL;
1455
1456   apr_pool_create(&pool, r->pool);
1457   regexp = ap_pregcomp(pool, "(<img[^>]*>)", AP_REG_EXTENDED|AP_REG_ICASE);
1458   doc.r = r;
1459   qs_init_malloc(&doc);
1460   qs_init_root_node(&doc);
1461
1462   while(1) {
1463     ap_regmatch_t        match[10];
1464     if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1465       apr_size_t plen = match[1].rm_so;
1466       if (plen > 0) {
1467         char *tmpstr = apr_palloc(pool, plen + 1);
1468         memset(tmpstr, 0, plen + 1);
1469         memcpy(tmpstr, &s[nowpos], plen);
1470         dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1471       }
1472       else {
1473         plen = 0;
1474       }
1475       char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1476       if (matchstr) {
1477         Node *node = qs_parse_tag(&doc, matchstr, strlen(matchstr) - 1);
1478         Attr *attr;
1479
1480         DBG(r,"REQ[%X] matchstr:[%s]", TO_ADDR(r),matchstr);
1481         dst = apr_pstrcat(pool, (dst) ? dst : "", "<img ", NULL);
1482         for (attr = qs_get_attr(&doc,node);
1483              attr;
1484              attr = qs_get_next_attr(&doc,attr)) {
1485           char *name  = qs_get_attr_name(&doc,attr);
1486           char *value = qs_get_attr_value(&doc,attr);
1487           DBG(r,"REQ[%X] name:[%s] value=[%s]", TO_ADDR(r),name, value);
1488           if (STRCASEEQ('s', 'S', "src", name)) {
1489             if (strchr(value, '?') != 0) {
1490               value = apr_pstrcat(pool, value, "&_chxj_cc=", cookie->cookie_id, "&_chxj_nc=true", NULL);
1491             }
1492             else {
1493               value = apr_pstrcat(pool, value, "?_chxj_cc=", cookie->cookie_id, "&_chxj_nc=true", NULL);
1494             }
1495             dst = apr_pstrcat(pool, (dst) ? dst : "", "src='", value, "' ", NULL);
1496           }
1497           else {
1498             dst = apr_pstrcat(pool, (dst) ? dst : "", name, "='", value, "' ", NULL);
1499           }
1500         }
1501         dst = apr_pstrcat(pool, (dst) ? dst : "", "/>", NULL);
1502         plen += strlen(matchstr);
1503       }
1504       nowpos += plen;
1505     }
1506     else {
1507       break;
1508     }
1509   }
1510
1511   if ((apr_size_t)nowpos < *len) {
1512     apr_size_t plen = *len - nowpos;
1513     char *tmpstr = apr_palloc(pool, plen + 1);
1514     memset(tmpstr, 0, plen+1);
1515     memcpy(tmpstr, &s[nowpos], plen);
1516     dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1517   }
1518
1519   *len = strlen(dst);
1520   return dst;
1521 }
1522 char *
1523 s_convert_form_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1524 {
1525   apr_pool_t *pool;
1526   ap_regex_t *regexp = NULL;
1527   int   nowpos = 0;
1528   Doc       doc;
1529   char *dst = NULL;
1530   char *cookie_id;
1531
1532   apr_pool_create(&pool, r->pool);
1533   regexp = ap_pregcomp(pool, "(</form>)", AP_REG_EXTENDED|AP_REG_ICASE);
1534   doc.r = r;
1535   qs_init_malloc(&doc);
1536   qs_init_root_node(&doc);
1537   cookie_id = chxj_url_decode(pool, cookie->cookie_id);
1538
1539   while(1) {
1540     ap_regmatch_t        match[10];
1541     if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1542       apr_size_t plen = match[1].rm_so;
1543       if (plen > 0) {
1544         char *tmpstr = apr_palloc(pool, plen + 1);
1545         memset(tmpstr, 0, plen + 1);
1546         memcpy(tmpstr, &s[nowpos], plen);
1547         dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1548       }
1549       else {
1550         plen = 0;
1551       }
1552       char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1553       if (matchstr) {
1554         DBG(r,"REQ[%X] matchstr:[%s]",TO_ADDR(r),matchstr);
1555         dst = apr_pstrcat(pool, (dst) ? dst : "", "<input type='hidden' name='_chxj_cc' value='", cookie_id, "' />", matchstr, NULL);
1556         plen += strlen(matchstr);
1557       }
1558       nowpos += plen;
1559     }
1560     else {
1561       break;
1562     }
1563   }
1564
1565   if ((apr_size_t)nowpos < *len) {
1566     apr_size_t plen = *len - nowpos;
1567     char *tmpstr = apr_palloc(pool, plen + 1);
1568     memset(tmpstr, 0, plen + 1);
1569     memcpy(tmpstr, &s[nowpos], plen);
1570     dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1571   }
1572
1573   *len = strlen(dst);
1574   return dst;
1575 }
1576
1577 char *
1578 chxj_cookie_only_mode(request_rec *r, const char *src, apr_size_t *len, cookie_t* cookie)
1579 {
1580   char *s;
1581   char *result;
1582   char *dst = NULL;
1583
1584   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1585   s = chxj_encoding(r, src, len);
1586
1587   dst = s_convert_a_tag(r, s, len, cookie);
1588   dst = s_convert_img_tag(r, dst, len, cookie);
1589   dst = s_convert_form_tag(r, dst, len, cookie);
1590
1591   result = chxj_rencoding(r, dst, len, NULL);
1592   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1593   return result;
1594 }
1595 /*
1596  * vim:ts=2 et
1597  */