OSDN Git Service

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