OSDN Git Service

* Added New Features.
[modchxj/mod_chxj.git] / src / mod_chxj.c
index 6b3459e..31716ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
+ * Copyright (C) 2005-2009 Atsushi Konno All rights reserved.
  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
 #  include "chxj_mysql.h"
 #endif
 #include "chxj_serf.h"
+#include "chxj_add_device_env.h"
+#include "chxj_conv_z2h.h"
+#include "chxj_header_inf.h"
+#include "chxj_jreserved_tag.h"
 
 
 #define CHXJ_VERSION_PREFIX PACKAGE_NAME "/"
 converter_t convert_routine[] = {
   {
     /* CHXJ_SPEC_UNKNOWN          */
-    .converter = NULL,
-    .encoder  = NULL,
+    .converter            = NULL,
+    .encoder              = NULL,
+    .emoji_only_converter = NULL,
   },
   {
     /* CHXJ_SPEC_Chtml_1_0        */
-    .converter = chxj_convert_chtml10,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_chtml10,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_chtml10_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Chtml_2_0        */
-    .converter = chxj_convert_chtml20,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_chtml20,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_chtml20_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Chtml_3_0        */
-    .converter = chxj_convert_chtml30,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_chtml30,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_chtml30_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Chtml_4_0        */
-    .converter = chxj_convert_chtml40,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_chtml40,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_chtml40_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Chtml_5_0        */
-    .converter = chxj_convert_chtml50,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_chtml50,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_chtml50_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Chtml_6_0        */
-    .converter = chxj_convert_chtml50,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_chtml50,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_chtml50_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Chtml_7_0        */
-    .converter = chxj_convert_chtml50,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_chtml50,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_chtml50_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_XHtml_Mobile_1_0 */
-    .converter = chxj_convert_xhtml_mobile_1_0,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_xhtml_mobile_1_0,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_xhtml_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Hdml             */
-    .converter = chxj_convert_hdml,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_hdml,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = NULL,
   },
   {
     /* CHXJ_SPEC_Jhtml            */
-    .converter = chxj_convert_jhtml,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_jhtml,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_jhtml_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_Jxhtml            */
-    .converter = chxj_convert_jxhtml,
-    .encoder  = chxj_encoding,
+    .converter            = chxj_convert_jxhtml,
+    .encoder              = chxj_encoding,
+    .emoji_only_converter = chxj_jxhtml_emoji_only_converter,
   },
   {
     /* CHXJ_SPEC_HTML             */
     .converter = NULL,
     .encoder  = NULL,
+    .emoji_only_converter = NULL,
   },
 };
 
-static int chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp);
+static int chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_table *spec);
+static void s_convert_guid_parameter_to_header(request_rec *r, const char *param, device_table *spec);
 static void s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *cookie);
 static void s_clear_cookie_header(request_rec *r, device_table *spec);
