OSDN Git Service

* Fixed Bug.
[modchxj/mod_chxj.git] / src / mod_chxj.c
index 13f3f4b..4353534 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2009 Atsushi Konno All rights reserved.
+ * Copyright (C) 2005-2011 Atsushi Konno All rights reserved.
  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,6 +33,7 @@
 #include "apr_dso.h"
 #include "apr_general.h"
 #include "apr_pools.h"
+#include "apr_file_info.h"
 
 #include "mod_chxj.h"
 #include "chxj_encoding.h"
@@ -174,29 +175,42 @@ static apr_status_t
 chxj_headers_fixup(request_rec *r)
 {
   mod_chxj_config*    dconf; 
+  mod_chxj_req_config *request_conf; 
   chxjconvrule_entry* entryp;
   char*               user_agent;
   device_table*       spec;
   char                *contentType;
   char                *contentLength;
 
-  DBG(r, "REQ[%X] start chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] start %s()", TO_ADDR(r), __func__);
   if (r->main) {
-    DBG(r, "REQ[%X] detect internal redirect.", (unsigned int)(apr_size_t)r);
-    DBG(r, "REQ[%X] end chxj_headers_fixup()",  (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] detect internal redirect.", TO_ADDR(r));
+    DBG(r, "REQ[%X] end %s()",  TO_ADDR(r),__func__);
     return DECLINED;
   }
 
+  request_conf = (mod_chxj_req_config *)chxj_get_module_config(r->request_config, &chxj_module);
+  if (!request_conf) {
+    request_conf = apr_palloc(r->pool, sizeof(mod_chxj_req_config));
+    request_conf->spec = NULL;
+    request_conf->user_agent = NULL;
+    chxj_set_module_config(r->request_config, &chxj_module, request_conf);
+  }
   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
   user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
+
+  /*
+   * check and get mobile type.
+   * and request_conf->user_agent , request_conf->spec is set.
+   */
   spec = chxj_specified_device(r, user_agent);
 
   contentType = (char *)apr_table_get(r->headers_in, "Content-Type");
   if (contentType
       && strncasecmp("multipart/form-data", contentType, 19) == 0) {
-    DBG(r, "REQ[%X] detect multipart/form-data ==> no target", (unsigned int)(apr_size_t)r);
-    DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] detect multipart/form-data ==> no target", TO_ADDR(r));
+    DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
     return DECLINED;
   }
 
@@ -215,15 +229,15 @@ chxj_headers_fixup(request_rec *r)
   case CHXJ_SPEC_Jxhtml:
     entryp = chxj_apply_convrule(r, dconf->convrules);
     if (! entryp) {
-      DBG(r, "REQ[%X] end chxj_headers_fixup() (no pattern)", (unsigned int)(apr_size_t)r);
+      DBG(r, "REQ[%X] end %s() (no pattern)", TO_ADDR(r),__func__);
       return DECLINED;
     }
-    if (!(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
-      DBG(r, "REQ[%X] end chxj_headers_fixup() (engine off)", (unsigned int)(apr_size_t)r);
+    if (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
+      DBG(r, "REQ[%X] end %s() (engine off)", TO_ADDR(r),__func__);
       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);
+      DBG(r, "REQ[%X] end %s() (emoji only)", TO_ADDR(r),__func__);
       return DECLINED;
     } 
   
@@ -238,7 +252,7 @@ chxj_headers_fixup(request_rec *r)
     /*
      * this clear process must do before chxj_convert_input_header function.
      */
-    if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
+    if ((entryp->action & CONVRULE_COOKIE_ON_BIT) || (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
       if (r->method_number == M_POST) {
         if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
           s_clear_cookie_header(r, spec);
@@ -254,17 +268,25 @@ chxj_headers_fixup(request_rec *r)
     break;
   
   default:
-    DBG(r, "REQ[%X] end chxj_headers_fixup() (not mobile) spec->device_name[%s] User-Agent:[%s]", (unsigned int)(apr_size_t)r, spec->device_name, user_agent);
+    DBG(r, "REQ[%X] end %s() (not mobile) spec->device_name[%s] User-Agent:[%s]", TO_ADDR(r),__func__, spec->device_name, user_agent);
     return DECLINED;
 
   }
 
+  char *x_client_type = (char *)apr_table_get(r->headers_out, "X-Client-Type");
+  apr_table_unset(r->headers_out, "X-Client-Type");
+  if (x_client_type) {
+    apr_table_setn(r->headers_in, "X-Client-Type", x_client_type);
+  }
+  else {
+    apr_table_setn(r->headers_in, "X-Client-Type", "");
+  }
 
   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)(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");
+      DBG(r, "REQ[%X] set Input handler old:[%s] proxyreq:[%d] uri:[%s] filename:[%s]", TO_ADDR(r), r->handler, r->proxyreq, r->uri, r->filename);
+      r->proxyreq = PROXYREQ_NONE;
+      r->handler = apr_psprintf(r->pool, "chxj-input-handler");
     }
     else {
       char *client_ip = (char *)apr_table_get(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_IP);
@@ -279,8 +301,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)(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);
+          ERR(r, "REQ[%X] %s:%d apr_sockaddr_info_get() failed: rv:[%d|%s]", TO_ADDR(r), APLOG_MARK, rv, apr_strerror(rv, buf, 256));
+          DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
           return DECLINED;
         }
         char *addr;
@@ -290,9 +312,21 @@ 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)(apr_size_t)r, r->connection->remote_ip, client_ip, addr);
+        DBG(r, "REQ[%X] Client IP:[%s] vs Orig Client IP:[%s] vs Server IP:[%s]", TO_ADDR(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);
+          /* For mod_cidr_lookup */
+          if (entryp->action & CONVRULE_OVERWRITE_X_CLIENT_TYPE_BIT) {
+            char *client_type = (char *)apr_table_get(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_TYPE);
+            DBG(r, "REQ[%X] Overwrite X-Client-Type to [%s]", TO_ADDR(r), client_type);
+            if (client_type) {
+              apr_table_setn(r->subprocess_env, "X_CLIENT_TYPE", client_type);
+              apr_table_setn(r->headers_in, "X-Client-Type", client_type);
+            }
+            else {
+              apr_table_unset(r->headers_in, "X-Client-Type");
+            }
+          }
         }
         if (! apr_table_get(r->headers_in, "Content-Length")) {
           contentLength = (char *)apr_table_get(r->headers_in, "X-Chxj-Content-Length");
@@ -303,19 +337,62 @@ chxj_headers_fixup(request_rec *r)
       }
     }
   }
