OSDN Git Service

* Fixed bug.
authorkonn <konn@1a406e8e-add9-4483-a2c8-d8cac5b7c224>
Thu, 26 Jun 2008 18:09:18 +0000 (18:09 +0000)
committerkonn <konn@1a406e8e-add9-4483-a2c8-d8cac5b7c224>
Thu, 26 Jun 2008 18:09:18 +0000 (18:09 +0000)
    - #12845

git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/modchxj/mod_chxj/branches/RELEASE_0_12_0@2732 1a406e8e-add9-4483-a2c8-d8cac5b7c224

ChangeLog
configure.ac
debian-sarge/changelog
debian/changelog
include/mod_chxj.h
src/Makefile.am
src/Makefile.in
src/chxj_buffered_write.c
src/chxj_jhtml.c
src/mod_chxj.c

index 27c50c0..faf9596 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+libapache2-mod-chxj (0.12.4-1) unstable; urgency=low
+
+  * Fixed Bug.
+    - Because Input_filter of Apache is a fuck-shit, it abolishes it.
+      Proxy is made at one's own expense by using libserf instead.
+      (Reported by tiruda1600 _at_ users.sourceforge.jp. thanks!)
+
+ -- Atsushi Konno <konn@users.sourceforge.jp>  Thu, 26 Jun 2008 10:32:44 +0900
+
 libapache2-mod-chxj (0.12.3-1) unstable; urgency=low
 
   * Fixed bug.
index 6e19217..ccc2664 100644 (file)
@@ -1,6 +1,6 @@
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
-AC_INIT([mod_chxj],[0.12.3-1])
+AC_INIT([mod_chxj],[0.12.4-1])
 AC_PREREQ(2.59)
 AC_CONFIG_SRCDIR([src/mod_chxj.c])
 AC_CANONICAL_TARGET
index d20b07a..b6ac1eb 100644 (file)
@@ -1,3 +1,12 @@
+libapache2-mod-chxj (0.12.4-1) unstable; urgency=low
+
+  * Fixed Bug.
+    - Because Input_filter of Apache is a fuck-shit, it abolishes it.
+      Proxy is made at one's own expense by using libserf instead.
+      (Reported by tiruda1600 _at_ users.sourceforge.jp. thanks!)
+
+ -- Atsushi Konno <konn@users.sourceforge.jp>  Thu, 26 Jun 2008 10:32:44 +0900
+
 libapache2-mod-chxj (0.12.3-1) unstable; urgency=low
 
   * Fixed bug.
index 4872934..9c44ec2 100644 (file)
@@ -1,3 +1,12 @@
+libapache2-mod-chxj (0.12.4-1) unstable; urgency=low
+
+  * Fixed Bug.
+    - Because Input_filter of Apache is a fuck-shit, it abolishes it.
+      Proxy is made at one's own expense by using libserf instead.
+      (Reported by tiruda1600 _at_ users.sourceforge.jp. thanks!)
+
+ -- Atsushi Konno <konn@users.sourceforge.jp>  Thu, 26 Jun 2008 10:32:44 +0900
+
 libapache2-mod-chxj (0.12.3-1) unstable; urgency=low
 
   * Fixed bug.
index 4dcbbaf..8bf7bb6 100644 (file)
@@ -346,6 +346,8 @@ struct mod_chxj_config {
 #if defined(USE_MEMCACHE_COOKIE)
   memcache_t            memcache;
 #endif
+  char                  *forward_url_base;  /* use input filter */
+  char                  *forward_server_ip; /* use input filter */
 
   chxj_new_line_type_t  new_line_type;
 };
