OSDN Git Service

* Fixed bug.
[modchxj/mod_chxj.git] / src / chxj_cookie.c
1 /*
2  * Copyright (C) 2005-2008 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
45 static char* s_get_hostname_from_url(request_rec* r, char* value);
46 static char* s_cut_until_end_hostname(request_rec*, char* value);
47 static int valid_domain(request_rec *r, const char *value);
48 static int valid_path(request_rec *r, const char *value);
49 static int valid_expires(request_rec *r, const char *value);
50 static int valid_secure(request_rec *r, const char *value);
51 static int check_valid_cookie_attribute(request_rec *r, const char *pair);
52
53
54 static char *
55 alloc_cookie_id(request_rec *r)
56 {
57   char                *cookie_id;
58   char                *uuid_string;
59   unsigned char       *md5_value;
60   apr_uuid_t          uuid;
61   apr_status_t        retval;
62
63   apr_uuid_get(&uuid);
64   uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
65   memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
66   apr_uuid_format(uuid_string, &uuid);;
67
68   md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
69   memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
70
71   retval = apr_md5(md5_value, 
72                    (const char*)uuid_string, 
73                    APR_UUID_FORMATTED_LENGTH);
74   if (retval != APR_SUCCESS) {
75     ERR(r, "md5 failed.");
76     return NULL;
77   }
78
79   cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
80   memset(cookie_id, 0, APR_MD5_DIGESTSIZE+1);
81   apr_base64_encode(cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
82
83   DBG(r, "cookie_id=[%s]", cookie_id);
84
85   cookie_id = chxj_url_encode(r,cookie_id);
86
87   DBG(r, "cookie_id=[%s]", cookie_id);
88   return cookie_id;
89 }
90
91
92 /*
93  *
94  */
95 cookie_t*
96 chxj_save_cookie(request_rec* r)
97 {
98   int                 ii;
99   apr_array_header_t  *headers;
100   apr_table_entry_t   *hentryp;
101   apr_array_header_t  *err_headers;
102   apr_table_entry_t   *err_hentryp;
103   char                *old_cookie_id;
104   char                *store_string;
105   mod_chxj_config     *dconf;
106   chxjconvrule_entry  *entryp;
107   apr_table_t*        new_cookie_table;
108   int                 has_cookie = 0;
109   cookie_t*           cookie;
110   cookie_t*           old_cookie;
111   char*               refer_string;
112   apr_uri_t           parsed_uri;
113   int                 has_refer;
114
115
116   DBG(r, "start chxj_save_cookie()");
117
118   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
119   cookie->cookie_id = NULL;
120
121   has_cookie = 0;
122   has_refer = 0;
123
124   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
125   entryp = chxj_apply_convrule(r, dconf->convrules);
126   if (! entryp) {
127     DBG(r, "end chxj_save_cookie() no pattern");
128     return NULL;
129   }
130   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
131     DBG(r, "end chxj_save_cookie() CookieOff");
132     return NULL;
133   }
134
135   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
136   hentryp = (apr_table_entry_t*)headers->elts;
137   err_headers = (apr_array_header_t*)apr_table_elts(r->err_headers_out);
138   err_hentryp = (apr_table_entry_t*)err_headers->elts;
139
140   new_cookie_table = apr_table_make(r->pool, 0);
141
142   for (ii=0; ii<headers->nelts; ii++) {
143     if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
144       DBG(r, "=====================================");
145       DBG(r, "cookie=[%s:%s]", hentryp[ii].key, hentryp[ii].val);
146
147       char* key;
148       char* val;
149       char* buff;
150
151
152       buff = apr_pstrdup(r->pool, hentryp[ii].val);
153       val = strchr(buff, '=');
154       if (val) {
155         key = buff;
156         *val++ = 0;
157         apr_table_add(new_cookie_table, key, val);
158         if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
159
160       }
161
162       has_cookie = 1;
163       DBG(r, "=====================================");
164     }
165   }
166   for (ii=0; ii<err_headers->nelts; ii++) {
167     if (strcasecmp(err_hentryp[ii].key, "Set-Cookie") == 0) {
168       DBG(r, "=====================================");
169       DBG(r, "cookie=[%s:%s]", err_hentryp[ii].key, err_hentryp[ii].val);
170
171       char* key;
172       char* val;
173       char* buff;
174
175
176       buff = apr_pstrdup(r->pool, err_hentryp[ii].val);
177       val = strchr(buff, '=');
178       if (val) {
179         key = buff;
180         *val++ = 0;
181         apr_table_add(new_cookie_table, key, val);
182         if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
183
184       }
185
186       has_cookie = 1;
187       DBG(r, "=====================================");
188     }
189   }
190   apr_table_unset(r->headers_out, "Set-Cookie");
191   apr_table_unset(r->err_headers_out, "Set-Cookie");
192
193
194   if (! has_refer) {
195     apr_uri_parse(r->pool,r->uri, &parsed_uri);
196     refer_string = apr_psprintf(r->pool, 
197                                 "%s://%s%s", 
198                                 chxj_run_http_scheme(r),
199                                 r->hostname,
200                                 apr_uri_unparse(r->pool,
201                                                 &parsed_uri,
202                                                 APR_URI_UNP_OMITSITEPART));
203     if (r->args && strlen(r->args)) {
204       refer_string = apr_pstrcat(r->pool, refer_string, "?", r->args, NULL);
205     }
206     apr_table_setn(new_cookie_table, REFERER_COOKIE_KEY, refer_string);
207     DBG(r, "ADD REFER[%s]", refer_string);
208     has_cookie++;
209   }
210
211
212   /*
213    * check input parameters
214    */
215   old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
216   if (old_cookie_id) {
217     old_cookie = chxj_load_cookie(r, old_cookie_id); 
218     if (old_cookie && old_cookie->cookie_headers) {
219       hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
220       for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
221         if (hentryp && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
222           apr_table_add(new_cookie_table, hentryp[ii].key, hentryp[ii].val);
223           has_cookie = 1;
224         }
225       }
226       chxj_delete_cookie(r,        old_cookie_id);
227       chxj_delete_cookie_expire(r, old_cookie_id);
228     }
229   }
230
231   if (! has_cookie) {
232     DBG(r, "no cookie");
233     DBG(r, "end chxj_save_cookie()");
234     return NULL;
235   }
236
237   /*
238    * create val
239    */
240   cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
241   store_string = apr_palloc(r->pool, 1);
242   store_string[0] = 0;
243   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
244
245   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
246     if (ii) store_string = apr_pstrcat(r->pool,
247                                store_string, 
248                                "\n",
249                                NULL);
250
251     store_string = apr_pstrcat(r->pool, 
252                                store_string, 
253                                hentryp[ii].key, 
254                                "=",
255                                hentryp[ii].val, 
256                                NULL);
257   }
258
259   if (old_cookie_id && IS_COOKIE_LAZY(dconf)) {
260     DBG(r, "LAZY COOKIE save");
261     cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
262   }
263   else {
264     DBG(r, "NO LAZY COOKIE save");
265     cookie->cookie_id = alloc_cookie_id(r);
266   }
267
268 DBG(r, "TYPE:[%d]", dconf->cookie_store_type);
269   {
270     int done_proc = 0;
271 #if defined(USE_MYSQL_COOKIE)
272     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
273       if (! chxj_save_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
274         ERR(r, "faild: chxj_save_cookie_mysql() cookie_id:[%s]", cookie->cookie_id);
275         goto on_error;
276       }
277       done_proc = 1;
278     }
279 #endif
280 #if defined(USE_MEMCACHE_COOKIE)
281     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
282       if (! chxj_save_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
283         ERR(r, "failed: chxj_save_cookie_memcache() cookie_id:[%s]", cookie->cookie_id);
284         goto on_error;
285       }
286       done_proc = 1;
287     }
288 #endif
289     if (IS_COOKIE_STORE_DBM(dconf->cookie_store_type) || ! done_proc) {
290       if (! chxj_save_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
291         ERR(r, "failed: chxj_save_cookie_dbm() cookie_id:[%s]", cookie->cookie_id);
292         goto on_error;
293       }
294     }
295   }
296
297
298   chxj_save_cookie_expire(r, cookie);
299
300
301
302 on_error:
303   DBG(r, "end chxj_save_cookie()");
304   return cookie;
305 }
306
307 /*
308  *
309  */
310 cookie_t*
311 chxj_update_cookie(request_rec* r, cookie_t* old_cookie)
312 {
313   int                 ii;
314   apr_array_header_t* headers;
315   apr_table_entry_t*  hentryp;
316   char*               store_string;
317   mod_chxj_config*    dconf;
318   chxjconvrule_entry* entryp;
319   cookie_t*           cookie;
320
321
322   DBG(r, "start chxj_update_cookie()");
323   if (!old_cookie || ! old_cookie->cookie_headers || ! old_cookie->cookie_id) {
324     DBG(r, "end chxj_update_cookie() (old_cookie is null)");
325     return  NULL;
326   }
327
328   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
329   cookie->cookie_id = NULL;
330
331
332   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
333   entryp = chxj_apply_convrule(r, dconf->convrules);
334   if (! entryp) {
335     DBG(r, "end chxj_update_cookie() no pattern");
336     return NULL;
337   }
338   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
339     DBG(r, "end chxj_update_cookie() CookieOff");
340     return NULL;
341   }
342
343
344   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
345   hentryp = (apr_table_entry_t*)headers->elts;
346
347
348   chxj_delete_cookie(r,        old_cookie->cookie_id);
349   chxj_delete_cookie_expire(r, old_cookie->cookie_id);
350
351   if (IS_COOKIE_LAZY(dconf)) {
352     DBG(r, "LAZY MODE");
353     cookie->cookie_id = apr_pstrdup(r->pool, old_cookie->cookie_id);
354   }
355   else {
356     DBG(r, "NO LAZY MODE");
357     cookie->cookie_id = alloc_cookie_id(r);
358   }
359
360   cookie->cookie_headers = old_cookie->cookie_headers;
361   store_string = apr_palloc(r->pool, 1);
362   store_string[0] = 0;
363   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
364
365   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
366     if (ii) store_string = apr_pstrcat(r->pool,
367                                store_string, 
368                                "\n",
369                                NULL);
370
371     DBG(r, "OLD COOKIE VALUE=[%s][%s]", hentryp[ii].key, hentryp[ii].val);
372     store_string = apr_pstrcat(r->pool, 
373                                store_string, 
374                                hentryp[ii].key, 
375                                "=",
376                                hentryp[ii].val, 
377                                NULL);
378   }
379
380   {
381     int done_proc = 0;
382 #if defined(USE_MYSQL_COOKIE)
383     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
384       if (!chxj_update_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
385         ERR(r, "failed: chxj_update_cookie_mysql() cookie_id:[%s]", cookie->cookie_id);
386         goto on_error;
387       }
388       done_proc = 1;
389     }
390 #endif
391
392 #if defined(USE_MEMCACHE_COOKIE)
393     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
394       if (! chxj_update_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
395         ERR(r, "failed: chxj_update_cookie_memcache() cookie_id:[%s]", cookie->cookie_id);
396         goto on_error;
397       }
398       done_proc = 1;
399     }
400 #endif
401     if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
402       if (! chxj_update_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
403         ERR(r, "failed: chxj_update_cookie_dbm() cookie_id:[%s]", cookie->cookie_id);
404         goto on_error;
405       }
406     }
407   }
408
409   chxj_save_cookie_expire(r, cookie);
410
411   apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
412
413
414 on_error:
415   DBG(r, "end   chxj_update_cookie()");
416   return cookie;
417 }
418
419
420 /*
421  *
422  * @return loaded data.
423  */
424 cookie_t*
425 chxj_load_cookie(request_rec* r, char* cookie_id)
426 {
427   mod_chxj_config         *dconf;
428   chxjconvrule_entry      *entryp;
429   cookie_t                *cookie;
430   apr_table_t             *load_cookie_table;
431   char                    *load_string = NULL;
432   char                    *pstat;
433   char                    *key;
434   char                    *val;
435   char                    *pair;
436   char                    *header_cookie;
437
438   DBG(r, "========================================================");
439   DBG(r, "========================================================");
440   DBG(r, "========================================================");
441   DBG(r, "========================================================");
442   DBG(r, "start chxj_load_cookie() cookie_id=[%s]", cookie_id);
443   chxj_cookie_expire_gc(r);
444
445   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
446   cookie->cookie_headers = NULL;
447   cookie->cookie_id = apr_pstrdup(r->pool, cookie_id);
448
449   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
450   entryp = chxj_apply_convrule(r, dconf->convrules);
451   if (! entryp) {
452     DBG(r, "end chxj_load_cookie() no pattern");
453     goto on_error0;
454   }
455   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
456     DBG(r, "end chxj_load_cookie() CookieOff");
457     goto on_error0;
458   }
459   load_cookie_table = apr_table_make(r->pool, 0);
460
461   {
462     int done_proc = 0;
463 #if defined(USE_MYSQL_COOKIE)
464     if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
465       if (! (load_string = chxj_load_cookie_mysql(r, dconf, cookie->cookie_id))) {
466         ERR(r, "failed: chxj_load_cookie_mysql() cookie_id:[%s]", cookie_id);
467         goto on_error0;
468       }
469       done_proc = 1;
470     }
471 #endif
472 #if defined(USE_MEMCACHE_COOKIE)
473     if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
474       if (! (load_string = chxj_load_cookie_memcache(r, dconf, cookie->cookie_id))) {
475         ERR(r, "failed: chxj_load_cookie_memcache() cookie_id:[%s]", cookie_id);
476         goto on_error0;
477       }
478       done_proc = 1;
479     }
480 #endif
481     if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
482       if (! (load_string = chxj_load_cookie_dbm(r, dconf, cookie->cookie_id))) {
483         ERR(r, "failed: chxj_load_cookie_dbm() cookie_id:[%s]", cookie_id);
484         goto on_error0;
485       }
486     }
487   }
488
489   if (load_string) {
490     DBG(r, "load_string=[%s]", load_string);
491     header_cookie = apr_palloc(r->pool, 1);
492     header_cookie[0] = 0;
493     for (;;) {
494       char* tmp_sem;
495       pair = apr_strtok(load_string, "\n", &pstat);  
496       load_string = NULL;
497       if (!pair) break;
498
499       DBG(r, "Cookie:[%s]", pair);
500       char* tmp_pair;
501
502       tmp_pair = apr_pstrdup(r->pool, pair);
503       val = strchr(tmp_pair, '=');
504       if (val) {
505         key = tmp_pair;
506         *val++ = 0;
507         apr_table_add(load_cookie_table, key, val);
508         DBG(r, "ADD key:[%s] val:[%s]", key, val);
509       }
510       tmp_pair = apr_pstrdup(r->pool, pair);
511       tmp_sem = strchr(tmp_pair, ';'); 
512       if (tmp_sem)
513         *tmp_sem = '\0';
514
515       if (check_valid_cookie_attribute(r, pair)) {
516         if (strlen(header_cookie)) 
517           header_cookie = apr_pstrcat(r->pool, header_cookie, ";", NULL);
518   
519         header_cookie = apr_pstrcat(r->pool, header_cookie, tmp_pair, NULL);
520       }
521     }
522     if (strlen(header_cookie)) {
523       DBG(r, "ADD COOKIE to REQUEST HEADER:[%s]", header_cookie);
524       apr_table_add(r->headers_in, "Cookie", header_cookie);
525     }
526   
527     cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
528
529     if (apr_table_get(r->headers_in, "referer") == NULL) {
530       apr_table_setn(r->headers_in, 
531                      "referer",
532                      apr_table_get(load_cookie_table, REFERER_COOKIE_KEY));
533     }
534   
535     /*
536      * save cookie_id to request header.
537      */
538     apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
539   }
540
541   DBG(r, "end   chxj_load_cookie()");
542   DBG(r, "========================================================");
543   DBG(r, "========================================================");
544   DBG(r, "========================================================");
545   DBG(r, "========================================================");
546
547   return cookie;
548
549
550 on_error0:
551
552   DBG(r, "end   chxj_load_cookie()");
553   DBG(r, "========================================================");
554   DBG(r, "========================================================");
555   DBG(r, "========================================================");
556   DBG(r, "========================================================");
557   return NULL;
558 }
559
560 static int
561 check_valid_cookie_attribute(request_rec *r, const char *value)
562 {
563   char *pstat;
564   char *pair;
565   char *first_pair;
566   char *domain_pair;
567   char *path_pair;
568   char *expire_pair;
569   char *secure_pair;
570   char *p;
571
572   DBG(r, "start check_valid_cookie_attribute() value:[%s]", value);
573
574   domain_pair = path_pair = expire_pair = secure_pair = NULL;
575   p = apr_pstrdup(r->pool, value);
576
577   /* pass first pair */
578   first_pair = apr_strtok(p, ";", &pstat);  
579
580   for (;;) {
581     pair = apr_strtok(NULL, ";", &pstat);
582     if (! pair) break;
583     pair = qs_trim_string(r->pool, pair);
584     if (STRNCASEEQ('d','D',"domain", pair, sizeof("domain")-1)) {
585       domain_pair = apr_pstrdup(r->pool, pair);
586     }
587     else if (STRNCASEEQ('p','P',"path", pair, sizeof("path")-1)) {
588       path_pair = apr_pstrdup(r->pool, pair);
589     }
590     else if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
591       expire_pair = apr_pstrdup(r->pool, pair);
592     }
593     else if (STRNCASEEQ('s','S',"secure", pair, sizeof("secure")-1)) {
594       secure_pair = apr_pstrdup(r->pool, pair);
595     }
596   }
597
598   if (domain_pair) {
599     if (!valid_domain(r, domain_pair)) {
600       DBG(r, "invalid domain. domain_pair:[%s]", domain_pair);
601       return CHXJ_FALSE;
602     }
603   }
604   if (path_pair) {
605     if (!valid_path(r, path_pair)) {
606       DBG(r, "invalid path. path_pair:[%s]", path_pair);
607       return CHXJ_FALSE;
608     }
609   }
610   if (expire_pair) {
611     if (!valid_expires(r, expire_pair)) {
612       DBG(r, "invalid expire. expire_pair:[%s]", expire_pair);
613       return CHXJ_FALSE;
614     }
615   }
616   if (secure_pair) {
617     if (!valid_secure(r, secure_pair)) {
618       DBG(r, "invalid secure. secure_pair:[%s]", secure_pair);
619       return CHXJ_FALSE;
620     }
621   }
622   DBG(r, "end check_valid_cookie_attribute() value:[%s]", value);
623   return CHXJ_TRUE;
624 }
625
626 static int
627 valid_domain(request_rec *r, const char *value)
628 {
629   int len;
630   char *name;
631   char *val;
632   char *pstat;
633   char *p = apr_pstrdup(r->pool, value);
634   const char *host = apr_table_get(r->headers_in, HTTP_HOST);
635
636   DBG(r, "start valid_domain() value:[%s]", value);
637   DBG(r, "host:[%s]", host);
638   if (!host)
639     return CHXJ_TRUE;
640
641   name = apr_strtok(p,"=", &pstat);
642   name = qs_trim_string(r->pool, name);
643   val = apr_strtok(NULL, "=", &pstat);
644   val = qs_trim_string(r->pool, val);
645   len = strlen(host);
646   if (len) {
647     if (chxj_strcasenrcmp(r->pool, host, val, strlen(val))) {
648       DBG(r, "not match domain. host domain:[%s] vs value:[%s]", host, val);
649       return CHXJ_FALSE;
650     }
651   }
652   DBG(r, "end valid_domain() value:[%s]", value);
653   return CHXJ_TRUE;
654 }
655
656 static int
657 valid_path(request_rec *r, const char *value)
658 {
659   char *p = apr_pstrdup(r->pool, value);
660   char *uri;
661   char *tmp;
662   char *name;
663   char *val;
664   char *pstat;
665
666   DBG(r, "start valid_path() unparsed_uri:[%s] value:[%s]", r->unparsed_uri, value);
667   if (chxj_starts_with(r->unparsed_uri, "http://")) {
668     uri = strchr(&r->unparsed_uri[sizeof("http://")], '/');
669     if (uri != NULL) {
670       uri = apr_pstrdup(r->pool, uri);
671     }
672   }
673   else if (chxj_starts_with(r->unparsed_uri, "https://")) {
674     uri = strchr(&r->unparsed_uri[sizeof("https://")], '/');
675     if (uri != NULL) {
676       uri = apr_pstrdup(r->pool, uri);
677     }
678   }
679   else if (chxj_starts_with(r->unparsed_uri, "/")) {
680     uri = apr_pstrdup(r->pool, r->unparsed_uri);
681   }
682   else {
683     uri = apr_pstrdup(r->pool, "/");
684   }
685   
686   if ((tmp = strchr(uri, '?'))) {
687     *tmp = '\0';
688   }
689   DBG(r, "uri=[%s]", uri);
690   name = apr_strtok(p, "=", &pstat);
691   val = apr_strtok(NULL, "=", &pstat);
692   name = qs_trim_string(r->pool, name);
693   val = qs_trim_string(r->pool, val);
694   DBG(r, "name=[%s] val=[%s]", name, val);
695   
696   DBG(r, "val:[%s] vs uri:[%s]", val, uri);
697   if (! chxj_starts_with(uri, val)) {
698     DBG(r, "end valid_path() unparsed_uri:[%s] value:[%s] (false)", r->unparsed_uri, value);
699     return CHXJ_FALSE;
700   }
701   DBG(r, "end valid_path() unparsed_uri:[%s] value:[%s] (true)", r->unparsed_uri, value);
702   return CHXJ_TRUE;
703 }
704
705 static int
706 valid_expires(request_rec *r, const char *value)
707 {
708   char *name;
709   char *val;
710   char *p = apr_pstrdup(r->pool, value);
711   char *pstat;
712   apr_time_t expires;
713   apr_time_t now;
714   DBG(r, "start valid_expire() value:[%s]", value);
715
716   name = apr_strtok(p, "=", &pstat);
717   val  = apr_strtok(NULL, "=", &pstat);
718   DBG(r, "name=[%s] val=[%s]", name, val);
719   now = apr_time_now();
720   expires = chxj_parse_cookie_expires(val);
721   if (expires < now) {
722     DBG(r, "end valid_expire() value:[%s] (expired)", value);
723     return CHXJ_FALSE;
724   }
725   
726   DBG(r, "end valid_expire() value:[%s] (non expired)", value);
727   return CHXJ_TRUE;
728 }
729
730 static int
731 valid_secure(request_rec *r, const char *value)
732 {
733   const char *scheme;
734   DBG(r, "start valid_secure() value:[%s]", value);
735   scheme = chxj_apache_run_http_scheme(r);
736   if (strcasecmp("https", scheme)) {
737     DBG(r, "end valid_secure() value:[%s] (non secure)", value);
738     return CHXJ_FALSE;
739   }
740   DBG(r, "end valid_secure() value:[%s] (secure)", value);
741   return CHXJ_TRUE;
742 }
743
744
745 char*
746 chxj_add_cookie_parameter(request_rec* r, char* value, cookie_t* cookie)
747 {
748   char* qs;
749   char* dst;
750
751   DBG(r, "start chxj_add_cookie_parameter() cookie_id=[%s]", (cookie) ? cookie->cookie_id : NULL);
752
753   dst = apr_pstrdup(r->pool, value);
754
755   if (!cookie)
756     goto on_error;
757
758   if (!cookie->cookie_id)
759     goto on_error;
760
761   if (chxj_cookie_check_host(r, value) != 0) {
762     DBG(r, "end chxj_add_cookie_parameter()(check host)");
763     goto on_error;
764   }
765
766   qs = strchr(dst, '?');
767   if (qs) {
768     dst = apr_psprintf(r->pool, "%s&%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
769   }
770   else {
771     dst = apr_psprintf(r->pool, "%s?%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
772   }
773
774   DBG(r, "end   chxj_add_cookie_parameter() dst=[%s]", dst);
775
776   return dst;
777
778 on_error:
779   DBG(r, "end   chxj_add_cookie_parameter() (on_error)");
780   return dst;
781 }
782
783
784 int
785 chxj_cookie_check_host(request_rec* r, char* value) 
786 {
787   char* hostnm;
788
789   DBG(r, "hostname=[%s]", r->hostname);
790
791   hostnm = s_get_hostname_from_url(r, value);
792   if (hostnm) {
793     if (strcasecmp(hostnm, r->hostname) == 0)
794       return 0;
795     else
796       return 1;
797   }
798   return 0;
799 }
800
801
802 static char*
803 s_get_hostname_from_url(request_rec* r, char* value)
804 {
805   if (!value) 
806     return NULL; 
807
808   if (strncasecmp(value, "http://",  7) == 0 )
809     return s_cut_until_end_hostname(r, &value[7]);
810
811   if (strncasecmp(value, "https://", 8) == 0)
812     return s_cut_until_end_hostname(r, &value[8]);
813
814   return NULL;
815 }
816
817
818 static char* 
819 s_cut_until_end_hostname(request_rec* r, char* value)
820 {
821   char* sp;
822   char* hostnm;
823
824   hostnm = sp = apr_pstrdup(r->pool, value);
825   for (;*sp; sp++) {
826     if (*sp == '/'|| *sp == '?') {
827       *sp = '\0';
828       break;
829     }
830   }
831   return hostnm;
832 }
833
834
835
836 void
837 chxj_delete_cookie(request_rec *r, const char *cookie_id)
838 {
839   int done_proc = 0;
840   mod_chxj_config *dconf;
841
842   DBG(r, "start chxj_delete_cookie()");
843   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
844
845 #if defined(USE_MYSQL_COOKIE)
846   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
847     if (! chxj_delete_cookie_mysql(r, dconf, cookie_id)) {
848       ERR(r, "failed: chxj_delete_cookie_mysql() cookie_id:[%s]", cookie_id);
849       DBG(r, "end   chxj_delete_cookie()");
850       return;
851     }
852     done_proc = 1;
853   }
854 #endif
855
856 #if defined(USE_MEMCACHE_COOKIE)
857   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
858     if (! chxj_delete_cookie_memcache(r, dconf, cookie_id)) {
859       ERR(r, "failed: chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
860       DBG(r, "end   chxj_delete_cookie()");
861       return;
862     }
863     done_proc = 1;
864   }
865 #endif
866   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
867     if (! chxj_delete_cookie_dbm(r, dconf, cookie_id)) {
868       ERR(r, "failed: chxj_delete_cookie_dbm() cookie_id:[%s]", cookie_id);
869       DBG(r, "end   chxj_delete_cookie()");
870       return;
871     }
872   }
873
874   DBG(r, "end   chxj_delete_cookie()");
875 }
876
877
878 /*
879  *
880  */
881 void
882 chxj_save_cookie_expire(request_rec* r, cookie_t* cookie)
883 {
884   int done_proc = 0;
885   mod_chxj_config         *dconf;
886
887   DBG(r, "start chxj_save_cookie_expire()");
888   if (!cookie) {
889     DBG(r, "cookie is NULL");
890     return;
891   }
892   if (!cookie->cookie_id) {
893     DBG(r, "cookie->cookie_id is NULL");
894     return;
895   }
896
897   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
898   if (!dconf) {
899     DBG(r, "dconf is NULL");
900     return;
901   }
902
903 #if defined(USE_MYSQL_COOKIE)
904   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
905     if (! chxj_save_cookie_expire_mysql(r, dconf, cookie->cookie_id)) {
906       ERR(r, "failed: chxj_save_cookie_expire_mysql() cookie_id:[%s]", cookie->cookie_id);
907       DBG(r, "end   chxj_save_cookie_expire()");
908       return;
909     }
910     done_proc = 1;
911   }
912 #endif
913 #if defined(USE_MEMCACHE_COOKIE)
914   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
915     if (! chxj_save_cookie_expire_memcache(r, dconf, cookie->cookie_id)) {
916       ERR(r, "failed: chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie->cookie_id);
917       DBG(r, "end   chxj_save_cookie_expire()");
918       return;
919     }
920     done_proc = 1;
921   }
922 #endif
923   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
924     if (! chxj_save_cookie_expire_dbm(r, dconf, cookie->cookie_id)) {
925       ERR(r, "failed: chxj_save_cookie_expire_dbm() cookie_id:[%s]", cookie->cookie_id);
926       DBG(r, "end   chxj_save_cookie_expire()");
927       return;
928     }
929   }
930
931   DBG(r, "end   chxj_save_cookie_expire()");
932 }
933
934
935
936
937
938 void
939 chxj_delete_cookie_expire(request_rec* r, char* cookie_id)
940 {
941   int done_proc = 0;
942   mod_chxj_config*  dconf;
943
944   DBG(r, "start chxj_delete_cookie_expire()");
945
946   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
947
948 #if defined(USE_MYSQL_COOKIE)
949   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
950     if (! chxj_delete_cookie_expire_mysql(r, dconf, cookie_id)) {
951       ERR(r, "failed: chxj_delete_cookie_expire_mysql() cookie_id:[%s]", cookie_id);
952       return;
953     }
954     done_proc = 1;
955   }
956 #endif
957 #if defined(USE_MEMCACHE_COOKIE)
958   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
959     if (!chxj_delete_cookie_expire_memcache(r, dconf, cookie_id)) {
960       ERR(r, "failed: chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
961       return;
962     } 
963     done_proc = 1;
964   }
965 #endif
966   if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
967     if (!chxj_delete_cookie_expire_dbm(r, dconf, cookie_id)) {
968       ERR(r, "failed: chxj_delete_cookie_expire_dbm() cookie_id:[%s]", cookie_id);
969       return;
970     } 
971   }
972
973   DBG(r, "end   chxj_delete_cookie_expire()");
974
975   return;
976 }
977
978
979 void
980 chxj_cookie_expire_gc(request_rec* r)
981 {
982   mod_chxj_config   *dconf;
983   int done_proc = 0;
984
985   DBG(r, "start chxj_cookie_expire_gc()");
986
987   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
988 #if defined(USE_MYSQL_COOKIE)
989   if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
990     if (! chxj_cookie_expire_gc_mysql(r, dconf)) {
991       ERR(r, "failed: chxj_cookie_expire_gc_mysql()");
992       return;
993     }
994     done_proc = 1;
995   } 
996 #endif
997 #if defined(USE_MEMCACHE_COOKIE)
998   if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
999     if (! chxj_cookie_expire_gc_memcache(r, dconf)) {
1000       ERR(r, "failed: chxj_cookie_expire_gc_memcache()");
1001       return;
1002     }
1003     done_proc = 1;
1004   } 
1005 #endif
1006   if (!done_proc) {
1007     if (! chxj_cookie_expire_gc_dbm(r, dconf)) {
1008       ERR(r, "failed: chxj_cookie_expire_gc_dbm()");
1009       return;
1010     }
1011   }
1012   DBG(r, "end   chxj_cookie_expire_gc()");
1013 }
1014
1015 apr_time_t
1016 chxj_parse_cookie_expires(const char *s)
1017 {
1018   if (!s) return (apr_time_t)0;
1019   return apr_date_parse_rfc(s);
1020 }
1021 /*
1022  * vim:ts=2 et
1023  */