+  else{
+    if(r->content_type && strncmp(r->content_type,"image/",6) == 0){
+      if (dconf->image_rewrite == CHXJ_IMG_REWRITE_ON && !apr_table_get(r->headers_in, CHXJ_IMG_X_HTTP_IMAGE_FILENAME)){
+        if(dconf->image_rewrite_mode == CHXJ_IMG_REWRITE_MODE_ALL){
+          // all image
+          apr_table_set(r->headers_in, CHXJ_IMG_X_HTTP_IMAGE_FILENAME, r->filename);
+          apr_table_set(r->headers_in, CHXJ_IMG_X_HTTP_IMAGE_TYPE,r->content_type);
+          r->filename = apr_pstrcat(r->pool,"img-redirect:",dconf->image_rewrite_url,NULL);
+          r->handler = "chxj-image-redirect-handler";
+          return OK;
+        }
+        else{
+          //   has _chxj_imgrewrite=on in args
+          char *args_tmp = chxj_url_decode(r->pool, r->args);
+          if (strstr(args_tmp,CHXJ_IMG_REWRITE_URL_STRING)){
+            apr_table_set(r->headers_in, CHXJ_IMG_X_HTTP_IMAGE_FILENAME, r->filename);
+            apr_table_set(r->headers_in, CHXJ_IMG_X_HTTP_IMAGE_TYPE,r->content_type);
+            r->filename = apr_pstrcat(r->pool,"img-redirect:",dconf->image_rewrite_url,NULL);
+            r->handler = "chxj-image-redirect-handler";
+            return OK;
+          }
+        }
+      }
+    }
+  }
 
   chxj_add_device_env(r, spec);
 
-  DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 
   return DECLINED;
 }
 
+static int
+chxj_image_redirect_handler(request_rec *r)
+{
+
+  if (strcmp(r->handler, "chxj-image-redirect-handler")) {
+    return DECLINED;
+  }
+
+  if (strncmp(r->filename, "img-redirect:", 13) != 0) {
+    return DECLINED;
+  }
+  DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
+  ap_internal_redirect(apr_pstrcat(r->pool, r->filename+13,
+                                       r->args ? "?" : NULL, r->args, NULL), r);
+  DBG(r,"REQ[%X] end %s()", TO_ADDR(r),__func__);
+  return OK;
+}
+
 
 static void
 s_clear_cookie_header(request_rec *r, device_table *spec)
 {
-  DBG(r, "REQ[%X] start s_clear_cookie_header()", TO_ADDR(r));
+  DBG(r, "REQ[%X] start %s()", TO_ADDR(r),__func__);
   switch(spec->html_spec_type) {
   case CHXJ_SPEC_Chtml_1_0:
   case CHXJ_SPEC_Chtml_2_0:
@@ -326,12 +403,13 @@ s_clear_cookie_header(request_rec *r, device_table *spec)
   case CHXJ_SPEC_Chtml_7_0:
   case CHXJ_SPEC_XHtml_Mobile_1_0:
   case CHXJ_SPEC_Jhtml:
+  case CHXJ_SPEC_Jxhtml:
     apr_table_unset(r->headers_in, "Cookie");
     break;
   default:
     break;
   }
-  DBG(r, "REQ[%X] end   s_clear_cookie_header()", TO_ADDR(r));
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 }
 
 
@@ -352,7 +430,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()", (unsigned int)(apr_size_t)r);
+  DBG(r,"REQ[%X] start %s()", TO_ADDR(r),__func__);
 
   chxj_dump_string(r, APLOG_MARK, "INPUT Data", *src, *len);
 
@@ -363,8 +441,8 @@ 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)(apr_size_t)r);
+  if (!entryp || (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT))) {
+    DBG(r,"REQ[%X] end %s()", TO_ADDR(r),__func__);
     return (char *)*src;
   }
 
@@ -377,14 +455,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)(apr_size_t)r, user_agent);
-  DBG(r,"REQ[%X] content type is %s", (unsigned int)(apr_size_t)r, r->content_type);
+  DBG(r,"REQ[%X] User-Agent:[%s]", TO_ADDR(r), user_agent);
+  DBG(r,"REQ[%X] content type is [%s]", TO_ADDR(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)(apr_size_t)r, r->content_type);
-    DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
+    DBG(r,"REQ[%X] no convert. content type is [%s]", TO_ADDR(r), r->content_type);
+    DBG(r,"REQ[%X] end %s()", TO_ADDR(r),__func__);
     return (char *)*src;
   }
 
