changeset 208:0b67be7d4489

nginx-0.0.1-2003-12-08-23:48:12 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 08 Dec 2003 20:48:12 +0000
parents 6e0fef527732
children e1c815be05ae
files src/core/ngx_array.h src/core/ngx_core.h src/core/ngx_crc.h src/core/ngx_file.c src/core/ngx_garbage_collector.h src/core/ngx_hunk.c src/core/ngx_log.c src/core/ngx_log.h src/core/ngx_regex.c src/core/ngx_times.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_thread.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_header.c src/http/ngx_http_core_module.c src/http/ngx_http_header_filter.c src/http/ngx_http_log_handler.c src/http/ngx_http_log_handler.h src/os/unix/ngx_freebsd_rfork_thread.c
diffstat 20 files changed, 349 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_array.h
+++ b/src/core/ngx_array.h
@@ -6,13 +6,13 @@
 #include <ngx_core.h>
 
 
-typedef struct {
+struct ngx_array_s {
     void       *elts;
     int         nelts;
     size_t      size;
     int         nalloc;
     ngx_pool_t *pool;
-} ngx_array_t;
+};
 
 
 ngx_array_t *ngx_create_array(ngx_pool_t *p, int n, size_t size);
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -6,6 +6,7 @@ typedef struct ngx_module_s      ngx_mod
 typedef struct ngx_conf_s        ngx_conf_t;
 typedef struct ngx_cycle_s       ngx_cycle_t;
 typedef struct ngx_log_s         ngx_log_t;
+typedef struct ngx_array_s       ngx_array_t;
 typedef struct ngx_open_file_s   ngx_open_file_t;
 typedef struct ngx_command_s     ngx_command_t;
 