+static void s_add_no_cache_headers(request_rec *r, chxjconvrule_entry  *entryp);
 
 /**
  * Only when User-Agent is specified, the User-Agent header is camouflaged. 
@@ -205,10 +224,14 @@ chxj_headers_fixup(request_rec *r)
       DBG(r, "REQ[%X] end chxj_headers_fixup() (no pattern)", (unsigned int)(apr_size_t)r);
       return DECLINED;
     }
-    if (!entryp || !(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
-      DBG(r, "REQ[%X] end chxj_headers_fixup() (engine off)", (unsigned int) r);
+    if (!(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
+      DBG(r, "REQ[%X] end chxj_headers_fixup() (engine off)", (unsigned int)(apr_size_t)r);
       return DECLINED;
     }
+    if (entryp->action & CONVRULE_EMOJI_ONLY_BIT) {
+      DBG(r, "REQ[%X] end chxj_headers_fixup() (emoji only)", (unsigned int)(apr_size_t)r);
+      return DECLINED;
+    } 
   
     apr_table_setn(r->headers_in, 
                    CHXJ_HTTP_USER_AGENT, 
@@ -219,12 +242,12 @@ chxj_headers_fixup(request_rec *r)
                      HTTP_USER_AGENT, 
                      entryp->user_agent);
 
-    chxj_convert_input_header(r,entryp);
+    chxj_convert_input_header(r,entryp, spec);
 
     break;
   
   default:
-    DBG(r, "REQ[%X] end chxj_headers_fixup() (not mobile)", (unsigned int) r);
+    DBG(r, "REQ[%X] end chxj_headers_fixup() (not mobile)", (unsigned int)(apr_size_t)r);
     return DECLINED;
 
   }
@@ -232,7 +255,7 @@ chxj_headers_fixup(request_rec *r)
 
   if (r->method_number == M_POST) {
     if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
-        DBG(r, "REQ[%X] set Input handler old:[%s] proxyreq:[%d] uri:[%s] filename:[%s]", (unsigned int)r, r->handler, r->proxyreq, r->uri, r->filename);
+        DBG(r, "REQ[%X] set Input handler old:[%s] proxyreq:[%d] uri:[%s] filename:[%s]", (unsigned int)(apr_size_t)r, r->handler, r->proxyreq, r->uri, r->filename);
         r->proxyreq = PROXYREQ_NONE;
         r->handler = apr_psprintf(r->pool, "chxj-input-handler");
     }
@@ -243,8 +266,8 @@ chxj_headers_fixup(request_rec *r)
         apr_status_t rv = apr_sockaddr_info_get(&address, ap_get_server_name(r), APR_UNSPEC, ap_get_server_port(r), 0, r->pool);
         if (rv != APR_SUCCESS) {
           char buf[256];
-          ERR(r, "REQ[%X] %s:%d apr_sockaddr_info_get() failed: rv:[%d|%s]", (unsigned int)r, APLOG_MARK, rv, apr_strerror(rv, buf, 256));
-          DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)r);
+          ERR(r, "REQ[%X] %s:%d apr_sockaddr_info_get() failed: rv:[%d|%s]", (unsigned int)(apr_size_t)r, APLOG_MARK, rv, apr_strerror(rv, buf, 256));
+          DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
           return DECLINED;
         }
         char *addr;
@@ -254,7 +277,7 @@ chxj_headers_fixup(request_rec *r)
         else {
           apr_sockaddr_ip_get(&addr, address);
         }
-        DBG(r, "REQ[%X] Client IP:[%s] vs Orig Client IP:[%s] vs Server IP:[%s]", (unsigned int)r, r->connection->remote_ip, client_ip, addr);
+        DBG(r, "REQ[%X] Client IP:[%s] vs Orig Client IP:[%s] vs Server IP:[%s]", (unsigned int)(apr_size_t)r, r->connection->remote_ip, client_ip, addr);
         if (strcmp(addr, r->connection->remote_ip) == 0) {
           r->connection->remote_ip = apr_pstrdup(r->connection->pool, client_ip);
         }
@@ -268,7 +291,9 @@ chxj_headers_fixup(request_rec *r)
     }
   }
 
-  DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)r);
+  chxj_add_device_env(r, spec);
+
+  DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
 
   return DECLINED;
 }
@@ -312,7 +337,7 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
   mod_chxj_config     *dconf; 
   chxjconvrule_entry  *entryp;
 
-  DBG(r,"REQ[%X] start of chxj_convert() input:[%.*s]", (unsigned int)r, (int)*len, *src);
+  DBG(r,"REQ[%X] start of chxj_convert() input:[%.*s]", (unsigned int)(apr_size_t)r, (int)*len, *src);
   dst  = apr_pstrcat(r->pool, (char *)*src, NULL);
 
   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
@@ -321,7 +346,7 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
   entryp = chxj_apply_convrule(r, dconf->convrules);
 
   if (!entryp || !(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
-    DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)r);
+    DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
     return (char *)*src;
   }
 
@@ -334,14 +359,14 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
   else
     user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
 
-  DBG(r,"REQ[%X] User-Agent:[%s]", (unsigned int)r, user_agent);
-  DBG(r,"REQ[%X] content type is %s", (unsigned int)r, r->content_type);
+  DBG(r,"REQ[%X] User-Agent:[%s]", (unsigned int)(apr_size_t)r, user_agent);
+  DBG(r,"REQ[%X] content type is %s", (unsigned int)(apr_size_t)r, r->content_type);
 
 
   if (  ! STRNCASEEQ('t','T', "text/html", r->content_type, sizeof("text/html")-1)
     &&  ! STRNCASEEQ('a','A', "application/xhtml+xml", r->content_type, sizeof("application/xhtml+xml")-1)) {
-    DBG(r,"REQ[%X] no convert. content type is %s", (unsigned int)r, r->content_type);
-    DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)r);
+    DBG(r,"REQ[%X] no convert. content type is %s", (unsigned int)(apr_size_t)r, r->content_type);
+    DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
     return (char *)*src;
   }
 
@@ -354,7 +379,9 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
    * save cookie.
    */
   cookie = NULL;
-  if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
+  if (entryp->action & CONVRULE_COOKIE_ON_BIT 
+      && !(entryp->action & CONVRULE_EMOJI_ONLY_BIT)
+      && !(entryp->action & CONVRULE_ENVINFO_ONLY_BIT)) {
     switch(spec->html_spec_type) {
     case CHXJ_SPEC_Chtml_1_0:
     case CHXJ_SPEC_Chtml_2_0:
@@ -380,23 +407,50 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
                                                           *src, 
                                                           (apr_size_t *)len);
 
-    if (convert_routine[spec->html_spec_type].converter) {
-      if (tmp)
-        dst = convert_routine[spec->html_spec_type].converter(r, 
-                                                              spec, 
-                                                              tmp, 
-                                                              *len, 
-                                                              len, 
-                                                              entryp, 
-                                                              cookie);
-      else
-        dst = convert_routine[spec->html_spec_type].converter(r,
-                                                              spec, 
-                                                              tmp, 
-                                                              *len, 
-                                                              len, 
-                                                              entryp, 
-                                                              cookie);
+    if (entryp->action & CONVRULE_EMOJI_ONLY_BIT) {
+      if (tmp) {
+        tmp = chxj_node_convert_chxjif_only(r, spec, (const char*)tmp, (apr_size_t *)len);
+      }
+      else {
+        tmp = chxj_node_convert_chxjif_only(r, spec, (const char *)*src, (apr_size_t *)len);
+      }
+      if (convert_routine[spec->html_spec_type].emoji_only_converter) {
+        dst = convert_routine[spec->html_spec_type].emoji_only_converter(r,spec, tmp,*len);
+        if (dst != NULL) {
+          *len = strlen(dst);
+        }
+        else {
+          dst = apr_palloc(r->pool, 1);
+          *dst = 0;
+          *len = 0;
+        }
+      }
+      DBG(r, "REQ[%X] end of chxj_convert()(emoji only)", (unsigned int)(apr_size_t)r);
+    }
+
+    if (   !(entryp->action & CONVRULE_EMOJI_ONLY_BIT) 
+        && !(entryp->action & CONVRULE_ENVINFO_ONLY_BIT)) {
+      if (convert_routine[spec->html_spec_type].converter) {
+        if (tmp)
+          dst = convert_routine[spec->html_spec_type].converter(r, 
+                                                                spec, 
+                                                                tmp, 
+                                                                *len, 
+                                                                len, 
+                                                                entryp, 
+                                                                cookie);
+        else
+          dst = convert_routine[spec->html_spec_type].converter(r,
+                                                                spec, 
+                                                                *src, 
+                                                                *len, 
+                                                                len, 
+                                                                entryp, 
+                                                                cookie);
+      }
+      if (dst && *len) {
+        dst = chxj_conv_z2h(r, dst, len, entryp);
+      }
     }
   }
   ap_set_content_length(r, *len);
@@ -410,19 +464,52 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
     *cookiep = cookie;
   }
 
