nginx-0.3.10-RELEASE import

    *) Change: the "valid_referers" directive and the "$invalid_referer"
       variable were moved to the new ngx_http_referer_module from the
       ngx_http_rewrite_module.

    *) Change: the "$apache_bytes_sent" variable name was changed to
       "$body_bytes_sent".

    *) Feature: the "$sent_http_..." variables.

    *) Feature: the "if" directive supports the "=" and "!=" operations.

    *) Feature: the "proxy_pass" directive supports the HTTPS protocol.

    *) Feature: the "proxy_set_body" directive.

    *) Feature: the "post_action" directive.

    *) Feature: the ngx_http_empty_gif_module.

    *) Feature: the "worker_cpu_affinity" directive for Linux.

    *) Bugfix: the "rewrite" directive did not unescape URI part in
       redirect, now it is unescaped except the %00-%25 and %7F-%FF
       characters.

    *) Bugfix: nginx could not be built by the icc 9.0 compiler.

    *) Bugfix: if the SSI was enabled for zero size static file, then the
       chunked response was encoded incorrectly.
diff --git a/src/os/unix/ngx_aio_read.c b/src/os/unix/ngx_aio_read.c
index 2a66eb8..206f0ef 100644
--- a/src/os/unix/ngx_aio_read.c
+++ b/src/os/unix/ngx_aio_read.c
@@ -22,7 +22,8 @@
  *                               timeout, aio_cancel(), aio_error()
  */
 
-ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size)
+ssize_t
+ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size)
 {
     int           n;
     ngx_event_t  *rev;
diff --git a/src/os/unix/ngx_aio_read_chain.c b/src/os/unix/ngx_aio_read_chain.c
index c6f9aea..da85ed9 100644
--- a/src/os/unix/ngx_aio_read_chain.c
+++ b/src/os/unix/ngx_aio_read_chain.c
@@ -10,7 +10,8 @@
 #include <ngx_aio.h>
 
 
-ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl)
+ssize_t
+ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl)
 {
     int           n;
     u_char       *buf, *prev;
diff --git a/src/os/unix/ngx_aio_write.c b/src/os/unix/ngx_aio_write.c
index 1d8c1aa..57e751d 100644
--- a/src/os/unix/ngx_aio_write.c
+++ b/src/os/unix/ngx_aio_write.c
@@ -22,7 +22,8 @@
  *                               timeout, aio_cancel(), aio_error()
  */
 
-ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size)
+ssize_t
+ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size)
 {
     int           n;
     ngx_event_t  *wev;
diff --git a/src/os/unix/ngx_aio_write_chain.c b/src/os/unix/ngx_aio_write_chain.c
index b90f8bb..e3d6631 100644
--- a/src/os/unix/ngx_aio_write_chain.c
+++ b/src/os/unix/ngx_aio_write_chain.c
@@ -10,8 +10,8 @@
 #include <ngx_aio.h>
 
 
-ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in,
-                                 off_t limit)
+ngx_chain_t *
+ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
 {
     u_char       *buf, *prev;
     off_t         send, sent;
diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c
index c7f1293..62ea7cc 100644
--- a/src/os/unix/ngx_channel.c
+++ b/src/os/unix/ngx_channel.c
@@ -11,7 +11,7 @@
 
 ngx_int_t
 ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
-    ngx_log_t *log) 
+    ngx_log_t *log)
 {
     ssize_t             n;
     ngx_err_t           err;
@@ -34,7 +34,7 @@
         msg.msg_controllen = sizeof(cmsg);
 
         cmsg.cm.cmsg_len = sizeof(cmsg);
-        cmsg.cm.cmsg_level = SOL_SOCKET; 
+        cmsg.cm.cmsg_level = SOL_SOCKET;
         cmsg.cm.cmsg_type = SCM_RIGHTS;
         *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
     }
@@ -80,7 +80,7 @@
 
 ngx_int_t
 ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