@@ -400,6 +402,7 @@ typedef struct {
 #define HTTP_USER_AGENT       "User-Agent"
 #define HTTP_HOST             "Host"
 #define CHXJ_HTTP_USER_AGENT  "CHXJ_HTTP_USER_AGENT"
+#define CHXJ_HEADER_ORIG_CLIENT_IP "X-Chxj-Orig-Client-Ip"
 
 module AP_MODULE_DECLARE_DATA chxj_module;
 
@@ -438,6 +441,7 @@ extern char* chxj_node_convert(
 
 #define IMAGE_CACHE_LIMIT_FMT_LEN  (20)
 
+
 #if HAVE_MALLOC == 0
 extern void *rpl_malloc(size_t n);
 #endif
index c49d14f..a1a6564 100644 (file)
@@ -37,21 +37,27 @@ libmod_chxj_la_SOURCES = mod_chxj.c \
     chxj_memcache.c \
     chxj_dbm.c \
     chxj_buffered_write.c \
-    chxj_apache.c
+    chxj_apache.c \
+    chxj_serf.c
 
 
-libmod_chxj_la_CFLAGS = -O2 -prefer-pic @QDEFS@ @DDEFS@ -I. -I../include -I@with_apache_header@ 
+libmod_chxj_la_CFLAGS = -O2 -prefer-pic @QDEFS@ @DDEFS@ -I. -I../include -I@with_apache_header@  -I./serf
 AM_CFLAGS = @CFLAGS@ -O2 -prefer-pic @QDEFS@ @DDEFS@ -I. -I../include -I@with_apache_header@
+libmod_chxj_la_LIBADD = serf/libserf-0.la
 
 lib_LTLIBRARIES = libmod_chxj.la
 
 make_so:
        @if test ! -L mod_chxj.so ; then ln -s .libs/libmod_chxj.so mod_chxj.so ; fi
 
+serf/libserf-0.la:
+       (cd serf; ./configure --with-apr=`dirname @APR_CONFIG@` --with-apr-util=`dirname @APU_CONFIG@`; make)
+
 clean:
        rm -fr .libs
        rm -f *.o *.lo *.la
        rm -f mod_chxj.so
+       (cd serf; make clean)
 
 install: make_so
        @@APXS@ -i -n "chxj" @PACKAGE_NAME@.so 
index 3213f8c..6f76d29 100644 (file)
@@ -51,7 +51,7 @@ am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
 am__installdirs = "$(DESTDIR)$(libdir)"
 libLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(lib_LTLIBRARIES)
-libmod_chxj_la_LIBADD =
+libmod_chxj_la_DEPENDENCIES = serf/libserf-0.la
 am_libmod_chxj_la_OBJECTS = libmod_chxj_la-mod_chxj.lo \
        libmod_chxj_la-qs_parse_string.lo libmod_chxj_la-qs_log.lo \
        libmod_chxj_la-qs_malloc.lo libmod_chxj_la-qs_parse_tag.lo \
@@ -78,7 +78,7 @@ am_libmod_chxj_la_OBJECTS = libmod_chxj_la-mod_chxj.lo \
        libmod_chxj_la-chxj_cookie.lo libmod_chxj_la-chxj_mysql.lo \
        libmod_chxj_la-chxj_memcache.lo libmod_chxj_la-chxj_dbm.lo \
        libmod_chxj_la-chxj_buffered_write.lo \
-       libmod_chxj_la-chxj_apache.lo
+       libmod_chxj_la-chxj_apache.lo libmod_chxj_la-chxj_serf.lo
 libmod_chxj_la_OBJECTS = $(am_libmod_chxj_la_OBJECTS)
 libmod_chxj_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libmod_chxj_la_CFLAGS) \
@@ -260,10 +260,12 @@ libmod_chxj_la_SOURCES = mod_chxj.c \
     chxj_memcache.c \
     chxj_dbm.c \
     chxj_buffered_write.c \
-    chxj_apache.c
+    chxj_apache.c \
+    chxj_serf.c
 
-libmod_chxj_la_CFLAGS = -O2 -prefer-pic @QDEFS@ @DDEFS@ -I. -I../include -I@with_apache_header@ 
+libmod_chxj_la_CFLAGS = -O2 -prefer-pic @QDEFS@ @DDEFS@ -I. -I../include -I@with_apache_header@  -I./serf
 AM_CFLAGS = @CFLAGS@ -O2 -prefer-pic @QDEFS@ @DDEFS@ -I. -I../include -I@with_apache_header@
+libmod_chxj_la_LIBADD = serf/libserf-0.la
 lib_LTLIBRARIES = libmod_chxj.la
 all: all-am
 
@@ -359,6 +361,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmod_chxj_la-chxj_node_convert.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmod_chxj_la-chxj_preg_replace.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmod_chxj_la-chxj_qr_code.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmod_chxj_la-chxj_serf.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmod_chxj_la-chxj_specified_device.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmod_chxj_la-chxj_str_util.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmod_chxj_la-chxj_tag_util.Plo@am__quote@
@@ -660,6 +663,13 @@ libmod_chxj_la-chxj_apache.lo: chxj_apache.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmod_chxj_la_CFLAGS) $(CFLAGS) -c -o libmod_chxj_la-chxj_apache.lo `test -f 'chxj_apache.c' || echo '$(srcdir)/'`chxj_apache.c
 
+libmod_chxj_la-chxj_serf.lo: chxj_serf.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmod_chxj_la_CFLAGS) $(CFLAGS) -MT libmod_chxj_la-chxj_serf.lo -MD -MP -MF $(DEPDIR)/libmod_chxj_la-chxj_serf.Tpo -c -o libmod_chxj_la-chxj_serf.lo `test -f 'chxj_serf.c' || echo '$(srcdir)/'`chxj_serf.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/libmod_chxj_la-chxj_serf.Tpo $(DEPDIR)/libmod_chxj_la-chxj_serf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='chxj_serf.c' object='libmod_chxj_la-chxj_serf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmod_chxj_la_CFLAGS) $(CFLAGS) -c -o libmod_chxj_la-chxj_serf.lo `test -f 'chxj_serf.c' || echo '$(srcdir)/'`chxj_serf.c
+
 mostlyclean-libtool:
        -rm -f *.lo
 