-  DBG(r, "REQ[%X] end of chxj_convert()", (unsigned int)r);
+
+  DBG(r, "REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
 
   return dst;
 }
 
 
 /**
+ * convert GUID parameter.
+ *
+ */
+static void
+s_convert_guid_parameter_to_header(request_rec *r, const char *param, device_table *spec)
+{
+  if (strcasecmp(param, "guid") == 0) {
+    switch(spec->html_spec_type) {
+    case CHXJ_SPEC_XHtml_Mobile_1_0:
+      do {
+        char *x_up_subno = (char *)apr_table_get(r->headers_in, "x-up-subno");
+        if (x_up_subno) {
+          apr_table_setn(r->headers_in, "X-DCMGUID", x_up_subno);
+        }
+      } while(0);
+      break;
+    case CHXJ_SPEC_Jhtml:
+    case CHXJ_SPEC_Jxhtml:
+      do {
+        char *x_jphone_uid = (char *)apr_table_get(r->headers_in, "x-jphone-uid");
+        if (x_jphone_uid) {
+          apr_table_setn(r->headers_in, "X-DCMGUID", x_jphone_uid);
+        }
+      } while(0);
+      break;
+    default:
+      break;
+    }
+  }
+}
+
+/**
  * It converts it from HEADER.
  *
  * @param r   [i]
  */
 static int
-chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp) 
+chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_table *spec
 {
 
   char       *buff;
@@ -440,8 +527,8 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp)
   DBG(r, "REQ[%X] start chxj_convert_input_header()", (unsigned int)(apr_size_t)r);
 
   if (! r->args) {
-    DBG(r, "REQ[%X] r->args=[null]", (unsigned int)r);
-    DBG(r, "REQ[%X] end   chxj_convert_input_header()", (unsigned int)r);
+    DBG(r, "REQ[%X] r->args=[null]", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] end   chxj_convert_input_header()", (unsigned int)(apr_size_t)r);
     return 0;
   }
   urilen = strlen(r->args);
@@ -465,13 +552,13 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp)
     value = apr_strtok(NULL, "=", &vstate);
     if (! name) continue;
     if (strcasecmp(name, CHXJ_COOKIE_NOUPDATE_PARAM) == 0 || strcasecmp(name, chxj_url_encode(r->pool, CHXJ_COOKIE_NOUPDATE_PARAM)) == 0) {
-      DBG(r, "REQ[%X] found cookie no update parameter", (unsigned int)r);
+      DBG(r, "REQ[%X] found cookie no update parameter", (unsigned int)(apr_size_t)r);
       no_update_flag++;
     }
   }
 
   buff = apr_pstrdup(r->pool, r->args);
-  DBG(r, "r->args=[%s]", buff);
+  DBG(r, "REQ[%X] r->args=[%s]", (unsigned int)(apr_size_t)r, buff);
 
   /* _chxj_dmy */
   /* _chxj_c_ */
@@ -491,6 +578,8 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp)
     name  = apr_strtok(pair, "=", &vstate);
     value = apr_strtok(NULL, "=", &vstate);
     if (! name) continue;
+    name = chxj_safe_to_jreserved_tag(r, name);
+
     if (strncasecmp(name, "_chxj", 5) != 0 && strncasecmp(name, "%5Fchxj", sizeof("%5Fchxj")-1) != 0) {
       if (strlen(result) != 0) 
         result = apr_pstrcat(r->pool, result, "&", NULL);
@@ -523,7 +612,7 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp)
         else {
           dname = "";
         }
-
+        s_convert_guid_parameter_to_header(r, dname, spec);
         result = apr_pstrcat(r->pool, result, dname, "=", dvalue, NULL);
       }
       else {
@@ -552,13 +641,13 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp)
     if (strcasecmp(name, CHXJ_COOKIE_PARAM) == 0 || strcasecmp(name, "%5Fchxj%5Fcc") == 0) {
       if (! cookie) {
         apr_table_unset(r->headers_in, "Cookie");
-        DBG(r, "REQ[%X] found cookie parameter[%s]",    (unsigned int)r, value);
-        DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)r);
+        DBG(r, "REQ[%X] found cookie parameter[%s]",    (unsigned int)(apr_size_t)r, value);
+        DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)(apr_size_t)r);
         cookie_lock_t *lock = chxj_cookie_lock(r);
         cookie = chxj_load_cookie(r, value);
