2 * Copyright (C) 2005-2011 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,"REQ[%X] cookie_id=[%s]", TO_ADDR(r),cookie_id);
97 cookie_id = chxj_url_encode(r->pool,cookie_id);
99 DBG(r, "REQ[%X] cookie_id=[%s]", TO_ADDR(r),cookie_id);
109 chxj_save_cookie(request_rec *r)
112 apr_array_header_t *headers;
113 apr_table_entry_t *hentryp;
114 apr_array_header_t *err_headers;
115 apr_table_entry_t *err_hentryp;
118 mod_chxj_config *dconf;
119 mod_chxj_req_config *req_conf;
120 chxjconvrule_entry *entryp;
121 apr_table_t *new_cookie_table;
124 cookie_t *old_cookie;
126 apr_uri_t parsed_uri;
131 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
133 apr_pool_create(&pool, r->pool);
135 cookie = (cookie_t*)apr_palloc(pool, sizeof(cookie_t));
136 cookie->cookie_id = NULL;
141 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
142 req_conf = chxj_get_req_config(r);
143 /*-------------------------------------------------------------------------*/
144 /* already setup entryp if request_conf->user_agent is not null */
145 /*-------------------------------------------------------------------------*/
146 if (req_conf->user_agent) {
147 entryp = req_conf->entryp;
150 entryp = chxj_apply_convrule(r, dconf->convrules);
153 DBG(r,"REQ[%X] end %s() no pattern",TO_ADDR(r),__func__);
156 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT) && ! (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
157 DBG(r,"REQ[%X] end %s() CookieOff",TO_ADDR(r),__func__);
163 headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
164 hentryp = (apr_table_entry_t*)headers->elts;
165 err_headers = (apr_array_header_t*)apr_table_elts(r->err_headers_out);
166 err_hentryp = (apr_table_entry_t*)err_headers->elts;
169 new_cookie_table = apr_table_make(pool, 0);
171 for (ii=0; ii<headers->nelts; ii++) {
172 if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
173 DBG(r, "REQ[%X] cookie=[%s:%s]", TO_ADDR(r), hentryp[ii].key, hentryp[ii].val);
179 char *pair = apr_psprintf(pool, "%s:%s", hentryp[ii].key, hentryp[ii].val);
180 if (check_valid_cookie_attribute_expires_only(r, pair)) {
181 buff = apr_pstrdup(pool, hentryp[ii].val);
182 val = strchr(buff, '=');
186 apr_table_set(new_cookie_table, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
187 if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
193 for (ii=0; ii<err_headers->nelts; ii++) {
194 if (strcasecmp(err_hentryp[ii].key, "Set-Cookie") == 0) {
195 DBG(r, "REQ[%X] cookie=[%s:%s]", TO_ADDR(r), err_hentryp[ii].key, err_hentryp[ii].val);
201 char *pair = apr_psprintf(pool, "%s:%s", err_hentryp[ii].key, err_hentryp[ii].val);
202 if (check_valid_cookie_attribute_expires_only(r, pair)) {
203 buff = apr_pstrdup(pool, err_hentryp[ii].val);
204 val = strchr(buff, '=');
208 apr_table_set(new_cookie_table, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
209 if (strcasecmp(REFERER_COOKIE_KEY, key) == 0) has_refer++;
215 apr_table_unset(r->headers_out, "Set-Cookie");
216 apr_table_unset(r->err_headers_out, "Set-Cookie");
219 apr_uri_parse(pool,r->uri, &parsed_uri);
220 refer_string = apr_psprintf(pool,
222 chxj_run_http_scheme(r),
224 apr_uri_unparse(pool,
226 APR_URI_UNP_OMITSITEPART));
227 if (r->args && strlen(r->args)) {
228 refer_string = apr_pstrcat(pool, refer_string, "?", r->args, NULL);
230 apr_table_setn(new_cookie_table, REFERER_COOKIE_KEY, refer_string);
231 DBG(r, "REQ[%X] ADD REFER[%s]", TO_ADDR(r),refer_string);
237 * check input parameters
239 old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
241 old_cookie = chxj_load_cookie(r, old_cookie_id);
242 if (old_cookie && old_cookie->cookie_headers) {
243 hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
244 for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
245 if (hentryp && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
246 apr_table_add(new_cookie_table, apr_pstrdup(pool, hentryp[ii].key), apr_pstrdup(pool, hentryp[ii].val));
250 chxj_delete_cookie(r, old_cookie_id);
251 chxj_delete_cookie_expire(r, old_cookie_id);
259 DBG(r,"REQ[%X] end %s() (no cookie)",TO_ADDR(r),__func__);
266 cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
267 hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
268 apr_size_t store_string_len = 0;
269 for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
270 if (ii) store_string_len++;
271 store_string_len += (strlen(hentryp[ii].key) + strlen(hentryp[ii].val) + 1);
273 store_string = apr_palloc(pool, store_string_len + 1);
274 memset(store_string, 0, store_string_len + 1);
277 for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
278 if (ii) store_string[npos++] = '\n';
279 memcpy(&store_string[npos], hentryp[ii].key, strlen(hentryp[ii].key));
280 npos += strlen(hentryp[ii].key);
281 store_string[npos++] = '=';
282 memcpy(&store_string[npos], hentryp[ii].val, strlen(hentryp[ii].val));
283 npos += strlen(hentryp[ii].val);
286 if (old_cookie_id && IS_COOKIE_LAZY(dconf)) {
287 DBG(r, "REQ[%X] LAZY COOKIE save",TO_ADDR(r));
288 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
290 else if (old_cookie_id && apr_table_get(r->headers_in, "X-Chxj-Cookie-No-Update")) {
291 DBG(r, "REQ[%X] NO UPDATE MODE",TO_ADDR(r));
292 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
295 if (old_cookie_id && apr_table_get(r->headers_in, "X-Chxj-Forward")) {
296 DBG(r, "REQ[%X] NO LAZY COOKIE(X-Chxj-Forward) save",TO_ADDR(r));
297 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie_id);
300 DBG(r, "REQ[%X] NO LAZY COOKIE save",TO_ADDR(r));
301 cookie->cookie_id = alloc_cookie_id(r);
305 DBG(r,"REQ[%X] TYPE:[%d]", TO_ADDR(r), dconf->cookie_store_type);
306 DBG(r,"REQ[%X] STORE STRING:=======================================================", TO_ADDR(r));
307 DBG(r,"REQ[%X] [%s]", TO_ADDR(r), store_string);
308 DBG(r,"REQ[%X] =======================================================:STORE STRING", TO_ADDR(r));
312 #if defined(USE_MYSQL_COOKIE)
313 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
314 if (! chxj_save_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
315 ERR(r, "%s:%d faild: chxj_save_cookie_mysql() cookie_id:[%s]", APLOG_MARK,cookie->cookie_id);
322 #if defined(USE_MEMCACHE_COOKIE)
323 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
324 if (! chxj_save_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
325 ERR(r, "%s:%d failed: chxj_save_cookie_memcache() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
332 if (IS_COOKIE_STORE_DBM(dconf->cookie_store_type) || ! done_proc) {
333 if (! chxj_save_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
334 ERR(r, "%s:%d failed: chxj_save_cookie_dbm() cookie_id:[%s]", APLOG_MARK, cookie->cookie_id);
340 apr_table_unset(r->headers_out, "Set-Cookie");
341 apr_table_unset(r->err_headers_out, "Set-Cookie");
344 chxj_save_cookie_expire(r, cookie);
348 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
358 chxj_update_cookie(request_rec *r, cookie_t *old_cookie)
361 apr_array_header_t *headers;
362 apr_table_entry_t *hentryp;
364 mod_chxj_config *dconf;
365 mod_chxj_req_config *req_conf;
366 chxjconvrule_entry *entryp;
370 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
371 if (!old_cookie || ! old_cookie->cookie_headers || ! old_cookie->cookie_id) {
372 DBG(r,"REQ[%X] old_cookie is null",TO_ADDR(r));
373 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
377 cookie = (cookie_t *)apr_palloc(r->pool, sizeof(cookie_t));
378 cookie->cookie_id = NULL;
380 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
381 req_conf = chxj_get_req_config(r);
382 /*-------------------------------------------------------------------------*/
383 /* already setup entryp if request_conf->user_agent is not null */
384 /*-------------------------------------------------------------------------*/
385 if (req_conf->user_agent) {
386 entryp = req_conf->entryp;
389 entryp = chxj_apply_convrule(r, dconf->convrules);
392 DBG(r,"REQ[%X] no pattern",TO_ADDR(r));
393 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
396 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
397 DBG(r,"REQ[%X] CookieOff",TO_ADDR(r));
398 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
402 headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
403 hentryp = (apr_table_entry_t*)headers->elts;
405 chxj_delete_cookie(r, old_cookie->cookie_id);
406 chxj_delete_cookie_expire(r, old_cookie->cookie_id);
408 if (IS_COOKIE_LAZY(dconf)) {
409 DBG(r,"REQ[%X] LAZY MODE",TO_ADDR(r));
410 cookie->cookie_id = apr_pstrdup(r->pool, old_cookie->cookie_id);
413 DBG(r,"REQ[%X] NO LAZY MODE",TO_ADDR(r));
414 cookie->cookie_id = alloc_cookie_id(r);
417 cookie->cookie_headers = old_cookie->cookie_headers;
418 store_string = apr_palloc(r->pool, 1);
420 hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
422 for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
423 if (ii) store_string = apr_pstrcat(r->pool,
428 DBG(r,"REQ[%X] OLD COOKIE VALUE=[%s][%s]",TO_ADDR(r), hentryp[ii].key, hentryp[ii].val);
429 store_string = apr_pstrcat(r->pool,
439 #if defined(USE_MYSQL_COOKIE)
440 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
441 if (!chxj_update_cookie_mysql(r, dconf, cookie->cookie_id, store_string)) {
442 ERR(r,"REQ[%X] failed: chxj_update_cookie_mysql() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
449 #if defined(USE_MEMCACHE_COOKIE)
450 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
451 if (! chxj_update_cookie_memcache(r, dconf, cookie->cookie_id, store_string)) {
452 ERR(r, "REQ[%X] failed: chxj_update_cookie_memcache() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
458 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
459 if (! chxj_update_cookie_dbm(r, dconf, cookie->cookie_id, store_string)) {
460 ERR(r, "REQ[%X] failed: chxj_update_cookie_dbm() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
466 chxj_save_cookie_expire(r, cookie);
468 apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
472 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
479 * @return loaded data.
482 chxj_load_cookie(request_rec *r, char *cookie_id)
484 mod_chxj_config *dconf;
485 mod_chxj_req_config *req_conf;
486 chxjconvrule_entry *entryp;
488 apr_table_t *load_cookie_table;
489 char *load_string = NULL;
496 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
497 DBG(r,"REQ[%X] cookie_id=[%s]", TO_ADDR(r), cookie_id);
498 chxj_cookie_expire_gc(r);
500 cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
501 cookie->cookie_headers = NULL;
502 cookie->cookie_id = chxj_url_decode(r->pool, apr_pstrdup(r->pool, cookie_id));
503 cookie->cookie_id = chxj_url_encode(r->pool, cookie->cookie_id);
506 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
507 req_conf = chxj_get_req_config(r);
508 /*-------------------------------------------------------------------------*/
509 /* already setup entryp if request_conf->user_agent is not null */
510 /*-------------------------------------------------------------------------*/
511 if (req_conf->user_agent) {
512 entryp = req_conf->entryp;
515 entryp = chxj_apply_convrule(r, dconf->convrules);
518 DBG(r,"REQ[%X] pattern", TO_ADDR(r));
519 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
522 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT) && ! (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
523 DBG(r,"REQ[%X] CookieOff", TO_ADDR(r));
524 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
527 load_cookie_table = apr_table_make(r->pool, 0);
531 #if defined(USE_MYSQL_COOKIE)
532 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
533 if (! (load_string = chxj_load_cookie_mysql(r, dconf, cookie->cookie_id))) {
534 ERR(r, "REQ[%X] %s:%d failed: chxj_load_cookie_mysql() cookie_id:[%s]", TO_ADDR(r),APLOG_MARK, cookie_id);
540 #if defined(USE_MEMCACHE_COOKIE)
541 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
542 if (! (load_string = chxj_load_cookie_memcache(r, dconf, cookie->cookie_id))) {
543 ERR(r, "REQ[%X] %s:%d failed: chxj_load_cookie_memcache() cookie_id:[%s]", TO_ADDR(r),APLOG_MARK,cookie_id);
549 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
550 if (! (load_string = chxj_load_cookie_dbm(r, dconf, cookie->cookie_id))) {
551 ERR(r, "REQ[%X] %s:%d failed: chxj_load_cookie_dbm() cookie_id:[%s]", TO_ADDR(r),APLOG_MARK,cookie_id);
558 DBG(r, "REQ[%X] load_string=[%s]", TO_ADDR(r), load_string);
559 header_cookie = apr_palloc(r->pool, 1);
560 header_cookie[0] = 0;
564 pair = apr_strtok(load_string, "\n", &pstat);
568 DBG(r,"REQ[%X] Cookie:[%s]", TO_ADDR(r), pair);
570 tmp_pair = apr_pstrdup(r->pool, pair);
571 val = strchr(tmp_pair, '=');
575 apr_table_add(load_cookie_table, key, val);
576 DBG(r,"REQ[%X] ADD key:[%s] val:[%s]", TO_ADDR(r), key, val);
578 tmp_pair = apr_pstrdup(r->pool, pair);
579 tmp_sem = strchr(tmp_pair, ';');
583 if (check_valid_cookie_attribute(r, pair)) {
584 if (strlen(header_cookie))
585 header_cookie = apr_pstrcat(r->pool, header_cookie, ";", NULL);
587 header_cookie = apr_pstrcat(r->pool, header_cookie, tmp_pair, NULL);
590 if (strlen(header_cookie)) {
591 DBG(r,"REQ[%X] ADD COOKIE to REQUEST HEADER:[%s]", TO_ADDR(r), header_cookie);
592 apr_table_add(r->headers_in, "Cookie", header_cookie);
595 cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
597 if (apr_table_get(r->headers_in, "referer") == NULL) {
598 apr_table_setn(r->headers_in,
600 apr_table_get(load_cookie_table, REFERER_COOKIE_KEY));
604 * save cookie_id to request header.
606 apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
609 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
615 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
620 check_valid_cookie_attribute(request_rec *r, const char *value)
631 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
632 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r),value);
634 domain_pair = path_pair = expire_pair = secure_pair = NULL;
635 p = apr_pstrdup(r->pool, value);
637 /* pass first pair */
638 first_pair = apr_strtok(p, ";", &pstat);
641 pair = apr_strtok(NULL, ";", &pstat);
643 pair = qs_trim_string(r->pool, pair);
644 if (STRNCASEEQ('d','D',"domain", pair, sizeof("domain")-1)) {
645 domain_pair = apr_pstrdup(r->pool, pair);
647 else if (STRNCASEEQ('p','P',"path", pair, sizeof("path")-1)) {
648 path_pair = apr_pstrdup(r->pool, pair);
650 else if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
651 expire_pair = apr_pstrdup(r->pool, pair);
653 else if (STRNCASEEQ('s','S',"secure", pair, sizeof("secure")-1)) {
654 secure_pair = apr_pstrdup(r->pool, pair);
659 if (!valid_domain(r, domain_pair)) {
660 DBG(r,"REQ[%X] invalid domain. domain_pair:[%s]", TO_ADDR(r),domain_pair);
661 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
666 if (!valid_path(r, path_pair)) {
667 DBG(r,"REQ[%X] invalid path. path_pair:[%s]", TO_ADDR(r),path_pair);
668 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
673 if (!valid_expires(r, expire_pair)) {
674 DBG(r,"REQ[%X] invalid expire. expire_pair:[%s]", TO_ADDR(r),expire_pair);
675 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
680 if (!valid_secure(r, secure_pair)) {
681 DBG(r,"REQ[%X] invalid secure. secure_pair:[%s]", TO_ADDR(r),secure_pair);
682 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
686 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r),value);
687 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
693 check_valid_cookie_attribute_expires_only(request_rec *r, const char *value)
698 char *expire_pair = NULL;
701 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
702 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
705 p = apr_pstrdup(r->pool, value);
707 /* pass first pair */
708 first_pair = apr_strtok(p, ";", &pstat);
711 pair = apr_strtok(NULL, ";", &pstat);
713 pair = qs_trim_string(r->pool, pair);
714 if (STRNCASEEQ('e','E',"expires", pair, sizeof("expires")-1)) {
715 expire_pair = apr_pstrdup(r->pool, pair);
720 if (!valid_expires(r, expire_pair)) {
721 DBG(r,"REQ[%X] invalid expire. expire_pair:[%s]", TO_ADDR(r), expire_pair);
722 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
726 DBG(r,"REQ[%X] value:[%s]",TO_ADDR(r), value);
727 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
733 valid_domain(request_rec *r, const char *value)
739 char *p = apr_pstrdup(r->pool, value);
740 char *host = (char *)apr_table_get(r->headers_in, HTTP_HOST);
742 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
743 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
745 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
746 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
749 DBG(r, "REQ[%X] host:[%s]", TO_ADDR(r), host);
750 host = s_cut_until_end_hostname(r, apr_pstrdup(r->pool, host));
751 DBG(r, "REQ[%X] host:[%s](after s_cut_until_end_hostname())", TO_ADDR(r), host);
753 name = apr_strtok(p,"=", &pstat);
754 name = qs_trim_string(r->pool, name);
755 val = apr_strtok(NULL, "=", &pstat);
756 val = qs_trim_string(r->pool, val);
759 if (chxj_strcasenrcmp(r->pool, host, val, strlen(val))) {
760 DBG(r,"REQ[%X] not match domain. host domain:[%s] vs value:[%s]", TO_ADDR(r), host, val);
761 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
762 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
766 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r), value);
767 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
773 valid_path(request_rec *r, const char *value)
775 char *p = apr_pstrdup(r->pool, value);
782 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
783 DBG(r,"REQ[%X] unparsed_uri:[%s] value:[%s]", TO_ADDR(r),r->unparsed_uri, value);
784 if (chxj_starts_with(r->unparsed_uri, "http://")) {
785 uri = strchr(&r->unparsed_uri[sizeof("http://")], '/');
787 uri = apr_pstrdup(r->pool, uri);
790 else if (chxj_starts_with(r->unparsed_uri, "https://")) {
791 uri = strchr(&r->unparsed_uri[sizeof("https://")], '/');
793 uri = apr_pstrdup(r->pool, uri);
796 else if (chxj_starts_with(r->unparsed_uri, "/")) {
797 uri = apr_pstrdup(r->pool, r->unparsed_uri);
800 uri = apr_pstrdup(r->pool, "/");
803 if ((tmp = strchr(uri, '?'))) {
806 DBG(r,"REQ[%X] uri=[%s]", TO_ADDR(r),uri);
807 name = apr_strtok(p, "=", &pstat);
808 val = apr_strtok(NULL, "=", &pstat);
809 name = qs_trim_string(r->pool, name);
810 val = qs_trim_string(r->pool, val);
811 DBG(r,"REQ[%X] name=[%s] val=[%s]", TO_ADDR(r),name, val);
813 DBG(r, "REQ[%X] val:[%s] vs uri:[%s]", TO_ADDR(r),val, uri);
814 if (! chxj_starts_with(uri, val)) {
815 DBG(r,"REQ[%X] unparsed_uri:[%s] value:[%s] (false)",TO_ADDR(r), r->unparsed_uri, value);
816 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
819 DBG(r,"REQ[%X] unparsed_uri:[%s] value:[%s] (true)", TO_ADDR(r),r->unparsed_uri, value);
820 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
826 valid_expires(request_rec *r, const char *value)
830 char *p = apr_pstrdup(r->pool, value);
835 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
836 DBG(r,"REQ[%X] value:[%s]",TO_ADDR(r),value);
837 name = apr_strtok(p, "=", &pstat);
838 val = apr_strtok(NULL, "=", &pstat);
839 DBG(r,"REQ[%X] name=[%s] val=[%s]", TO_ADDR(r),name, val);
840 now = apr_time_now();
841 expires = chxj_parse_cookie_expires(val);
843 DBG(r,"REQ[%X] value:[%s] (expired)", TO_ADDR(r),value);
844 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
848 DBG(r,"REQ[%X] value:[%s] (non expired)", TO_ADDR(r),value);
849 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
855 valid_secure(request_rec *r, const char *value)
858 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
859 DBG(r,"REQ[%X] value:[%s]", TO_ADDR(r),value);
860 scheme = chxj_apache_run_http_scheme(r);
861 if (strcasecmp("https", scheme)) {
862 DBG(r,"REQ[%X] value:[%s] (non secure)", TO_ADDR(r),value);
863 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
866 DBG(r,"REQ[%X] value:[%s] (secure)", TO_ADDR(r),value);
867 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
873 chxj_add_cookie_parameter(request_rec *r, char *value, cookie_t *cookie)
879 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
880 DBG(r,"REQ[%X] cookie_id=[%s]", TO_ADDR(r), (cookie) ? cookie->cookie_id : NULL);
882 dst = apr_pstrdup(r->pool, value);
887 if (!cookie->cookie_id)
890 if (chxj_cookie_check_host(r, value) != 0) {
891 DBG(r,"REQ[%X] (check host)", TO_ADDR(r));
892 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
896 qs = strchr(dst, '#');
898 name = apr_pstrdup(r->pool, qs);
902 qs = strchr(dst, '?');
905 qs = chxj_delete_chxj_cc_param(r, ++qs);
906 DBG(r, "REQ[%X] qs:[%s]",TO_ADDR(r), qs);
908 if (qs && strlen(qs)) {
909 dst = apr_psprintf(r->pool, "%s?%s", dst, qs);
913 dst = apr_psprintf(r->pool, "%s&%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
916 dst = apr_psprintf(r->pool, "%s?%s=%s%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id, name);
919 DBG(r,"REQ[%X] dst=[%s]", TO_ADDR(r), dst);
920 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
925 DBG(r,"REQ[%X] (on_error)", TO_ADDR(r));
926 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
932 chxj_add_cookie_no_update_parameter(request_rec *r, char *value)
938 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
940 if (! value || ! *value) {
941 DBG(r,"REQ[%X] (void value)", TO_ADDR(r));
942 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
943 return apr_pstrdup(r->pool, "");
946 dst = apr_pstrdup(r->pool, value);
948 if (chxj_cookie_check_host(r, value) != 0) {
949 DBG(r,"REQ[%X] (check host)", TO_ADDR(r));
950 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
954 qs = strchr(dst, '#');
956 name = apr_pstrdup(r->pool, qs);
959 dst = apr_psprintf(r->pool, "%s%c%s=true%s", dst, (strchr(dst,'?')) ? '&' : '?',CHXJ_COOKIE_NOUPDATE_PARAM, name);
960 DBG(r,"REQ[%X] dst=[%s]", TO_ADDR(r), dst);
961 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
965 DBG(r,"REQ[%X] (on_error)", TO_ADDR(r));
966 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
972 chxj_cookie_check_host(request_rec *r, char *value)
975 mod_chxj_config *dconf;
977 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
978 DBG(r,"REQ[%X] hostname=[%s] vs Location:[%s]", TO_ADDR(r), r->hostname, value);
980 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
982 hostnm = s_get_hostname_from_url(r, value);
984 if (dconf->allowed_cookie_domain) {
985 DBG(r, "REQ[%X] allowed_domain[%s] vs Location:[%s]", TO_ADDR(r), dconf->allowed_cookie_domain, value);
986 if (chxj_strcasenrcmp(r->pool, hostnm, dconf->allowed_cookie_domain, strlen(dconf->allowed_cookie_domain))) {
987 DBG(r,"REQ[%X] (false/allowed_domain)", TO_ADDR(r));
988 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
992 DBG(r,"REQ[%X] (true/allowed_domain)", TO_ADDR(r));
993 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
998 if (strcasecmp(hostnm, r->hostname) == 0) {
999 DBG(r,"REQ[%X] (true)", TO_ADDR(r));
1000 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1004 DBG(r,"REQ[%X] (false)", TO_ADDR(r));
1005 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1010 DBG(r,"REQ[%X] (true)", TO_ADDR(r));
1011 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1017 s_get_hostname_from_url(request_rec *r, char *value)
1022 if (strncasecmp(value, "http://", 7) == 0 )
1023 return s_cut_until_end_hostname(r, &value[7]);
1025 if (strncasecmp(value, "https://", 8) == 0)
1026 return s_cut_until_end_hostname(r, &value[8]);
1033 s_cut_until_end_hostname(request_rec *r, char *value)
1038 hostnm = sp = apr_pstrdup(r->pool, value);
1040 if (*sp == '/'|| *sp == '?' || *sp == ':') {
1051 chxj_delete_cookie(request_rec *r, const char *cookie_id)
1054 mod_chxj_config *dconf;
1056 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1057 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1059 #if defined(USE_MYSQL_COOKIE)
1060 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1061 if (! chxj_delete_cookie_mysql(r, dconf, cookie_id)) {
1062 ERR(r,"REQ[%X] failed: chxj_delete_cookie_mysql() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1063 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1069 #if defined(USE_MEMCACHE_COOKIE)
1070 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1071 if (! chxj_delete_cookie_memcache(r, dconf, cookie_id)) {
1072 ERR(r,"REQ[%X] failed: chxj_delete_cookie_memcache() cookie_id:[%s]", TO_ADDR(r), cookie_id);
1073 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1079 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1080 if (! chxj_delete_cookie_dbm(r, dconf, cookie_id)) {
1081 ERR(r,"REQ[%X] failed: chxj_delete_cookie_dbm() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1082 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1087 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1095 chxj_save_cookie_expire(request_rec *r, cookie_t *cookie)
1098 mod_chxj_config *dconf;
1100 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1102 DBG(r,"REQ[%X] cookie is NULL",TO_ADDR(r));
1103 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1106 if (!cookie->cookie_id) {
1107 DBG(r,"REQ[%X] cookie->cookie_id is NULL",TO_ADDR(r));
1108 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1112 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1114 DBG(r,"REQ[%X] dconf is NULL",TO_ADDR(r));
1115 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1119 #if defined(USE_MYSQL_COOKIE)
1120 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1121 if (! chxj_save_cookie_expire_mysql(r, dconf, cookie->cookie_id)) {
1122 ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_mysql() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1123 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1129 #if defined(USE_MEMCACHE_COOKIE)
1130 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1131 if (! chxj_save_cookie_expire_memcache(r, dconf, cookie->cookie_id)) {
1132 ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_memcache() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1133 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1139 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1140 if (! chxj_save_cookie_expire_dbm(r, dconf, cookie->cookie_id)) {
1141 ERR(r,"REQ[%X] failed: chxj_save_cookie_expire_dbm() cookie_id:[%s]", TO_ADDR(r),cookie->cookie_id);
1142 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1147 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1152 chxj_delete_cookie_expire(request_rec *r, char *cookie_id)
1155 mod_chxj_config *dconf;
1157 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1159 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1161 #if defined(USE_MYSQL_COOKIE)
1162 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1163 if (! chxj_delete_cookie_expire_mysql(r, dconf, cookie_id)) {
1164 ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_mysql() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1165 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1171 #if defined(USE_MEMCACHE_COOKIE)
1172 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1173 if (!chxj_delete_cookie_expire_memcache(r, dconf, cookie_id)) {
1174 ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_memcache() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1175 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1181 if (!done_proc || IS_COOKIE_STORE_DBM(dconf->cookie_store_type)) {
1182 if (!chxj_delete_cookie_expire_dbm(r, dconf, cookie_id)) {
1183 ERR(r,"REQ[%X] failed: chxj_delete_cookie_expire_dbm() cookie_id:[%s]", TO_ADDR(r),cookie_id);
1184 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1189 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1194 chxj_cookie_expire_gc(request_rec *r)
1196 mod_chxj_config *dconf;
1199 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1201 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1202 #if defined(USE_MYSQL_COOKIE)
1203 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1204 if (! chxj_cookie_expire_gc_mysql(r, dconf)) {
1205 ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_mysql()", TO_ADDR(r),APLOG_MARK);
1206 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1212 #if defined(USE_MEMCACHE_COOKIE)
1213 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1214 if (! chxj_cookie_expire_gc_memcache(r, dconf)) {
1215 ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_memcache()", TO_ADDR(r),APLOG_MARK);
1216 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1223 if (! chxj_cookie_expire_gc_dbm(r, dconf)) {
1224 ERR(r,"REQ[%X] %s:%d end chxj_cookie_expire_gc(): failed: chxj_cookie_expire_gc_dbm()", TO_ADDR(r),APLOG_MARK);
1225 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1229 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1233 chxj_parse_cookie_expires(const char *s)
1235 if (!s) return (apr_time_t)0;
1236 return apr_date_parse_rfc(s);
1241 __chxj_cookie_lock(request_rec *r, const char *filename, int line)
1243 mod_chxj_config *dconf;
1246 cookie_lock_t *ret = NULL;
1248 DBG(r,"REQ[%X] start %s() call from %s:%d",TO_ADDR(r),__func__, filename,line);
1249 if ((rv = apr_proc_mutex_lock(global_cookie_mutex)) != APR_SUCCESS) {
1251 ERR(r,"REQ[%X] %s:%d apr_proc_mutex_lock failure.(%d:%s)", TO_ADDR(r),APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1252 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1255 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1256 #if defined(USE_MYSQL_COOKIE)
1257 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1258 if (! chxj_cookie_lock_mysql(r, dconf)) {
1259 ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_mysql()", TO_ADDR(r),APLOG_MARK);
1260 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1264 ret = apr_palloc(r->pool, sizeof(*ret));
1265 memset(ret, 0, sizeof(*ret));
1268 #if defined(USE_MEMCACHE_COOKIE)
1269 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1270 if (! chxj_cookie_lock_memcache(r, dconf)) {
1271 ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_memcache()", TO_ADDR(r),APLOG_MARK);
1272 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1276 ret = apr_palloc(r->pool, sizeof(*ret));
1277 memset(ret, 0, sizeof(*ret));
1281 if (!(ret = chxj_cookie_lock_dbm(r, dconf))) {
1282 ERR(r,"REQ[%X] %s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_dbm()", TO_ADDR(r),APLOG_MARK);
1283 DBG(r,"REQ[%X] end %s() call from %s:%d",TO_ADDR(r),__func__,filename,line);
1287 DBG(r,"REQ[%X] end %s() call from %s:%d",TO_ADDR(r),__func__,filename,line);
1293 __chxj_cookie_unlock(request_rec *r, cookie_lock_t *lock, const char *filename, int line)
1295 mod_chxj_config *dconf;
1300 DBG(r,"REQ[%X] start %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1302 dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1303 #if defined(USE_MYSQL_COOKIE)
1304 if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) {
1305 if (! chxj_cookie_unlock_mysql(r, dconf)) {
1306 ERR(r,"REQ[%X] failed: chxj_cookie_unlock_mysql()",TO_ADDR(r));
1308 goto end_chxj_cookie_unlock;
1313 #if defined(USE_MEMCACHE_COOKIE)
1314 if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) {
1315 if (! chxj_cookie_unlock_memcache(r, dconf)) {
1316 ERR(r,"REQ[%X] failed: chxj_cookie_unlock_memcache()",TO_ADDR(r));
1318 goto end_chxj_cookie_unlock;
1324 if (! chxj_cookie_unlock_dbm(r, lock, dconf)) {
1325 ERR(r,"REQ[%X] failed: chxj_cookie_unlock_dbm()",TO_ADDR(r));
1327 goto end_chxj_cookie_unlock;
1330 end_chxj_cookie_unlock:
1331 if ((rv = apr_proc_mutex_unlock(global_cookie_mutex)) != APR_SUCCESS) {
1333 ERR(r,"REQ[%X] %s:%d apr_proc_mutex_unlock failure.(%d:%s)", TO_ADDR(r),APLOG_MARK, rv, apr_strerror(rv, errstr, 255));
1334 DBG(r,"REQ[%X] end %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1337 DBG(r,"REQ[%X] end %s() call from %s:%d", TO_ADDR(r),__func__,filename, line);
1343 #include "chxj_encoding.h"
1345 s_convert_a_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1348 ap_regex_t *regexp = NULL;
1353 apr_pool_create(&pool, r->pool);
1354 regexp = ap_pregcomp(pool, "(<a[^>]*>)", AP_REG_EXTENDED|AP_REG_ICASE);
1356 qs_init_malloc(&doc);
1357 qs_init_root_node(&doc);
1360 ap_regmatch_t match[10];
1361 if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1362 apr_size_t plen = match[1].rm_so;
1364 char *tmpstr = apr_palloc(pool, plen + 1);
1365 memset(tmpstr, 0, plen + 1);
1366 memcpy(tmpstr, &s[nowpos], plen);
1367 dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1372 char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1374 Node *node = qs_parse_tag(&doc, matchstr, strlen(matchstr) - 1);
1377 DBG(r,"REQ[%X] matchstr:[%s]", TO_ADDR(r),matchstr);
1378 dst = apr_pstrcat(pool, (dst) ? dst : "", "<a ", NULL);
1379 for (attr = qs_get_attr(&doc,node);
1381 attr = qs_get_next_attr(&doc,attr)) {
1382 char *name = qs_get_attr_name(&doc,attr);
1383 char *value = qs_get_attr_value(&doc,attr);
1384 DBG(r,"REQ[%X] name:[%s] value=[%s]",TO_ADDR(r), name, value);
1385 if (STRCASEEQ('h', 'H', "href", name)
1386 && ! chxj_starts_with(value, "mailto:")
1387 && ! chxj_starts_with(value, "tel:")) {
1388 char *flgp = strchr(value, '#');
1391 int flgl = strlen(flgp);
1392 flgsv = apr_palloc(pool, flgl+1);
1393 memset(flgsv, 0, flgl + 1);
1394 memcpy(flgsv, flgp, flgl);
1397 if (strchr(value, '?') != 0) {
1398 value = apr_pstrcat(pool, value, "&_chxj_cc=", cookie->cookie_id, NULL);
1401 value = apr_pstrcat(pool, value, "?_chxj_cc=", cookie->cookie_id, NULL);
1404 value = apr_pstrcat(pool, value, flgsv, NULL);
1406 dst = apr_pstrcat(pool, (dst) ? dst : "", "href='", value, "' ", NULL);
1409 dst = apr_pstrcat(pool, (dst) ? dst : "", name, "='", value, "' ", NULL);
1412 dst = apr_pstrcat(pool, (dst) ? dst : "", ">", NULL);
1413 plen += strlen(matchstr);
1422 if ((apr_size_t)nowpos < *len) {
1423 apr_size_t plen = *len - nowpos;
1424 char *tmpstr = apr_palloc(pool, plen + 1);
1425 memset(tmpstr, 0, plen+1);
1426 memcpy(tmpstr, &s[nowpos], plen);
1427 dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1434 s_convert_img_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1437 ap_regex_t *regexp = NULL;
1442 apr_pool_create(&pool, r->pool);
1443 regexp = ap_pregcomp(pool, "(<img[^>]*>)", AP_REG_EXTENDED|AP_REG_ICASE);
1445 qs_init_malloc(&doc);
1446 qs_init_root_node(&doc);
1449 ap_regmatch_t match[10];
1450 if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1451 apr_size_t plen = match[1].rm_so;
1453 char *tmpstr = apr_palloc(pool, plen + 1);
1454 memset(tmpstr, 0, plen + 1);
1455 memcpy(tmpstr, &s[nowpos], plen);
1456 dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1461 char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1463 Node *node = qs_parse_tag(&doc, matchstr, strlen(matchstr) - 1);
1466 DBG(r,"REQ[%X] matchstr:[%s]", TO_ADDR(r),matchstr);
1467 dst = apr_pstrcat(pool, (dst) ? dst : "", "<img ", NULL);
1468 for (attr = qs_get_attr(&doc,node);
1470 attr = qs_get_next_attr(&doc,attr)) {
1471 char *name = qs_get_attr_name(&doc,attr);
1472 char *value = qs_get_attr_value(&doc,attr);
1473 DBG(r,"REQ[%X] name:[%s] value=[%s]", TO_ADDR(r),name, value);
1474 if (STRCASEEQ('s', 'S', "src", name)) {
1475 if (strchr(value, '?') != 0) {
1476 value = apr_pstrcat(pool, value, "&_chxj_cc=", cookie->cookie_id, "&_chxj_nc=true", NULL);
1479 value = apr_pstrcat(pool, value, "?_chxj_cc=", cookie->cookie_id, "&_chxj_nc=true", NULL);
1481 dst = apr_pstrcat(pool, (dst) ? dst : "", "src='", value, "' ", NULL);
1484 dst = apr_pstrcat(pool, (dst) ? dst : "", name, "='", value, "' ", NULL);
1487 dst = apr_pstrcat(pool, (dst) ? dst : "", "/>", NULL);
1488 plen += strlen(matchstr);
1497 if ((apr_size_t)nowpos < *len) {
1498 apr_size_t plen = *len - nowpos;
1499 char *tmpstr = apr_palloc(pool, plen + 1);
1500 memset(tmpstr, 0, plen+1);
1501 memcpy(tmpstr, &s[nowpos], plen);
1502 dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1509 s_convert_form_tag(request_rec *r, const char *s, apr_size_t *len, cookie_t *cookie)
1512 ap_regex_t *regexp = NULL;
1518 apr_pool_create(&pool, r->pool);
1519 regexp = ap_pregcomp(pool, "(</form>)", AP_REG_EXTENDED|AP_REG_ICASE);
1521 qs_init_malloc(&doc);
1522 qs_init_root_node(&doc);
1523 cookie_id = chxj_url_decode(pool, cookie->cookie_id);
1526 ap_regmatch_t match[10];
1527 if (ap_regexec((const ap_regex_t *)regexp, &s[nowpos], (apr_size_t)regexp->re_nsub + 1, match, 0) == 0) {
1528 apr_size_t plen = match[1].rm_so;
1530 char *tmpstr = apr_palloc(pool, plen + 1);
1531 memset(tmpstr, 0, plen + 1);
1532 memcpy(tmpstr, &s[nowpos], plen);
1533 dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1538 char *matchstr = ap_pregsub(pool, "$1", &s[nowpos], regexp->re_nsub + 1, match);
1540 DBG(r,"REQ[%X] matchstr:[%s]",TO_ADDR(r),matchstr);
1541 dst = apr_pstrcat(pool, (dst) ? dst : "", "<input type='hidden' name='_chxj_cc' value='", cookie_id, "' />", matchstr, NULL);
1542 plen += strlen(matchstr);
1551 if ((apr_size_t)nowpos < *len) {
1552 apr_size_t plen = *len - nowpos;
1553 char *tmpstr = apr_palloc(pool, plen + 1);
1554 memset(tmpstr, 0, plen + 1);
1555 memcpy(tmpstr, &s[nowpos], plen);
1556 dst = apr_pstrcat(pool, (dst) ? dst : "", tmpstr, NULL);
1564 chxj_cookie_only_mode(request_rec *r, const char *src, apr_size_t *len, cookie_t* cookie)
1570 DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1571 s = chxj_encoding(r, src, len);
1573 dst = s_convert_a_tag(r, s, len, cookie);
1574 dst = s_convert_img_tag(r, dst, len, cookie);
1575 dst = s_convert_form_tag(r, dst, len, cookie);
1577 result = chxj_rencoding(r, dst, len, NULL);
1578 DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);