OSDN Git Service

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