diff src/http/modules/proxy/ngx_http_proxy_cache.c @ 170:c42be4185301

nginx-0.0.1-2003-11-03-01:56:18 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 02 Nov 2003 22:56:18 +0000
parents
children aff0e5d32af8
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/http/modules/proxy/ngx_http_proxy_cache.c
@@ -0,0 +1,235 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#include <ngx_http_proxy_handler.h>
+
+
+int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p)
+{
+    int                         rc;
+    char                       *last;
+    ngx_http_request_t         *r;
+    ngx_http_proxy_cache_t     *c;
+    ngx_http_proxy_upstream_t  *u;
+
+    r = p->request;
+
+    if (!(c = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_cache_t)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    c->ctx.file.fd = NGX_INVALID_FILE;
+    c->ctx.file.log = r->connection->log;
+    c->ctx.path = p->lcf->cache_path;
+
+    u = p->lcf->upstream;
+
+    c->ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len;
+    if (!(c->ctx.key.data = ngx_palloc(r->pool, c->ctx.key.len + 1))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    last = ngx_cpymem(c->ctx.key.data, u->url.data, u->url.len);
+
+    last = ngx_cpymem(last, r->uri.data + u->location->len,
+                      r->uri.len - u->location->len);
+
+    if (r->args.len > 0) {
+        *(last++) = '?';
+        last = ngx_cpymem(last, r->args.data, r->args.len);
+    }
+    *last = '\0';
+
+    p->header_in = ngx_create_temp_hunk(r->pool, p->lcf->header_buffer_size);
+    if (p->header_in == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+    p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
+
+    c->ctx.buf = p->header_in; 
+    p->cache = c;
+
+    rc = ngx_http_cache_get_file(r, &c->ctx);
+
+    if (rc == NGX_OK || rc == NGX_STALE) {
+        p->header_in->pos += c->ctx.header.size;
+
+    } else if (rc == NGX_DECLINED) {
+        p->header_in->pos += c->ctx.header.size;
+        p->header_in->last = p->header_in->pos;
+    }
+
+    return rc;
+}
+
+
+int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p)
+{
+    int                      rc, i;
+    ngx_table_elt_t         *h;
+    ngx_http_request_t      *r;
+    ngx_http_proxy_cache_t  *c;
+
+    rc = ngx_http_proxy_parse_status_line(p);
+
+    c = p->cache;
+    r = p->request;
+
+    if (rc == NGX_AGAIN) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "\"proxy_header_buffer_size\" "
+                      "is too small to read header from \"%s\"",
+                      c->ctx.file.name.data);
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "no valid HTTP/1.0 header in \"%s\"",
+                      c->ctx.file.name.data);
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    /* rc == NGX_OK */
+
+    c->status = p->status;
+    c->status_line.len = p->status_end - p->status_start;
+    c->status_line.data = ngx_palloc(r->pool, c->status_line.len + 1);
+    if (c->status_line.data == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    ngx_cpystrn(c->status_line.data, p->status_start, c->status_line.len + 1);
+
+    ngx_log_debug(r->connection->log, "http cache status %d '%s'" _ 
+                  c->status _ c->status_line.data);
+
+    c->headers_in.headers = ngx_create_table(r->pool, 20);
+
+    for ( ;; ) {
+        rc = ngx_http_parse_header_line(r, p->header_in);
+
+        if (rc == NGX_OK) {
+
+            /* a header line has been parsed successfully */
+
+            h = ngx_http_add_header(&c->headers_in, ngx_http_proxy_headers_in);
+            if (h == NULL) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            h->key.len = r->header_name_end - r->header_name_start;
+            h->value.len = r->header_end - r->header_start;
+
+            h->key.data = ngx_palloc(r->pool,
+                                     h->key.len + 1 + h->value.len + 1);
+            if (h->key.data == NULL) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            h->value.data = h->key.data + h->key.len + 1;
+            ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
+            ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
+
+            for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
+                if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
+                    continue;
+                }
+
+                if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
+                                                             h->key.data) == 0)
+                {
+                    *((ngx_table_elt_t **) ((char *) &c->headers_in
+                                   + ngx_http_proxy_headers_in[i].offset)) = h;
+                    break;
+                }
+            }
+
+            ngx_log_debug(r->connection->log, "HTTP cache header: '%s: %s'" _
+                          h->key.data _ h->value.data);
+
+            continue;
+
+        } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+
+            /* a whole header has been parsed successfully */
+
+            ngx_log_debug(r->connection->log, "HTTP header done");
+
+            return ngx_http_proxy_send_cached_response(p);
+
+        } else if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
+
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "invalid header in \"%s\"",
+                          c->ctx.file.name.data);
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        /* rc == NGX_AGAIN || rc == NGX_HTTP_PARSE_TOO_LONG_HEADER */
+
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "\"proxy_header_buffer_size\" "
+                      "is too small to read header from \"%s\"",
+                      c->ctx.file.name.data);
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+}
+
+
+int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p)
+{
+    int                  rc;
+    ngx_hunk_t          *h;
+    ngx_chain_t          out;
+    ngx_http_request_t  *r;
+
+    r = p->request;
+
+    r->headers_out.status = p->status;
+
+#if 0
+    r->headers_out.content_length_n = -1;
+    r->headers_out.content_length = NULL;
+#endif
+
+    /* copy an cached header to r->headers_out */
+    
+    if (ngx_http_proxy_copy_header(p, &p->cache->headers_in) == NGX_ERROR) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    /* we need to allocate all before the header would be sent */
+
+    if (!((h = ngx_calloc_hunk(r->pool)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (!((h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    rc = ngx_http_send_header(r);
+
+    /* NEEDED ??? */ p->header_sent = 1;
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return rc;
+    }
+
+    /* TODO: part in p->header_in */
+
+    h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
+
+    h->file_pos = p->header_in->pos - p->header_in->start;
+    h->file_last = h->file_pos + p->cache->ctx.header.length;
+
+    h->file->fd = p->cache->ctx.file.fd;
+    h->file->log = r->connection->log;
+    
+    out.hunk = h;
+    out.next = NULL;
+
+    return ngx_http_output_filter(r, &out);
+}