OSDN Git Service

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