-{   
+{
     ssize_t             n;
     ngx_err_t           err;
     struct iovec        iov[1];
@@ -165,7 +165,7 @@
 
     if (ch->command == NGX_CMD_OPEN_CHANNEL) {
         if (msg.msg_accrightslen != sizeof(int)) {
-            ngx_log_error(NGX_LOG_ALERT, log, 0, 
+            ngx_log_error(NGX_LOG_ALERT, log, 0,
                           "recvmsg() returned no ancillary data");
             return NGX_ERROR;
         }
@@ -219,8 +219,8 @@
             ngx_free_connection(c);
             return NGX_ERROR;
         }
-    
-    } else { 
+
+    } else {
         if (ngx_add_event(ev, event, 0) == NGX_ERROR) {
             ngx_free_connection(c);
             return NGX_ERROR;
diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c
index 67cad1a..b5a807b 100644
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -148,7 +148,7 @@
 
     vec.elts = iovs;
     vec.size = sizeof(struct iovec);
-    vec.nalloc = NGX_IOVS; 
+    vec.nalloc = NGX_IOVS;
     vec.pool = pool;
 
     do {
diff --git a/src/os/unix/ngx_freebsd_rfork_thread.h b/src/os/unix/ngx_freebsd_rfork_thread.h
index 20957a5..6b5c8a9 100644
--- a/src/os/unix/ngx_freebsd_rfork_thread.h
+++ b/src/os/unix/ngx_freebsd_rfork_thread.h
@@ -100,7 +100,7 @@
 
 static void *
 ngx_thread_get_tls(ngx_tls_key_t key)
-{   
+{
     if (key >= NGX_THREAD_KEYS_MAX) {
         return NULL;
     }
diff --git a/src/os/unix/ngx_gcc_atomic_amd64.h b/src/os/unix/ngx_gcc_atomic_amd64.h
index 374e3b8..2183e73 100644
--- a/src/os/unix/ngx_gcc_atomic_amd64.h
+++ b/src/os/unix/ngx_gcc_atomic_amd64.h
@@ -32,7 +32,7 @@
 static ngx_inline ngx_atomic_uint_t
 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
     ngx_atomic_uint_t set)
-{   
+{
     ngx_atomic_uint_t  res;
 
     __asm__ volatile (
diff --git a/src/os/unix/ngx_gcc_atomic_ppc.h b/src/os/unix/ngx_gcc_atomic_ppc.h
index 58b24c3..a6bbb39 100644
--- a/src/os/unix/ngx_gcc_atomic_ppc.h
+++ b/src/os/unix/ngx_gcc_atomic_ppc.h
@@ -10,7 +10,7 @@
  * this branch is unlikely to be taken.
  * The "1b" means the nearest backward label "1" and the "1f" means
  * the nearest forward label "1".
- *  
+ *
  * The "b" means that the base registers can be used only, i.e.
  * any register except r0.  The r0 register always has a zero value and
  * could not be used in "addi  r0, r0, 1".
diff --git a/src/os/unix/ngx_gcc_atomic_sparc64.h b/src/os/unix/ngx_gcc_atomic_sparc64.h
index 8314318..fc6bace 100644
--- a/src/os/unix/ngx_gcc_atomic_sparc64.h
+++ b/src/os/unix/ngx_gcc_atomic_sparc64.h
@@ -40,7 +40,7 @@
     : "+r" (set) : "r" (lock), "r" (old) : "memory");
 
     return (set == old);
-}   
+}
 
 
 static ngx_inline ngx_atomic_int_t
diff --git a/src/os/unix/ngx_gcc_atomic_x86.h b/src/os/unix/ngx_gcc_atomic_x86.h
index 3053e72..b458032 100644
--- a/src/os/unix/ngx_gcc_atomic_x86.h
+++ b/src/os/unix/ngx_gcc_atomic_x86.h
@@ -22,7 +22,7 @@
  *         eax = [m];
  *     }
  *
- * 
+ *
  * The "q" is any of the %eax, %ebx, %ecx, or %edx registers.
  * The "=a" and "a" are the %eax register.  Although we can return result
  * in any register, we use %eax because it is used in cmpxchgl anyway.
diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c
index 9ddac67..115b991 100644
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -158,7 +158,7 @@
                      * and without the TCP_CORK
                      */
 
-                    if (err != NGX_EINTR) { 
+                    if (err != NGX_EINTR) {
                         wev->error = 1;
                         ngx_connection_error(c, err,
                                              "setsockopt(TCP_NODELAY) failed");
@@ -183,7 +183,7 @@
                      * we continue a processing without the TCP_CORK
                      */
 
-                    if (err != NGX_EINTR) { 
+                    if (err != NGX_EINTR) {
                         wev->error = 1;
                         ngx_connection_error(c, err,
                                              ngx_tcp_nopush_n " failed");
@@ -192,7 +192,7 @@
 
                 } else {
                     c->tcp_nopush = NGX_TCP_NOPUSH_SET;
-    
+
                     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
                                    "tcp_nopush");
                 }
@@ -281,7 +281,7 @@
                 } else {
                     wev->error = 1;
                     ngx_connection_error(c, err, "writev() failed");
-                    return NGX_CHAIN_ERROR; 
+                    return NGX_CHAIN_ERROR;
                 }
             }
 
@@ -334,10 +334,10 @@
         }
 
         if (eintr) {
-            continue; 
+            continue;
         }
 
-        if (!complete) { 
+        if (!complete) {
             wev->ready = 0;
             return cl;
         }
diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c
index 4a2b581..4968de5 100644
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -49,7 +49,7 @@
                       "getrlimit(RLIMIT_NOFILE) failed)");
         return NGX_ERROR;
     }
-    
+
     ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur;
 
 #if (NGX_HAVE_INHERITED_NONBLOCK)
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index ddc10c8..7adcc6e 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -58,7 +58,8 @@
 #endif
 
 
-u_char  master_process[] = "master process";
+u_long         cpu_affinity;
+static u_char  master_process[] = "master process";
 
 
 void
@@ -312,14 +313,17 @@
 static void
 ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
 {
-    ngx_int_t      i;
+    ngx_int_t      i, s;
     ngx_channel_t  ch;
 
     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
 
     ch.command = NGX_CMD_OPEN_CHANNEL;
 
-    while (n--) {
+    for (i = 0; i < n; i++) {
+
+        cpu_affinity = ngx_get_cpu_affinity(i);
+
         ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,
                           "worker process", type);
 
@@ -327,11 +331,11 @@
         ch.slot = ngx_process_slot;
         ch.fd = ngx_processes[ngx_process_slot].channel[0];
 
-        for (i = 0; i < ngx_last_process; i++) {
+        for (s = 0; s < ngx_last_process; s++) {
 
-            if (i == ngx_process_slot
-                || ngx_processes[i].pid == -1
-                || ngx_processes[i].channel[0] == -1)
+            if (s == ngx_process_slot
+                || ngx_processes[s].pid == -1
+                || ngx_processes[s].channel[0] == -1)
             {
                 continue;
             }
@@ -339,12 +343,12 @@
             ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                           "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
                           ch.slot, ch.pid, ch.fd,
-                          i, ngx_processes[i].pid,
-                          ngx_processes[i].channel[0]);
+                          s, ngx_processes[s].pid,
+                          ngx_processes[s].channel[0]);
 
             /* TODO: NGX_AGAIN */
 
-            ngx_write_channel(ngx_processes[i].channel[0],
+            ngx_write_channel(ngx_processes[s].channel[0],
                               &ch, sizeof(ngx_channel_t), cycle->log);
         }
     }
@@ -817,6 +821,20 @@
         }
     }
 
+#if (NGX_HAVE_SCHED_SETAFFINITY)
+
+    if (cpu_affinity) {
+        ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
+                      "sched_setaffinity(0x%08Xl)", cpu_affinity);
+
+        if (sched_setaffinity(0, 32, (cpu_set_t *) &cpu_affinity) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          "sched_setaffinity(0x%08Xl) failed", cpu_affinity);
+        }
+    }
+
+#endif
+
 #if (NGX_HAVE_PR_SET_DUMPABLE)
 
     /* allow coredump after setuid() in Linux 2.4.x */
