OSDN Git Service

* Added New Features.
[modchxj/mod_chxj.git] / src / mod_chxj.c
index 45cd475..0f7bb65 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");
@@ -70,6 +70,7 @@
 #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,
   },
 };
 
@@ -148,6 +162,7 @@ static int chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp,
 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. 
@@ -209,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)) {
+    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, 
@@ -360,7 +379,7 @@ 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)) {
     switch(spec->html_spec_type) {
     case CHXJ_SPEC_Chtml_1_0:
     case CHXJ_SPEC_Chtml_2_0:
@@ -386,6 +405,28 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
                                                           *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);
+        }
+        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);
+      return dst;
+    }
+
     if (convert_routine[spec->html_spec_type].converter) {
       if (tmp)
         dst = convert_routine[spec->html_spec_type].converter(r, 
@@ -398,7 +439,7 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
       else
         dst = convert_routine[spec->html_spec_type].converter(r,
                                                               spec, 
-                                                              tmp
+                                                              *src
                                                               *len, 
                                                               len, 
                                                               entryp, 
@@ -533,6 +574,8 @@ chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_tabl
     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);
@@ -720,6 +763,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);
@@ -902,6 +947,27 @@ pass_data_to_filter(ap_filter_t *f, const char *data,
 
 
 /**
+ * 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.
@@ -977,6 +1043,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           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;
@@ -1154,6 +1221,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
             }
           }
           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);
@@ -1200,13 +1268,13 @@ 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, "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;
@@ -1332,6 +1400,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);
@@ -1353,7 +1425,7 @@ chxj_input_handler(request_rec *r)
   }
 
   DBG(r, "REQ[%X] end of chxj_input_handler()", (unsigned int)(apr_size_t)r);
-  return response_code;
+  return APR_SUCCESS;
 }
 
 static mod_chxj_global_config *
@@ -1604,6 +1676,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;
@@ -1648,6 +1721,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);
 
@@ -1866,6 +1940,13 @@ chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
   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;
 }
 
@@ -2235,6 +2316,10 @@ 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;
+      }
       break;
 
     case 'C':
@@ -2244,6 +2329,27 @@ cmd_convert_rule(cmd_parms *cmd, void *mconfig, const char *arg)
       }
       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) {
@@ -2644,6 +2750,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, 
@@ -2823,6 +2947,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}
 };