changeset 88:674d333f4296

nginx-0.0.1-2003-05-14-21:13:13 import
author Igor Sysoev <igor@sysoev.ru>
date Wed, 14 May 2003 17:13:13 +0000
parents 5f6d848dcbef
children 29bf798b583f
files src/core/nginx.c src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/http/modules/ngx_http_index_handler.c src/http/modules/ngx_http_static_handler.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_config.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_header_filter.c src/http/ngx_http_special_response.c src/os/unix/ngx_freebsd_init.c src/os/unix/ngx_freebsd_init.h src/os/unix/ngx_freebsd_write_chain.c src/os/unix/ngx_os_init.h
diffstat 16 files changed, 398 insertions(+), 133 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -4,6 +4,7 @@
 #include <ngx_config.h>
 
 #include <ngx_core.h>
+#include <ngx_os_init.h>
 #include <ngx_string.h>
 #include <ngx_errno.h>
 #include <ngx_time.h>
@@ -52,6 +53,10 @@ int main(int argc, char *const *argv)
     /* STUB */
     ngx_log.log_level = NGX_LOG_DEBUG;
 
+    if (ngx_os_init(&ngx_log) == NGX_ERROR) {
+        exit(1);
+    }
+
     ngx_pool = ngx_create_pool(16 * 1024, &ngx_log);
     /* */
 
@@ -67,12 +72,6 @@ int main(int argc, char *const *argv)
 
 #endif
 
-#if 0
-    if (ngx_os_init(&ngx_log) == NGX_ERROR) {
-        exit(1);
-    }
-#endif
-
     ngx_init_array(ngx_listening_sockets, ngx_pool, 10, sizeof(ngx_listen_t),
                    1);
 
@@ -86,7 +85,8 @@ int main(int argc, char *const *argv)
                   ngx_create_array(ngx_pool, 10, sizeof(ngx_str_t)), 1);
     conf.pool = ngx_pool;
     conf.log = &ngx_log;
-    conf.type = NGX_CORE_MODULE_TYPE;
+    conf.module_type = NGX_CORE_MODULE_TYPE;
+    conf.cmd_type = NGX_MAIN_CONF;
 
     conf_file.len = sizeof("nginx.conf") - 1;
     conf_file.data = "nginx.conf";
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -76,11 +76,21 @@ ngx_log_debug(cf->log, "token %d" _ rc);
 
         if (cf->handler) {
 
-            if ((*cf->handler)(cf) == NGX_CONF_ERROR) {
+            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
+            if (rv == NGX_CONF_OK) {
+                continue;
+
+            } else if (rv == NGX_CONF_ERROR) {
+                return NGX_CONF_ERROR;
+
+            } else {
+                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                             "%s %s in %s:%d",
+                             name->data, rv,
+                             cf->conf_file->file.name.data,
+                             cf->conf_file->line);
                 return NGX_CONF_ERROR;
             }
-
-            continue;
         }
 
         name = (ngx_str_t *) cf->args->elts;
@@ -88,7 +98,7 @@ ngx_log_debug(cf->log, "token %d" _ rc);
 
         for (i = 0; !found && ngx_modules[i]; i++) {
             if (ngx_modules[i]->type != NGX_CONF_MODULE_TYPE
-                && ngx_modules[i]->type != cf->type)
+                && ngx_modules[i]->type != cf->module_type)
             {
                 continue;
             }
@@ -107,6 +117,16 @@ ngx_log_debug(cf->log, "token %d" _ rc);
 ngx_log_debug(cf->log, "command '%s'" _ cmd->name.data);
 #endif
 
