2 * Copyright (C) 2005-2009 Atsushi Konno All rights reserved.
3 * Copyright (C) 2005 QSDN,Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "chxj_cookie.h"
21 #include "chxj_url_encode.h"
22 #include "chxj_apply_convrule.h"
23 #include "chxj_str_util.h"
25 #include "ap_release.h"
31 #include "apr_base64.h"
36 #if defined(USE_MYSQL_COOKIE)
37 # include "chxj_mysql.h"
39 #if defined(USE_MEMCACHE_COOKIE)
40 # include "chxj_memcache.h"
44 #define DUMP_HEADERS(X) do { \
46 apr_array_header_t *__headers = (apr_array_header_t*)apr_table_elts((X)); \
47 apr_table_entry_t *__hentryp = (apr_table_entry_t*)__headers->elts; \
48 for (__ii=0; __ii<__headers->nelts; __ii++) { \
49 DBG(r, "key:[%s] val:[%s]", __hentryp[__ii].key, __hentryp[__ii].val); \
55 static char* s_get_hostname_from_url(request_rec* r, char* value);
56 static char* s_cut_until_end_hostname(request_rec*, char* value);
57 static int valid_domain(request_rec *r, const char *value);
58 static int valid_path(request_rec *r, const char *value);
59 static int valid_expires(request_rec *r, const char *value);
60 static int valid_secure(request_rec *r, const char *value);
61 static int check_valid_cookie_attribute(request_rec *r, const char *pair);
62 static int check_valid_cookie_attribute_expires_only(request_rec *r, const char *value);
64 apr_proc_mutex_t *global_cookie_mutex;
67 alloc_cookie_id(request_rec *r)
71 unsigned char *md5_value;
76 uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
77 memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
78 apr_uuid_format(uuid_string, &uuid);;
80 md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
81 memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
83 retval = apr_md5(md5_value,
84 (const char*)uuid_string,
85 APR_UUID_FORMATTED_LENGTH);
86 if (retval != APR_SUCCESS) {
87 ERR(r, "md5 failed.");
91 cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
92 memset(cookie_id, 0, APR_MD5_DIGESTSIZE+1);
93 apr_base64_encode(cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
95 DBG(r, "cookie_id=[%s]", cookie_id);
97 cookie_id = chxj_url_encode(r->pool,cookie_id);
99 DBG(r, "cookie_id=[%s]", cookie_id);
108 chxj_save_cookie(request_rec *r)
111 apr_array_header_t *headers;
112 apr_table_entry_t *hentryp;
113 apr_array_header_t *err_headers;
114 apr_table_entry_t *err_hentryp;
117 mod_chxj_config *dconf;
118 chxjconvrule_entry *entryp;
119 apr_table_t *new_cookie_table;
122 cookie_t *old_cookie;
124 apr_uri_t parsed_uri;
129 DBG(r, "start chxj_save_cookie()");
131 apr_pool_create(&pool, r->pool);
133 cookie = (cookie_t*)apr_palloc(pool, sizeof(cookie_t));
134 cookie->cookie_id = NULL;
139 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
140 entryp = chxj_apply_convrule(r, dconf->convrules);
142 DBG(r, "end chxj_save_cookie() no pattern");
145 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
146 DBG(r, "end chxj_save_cookie() CookieOff");
152 headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
153 hentryp = (apr_table_entry_t*)headers->elts;
154 err_headers = (apr_array_header_t*)apr_table_elts(r->err_headers_out);
155 err_hentryp = (apr_table_entry_t*)err_headers->elts;
158 new_cookie_table = apr_table_make(pool, 0);
160 for (ii=0; ii<headers->nelts; ii++) {
161 if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
162 DBG(r, "REQ[%X] cookie=[%s:%s]", TO_ADDR(r), hentryp[ii].key, hentryp[ii].val);
168 char *pair = apr_psprintf(pool, "%s:%s", hentryp[ii].key, hentryp[ii].val);
169 if (check_valid_cookie_attribute_expires_only(r, pair)) {
170 buff = apr_pstrdup(pool, hentryp[ii].val);
171 val = strchr(buff, '=');
175 apr_table_set(new_cookie_table, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
176 if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
182 for (ii=0; ii<err_headers->nelts; ii++) {
183 if (strcasecmp(err_hentryp[ii].key, "Set-Cookie") == 0) {
184 DBG(r, "REQ[%X] cookie=[%s:%s]", TO_ADDR(r), err_hentryp[ii].key, err_hentryp[ii].val);
190 char *pair = apr_psprintf(pool, "%s:%s", err_hentryp[ii].key, err_hentryp[ii].val);
191 if (check_valid_cookie_attribute_expires_only(r, pair)) {
192 buff = apr_pstrdup(pool, err_hentryp[ii].val);
193 val = strchr(buff, '=');
197 apr_table_set(new_cookie_table, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
198 if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
204 apr_table_unset(r->headers_out, "Set-Cookie");
205 apr_table_unset(r->err_headers_out, "Set-Cookie");
208 apr_uri_parse(pool,r->uri, &parsed_uri);
209 refer_string = apr_psprintf(pool,
211 chxj_run_http_scheme(r),
213 apr_uri_unparse(pool,
215 APR_URI_UNP_OMITSITEPART));
216 if (r->args && strlen(r->args)) {
217 refer_string = apr_pstrcat(pool, refer_string, "?", r->args, NULL);
219 apr_table_setn(new_cookie_table, REFERER_COOKIE_KEY, refer_string);
220 DBG(r, "ADD REFER[%s]", refer_string);
226 * check input parameters
228 old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
230 old_cookie = chxj_load_cookie(r, old_cookie_id);
231 if (old_cookie && old_cookie->cookie_headers) {
232 hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
233 for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
234 if (hentryp && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
235 apr_table_add(new_cookie_table, apr_pstrdup(pool, hentryp[ii].key), apr_pstrdup(pool, hentryp[ii].val));
239 chxj_delete_cookie(r, old_cookie_id);
240 chxj_delete_cookie_expire(r, old_cookie_id);
248 DBG(r, "REQ[%X] end chxj_save_cookie() (no cookie)", (unsigned int)(apr_size_t)r);
255 cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
256 hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
257 apr_size_t store_string_len = 0;
258 for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
259 if (ii) store_string_len++;
260 store_string_len += (strlen(hentryp[ii].key) + strlen(hentryp[ii].val) + 1);
262 store_string = apr_palloc(pool, store_string_len + 1);
263 memset(store_string, 0, store_string_len + 1);
266 for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
267 if (ii) store_string[npos++] = '\n';
268 memcpy(&store_string[npos], hentryp[ii].key, strlen(hentryp[ii].key));
269 npos += strlen(hentryp[ii].key);
270 store_string[npos++] = '=';
271 memcpy(&store_string[npos], hentryp[ii].val, strlen(hentryp[ii].val));
272 npos += strlen(hentryp[ii].val);
275 if (old_cookie_id && IS_COOKIE_LAZY(dconf)) {
276 DBG(r, "REQ[%X] LAZY COOKIE save",(unsigned int)(apr_size_t)r);
277 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
279 else if (old_cookie_id && apr_table_get(r->headers_in, "X-Chxj-Cookie-No-Update")) {
280 DBG(r, "REQ[%X] NO UPDATE MODE",(unsigned int)(apr_size_t)r);
281 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
284 if (old_cookie_id && apr_table_get(r->headers_in, "X-Chxj-Forward")) {
285 DBG(r, "REQ[%X] NO LAZY COOKIE(X-Chxj-Forward) save",(unsigned int)(apr_size_t)r);
286 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
289 DBG(r, "REQ[%X] NO LAZY COOKIE save",(unsigned int)(apr_size_t)r);
290 cookie->cookie_id = alloc_cookie_id(r);
294 DBG(r, "REQ[%X] TYPE:[%d]", (unsigned int)(apr_size_t)r, dconf->cookie_store_type);
295 DBG(r, "REQ[%X] STORE STRING:=======================================================", TO_ADDR(r));
296 DBG(r, "REQ[%X] [%s]", TO_ADDR(r), store_string);
297 DBG(r, "REQ[%X] =======================================================:STORE STRING", TO_ADDR(r));
301 #if defined(USE_MYSQL_COOKIE)
302 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
303 if (! chxj_save_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
304 ERR(r, "%s:%d faild: chxj_save_cookie_mysql() cookie_id:[%s]", APLOG_MARK,cookie->cookie_id);
311 #if defined(USE_MEMCACHE_COOKIE)
312 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
313 if (! chxj_save_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
314 ERR(r, "%s:%d failed: chxj_save_cookie_memcache() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
321 if (IS_COOKIE_STORE_DBM(dconf->cookie_store_type) || ! done_proc) {
322 if (! chxj_save_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
323 ERR(r, "%s:%d failed: chxj_save_cookie_dbm() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
329 apr_table_unset(r->headers_out, "Set-Cookie");
330 apr_table_unset(r->err_headers_out, "Set-Cookie");
333 chxj_save_cookie_expire(r, cookie);
337 DBG(r, "end chxj_save_cookie()");
347 chxj_update_cookie(request_rec *r, cookie_t *old_cookie)
350 apr_array_header_t *headers;
351 apr_table_entry_t *hentryp;
353 mod_chxj_config *dconf;
354 chxjconvrule_entry *entryp;
358 DBG(r, "start chxj_update_cookie()");
359 if (!old_cookie || ! old_cookie->cookie_headers || ! old_cookie->cookie_id) {
360 DBG(r, "end chxj_update_cookie() (old_cookie is null)");
364 cookie = (cookie_t *)apr_palloc(r->pool, sizeof(cookie_t));
365 cookie->cookie_id = NULL;
367 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
368 entryp = chxj_apply_convrule(r, dconf->convrules);
370 DBG(r, "end chxj_update_cookie() no pattern");
373 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
374 DBG(r, "end chxj_update_cookie() CookieOff");
378 headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
379 hentryp = (apr_table_entry_t*)headers->elts;
381 chxj_delete_cookie(r, old_cookie->cookie_id);
382 chxj_delete_cookie_expire(r, old_cookie->cookie_id);
384 if (IS_COOKIE_LAZY(dconf)) {
386 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie->cookie_id);
389 DBG(r, "NO LAZY MODE");
390 cookie->cookie_id = alloc_cookie_id(r);
393 cookie->cookie_headers = old_cookie->cookie_headers;
394 store_string = apr_palloc(r->pool, 1);
396 hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
398 for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
399 if (ii) store_string = apr_pstrcat(r->pool,
404 DBG(r, "OLD COOKIE VALUE=[%s][%s]", hentryp[ii].key, hentryp[ii].val);
405 store_string = apr_pstrcat(r->pool,
415 #if defined(USE_MYSQL_COOKIE)
416 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
417 if (!chxj_update_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
418 ERR(r, "failed: chxj_update_cookie_mysql() cookie_id:[%s]", cookie->cookie_id);
425 #if defined(USE_MEMCACHE_COOKIE)
426 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
427 if (! chxj_update_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
428 ERR(r, "failed: chxj_update_cookie_memcache() cookie_id:[%s]", cookie->cookie_id);
434 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
435 if (! chxj_update_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
436 ERR(r, "failed: chxj_update_cookie_dbm() cookie_id:[%s]", cookie->cookie_id);
442 chxj_save_cookie_expire(r, cookie);
444 apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
448 DBG(r, "end chxj_update_cookie()");
455 * @return loaded data.
458 chxj_load_cookie(request_rec *r, char *cookie_id)
460 mod_chxj_config *dconf;
461 chxjconvrule_entry *entryp;
463 apr_table_t *load_cookie_table;
464 char *load_string = NULL;
471 DBG(r, "REQ[%X] start chxj_load_cookie() cookie_id=[%s]", TO_ADDR(r), cookie_id);
472 chxj_cookie_expire_gc(r);
474 cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
475 cookie->cookie_headers = NULL;
476 cookie->cookie_id = chxj_url_decode(r->pool, apr_pstrdup(r->pool, cookie_id));
477 cookie->cookie_id = chxj_url_encode(r->pool, cookie->cookie_id);
480 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
481 entryp = chxj_apply_convrule(r, dconf->convrules);
483 DBG(r, "REQ[%X] end chxj_load_cookie() no pattern", TO_ADDR(r));
486 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
487 DBG(r, "REQ[%X] end chxj_load_cookie() CookieOff", TO_ADDR(r));
490 load_cookie_table = apr_table_make(r->pool, 0);
494 #if defined(USE_MYSQL_COOKIE)
495 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
496 if (! (load_string = chxj_load_cookie_mysql(r, dconf, cookie->cookie_id))) {
497 ERR(r, "%s:%d failed: chxj_load_cookie_mysql() cookie_id:[%s]", APLOG_MARK, cookie_id);
503 #if defined(USE_MEMCACHE_COOKIE)
504 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
505 if (! (load_string = chxj_load_cookie_memcache(r, dconf, cookie->cookie_id))) {
506 ERR(r, "%s:%d failed: chxj_load_cookie_memcache() cookie_id:[%s]", APLOG_MARK,cookie_id);
512 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
513 if (! (load_string = chxj_load_cookie_dbm(r, dconf, cookie->cookie_id))) {
514 ERR(r, "%s:%d failed: chxj_load_cookie_dbm() cookie_id:[%s]", APLOG_MARK,cookie_id);
521 DBG(r, "REQ[%X] load_string=[%s]", TO_ADDR(r), load_string);
522 header_cookie = apr_palloc(r->pool, 1);
523 header_cookie[0] = 0;
527 pair = apr_strtok(load_string, "\n", &pstat);
531 DBG(r, "REQ[%X] Cookie:[%s]", TO_ADDR(r), pair);
533 tmp_pair = apr_pstrdup(r->pool, pair);
534 val = strchr(tmp_pair, '=');
538 apr_table_add(load_cookie_table, key, val);
539 DBG(r, "REQ[%X] ADD key:[%s] val:[%s]", TO_ADDR(r), key, val);
541 tmp_pair = apr_pstrdup(r->pool, pair);
542 tmp_sem = strchr(tmp_pair, ';');
546 if (check_valid_cookie_attribute(r, pair)) {
547 if (strlen(header_cookie))
548 header_cookie = apr_pstrcat(r->pool, header_cookie, ";", NULL);
550 header_cookie = apr_pstrcat(r->pool, header_cookie, tmp_pair, NULL);
553 if (strlen(header_cookie)) {
554 DBG(r, "REQ[%X] ADD COOKIE to REQUEST HEADER:[%s]", TO_ADDR(r), header_cookie);
555 apr_table_add(r->headers_in, "Cookie", header_cookie);
558 cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
560 if (apr_table_get(r->headers_in, "referer") == NULL) {
561 apr_table_setn(r->headers_in,
563 apr_table_get(load_cookie_table, REFERER_COOKIE_KEY));
567 * save cookie_id to request header.
569 apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
572 DBG(r, "REQ[%X] end chxj_load_cookie()", TO_ADDR(r));
578 DBG(r, "REQ[%X] end chxj_load_cookie()", TO_ADDR(r));
583 check_valid_cookie_attribute(request_rec *r, const char *value)
594 DBG(r, "start check_valid_cookie_attribute() value:[%s]", value);
596 domain_pair = path_pair = expire_pair = secure_pair = NULL;
597 p = apr_pstrdup(r->pool, value);
599 /* pass first pair */
600 first_pair = apr_strtok(p, ";", &pstat);
603 pair = apr_strtok(NULL, ";", &pstat);
605 pair = qs_trim_string(r->pool, pair);
606 if (STRNCASEEQ('d','D',"domain", pair, sizeof("domain")-1)) {
607 domain_pair = apr_pstrdup(r->pool, pair);
609 else if (STRNCASEEQ('p','P',"path", pair, sizeof("path")-1)) {
610 path_pair = apr_pstrdup(r->pool, pair);
612 else if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
613 expire_pair = apr_pstrdup(r->pool, pair);
615 else if (STRNCASEEQ('s','S',"secure", pair, sizeof("secure")-1)) {
616 secure_pair = apr_pstrdup(r->pool, pair);
621 if (!valid_domain(r, domain_pair)) {
622 DBG(r, "invalid domain. domain_pair:[%s]", domain_pair);
627 if (!valid_path(r, path_pair)) {
628 DBG(r, "invalid path. path_pair:[%s]", path_pair);
633 if (!valid_expires(r, expire_pair)) {
634 DBG(r, "invalid expire. expire_pair:[%s]", expire_pair);
639 if (!valid_secure(r, secure_pair)) {
640 DBG(r, "invalid secure. secure_pair:[%s]", secure_pair);
644 DBG(r, "end check_valid_cookie_attribute() value:[%s]", value);
650 check_valid_cookie_attribute_expires_only(request_rec *r, const char *value)
655 char *expire_pair = NULL;
658 DBG(r, "REQ[%X] start check_valid_cookie_attribute_expires_only() value:[%s]", (unsigned int)(apr_size_t)r, value);
661 p = apr_pstrdup(r->pool, value);
663 /* pass first pair */
664 first_pair = apr_strtok(p, ";", &pstat);
667 pair = apr_strtok(NULL, ";", &pstat);
669 pair = qs_trim_string(r->pool, pair);
670 if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
671 expire_pair = apr_pstrdup(r->pool, pair);
676 if (!valid_expires(r, expire_pair)) {
677 DBG(r, "REQ[%X] invalid expire. expire_pair:[%s]", (unsigned int)(apr_size_t)r, expire_pair);
681 DBG(r, "REQ[%X] end check_valid_cookie_attribute_expires_only() value:[%s]", (unsigned int)(apr_size_t)r, value);
687 valid_domain(request_rec *r, const char *value)
693 char *p = apr_pstrdup(r->pool, value);
694 char *host = (char *)apr_table_get(r->headers_in, HTTP_HOST);
696 DBG(r, "REQ[%X] start valid_domain() value:[%s]", TO_ADDR(r), value);
698 DBG(r, "REQ[%X] end valid_domain() value:[%s]", TO_ADDR(r), value);
701 DBG(r, "REQ[%X] host:[%s]", TO_ADDR(r), host);
702 host = s_cut_until_end_hostname(r, apr_pstrdup(r->pool, host));
703 DBG(r, "REQ[%X] host:[%s](after s_cut_until_end_hostname())", TO_ADDR(r), host);
705 name = apr_strtok(p,"=", &pstat);
706 name = qs_trim_string(r->pool, name);
707 val = apr_strtok(NULL, "=", &pstat);
708 val = qs_trim_string(r->pool, val);
711 if (chxj_strcasenrcmp(r->pool, host, val, strlen(val))) {
712 DBG(r, "REQ[%X] not match domain. host domain:[%s] vs value:[%s]", TO_ADDR(r), host, val);
713 DBG(r, "REQ[%X] end valid_domain() value:[%s]", TO_ADDR(r), value);
717 DBG(r, "REQ[%X] end valid_domain() value:[%s]", TO_ADDR(r), value);
723 valid_path(request_rec *r, const char *value)
725 char *p = apr_pstrdup(r->pool, value);
732 DBG(r, "start valid_path() unparsed_uri:[%s] value:[%s]", r->unparsed_uri, value);
733 if (chxj_starts_with(r->unparsed_uri, "http://")) {
734 uri = strchr(&r->unparsed_uri[sizeof("http://")], '/');
736 uri = apr_pstrdup(r->pool, uri);
739 else if (chxj_starts_with(r->unparsed_uri, "https://")) {
740 uri = strchr(&r->unparsed_uri[sizeof("https://")], '/');
742 uri = apr_pstrdup(r->pool, uri);
745 else if (chxj_starts_with(r->unparsed_uri, "/")) {
746 uri = apr_pstrdup(r->pool, r->unparsed_uri);
749 uri = apr_pstrdup(r->pool, "/");
752 if ((tmp = strchr(uri, '?'))) {
755 DBG(r, "uri=[%s]", uri);
756 name = apr_strtok(p, "=", &pstat);
757 val = apr_strtok(NULL, "=", &pstat);
758 name = qs_trim_string(r->pool, name);
759 val = qs_trim_string(r->pool, val);
760 DBG(r, "name=[%s] val=[%s]", name, val);
762 DBG(r, "val:[%s] vs uri:[%s]", val, uri);
763 if (! chxj_starts_with(uri, val)) {
764 DBG(r, "end valid_path() unparsed_uri:[%s] value:[%s] (false)", r->unparsed_uri, value);
767 DBG(r, "end valid_path() unparsed_uri:[%s] value:[%s] (true)", r->unparsed_uri, value);
773 valid_expires(request_rec *r, const char *value)
777 char *p = apr_pstrdup(r->pool, value);
782 DBG(r, "start valid_expire() value:[%s]", value);
783 name = apr_strtok(p, "=", &pstat);
784 val = apr_strtok(NULL, "=", &pstat);
785 DBG(r, "name=[%s] val=[%s]", name, val);
786 now = apr_time_now();
787 expires = chxj_parse_cookie_expires(val);
789 DBG(r, "end valid_expire() value:[%s] (expired)", value);
793 DBG(r, "end valid_expire() value:[%s] (non expired)", value);
799 valid_secure(request_rec *r, const char *value)
802 DBG(r, "start valid_secure() value:[%s]", value);
803 scheme = chxj_apache_run_http_scheme(r);
804 if (strcasecmp("https", scheme)) {
805 DBG(r, "end valid_secure() value:[%s] (non secure)", value);
808 DBG(r, "end valid_secure() value:[%s] (secure)", value);
814 chxj_add_cookie_parameter(request_rec *r, char *value, cookie_t *cookie)
820 DBG(r, "REQ[%X] start chxj_add_cookie_parameter() cookie_id=[%s]", TO_ADDR(r), (cookie) ? cookie->cookie_id : NULL);
822 dst = apr_pstrdup(r->pool, value);
827 if (!cookie->cookie_id)
830 if (chxj_cookie_check_host(r, value) != 0) {
831 DBG(r, "REQ[%X] end chxj_add_cookie_parameter()(check host)", TO_ADDR(r));
835 qs = strchr(dst, '#');
837 name = apr_pstrdup(r->pool, qs);
841 qs = strchr(dst, '?');
844 qs = chxj_delete_chxj_cc_param(r, ++qs);
845 DBG(r, "REQ[%X] qs:[%s]",TO_ADDR(r), qs);
847 if (qs && strlen(qs)) {
848 dst = apr_psprintf(r->pool, "%s?%s", dst, qs);
852 dst = apr_psprintf(r->pool, "%s&%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
855 dst = apr_psprintf(r->pool, "%s?%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
858 DBG(r, "REQ[%X] end chxj_add_cookie_parameter() dst=[%s]", TO_ADDR(r), dst);
863 DBG(r, "REQ[%X] end chxj_add_cookie_parameter() (on_error)", TO_ADDR(r));
869 chxj_add_cookie_no_update_parameter(request_rec *r, char *value)
875 DBG(r, "REQ[%X] start chxj_add_cookie_no_update_parameter()", (unsigned int)(apr_size_t)r);
877 if (! value || ! *value) {
878 DBG(r, "REQ[%X] end chxj_add_cookie_parameter()(void value)", (unsigned int)(apr_size_t)r);
879 return apr_pstrdup(r->pool, "");
882 dst = apr_pstrdup(r->pool, value);
884 if (chxj_cookie_check_host(r, value) != 0) {
885 DBG(r, "REQ[%X] end chxj_add_cookie_parameter()(check host)", (unsigned int)(apr_size_t)r);
889 qs = strchr(dst, '#');
891 name = apr_pstrdup(r->pool, qs);
894 dst = apr_psprintf(r->pool, "%s%c%s=true%s", dst, (strchr(dst,'?')) ? '&' : '?',CHXJ_COOKIE_NOUPDATE_PARAM, name);
895 DBG(r, "REQ[%X] end chxj_add_cookie_no_update_parameter() dst=[%s]", (unsigned int)(apr_size_t)r, dst);
899 DBG(r, "REQ[%X] end chxj_add_cookie_no_update_parameter() (on_error)", (unsigned int)(apr_size_t)r);
905 chxj_cookie_check_host(request_rec *r, char *value)
908 mod_chxj_config *dconf;
910 DBG(r, "REQ[%X] start chxj_cookie_check_host()", (unsigned int)(apr_size_t)r);
911 DBG(r, "REQ[%X] hostname=[%s] vs Location:[%s]", (unsigned int)(apr_size_t)r, r->hostname, value);
913 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
915 hostnm = s_get_hostname_from_url(r, value);
917 if (dconf->allowed_cookie_domain) {
918 DBG(r, "REQ[%X] allowed_domain[%s] vs Location:[%s]", (unsigned int)(apr_size_t)r, dconf->allowed_cookie_domain, value);
919 if (chxj_strcasenrcmp(r->pool, hostnm, dconf->allowed_cookie_domain, strlen(dconf->allowed_cookie_domain))) {
920 DBG(r, "REQ[%X] end chxj_cookie_check_host() (false/allowed_domain)", (unsigned int)(apr_size_t)r);
924 DBG(r, "REQ[%X] end chxj_cookie_check_host() (true/allowed_domain)", (unsigned int)(apr_size_t)r);
929 if (strcasecmp(hostnm, r->hostname) == 0) {
930 DBG(r, "REQ[%X] end chxj_cookie_check_host() (true)", (unsigned int)(apr_size_t)r);
934 DBG(r, "REQ[%X] end chxj_cookie_check_host() (false)", (unsigned int)(apr_size_t)r);
939 DBG(r, "REQ[%X] end chxj_cookie_check_host() (true)", (unsigned int)(apr_size_t)r);
945 s_get_hostname_from_url(request_rec *r, char *value)
950 if (strncasecmp(value, "http://", 7) == 0 )
951 return s_cut_until_end_hostname(r, &value[7]);
953 if (strncasecmp(value, "https://", 8) == 0)
954 return s_cut_until_end_hostname(r, &value[8]);
961 s_cut_until_end_hostname(request_rec *r, char *value)
966 hostnm = sp = apr_pstrdup(r->pool, value);
968 if (*sp == '/'|| *sp == '?' || *sp == ':') {
979 chxj_delete_cookie(request_rec *r, const char *cookie_id)
982 mod_chxj_config *dconf;
984 DBG(r, "start chxj_delete_cookie()");
985 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
987 #if defined(USE_MYSQL_COOKIE)
988 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
989 if (! chxj_delete_cookie_mysql(r, dconf, cookie_id)) {
990 ERR(r, "failed: chxj_delete_cookie_mysql() cookie_id:[%s]", cookie_id);
991 DBG(r, "end chxj_delete_cookie()");
997 #if defined(USE_MEMCACHE_COOKIE)
998 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
999 if (! chxj_delete_cookie_memcache(r, dconf, cookie_id)) {
1000 ERR(r, "failed: chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
1001 DBG(r, "end chxj_delete_cookie()");
1007 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1008 if (! chxj_delete_cookie_dbm(r, dconf, cookie_id)) {
1009 ERR(r, "failed: chxj_delete_cookie_dbm() cookie_id:[%s]", cookie_id);
1010 DBG(r, "end chxj_delete_cookie()");
1015 DBG(r, "end chxj_delete_cookie()");
1023 chxj_save_cookie_expire(request_rec *r, cookie_t *cookie)
1026 mod_chxj_config *dconf;
1028 DBG(r, "start chxj_save_cookie_expire()");
1030 DBG(r, "cookie is NULL");
1033 if (!cookie->cookie_id) {
1034 DBG(r, "cookie->cookie_id is NULL");
1038 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1040 DBG(r, "dconf is NULL");
1044 #if defined(USE_MYSQL_COOKIE)
1045 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1046 if (! chxj_save_cookie_expire_mysql(r, dconf, cookie->cookie_id)) {
1047 ERR(r, "failed: chxj_save_cookie_expire_mysql() cookie_id:[%s]", cookie->cookie_id);
1048 DBG(r, "end chxj_save_cookie_expire()");
1054 #if defined(USE_MEMCACHE_COOKIE)
1055 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1056 if (! chxj_save_cookie_expire_memcache(r, dconf, cookie->cookie_id)) {
1057 ERR(r, "failed: chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie->cookie_id);
1058 DBG(r, "end chxj_save_cookie_expire()");
1064 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1065 if (! chxj_save_cookie_expire_dbm(r, dconf, cookie->cookie_id)) {
1066 ERR(r, "failed: chxj_save_cookie_expire_dbm() cookie_id:[%s]", cookie->cookie_id);
1067 DBG(r, "end chxj_save_cookie_expire()");
1072 DBG(r, "end chxj_save_cookie_expire()");
1077 chxj_delete_cookie_expire(request_rec *r, char *cookie_id)
1080 mod_chxj_config *dconf;
1082 DBG(r, "start chxj_delete_cookie_expire()");
1084 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1086 #if defined(USE_MYSQL_COOKIE)
1087 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1088 if (! chxj_delete_cookie_expire_mysql(r, dconf, cookie_id)) {
1089 ERR(r, "failed: chxj_delete_cookie_expire_mysql() cookie_id:[%s]", cookie_id);
1095 #if defined(USE_MEMCACHE_COOKIE)
1096 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1097 if (!chxj_delete_cookie_expire_memcache(r, dconf, cookie_id)) {
1098 ERR(r, "failed: chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
1104 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1105 if (!chxj_delete_cookie_expire_dbm(r, dconf, cookie_id)) {
1106 ERR(r, "failed: chxj_delete_cookie_expire_dbm() cookie_id:[%s]", cookie_id);
1111 DBG(r, "end chxj_delete_cookie_expire()");
1116 chxj_cookie_expire_gc(request_rec *r)
1118 mod_chxj_config *dconf;
1121 DBG(r, "start chxj_cookie_expire_gc()");
1123 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1124 #if defined(USE_MYSQL_COOKIE)
1125 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1126 if (! chxj_cookie_expire_gc_mysql(r, dconf)) {
1127 ERR(r, "%s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_mysql()", APLOG_MARK);
1133 #if defined(USE_MEMCACHE_COOKIE)
1134 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1135 if (! chxj_cookie_expire_gc_memcache(r, dconf)) {
1136 ERR(r, "%s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_memcache()", APLOG_MARK);
1143 if (! chxj_cookie_expire_gc_dbm(r, dconf)) {
1144 ERR(r, "%s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_dbm()", APLOG_MARK);
1148 DBG(r, "end chxj_cookie_expire_gc()");
1152 chxj_parse_cookie_expires(const char *s)
1154 if (!s) return (apr_time_t)0;
1155 return apr_date_parse_rfc(s);
1160 __chxj_cookie_lock(request_rec *r, const char *filename, int line)
1162 mod_chxj_config *dconf;
1165 cookie_lock_t *ret = NULL;
1167 DBG(r, "start chxj_cookie_lock() call from %s:%d", filename, line);
1168 if ((rv = apr_proc_mutex_lock(global_cookie_mutex)) != APR_SUCCESS) {
1170 ERR(r, "%s:%d apr_proc_mutex_lock failure.(%d:%s)", APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1173 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1174 #if defined(USE_MYSQL_COOKIE)
1175 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1176 if (! chxj_cookie_lock_mysql(r, dconf)) {
1177 ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_mysql()", APLOG_MARK);
1181 ret = apr_palloc(r->pool, sizeof(*ret));
1182 memset(ret, 0, sizeof(*ret));
1185 #if defined(USE_MEMCACHE_COOKIE)
1186 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1187 if (! chxj_cookie_lock_memcache(r, dconf)) {
1188 ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_memcache()", APLOG_MARK);
1192 ret = apr_palloc(r->pool, sizeof(*ret));
1193 memset(ret, 0, sizeof(*ret));
1197 if (!(ret = chxj_cookie_lock_dbm(r, dconf))) {
1198 ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_dbm()", APLOG_MARK);
1199 DBG(r, "end chxj_cookie_lock() call from %s:%d", filename, line);
1203 DBG(r, "REQ:[%X] end chxj_cookie_lock() call from %s:%d", (unsigned int)(apr_size_t)r, filename, line);
1209 __chxj_cookie_unlock(request_rec *r, cookie_lock_t *lock, const char *filename, int line)
1211 mod_chxj_config *dconf;
1216 DBG(r, "start chxj_cookie_unlock() call from %s:%d", filename, line);
1218 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1219 #if defined(USE_MYSQL_COOKIE)
1220 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1221 if (! chxj_cookie_unlock_mysql(r, dconf)) {
1222 ERR(r, "failed: chxj_cookie_unlock_mysql()");
1224 goto end_chxj_cookie_unlock;
1229 #if defined(USE_MEMCACHE_COOKIE)
1230 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1231 if (! chxj_cookie_unlock_memcache(r, dconf)) {
1232 ERR(r, "failed: chxj_cookie_unlock_memcache()");
1234 goto end_chxj_cookie_unlock;
1240 if (! chxj_cookie_unlock_dbm(r, lock, dconf)) {
1241 ERR(r, "failed: chxj_cookie_unlock_dbm()");
1243 goto end_chxj_cookie_unlock;
1246 end_chxj_cookie_unlock:
1247 if ((rv = apr_proc_mutex_unlock(global_cookie_mutex)) != APR_SUCCESS) {
1249 ERR(r, "%s:%d apr_proc_mutex_unlock failure.(%d:%s)", APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1250 DBG(r, "end chxj_cookie_unlock() call from %s:%d", filename, line);
1253 DBG(r, "end chxj_cookie_unlock() call from %s:%d", filename, line);