@@ -848,10 +858,14 @@ uninstall-am: uninstall-libLTLIBRARIES
 make_so:
        @if test ! -L mod_chxj.so ; then ln -s .libs/libmod_chxj.so mod_chxj.so ; fi
 
+serf/libserf-0.la:
+       (cd serf; ./configure --with-apr=`dirname @APR_CONFIG@` --with-apr-util=`dirname @APU_CONFIG@`; make)
+
 clean:
        rm -fr .libs
        rm -f *.o *.lo *.la
        rm -f mod_chxj.so
+       (cd serf; make clean)
 
 install: make_so
        @@APXS@ -i -n "chxj" @PACKAGE_NAME@.so 
index cfcb92c..754469f 100644 (file)
@@ -48,6 +48,15 @@ chxj_buffered_write(const char *src, buf_object *buf, const char *add, int add_l
     buf->buffer[buf->use_len] = 0;
     return (char *)src;
   }
+  else if (buf->use_len < CHXJ_BUFFERED_OBJECT_SIZE - 1) {
+    int new_add_len = CHXJ_BUFFERED_OBJECT_SIZE - 1 - buf->use_len;
+    memcpy(&buf->buffer[buf->use_len], add, new_add_len);
+    buf->use_len += new_add_len;
+    buf->buffer[buf->use_len] = 0;
+    result = chxj_buffered_write_flush(src, buf);
+    result = chxj_buffered_write(result, buf, add + new_add_len, add_len - new_add_len);
+    return result;
+  }
   result = chxj_buffered_write_flush(src, buf);
   result = chxj_buffered_write(result, buf, add, add_len);
   return result;
index cb8e362..f12aef7 100644 (file)
@@ -424,6 +424,7 @@ chxj_convert_jhtml(
   char      *ss;
   jhtml_t   jhtml;
   Doc       doc;
+  apr_pool_t *pool;
 
   dst = NULL;
 
@@ -454,7 +455,8 @@ chxj_convert_jhtml(
   qs_init_malloc(&doc);
   qs_init_root_node(&doc);
 
-  ss = apr_pcalloc(r->pool, srclen + 1);
+  apr_pool_create(&pool, r->pool);
+  ss = apr_pcalloc(pool, srclen + 1);
 
   memset(ss,   0, srclen + 1);
   memcpy(ss, src, srclen);
@@ -471,17 +473,17 @@ chxj_convert_jhtml(
   /*--------------------------------------------------------------------------*/
   chxj_node_convert(spec,r,(void*)&jhtml, &doc, qs_get_root(&doc), 0);
   jhtml.out = chxj_buffered_write_flush(jhtml.out, &doc.buf);
-  dst = apr_pstrdup(r->pool, jhtml.out);
+  dst = apr_pstrdup(pool, jhtml.out);
   chxj_buffered_write_terminate(&doc.buf);
 
 
   qs_all_free(&doc,QX_LOGMARK);
 
   if (! dst) 
-    return apr_pstrdup(r->pool,ss);
+    return apr_pstrdup(pool,ss);
 
   if (! strlen(dst)) 
-    dst = apr_psprintf(r->pool, "\n");
+    dst = apr_psprintf(pool, "\n");
 
   *dstlen = strlen(dst);
 
@@ -2500,6 +2502,7 @@ s_jhtml_text_tag(void* pdoc, Node* child)
   jhtml = GET_JHTML(pdoc);
   doc   = jhtml->doc;
   r     = doc->r;
+  DBG(r, "start s_jhtml_text_tag()");
 
   textval = qs_get_node_value(doc,child);
   if (strlen(textval) == 0) {
@@ -2547,6 +2550,7 @@ s_jhtml_text_tag(void* pdoc, Node* child)
     }
   }
   W_V(tdst);
+  DBG(r, "end s_jhtml_text_tag()");
   return jhtml->out;
 }
 
index aa799ef..b279b6c 100644 (file)
 #if defined(USE_MYSQL_COOKIE)
 #  include "chxj_mysql.h"
 #endif
+#include "chxj_serf.h"
 
 
 #define CHXJ_VERSION_PREFIX PACKAGE_NAME "/"
 #define CHXJ_VERSION        PACKAGE_VERSION
+#define CHXJ_POST_MAX       (0x1000000)
 
 converter_t convert_routine[] = {
   {
@@ -150,34 +152,45 @@ static void s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *coo
 static apr_status_t 
 chxj_headers_fixup(request_rec *r)
 {
-  mod_chxj_config     *dconf; 
-  chxjconvrule_entry  *entryp;
-  char                *user_agent;
-  device_table        *spec;
+  mod_chxj_config*    dconf; 
+  chxjconvrule_entry* entryp;
+  char*               user_agent;
+  device_table*       spec;
+  char                *contentType;
+  char                *contentLength;
 
   DBG(r, "start chxj_headers_fixup()");
   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
-  user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
+  user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
   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, "detect multipart/form-data ==> no target");
+    DBG(r, "end chxj_headers_fixup()");
+    return DECLINED;
+  }
+
   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_Hdml:
   case CHXJ_SPEC_Jhtml:
-  case CHXJ_SPEC_Jxhtml:
     entryp = chxj_apply_convrule(r, dconf->convrules);
     if (! entryp) {
       DBG(r, "end chxj_headers_fixup() no pattern");
       return DECLINED;
     }
+    if (!entryp || !(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
+      DBG(r,"EngineOff");
+      return DECLINED;
+    }
   
     apr_table_setn(r->headers_in, 
                    CHXJ_HTTP_USER_AGENT, 
@@ -193,8 +206,47 @@ chxj_headers_fixup(request_rec *r)
     break;
   
   default:
-    break;
+    return DECLINED;
+
+  }
 
+
+  if (r->method_number == M_POST) {
+    if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
+        DBG(r, "set Input handler old:[%s] proxyreq:[%d] uri:[%s] filename:[%s]", 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);
+      if (client_ip) {
+        apr_sockaddr_t *address = NULL;
+        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, "%s:%d apr_sockaddr_info_get() failed: rv:[%d|%s]", APLOG_MARK, rv, apr_strerror(rv, buf, 256));
+          DBG(r, "end chxj_headers_fixup()");
+          return DECLINED;
+        }
+        char *addr;
+        if (dconf->forward_server_ip) {
+          addr = dconf->forward_server_ip;
+        }
+        else {
+          apr_sockaddr_ip_get(&addr, address);
+        }
+        DBG(r, "Client IP:[%s] vs Orig Client IP:[%s] vs Server IP:[%s]", 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);
+        }
+        if (! apr_table_get(r->headers_in, "Content-Length")) {
+          contentLength = (char *)apr_table_get(r->headers_in, "X-Chxj-Content-Length");
+          if (contentLength) {
+            apr_table_set(r->headers_in, "Content-Length", contentLength);
+          }
+        }
+      }
+    }
   }
 
   DBG(r, "end chxj_headers_fixup()");