+                    if ((cmd->type & cf->cmd_type) == 0) {
+                        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                                      "directive \"%s\" in %s:%d "
+                                      "is not allowed here",
+                                      name->data,
+                                      cf->conf_file->file.name.data,
+                                      cf->conf_file->line);
+                        return NGX_CONF_ERROR;
+                    }
+
                     if (!(cmd->type & NGX_CONF_ANY)
                         && ((cmd->type & NGX_CONF_FLAG && cf->args->nelts != 2)
                             || (!(cmd->type & NGX_CONF_FLAG)
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -12,6 +12,12 @@
 #include <ngx_array.h>
 
 
+/*
+ *      AAAA  number of agruments
+ *    TT      command flags
+ *  LL        command location
+ */
+
 #define NGX_CONF_NOARGS      1
 #define NGX_CONF_TAKE1       2
 #define NGX_CONF_TAKE2       4
@@ -20,6 +26,9 @@
 #define NGX_CONF_BLOCK       0x020000
 #define NGX_CONF_FLAG        0x040000
 
+#define NGX_MAIN_CONF        0x1000000
+
+
 
 #define NGX_CONF_UNSET       -1
 
@@ -65,17 +74,24 @@ typedef struct {
 } ngx_conf_file_t;
 
 
+typedef char *(*ngx_conf_handler_pt)(ngx_conf_t *cf,
+                                     ngx_command_t *dummy, char *conf);
+
+
 struct ngx_conf_s {
-    char             *name;
-    ngx_array_t      *args;
+    char                 *name;
+    ngx_array_t          *args;
 
-    ngx_pool_t       *pool;
-    ngx_conf_file_t  *conf_file;
-    ngx_log_t        *log;
+    ngx_pool_t           *pool;
+    ngx_conf_file_t      *conf_file;
+    ngx_log_t            *log;
 
-    void             *ctx;
-    int               type;
-    char           *(*handler)(ngx_conf_t *cf);
+    void                 *ctx;
+    int                   module_type;
+    int                   cmd_type;
+
+    ngx_conf_handler_pt   handler;
+    char                 *handler_conf;
 };
 
 
@@ -84,6 +100,10 @@ struct ngx_conf_s {
         conf = (prev == NGX_CONF_UNSET) ? default : prev;                    \
     }
 
+#define ngx_conf_msec_merge(conf, prev, default)                             \
+    if (conf == NGX_CONF_UNSET) {                                            \
+        conf = (prev == NGX_CONF_UNSET) ? default : prev;                    \
+    }
 
 #define ngx_conf_size_merge(conf, prev, default)                             \
     if (conf == (size_t) NGX_CONF_UNSET) {                                   \
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -157,6 +157,8 @@ ngx_log_error(NGX_LOG_DEBUG, r->connecti
                                + index[i].len;
         }
 
+/* STUB */ r->exten.len = 4; r->exten.data = "html";
+
         return ngx_http_internal_redirect(r, loc);
     }
 
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -6,6 +6,7 @@
 #include <ngx_hunk.h>
 #include <ngx_http.h>
 #include <ngx_http_config.h>
+#include <ngx_http_core_module.h>
 #include <ngx_http_output_filter.h>
 
 
@@ -14,16 +15,22 @@ ngx_http_module_t  ngx_http_static_modul
 
 int ngx_http_static_handler(ngx_http_request_t *r)
 {
-    int                  rc;
+    int                  rc, key, i;
+    ngx_log_e            level;
     ngx_err_t            err;
     ngx_hunk_t          *h;
+    ngx_http_type_t     *type;
     ngx_http_log_ctx_t  *ctx;
+    ngx_http_core_loc_conf_t  *core_lcf; 
+
+    core_lcf = (ngx_http_core_loc_conf_t *)
+                     ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
 
 #if 0
-    ngx_http_event_static_handler_loc_conf_t  *cf;
+    ngx_http_event_static_handler_loc_conf_t  *lcf;
 
-    cf = (ngx_http_event_static_handler_loc_conf_t *)
-             ngx_get_module_loc_conf(r, &ngx_http_event_static_handler_module);
+    lcf = (ngx_http_event_static_handler_loc_conf_t *)
+         ngx_get_module_loc_conf(r, &ngx_http_event_static_handler_module_ctx);
 
 #endif
 
@@ -31,32 +38,34 @@ int ngx_http_static_handler(ngx_http_req
     ctx = r->connection->log->data;
     ctx->action = "sending response";
 
-    if (r->file.fd == NGX_INVALID_FILE)
+    if (r->file.fd == NGX_INVALID_FILE) {
         r->file.fd = ngx_open_file(r->file.name.data, NGX_FILE_RDONLY);
 
-    if (r->file.fd == NGX_INVALID_FILE) {
-        err = ngx_errno;
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
-                      "ngx_http_static_handler: "
-                      ngx_open_file_n " %s failed", r->file.name.data);
+        if (r->file.fd == NGX_INVALID_FILE) {
+            err = ngx_errno;
+
+            if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
+                level = NGX_LOG_ERR;
+                rc = NGX_HTTP_NOT_FOUND;
 
-        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
-            return NGX_HTTP_NOT_FOUND;
+            } else {
+                level = NGX_LOG_CRIT;
+                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
 
-        } else {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            ngx_log_error(level, r->connection->log, ngx_errno,
+                          ngx_open_file_n " %s failed", r->file.name.data);
+            return rc;
         }
     }
 
     if (!r->file.info_valid) {
         if (ngx_stat_fd(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
-                          "ngx_http_static_handler: "
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                           ngx_stat_fd_n " %s failed", r->file.name.data);
 
             if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
-                              "ngx_http_static_handler: "
+                ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                               ngx_close_file_n " %s failed", r->file.name.data);
 
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -65,16 +74,14 @@ int ngx_http_static_handler(ngx_http_req
         r->file.info_valid = 1;
     }
 
-#if !(WIN32) /* it's probably Unix specific */
+#if !(WIN32) /* not regular files is probably Unix specific */
 
     if (!ngx_is_file(r->file.info)) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
-                      "ngx_http_static_handler: "
+        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                       "%s is not regular file", r->file.name.data);
 
         if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
-                          "ngx_http_static_handler: "
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                           ngx_close_file_n " %s failed", r->file.name.data);
 
         return NGX_HTTP_NOT_FOUND;
@@ -93,30 +100,29 @@ int ngx_http_static_handler(ngx_http_req
     r->headers_out.content_type->key.len = 12;
     r->headers_out.content_type->key.data = "Content-Type";
 
-    /* STUB */
     if (r->exten.len) {
-        if (ngx_strcasecmp(r->exten.data, "html") == 0) {
-            r->headers_out.content_type->value.len = 25;
-            r->headers_out.content_type->value.data =
-                                                   "text/html; charset=koi8-r";
-        } else if (ngx_strcasecmp(r->exten.data, "gif") == 0) {
-            r->headers_out.content_type->value.len = 9;
-            r->headers_out.content_type->value.data = "image/gif";
-        } else if (ngx_strcasecmp(r->exten.data, "jpg") == 0) {
-            r->headers_out.content_type->value.len = 10;
-            r->headers_out.content_type->value.data = "image/jpeg";
-        } else if (ngx_strcasecmp(r->exten.data, "pdf") == 0) {
-            r->headers_out.content_type->value.len = 15;
-            r->headers_out.content_type->value.data = "application/pdf";
+        ngx_http_types_hash_key(key, r->exten);
+
+        type = (ngx_http_type_t *) core_lcf->types[key].elts;
+        for (i = 0; i < core_lcf->types[key].nelts; i++) {
+            if (r->exten.len != type[i].exten.len) {
+                continue;
+            }
+
+            if (ngx_strcasecmp(r->exten.data, type[i].exten.data) == 0) {
+                r->headers_out.content_type->value.len = type[i].type.len;
+                r->headers_out.content_type->value.data = type[i].type.data;
+            }
         }
+    }
 
-    } else {
+    if (r->headers_out.content_type->value.len == 0) {
+        /* STUB: default type */
         r->headers_out.content_type->value.len = 25;
         r->headers_out.content_type->value.data = "text/html; charset=koi8-r";
     }
-    /**/
 
-    /* we need to allocate them before header would be sent */
+    /* we need to allocate all before the header would be sent */
     ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
                   NGX_HTTP_INTERNAL_SERVER_ERROR);
 
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -42,7 +42,7 @@ static ngx_str_t  http_name = ngx_string
 static ngx_command_t  ngx_http_commands[] = {
 
     {ngx_string("http"),
-     NGX_CONF_BLOCK|NGX_CONF_NOARGS,
+     NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_http_block,
      0,
      0},
@@ -69,7 +69,8 @@ static char *ngx_http_block(ngx_conf_t *
     ngx_array_t                 in_ports;
     ngx_listen_t               *ls;
     ngx_http_module_t          *module;
-    ngx_http_conf_ctx_t        *ctx, *prev;
+    ngx_conf_t                  prev;
+    ngx_http_conf_ctx_t        *ctx;
     ngx_http_in_port_t         *in_port;
     ngx_http_in_addr_t         *in_addr, *inaddr;
     ngx_http_core_srv_conf_t  **cscf;
@@ -113,12 +114,12 @@ static char *ngx_http_block(ngx_conf_t *
         }
     }
 
-    prev = cf->ctx;
+    prev = *cf;
     cf->ctx = ctx;
-    cf->type = NGX_HTTP_MODULE_TYPE;
-
+    cf->module_type = NGX_HTTP_MODULE_TYPE;
+    cf->cmd_type = NGX_HTTP_MAIN_CONF;
     rv = ngx_conf_parse(cf, NULL);
-    cf->ctx = prev;
+    *cf = prev;
 
     if (rv != NGX_CONF_OK)
         return rv;
@@ -147,7 +148,7 @@ static char *ngx_http_block(ngx_conf_t *
     ngx_init_array(ngx_http_index_handlers,
                    cf->pool, 3, sizeof(ngx_http_handler_pt), NGX_CONF_ERROR);
 
-    /* create lists of ports, addresses and server names */
+    /* create lists of the ports, the addresses and the server names */
 
     ngx_init_array(in_ports, cf->pool, 10, sizeof(ngx_http_in_port_t),
                    NGX_CONF_ERROR);
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -234,7 +234,7 @@ int ngx_http_init(ngx_pool_t *pool, ngx_
 void ngx_http_init_connection(ngx_connection_t *c);
 int ngx_parse_http_request_line(ngx_http_request_t *r);
 int ngx_parse_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h);
-int ngx_http_handler(ngx_http_request_t *r);
+void ngx_http_handler(ngx_http_request_t *r);
 void ngx_http_finalize_request(ngx_http_request_t *r, int error);
 void ngx_http_set_write_handler(ngx_http_request_t *r);
 
--- a/src/http/ngx_http_config.h
+++ b/src/http/ngx_http_config.h
@@ -33,9 +33,9 @@ typedef struct {
 
 #define NGX_HTTP_MODULE           0
 
-#define NGX_HTTP_MAIN_CONF        0x1000000
-#define NGX_HTTP_SRV_CONF         0x2000000
-#define NGX_HTTP_LOC_CONF         0x6000000
+#define NGX_HTTP_MAIN_CONF        0x2000000
+#define NGX_HTTP_SRV_CONF         0x4000000
+#define NGX_HTTP_LOC_CONF         0x8000000
 
 
 #define NGX_HTTP_SRV_CONF_OFFSET  offsetof(ngx_http_conf_ctx_t, srv_conf)
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2,8 +2,8 @@
 #include <ngx_config.h>
 
 #include <ngx_listen.h>
-
 #include <ngx_core.h>
+#include <ngx_string.h>
 #include <ngx_conf_file.h>
 
 #include <ngx_http.h>
@@ -30,6 +30,7 @@ static char *ngx_http_core_merge_loc_con
 static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, char *dummy);
 static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd,
                                                                   char *dummy);
+static char *ngx_types_block(ngx_conf_t *cf, ngx_command_t *cmd, char *dummy);
 static char *ngx_set_listen(ngx_conf_t *cf, ngx_command_t *cmd, char *conf);
 
 
@@ -89,6 +90,12 @@ static ngx_command_t  ngx_http_core_comm
      NGX_HTTP_SRV_CONF_OFFSET,
      0},
 
+    {ngx_string("types"),
+     NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
+     ngx_types_block,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     0},
+
     {ngx_string("root"),
      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_str_slot,
@@ -143,7 +150,7 @@ ngx_module_t  ngx_http_core_module = {
 };
 
 
-int ngx_http_handler(ngx_http_request_t *r)
+void ngx_http_handler(ngx_http_request_t *r)
 {
     int                         rc, a, n, i;
     ngx_http_handler_pt        *h;
@@ -267,16 +274,23 @@ ngx_log_debug(r->connection->log, "trans
             continue;
         }
 
-        if (rc == NGX_OK) {
-            break;
+        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+            ngx_http_finalize_request(r, rc);
+            return;
         }
 
-        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-            return rc;
+        if (rc == NGX_OK) {
+            rc = r->handler(r);
+            if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+                ngx_http_finalize_request(r, rc);
+            }
+            return;
         }
     }
 
-    return r->handler(r);
+    /* TODO: no handlers found ? */
+    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    return;
 }
 
 
@@ -372,10 +386,7 @@ ngx_log_debug(r->connection->log, "HTTP 
                       "ngx_http_core_translate_handler: "
                       ngx_file_type_n " \"%s\" failed", r->file.name.data);
 
-        if (err == NGX_ENOENT) {
-            return NGX_HTTP_NOT_FOUND;
-
-        } else if (err == NGX_ENOTDIR) {
+        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
             return NGX_HTTP_NOT_FOUND;
 
         } else if (err == NGX_EACCES) {
@@ -398,10 +409,7 @@ ngx_log_debug(r->connection->log, "HTTP 
                       "ngx_http_core_handler: "
                       ngx_open_file_n " \"%s\" failed", r->file.name.data);
 
-        if (err == NGX_ENOENT) {
-            return NGX_HTTP_NOT_FOUND;
-
-        } else if (err == NGX_ENOTDIR) {
+        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
             return NGX_HTTP_NOT_FOUND;
 
         } else if (err == NGX_EACCES) {
@@ -547,7 +555,8 @@ int ngx_http_internal_redirect(ngx_http_
     r->uri_end = uri.data + uri.len;
     /**/
 
-    return ngx_http_handler(r);
+    ngx_http_handler(r);
+    return 0;
 }
 
 
@@ -568,7 +577,8 @@ static char *ngx_server_block(ngx_conf_t
     int                         i, j;
     char                       *rv;
     ngx_http_module_t          *module;
-    ngx_http_conf_ctx_t        *ctx, *prev;
+    ngx_conf_t                  pcf;
+    ngx_http_conf_ctx_t        *ctx, *pctx;
     ngx_http_core_srv_conf_t   *scf;
     ngx_http_core_loc_conf_t  **plcf;
 
@@ -606,10 +616,12 @@ static char *ngx_server_block(ngx_conf_t
         }
     }
 
-    prev = cf->ctx;
+    pcf = *cf;
+    pctx = cf->ctx;
     cf->ctx = ctx;
+    cf->cmd_type = NGX_HTTP_SRV_CONF;
     rv = ngx_conf_parse(cf, NULL);
-    cf->ctx = prev;
+    *cf = pcf;
 
     if (rv != NGX_CONF_OK)
         return rv;
@@ -636,19 +648,19 @@ static char *ngx_server_block(ngx_conf_t
         }
 
         if (module->merge_loc_conf) {
-            if (module->merge_loc_conf(cf->pool,
-                                       prev->loc_conf[module->index],
-                                       ctx->loc_conf[module->index])
-                                                           == NGX_CONF_ERROR) {
-                return NGX_CONF_ERROR;
+            rv = module->merge_loc_conf(cf->pool,
+                                        pctx->loc_conf[module->index],
+                                        ctx->loc_conf[module->index]);
+            if (rv != NGX_CONF_OK) {
+                return rv;
             }
 
             for (j = 0; j < scf->locations.nelts; j++) {
-                if (module->merge_loc_conf(cf->pool,
-                                      ctx->loc_conf[module->index],
-                                      plcf[j]->loc_conf[module->index])
-                                                           == NGX_CONF_ERROR) {
-                    return NGX_CONF_ERROR;
+                rv = module->merge_loc_conf(cf->pool,
+                                            ctx->loc_conf[module->index],
+                                            plcf[j]->loc_conf[module->index]);
+                if (rv != NGX_CONF_OK) {
+                    return rv;
                 }
             }
         }
@@ -664,7 +676,8 @@ static char *ngx_location_block(ngx_conf
     char                      *rv;
     ngx_str_t                 *location;
     ngx_http_module_t         *module;
-    ngx_http_conf_ctx_t       *ctx, *prev;
+    ngx_conf_t                 pcf;
+    ngx_http_conf_ctx_t       *ctx, *pctx;
     ngx_http_core_srv_conf_t  *scf;
     ngx_http_core_loc_conf_t  *lcf, **plcf;
 
@@ -672,8 +685,8 @@ static char *ngx_location_block(ngx_conf
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
                   NGX_CONF_ERROR);
 
-    prev = (ngx_http_conf_ctx_t *) cf->ctx;
-    ctx->srv_conf = prev->srv_conf;
+    pctx = (ngx_http_conf_ctx_t *) cf->ctx;
+    ctx->srv_conf = pctx->srv_conf;
 
     ngx_test_null(ctx->loc_conf,
                   ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
@@ -705,9 +718,62 @@ static char *ngx_location_block(ngx_conf
     ngx_test_null(plcf, ngx_push_array(&scf->locations), NGX_CONF_ERROR);
     *plcf = lcf;
 
+    pcf = *cf;
     cf->ctx = ctx;
+    cf->cmd_type = NGX_HTTP_LOC_CONF;
     rv = ngx_conf_parse(cf, NULL);
-    cf->ctx = prev;
+    *cf = pcf;
+
+    return rv;
+}
+
+
+static char *ngx_set_type(ngx_conf_t *cf, ngx_command_t *dummy, char *conf)
+{
+    ngx_http_core_loc_conf_t *lcf = (ngx_http_core_loc_conf_t *) conf;
+
+    int               i, key;
+    ngx_str_t        *args;
+    ngx_http_type_t  *t;
+
+    if (lcf->types == NULL) {
+        ngx_test_null(lcf->types,
+                      ngx_palloc(cf->pool, NGX_HTTP_TYPES_HASH_PRIME
+                                                        * sizeof(ngx_array_t)),
+                      NGX_CONF_ERROR);
+
+        for (i = 0; i < NGX_HTTP_TYPES_HASH_PRIME; i++) {
+            ngx_init_array(lcf->types[i], cf->pool, 5, sizeof(ngx_http_type_t),
+                           NGX_CONF_ERROR);
+        }
+    }
+
+    args = (ngx_str_t *) cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        ngx_http_types_hash_key(key, args[i]);
+
+        ngx_test_null(t, ngx_push_array(&lcf->types[key]), NGX_CONF_ERROR);
+        t->exten.len = args[i].len;
+        t->exten.data = args[i].data;
+        t->type.len = args[0].len;
+        t->type.data = args[0].data;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *ngx_types_block(ngx_conf_t *cf, ngx_command_t *cmd, char *conf)
+{
+    char        *rv;
+    ngx_conf_t   pcf;
+
+    pcf = *cf;
+    cf->handler = ngx_set_type;
+    cf->handler_conf = conf;
+    rv = ngx_conf_parse(cf, NULL);
+    *cf = pcf;
 
     return rv;
 }
@@ -776,29 +842,95 @@ static void *ngx_http_core_create_loc_co
                   ngx_pcalloc(pool, sizeof(ngx_http_core_loc_conf_t)), 
                   NGX_CONF_ERROR);
 
-    lcf->doc_root.len = 4;
-    lcf->doc_root.data = "html";
-
-    lcf->sendfile = 0;
+/*
+    ngx_pcalloc():
 
-    lcf->send_timeout = 10000;
-    lcf->discarded_buffer_size = 1500;
-    lcf->lingering_time = 30000;
-    lcf->lingering_timeout = 5000;
+    lcf->doc_root.len = 0;
+    lcf->doc_root.data = NULL;
+    lcf->types = NULL;
+*/
 
-/*
+    lcf->sendfile = NGX_CONF_UNSET;
+
     lcf->send_timeout = NGX_CONF_UNSET;
-*/
+    lcf->discarded_buffer_size = NGX_CONF_UNSET;
+    lcf->lingering_time = NGX_CONF_UNSET;
+    lcf->lingering_timeout = NGX_CONF_UNSET;
 
     return lcf;
 }
 
+
+static ngx_http_type_t default_types[] = {
+    { ngx_string("html"), ngx_string("text/html") },
+    { ngx_string("gif"), ngx_string("image/gif") },
+    { ngx_string("jpg"), ngx_string("image/jpeg") },
+    { ngx_null_string, ngx_null_string }
+};
+
+
 static char *ngx_http_core_merge_loc_conf(ngx_pool_t *pool,
                                           void *parent, void *child)
 {
+    ngx_http_core_loc_conf_t *prev = (ngx_http_core_loc_conf_t *) parent;
+    ngx_http_core_loc_conf_t *conf = (ngx_http_core_loc_conf_t *) child;
+
+    int               i, key;
+    ngx_http_type_t  *t;
+
+    if (conf->doc_root.len == 0) {
+        if (prev->doc_root.len) {
+           conf->doc_root.len = prev->doc_root.len;
+           conf->doc_root.data = prev->doc_root.data;
+
+        } else {
+           conf->doc_root.len = 4;
+           conf->doc_root.data = "html";
+        }
+    }
+
+    if (conf->types == NULL) {
+        if (prev->types) {
+            conf->types = prev->types;
+
+        } else {
+            ngx_test_null(conf->types,
+                          ngx_palloc(pool, NGX_HTTP_TYPES_HASH_PRIME
+                                                        * sizeof(ngx_array_t)),
+                          NGX_CONF_ERROR);
+
+            for (i = 0; i < NGX_HTTP_TYPES_HASH_PRIME; i++) {
+                ngx_init_array(conf->types[i], pool, 5, sizeof(ngx_http_type_t),
+                               NGX_CONF_ERROR);
+            }
+
+            for (i = 0; default_types[i].exten.len; i++) {
+                ngx_http_types_hash_key(key, default_types[i].exten);
+
+                ngx_test_null(t, ngx_push_array(&conf->types[key]),
+                              NGX_CONF_ERROR);
+                t->exten.len = default_types[i].exten.len;
+                t->exten.data = default_types[i].exten.data;
+                t->type.len = default_types[i].type.len;
+                t->type.data = default_types[i].type.data;
+            }
+        }
+    }
+
+    ngx_conf_merge(conf->sendfile, prev->sendfile, 0);
+
+    ngx_conf_msec_merge(conf->send_timeout, prev->send_timeout, 10000);
+
+    ngx_conf_size_merge(conf->discarded_buffer_size,
+                        prev->discarded_buffer_size, 1500);
+
+    ngx_conf_msec_merge(conf->lingering_time, prev->lingering_time, 30000);
+    ngx_conf_msec_merge(conf->lingering_timeout, prev->lingering_timeout, 5000);
+
     return NGX_CONF_OK;
 }
 
+
 static char *ngx_set_listen(ngx_conf_t *cf, ngx_command_t *cmd, char *conf)
 {
     ngx_str_t          *args;
@@ -817,7 +949,7 @@ static char *ngx_set_listen(ngx_conf_t *
 
     args = (ngx_str_t *) cf->args->elts;
 
-    ls->port = atoi(args[1].data);
+    ls->port = ngx_atoi(args[1].data, args[1].len);
     if (ls->port < 1 || ls->port > 65536) {
         return "port must be between 1 and 65535";
     }
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -50,6 +50,21 @@ typedef struct {
 } ngx_http_server_name_t;
 
 
+#define NGX_HTTP_TYPES_HASH_PRIME  13
+
+#define ngx_http_types_hash_key(key, ext)                                   \
+        {                                                                   \
+            int n;                                                          \
+            for (key = 0, n = 0; n < ext.len; n++) {                        \
+                key += ext.data[n];                                         \
+            }                                                               \
+            key %= NGX_HTTP_TYPES_HASH_PRIME;                               \
+        }
+
+typedef struct {
+    ngx_str_t  exten;
+    ngx_str_t  type;
+} ngx_http_type_t;
 
 
 typedef struct {
@@ -61,6 +76,8 @@ typedef struct {
 
     ngx_str_t   doc_root;                /* root */
 
+    ngx_array_t  *types;
+
     int         sendfile;                /* sendfile */
     time_t      send_timeout;            /* send_timeout */
     size_t      send_lowat;              /* send_lowa */
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -65,7 +65,7 @@ static ngx_str_t http_codes[] = {
     ngx_null_string,  /* 412 */
     ngx_string("413 Request Entity Too Large"),
     ngx_null_string,  /* "414 Request-URI Too Large" but we never send it
-                         because we treat such requests as HTTP/0.9 requests
+                         because we treat such requests as the HTTP/0.9 requests
                          and send only the body without the header */
     ngx_null_string,  /* 415 */
     ngx_string("416 Requested Range Not Satisfiable"),
@@ -124,16 +124,20 @@ static int ngx_http_header_filter(ngx_ht
 
     } else {
         if (r->headers_out.status < NGX_HTTP_MOVED_PERMANENTLY) {
+            /* 2XX */
             status = r->headers_out.status - NGX_HTTP_OK;
 
         } else if (r->headers_out.status < NGX_HTTP_BAD_REQUEST) {
+            /* 3XX */
             status = r->headers_out.status - NGX_HTTP_MOVED_PERMANENTLY + 1;
             r->header_only = 1;
 
         } else if (r->headers_out.status < NGX_HTTP_INTERNAL_SERVER_ERROR) {
+            /* 4XX */
             status = r->headers_out.status - NGX_HTTP_BAD_REQUEST + 1 + 4;
 
         } else {
+            /* 5XX */
             status = r->headers_out.status
                                  - NGX_HTTP_INTERNAL_SERVER_ERROR + 1 + 4 + 17;
         }
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -120,6 +120,7 @@ int ngx_http_special_response_handler(ng
     r->headers_out.status = error;
 
     if (error < NGX_HTTP_BAD_REQUEST) {
+        /* 3XX */
         err = error - NGX_HTTP_MOVED_PERMANENTLY;
 
     } else {
@@ -133,9 +134,11 @@ int ngx_http_special_response_handler(ng
         r->headers_out.content_type->value.data = "text/html";
 
         if (error < NGX_HTTP_INTERNAL_SERVER_ERROR) {
+            /* 4XX */
             err = error - NGX_HTTP_BAD_REQUEST + 3;
 
         } else {
+            /* 5XX */
             err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 3 + 17;
         }
     }
@@ -149,6 +152,15 @@ int ngx_http_special_response_handler(ng
         }
     }
 
+    if (r->lingering_close == 1) {
+        switch (error) {
+            case NGX_HTTP_BAD_REQUEST:
+            case NGX_HTTP_REQUEST_URI_TOO_LARGE:
+            case NGX_HTTP_INTERNAL_SERVER_ERROR:
+                r->lingering_close = 0;
+        }
+    }
+
     if (error_pages[err].len == 0) {
         r->headers_out.content_length = -1;
     } else {
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -2,19 +2,41 @@
 #include <ngx_freebsd_init.h>
 
 
-int freebsd_kern_osreldate;
-int freebsd_hw_ncpu;
-
-int freebsd_sendfile_nbytes_bug;
+char ngx_freebsd_kern_ostype[20];
+char ngx_freebsd_kern_osrelease[20];
+int ngx_freebsd_kern_osreldate;
+int ngx_freebsd_hw_ncpu;
+int ngx_freebsd_net_inet_tcp_sendspace;
+int ngx_freebsd_sendfile_nbytes_bug;
 
 
 int ngx_os_init(ngx_log_t *log)
 {
     size_t  size;
 
+    size = 20;
+    if (sysctlbyname("kern.ostype",
+                     ngx_freebsd_kern_ostype, &size, NULL, 0) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno,
+                      "sysctlbyname(kern.ostype) failed");
+        return NGX_ERROR;
+    }
+
+    size = 20;
+    if (sysctlbyname("kern.osrelease",
+                     ngx_freebsd_kern_osrelease, &size, NULL, 0) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno,
+                      "sysctlbyname(kern.osrelease) failed");
+        return NGX_ERROR;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %s %s",
+                  ngx_freebsd_kern_ostype, ngx_freebsd_kern_osrelease);
+
+
     size = 4;
     if (sysctlbyname("kern.osreldate",
-                     &freebsd_kern_osreldate, &size, NULL, 0) == -1) {
+                     &ngx_freebsd_kern_osreldate, &size, NULL, 0) == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, errno,
                       "sysctlbyname(kern.osreldate) failed");
         return NGX_ERROR;
@@ -22,7 +44,7 @@ int ngx_os_init(ngx_log_t *log)
 
     ngx_log_error(NGX_LOG_INFO, log, 0,
                   "kern.osreldate: %d, built on %d",
-                  freebsd_kern_osreldate, __FreeBSD_version);
+                  ngx_freebsd_kern_osreldate, __FreeBSD_version);
 
 
 #if HAVE_FREEBSD_SENDFILE
@@ -42,12 +64,12 @@ int ngx_os_init(ngx_log_t *log)
     || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039
 
     /* a new syscall without the bug */
-    freebsd_sendfile_nbytes_bug = 0;
+    ngx_freebsd_sendfile_nbytes_bug = 0;
 
 #else
 
     /* an old syscall that can have the bug */
-    freebsd_sendfile_nbytes_bug = 1;
+    ngx_freebsd_sendfile_nbytes_bug = 1;
 
 #endif
 
@@ -55,13 +77,27 @@ int ngx_os_init(ngx_log_t *log)
 
 
     size = 4;
-    if (sysctlbyname("hw.ncpu", &freebsd_hw_ncpu, &size, NULL, 0) == -1) {
+    if (sysctlbyname("hw.ncpu", &ngx_freebsd_hw_ncpu, &size, NULL, 0) == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, errno,
                       "sysctlbyname(hw.ncpu) failed");
         return NGX_ERROR;
     }
 
-    ngx_log_error(NGX_LOG_INFO, log, 0, "hw.ncpu: %d", freebsd_hw_ncpu);
+    ngx_log_error(NGX_LOG_INFO, log, 0, "hw.ncpu: %d", ngx_freebsd_hw_ncpu);
+
+
+    size = 4;
+    if (sysctlbyname("net.inet.tcp.sendspace",
+                     &ngx_freebsd_net_inet_tcp_sendspace,
+                     &size, NULL, 0) == -1)
+    {
+        ngx_log_error(NGX_LOG_ALERT, log, errno,
+                      "sysctlbyname(net.inet.tcp.sendspace) failed");
+        return NGX_ERROR;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, log, 0, "net.inet.tcp.sendspace: %d",
+                  ngx_freebsd_net_inet_tcp_sendspace);
 
     return NGX_OK;
 }
--- a/src/os/unix/ngx_freebsd_init.h
+++ b/src/os/unix/ngx_freebsd_init.h
@@ -1,5 +1,5 @@
-#ifndef _NGX_OS_INIT_H_INCLUDED_
-#define _NGX_OS_INIT_H_INCLUDED_
+#ifndef _NGX_FREEBSD_INIT_H_INCLUDED_
+#define _NGX_FREEBSD_INIT_H_INCLUDED_
 
 
 #include <ngx_config.h>
@@ -11,8 +11,10 @@
 int ngx_os_init(ngx_log_t *log);
 
 
-extern int freebsd_kern_osreldate;
-extern int freebsd_hw_ncpu;
+extern int ngx_freebsd_kern_osreldate;
+extern int ngx_freebsd_hw_ncpu;
+extern int ngx_freebsd_net_inet_tcp_sendspace;
+extern int ngx_freebsd_sendfile_nbytes_bug;
 
 
-#endif /* _NGX_OS_INIT_H_INCLUDED_ */
+#endif /* _NGX_FREEBSD_INIT_H_INCLUDED_ */
--- a/src/os/unix/ngx_freebsd_write_chain.c
+++ b/src/os/unix/ngx_freebsd_write_chain.c
@@ -9,6 +9,7 @@
 #include <ngx_connection.h>
 #include <ngx_sendv.h>
 #include <ngx_sendfile.h>
+#include <ngx_freebsd_init.h>
 
 
 ngx_chain_t *ngx_freebsd_write_chain(ngx_connection_t *c, ngx_chain_t *in)
@@ -50,9 +51,9 @@ ngx_chain_t *ngx_freebsd_write_chain(ngx
                 prev = ce->hunk->last;
             }
 
-#if (HAVE_FREEBSD_SENDFILE_NBYTES_BUG)
-            hsize += ce->hunk->last - ce->hunk->pos;
-#endif
+            if (ngx_freebsd_sendfile_nbytes_bug) {
+                hsize += ce->hunk->last - ce->hunk->pos;
+            }
             ce = ce->next;
         }
     }
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_os_init.h
@@ -0,0 +1,12 @@
+#ifndef _NGX_OS_INIT_H_INCLUDED_
+#define _NGX_OS_INIT_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_log.h>
+
+
+int ngx_os_init(ngx_log_t *log);
+
+
+#endif /* _NGX_OS_INIT_H_INCLUDED_ */