--- a/src/core/ngx_crc.h
+++ b/src/core/ngx_crc.h
@@ -7,7 +7,7 @@
 ngx_inline static uint32_t ngx_crc(char *data, size_t len)
 {
     uint32_t  sum;
-    
+
     for (sum = 0; len; len--) {
         /*
          * gcc 2.95.2 x86 and icc 7.1.006 compile that operator
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -14,7 +14,7 @@ int ngx_write_chain_to_temp_file(ngx_tem
     if (tf->file.fd == NGX_INVALID_FILE) {
         rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
                                   tf->persistent);
-    
+
         if (rc == NGX_ERROR || rc == NGX_AGAIN) {
             return rc;
         }
--- a/src/core/ngx_garbage_collector.h
+++ b/src/core/ngx_garbage_collector.h
@@ -17,7 +17,7 @@ struct ngx_gc_s {
 };
 
 
-int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name, 
+int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
                                        ngx_dir_t *dir);
 
 
--- a/src/core/ngx_hunk.c
+++ b/src/core/ngx_hunk.c
@@ -108,7 +108,7 @@ void ngx_chain_update_chains(ngx_chain_t
             if (te->next == NULL) {
                 te->next = *out;
                 break;
-            }   
+            }
         }
     }
 
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -22,7 +22,7 @@ static ngx_str_t  errlog_name = ngx_stri
 static ngx_command_t  ngx_errlog_commands[] = {
 
     {ngx_string("error_log"),
-     NGX_MAIN_CONF|NGX_CONF_TAKE12,
+     NGX_MAIN_CONF|NGX_CONF_1MORE,
      ngx_set_error_log,
      0,
      0,
@@ -51,6 +51,11 @@ static const char *err_levels[] = {
     "warn", "notice", "info", "debug"
 };
 
+static const char *debug_levels[] = {
+    "debug", "debug_alloc", "debug_event", "debug_http"
+};
+
+
 #if (HAVE_VARIADIC_MACROS)
 void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
                         const char *fmt, ...)
@@ -262,9 +267,18 @@ ngx_log_t *ngx_log_init_errlog()
 }
 
 
-ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_str_t *name)
+ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args)
 {
     ngx_log_t  *log;
+    ngx_str_t  *value, *name;
+
+    if (args) {
+        value = args->elts;
+        name = &value[1];
+
+    } else {
+        name = NULL;
+    }
 
     ngx_test_null(log, ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)), NULL);
     ngx_test_null(log->file, ngx_conf_open_file(cycle, name), NULL);
@@ -279,7 +293,7 @@ ngx_log_t *ngx_log_create_errlog(ngx_cyc
 
 static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_int_t   i;
+    ngx_int_t   i, n, d;
     ngx_str_t  *value;
 
     value = cf->args->elts;
@@ -291,16 +305,43 @@ static char *ngx_set_error_log(ngx_conf_
         cf->cycle->log->file->name = value[1];
     }
 
-    if (cf->args->nelts == 3) {
-        for (i = 1; i <= /* STUB ??? */ NGX_LOG_DEBUG; i++) {
-            if (ngx_strcmp(value[2].data, err_levels[i]) == 0) {
-                cf->cycle->log->log_level = i;
-                break;
+    for (i = 2; i < cf->args->nelts; i++) {
+
+        for (n = 1; n < NGX_LOG_DEBUG; n++) {
+            if (ngx_strcmp(value[i].data, err_levels[n]) == 0) {
+
+                if (cf->cycle->log->log_level != 0) {
+                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                       "invalid log level \"%s\"",
+                                       value[i].data);
+                    return NGX_CONF_ERROR;
+                }
+
+                cf->cycle->log->log_level = n;
+                continue;
             }
         }
-        if (i > NGX_LOG_DEBUG) {
+
+        d = NGX_LOG_DEBUG_FIRST;
+        for (n = 0; n < /* STUB */ 3; n++) {
+            if (ngx_strcmp(value[i].data, debug_levels[n]) == 0) {
+                if (cf->cycle->log->log_level & ~NGX_LOG_DEBUG_ALL) {
+                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                       "invalid log level \"%s\"",
+                                       value[i].data);
+                    return NGX_CONF_ERROR;
+                }
+
+                cf->cycle->log->log_level |= d;
+                d <<= 1;
+                continue;
+            }
+        }
+
+
+        if (cf->cycle->log->log_level == 0) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid log level \"%s\"", value[2].data);
+                               "invalid log level \"%s\"", value[i].data);
             return NGX_CONF_ERROR;
         }
     }
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -16,7 +16,13 @@
 #define NGX_LOG_INFO            7
 #define NGX_LOG_DEBUG           8
 
-#define NGX_LOG_DEBUG_HTTP   0x80
+#define NGX_LOG_DEBUG_ALLOC     0x10
+#define NGX_LOG_DEBUG_EVENT     0x20
+#define NGX_LOG_DEBUG_HTTP      0x40
+
+#define NGX_LOG_DEBUG_FIRST     NGX_LOG_DEBUG
+#define NGX_LOG_DEBUG_LAST      NGX_LOG_DEBUG_HTTP
+#define NGX_LOG_DEBUG_ALL       0xfffffff8
 
 
 /*
@@ -212,7 +218,7 @@ void ngx_assert_core(ngx_log_t *log, con
 #define ngx_log_copy_log(new, old)    ngx_memcpy(new, old, sizeof(ngx_log_t))
 
 ngx_log_t *ngx_log_init_errlog();
-ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_str_t *name);
+ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args);
 
 
 extern ngx_module_t  ngx_errlog_module;
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -30,7 +30,7 @@ ngx_regex_t *ngx_regex_compile(ngx_str_t
     re = pcre_compile(pattern->data, (int) options, &errstr, &erroff, NULL);
 
     if (re == NULL) {
-       if ((size_t) erroff == pattern->len) { 
+       if ((size_t) erroff == pattern->len) {
            ngx_snprintf(err->data, err->len - 1,
                         "pcre_compile() failed: %s in \"%s\"",
                         errstr, pattern->data);
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -116,11 +116,11 @@ void ngx_gmtime(time_t t, ngx_tm_t *tp)
     t %= 86400;
     hour = t / 3600;
     t %= 3600;
-    min = t / 60; 
+    min = t / 60;
     sec = t % 60;
 
     /* the algorithm based on Gauss's formula */
