changeset 239:574bea0142be

nginx-0.0.1-2004-01-26-11:52:49 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 26 Jan 2004 08:52:49 +0000
parents 674f85a4d00f
children 725129fdd524
files auto/make auto/options auto/sources src/core/ngx_hunk.c src/http/modules/ngx_http_gzip_filter.c src/http/modules/ngx_http_ssi_filter.c src/http/ngx_http_parse.c src/http/ngx_http_request.c
diffstat 8 files changed, 331 insertions(+), 213 deletions(-) [+]
line wrap: on
line diff
--- a/auto/make
+++ b/auto/make
@@ -21,6 +21,11 @@ if [ $HTTP_GZIP = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_SRCS"
 fi
 
+if [ $HTTP_SSI = YES ]; then
+    HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SSI_FILTER_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS"
+fi
+
 if [ $HTTP_PROXY = YES ]; then
     HTTP_MODULES="$HTTP_MODULES $HTTP_PROXY_MODULE"
     HTTP_INCS="$HTTP_INCS $HTTP_PROXY_INCS"
--- a/auto/options
+++ b/auto/options
@@ -11,6 +11,7 @@ POLL=YES
 
 HTTP_REWRITE=YES
 HTTP_GZIP=YES
+HTTP_SSI=YES
 HTTP_PROXY=YES
 
 PCRE=NO
@@ -42,6 +43,7 @@ do
         --without-poll_module)           POLL=NO                    ;;
 
         --without-http_rewrite_module)   HTTP_REWRITE=NO            ;;
+        --without-http_ssi_module)       HTTP_SSI=NO                ;;
         --without-http_gzip_module)      HTTP_GZIP=NO               ;;
         --without-http_proxy_module)     HTTP_PROXY=NO              ;;
 
--- a/auto/sources
+++ b/auto/sources
@@ -206,6 +206,10 @@ HTTP_GZIP_UNIX_LIBS=-lz
 HTTP_GZIP_WIN_LIBS=zlib.lib
 
 
+HTTP_SSI_FILTER_MODULE=ngx_http_ssi_filter_module
+HTTP_SSI_SRCS=src/http/modules/ngx_http_ssi_filter.c
+
+
 HTTP_PROXY_MODULE=ngx_http_proxy_module
 HTTP_PROXY_INCS="-I src/http/modules/proxy"
 HTTP_PROXY_DEPS=src/http/modules/proxy/ngx_http_proxy_handler.h
