OSDN Git Service

img url rewrite tag mode
[modchxj/mod_chxj.git] / src / mod_chxj.c
old mode 100644 (file)
new mode 100755 (executable)
index f760efa..ff94a08
@@ -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"
@@ -70,7 +71,6 @@
 #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"
 
@@ -200,14 +200,7 @@ chxj_headers_fixup(request_rec *r)
     DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
     return DECLINED;
   }
-  if (r->method_number == M_POST) {
-    if (!apr_table_get(r->headers_in, "X-Chxj-Forward")) {
-      s_clear_cookie_header(r, spec);
-    }
-  }
-  else {
-    s_clear_cookie_header(r, spec);
-  }
+
 
   switch(spec->html_spec_type) {
   case CHXJ_SPEC_Chtml_1_0:
@@ -226,7 +219,7 @@ 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->action & CONVRULE_ENGINE_ON_BIT)) {
+    if (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
       DBG(r, "REQ[%X] end chxj_headers_fixup() (engine off)", (unsigned int)(apr_size_t)r);
       return DECLINED;
     }
@@ -243,13 +236,26 @@ chxj_headers_fixup(request_rec *r)
       apr_table_setn(r->headers_in, 
                      HTTP_USER_AGENT, 
                      entryp->user_agent);
+    /*
+     * this clear process must do before chxj_convert_input_header function.
+     */
+    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);
+        }
+      }
+      else {
+        s_clear_cookie_header(r, spec);
+      }
+    }
 
     chxj_convert_input_header(r,entryp, spec);
 
     break;
   
   default:
-    DBG(r, "REQ[%X] end chxj_headers_fixup() (not mobile) spec->device_name[%s]", (unsigned int)(apr_size_t)r, spec->device_name);
+    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);
     return DECLINED;
 
   }
@@ -298,6 +304,31 @@ chxj_headers_fixup(request_rec *r)
       }
     }
   }
+  else{
+    if(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);
 
@@ -306,10 +337,29 @@ chxj_headers_fixup(request_rec *r)
   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,"start chxj_image_redirect_handler");
+  ap_internal_redirect(apr_pstrcat(r->pool, r->filename+13,
+                                       r->args ? "?" : NULL, r->args, NULL), r);
+  DBG(r,"end chxj_image_redirect_handler");
+  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));
   switch(spec->html_spec_type) {
   case CHXJ_SPEC_Chtml_1_0:
   case CHXJ_SPEC_Chtml_2_0:
@@ -325,6 +375,7 @@ s_clear_cookie_header(request_rec *r, device_table *spec)
   default:
     break;
   }
+  DBG(r, "REQ[%X] end   s_clear_cookie_header()", TO_ADDR(r));
 }
 
 
@@ -356,7 +407,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)) {
+  if (!entryp || (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT))) {
     DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
     return (char *)*src;
   }
@@ -390,9 +441,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:
@@ -412,58 +464,67 @@ 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);
-      }
-      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);
+    if ((entryp->action & CONVRULE_COOKIE_ONLY_BIT) && cookie) {
+      dst = chxj_cookie_only_mode(r, *src, (apr_size_t *)len, cookie);
+    }
+    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 of chxj_convert()(emoji only)", (unsigned int)(apr_size_t)r);
       }
-      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);
+  
+      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) {
@@ -476,6 +537,7 @@ 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);
 
   return dst;
@@ -606,7 +668,7 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
           dlen   = strlen(value);
           DBG(r, "************ before encoding[%s]", 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);
@@ -618,7 +680,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 {
@@ -783,7 +845,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 {
@@ -793,7 +855,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 {
@@ -826,7 +888,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);
 
@@ -863,12 +925,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);
@@ -886,7 +950,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);
@@ -1004,6 +1068,42 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
   spec   = ctx->spec;
   dconf  = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
+
+  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) || (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) {
+      case CHXJ_SPEC_Chtml_1_0:
+      case CHXJ_SPEC_Chtml_2_0:
+      case CHXJ_SPEC_Chtml_3_0:
+      case CHXJ_SPEC_Chtml_4_0:
+      case CHXJ_SPEC_Chtml_5_0:
+      case CHXJ_SPEC_Chtml_6_0:
+      case CHXJ_SPEC_Chtml_7_0:
+      case CHXJ_SPEC_XHtml_Mobile_1_0:
+      case CHXJ_SPEC_Jhtml:
+        lock = chxj_cookie_lock(r);
+        cookie = chxj_save_cookie(r);
+        s_add_cookie_id_if_has_location_header(r, cookie);
+        chxj_cookie_unlock(r, lock);
+        break;
+      default:
+        break;
+      }
+    }
+    if (! ap_is_HTTP_REDIRECT(r->status)) {
+      r->status = HTTP_MOVED_TEMPORARILY;
+    }
+    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));
+    return rv;
+  }
+
+
   if (r->content_type) {
     if (! STRNCASEEQ('t','T',"text/html",r->content_type, sizeof("text/html")-1)
     &&  ! STRNCASEEQ('t','T',"text/xml", r->content_type, sizeof("text/xml")-1)
@@ -1554,6 +1654,19 @@ chxj_translate_name(request_rec *r)
   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);
+
+  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
@@ -1586,7 +1699,7 @@ 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] detect multipart/form-data ==> no target", (unsigned int)(apr_size_t)r);
     DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
     return;
   }
@@ -1609,7 +1722,7 @@ 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)) {
+  if (!entryp || (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_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);
     return;
@@ -1669,8 +1782,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);
+
 }
 
 
@@ -1691,6 +1808,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;
@@ -1699,6 +1817,10 @@ chxj_create_per_dir_config(apr_pool_t *p, char *arg)
   conf->cookie_timeout   = 0;
   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;
@@ -1727,6 +1849,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;
 }
 
@@ -1754,11 +1880,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);
 
@@ -1990,6 +2121,62 @@ chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
   else {
     mrg->post_log = base->post_log;
   }
+  if (add->cookie_dbm_type) {
+    mrg->cookie_dbm_type = add->cookie_dbm_type;
+  }
+  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;
 }
 
@@ -2252,6 +2439,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);
@@ -2383,6 +2581,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':
@@ -2870,6 +3071,134 @@ cmd_post_log_env(
   return NULL;
 }
 
+static const char *
+cmd_cookie_dbm_type(
+  cmd_parms   *cmd, 
+  void        *mconfig, 
+  const char  *arg)
+{
+  mod_chxj_config  *dconf;
+  if (strlen(arg) > 255)
+    return "mod_chxj: ChxjCookieDbmType is too long.";
+
+  dconf = (mod_chxj_config *)mconfig;
+
+  dconf->cookie_dbm_type = apr_pstrdup(cmd->pool, arg);
+
+  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(
@@ -3032,7 +3361,46 @@ static const command_rec cmds[] = {
     NULL,
     OR_ALL,
     "for CustomLog directive. mod_chxj's internal POST log environment name.(Default:chxj-post-log)"),
-  {NULL}
+  AP_INIT_TAKE1(
+    "ChxjCookieDbmType",
+    cmd_cookie_dbm_type,
+    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},
 };