-        DBG(r, "REQ[%X] call end   chxj_load_cookie()", (unsigned int)r);
+        DBG(r, "REQ[%X] call end   chxj_load_cookie()", (unsigned int)(apr_size_t)r);
         if (! no_update_flag && cookie) {
-          chxj_update_cookie(r, cookie);
+          cookie = chxj_update_cookie(r, cookie);
         }
         chxj_cookie_unlock(r, lock);
       }
@@ -581,8 +670,8 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp)
   }
   r->args = result;
 
-  DBG(r, "REQ[%X] result r->args=[%s]",               (unsigned int)r, r->args);
-  DBG(r, "REQ[%X] end   chxj_convert_input_header()", (unsigned int)r);
+  DBG(r, "REQ[%X] result r->args=[%s]",               (unsigned int)(apr_size_t)r, r->args);
+  DBG(r, "REQ[%X] end   chxj_convert_input_header()", (unsigned int)(apr_size_t)r);
   return 0;
 }
 
@@ -599,7 +688,8 @@ chxj_input_convert(
   request_rec         *r, 
   const char          **src, 
   apr_size_t          *len, 
-  chxjconvrule_entry  *entryp)
+  chxjconvrule_entry  *entryp,
+  device_table        *spec)
 {
   char     *pair;
   char     *name;
@@ -615,10 +705,10 @@ chxj_input_convert(
   apr_size_t ilen = 0;
   apr_pool_t *pool;
 
-  DBG(r, "REQ[%X] start of chxj_input_convert()", (unsigned int)r);
+  DBG(r, "REQ[%X] start of chxj_input_convert()", (unsigned int)(apr_size_t)r);
 
   if (! *src) {
-    DBG(r, "REQ[%X] end of chxj_input_convert() (input is null)", (unsigned int)r);
+    DBG(r, "REQ[%X] end of chxj_input_convert() (input is null)", (unsigned int)(apr_size_t)r);
     return apr_pstrdup(r->pool, "");
   }
 
@@ -630,14 +720,19 @@ chxj_input_convert(
 
   result   = qs_alloc_zero_byte_string(pool);
 
-  DBG(r, "REQ[%X] +-------------------------------------------------------------------+", (unsigned int)r);
-  DBG(r, "REQ[%X] | BEFORE input convert source                                       |", (unsigned int)r);
-  DBG(r, "REQ[%X] +-------------------------------------------------------------------+", (unsigned int)r);
+  DBG(r, "REQ[%X] +-------------------------------------------------------------------+", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] | BEFORE input convert source                                       |", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] +-------------------------------------------------------------------+", (unsigned int)(apr_size_t)r);
   for (ii=0; ii<ilen-64; ii+=64) {
-    DBG(r, "REQ[%X] | [%-*.*s] |", (unsigned int)r, 64, 64, &s[ii]);
+    DBG(r, "REQ[%X] | [%-*.*s] |", (unsigned int)(apr_size_t)r, 64, 64, &s[ii]);
+    if (ilen < 64) {
+      break;
+    }
+  }
+  if (ilen >= 64 && ((ilen-64) % 64 != 0)) {
+    DBG(r, "REQ[%X] | [%-*.*s] |", (unsigned int)(apr_size_t)r, 64, 64, &s[ii]);
   }
-  DBG(r, "REQ[%X] | [%-*.*s] |", (unsigned int)r, 64, 64, &s[ii]);
-  DBG(r, "REQ[%X] +--------------------------------------------------------------------+", (unsigned int)r);
+  DBG(r, "REQ[%X] +--------------------------------------------------------------------+", (unsigned int)(apr_size_t)r);
 
   for (;;) {
     char *pair_sv;
@@ -654,7 +749,7 @@ chxj_input_convert(
     value = apr_strtok(NULL, "=", &vstate);
     if (! name) continue;
     if (strcasecmp(name, CHXJ_COOKIE_NOUPDATE_PARAM) == 0 || strcasecmp(name, chxj_url_encode(r->pool, CHXJ_COOKIE_NOUPDATE_PARAM)) == 0) {
-      DBG(r, "REQ[%X] found cookie no update parameter", (unsigned int)r);
+      DBG(r, "REQ[%X] found cookie no update parameter", (unsigned int)(apr_size_t)r);
       no_update_flag++;
     }
   }
@@ -672,6 +767,8 @@ chxj_input_convert(
     name  = apr_strtok(pair, "=", &vstate);
     value = apr_strtok(NULL, "=", &vstate);
     if (! name) continue;
+    name  = chxj_safe_to_jreserved_tag(r, name);
+
     if (strncasecmp(name, "_chxj", 5) != 0 && strncasecmp(name, "%5Fchxj", sizeof("%5Fchxj")-1) != 0) {
       if (strlen(result) != 0) 
         result = apr_pstrcat(pool, result, "&", NULL);
@@ -701,6 +798,7 @@ chxj_input_convert(
           dname = "";
         }
 
+
         result = apr_pstrcat(pool, result, dname, "=", dvalue, NULL);
       }
       else {
@@ -739,13 +837,13 @@ chxj_input_convert(
     if (strcasecmp(name, CHXJ_COOKIE_PARAM) == 0 || strcasecmp(name, "%5Fchxj%5Fcc") == 0) {
       if (! cookie) {
         apr_table_unset(r->headers_in, "Cookie");
-        DBG(r, "REQ[%X] found cookie parameter[%s]",    (unsigned int)r, value);
-        DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)r);
+        DBG(r, "REQ[%X] found cookie parameter[%s]",    (unsigned int)(apr_size_t)r, value);
+        DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)(apr_size_t)r);
         cookie_lock_t *lock = chxj_cookie_lock(r);
         cookie = chxj_load_cookie(r, value);
-        DBG(r, "REQ[%X] call end   chxj_load_cookie()", (unsigned int)r);
+        DBG(r, "REQ[%X] call end   chxj_load_cookie()", (unsigned int)(apr_size_t)r);
         if (! no_update_flag && cookie) {
-          chxj_update_cookie(r, cookie);
+          cookie = chxj_update_cookie(r, cookie);
         }
         chxj_cookie_unlock(r, lock);
       }
@@ -776,6 +874,7 @@ chxj_input_convert(
         else {
           r->args = apr_pstrcat(pool, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1], "=", dvalue, NULL);
         }
+        s_convert_guid_parameter_to_header(r, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1], spec);
       }
     }
     else