@@ -397,9 +475,10 @@ 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)) {
+      && !(entryp->action & CONVRULE_ENVINFO_ONLY_BIT))
+      || (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
     switch(spec->html_spec_type) {
     case CHXJ_SPEC_Chtml_1_0:
     case CHXJ_SPEC_Chtml_2_0:
@@ -410,6 +489,7 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
     case CHXJ_SPEC_Chtml_7_0:
     case CHXJ_SPEC_XHtml_Mobile_1_0:
     case CHXJ_SPEC_Jhtml:
+    case CHXJ_SPEC_Jxhtml:
       cookie = chxj_save_cookie(r);
       break;
     default:
@@ -419,55 +499,72 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
 
   if (!r->header_only) {
 
-    tmp = NULL;
-    if (convert_routine[spec->html_spec_type].encoder)
-      tmp = convert_routine[spec->html_spec_type].encoder(r, 
-                                                          *src, 
-                                                          (apr_size_t *)len);
-
-    if (entryp->action & CONVRULE_EMOJI_ONLY_BIT) {
-      if (tmp) {
-        tmp = chxj_node_convert_chxjif_only(r, spec, (const char*)tmp, (apr_size_t *)len);
+    if ((entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
+      if (cookie) {
+        dst = chxj_cookie_only_mode(r, *src, (apr_size_t *)len, cookie);
       }
       else {
-        tmp = chxj_node_convert_chxjif_only(r, spec, (const char *)*src, (apr_size_t *)len);
+        /* ignore */
       }
-      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 {
+      tmp = NULL;
+      if (convert_routine[spec->html_spec_type].encoder)
+        tmp = convert_routine[spec->html_spec_type].encoder(r, 
+                                                            *src, 
+                                                            (apr_size_t *)len);
+  
+      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 {
-          dst = apr_palloc(r->pool, 1);
-          *dst = 0;
-          *len = 0;
+          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 %s()(emoji only)", TO_ADDR(r),__func__);
       }
-      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 (   !(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 (*len > 0){
+    if (strcasecmp(spec->output_encoding,"UTF-8") == 0){
+      dst = chxj_iconv(r,r->pool,dst,len,"CP932","UTF-8");
+    }
+  }
+
+
   ap_set_content_length(r, *len);
 
   if (*len == 0) {
@@ -480,7 +577,8 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
   }
 
 
-  DBG(r, "REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
+
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 
   return dst;
 }
@@ -493,7 +591,7 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
 static void
 s_convert_guid_parameter_to_header(request_rec *r, const char *param, device_table *spec)
 {
-  DBG(r, "REQ[%X] start s_convert_guid_parameter() param:[%s]", (unsigned int)(apr_size_t)r, param);
+  DBG(r, "REQ[%X] start %s() param:[%s]", TO_ADDR(r),__func__, param);
   if (strcasecmp(param, "guid") == 0) {
     switch(spec->html_spec_type) {
     case CHXJ_SPEC_XHtml_Mobile_1_0:
@@ -517,7 +615,7 @@ s_convert_guid_parameter_to_header(request_rec *r, const char *param, device_tab
       break;
     }
   }
-  DBG(r, "REQ[%X] end s_convert_guid_parameter()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 }
 
 /**
@@ -541,11 +639,11 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
   cookie_t   *cookie = NULL;
   int        no_update_flag = 0;
 
-  DBG(r, "REQ[%X] start chxj_convert_input_header()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] start %s()", TO_ADDR(r),__func__);
 
   if (! r->args) {
-    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);
+    DBG(r, "REQ[%X] r->args=[null]", TO_ADDR(r));
+    DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
     return 0;
   }
   urilen = strlen(r->args);
@@ -569,13 +667,13 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
     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)(apr_size_t)r);
+      DBG(r, "REQ[%X] found cookie no update parameter", TO_ADDR(r));
       no_update_flag++;
     }
   }
 
   buff = apr_pstrdup(r->pool, r->args);
-  DBG(r, "REQ[%X] r->args=[%s]", (unsigned int)(apr_size_t)r, buff);
+  DBG(r, "REQ[%X] r->args=[%s]", TO_ADDR(r), buff);
 
   /* _chxj_dmy */
   /* _chxj_c_ */
@@ -608,12 +706,12 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
         if (value && *value != 0) {
           value = chxj_url_decode(r->pool, value);
           dlen   = strlen(value);
-          DBG(r, "************ before encoding[%s]", value);
+          DBG(r, "REQ[%X] ************ before encoding[%s]", TO_ADDR(r),value);
   
-          dvalue = chxj_rencoding(r, value, &dlen);
+          dvalue = chxj_rencoding(r, value, &dlen,spec->output_encoding);
           dvalue = chxj_url_encode(r->pool, dvalue);
   
-          DBG(r, "************ after encoding[%s]", dvalue);
+          DBG(r, "REQ[%X] ************ after encoding[%s]", TO_ADDR(r),dvalue);
         }
         else {
           dvalue = "";
@@ -622,7 +720,7 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
         if (name && *name != 0) {
           name = chxj_url_decode(r->pool, name);
           dlen = strlen(name);
-          dname = chxj_rencoding(r, name, &dlen);
+          dname = chxj_rencoding(r, name, &dlen,spec->output_encoding);
           dname = chxj_url_encode(r->pool, dname);
         }
         else {
@@ -660,11 +758,9 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
     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)(apr_size_t)r, value);
-        DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)(apr_size_t)r);
+        DBG(r, "REQ[%X] found cookie parameter[%s]", TO_ADDR(r), value);
         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)(apr_size_t)r);
         if (! no_update_flag && cookie) {
           cookie = chxj_update_cookie(r, cookie);
         }
@@ -689,8 +785,8 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
   }
   r->args = result;
 
-  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);
+  DBG(r, "REQ[%X] result r->args=[%s]", TO_ADDR(r), r->args);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
   return 0;
 }
 
@@ -723,10 +819,10 @@ chxj_input_convert(
   apr_size_t ilen = 0;
   apr_pool_t *pool;
 
-  DBG(r, "REQ[%X] start of chxj_input_convert()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] start %s()", TO_ADDR(r),__func__);
 
   if (! *src) {
-    DBG(r, "REQ[%X] end of chxj_input_convert() (input is null)", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] end %s() (input is null)", TO_ADDR(r),__func__);
     return apr_pstrdup(r->pool, "");
   }
 
@@ -755,7 +851,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)(apr_size_t)r);
+      DBG(r, "REQ[%X] found cookie no update parameter", TO_ADDR(r));
       no_update_flag++;
     }
   }
@@ -787,7 +883,7 @@ chxj_input_convert(
         if (value && *value != 0) {
           value = chxj_url_decode(pool, value);
           dlen   = strlen(value);
-          dvalue = chxj_rencoding(r, value, &dlen);
+          dvalue = chxj_rencoding(r, value, &dlen,spec->output_encoding);
           dvalue = chxj_url_encode(pool, dvalue);
         }
         else {
@@ -797,7 +893,7 @@ chxj_input_convert(
         if (name && *name != 0) {
           name = chxj_url_decode(pool, name);
           dlen = strlen(name);
-          dname = chxj_rencoding(r, name, &dlen);
+          dname = chxj_rencoding(r, name, &dlen,spec->output_encoding);
           dname = chxj_url_encode(pool, dname);
         }
         else {
@@ -830,7 +926,7 @@ chxj_input_convert(
 
         dlen   = strlen(value);
         value = chxj_url_decode(pool, value);
-        dvalue = chxj_rencoding(r, value, &dlen);
+        dvalue = chxj_rencoding(r, value, &dlen,spec->output_encoding);
         dvalue = chxj_url_encode(pool,dvalue);
         result = apr_pstrcat(pool, result, &name[8], "=", dvalue, NULL);
 
@@ -843,11 +939,9 @@ 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)(apr_size_t)r, value);
-        DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)(apr_size_t)r);
+        DBG(r, "REQ[%X] found cookie parameter[%s]",    TO_ADDR(r), value);
         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)(apr_size_t)r);
         if (! no_update_flag && cookie) {
           cookie = chxj_update_cookie(r, cookie);
         }
@@ -867,12 +961,14 @@ chxj_input_convert(
     }
     else
     if ( strncasecmp(name, CHXJ_QUERY_STRING_PARAM_PREFIX,     sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1) == 0) {
-      apr_size_t dlen;
+      apr_size_t dlen = 0;
       char*      dvalue;
-      dlen   = strlen(value);
-      if (dlen && value) {
+      if (value) {
+        dlen   = strlen(value);
+      }
+      if (dlen) {
         value = chxj_url_decode(pool, value);
-        dvalue = chxj_rencoding(r, value, &dlen);
+        dvalue = chxj_rencoding(r, value, &dlen,spec->output_encoding);
         dvalue = chxj_url_encode(pool,dvalue);
         if (r->args && strlen(r->args) > 0) {
           r->args = apr_pstrcat(pool, r->args, "&", &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1], "=", dvalue, NULL);
@@ -890,7 +986,7 @@ chxj_input_convert(
       dlen   = strlen(value);
       if (dlen && value) {
         value = chxj_url_decode(pool, value);
-        dvalue = chxj_rencoding(r, value, &dlen);
+        dvalue = chxj_rencoding(r, value, &dlen,spec->output_encoding);
         dvalue = chxj_url_encode(pool,dvalue);
         if (r->args && strlen(r->args) > 0) {
           r->args = apr_pstrcat(pool, r->args, "&", &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX_ENC)-1], "=", dvalue, NULL);
@@ -901,7 +997,7 @@ chxj_input_convert(
         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);
+    DBG(r, "REQ[%X] ************************ name:[%s]", TO_ADDR(r), name);
   }
   *len = strlen(result);
   apr_table_setn(r->headers_in, "X-Chxj-Cookie-No-Update", "true");
@@ -909,8 +1005,8 @@ chxj_input_convert(
     result = apr_pstrcat(pool, result, "&_chxj_nc=true", NULL);
   }
 
-  DBG(r, "REQ[%X] AFTER input convert result = [%s]", (unsigned int)(apr_size_t)r, result);
-  DBG(r, "REQ[%X] end chxj_input_convert()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] AFTER input convert result = [%s]", TO_ADDR(r), result);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 
   return result;
 }
@@ -933,7 +1029,7 @@ pass_data_to_filter(ap_filter_t *f, const char *data,
   apr_bucket_brigade  *bb;
   apr_bucket          *b;
 
-  DBG(r, "REQ[%X] start pass_data_to_filter()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] start %s()", TO_ADDR(r),__func__);
 
   chxj_header_inf_clear(r);
 
@@ -946,16 +1042,15 @@ pass_data_to_filter(ap_filter_t *f, const char *data,
 
   rv = ap_pass_brigade(f->next, bb);
   if (rv != APR_SUCCESS) {
-    DBG(r, "REQ[%X] end pass_data_to_filter() (apr_pass_brigade)", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] end %s() (apr_pass_brigade)", TO_ADDR(r),__func__);
     return rv;
   }
 
-  DBG(r, "REQ[%X] end pass_data_to_filter()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 
   return rv;
 }
 
-
 /**
  * Add No Cache Header
  */
@@ -1000,7 +1095,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
   apr_pool_t          *pool;
 
   r  = f->r;
-  DBG(f->r, "REQ[%X] start of chxj_output_filter()", (unsigned int)(apr_size_t)r);
+  DBG(f->r, "REQ[%X] start %s()", TO_ADDR(r),__func__);
   rv = APR_SUCCESS;
 
   apr_pool_create(&pool, r->pool);
@@ -1012,7 +1107,7 @@ 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")) {
     DBG(r, "REQ[%X] found Location header", TO_ADDR(r));
-    if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
+    if ((entryp->action & CONVRULE_COOKIE_ON_BIT) || (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
       cookie_lock_t *lock = NULL;
       DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", TO_ADDR(r));
       switch(spec->html_spec_type) {
@@ -1025,6 +1120,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
       case CHXJ_SPEC_Chtml_7_0:
       case CHXJ_SPEC_XHtml_Mobile_1_0:
       case CHXJ_SPEC_Jhtml:
+      case CHXJ_SPEC_Jxhtml:
         lock = chxj_cookie_lock(r);
         cookie = chxj_save_cookie(r);
         s_add_cookie_id_if_has_location_header(r, cookie);
@@ -1040,7 +1136,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
     s_add_no_cache_headers(r, entryp);
     /* must not send body. */
     rv = pass_data_to_filter(f, "", 0);
-    DBG(f->r, "REQ[%X] end of chxj_output_filter()", TO_ADDR(r));
+    DBG(f->r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
     return rv;
   }
 
@@ -1062,10 +1158,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, "REQ[%X] not convert content-type:[%s] dconf->image:[%d]", (unsigned int)(apr_size_t)r, r->content_type, dconf->image);
+      DBG(r, "REQ[%X] not convert content-type:[%s] dconf->image:[%d]", TO_ADDR(r), r->content_type, dconf->image);
       if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
         cookie_lock_t *lock = NULL;
-        DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", (unsigned int)(apr_size_t)r);
+        DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", TO_ADDR(r));
         switch(spec->html_spec_type) {
         case CHXJ_SPEC_Chtml_1_0:
         case CHXJ_SPEC_Chtml_2_0:
@@ -1076,6 +1172,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
         case CHXJ_SPEC_Chtml_7_0:
         case CHXJ_SPEC_XHtml_Mobile_1_0:
         case CHXJ_SPEC_Jhtml:
+        case CHXJ_SPEC_Jxhtml:
           lock = chxj_cookie_lock(r);
           cookie = chxj_save_cookie(r);
           s_add_cookie_id_if_has_location_header(r, cookie);
@@ -1092,14 +1189,14 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
       }
       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);
+      DBG(f->r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
       return APR_SUCCESS;
     }
   }
   else {
-    DBG(r, "REQ[%X] not convert content-type:[(null)]", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] not convert content-type:[(null)]", TO_ADDR(r));
     ap_pass_brigade(f->next, bb);
-    DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
+    DBG(f->r, "REQ[%X] end %s()", TO_ADDR(f->r),__func__);
     return APR_SUCCESS;
   }
 
@@ -1115,7 +1212,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
       /* append data                                                        */
       /*--------------------------------------------------------------------*/
       char *tmp;
-      DBG(r, "append data start");
+      DBG(r, "REQ[%X] append data start", TO_ADDR(r));
       ctx = (mod_chxj_ctx *)f->ctx;
 
       if (len > 0) {
@@ -1129,12 +1226,12 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 
         ctx->len += len;
       }
-      DBG(r, "REQ[%X] append data end", (unsigned int)(apr_size_t)r);
+      DBG(r, "REQ[%X] append data end", TO_ADDR(r));
     }
 
     if (APR_BUCKET_IS_EOS(b)) {
 
-      DBG(r, "REQ[%X] eos", (unsigned int)(apr_size_t)r);
+      DBG(r, "REQ[%X] eos", TO_ADDR(r));
       /*----------------------------------------------------------------------*/
       /* End Of File                                                          */
       /*----------------------------------------------------------------------*/
@@ -1142,14 +1239,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, "REQ[%X] content_type=[%s]", (unsigned int)(apr_size_t)r, r->content_type);
+        DBG(r, "REQ[%X] content_type=[%s]", TO_ADDR(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, "REQ[%X] detect convert target:[%s]", (unsigned int)(apr_size_t)r, r->content_type);
+          DBG(r, "REQ[%X] detect convert target:[%s]", TO_ADDR(r), r->content_type);
 
           if (ctx->len) {
             char *tmp;
@@ -1180,7 +1277,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, "REQ[%X] text/XML", (unsigned int)(apr_size_t)r);
+          DBG(r, "REQ[%X] text/XML", TO_ADDR(r));
 
           Doc       doc;
           Node      *root;
@@ -1215,9 +1312,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, "REQ[%X] qrcode create failed.", (unsigned int)(apr_size_t)r);
+              ERR(r, "REQ[%X] qrcode create failed.", TO_ADDR(r));
               chxj_cookie_unlock(r, lock);
-              DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
+              DBG(f->r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
               return sts;
             }
             r->content_type = apr_psprintf(r->pool, "image/jpeg");
@@ -1238,10 +1335,11 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
               || STRCASEEQ('x','X',"x-png",           &r->content_type[6])         /* PNG */
               || STRCASEEQ('x','X',"x-ms-bmp",     &r->content_type[6])         /* BMP */
               || STRCASEEQ('g','G',"gif",             &r->content_type[6]))) {     /* GIF */
-          DBG(r, "REQ[%X] detect convert target:[%s]", (unsigned int)(apr_size_t)r, r->content_type);
+          DBG(r, "REQ[%X] detect convert target:[%s]", TO_ADDR(r), r->content_type);
           if (ctx->len) {
             char *tmp;
 
+            DBG(r, "REQ[%X] ctx->len[%d]", TO_ADDR(r), (unsigned int)ctx->len);
             tmp = apr_palloc(pool, ctx->len + 1);
 
             memset(tmp, 0, ctx->len + 1);
@@ -1250,9 +1348,6 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
               chxj_convert_image(r, 
                                   (const char **)&tmp,
                                   (apr_size_t *)&ctx->len);
-            if (ctx->buffer == NULL) {
-              ctx->buffer = tmp;
-            }
           }
         }
 
@@ -1262,7 +1357,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 
         
         if (ctx->len > 0) {
-          DBG(r, "REQ[%X] call pass_data_to_filter()", (unsigned int)(apr_size_t)r);
+          DBG(r, "REQ[%X] call %s()", TO_ADDR(r),__func__);
           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 (! ap_is_HTTP_REDIRECT(r->status)) {
@@ -1290,18 +1385,18 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
                                    (const char *)ctx->buffer, 
                                    (apr_size_t)ctx->len);
         }
-        DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
+        DBG(f->r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
         return rv;
       }
       else {
-        DBG(r, "REQ[%X] SAVE COOKIE[%x]", (unsigned int)(apr_size_t)r, entryp->action);
+        DBG(r, "REQ[%X] SAVE COOKIE[%x]", TO_ADDR(r), entryp->action);
 
         /*
          * save cookie.
          */
         if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
           cookie_lock_t *lock = NULL;
-          DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", (unsigned int)(apr_size_t)r);
+          DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", TO_ADDR(r));
           switch(spec->html_spec_type) {
           case CHXJ_SPEC_Chtml_1_0:
           case CHXJ_SPEC_Chtml_2_0:
@@ -1312,6 +1407,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           case CHXJ_SPEC_Chtml_7_0:
           case CHXJ_SPEC_XHtml_Mobile_1_0:
           case CHXJ_SPEC_Jhtml:
+          case CHXJ_SPEC_Jxhtml:
             lock = chxj_cookie_lock(r);
             cookie = chxj_save_cookie(r);
             /*
@@ -1333,17 +1429,15 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           }
         }
         apr_table_setn(r->headers_out, "Content-Length", "0");
-        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(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 
   return APR_SUCCESS;
 }
@@ -1354,22 +1448,24 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 static void
 s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *cookie)
 {
+  DBG(r, "REQ[%X] start %s()", TO_ADDR(r),__func__);
   char *location_header = (char *)apr_table_get(r->headers_out, "Location");
   if (! location_header) {
     location_header = (char *)apr_table_get(r->err_headers_out, "Location");
   }
   if (cookie && location_header) {
-    DBG(r, "REQ[%X] Location Header=[%s]", (unsigned int)(apr_size_t)r, location_header);
+    DBG(r, "REQ[%X] Location Header=[%s]", TO_ADDR(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)(apr_size_t)r, location_header);
+    DBG(r, "REQ[%X] Location Header=[%s]", TO_ADDR(r), location_header);
     if (!ap_is_HTTP_REDIRECT(r->status)) {
       r->status = HTTP_MOVED_TEMPORARILY;
     }
   }
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 }
 
 /**
@@ -1387,13 +1483,12 @@ chxj_input_handler(request_rec *r)
   char                *response;
   char                *user_agent;
   apr_pool_t          *pool;
-  apr_size_t          ii;
   int                 response_code = 0;
   
-  DBG(r, "start of chxj_input_handler()");
+  DBG(r, "REQ[%X] start %s()",TO_ADDR(r),__func__);
 
   if (strcasecmp(r->handler, "chxj-input-handler")) {
-    DBG(r, "end chxj_input_handler()");
+    DBG(r, "REQ[%X] end %s()",TO_ADDR(r),__func__);
     return DECLINED;
   }
   apr_pool_create(&pool, r->pool);
@@ -1429,7 +1524,7 @@ chxj_input_handler(request_rec *r)
    */
   if (post_data_len > 0) {
     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);
+    DBG(r, "REQ[%X] (in:exchange)POSTDATA:[%s]", TO_ADDR(r),post_data);
   }
 
   char *url_path;
@@ -1442,19 +1537,20 @@ chxj_input_handler(request_rec *r)
   if (r->args) {
     url_path = apr_pstrcat(pool, url_path, "?", r->args, NULL);
   }
-  DBG(r, "==> new url_path:[%s]", url_path);
+  DBG(r, "REQ[%X] ==> new url_path:[%s]", TO_ADDR(r),url_path);
 
   apr_size_t res_len;
   apr_table_setn(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_IP, r->connection->remote_ip);
+  char *x_client_type = (char *)apr_table_get(r->headers_in, "X-Client-Type");
+  if (x_client_type) {
+    apr_table_setn(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_TYPE, x_client_type); /* for mod_cidr_lookup */
+  }
+  else {
+    apr_table_unset(r->headers_in, "X-Client-Type");
+  }
   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_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++) {
-    DBG(r, "REQ[%X] response:[%.*s]", (unsigned int)(apr_size_t)r, 64, &response[ii*64]);
-  }
-  DBG(r, "REQ[%X] -------------------------------------------------------", (unsigned int)(apr_size_t)r);
 
   char *chunked;
   if ((chunked = (char *)apr_table_get(r->headers_out, "Transfer-Encoding")) != NULL) {
@@ -1464,7 +1560,7 @@ chxj_input_handler(request_rec *r)
     }
   }
   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);
+    DBG(r, "REQ[%X] end %s() (HTTP-ERROR received. response code:[%d])", TO_ADDR(r), __func__,response_code);
     return response_code;
   }
   {
@@ -1481,13 +1577,13 @@ chxj_input_handler(request_rec *r)
     e = apr_bucket_eos_create(c->bucket_alloc);
     APR_BRIGADE_INSERT_TAIL(bb, e);
     if ((rv = ap_pass_brigade(r->output_filters, bb)) != APR_SUCCESS) {
-      ERR(r, "REQ[%X] %s:%d failed ap_pass_brigade()", (unsigned int)(apr_size_t)r, APLOG_MARK);
+      ERR(r, "REQ[%X] %s:%d failed ap_pass_brigade()", TO_ADDR(r), APLOG_MARK);
       return rv;
     }
     apr_brigade_cleanup(bb);
   }
 