@@ -849,7 +867,7 @@
     /*
      * disable deleting previous events for the listening sockets because
      * in the worker processes there are no events at all at this point
-     */ 
+     */
     ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
         ls[i].previous = NULL;
diff --git a/src/os/unix/ngx_pthread_thread.c b/src/os/unix/ngx_pthread_thread.c
index c91e65d..676c760 100644
--- a/src/os/unix/ngx_pthread_thread.c
+++ b/src/os/unix/ngx_pthread_thread.c
@@ -45,7 +45,7 @@
 
 ngx_int_t
 ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle)
-{   
+{
     int  err;
 
     max_threads = n;
@@ -82,7 +82,7 @@
     if (m == NULL) {
         return NULL;
     }
-    
+
     m->log = log;
 
     err = pthread_mutex_init(&m->mutex, NULL);
@@ -202,7 +202,7 @@
     if (cv == NULL) {
         return NULL;
     }
-    
+
     cv->log = log;
 
     err = pthread_cond_init(&cv->cond, NULL);
diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c
index 08b5cc0..9de4cd5 100644
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -24,7 +24,7 @@
     ngx_event_t   *rev;
     struct iovec  *iov, iovs[NGX_IOVS];
 
-    rev = c->read; 
+    rev = c->read;
 
     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c
index 4345385..5347cd9 100644
--- a/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -190,7 +190,7 @@
         for (cl = in; cl; cl = cl->next) {
 
             if (ngx_buf_special(cl->buf)) {
-                continue; 
+                continue;
             }
 
             if (sent == 0) {
diff --git a/src/os/unix/ngx_sunpro_atomic_sparc64.h b/src/os/unix/ngx_sunpro_atomic_sparc64.h
index 6b4ce84..691e94e 100644
--- a/src/os/unix/ngx_sunpro_atomic_sparc64.h
+++ b/src/os/unix/ngx_sunpro_atomic_sparc64.h
@@ -27,7 +27,7 @@
     NGX_CASA(set, old, lock);
 
     return (set == old);
-}   
+}
 
 
 static ngx_inline ngx_atomic_int_t
diff --git a/src/os/unix/ngx_sunpro_sparc64.il b/src/os/unix/ngx_sunpro_sparc64.il
index d2708ed..2dd8320 100644
--- a/src/os/unix/ngx_sunpro_sparc64.il
+++ b/src/os/unix/ngx_sunpro_sparc64.il
@@ -5,7 +5,7 @@
 
 /  "casa   [%o2] 0x80, %o1, %o0"  and
 /  "casxa  [%o2] 0x80, %o1, %o0"  do the following:
-/ 
+/
 /       if ([%o2] == %o1) {
 /           swap(%o0, [%o2]);
 /       } else {
diff --git a/src/os/win32/nginx.rc b/src/os/win32/nginx.rc
index fee869a..8aa6ff5 100644
--- a/src/os/win32/nginx.rc
+++ b/src/os/win32/nginx.rc
@@ -6,7 +6,7 @@
 nginx   icon  discardable  "src\\os\\win32\\nginx.ico"
 tray    icon  discardable  "src\\os\\win32\\nginx_tray.ico"
 
-nginx   menu  discardable 
+nginx   menu  discardable
 begin
     popup "&nginx"
     begin
diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c
index 78b7f95..dcffca7 100644
--- a/src/os/win32/ngx_files.c
+++ b/src/os/win32/ngx_files.c
@@ -281,11 +281,11 @@
     ngx_cpystrn(name->data + name->len, NGX_DIR_MASK, NGX_DIR_MASK_LEN + 1);
 
     dir->dir = FindFirstFile((const char *) name->data, &dir->fd);
-    
+
     if (dir->dir == INVALID_HANDLE_VALUE) {
-        return NGX_ERROR; 
+        return NGX_ERROR;
     }
-    
+
     dir->valid_info = 1;
     dir->ready = 1;
 
@@ -305,7 +305,7 @@
         return NGX_ERROR;
     }
 
-    return NGX_OK; 
+    return NGX_OK;
 }
 
 
diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c
index be363e2..05fa73c 100644
--- a/src/os/win32/ngx_process_cycle.c
+++ b/src/os/win32/ngx_process_cycle.c
@@ -85,7 +85,7 @@
 
     if (ngx_init_threads(ngx_threads_n,
                                    ccf->thread_stack_size, cycle) == NGX_ERROR)
-    {     
+    {
         /* fatal */
         exit(2);
     }
@@ -134,7 +134,7 @@
     }
 
 
-    wc.style = CS_HREDRAW|CS_VREDRAW; 
+    wc.style = CS_HREDRAW|CS_VREDRAW;
     wc.lpfnWndProc = ngx_window_procedure;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
diff --git a/src/os/win32/ngx_wsarecv_chain.c b/src/os/win32/ngx_wsarecv_chain.c
index c22a08d..4bdac42 100644
--- a/src/os/win32/ngx_wsarecv_chain.c
+++ b/src/os/win32/ngx_wsarecv_chain.c
@@ -9,7 +9,7 @@
 #include <ngx_event.h>
 
 
-#define NGX_WSABUFS  8 
+#define NGX_WSABUFS  8
 
 
 ssize_t
@@ -34,7 +34,7 @@
     vec.elts = wsabufs;
     vec.nelts = 0;
     vec.size = sizeof(WSABUF);
-    vec.nalloc = NGX_WSABUFS; 
+    vec.nalloc = NGX_WSABUFS;
     vec.pool = c->pool;
 
     /* coalesce the neighbouring bufs */
diff --git a/src/os/win32/ngx_wsasend_chain.c b/src/os/win32/ngx_wsasend_chain.c
index bc3b015..03c5aa9 100644
--- a/src/os/win32/ngx_wsasend_chain.c
+++ b/src/os/win32/ngx_wsasend_chain.c
@@ -48,7 +48,7 @@
 
     vec.elts = wsabufs;
     vec.size = sizeof(WSABUF);
-    vec.nalloc = NGX_WSABUFS; 
+    vec.nalloc = NGX_WSABUFS;
     vec.pool = c->pool;
 
     for ( ;; ) {
@@ -187,7 +187,7 @@
         if (limit == 0 || limit > NGX_MAX_UINT32_VALUE - ngx_pagesize) {
             limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
         }
- 
+
         /*
          * WSABUFs must be 4-byte aligned otherwise
          * WSASend() will return undocumented WSAEINVAL error.
@@ -196,13 +196,13 @@
         vec.elts = wsabufs;
         vec.nelts = 0;
         vec.size = sizeof(WSABUF);
-        vec.nalloc = NGX_WSABUFS; 
+        vec.nalloc = NGX_WSABUFS;
         vec.pool = c->pool;
 
         send = 0;
         prev = NULL;
         wsabuf = NULL;
- 
+
         /* create the WSABUF and coalesce the neighbouring bufs */
 
         for (cl = in;
@@ -238,7 +238,7 @@
 
         ovlp = (LPWSAOVERLAPPED) &c->write->ovlp;
         ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
- 
+
         rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, ovlp, NULL);
 
         wev->complete = 0;
@@ -257,7 +257,7 @@
                 ngx_connection_error(c, err, "WSASend() failed");
                 return NGX_CHAIN_ERROR;
             }
- 
+
         } else if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
 
              /*
@@ -293,7 +293,7 @@
                                        &sent, 0, NULL) == 0) {
                 ngx_connection_error(c, ngx_socket_errno,
                                "WSASend() or WSAGetOverlappedResult() failed");
-    
+
                 return NGX_CHAIN_ERROR;
             }
         }