--- a/src/core/ngx_hunk.c
+++ b/src/core/ngx_hunk.c
@@ -98,15 +98,15 @@ int ngx_chain_add_copy(ngx_pool_t *pool,
 void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
                              ngx_chain_t **out, ngx_hunk_tag_t tag)
 {
-    ngx_chain_t  *te;
+    ngx_chain_t  *tl;
 
     if (*busy == NULL) {
         *busy = *out;
 
     } else {
-        for (te = *busy; /* void */ ; te = te->next) {
-            if (te->next == NULL) {
-                te->next = *out;
+        for (tl = *busy; /* void */ ; tl = tl->next) {
+            if (tl->next == NULL) {
+                tl->next = *out;
                 break;
             }
         }
@@ -132,9 +132,9 @@ void ngx_chain_update_chains(ngx_chain_t
 
         (*busy)->hunk->pos = (*busy)->hunk->last = (*busy)->hunk->start;
 
-        te = *busy;
+        tl = *busy;
         *busy = (*busy)->next;
-        te->next = *free;
-        *free = te;
+        tl->next = *free;
+        *free = tl;
     }
 }
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -76,49 +76,49 @@ static ngx_conf_post_handler_pt  ngx_htt
 
 static ngx_command_t  ngx_http_gzip_filter_commands[] = {
 
-    {ngx_string("gzip"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-     ngx_conf_set_flag_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_gzip_conf_t, enable),
-     NULL},
+    { ngx_string("gzip"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, enable),
+      NULL},
 
-    {ngx_string("gzip_buffers"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
-     ngx_conf_set_bufs_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_gzip_conf_t, bufs),
-     NULL},
+    { ngx_string("gzip_buffers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_bufs_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, bufs),
+      NULL},
 
-    {ngx_string("gzip_comp_level"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_num_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_gzip_conf_t, level),
-     &ngx_http_gzip_comp_level_bounds},
+    { ngx_string("gzip_comp_level"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, level),
+      &ngx_http_gzip_comp_level_bounds},
 
-    {ngx_string("gzip_window"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_size_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_gzip_conf_t, wbits),
-     &ngx_http_gzip_set_window_p},
+    { ngx_string("gzip_window"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, wbits),
+      &ngx_http_gzip_set_window_p},
 
-    {ngx_string("gzip_hash"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_size_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_gzip_conf_t, memlevel),
-     &ngx_http_gzip_set_hash_p},
+    { ngx_string("gzip_hash"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, memlevel),
+      &ngx_http_gzip_set_hash_p},
 
-    {ngx_string("gzip_no_buffer"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-     ngx_conf_set_flag_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_gzip_conf_t, no_buffer),
-     NULL},
+    { ngx_string("gzip_no_buffer"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, no_buffer),
+      NULL},
 
-    ngx_null_command
+      ngx_null_command
 };
 
 
--- a/src/http/modules/ngx_http_ssi_filter.c
+++ b/src/http/modules/ngx_http_ssi_filter.c
@@ -7,7 +7,7 @@
 #define NGX_HTTP_SSI_COMMAND_LEN      31
 #define NGX_HTTP_SSI_PARAM_LEN        31
 
-#define NGX_HTTP_SSI_DONE             1
+#define NGX_HTTP_SSI_COPY             1
 #define NGX_HTTP_SSI_INVALID_COMMAND  2
 #define NGX_HTTP_SSI_INVALID_PARAM    3
 #define NGX_HTTP_SSI_INVALID_VALUE    4
@@ -15,175 +15,267 @@
 
 
 typedef struct {
-    ngx_hunk_t       *hunk;
-    ngx_table_elt_t  *param;
-    ngx_str_t         command;
-    ngx_array_t       params;
-    int               state;
-    int               looked;
-    char             *pos;
-    ngx_chain_t      *incoming;
-    int               new_hunk;
-    u_int             value_len;
+    int               enable;
+} ngx_http_ssi_conf_t;
+
+
+typedef struct {
+    ngx_hunk_t        *buf;
+
+    char              *start;
+    char              *last;
+    char              *pos;
+
+    ngx_table_elt_t   *param;
+    ngx_str_t          command;
+    ngx_array_t        params;
+    int                state;
+
+    ngx_chain_t       *in;
+    ngx_chain_t       *current;
+    ngx_chain_t       *out;
+    ngx_chain_t      **last_out;
+    ngx_chain_t       *busy;
+
+    size_t             prev;
+
+    u_int              value_len;
 } ngx_http_ssi_ctx_t;
 
 
+static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
+                                    ngx_http_ssi_ctx_t *ctx);
+static void *ngx_http_ssi_create_conf(ngx_conf_t *cf);
+static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf,
+                                     void *parent, void *child);
 static int ngx_http_ssi_filter_init(ngx_cycle_t *cycle);
 
+
+static ngx_command_t  ngx_http_ssi_filter_commands[] = {
+
+    { ngx_string("ssi"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_ssi_conf_t, enable),
+      NULL },
+
+     ngx_null_command
+};
+
+
     
 static ngx_http_module_t  ngx_http_ssi_filter_module_ctx = {
+    NULL,                                  /* pre conf */
+
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
 
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
 
-    NULL,                                  /* create location configuration */
-    NULL,                                  /* merge location configuration */
+    ngx_http_ssi_create_conf,              /* create location configuration */
+    ngx_http_ssi_merge_conf                /* merge location configuration */
 };  
 
 
 ngx_module_t  ngx_http_ssi_filter_module = {
     NGX_MODULE,
     &ngx_http_ssi_filter_module_ctx,       /* module context */
-    NULL,                                  /* module directives */
+    ngx_http_ssi_filter_commands,          /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     ngx_http_ssi_filter_init,              /* init module */
     NULL                                   /* init child */
 };
 
 
-static int (*next_header_filter) (ngx_http_request_t *r);
-static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+static int (*ngx_http_next_header_filter) (ngx_http_request_t *r);
+static int (*ngx_http_next_body_filter) (ngx_http_request_t *r, ngx_chain_t *in);
 
 
 
 static char comment_string[] = "<!--";
+static char error_string[] = "[an error occurred while processing "
+                             "the directive]";
 
 
 static int ngx_http_ssi_header_filter(ngx_http_request_t *r)
 {
-    ngx_http_ssi_ctx_t  *ctx;
+    ngx_http_ssi_ctx_t   *ctx;
+    ngx_http_ssi_conf_t  *conf;
 
-    /* if () */ {
-        ngx_http_create_ctx(r, ctx, ngx_http_ssi_filter_module,
-                            sizeof(ngx_http_ssi_ctx_t), NGX_ERROR);
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);
+
+    if (!conf->enable) {
+        return ngx_http_next_header_filter(r);
     }
 
-    return NGX_OK;
+    ngx_http_create_ctx(r, ctx, ngx_http_ssi_filter_module,
+                        sizeof(ngx_http_ssi_ctx_t), NGX_ERROR);
+
+    ctx->last_out = &ctx->out;
+    /* STUB: conf */ ctx->value_len = 200;
+
+    r->headers_out.content_length_n = -1;
+    if (r->headers_out.content_length) {
+        r->headers_out.content_length->key.len = 0;
+        r->headers_out.content_length = NULL;
+    }
+
+    r->headers_out.last_modified_time = -1;
+    if (r->headers_out.last_modified) {
+        r->headers_out.last_modified->key.len = 0;
+        r->headers_out.last_modified = NULL;
+    }
+
+    r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY;
+
+    return ngx_http_next_header_filter(r);
 }
 
 
 static int ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
-    int                  rc;
-    ngx_chain_t          chain;
+    ngx_int_t            rc;
+    ngx_hunk_t          *hunk;
+    ngx_chain_t         *cl, *tl;
     ngx_http_ssi_ctx_t  *ctx;
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module);
 
-    if ((ctx == NULL) || (in == NULL && ctx->incoming == NULL)) {
-        return next_body_filter(r, NULL);
+    if (ctx == NULL || (in == NULL && ctx->in == NULL)) {
+        return ngx_http_next_body_filter(r, NULL);
     }
 
-    if (ctx->hunk &&
-        (((ctx->hunk->type & NGX_HUNK_FILE)
-           && (ctx->hunk->file_pos < ctx->hunk->file_last))
-        || ((ctx->hunk->type & NGX_HUNK_IN_MEMORY)
-             && (ctx->hunk->pos < ctx->hunk->last))))
-    {
-        rc = next_body_filter(r, NULL);
+    /* add the incoming hunk to the chain ctx->in */
 
-        if (rc == NGX_ERROR) {
+    if (in) {
+        if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
             return NGX_ERROR;
         }
 
-        if (ctx->hunk->shadow) {
-            if (ctx->hunk->type & NGX_HUNK_FILE) {
-                ctx->hunk->shadow->file_pos = ctx->hunk->file_pos;
-            }
+        if (ctx->current == NULL) {
+            ctx->current = ctx->in;
+        }
+    }
 
-            if (ctx->hunk->type & NGX_HUNK_IN_MEMORY) {
-                ctx->hunk->shadow->pos = ctx->hunk->pos;
-            }
-        }
+    while (ctx->current) {
+        if (ctx->buf == NULL) {
+            ctx->buf = ctx->current->hunk;
+            ctx->current = ctx->current->next;
 
-        if (rc == NGX_AGAIN) {
-            return NGX_AGAIN;
+            ctx->start = ctx->buf->pos;
+            ctx->pos = ctx->buf->pos;
+            ctx->last = ctx->buf->pos;
         }
 
+        while (ctx->pos < ctx->buf->last) {
+            rc = ngx_http_ssi_parse(r, ctx);
 
-    }
+            if (rc == NGX_ERROR) {
+                return rc;
+
+            } else if (rc == NGX_HTTP_SSI_COPY) {
+                if (ctx->prev) {
+
+                    if (!(hunk = ngx_calloc_hunk(r->pool))) {
+                        return NGX_ERROR;
+                    }
+
+                    hunk->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
+                    hunk->pos = comment_string;
+                    hunk->last = comment_string + ctx->prev;
+
+                    ngx_alloc_link_and_set_hunk(cl, hunk, r->pool, NGX_ERROR);
+
+                    *ctx->last_out = cl;
+                    ctx->last_out = &cl->next;
+
+                    ctx->prev = 0;
+                }
+
+                if (ctx->pos == ctx->buf->last) {
+                    ctx->prev = ctx->buf->last - ctx->last;
+                }
+
+                if (!(hunk = ngx_calloc_hunk(r->pool))) {
+                    return NGX_ERROR;
+                }
+
+                hunk->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP|NGX_HUNK_RECYCLED;
+                hunk->pos = ctx->start;
+                hunk->last = ctx->last;
+                hunk->shadow = ctx->buf;
+
+                ngx_alloc_link_and_set_hunk(cl, hunk, r->pool, NGX_ERROR);
+
+                *ctx->last_out = cl;
+                ctx->last_out = &cl->next;
+
+                continue;
 
 #if 0
+            } else if (rc == NGX_HTTP_SSI_INVALID_COMMAND) {
+            } else if (rc == NGX_HTTP_SSI_INVALID_PARAM) {
+            } else if (rc == NGX_HTTP_SSI_INVALID_VALUE) {
+            } else if (rc == NGX_HTTP_SSI_LONG_VALUE) {
+#endif
 
-    add in to ctx->incoming chain
+            } else {
+                if (!(hunk = ngx_calloc_hunk(r->pool))) {
+                    return NGX_ERROR;
+                }
 
-    while (ctx->incoming) {
-        rc == ngx_http_ssi_exec(r, ctx);
+                hunk->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
+                hunk->pos = error_string;
+                hunk->last = error_string + sizeof(error_string) - 1;
+
+                ngx_alloc_link_and_set_hunk(cl, hunk, r->pool, NGX_ERROR);
 
-        if (rc != NGX_ERROR) {
-            return rc;
+                *ctx->last_out = cl;
+                ctx->last_out = &cl->next;
+            }
+        }
+    }
+
+    if (ctx->out) {
+        if (ngx_http_next_body_filter(r, ctx->out) == NGX_ERROR) {
+            return NGX_ERROR;
         }
 
-        ctx->incoming = ctx->incoming->next;
+        if (ctx->busy == NULL) {
+            ctx->busy = ctx->out;
+
+        } else {
+            for (tl = ctx->busy; /* void */ ; tl = tl->next) {
+                if (tl->next == NULL) { 
+                    tl->next = ctx->out;
+                    break;
+                }
+            }
+        }
+    
+        ctx->out = NULL;
+
+        while (ctx->busy) {
+            if (ngx_hunk_size(ctx->busy->hunk) != 0) {
+                break;
+            }
+
+            if (ctx->busy->hunk->shadow) {
+                ctx->busy->hunk->shadow->pos = ctx->busy->hunk->pos;
+            }
+
+            ctx->busy = ctx->busy->next;
+        }
     }
 
-#endif
-
     return NGX_OK;
 }
 
 
 #if 0
 
-
-    while (ctx->incoming) {
-        rc = ngx_http_ssi_parse(r, ctx, ctx->incoming->hunk);
-
-        if (rc == NGX_ERROR) {
-            return rc;
-        }
-
-        if (rc == NGX_OK) {
-            ngx_test_null(temp, ngx_calloc_hunk(r->pool), NGX_ERROR);
-            temp->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
-            temp->pos = comment_string;
-            temp->last = comment_string + looked;
-        }
-
-        if (rc == NGX_HTTP_SSI_DONE) {
-
-
-            - looked
-
-            chain.hunk = ctx->incoming->hunk;
-            chain.next = NULL;
-
-            rc = next_body_filter(r, &chain);
-
-            if (rc != NGX_OK) {
-                ctx->incoming = ctx->incoming->next;
-                return rc;
-            }
-
-        } else if (rc == NGX_HTTP_SSI_INVALID_COMMAND) {
-        } else if (rc == NGX_HTTP_SSI_INVALID_PARAM) {
-        } else if (rc == NGX_HTTP_SSI_INVALID_VALUE) {
-        } else if (rc == NGX_HTTP_SSI_LONG_VALUE) {
-        }
-
-        ctx->incoming = ctx->incoming->next;
-    }
-
-#endif
-
-
-
-
-
-#if 0
-
 static int ngx_http_ssi_copy_opcode(ngx_http_request_t *r,
                                     ngx_http_ssi_ctx_t *ctx, void *data)
 {
@@ -245,14 +337,10 @@ static int ngx_http_ssi_copy_opcode(ngx_
 #endif
 
 
-
-static int ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
-                              ngx_hunk_t *h)
+static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
+                                    ngx_http_ssi_ctx_t *ctx)
 {
-    int           looked;
-    char         *p, ch;
-    ngx_hunk_t   *temp;
-    ngx_chain_t   chain;
+    char  *p, *last, *end, ch;
 
     enum {
         ssi_start_state = 0,
@@ -275,50 +363,35 @@ static int ngx_http_ssi_parse(ngx_http_r
     } state;
 
 
-    looked = ctx->looked;
     state = ctx->state;
+    last = ctx->last;
     p = ctx->pos;
+    end = ctx->buf->last;
 
-    while (p < h->last) {
+    while (p < end) {
         ch = *p++;
 
         switch (state) {
 
         case ssi_start_state:
 
-            if (ctx->new_hunk) {
-
-                if (looked) {
-                    ngx_test_null(temp, ngx_calloc_hunk(r->pool), NGX_ERROR);
-                    temp->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
-                    temp->pos = comment_string;
-                    temp->last = comment_string + looked;
+            last = NULL;
 
-                    chain.hunk = temp;
-                    chain.next = NULL;
-
-                    if (next_body_filter(r, &chain) == NGX_ERROR) {
-                        return NGX_ERROR;
-                    }
-                }
-
-                ctx->new_hunk = 0;
-            }
-
-            /* tight loop */
+            /* a tight loop */
             for ( ;; ) {
 
                 if (ch == '<') {
                     state = ssi_tag_state;
-                    looked = 1;
+                    last = p - 1;
                     break;
                 }
 
-                if (p < h->last) {
+                if (p == end) {
                     ctx->state = ssi_start_state;
-                    ctx->looked = 0;
+                    ctx->last = p;
                     ctx->pos = p;
-                    return NGX_HTTP_SSI_DONE;
+
+                    return NGX_HTTP_SSI_COPY;
                 }
 
                 ch = *p++;
@@ -330,15 +403,14 @@ static int ngx_http_ssi_parse(ngx_http_r
             switch (ch) {
             case '!':
                 state = ssi_comment0_state;
-                looked = 2;
                 break;
 
             case '<':
+                last = p - 1;
                 break;
 
             default:
                 state = ssi_start_state;
-                looked = 0;
                 break;
             }
 
@@ -348,17 +420,15 @@ static int ngx_http_ssi_parse(ngx_http_r
             switch (ch) {
             case '-':
                 state = ssi_comment1_state;
-                looked = 3;
                 break;
 
             case '<':
+                last = p - 1;
                 state = ssi_tag_state;
-                looked = 1;
                 break;
 
             default:
                 state = ssi_start_state;
-                looked = 0;
                 break;
             }
 
@@ -368,17 +438,15 @@ static int ngx_http_ssi_parse(ngx_http_r
             switch (ch) {
             case '-':
                 state = ssi_sharp_state;
-                looked = 4;
                 break;
 
             case '<':
+                last = p - 1;
                 state = ssi_tag_state;
-                looked = 1;
                 break;
 
             default:
                 state = ssi_start_state;
-                looked = 0;
                 break;
             }
 
@@ -387,18 +455,19 @@ static int ngx_http_ssi_parse(ngx_http_r
         case ssi_sharp_state:
             switch (ch) {
             case '#':
-                state = ssi_precommand_state;
-                looked = 0;
-                break;
+                ctx->state = ssi_precommand_state;
+                ctx->last = last;
+                ctx->pos = p;
+
+                return NGX_HTTP_SSI_COPY;
 
             case '<':
+                last = p - 1;
                 state = ssi_tag_state;
-                looked = 1;
                 break;
 
             default:
                 state = ssi_start_state;
-                looked = 0;
                 break;
             }
 
@@ -413,9 +482,12 @@ static int ngx_http_ssi_parse(ngx_http_r
                 break;
 
             default:
-                ngx_test_null(ctx->command.data,
-                              ngx_palloc(r->pool, NGX_HTTP_SSI_COMMAND_LEN + 1),
-                              NGX_ERROR);
+                ctx->command.data = 
+                             ngx_palloc(r->pool, NGX_HTTP_SSI_COMMAND_LEN + 1);
+                if (ctx->command.data == NULL) {
+                    return NGX_ERROR;
+                }
+
                 ctx->command.data[0] = ch;
                 ctx->command.len = 1;
                 state = ssi_command_state;
@@ -462,18 +534,23 @@ static int ngx_http_ssi_parse(ngx_http_r
                 break;
 
             default:
-                ngx_test_null(ctx->param, ngx_push_array(&ctx->params),
-                              NGX_ERROR);
+                if (!(ctx->param = ngx_push_array(&ctx->params))) {
+                    return NGX_ERROR;
+                }
 
-                ngx_test_null(ctx->param->key.data,
-                              ngx_palloc(r->pool, NGX_HTTP_SSI_PARAM_LEN + 1),
-                              NGX_ERROR);
+                ctx->param->key.data =
+                               ngx_palloc(r->pool, NGX_HTTP_SSI_PARAM_LEN + 1);
+                if (ctx->param->key.data == NULL) {
+                    return NGX_ERROR;
+                }
                 ctx->param->key.data[0] = ch;
                 ctx->param->key.len = 1;
 
-                ngx_test_null(ctx->param->value.data,
-                              ngx_palloc(r->pool, ctx->value_len + 1),
-                              NGX_ERROR);
+                ctx->param->value.data =
+                                       ngx_palloc(r->pool, ctx->value_len + 1);
+                if (ctx->param->value.data == NULL) {
+                    return NGX_ERROR;
+                }
                 ctx->param->value.len = 0;
 
                 state = ssi_param_state;
@@ -623,6 +700,7 @@ static int ngx_http_ssi_parse(ngx_http_r
             switch (ch) {
             case '>':
                 ctx->state = ssi_start_state;
+                ctx->start = p;
                 ctx->pos = p;
                 return NGX_OK;
 
@@ -635,19 +713,45 @@ static int ngx_http_ssi_parse(ngx_http_r
     }
 
     ctx->state = state;
-    ctx->looked = looked;
+    ctx->last = last;
     ctx->pos = p;
 
-    return NGX_HTTP_SSI_DONE;
+    return NGX_HTTP_SSI_COPY;
+}
+
+
+static void *ngx_http_ssi_create_conf(ngx_conf_t *cf)
+{
+    ngx_http_ssi_conf_t  *conf;
+
+    if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_conf_t)))) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->enable = NGX_CONF_UNSET;
+
+    return conf;
+}
+
+
+static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf,
+                                     void *parent, void *child)
+{
+    ngx_http_ssi_conf_t *prev = parent;
+    ngx_http_ssi_conf_t *conf = child;
+
+    ngx_conf_merge_value(conf->enable, prev->enable, 0);
+
+    return NGX_CONF_OK;
 }
 
 
 static int ngx_http_ssi_filter_init(ngx_cycle_t *cycle)
 {
-    next_header_filter = ngx_http_top_header_filter;
+    ngx_http_next_header_filter = ngx_http_top_header_filter;
     ngx_http_top_header_filter = ngx_http_ssi_header_filter;
 
-    next_body_filter = ngx_http_top_body_filter;
+    ngx_http_next_body_filter = ngx_http_top_body_filter;
     ngx_http_top_body_filter = ngx_http_ssi_body_filter;
 
     return NGX_OK;
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -463,7 +463,7 @@ ngx_int_t ngx_http_parse_header_line(ngx
                     break;
                 }
 
-                if (ch == '-' || ch == '_' || ch == '~') {
+                if (ch == '-' || ch == '_' || ch == '~' || ch == '.') {
                     break;
                 }
 
@@ -489,7 +489,7 @@ ngx_int_t ngx_http_parse_header_line(ngx
                 break;
             }
 
-            if (ch == '-' || ch == '_' || ch == '~') {
+            if (ch == '-' || ch == '_' || ch == '~' || ch == '.') {
                 break;
             }
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1115,7 +1115,8 @@ static int ngx_http_read_discarded_body(
     ssize_t                    size, n;
     ngx_http_core_loc_conf_t  *clcf;
 
-    ngx_log_debug(r->connection->log, "http read discarded body");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http read discarded body");
 
     if (r->headers_in.content_length_n == 0) {
         return NGX_OK;
@@ -1164,7 +1165,7 @@ static void ngx_http_set_keepalive(ngx_h
     c = r->connection;
     rev = c->read;
 
-    ngx_log_debug(c->log, "set http keepalive handler");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "set http keepalive handler");
 
     ctx = (ngx_http_log_ctx_t *) c->log->data;
     ctx->action = "closing request";
@@ -1201,7 +1202,7 @@ static void ngx_http_set_keepalive(ngx_h
             h->last = h->start + len;
         }
 
-        ngx_log_debug(c->log, "pipelined request");
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "pipelined request");
 
         c->pipeline = 1;
         ctx->action = "reading client pipelined request line";
@@ -1259,7 +1260,7 @@ static void ngx_http_keepalive_handler(n
 
     c = (ngx_connection_t *) rev->data;
 
-    ngx_log_debug(c->log, "http keepalive handler");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http keepalive handler");
 
     if (rev->timedout) {
         ngx_http_close_connection(c);
@@ -1370,7 +1371,8 @@ static void ngx_http_lingering_close_han
     c = rev->data;
     r = c->data;
 
-    ngx_log_debug(c->log, "http lingering close handler");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http lingering close handler");
 
     if (rev->timedout) {
         ngx_http_close_request(r, 0);
@@ -1411,7 +1413,7 @@ static void ngx_http_lingering_close_han
     do {
         n = ngx_recv(c, r->discarded_buffer, clcf->discarded_buffer_size);
 
-        ngx_log_debug(c->log, "lingering read: %d" _ n);
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %d", n);
 
         if (n == NGX_ERROR || n == 0) {
             ngx_http_close_request(r, 0);
@@ -1434,7 +1436,7 @@ static void ngx_http_lingering_close_han
 
 void ngx_http_empty_handler(ngx_event_t *wev)
 {
-    ngx_log_debug(wev->log, "http EMPTY handler");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http empty handler");
 
     return;
 }
@@ -1519,7 +1521,8 @@ void ngx_http_close_request(ngx_http_req
 
 void ngx_http_close_connection(ngx_connection_t *c)
 {
-    ngx_log_debug(c->log, "close connection: %d" _ c->fd);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "close connection: %d", c->fd);
 
     if (c->pool == NULL) {
         ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");