-  DBG(r, "REQ[%X] end of chxj_input_handler()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
   return APR_SUCCESS;
 }
 
@@ -1589,12 +1685,25 @@ 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)(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] METHOD [%s]", TO_ADDR(r), r->method);
-  DBG(r, "REQ[%X] ", (unsigned int)(apr_size_t)r);
-  DBG(r, "REQ[%X] =======================================================================", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] =======================================================================", TO_ADDR(r));
+  DBG(r, "REQ[%X] ",                                                                        TO_ADDR(r));
+  DBG(r, "REQ[%X] START REQUEST (uri:[%s] args:[%s])",                                      TO_ADDR(r), r->unparsed_uri, r->args ? r->args : "");
+  DBG(r, "REQ[%X] METHOD [%s]",                                                             TO_ADDR(r), r->method);
+  DBG(r, "REQ[%X] ",                                                                        TO_ADDR(r));
+  DBG(r, "REQ[%X] =======================================================================", TO_ADDR(r));
+
+  mod_chxj_config *dconf;
+  dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
+  /*
+  if (dconf->image_rewrite ==CHXJ_IMG_REWRITE_ON ){
+    if(r->args && strcasecmp(r->args,"rewrite") == 0){
+      DBG(r, "image rewrite is ON [%s] - %s", dconf->image_rewrite_url ,r->content_type);
+      r->filename = apr_pstrcat(r->pool,dconf->image_rewrite_url,NULL);
+      return OK;
+    }
+  }
+  */
+
 #if 0
   return chxj_trans_name(r);
 #else
