OSDN Git Service

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