OSDN Git Service

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