@@ -1614,7 +1723,7 @@ chxj_insert_filter(request_rec *r)
   apr_status_t        rv;
   char                *contentType;
 
-  DBG(r, "REQ[%X] start chxj_insert_filter()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] start %s()", TO_ADDR(r),__func__);
 
   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
@@ -1627,22 +1736,22 @@ chxj_insert_filter(request_rec *r)
   contentType = (char *)apr_table_get(r->headers_in, "Content-Type");
   if (contentType
       && strncasecmp("multipart/form-data", contentType, 19) == 0) {
-    DBG(r, "REQ[%X] detect multipart/form-data ==> no target", (apr_size_t)(unsigned int)r);
-    DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] detect multipart/form-data ==> no target", TO_ADDR(r));
+    DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
     return;
   }
 
   spec = chxj_specified_device(r, user_agent);
   entryp = chxj_apply_convrule(r, dconf->convrules);
   if (!entryp) {
-    DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
     return;
   }
   ctx = apr_palloc(r->pool, sizeof(*ctx));
   memset(ctx, 0, sizeof(*ctx));
   if ((rv = apr_pool_create(&ctx->pool, r->pool)) != APR_SUCCESS) {
-    ERR(r, "%s:%d: failed: new pool create. rv:[%d]", __FILE__,__LINE__,rv);
-    DBG(r, "REQ:[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
+    ERR(r, "REQ[%X] %s:%d: failed: new pool create. rv:[%d]", TO_ADDR(r),__FILE__,__LINE__,rv);
+    DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
     return;
   }
   ctx->entryp = entryp;
@@ -1650,9 +1759,9 @@ chxj_insert_filter(request_rec *r)
   ctx->buffer = apr_palloc(ctx->pool, 1);
   ctx->buffer[0] = 0;
 
-  if (!entryp || !(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
-    DBG(r,"REQ[%X] EngineOff", (unsigned int)(apr_size_t)r);
-    DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
+  if (!entryp || (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT))) {
+    DBG(r,"REQ[%X] EngineOff", TO_ADDR(r));
+    DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
     return;
   }
 
@@ -1671,17 +1780,17 @@ chxj_insert_filter(request_rec *r)
     break;
 
   default:
-    DBG(r, "REQ[%X] end chxj_insert_filter() Unknown spec type(%d).", (unsigned int)(apr_size_t)r, spec->html_spec_type);
+    DBG(r, "REQ[%X] end %s() Unknown spec type(%d).", TO_ADDR(r), __func__,spec->html_spec_type);
     return;
   }
 
 
   if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
     ap_add_output_filter("chxj_output_filter", ctx, r, r->connection);
-    DBG(r, "REQ[%X] added Output Filter", (unsigned int)(apr_size_t)r);
+    DBG(r, "REQ[%X] added Output Filter", TO_ADDR(r));
   }
 