@@ -793,6 +892,7 @@ chxj_input_convert(
         else {
           r->args = apr_pstrcat(pool, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX_ENC)-1], "=", dvalue, NULL);
         }
+        s_convert_guid_parameter_to_header(r, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX_ENC)-1], spec);
       }
     }
     DBG(r, "REQ[%X] ************************ name:[%s]", (unsigned int)(apr_size_t)r, name);
@@ -827,7 +927,9 @@ pass_data_to_filter(ap_filter_t *f, const char *data,
   apr_bucket_brigade  *bb;
   apr_bucket          *b;
 
-  DBG(r, "start pass_data_to_filter()");
+  DBG(r, "REQ[%X] start pass_data_to_filter()", (unsigned int)(apr_size_t)r);
+
+  chxj_header_inf_clear(r);
 
   bb = apr_brigade_create(r->pool, c->bucket_alloc);
   b  = apr_bucket_transient_create(data, len, c->bucket_alloc);
@@ -838,17 +940,38 @@ pass_data_to_filter(ap_filter_t *f, const char *data,
 
   rv = ap_pass_brigade(f->next, bb);
   if (rv != APR_SUCCESS) {
-    DBG(r, "ap_pass_brigade()");
+    DBG(r, "REQ[%X] end pass_data_to_filter() (apr_pass_brigade)", (unsigned int)(apr_size_t)r);
     return rv;
   }
 
-  DBG(r, "end pass_data_to_filter()");
+  DBG(r, "REQ[%X] end pass_data_to_filter()", (unsigned int)(apr_size_t)r);
 
   return rv;
 }
 
 
 /**
+ * Add No Cache Header
+ */
+static void
+s_add_no_cache_headers(request_rec *r, chxjconvrule_entry  *entryp)
+{
+  if (entryp->action & CONVRULE_NOCACHE_ON_BIT) {
+    apr_table_unset(r->headers_out,     "Pragma");
+    apr_table_unset(r->err_headers_out, "Pragma");
+    apr_table_unset(r->headers_out,     "Expires");
+    apr_table_unset(r->err_headers_out, "Expires");
+    apr_table_unset(r->headers_out,     "Cache-Control");
+    apr_table_unset(r->err_headers_out, "Cache-Control");
+
+    apr_table_setn(r->err_headers_out, "Pragma", "no-cache");
+    apr_table_setn(r->err_headers_out, "Expires", "Thu, 01 Jan 1970 00:00:00 GMT");
+    apr_table_setn(r->err_headers_out, "Cache-Control", "no-cache, no-store");
+  }
+}
+
+
+/**
  * It is the main loop of the output filter. 
  *
  * @param f   [i/o] It is a filter.
@@ -870,8 +993,8 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
   device_table        *spec = NULL;
   apr_pool_t          *pool;
 
-  DBG(f->r, "start of chxj_output_filter()");
   r  = f->r;
+  DBG(f->r, "REQ[%X] start of chxj_output_filter()", (unsigned int)(apr_size_t)r);
   rv = APR_SUCCESS;
 
   apr_pool_create(&pool, r->pool);
@@ -896,10 +1019,10 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
             || STRCASEEQ('x','X',"x-png",           &r->content_type[6])         /* PNG */
             || STRCASEEQ('g','G',"gif",             &r->content_type[6])))) {     /* GIF */
       
-      DBG(r, "not convert content-type:[%s] dconf->image:[%d]", r->content_type, dconf->image);
+      DBG(r, "REQ[%X] not convert content-type:[%s] dconf->image:[%d]", (unsigned int)(apr_size_t)r, r->content_type, dconf->image);
       if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
         cookie_lock_t *lock = NULL;
-        DBG(r, "entryp->action == COOKIE_ON_BIT");
+        DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", (unsigned int)(apr_size_t)r);
         switch(spec->html_spec_type) {
         case CHXJ_SPEC_Chtml_1_0:
         case CHXJ_SPEC_Chtml_2_0:
@@ -920,17 +1043,20 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
         }
       }
       if (apr_table_get(r->headers_out, "Location") || apr_table_get(r->err_headers_out, "Location")) {
-        if (r->status < HTTP_MULTIPLE_CHOICES || r->status > HTTP_TEMPORARY_REDIRECT) {
+        if (! ap_is_HTTP_REDIRECT(r->status)) {
           r->status = HTTP_MOVED_TEMPORARILY;
         }
       }
+      s_add_no_cache_headers(r, entryp);
       ap_pass_brigade(f->next, bb);
+      DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
       return APR_SUCCESS;
     }
   }
   else {
-    DBG(r, "not convert content-type:[(null)]");
+    DBG(r, "REQ[%X] not convert content-type:[(null)]", (unsigned int)(apr_size_t)r);
     ap_pass_brigade(f->next, bb);
+    DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
     return APR_SUCCESS;
   }
 