-    
+
     days = days - (31 + 28) + 719527;
 
     year = days * 400 / (365 * 400 + 100 - 4 + 1);
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -36,9 +36,11 @@ struct ngx_event_s {
     /*
      * The inline of "ngx_rbtree_t  rbtree;".
      *
-     * It allows to pack rbtree_color and variuos event bit flags into
-     * the single int.  We also use "unsigned char" and then "usigned short"
-     * because otherwise MSVC 6.0 uses an additional int for bit flags.
+     * It allows to pack the rbtree_color and the variuos event bit flags into
+     * the single "int".  We also use "unsigned char" and then "usigned short"
+     * because otherwise MSVC 6.0 uses an additional "int" for the bit flags.
+     * We use "char rbtree_color" instead of "unsigned int rbtree_color:1"
+     * because it preserves the bits order on the big endian platforms.
      */
 
     ngx_int_t        rbtree_key;
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -199,7 +199,14 @@ void ngx_event_accept(ngx_event_t *ev)
         rev->log = log;
         wev->log = log;
 
-        /* TODO: x86: MT: lock xadd, MP: lock xadd, shared */
+        /*
+         * In the multithreaded model the connection counter is updated by
+         * the main thread only that accept()s connections.
+         *
+         * TODO: MP: - allocated in a shared memory
+         *           - atomic increment (x86: lock xadd)
+         *             or protection by critical section or mutex
+         */
         c->number = ngx_connection_counter++;
 
         ngx_log_debug(ev->log, "accept: %d, %d" _ s _ c->number);
new file mode 100644
--- /dev/null
+++ b/src/event/ngx_event_thread.c
@@ -0,0 +1,129 @@
+
+volitile int  ngx_last_posted_event;
+
+
+typedef struct {
+    ngx_tid_t   tid;
+    ngx_cv_t    cv;
+} ngx_thread_data_t;
+
+static ngx_thread_data_t  *threead_data;
+
+
+
+
+
+{
+
+    err = ngx_thread_cond_wait(ngx_thread_data_cv, ngx_thread_data_mutex);
+
+    tid = ngx_thread_self();
+
+    for (i = 0; i < thread_data_n; i++) {
+        if (thread_data[i].tid == tid) {
+            cv = thread_data[i].cv;
+            break;
+        }
+    }
+
+    if (i == thread_data_n) {
+        error
+        return
+    }
+
+
+    for ( ;; ) {
+
+        err = ngx_thread_cond_wait(cv, ngx_posted_events_mutex);
+        if (err) {
+            ngx_log_error(NGX_ALERT, log, err,
+                          ngx_thread_cond_wait_n " failed, thread is exiting");
+            return;
+        }
+
+        for ( ;; ) {
+            ev = NULL;
+
+            for (i = ngx_last_posted_event; i > 0; i--) {
+                ev = ngx_posted_events[i];
+
+                if (ev == NULL) {
+                    continue;
+                }
+
+                err = ngx_thread_mutex_trylock(ev->mutex);
+
+                if (err == 0) {
+                    ngx_posted_events[i] = NULL;
+
+                    while (ngx_posted_events[ngx_last_posted_event] == NULL) {
+                        ngx_last_posted_event--;
+                    }
+
+                    break;
+                }
+
+                if (err == NGX_EBUSY) {
+                    ev = NULL;
+                    continue;
+                }
+
+                ngx_log_error(NGX_ALERT, log, err,
+                              ngx_thread_mutex_unlock_n " failed,
+                              thread is exiting");
+
+                ngx_worker_thread_error();
+                return;
+            }
+
+            err = ngx_thread_mutex_unlock(ngx_posted_events_mutex);
+            if (err) {
+                ngx_log_error(NGX_ALERT, log, err,
+                              ngx_thread_mutex_unlock_n
+                              " failed, thread exiting");
+                return;
+            }
+
+            if (ev == NULL) {
+                break;
+            }
+
+            ngx_event_handle_event(ev);
+
+            err = ngx_thread_mutex_unlock(ev->mutex);
+            if (err) {
+                ngx_log_error(NGX_ALERT, log, err,
+                              ngx_thread_mutex_unlock_n
+                              " failed, thread exiting");
+
+                ngx_worker_thread_error();
+                return;
+            }
+
+            err = ngx_thread_mutex_lock(ngx_posted_events_mutex);
+            if (err) {
+                ngx_log_error(NGX_ALERT, log, err,
+                              ngx_thread_mutex_lock_n
+                              " failed, thread exiting");
+                return;
+            }
+        }
+
+        if (restart) {
+            ngx_log_error(NGX_INFO, log, 0, "thread is exiting");
+            return;
+        }
+    }
+}
+
+ngx_worker_thread_error()
+{
+    ngx_err_t  err;
+
+    err = ngx_thread_mutex_unlock(ngx_posted_events_mutex);
+    if (err) {
+        ngx_log_error(NGX_ALERT, log, err,
+                      ngx_thread_mutex_unlock_n
+                      " failed, thread exiting");
+    }
+}
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -384,7 +384,7 @@ void ngx_http_proxy_busy_lock_handler(ng
     ngx_connection_t      *c;
     ngx_http_request_t    *r;
     ngx_http_proxy_ctx_t  *p;
-    
+
     ngx_log_debug(rev->log, "busy lock");
 
     c = rev->data;
@@ -594,7 +594,7 @@ static char *ngx_http_proxy_log_proxy_st
         *buf++ = '-';
 
     } else {
-        buf += ngx_snprintf(buf, NGX_TIME_LEN, TIME_T_FMT, p->state->expired);
+        buf += ngx_snprintf(buf, NGX_TIME_T_LEN, TIME_T_FMT, p->state->expired);
     }
 
     *buf++ = '/';
@@ -603,7 +603,7 @@ static char *ngx_http_proxy_log_proxy_st
         *buf++ = '-';
 
     } else {
-        buf += ngx_snprintf(buf, NGX_TIME_LEN, TIME_T_FMT, p->state->bl_time);
+        buf += ngx_snprintf(buf, NGX_TIME_T_LEN, TIME_T_FMT, p->state->bl_time);
     }
 
     *buf++ = '/';
@@ -635,7 +635,7 @@ static char *ngx_http_proxy_log_proxy_st
         *buf++ = '-';
 
     } else {
-        buf += ngx_snprintf(buf, NGX_TIME_LEN, TIME_T_FMT, p->state->expires);
+        buf += ngx_snprintf(buf, NGX_TIME_T_LEN, TIME_T_FMT, p->state->expires);
     }
 
     *buf++ = ' ';