-  DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
+  DBG(r, "REQ[%X] end %s()", TO_ADDR(r),__func__);
 }
 
 
@@ -1710,8 +1819,12 @@ chxj_register_hooks(apr_pool_t *UNUSED(p))
   ap_hook_handler(chxj_img_conv_format_handler, NULL, NULL, APR_HOOK_MIDDLE);
   ap_hook_handler(chxj_qr_code_handler, NULL, NULL, APR_HOOK_MIDDLE);
   ap_hook_handler(chxj_input_handler, NULL, NULL, APR_HOOK_MIDDLE);
+
+  ap_hook_handler(chxj_image_redirect_handler, NULL, NULL, APR_HOOK_MIDDLE);
+
   ap_hook_translate_name(chxj_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
   ap_hook_fixups(chxj_headers_fixup, NULL, NULL, APR_HOOK_FIRST);
+
 }
 
 
@@ -1732,6 +1845,7 @@ chxj_create_per_dir_config(apr_pool_t *p, char *arg)
   conf->emoji_data_file  = NULL;
   conf->emoji            = NULL;
   conf->emoji_tail       = NULL;
+  conf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_NONE;
   conf->image            = CHXJ_IMG_NONE;
   conf->image_cache_dir  = apr_psprintf(p, "%s",DEFAULT_IMAGE_CACHE_DIR);
   conf->image_cache_limit = 0;