@@ -940,7 +1066,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
        b = APR_BUCKET_NEXT(b)) {
 
     if (apr_bucket_read(b, &data, &len, APR_BLOCK_READ) == APR_SUCCESS) {
-      DBG(r, "read data[%.*s]",(int)len, data);
+      DBG(r, "REQ[%X] read data[%.*s]",(unsigned int)(apr_size_t)r, (int)len, data);
 
       /*--------------------------------------------------------------------*/
       /* append data                                                        */
@@ -960,12 +1086,12 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 
         ctx->len += len;
       }
-      DBG(r, "append data end");
+      DBG(r, "REQ[%X] append data end", (unsigned int)(apr_size_t)r);
     }
 
     if (APR_BUCKET_IS_EOS(b)) {
 
-      DBG(r, "eos");
+      DBG(r, "REQ[%X] eos", (unsigned int)(apr_size_t)r);
       /*----------------------------------------------------------------------*/
       /* End Of File                                                          */
       /*----------------------------------------------------------------------*/
@@ -973,14 +1099,14 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
         cookie_lock_t *lock = NULL;
         ctx = (mod_chxj_ctx *)f->ctx;
 
-        DBG(r, "content_type=[%s]", r->content_type);
+        DBG(r, "REQ[%X] content_type=[%s]", (unsigned int)(apr_size_t)r, r->content_type);
         lock = chxj_cookie_lock(r);
 
         if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN 
             && r->content_type 
             && (STRNCASEEQ('a','A',"application/xhtml+xml", r->content_type, sizeof("application/xhtml+xml")-1)
             ||  STRNCASEEQ('t','T',"text/html", r->content_type, sizeof("text/html")-1))) {
-          DBG(r, "detect convert target:[%s]", r->content_type);
+          DBG(r, "REQ[%X] detect convert target:[%s]", (unsigned int)(apr_size_t)r, r->content_type);
 
           if (ctx->len) {
             char *tmp;
@@ -1011,7 +1137,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
         if (r->content_type
             && *(char *)r->content_type == 't'
             && strncmp(r->content_type, "text/xml",   8) == 0) {
-          DBG(r, "text/XML");
+          DBG(r, "REQ[%X] text/XML", (unsigned int)(apr_size_t)r);
 
           Doc       doc;
           Node      *root;
@@ -1046,8 +1172,9 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
             chxj_qrcode_node_to_qrcode(&qrcode, root);
             sts = chxj_qrcode_create_image_data(&qrcode, &ctx->buffer, &ctx->len);
             if (sts != OK) {
-              ERR(r, "qrcode create failed.");
+              ERR(r, "REQ[%X] qrcode create failed.", (unsigned int)(apr_size_t)r);
               chxj_cookie_unlock(r, lock);
+              DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
               return sts;
             }
             r->content_type = apr_psprintf(r->pool, "image/jpeg");
@@ -1090,14 +1217,15 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 
         
         if (ctx->len > 0) {
-          DBG(r, "call pass_data_to_filter()");
+          DBG(r, "REQ[%X] call pass_data_to_filter()", (unsigned int)(apr_size_t)r);
           s_add_cookie_id_if_has_location_header(r, cookie);
           if (apr_table_get(r->headers_out, "Location") || apr_table_get(r->err_headers_out, "Location")) {
-            if (r->status < HTTP_MULTIPLE_CHOICES || r->status > HTTP_TEMPORARY_REDIRECT) {
+            if (! ap_is_HTTP_REDIRECT(r->status)) {
               r->status = HTTP_MOVED_TEMPORARILY;
             }
           }
           chxj_cookie_unlock(r,lock);
+          s_add_no_cache_headers(r, entryp);
           rv = pass_data_to_filter(f, 
                                    (const char *)ctx->buffer, 
                                    (apr_size_t)ctx->len);
@@ -1106,17 +1234,18 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           chxj_cookie_unlock(r, lock);
 
         }
+        DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
         return rv;
       }
       else {
-        DBG(r, " SAVE COOKIE[%x]", entryp->action);
+        DBG(r, "REQ[%X] SAVE COOKIE[%x]", (unsigned int)(apr_size_t)r, entryp->action);
 
         /*
          * save cookie.
          */
         if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
           cookie_lock_t *lock = NULL;
-          DBG(r, "entryp->action == COOKIE_ON_BIT");
+          DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", (unsigned int)(apr_size_t)r);
           switch(spec->html_spec_type) {
           case CHXJ_SPEC_Chtml_1_0:
           case CHXJ_SPEC_Chtml_2_0:
@@ -1143,20 +1272,22 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           }
         }
         if (apr_table_get(r->headers_out, "Location") || apr_table_get(r->err_headers_out, "Location")) {
-          if (r->status < HTTP_MULTIPLE_CHOICES || r->status > HTTP_TEMPORARY_REDIRECT) {
+          if (! ap_is_HTTP_REDIRECT(r->status)) {
             r->status = HTTP_MOVED_TEMPORARILY;
           }
         }
         apr_table_setn(r->headers_out, "Content-Length", "0");
-        DBG(r, "call pass_data_to_filter()");
+        DBG(r, "REQ[%X] call pass_data_to_filter()", (unsigned int)(apr_size_t)r);
+        s_add_no_cache_headers(r, entryp);
         rv = pass_data_to_filter(f, (const char *)"", (apr_size_t)0);
+        DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
         return rv;
       }
     }
   }
   apr_brigade_destroy(bb);
 
-  DBG(r, "end of output filter");
+  DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
 
   return APR_SUCCESS;
 }