--- a/src/http/modules/proxy/ngx_http_proxy_header.c
+++ b/src/http/modules/proxy/ngx_http_proxy_header.c
@@ -23,7 +23,7 @@ int ngx_http_proxy_copy_header(ngx_http_
         if (&h[i] == headers_in->connection) {
             continue;
         }
-    
+
         if (p->accel) {
             if (&h[i] == headers_in->date
                 || &h[i] == headers_in->accept_ranges) {
@@ -34,12 +34,12 @@ int ngx_http_proxy_copy_header(ngx_http_
                 && !p->lcf->pass_x_accel_expires)
             {
                 continue;
-            } 
-    
+            }
+
             if (&h[i] == headers_in->server && !p->lcf->pass_server) {
                 continue;
-            } 
-    
+            }
+
             if (&h[i] == headers_in->location) {
                 if (ngx_http_proxy_rewrite_location_header(p, &h[i])
                                                                   == NGX_ERROR)
@@ -48,9 +48,9 @@ int ngx_http_proxy_copy_header(ngx_http_
                 }
 
                 continue;
-            } 
+            }
         }
-    
+
         if (&h[i] == headers_in->content_type) {
             r->headers_out.content_type = &h[i];
             r->headers_out.content_type->key.len = 0;
@@ -61,9 +61,9 @@ int ngx_http_proxy_copy_header(ngx_http_
         {
             return NGX_ERROR;
         }
-    
+
         *ho = h[i];
-    
+
         /*
          * ngx_http_header_filter() does not handle specially
          * the following headers if they are set:
@@ -122,7 +122,7 @@ static int ngx_http_proxy_rewrite_locati
     r->headers_out.location->value.len = uc->location->len
                                          + (loc->value.len - uc->url.len) + 1;
     r->headers_out.location->value.data =
-                       ngx_palloc(r->pool, r->headers_out.location->value.len); 
+                       ngx_palloc(r->pool, r->headers_out.location->value.len);
 
     if (r->headers_out.location->value.data == NULL) {
         return NGX_ERROR;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1354,12 +1354,14 @@ static char *ngx_set_error_log(ngx_conf_
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
+#if 0
     ngx_str_t  *value;
 
     value = cf->args->elts;
+#endif
 
     ngx_test_null(lcf->err_log,
-                  ngx_log_create_errlog(cf->cycle, &value[1]),
+                  ngx_log_create_errlog(cf->cycle, cf->args),
                   NGX_CONF_ERROR);
 
     return NGX_CONF_OK;
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -158,8 +158,7 @@ static int ngx_http_header_filter(ngx_ht
 
     if (r->headers_out.content_length == NULL) {
         if (r->headers_out.content_length_n >= 0) {
-                                           /* 2^64 */
-            len += sizeof("Content-Length: 18446744073709551616" CRLF) - 1;
+            len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
         }
     }
 