@@ -1741,6 +1855,9 @@ chxj_create_per_dir_config(apr_pool_t *p, char *arg)
   conf->cookie_store_type = COOKIE_STORE_TYPE_NONE;
   conf->cookie_lazy_mode  = 0;
   conf->cookie_dbm_type  = NULL;
+  
+  conf->detect_device_type = CHXJ_ADD_DETECT_DEVICE_TYPE_NONE;
+  
 #if defined(USE_MYSQL_COOKIE)
   memset((void *)&conf->mysql, 0, sizeof(mysql_t));
   conf->mysql.port       = MYSQL_PORT;
@@ -1769,6 +1886,10 @@ chxj_create_per_dir_config(apr_pool_t *p, char *arg)
   /* Default is copyleft */
   conf->image_copyright = NULL; 
 
+  conf->image_rewrite = CHXJ_IMG_REWRITE_NONE;
+  conf->image_rewrite_mode = CHXJ_IMG_REWRITE_MODE_NONE;
+  conf->image_rewrite_url = NULL;
+
   return conf;
 }
 
@@ -1796,12 +1917,16 @@ chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
   mrg->image_cache_limit  = 0;
   mrg->emoji            = NULL;
   mrg->emoji_tail       = NULL;
+  mrg->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_NONE;
   mrg->new_line_type    = NLTYPE_NIL;
   mrg->forward_url_base = NULL;
   mrg->forward_server_ip = NULL;
   mrg->allowed_cookie_domain = NULL;
   mrg->post_log         = NULL;
   mrg->cookie_dbm_type  = NULL;
+  
+  mrg->device_keys      = NULL;
+  mrg->device_hash      = NULL;
 
   mrg->dir = apr_pstrdup(p, add->dir);
 
@@ -2039,6 +2164,56 @@ chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
   else {
     mrg->cookie_dbm_type = base->cookie_dbm_type;
   }
+  
+  if (add->imode_emoji_color == CHXJ_IMODE_EMOJI_COLOR_NONE) {
+    mrg->imode_emoji_color = base->imode_emoji_color;
+  }
+  else {
+    mrg->imode_emoji_color = add->imode_emoji_color;
+  }
+  
+  if (add->detect_device_type == CHXJ_ADD_DETECT_DEVICE_TYPE_NONE) {
+    mrg->detect_device_type = base->detect_device_type;
+  }
+  else {
+    mrg->detect_device_type = add->detect_device_type;
+  }
+  
+  if (add->device_keys) {
+    mrg->device_keys = add->device_keys;
+  }
+  else{
+    mrg->device_keys = base->device_keys;
+  }
+  
+  if (add->device_hash) {
+    mrg->device_hash = add->device_hash;
+  }
+  else{
+    mrg->device_hash = base->device_hash;
+  }
+  
+  if (add->image_rewrite == CHXJ_IMG_REWRITE_NONE){
+    mrg->image_rewrite = base->image_rewrite;
+  }
+  else{
+    mrg->image_rewrite = add->image_rewrite;
+  }
+
+  if (add->image_rewrite_url) {
+    mrg->image_rewrite_url = add->image_rewrite_url;
+  }
+  else{
+    mrg->image_rewrite_url = base->image_rewrite_url;
+  }
+
+  if (add->image_rewrite_mode == CHXJ_IMG_REWRITE_MODE_NONE){
+    mrg->image_rewrite_mode = base->image_rewrite_mode;
+  }
+  else{
+    mrg->image_rewrite_mode = add->image_rewrite_mode;
+  }
+
   return mrg;
 }
 
@@ -2301,6 +2476,17 @@ cmd_set_image_cache_dir(cmd_parms *parms, void *mconfig, const char *arg)
 
   if (strlen(arg) > 256) 
     return "cache dir name is too long.";
+  
+  apr_finfo_t info;
+  apr_status_t res = apr_stat(&info,arg,APR_FINFO_TYPE,parms->pool);
+  if(res != APR_SUCCESS){
+    return apr_psprintf(parms->pool,"ChxjImageCacheDir [%s]: not found ",arg);
+  }
+  else{
+    if(info.filetype != APR_DIR){
+      return apr_psprintf(parms->pool,"ChxjImageCacheDir [%s]: is not directory ",arg);
+    }
+  }
 
   conf = (mod_chxj_config *)mconfig;
   conf->image_cache_dir = apr_pstrdup(parms->pool, arg);
@@ -2418,6 +2604,13 @@ cmd_convert_rule(cmd_parms *cmd, void *mconfig, const char *arg)
       }
       break;
 