@@ -1172,14 +1303,14 @@ s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *cookie)
     location_header = (char *)apr_table_get(r->err_headers_out, "Location");
   }
   if (cookie && location_header) {
-    DBG(r, "REQ[%X] Location Header=[%s]", (unsigned int)r, location_header);
+    DBG(r, "REQ[%X] Location Header=[%s]", (unsigned int)(apr_size_t)r, location_header);
     location_header = chxj_add_cookie_parameter(r,
                                                 location_header,
                                                 cookie);
     apr_table_unset(r->headers_out, "Location");
     apr_table_setn(r->headers_out, "Location", location_header);
-    DBG(r, "REQ[%X] Location Header=[%s]", (unsigned int)r, location_header);
-    if (r->status < HTTP_MULTIPLE_CHOICES || r->status > HTTP_TEMPORARY_REDIRECT) {
+    DBG(r, "REQ[%X] Location Header=[%s]", (unsigned int)(apr_size_t)r, location_header);
+    if (!ap_is_HTTP_REDIRECT(r->status)) {
       r->status = HTTP_MOVED_TEMPORARILY;
     }
   }
@@ -1189,7 +1320,7 @@ s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *cookie)
  * It is the main loop of the input filter handler. 
  *
  */
-static int 
+static apr_status_t
 chxj_input_handler(request_rec *r)
 {
   mod_chxj_config     *dconf;
@@ -1201,6 +1332,7 @@ chxj_input_handler(request_rec *r)
   char                *user_agent;
   apr_pool_t          *pool;
   apr_size_t          ii;
+  int                 response_code = 0;
   
   DBG(r, "start of chxj_input_handler()");
 
@@ -1237,7 +1369,7 @@ chxj_input_handler(request_rec *r)
    * now convert.
    */
   if (post_data_len > 0) {
-    post_data = chxj_input_convert(r, (const char**)&post_data, (apr_size_t*)&post_data_len, entryp);
+    post_data = chxj_input_convert(r, (const char**)&post_data, (apr_size_t*)&post_data_len, entryp, spec);
     DBG(r, "(in:exchange)POSTDATA:[%s]", post_data);
   }
 
@@ -1257,7 +1389,7 @@ chxj_input_handler(request_rec *r)
   apr_table_setn(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_IP, r->connection->remote_ip);
   apr_table_unset(r->headers_in, "Content-Length");
   apr_table_setn(r->headers_in, "Content-Length", apr_psprintf(pool, "%" APR_SIZE_T_FMT, post_data_len));
-  response = chxj_serf_post(r, pool, url_path, post_data, post_data_len, 1, &res_len);
+  response = chxj_serf_post(r, pool, url_path, post_data, post_data_len, 1, &res_len, &response_code);
   DBG(r, "REQ[%X] -------------------------------------------------------", (unsigned int)(apr_size_t)r);
   DBG(r, "REQ[%X] response length:[%" APR_SIZE_T_FMT "]", (unsigned int)(apr_size_t)r, res_len);
   for (ii=0; ii<res_len/64; ii++) {
@@ -1272,6 +1404,10 @@ chxj_input_handler(request_rec *r)
       apr_table_unset(r->headers_out, "Transfer-Encoding");
     }
   }
