changeset 172:caa57ddf6d77

nginx-0.0.1-2003-11-04-01:20:44 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 03 Nov 2003 22:20:44 +0000
parents aff0e5d32af8
children 4fb2a2cff023
files src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/event/ngx_event_pipe.c src/http/modules/proxy/ngx_http_proxy_cache.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_handler.h src/http/modules/proxy/ngx_http_proxy_header.c src/http/modules/proxy/ngx_http_proxy_parse.c src/http/modules/proxy/ngx_http_proxy_upstream.c src/http/ngx_http_cache.c src/http/ngx_http_cache.h src/http/ngx_http_headers.c src/http/ngx_http_request.h
diffstat 13 files changed, 288 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -805,9 +805,24 @@ char *ngx_conf_check_num_bounds(ngx_conf
     ngx_conf_num_bounds_t *bounds = post;
     int *np = data;
 
-    if (*np >= bounds->low && (u_int) *np <= (u_int) bounds->high) {
+    if (bounds->high == -1) {
+        if (*np >= bounds->low) {
+            return NGX_CONF_OK;
+        }
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "value must be more than %d", bounds->low);
+
+        return NGX_CONF_ERROR;
+    }
+
+    if (*np >= bounds->low && *np <= bounds->high) {
         return NGX_CONF_OK;
     }
 
-    return "invalid value";
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "value must be between %d and %d",
+                       bounds->low, bounds->high);
+
+    return NGX_CONF_ERROR;
 }
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -195,9 +195,14 @@ char *ngx_conf_check_num_bounds(ngx_conf
         conf = (prev == (ngx_msec_t) NGX_CONF_UNSET) ? default : prev;       \
     }
 
+#define ngx_conf_merge_sec_value(conf, prev, default)                        \
+    if (conf == NGX_CONF_UNSET) {                                            \
+        conf = (prev == NGX_CONF_UNSET) ? default : prev;                    \
+    }
+
 #define ngx_conf_merge_size_value(conf, prev, default)                       \