@@ -238,49 +237,18 @@ static int ngx_http_header_filter(ngx_ht
 
     if (!(r->headers_out.date && r->headers_out.date->key.len)) {
         h->last = ngx_cpymem(h->last, "Date: ", sizeof("Date: ") - 1);
-#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
-        p = h->last;
-#endif
         h->last = ngx_cpymem(h->last, ngx_cached_http_time.data,
                              ngx_cached_http_time.len);
 
-#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
-        r->headers_out.date = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
-        if (r->headers_out.date == NULL) {
-            return NGX_ERROR;
-        }
-
-        r->headers_out.date->key.len = 0;
-        r->headers_out.date->key.data = NULL;
-        r->headers_out.date->value.len = h->last - p;
-        r->headers_out.date->value.data = p;
-#endif
-
         *(h->last++) = CR; *(h->last++) = LF;
     }
 
     if (r->headers_out.content_length == NULL) {
         if (r->headers_out.content_length_n >= 0) {
-#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
-            p = h->last + sizeof("Content-Length: ") - 1;
-#endif
-            h->last += ngx_snprintf(h->last,        /* 2^64 */
-                            sizeof("Content-Length: 18446744073709551616" CRLF),
-                            "Content-Length: " OFF_T_FMT CRLF,
-                            r->headers_out.content_length_n);
-
-#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
-            r->headers_out.content_length = ngx_palloc(r->pool,
-                                                       sizeof(ngx_table_elt_t));
-            if (r->headers_out.content_length == NULL) {
-                return NGX_ERROR;
-            }
-
-            r->headers_out.content_length->key.len = 0;
-            r->headers_out.content_length->key.data = NULL;
-            r->headers_out.content_length->value.len = h->last - p - 2;
-            r->headers_out.content_length->value.data = p;
-#endif
+            h->last += ngx_snprintf(h->last,
+                                sizeof("Content-Length: ") + NGX_OFF_T_LEN + 2,
+                                "Content-Length: " OFF_T_FMT CRLF,
+                                r->headers_out.content_length_n);
         }
     }
 
@@ -332,24 +300,8 @@ static int ngx_http_header_filter(ngx_ht
     {
         h->last = ngx_cpymem(h->last, "Last-Modified: ",
                              sizeof("Last-Modified: ") - 1);
-#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
-        p = h->last;
-#endif
         h->last += ngx_http_time(h->last, r->headers_out.last_modified_time);
 
-#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
-        r->headers_out.last_modified = ngx_palloc(r->pool,
-                                                  sizeof(ngx_table_elt_t));
-        if (r->headers_out.last_modified == NULL) {
-            return NGX_ERROR;
-        }
-
-        r->headers_out.last_modified->key.len = 0;
-        r->headers_out.last_modified->key.data = NULL;
-        r->headers_out.last_modified->value.len = h->last - p;
-        r->headers_out.last_modified->value.data = p;
-#endif
-
         *(h->last++) = CR; *(h->last++) = LF;
     }
 
--- a/src/http/ngx_http_log_handler.c
+++ b/src/http/ngx_http_log_handler.c
@@ -21,10 +21,15 @@ static char *ngx_http_log_length(ngx_htt
                                  uintptr_t data);
 static char *ngx_http_log_header_in(ngx_http_request_t *r, char *buf,
                                     uintptr_t data);
+static char *ngx_http_log_connection_header_out(ngx_http_request_t *r,
+                                                char *buf, uintptr_t data);
+static char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r,
+                                                       char *buf,
+                                                       uintptr_t data);
 static char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, char *buf,
                                             uintptr_t data);
 static char *ngx_http_log_header_out(ngx_http_request_t *r, char *buf,
-                                    uintptr_t data);
+                                     uintptr_t data);
 static char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, char *buf,
                                              uintptr_t data);
 