+    case 'O':
+    case 'o':
+      if (strcasecmp(CONVRULE_OVERWRITE_X_CLIENT_TYPE_CMD, action) == 0) {
+        newrule->action |= CONVRULE_OVERWRITE_X_CLIENT_TYPE_BIT;
+      }
+      break;
+
     case 'C':
     case 'c':
       if (strcasecmp(CONVRULE_COOKIE_ON_CMD, action) == 0) {
@@ -2432,6 +2625,9 @@ cmd_convert_rule(cmd_parms *cmd, void *mconfig, const char *arg)
       else if (strcasecmp(CONVRULE_CSS_OFF_CMD, action) == 0) {
         newrule->action &= (0xffffffff ^ CONVRULE_CSS_ON_BIT);
       }
+      else if (strcasecmp(CONVRULE_COOKIE_ONLY_CMD, action) == 0) {
+        newrule->action |= CONVRULE_COOKIE_ONLY_BIT;
+      }
       break;
 
     case 'J':
@@ -2936,6 +3132,117 @@ cmd_cookie_dbm_type(
   return NULL;
 }
 
+static const char *
+cmd_imode_emoji_color(
+  cmd_parms   *cmd, 
+  void        *mconfig, 
+  const char  *arg)
+{
+  mod_chxj_config  *dconf;
+  
+  if (strlen(arg) > 256) 
+    return "imode emoji color is too long.";
+
+  dconf = (mod_chxj_config *)mconfig;
+  if (strcasecmp("ON", arg) == 0) {
+    dconf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_ON;
+  }
+  else if(strcasecmp("AUTO",arg) == 0) {
+    dconf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_AUTO;
+  }
+  else {
+    dconf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_OFF;
+  }
+  
+  return NULL;
+}
+
+static const char *
+cmd_add_device_data_tsv(cmd_parms *parms, void *mconfig, const char *arg) 
+{
+  mod_chxj_config  *conf;
+  
+  if (strlen(arg) > 256) 
+    return "mod_chxj: device tsv filename too long.";
+
+  conf = (mod_chxj_config *)mconfig;
+  
+  conf->detect_device_type = CHXJ_ADD_DETECT_DEVICE_TYPE_TSV;
+  
+  apr_finfo_t info;
+  apr_status_t res = apr_stat(&info,arg,APR_FINFO_TYPE,parms->pool);
+  if(res != APR_SUCCESS){
+    return apr_psprintf(parms->pool,"ChxjDeviceTSV [%s]: not found ",arg);
+  }
+  else{
+    if(info.filetype != APR_REG ){
+      return apr_psprintf(parms->pool,"ChxjDeviceTSV [%s]: is not file ",arg);
+    }
+  }
+  apr_file_t *fp;
+  apr_file_open(&fp, arg, APR_READ|APR_BUFFERED, APR_OS_DEFAULT, parms->pool);
+  
+  chxj_load_device_tsv_data(fp,parms->pool,conf);
+  
+  apr_file_close(fp);
+  return NULL;
+}
+
+static const char *
+cmd_image_rewrite(cmd_parms *parms, void *mconfig, const char *arg)
+{
+  mod_chxj_config *conf;
+  if (strlen(arg) > 256){
+    return "mod_chxj: set rewrite too long.";
+  }
+  conf = (mod_chxj_config *)mconfig;
+  if (strcasecmp("ON", arg) == 0) {
+    conf->image_rewrite = CHXJ_IMG_REWRITE_ON;
+  }
+  else if(strcasecmp("OFF",arg) == 0) {
+    conf->image_rewrite = CHXJ_IMG_REWRITE_OFF;
+  }
+  else {
+    conf->image_rewrite = CHXJ_IMG_REWRITE_NONE;
+  }
+  return NULL;
+}
+
+static const char *
+cmd_image_rewrite_url(cmd_parms *parms, void *mconfig, const char *arg)
+{
+  mod_chxj_config *conf;
+  if (strlen(arg) > 256){
+    return "mod_chxj: set rewrite url too long.";
+  }
+  conf = (mod_chxj_config *)mconfig;
+  conf->image_rewrite_url = apr_pstrdup(parms->pool, arg);;
+  return NULL;
+}
+
+static const char *
+cmd_image_rewrite_mode(cmd_parms *parms, void *mconfig, const char *arg)
+{
+  mod_chxj_config *conf;
+  if (strlen(arg) > 256){
+    return "mod_chxj: set rewrite mode is too long.";
+  }
+
+  conf = (mod_chxj_config *)mconfig;
+  if (strcasecmp("all",arg) == 0) {
+    conf->image_rewrite_mode = CHXJ_IMG_REWRITE_MODE_ALL;
+  }
+  else if (strcasecmp("user",arg) == 0) {
+    conf->image_rewrite_mode = CHXJ_IMG_REWRITE_MODE_USER;
+  }
+  else if (strcasecmp("tag",arg) == 0) {
+    conf->image_rewrite_mode = CHXJ_IMG_REWRITE_MODE_TAG;
+  }
+  else{
+    conf->image_rewrite_mode = CHXJ_IMG_REWRITE_MODE_NONE;
+  }
+  return NULL;
+}
 
 static const command_rec cmds[] = {
   AP_INIT_TAKE1(
@@ -3104,6 +3411,39 @@ static const command_rec cmds[] = {
     NULL,
     OR_ALL,
     "Kind of DBM used with Cookie simulator.(default|GDBM|SDBM|DB|NDBM)"),
+  AP_INIT_TAKE1(
+    "ChxjImodeEmojiColor",
+    cmd_imode_emoji_color,
+    NULL,
+    OR_ALL,
+    "Auto i-mode emoji color"),
+  AP_INIT_TAKE1(
+    "ChxjAddDeviceDataTSV",
+    cmd_add_device_data_tsv,
+    NULL,
+    OR_ALL,
+    "Additional devices TSV data"),
+  AP_INIT_TAKE1(
+    "ChxjImageRewrite",
+    cmd_image_rewrite,
+    NULL,
+    OR_ALL,
+    "Rewrite Image"
+   ),
+  AP_INIT_TAKE1(
+    "ChxjImageRewriteUrl",
+    cmd_image_rewrite_url,
+    NULL,
+    OR_ALL,
+    "Set rewrite Image url"
+   ),
+  AP_INIT_TAKE1(
+    "ChxjImageRewriteMode",
+    cmd_image_rewrite_mode,
+    NULL,
+    OR_ALL,
+    "Set rewrite Image rewrite url mode"
+   ),
   {NULL,{NULL},NULL,0,0,NULL},
 };