@@ -202,7 +254,6 @@ chxj_headers_fixup(request_rec *r)
   return DECLINED;
 }
 
-
 /**
  * It converts it from CHTML into XXML corresponding to each model. 
  *
@@ -305,6 +356,7 @@ chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *sp
                                                               cookie);
     }
   }
+  ap_set_content_length(r, *len);
 
   if (*len == 0) {
     dst = apr_psprintf(r->pool, "\n");
@@ -655,24 +707,18 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
   mod_chxj_config     *dconf;
   chxjconvrule_entry  *entryp = NULL;
   device_table        *spec = NULL;
+  apr_pool_t          *pool;
 
   DBG(f->r, "start of chxj_output_filter()");
   r  = f->r;
   rv = APR_SUCCESS;
 
-  dconf      = ap_get_module_config(r->per_dir_config, &chxj_module);
-  user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
-  if (ctx && ctx->entryp) entryp = ctx->entryp;
-  else                    entryp = chxj_apply_convrule(r, dconf->convrules);
-  if (ctx && ctx->spec)   spec   = ctx->spec;
-  else                    spec   = chxj_specified_device(r, user_agent);
+  apr_pool_create(&pool, r->pool);
+
+  entryp = ctx->entryp;
+  spec   = ctx->spec;
+  dconf  = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
-  if (!f->ctx) {
-    if ((f->r->proto_num >= 1001) 
-    &&  !f->r->main 
-    &&  !f->r->prev) 
-      f->r->chunked = 1;
-  }
   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)
@@ -728,46 +774,25 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
     if (apr_bucket_read(b, &data, &len, APR_BLOCK_READ) == APR_SUCCESS) {
       DBG(r, "read data[%.*s]",(int)len, data);
 
-      if (f->ctx == NULL) {
-        /*--------------------------------------------------------------------*/
-        /* Start                                                              */
-        /*--------------------------------------------------------------------*/
-        DBG(r, "new context");
-        ctx = (mod_chxj_ctx *)apr_palloc(r->pool, sizeof(mod_chxj_ctx));
-        if (len > 0) {
-          ctx->buffer = apr_palloc(r->pool, len);
-          memcpy(ctx->buffer, data, len);
-        }
-        else {
-          ctx->buffer = apr_palloc(r->pool, 1);
-          ctx->buffer = '\0';
-        }
-        ctx->len = len;
-        f->ctx = (void *)ctx;
-        ctx->entryp = entryp;
-        ctx->spec   = spec;
-      }
-      else {
-        /*--------------------------------------------------------------------*/
-        /* append data                                                        */
-        /*--------------------------------------------------------------------*/
-        char *tmp;
-        DBG(r, "append data start");
-        ctx = (mod_chxj_ctx *)f->ctx;
+      /*--------------------------------------------------------------------*/
+      /* append data                                                        */
+      /*--------------------------------------------------------------------*/
+      char *tmp;
+      DBG(r, "append data start");
+      ctx = (mod_chxj_ctx *)f->ctx;
 
-        if (len > 0) {
-          tmp = apr_palloc(r->pool, ctx->len);
-          memcpy(tmp, ctx->buffer, ctx->len);
+      if (len > 0) {
+        tmp = apr_palloc(r->pool, ctx->len);
+        memcpy(tmp, ctx->buffer, ctx->len);
 
-          ctx->buffer = apr_palloc(r->pool, ctx->len + len);
+        ctx->buffer = apr_palloc(pool, ctx->len + len);
 
-          memcpy(ctx->buffer, tmp, ctx->len);
-          memcpy(&ctx->buffer[ctx->len], data, len);
+        memcpy(ctx->buffer, tmp, ctx->len);
+        memcpy(&ctx->buffer[ctx->len], data, len);
 
-          ctx->len += len;
-        }
-        DBG(r, "append data end");
+        ctx->len += len;
       }
+      DBG(r, "append data end");
     }
 
     if (APR_BUCKET_IS_EOS(b)) {
@@ -791,7 +816,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           if (ctx->len) {
             char *tmp;
 
-            tmp = apr_palloc(r->pool, ctx->len + 1);
+            tmp = apr_palloc(pool, ctx->len + 1);
 
             memset(tmp, 0, ctx->len + 1);
             memcpy(tmp, ctx->buffer, ctx->len);
@@ -876,7 +901,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           if (ctx->len) {
             char *tmp;
 
-            tmp = apr_palloc(r->pool, ctx->len + 1);
+            tmp = apr_palloc(pool, ctx->len + 1);
 
             memset(tmp, 0, ctx->len + 1);
             memcpy(tmp, ctx->buffer, ctx->len);
@@ -890,7 +915,7 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
           }
         }
 
-        contentLength = apr_psprintf(r->pool, "%d", (int)ctx->len);
+        contentLength = apr_psprintf(pool, "%d", (int)ctx->len);
         apr_table_setn(r->headers_out, "Content-Length", contentLength);
         
         if (ctx->len > 0) {
@@ -904,8 +929,6 @@ chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
         else {
           chxj_cookie_unlock(r);
         }
-        f->ctx = NULL;
-
         return rv;
       }
       else {
@@ -971,197 +994,109 @@ s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *cookie)
 }
 
 /**
- * It is the main loop of the input filter. 
+ * It is the main loop of the input filter handler
  *
- * @param f         [i/o] It is a filter.
- * @param bb        [i]   brigade
- * @param mode      [i]   mode
- * @param block     [i]   block
- * @param readbytes [i]   readbyte
  */