@@ -104,7 +109,7 @@ ngx_http_log_op_name_t ngx_http_log_fmt_
                           ngx_http_log_time },
     { ngx_string("request"), 0, ngx_http_log_request },
     { ngx_string("status"), 3, ngx_http_log_status },
-    { ngx_string("length"), NGX_OFF_LEN, ngx_http_log_length },
+    { ngx_string("length"), NGX_OFF_T_LEN, ngx_http_log_length },
     { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in },
     { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out },
     { ngx_null_string, 0, NULL }
@@ -212,18 +217,6 @@ static char *ngx_http_log_time(ngx_http_
 {
     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
                       ngx_cached_http_log_time.len);
-
-#if 0
-    ngx_tm_t  tm;
-
-    ngx_localtime(&tm);
-
-    return buf + ngx_snprintf(buf, sizeof("28/Sep/1970:12:00:00"),
-                              "%02d/%s/%d:%02d:%02d:%02d",
-                              tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
-                              tm.ngx_tm_year,
-                              tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
-#endif
 }
 
 
@@ -250,7 +243,7 @@ static char *ngx_http_log_status(ngx_htt
 static char *ngx_http_log_length(ngx_http_request_t *r, char *buf,
                                  uintptr_t data)
 {
-    return buf + ngx_snprintf(buf, NGX_OFF_LEN + 1, OFF_T_FMT,
+    return buf + ngx_snprintf(buf, NGX_OFF_T_LEN + 1, OFF_T_FMT,
                               r->connection->sent);
 }
 
@@ -357,11 +350,36 @@ static char *ngx_http_log_header_out(ngx
     ngx_http_log_op_t  *op;
 
     if (r) {
+
+        /* run-time execution */
+
+        if (r->http_version < NGX_HTTP_VERSION_10) {
+            if (buf) {
+                *buf = '-';
+            }
+
+            return buf + 1;
+        }
+
         h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data);
 
         if (h == NULL) {
 
-            /* no header */
+            /*
+             * No header pointer was found.
+             * However, some headers: "Date", "Server", "Content-Length",
+             * and "Last-Modified" have a special handling in the header filter
+             * but we do not set up their pointers in the filter because
+             * they are too seldom needed to be logged.
+             */
+
+            if (data == offsetof(ngx_http_headers_out_t, date)) {
+                if (buf == NULL) {
+                    return (char *) ngx_cached_http_time.len;
+                }
+                return ngx_cpymem(buf, ngx_cached_http_time.data,
+                                  ngx_cached_http_time.len);
+            }
 
             if (data == offsetof(ngx_http_headers_out_t, server)) {
                 if (buf == NULL) {
@@ -370,6 +388,36 @@ static char *ngx_http_log_header_out(ngx
                 return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1);
             }
 
+            if (data == offsetof(ngx_http_headers_out_t, content_length)) {
+                if (r->headers_out.content_length_n == -1) {
+                    if (buf) {
+                        *buf = '-';
+                    }
+                    return buf + 1;
+                }
+
+                if (buf == NULL) {
+                    return (char *) NGX_OFF_T_LEN;
+                }
+                return buf + ngx_snprintf(buf, NGX_OFF_T_LEN + 2, OFF_T_FMT,
+                                          r->headers_out.content_length_n);
+            }
+
+            if (data == offsetof(ngx_http_headers_out_t, last_modified)) {
+                if (r->headers_out.last_modified_time == -1) {
+                    if (buf) {
+                        *buf = '-';
+                    }
+                    return buf + 1;
+                }
+
+                if (buf == NULL) {
+                    return (char *) sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
+                }
+                return buf + ngx_http_time(buf,
+                                           r->headers_out.last_modified_time);
+            }
+
             if (buf) {
                 *buf = '-';
             }
@@ -406,6 +454,21 @@ static char *ngx_http_log_header_out(ngx
         }
     }
 
+    if (s->len == sizeof("Connection") - 1
+        && ngx_strncasecmp(s->data, "Connection", s->len) == 0)
+    {
+        op->op = ngx_http_log_connection_header_out;
+        op->data = NULL;
+        return NULL;
+    }
+
+    if (s->len == sizeof("Transfer-Encoding") - 1
+        && ngx_strncasecmp(s->data, "Transfer-Encoding", s->len) == 0) {
+        op->op = ngx_http_log_transfer_encoding_header_out;
+        op->data = NULL;
+        return NULL;
+    }
+
     op->op = ngx_http_log_unknown_header_out;
     op->data = (uintptr_t) s;
 
@@ -413,6 +476,41 @@ static char *ngx_http_log_header_out(ngx
 }
 
 
+static char *ngx_http_log_connection_header_out(ngx_http_request_t *r,
+                                                char *buf, uintptr_t data)
+{
+    if (buf == NULL) {
+        return (char *) ((r->keepalive) ? sizeof("keep-alive") - 1:
+                                          sizeof("close") - 1);
+    }
+
+    if (r->keepalive) {
+        return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1);
+
+    } else {
+        return ngx_cpymem(buf, "close", sizeof("close") - 1);
+    }
+}
+
+
+static char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r,
+                                                       char *buf,
+                                                       uintptr_t data)
+{
+    if (buf == NULL) {
+        return (char *) ((r->chunked) ? sizeof("chunked") - 1 : 1);
+    }
+
+    if (r->chunked) {
+        return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1);
+    }
+
+    *buf = '-';
+
+    return buf + 1;
+}
+
+
 static char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, char *buf,
                                              uintptr_t data)
 {
--- a/src/http/ngx_http_log_handler.h
+++ b/src/http/ngx_http_log_handler.h
@@ -17,8 +17,8 @@ typedef char *(*ngx_http_log_op_pt) (ngx
 
 /* STUB */
 #define NGX_INT32_LEN      sizeof("-2147483648") - 1
-#define NGX_TIME_LEN       sizeof("-2147483648") - 1
-#define NGX_OFF_LEN        sizeof("-9223372036854775808") - 1
+#define NGX_TIME_T_LEN     sizeof("-2147483648") - 1
+#define NGX_OFF_T_LEN      sizeof("-9223372036854775808") - 1
 
 
 typedef struct {
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -1,9 +1,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_process.h>
-#include <ngx_log.h>
-#include <ngx_alloc.h>
 
 
 extern int   __isthreaded;