+  if (ap_is_HTTP_ERROR(response_code)) {
+    DBG(r, "REQ[%X] end of chxj_input_handler() (HTTP-ERROR received. response code:[%d])", (unsigned int)(apr_size_t)r, response_code);
+    return response_code;
+  }
   {
     apr_pool_t *wpool;
     apr_pool_create(&wpool, r->pool);
@@ -1394,11 +1530,11 @@ chxj_config_server_create(apr_pool_t *p, server_rec *s)
 static int
 chxj_translate_name(request_rec *r)
 {
-  DBG(r, "REQ[%X] =======================================================================", (unsigned int)r);
-  DBG(r, "REQ[%X] ", (unsigned int)r);
+  DBG(r, "REQ[%X] =======================================================================", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] ", (unsigned int)(apr_size_t)r);
   DBG(r, "REQ[%X] START REQUEST (uri:[%s] args:[%s])", (unsigned int)(apr_size_t)r, r->unparsed_uri, r->args ? r->args : "");
-  DBG(r, "REQ[%X] ", (unsigned int)r);
-  DBG(r, "REQ[%X] =======================================================================", (unsigned int)r);
+  DBG(r, "REQ[%X] ", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] =======================================================================", (unsigned int)(apr_size_t)r);
   return chxj_trans_name(r);
 }
 
@@ -1544,6 +1680,7 @@ chxj_create_per_dir_config(apr_pool_t *p, char *arg)
 #endif
   conf->forward_url_base = NULL;
   conf->forward_server_ip = NULL;
+  conf->allowed_cookie_domain = NULL;
 
   if (arg == NULL) {
     conf->dir                  = NULL;
@@ -1588,6 +1725,7 @@ chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
   mrg->new_line_type    = NLTYPE_NIL;
   mrg->forward_url_base = NULL;
   mrg->forward_server_ip = NULL;
+  mrg->allowed_cookie_domain = NULL;
 
   mrg->dir = apr_pstrdup(p, add->dir);
 
@@ -1799,6 +1937,20 @@ chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
   else {
     mrg->new_line_type = NLTYPE_NIL;
   }
+
+  if (add->forward_url_base) {
+    mrg->forward_url_base = add->forward_url_base;
+  }
+  else if (base->forward_url_base) {
+    mrg->forward_url_base = base->forward_url_base;
+  }
+
+  if (add->allowed_cookie_domain) {
+    mrg->allowed_cookie_domain = add->allowed_cookie_domain;
+  }
+  else {
+    mrg->allowed_cookie_domain = base->allowed_cookie_domain;
+  }
   return mrg;
 }
 
@@ -2168,6 +2320,14 @@ cmd_convert_rule(cmd_parms *cmd, void *mconfig, const char *arg)
       if (strcasecmp(CONVRULE_ENGINE_OFF_CMD, action) == 0) {
         newrule->action |= CONVRULE_ENGINE_OFF_BIT;
       }
+      else
+      if (strcasecmp(CONVRULE_EMOJI_ONLY_CMD, action) == 0) {
+        newrule->action |= CONVRULE_EMOJI_ONLY_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_ENVINFO_ONLY_CMD, action) == 0) {
+        newrule->action |= CONVRULE_ENVINFO_ONLY_BIT;
+      }
       break;
 
     case 'C':
@@ -2176,6 +2336,63 @@ cmd_convert_rule(cmd_parms *cmd, void *mconfig, const char *arg)
         newrule->action |= CONVRULE_COOKIE_ON_BIT;
       }
       break;
+
+    case 'J':
+    case 'j':
+      if (strcasecmp(CONVRULE_JRCONV_OFF_CMD, action) == 0) {
+        newrule->action |= CONVRULE_JRCONV_OFF_BIT;
+      }
+      break;
+
+    case 'N':
+    case 'n':
+      if (strcasecmp(CONVRULE_NOCACHE_ON_CMD, action) == 0) {
+        newrule->action |= CONVRULE_NOCACHE_ON_BIT;
+      }
+      break;
+
+    case 'Q':
+    case 'q':
+      if (strcasecmp(CONVRULE_QSCONV_OFF_CMD, action) == 0) {
+        newrule->action |= CONVRULE_QSCONV_OFF_BIT;
+      }
+      break;
+
+    case 'Z':
+    case 'z':
+      if (strcasecmp(CONVRULE_Z2H_ON_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_ON_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_Z2H_OFF_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_OFF_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_Z2H_ALPHA_ON_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_ALPHA_ON_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_Z2H_ALPHA_OFF_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_ALPHA_OFF_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_Z2H_NUM_ON_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_NUM_ON_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_Z2H_NUM_OFF_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_NUM_OFF_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_Z2H_ALL_ON_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_ON_BIT | CONVRULE_Z2H_ALPHA_ON_BIT | CONVRULE_Z2H_NUM_ON_BIT;
+      }
+      else
+      if (strcasecmp(CONVRULE_Z2H_NUM_OFF_CMD, action) == 0) {
+        newrule->action |= CONVRULE_Z2H_OFF_BIT | CONVRULE_Z2H_ALPHA_OFF_BIT | CONVRULE_Z2H_NUM_OFF_BIT;
+      }
+      break;
+
     default:
       break;
     }
@@ -2541,6 +2758,24 @@ cmd_set_forward_server_ip(
 }
 
 static const char *
+cmd_allowed_cookie_domain(
+  cmd_parms   *cmd,
+  void        *mconfig,
+  const char  *arg)
+{
+  mod_chxj_config *dconf;
+
+  if (strlen(arg) > 255)
+    return "mod_chxj: ChxjAllowedCookieDomain is too long.";
+
+  dconf = (mod_chxj_config *)mconfig;
+
+  dconf->allowed_cookie_domain = apr_pstrdup(cmd->pool, arg);
+
+  return NULL;
+}
+
+static const char *
 cmd_set_new_line_type(
   cmd_parms   *UNUSED(cmd), 
   void        *mconfig, 
@@ -2720,6 +2955,12 @@ static const command_rec cmds[] = {
     NULL,
     OR_ALL,
     "The forward server ip(default: this server ip)"),
+  AP_INIT_TAKE1(
+    "ChxjAllowedCookieDomain",
+    cmd_allowed_cookie_domain,
+    NULL,
+    OR_ALL,
+    "Domain that permits parameter addition for cookie besides hostname.(Default:hostname Only)"),
   {NULL}
 };