-static apr_status_t 
-chxj_input_filter(ap_filter_t         *f, 
-                 apr_bucket_brigade   *bb,
-                 ap_input_mode_t      mode, 
-                 apr_read_type_e      block,
-                 apr_off_t            readbytes)
+static int 
+chxj_input_handler(request_rec *r)
 {
-  request_rec         *r;
-  apr_status_t        rv;
-  conn_rec            *c;
-  apr_bucket          *b;
-  /*--------------------------------------------------------------------------*/
-  /* It is the brigade area for output                                        */
-  /*--------------------------------------------------------------------------*/
-  apr_bucket_brigade  *ibb;            
-  /*--------------------------------------------------------------------------*/
-  /* It is the brigade area for input                                         */
-  /*--------------------------------------------------------------------------*/
-  apr_bucket_brigade  *obb;
-  apr_size_t          len;
-  apr_bucket          *tmp_heap;
-  apr_bucket          *eos;
-  const char          *data;
-  char                *data_bucket;
-  char                *data_brigade;
-  char                *content_type;
-  device_table        *spec = NULL;
-  char                *user_agent = NULL;
   mod_chxj_config     *dconf;
   chxjconvrule_entry  *entryp = NULL;
-  mod_chxj_ctx        *ctx = (mod_chxj_ctx *)f->ctx;
-  int                 eos_flag = 0;
-
-  r = f->r;
-  c = r->connection;
-
-  DBG(r, "start of chxj_input_filter()");
-
-  data_brigade = qs_alloc_zero_byte_string(r->pool);
-
-
-  ibb = apr_brigade_create(r->pool, c->bucket_alloc);
-  obb = apr_brigade_create(r->pool, c->bucket_alloc);
-
-  content_type = (char *)apr_table_get(r->headers_in, "Content-Type");
-  if (content_type 
-      && strncasecmp("multipart/form-data", content_type, 19) == 0) {
-
-    DBG(r, "detect multipart/form-data");
-    ap_remove_input_filter(f);
-
-    return ap_get_brigade(f->next, bb, mode, block, readbytes);
+  device_table        *spec   = NULL;
+  char                *post_data = NULL;
+  apr_size_t          post_data_len = 0;
+  char                *response;
+  char                *user_agent;
+  apr_pool_t          *pool;
+  
+  DBG(r, "start of chxj_input_handler()");
+
+  if (strcasecmp(r->handler, "chxj-input-handler")) {
+    DBG(r, "end chxj_input_handler()");
+    return DECLINED;
+  }
+  apr_pool_create(&pool, r->pool);
+
+  dconf      = chxj_get_module_config(r->per_dir_config, &chxj_module);
+  user_agent = (char*)apr_table_get(r->headers_in, "User-Agent");
+  spec       = chxj_specified_device(r, user_agent);
+  entryp     = chxj_apply_convrule(r, dconf->convrules);
+
+  post_data = apr_pstrdup(pool, "");
+  if (ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK) == OK) {
+    if (ap_should_client_block(r)) {
+      while (post_data_len < CHXJ_POST_MAX) {
+#define BUFSZ (256)
+        char buffer[BUFSZ];
+        int read_bytes = ap_get_client_block(r, buffer, BUFSZ-1);
+        if (read_bytes<=0) {
+          break;
+        }
+        buffer[read_bytes] = '\0';
+        post_data = apr_pstrcat(pool, post_data, buffer, NULL);
+        post_data_len += read_bytes;
+#undef BUFSZ
+      }
+    }
   }
 
-  dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
-  user_agent = (char *)apr_table_get(r->headers_in, "User-Agent");
-
-  if (ctx && ctx->entryp) entryp = ctx->entryp;
-  else                    entryp = chxj_apply_convrule(r, dconf->convrules);
-
-  if (ctx && ctx->spec) spec = ctx->spec;
-  else                  spec = chxj_specified_device(r, user_agent);
-
-  if (!entryp || !(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
-    DBG(r,"EngineOff");
-
-    ap_remove_input_filter(f);
-    return ap_get_brigade(f->next, bb, mode, block, readbytes);
+  /* 
+   * now convert.
+   */
+  if (post_data_len > 0) {
+    post_data = chxj_input_convert(r, (const char**)&post_data, (apr_size_t*)&post_data_len, entryp);
+    DBG(r, "(in:exchange)POSTDATA:[%s]", post_data);
   }
 
-
-  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_Hdml:
-  case CHXJ_SPEC_Jhtml:
-  case CHXJ_SPEC_Jxhtml:
-    break;
-
-  default:
-    ap_remove_input_filter(f);
-    return ap_get_brigade(f->next, bb, mode, block, readbytes);
+  char *url_path;
+  if (dconf->forward_url_base) {
+    url_path = apr_psprintf(pool, "%s%s", dconf->forward_url_base, r->uri);
   }
-
-
-  rv = ap_get_brigade(f->next, ibb, mode, block, readbytes);
-  if (rv != APR_SUCCESS) {
-    DBG(r, "ap_get_brigade() failed");
-    return rv;
+  else {
+    url_path = apr_psprintf(pool, "%s://%s:%d%s", chxj_apache_run_http_scheme(r), ap_get_server_name(r), ap_get_server_port(r), r->uri);
   }
-  if (!ctx) {
-    ctx = apr_palloc(f->c->pool, sizeof(*ctx));
-    memset(ctx, 0, sizeof(*ctx));
-    if ((rv = apr_pool_create(&ctx->pool, f->c->pool)) != APR_SUCCESS) {
-      ERR(r, "failed: new pool create. rv:[%d]", rv);
-      return rv;
-    }
-    ctx->entryp = entryp;
-    ctx->spec = spec;
-    ctx->buffer = apr_palloc(ctx->pool, 1);
-    ctx->buffer[0] = 0;
-    f->ctx = ctx;
+  if (r->args) {
+    url_path = apr_pstrcat(pool, url_path, "?", r->args, NULL);
   }
+  DBG(r, "==> new url_path:[%s]", url_path);
 
-  for (b =  APR_BRIGADE_FIRST(ibb); 
-       b != APR_BRIGADE_SENTINEL(ibb);
-       b =  APR_BUCKET_NEXT(b)) {
-
-    rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
-    if (rv != APR_SUCCESS) {
-      DBG(r, "apr_bucket_read() failed");
-      return rv;
-    }
+  apr_size_t res_len;
+  apr_table_setn(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_IP, r->connection->remote_ip);
+  apr_table_unset(r->headers_in, "Content-Length");
+  apr_table_setn(r->headers_in, "Content-Length", apr_psprintf(pool, "%d", post_data_len));
+  response = chxj_serf_post(r, pool, url_path, post_data, post_data_len, 1, &res_len);
+  DBG(r, "response:[%.*s][%d]", res_len, response, res_len);
 
-    if (data != NULL) {
-      ctx->len += len;
-      data_bucket = apr_palloc(ctx->pool, len+1);
-      memset((void *)data_bucket, 0, len+1);
-      memcpy(data_bucket, data, len);
-      DBG(r, "(in)POSTDATA:[%s]", data_bucket);
-      ctx->buffer = apr_pstrcat(ctx->pool, ctx->buffer, data_bucket, NULL);
-    }
-    if (APR_BUCKET_IS_EOS(b)) {
-      DBG(r, "eos");
-      eos_flag = 1;
-      break;
+  char *chunked;
+  if ((chunked = (char *)apr_table_get(r->headers_out, "Transfer-Encoding")) != NULL) {
+    if (strcasecmp(chunked, "chunked") == 0) {
+      r->chunked = 1;  
     }
   }
-  apr_brigade_cleanup(ibb);
-
-  if (ctx->len == 0) {
-    DBG(r,"data_brigade length is 0");
-    DBG(r,"end of chxj_input_filter()");
-    ap_remove_input_filter(f);
-    return ap_get_brigade(f->next, bb, mode, block, readbytes);
-  }
-
-  if (eos_flag) {
-    len = ctx->len;
-    data_brigade = chxj_input_convert(
-      r, 
-      (const char **)&ctx->buffer, 
-      (apr_size_t *)&len,
-      entryp
-      );
-  
-    if (len > 0) {
-      DBG(r, "(in:convert)POSTDATA:[%s]", data_brigade);
-  
-      obb = apr_brigade_create(r->pool, c->bucket_alloc);
-  
-      tmp_heap = apr_bucket_heap_create(data_brigade, 
-                                        len, 
-                                        NULL, 
-                                        f->c->bucket_alloc);
-      eos = apr_bucket_eos_create(f->c->bucket_alloc);
-  
-      APR_BRIGADE_INSERT_TAIL(obb, tmp_heap);
-      APR_BRIGADE_INSERT_TAIL(obb, eos);
-      APR_BRIGADE_CONCAT(bb, obb);
-    }
-    else {
-      obb = apr_brigade_create(r->pool, c->bucket_alloc);
-      eos = apr_bucket_eos_create(f->c->bucket_alloc);
-      APR_BRIGADE_INSERT_TAIL(obb, eos);
-      APR_BRIGADE_CONCAT(bb, obb);
+  {
+    apr_pool_t *wpool;
+    apr_pool_create(&wpool, r->pool);
+    apr_bucket_brigade *bb;
+    apr_bucket *e;
+    apr_status_t rv;
+    conn_rec *c = r->connection;
+    
+    bb = apr_brigade_create(wpool, c->bucket_alloc);
+    e = apr_bucket_heap_create(response, res_len, NULL, c->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(bb, e);
+    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, "%s:%d failed ap_pass_brigade()", APLOG_MARK);
+      return rv;
     }
-    apr_pool_destroy(ctx->pool);
-    f->ctx = NULL;
-  }
-
-  DBG(r, "end of chxj_input_filter()");
+    apr_brigade_cleanup(bb);
+  }  
 
+  DBG(r, "end of chxj_input_handler()");
   return APR_SUCCESS;
 }
 
-
 static mod_chxj_global_config *
 chxj_global_config_create(apr_pool_t *pool, server_rec *s)
 {
@@ -1220,23 +1155,6 @@ chxj_init_module(apr_pool_t *p,
     SERR(s, "%s:%d end chxj_init_module(). mutex create failure.(%d:%s)",APLOG_MARK, rv,apr_strerror(rv,errstr,255));
     return HTTP_INTERNAL_SERVER_ERROR;
   }
-#if 0
-  conf = (mod_chxj_global_config *)ap_get_module_config(s->module_config, 
-                                                        &chxj_module);
-
-  if (apr_global_mutex_create(&(conf->cookie_db_lock), 
-                              NULL, APR_LOCK_DEFAULT, p) != APR_SUCCESS) {
-    SERR(s, "end  chxj_init_module()");
-    return HTTP_INTERNAL_SERVER_ERROR;
-  }
-
-#ifdef AP_NEED_SET_MUTEX_PERMS
-  if (unixd_set_global_mutex_perms(conf->cookie_db_lock) != APR_SUCCESS) {
-    SERR(s, "end  chxj_init_module()");
-    return HTTP_INTERNAL_SERVER_ERROR;
-  }
-#endif
-#endif
 
   SDBG(s, "end  chxj_init_module()");
 
@@ -1288,26 +1206,67 @@ chxj_insert_filter(request_rec *r)
   device_table        *spec;
   mod_chxj_config     *dconf;
   chxjconvrule_entry  *entryp;
-DBG(r, "start chxj_insert_filter()");
+  mod_chxj_ctx        *ctx;
+  apr_status_t        rv;
+  char                *contentType;
+
+  DBG(r, "start chxj_insert_filter()");
 
   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
-  user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
-  spec = chxj_specified_device(r, user_agent);
-  entryp = NULL;
+  user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
+
+  contentType = (char *)apr_table_get(r->headers_in, "Content-Type");
+  if (contentType
+      && strncasecmp("multipart/form-data", contentType, 19) == 0) {
+    DBG(r, "detect multipart/form-data ==> no target");
+    return;
+  }
 
+  spec = chxj_specified_device(r, user_agent);
   entryp = chxj_apply_convrule(r, dconf->convrules);
   if (!entryp) {
     DBG(r, "end chxj_insert_filter()");
     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, "failed: new pool create. rv:[%d]", rv);
+    return;
+  }
+  ctx->entryp = entryp;
+  ctx->spec   = spec;
+  ctx->buffer = apr_palloc(ctx->pool, 1);
+  ctx->buffer[0] = 0;
 
-  if (entryp->action & CONVRULE_ENGINE_ON_BIT) {
-    ap_add_input_filter("chxj_input_filter",   NULL, r, r->connection);
-    ap_add_output_filter("chxj_output_filter", NULL, r, r->connection);
+  if (!entryp || !(entryp->action & CONVRULE_ENGINE_ON_BIT)) {
+    DBG(r,"EngineOff");
+    return;
   }
 
-DBG(r, "end   chxj_insert_filter()");
+  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_XHtml_Mobile_1_0:
+  case CHXJ_SPEC_Hdml:
+  case CHXJ_SPEC_Jhtml:
+    break;
+
+  default:
+    return;
+  }
+
+
+  if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
+    ap_add_output_filter("chxj_output_filter", ctx, r, r->connection);
+    DBG(r, "added Output Filter");
+  }
+
+  DBG(r, "end   chxj_insert_filter()");
 }
 
 
@@ -1332,16 +1291,12 @@ chxj_register_hooks(apr_pool_t *UNUSED(p))
                       chxj_output_filter, 
                       NULL, 
                       AP_FTYPE_RESOURCE);
-  ap_register_input_filter(
-                      "chxj_input_filter", 
-                      chxj_input_filter, 
-                      NULL, 
-                      AP_FTYPE_RESOURCE);
   ap_hook_insert_filter(chxj_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
   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_translate_name(chxj_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
-  ap_hook_fixups(chxj_headers_fixup, NULL, NULL, APR_HOOK_LAST);
+  ap_hook_fixups(chxj_headers_fixup, NULL, NULL, APR_HOOK_FIRST);
 }
 
 
@@ -1380,6 +1335,8 @@ chxj_create_per_dir_config(apr_pool_t *p, char *arg)
   conf->memcache.host    = NULL;
   conf->memcache.port    = 0;
 #endif
+  conf->forward_url_base = NULL;
+  conf->forward_server_ip = NULL;
 
   if (arg == NULL) {
     conf->dir                  = NULL;
@@ -1422,6 +1379,8 @@ chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
   mrg->emoji            = NULL;
   mrg->emoji_tail       = NULL;
   mrg->new_line_type    = NLTYPE_NIL;
+  mrg->forward_url_base = NULL;
+  mrg->forward_server_ip = NULL;
 
   mrg->dir = apr_pstrdup(p, add->dir);
 
@@ -2339,6 +2298,42 @@ cmd_set_cookie_store_type(
 }
 
 static const char *
+cmd_set_forward_url_base(
+  cmd_parms   *cmd,
+  void        *mconfig,
+  const char  *arg)
+{
+ mod_chxj_config *dconf;
+
+  if (strlen(arg) > 255)
+    return "mod_chxj: ChxjForwardUrlBase is too long.";
+
+  dconf = (mod_chxj_config *)mconfig;
+
+  dconf->forward_url_base = apr_pstrdup(cmd->pool, arg);
+
+  return NULL;
+}
+
+static const char *
+cmd_set_forward_server_ip(
+  cmd_parms   *cmd,
+  void        *mconfig,
+  const char  *arg)
+{
+  mod_chxj_config *dconf;
+
+  if (strlen(arg) > 255)
+    return "mod_chxj: ChxjForwardServerIp is too long.";
+
+  dconf = (mod_chxj_config *)mconfig;
+
+  dconf->forward_server_ip = apr_pstrdup(cmd->pool, arg);
+
+  return NULL;
+}
+
+static const char *
 cmd_set_new_line_type(
   cmd_parms   *UNUSED(cmd), 
   void        *mconfig, 
@@ -2506,6 +2501,18 @@ static const command_rec cmds[] = {
     NULL,
     OR_ALL,
     "HTML new line type (NONE|CRLF|LF|CR). default is CRLF"),
+  AP_INIT_TAKE1(
+    "ChxjForwardUrlBase",
+    cmd_set_forward_url_base,
+    NULL,
+    OR_ALL,
+    "The forward url base(default: {request protocol}://{this server}:{this server port}"),
+  AP_INIT_TAKE1(
+    "ChxjForwardServerIp",
+    cmd_set_forward_server_ip,
+    NULL,
+    OR_ALL,
+    "The forward server ip(default: this server ip)"),
   {NULL}
 };