-    if (conf == (ssize_t) NGX_CONF_UNSET) {                                   \
-        conf = (prev == (ssize_t) NGX_CONF_UNSET) ? default : prev;           \
+    if (conf == (ssize_t) NGX_CONF_UNSET) {                                  \
+        conf = (prev == (ssize_t) NGX_CONF_UNSET) ? default : prev;          \
     }
 
 #define ngx_conf_merge_str_value(conf, prev, default)                        \
@@ -244,6 +249,7 @@ char *ngx_conf_set_str_slot(ngx_conf_t *
 char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_time_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -433,7 +433,7 @@ int ngx_event_pipe_write_to_downstream(n
 
 static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
 {
-    int           rc, size, hsize;
+    int           size, hsize;
     char         *save_pos;
     ngx_hunk_t   *h;
     ngx_chain_t  *cl, *tl, *next, *out, **ll, **last_free;
--- a/src/http/modules/proxy/ngx_http_proxy_cache.c
+++ b/src/http/modules/proxy/ngx_http_proxy_cache.c
@@ -56,11 +56,29 @@ int ngx_http_proxy_get_cached_response(n
 
     rc = ngx_http_cache_get_file(r, &c->ctx);
 
-    if (rc == NGX_STALE) {
+    switch (rc) {
+    case NGX_HTTP_CACHE_STALE:
+        p->stale = 1;
+        p->state->cache = NGX_HTTP_PROXY_CACHE_EXPR;
+        break;
+
+    case NGX_HTTP_CACHE_AGED:
         p->stale = 1;
+        p->state->cache = NGX_HTTP_PROXY_CACHE_AGED;
+        break;
+
+    case NGX_OK:
+        p->state->cache = NGX_HTTP_PROXY_CACHE_HIT;
+        break;
+
+    default:
+        p->state->cache = NGX_HTTP_PROXY_CACHE_MISS;
     }
 
-    if (rc == NGX_OK || rc == NGX_STALE) {
+    if (rc == NGX_OK
+        || rc == NGX_HTTP_CACHE_STALE
+        || rc == NGX_HTTP_CACHE_AGED)
+    {
         p->header_in->pos += c->ctx.header_size;
         if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -246,6 +264,99 @@ int ngx_http_proxy_send_cached_response(
 }
 
 
+int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p)
+{
+    time_t                        date, last_modified, expires;
+    ngx_http_proxy_headers_in_t  *h;
+
+    switch (p->upstream->status) {
+    case NGX_HTTP_OK:
+    case NGX_HTTP_MOVED_PERMANENTLY:
+    case NGX_HTTP_MOVED_TEMPORARILY:
+        break;
+
+#if 0
+    case NGX_HTTP_NOT_MODIFIED:
+        return 1;
+#endif
+
+    default:
+        return 0;
+    }
+
+    h = &p->upstream->headers_in;
+
+    date = NGX_ERROR;
+    if (h->date) {
+        date = ngx_http_parse_time(h->date->value.data, h->date->value.len);
+    }
+    if (date == NGX_ERROR) {
+        date = ngx_time();
+    }
+    p->cache->ctx.header.date = date;
+
+    last_modified = NGX_ERROR;
+    if (h->last_modified) {
+        last_modified = ngx_http_parse_time(h->last_modified->value.data,
+                                            h->last_modified->value.len);
+        p->cache->ctx.header.last_modified = last_modified;
+    }
+
+    if (h->x_accel_expires) {
+        expires = ngx_atoi(h->x_accel_expires->value.data,
+                           h->x_accel_expires->value.len);
+        if (expires != NGX_ERROR) {
+            p->state->reason = NGX_HTTP_PROXY_CACHE_XAE;
+            p->cache->ctx.header.expires = date + expires;
+            return (expires > 0);
+        }
+    }
+
+    if (!p->lcf->ignore_expires) {
+
+        /* TODO: Cache-Control: no-cache, max-age= */
+
+        if (h->expires) {
+            expires = ngx_http_parse_time(h->expires->value.data,
+                                          h->expires->value.len);
+            if (expires != NGX_ERROR) {
+                p->state->reason = NGX_HTTP_PROXY_CACHE_EXP;
+                p->cache->ctx.header.expires = expires;
+                return (date < expires);
+            }
+        }
+    }
+
+    if (p->upstream->status == NGX_HTTP_MOVED_PERMANENTLY) {
+        p->state->reason = NGX_HTTP_PROXY_CACHE_MVD;
+        p->cache->ctx.header.expires = /* STUB: 1 hour */ 60 * 60;
+        return 1;
+    }
+
+    if (p->upstream->status == NGX_HTTP_MOVED_TEMPORARILY) {
+        return 1;
+    }
+
+    if (last_modified != NGX_ERROR && p->lcf->lm_factor > 0) {
+
+        /* FIXME: time_t == int_64_t */ 
+
+        p->state->reason = NGX_HTTP_PROXY_CACHE_LMF;
+        p->cache->ctx.header.expires = ngx_time()
+              + (((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100;
+        return 1;
+    }
+
+    if (p->lcf->default_expires > 0) {
+        p->state->reason = NGX_HTTP_PROXY_CACHE_PDE;
+        p->cache->ctx.header.expires = p->lcf->default_expires;
+        return 1;
+    }
+
+    return 0;
+}
+
+
 int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
 {
     if (p->cache == NULL) {
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -38,6 +38,12 @@ static ngx_conf_bitmask_t  use_stale_mas
     { ngx_null_string, 0 }
 };
 
+
+static ngx_conf_num_bounds_t  ngx_http_proxy_lm_factor_bounds = {
+    ngx_conf_check_num_bounds, 0, 100
+};
+
+
 static ngx_command_t  ngx_http_proxy_commands[] = {
 
     { ngx_string("proxy_pass"),
@@ -124,6 +130,7 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, cache),
       NULL },
 
+
     { ngx_string("proxy_pass_server"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -131,6 +138,35 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, pass_server),
       NULL },
 
+    { ngx_string("proxy_pass_x_accel_expires"),
+      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_proxy_loc_conf_t, pass_x_accel_expires),
+      NULL },
+
+    { ngx_string("proxy_ignore_expires"),
+      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_proxy_loc_conf_t, ignore_expires),
+      NULL },
+
+    { ngx_string("proxy_lm_factor"),
+      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_proxy_loc_conf_t, lm_factor),
+      &ngx_http_proxy_lm_factor_bounds },
+
+    { ngx_string("proxy_default_expires"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_sec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, default_expires),
+      NULL },
+
+
     { ngx_string("proxy_next_upstream"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
       ngx_conf_set_bitmask_slot,
@@ -199,8 +235,6 @@ ngx_http_header_t ngx_http_proxy_headers
 static int ngx_http_proxy_handler(ngx_http_request_t *r)
 {
     int                    rc;
-    char                  *last;
-    ngx_http_cache_ctx_t  *cctx;
     ngx_http_proxy_ctx_t  *p;
 
     ngx_http_create_ctx(r, p, ngx_http_proxy_module,
@@ -213,7 +247,34 @@ static int ngx_http_proxy_handler(ngx_ht
     /* TODO: we currently support reverse proxy only */
     p->accel = 1;
 
-    if (!p->lcf->cache || r->bypass_cache) {
+    ngx_init_array(p->states, r->pool, p->lcf->peers->number,
+                   sizeof(ngx_http_proxy_state_t),
+                   NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+    if (!(p->state = ngx_push_array(&p->states))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+
+    if (!p->lcf->cache) {
+        p->state->cache = NGX_HTTP_PROXY_CACHE_PASS;
+
+    } else if (r->bypass_cache) {
+        p->state->cache = NGX_HTTP_PROXY_CACHE_BYPASS;
+
+    } else if (r->headers_in.authorization) {
+        p->state->cache = NGX_HTTP_PROXY_CACHE_AUTH;
+
+    } else if (r->no_cache) {
+        p->state->cache = NGX_HTTP_PROXY_CACHE_PGNC;
+        p->cachable = 1;
+
+    } else {
+        p->cachable = 1;
+    }
+
+
+    if (p->state->cache) {
         return ngx_http_proxy_request_upstream(p);
     }
 
@@ -227,27 +288,9 @@ static int ngx_http_proxy_handler(ngx_ht
         return rc;
     }
 
-    if (rc == NGX_DECLINED || rc == NGX_STALE) {
-        return ngx_http_proxy_request_upstream(p);
-    }
-
-    return NGX_DONE;
-}
-
+    /* rc == NGX_DECLINED || NGX_HTTP_CACHE_STALE || NGX_HTTP_CACHE_AGED */
 
-int ngx_http_proxy_log_state(ngx_http_proxy_ctx_t *p, int status)
-{
-    ngx_http_proxy_state_t  *state;
-
-    if (!(state = ngx_push_array(&p->states))) {
-        return NGX_ERROR;
-    }
-
-    state->status = status;
-    state->peer =
-     &p->upstream->peer.peers->peers[p->upstream->peer.cur_peer].addr_port_text;
-
-    return NGX_OK;
+    return ngx_http_proxy_request_upstream(p);
 }
 
 
@@ -386,6 +429,10 @@ static void *ngx_http_proxy_create_loc_c
     conf->cache = NGX_CONF_UNSET;
 
     conf->pass_server = NGX_CONF_UNSET;
+    conf->pass_x_accel_expires = NGX_CONF_UNSET;
+    conf->ignore_expires = NGX_CONF_UNSET;
+    conf->lm_factor = NGX_CONF_UNSET;
+    conf->default_expires = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -436,6 +483,11 @@ static char *ngx_http_proxy_merge_loc_co
     ngx_conf_merge_value(conf->cache, prev->cache, 0);
 
     ngx_conf_merge_value(conf->pass_server, prev->pass_server, 0);
+    ngx_conf_merge_value(conf->pass_x_accel_expires,
+                         prev->pass_x_accel_expires, 0);
+    ngx_conf_merge_value(conf->ignore_expires, prev->ignore_expires, 0);
+    ngx_conf_merge_value(conf->lm_factor, prev->lm_factor, 0);
+    ngx_conf_merge_sec_value(conf->default_expires, prev->default_expires, 0);
 
     return NULL;
 }
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -10,6 +10,29 @@
 #include <ngx_http.h>
 
 
+typedef enum {
+    NGX_HTTP_PROXY_CACHE_PASS = 1,
+    NGX_HTTP_PROXY_CACHE_BYPASS,
+    NGX_HTTP_PROXY_CACHE_AUTH,
+    NGX_HTTP_PROXY_CACHE_PGNC,
+    NGX_HTTP_PROXY_CACHE_MISS,
+    NGX_HTTP_PROXY_CACHE_EXPR,
+    NGX_HTTP_PROXY_CACHE_AGED,
+    NGX_HTTP_PROXY_CACHE_HIT
+} ngx_http_proxy_state_e;
+
+
+typedef enum {
+    NGX_HTTP_PROXY_CACHE_BPS = 1,
+    NGX_HTTP_PROXY_CACHE_XAE,
+    NGX_HTTP_PROXY_CACHE_CTL,
+    NGX_HTTP_PROXY_CACHE_EXP,
+    NGX_HTTP_PROXY_CACHE_MVD,
+    NGX_HTTP_PROXY_CACHE_LMF,
+    NGX_HTTP_PROXY_CACHE_PDE
+} ngx_http_proxy_reason_e;
+
+
 typedef struct {
     ngx_str_t                        url;
     ngx_str_t                        host;
@@ -36,7 +59,13 @@ typedef struct {
     int                              cyclic_temp_file;
 
     int                              cache;
+
     int                              pass_server;
+    int                              pass_x_accel_expires;
+
+    int                              ignore_expires;
+    int                              lm_factor;
+    int                              default_expires;
 
     int                              next_upstream;
     int                              use_stale;
@@ -50,6 +79,8 @@ typedef struct {
 
 
 typedef struct {
+    ngx_http_proxy_state_e           cache;
+    ngx_http_proxy_reason_e          reason;
     int                              status;
     ngx_str_t                       *peer;
 } ngx_http_proxy_state_t;
@@ -122,8 +153,9 @@ struct ngx_http_proxy_ctx_s {
     char                         *status_start;
     char                         *status_end;
     int                           status_count;
-    int                           state;
+    int                           parse_state;
 
+    ngx_http_proxy_state_t       *state;
     ngx_array_t                   states;    /* of ngx_http_proxy_state_t */
 
     char                         *action;
@@ -134,6 +166,7 @@ struct ngx_http_proxy_ctx_s {
 
 #define NGX_HTTP_PROXY_PARSE_NO_HEADER       20
 
+
 #define NGX_HTTP_PROXY_FT_ERROR              2
 #define NGX_HTTP_PROXY_FT_TIMEOUT            4
 #define NGX_HTTP_PROXY_FT_INVALID_HEADER     8
@@ -147,9 +180,9 @@ int ngx_http_proxy_request_upstream(ngx_
 
 int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p);
 int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p);
+int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p);
 int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p);
 
-int ngx_http_proxy_log_state(ngx_http_proxy_ctx_t *p, int status);
 size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len);
 void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
 void ngx_http_proxy_close_connection(ngx_connection_t *c);
--- a/src/http/modules/proxy/ngx_http_proxy_header.c
+++ b/src/http/modules/proxy/ngx_http_proxy_header.c
@@ -26,6 +26,12 @@ int ngx_http_proxy_copy_header(ngx_http_
                 || &h[i] == headers_in->accept_ranges) {
                 continue;
             }
+
+            if (&h[i] == headers_in->x_accel_expires
+                && !p->lcf->pass_x_accel_expires)
+            {
+                continue;
+            } 
     
             if (&h[i] == headers_in->server && !p->lcf->pass_server) {
                 continue;
--- a/src/http/modules/proxy/ngx_http_proxy_parse.c
+++ b/src/http/modules/proxy/ngx_http_proxy_parse.c
@@ -26,7 +26,7 @@ int ngx_http_proxy_parse_status_line(ngx
         sw_done
     } state;
 
-    state = p->state;
+    state = p->parse_state;
     pos = p->header_in->pos;
 
     while (pos < p->header_in->last && state < sw_done) {
@@ -195,10 +195,10 @@ int ngx_http_proxy_parse_status_line(ngx
             p->status_end = pos - 1;
         }
 
-        p->state = sw_start;
+        p->parse_state = sw_start;
         return NGX_OK;
     }
 
-    p->state = state;
+    p->parse_state = state;
     return NGX_AGAIN;
 }
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -17,7 +17,6 @@ static void ngx_http_proxy_send_request_
 static void ngx_http_proxy_dummy_handler(ngx_event_t *wev);
 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev);
 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
-static void ngx_http_proxy_process_upstream_header(ngx_http_proxy_ctx_t *p);
 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
 static void ngx_http_proxy_process_body(ngx_event_t *ev);
@@ -59,14 +58,8 @@ int ngx_http_proxy_request_upstream(ngx_
     u->peer.peers = p->lcf->peers;
     u->peer.tries = p->lcf->peers->number;
 
-    ngx_init_array(p->states, r->pool, u->peer.tries,
-                   sizeof(ngx_http_proxy_state_t),
-                   NGX_HTTP_INTERNAL_SERVER_ERROR);
-
     u->method = r->method;
 
-    /* STUB */ p->cachable = p->lcf->cache;
-
     if (r->headers_in.content_length_n > 0) {
         if (!(r->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -313,7 +306,6 @@ static void ngx_http_proxy_reinit_upstre
 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
 {
     int                      rc;
-    ngx_chain_t             *cl;
     ngx_connection_t        *c;
     ngx_http_request_t      *r;
     ngx_output_chain_ctx_t  *octx;
@@ -327,6 +319,9 @@ static void ngx_http_proxy_connect(ngx_h
         return;
     }
 
+    p->state->peer =
+     &p->upstream->peer.peers->peers[p->upstream->peer.cur_peer].addr_port_text;
+
     if (rc == NGX_CONNECT_ERROR) {
         ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
         return;
@@ -367,6 +362,11 @@ static void ngx_http_proxy_connect(ngx_h
 
     p->request_sent = 0;
 
+    if (!(p->state = ngx_push_array(&p->states))) {
+        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
     if (rc == NGX_AGAIN) {
         ngx_add_timer(c->write, p->lcf->connect_timeout);
         return;
@@ -731,7 +731,12 @@ static void ngx_http_proxy_process_upstr
 
             ngx_log_debug(c->log, "HTTP header done");
 
-            ngx_http_proxy_process_upstream_header(p);
+            /* TODO: hook to process the upstream header */
+
+            if (p->cachable) {
+                p->cachable = ngx_http_proxy_is_cachable(p);
+            }
+
             ngx_http_proxy_send_response(p);
             return;
 
@@ -759,17 +764,6 @@ static void ngx_http_proxy_process_upstr
 }
 
 
-static void ngx_http_proxy_process_upstream_header(ngx_http_proxy_ctx_t *p)
-{
-    time_t  expires;
-
-    expires = ngx_http_parse_time(p->upstream->headers_in.expires->value.data,
-                                  p->upstream->headers_in.expires->value.len);
-
-    p->cache->ctx.header.expires = expires;
-}
-
-
 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p)
 {
     ssize_t       n;
@@ -814,8 +808,7 @@ static ssize_t ngx_http_proxy_read_upstr
 
 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
 {
-    int                           rc, i;
-    ngx_table_elt_t              *ho, *h;
+    int                           rc;
     ngx_event_pipe_t             *ep;
     ngx_http_request_t           *r;
     ngx_http_cache_file_t        *header;
@@ -995,13 +988,13 @@ static void ngx_http_proxy_process_body(
     }
 
     if (p->upstream->peer.connection) {
-        if (ep->upstream_done) {
+        if (ep->upstream_done && p->cachable) {
             if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
                 ngx_http_proxy_finalize_request(p, 0);
                 return;
             }
 
-        } else if (ep->upstream_eof) {
+        } else if (ep->upstream_eof && p->cachable) {
 
             /* TODO: check length & update cache */
 
@@ -1086,10 +1079,7 @@ ngx_log_debug(p->request->connection->lo
     }
 
     if (status) {
-        if (ngx_http_proxy_log_state(p, status) == NGX_ERROR) {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return;
-        }
+        p->state->status = status;
 
         if (p->upstream->peer.tries == 0 || !(p->lcf->next_upstream & ft_type))
         {
--- a/src/http/ngx_http_cache.c
+++ b/src/http/ngx_http_cache.c
@@ -80,9 +80,11 @@ ngx_log_debug(r->connection->log, "FILE:
     ctx->buf->last += n;
 
     if (ctx->header.expires < ngx_time()) {
-        return NGX_STALE;
+        return NGX_HTTP_CACHE_STALE;
     }
 
+    /* TODO: NGX_HTTP_CACHE_AGED */
+
     return NGX_OK;
 }
 
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -9,6 +9,7 @@
 typedef struct {
     time_t       expires;
     time_t       last_modified;
+    time_t       date;
     off_t        length;
 } ngx_http_cache_header_t;
 
@@ -44,7 +45,8 @@ typedef struct {
 } ngx_http_cache_ctx_t;
 
 
-#define NGX_STALE  1
+#define NGX_HTTP_CACHE_STALE  1
+#define NGX_HTTP_CACHE_AGED   2
 
 
 int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx);
--- a/src/http/ngx_http_headers.c
+++ b/src/http/ngx_http_headers.c
@@ -20,6 +20,9 @@ ngx_http_header_t  ngx_http_headers_in[]
     { ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range) },
 #endif
 
+    { ngx_string("Authorization"),
+                             offsetof(ngx_http_headers_in_t, authorization) },
+
     { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive) },
 
     { ngx_null_string, 0 }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -79,6 +79,8 @@ typedef struct {
     ngx_table_elt_t  *accept_encoding;
     ngx_table_elt_t  *range;
 
+    ngx_table_elt_t  *authorization;
+
     ngx_table_elt_t  *keep_alive;
 
     size_t            host_name_len;
@@ -198,6 +200,7 @@ struct ngx_http_request_s {
 
     unsigned             proxy:1;
     unsigned             bypass_cache:1;
+    unsigned             no_cache:1;
 
 #if 0
     unsigned             cachable:1;