blob: 6309b398d273865efd51fbeaf16dd5b187517b9d [file] [log] [blame]
Igor Sysoev65977492003-11-02 22:56:18 +00001
2#include <ngx_config.h>
3#include <ngx_core.h>
4#include <ngx_http.h>
5#include <ngx_http_proxy_handler.h>
6
7
Igor Sysoeva1512b12003-11-03 17:33:31 +00008static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p);
9
10
Igor Sysoev65977492003-11-02 22:56:18 +000011int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p)
12{
Igor Sysoeva1512b12003-11-03 17:33:31 +000013 int rc;
14 char *last;
15 ngx_http_request_t *r;
16 ngx_http_proxy_cache_t *c;
17 ngx_http_proxy_upstream_conf_t *u;
Igor Sysoev65977492003-11-02 22:56:18 +000018
19 r = p->request;
20
21 if (!(c = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_cache_t)))) {
22 return NGX_HTTP_INTERNAL_SERVER_ERROR;
23 }
24
Igor Sysoeva1512b12003-11-03 17:33:31 +000025 p->cache = c;
26
Igor Sysoev65977492003-11-02 22:56:18 +000027 c->ctx.file.fd = NGX_INVALID_FILE;
28 c->ctx.file.log = r->connection->log;
29 c->ctx.path = p->lcf->cache_path;
30
31 u = p->lcf->upstream;
32
33 c->ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len;
34 if (!(c->ctx.key.data = ngx_palloc(r->pool, c->ctx.key.len + 1))) {
35 return NGX_HTTP_INTERNAL_SERVER_ERROR;
36 }
37
38 last = ngx_cpymem(c->ctx.key.data, u->url.data, u->url.len);
39
40 last = ngx_cpymem(last, r->uri.data + u->location->len,
41 r->uri.len - u->location->len);
42
43 if (r->args.len > 0) {
44 *(last++) = '?';
45 last = ngx_cpymem(last, r->args.data, r->args.len);
46 }
47 *last = '\0';
48
49 p->header_in = ngx_create_temp_hunk(r->pool, p->lcf->header_buffer_size);
50 if (p->header_in == NULL) {
51 return NGX_HTTP_INTERNAL_SERVER_ERROR;
52 }
53 p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
54
55 c->ctx.buf = p->header_in;
Igor Sysoev65977492003-11-02 22:56:18 +000056
57 rc = ngx_http_cache_get_file(r, &c->ctx);
58
Igor Sysoeva1512b12003-11-03 17:33:31 +000059 if (rc == NGX_STALE) {
60 p->stale = 1;
61 }
62
Igor Sysoev65977492003-11-02 22:56:18 +000063 if (rc == NGX_OK || rc == NGX_STALE) {
Igor Sysoeva1512b12003-11-03 17:33:31 +000064 p->header_in->pos += c->ctx.header_size;
65 if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
66 return NGX_HTTP_INTERNAL_SERVER_ERROR;
67 }
Igor Sysoev65977492003-11-02 22:56:18 +000068
69 } else if (rc == NGX_DECLINED) {
Igor Sysoeva1512b12003-11-03 17:33:31 +000070 p->header_in->pos += c->ctx.header_size;
Igor Sysoev65977492003-11-02 22:56:18 +000071 p->header_in->last = p->header_in->pos;
72 }
73
74 return rc;
75}
76
77
Igor Sysoeva1512b12003-11-03 17:33:31 +000078static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p)
Igor Sysoev65977492003-11-02 22:56:18 +000079{
80 int rc, i;
81 ngx_table_elt_t *h;
82 ngx_http_request_t *r;
83 ngx_http_proxy_cache_t *c;
84
85 rc = ngx_http_proxy_parse_status_line(p);
86
87 c = p->cache;
88 r = p->request;
89
90 if (rc == NGX_AGAIN) {
91 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
92 "\"proxy_header_buffer_size\" "
93 "is too small to read header from \"%s\"",
94 c->ctx.file.name.data);
Igor Sysoeva1512b12003-11-03 17:33:31 +000095 return NGX_ERROR;
Igor Sysoev65977492003-11-02 22:56:18 +000096 }
97
98 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
99 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
100 "no valid HTTP/1.0 header in \"%s\"",
101 c->ctx.file.name.data);
Igor Sysoeva1512b12003-11-03 17:33:31 +0000102 return NGX_ERROR;
Igor Sysoev65977492003-11-02 22:56:18 +0000103 }
104
105 /* rc == NGX_OK */
106
107 c->status = p->status;
108 c->status_line.len = p->status_end - p->status_start;
109 c->status_line.data = ngx_palloc(r->pool, c->status_line.len + 1);
110 if (c->status_line.data == NULL) {
Igor Sysoeva1512b12003-11-03 17:33:31 +0000111 return NGX_ERROR;
Igor Sysoev65977492003-11-02 22:56:18 +0000112 }
113
114 ngx_cpystrn(c->status_line.data, p->status_start, c->status_line.len + 1);
115
116 ngx_log_debug(r->connection->log, "http cache status %d '%s'" _
117 c->status _ c->status_line.data);
118
119 c->headers_in.headers = ngx_create_table(r->pool, 20);
120
121 for ( ;; ) {
122 rc = ngx_http_parse_header_line(r, p->header_in);
123
124 if (rc == NGX_OK) {
125
126 /* a header line has been parsed successfully */
127
128 h = ngx_http_add_header(&c->headers_in, ngx_http_proxy_headers_in);
129 if (h == NULL) {
Igor Sysoeva1512b12003-11-03 17:33:31 +0000130 return NGX_ERROR;
Igor Sysoev65977492003-11-02 22:56:18 +0000131 }
132
133 h->key.len = r->header_name_end - r->header_name_start;
134 h->value.len = r->header_end - r->header_start;
135
136 h->key.data = ngx_palloc(r->pool,
137 h->key.len + 1 + h->value.len + 1);
138 if (h->key.data == NULL) {
Igor Sysoeva1512b12003-11-03 17:33:31 +0000139 return NGX_ERROR;
Igor Sysoev65977492003-11-02 22:56:18 +0000140 }
141
142 h->value.data = h->key.data + h->key.len + 1;
143 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
144 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
145
146 for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
147 if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
148 continue;
149 }
150
151 if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
152 h->key.data) == 0)
153 {
154 *((ngx_table_elt_t **) ((char *) &c->headers_in
155 + ngx_http_proxy_headers_in[i].offset)) = h;
156 break;
157 }
158 }
159
160 ngx_log_debug(r->connection->log, "HTTP cache header: '%s: %s'" _
161 h->key.data _ h->value.data);
162
163 continue;
164
165 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
166
167 /* a whole header has been parsed successfully */
168
169 ngx_log_debug(r->connection->log, "HTTP header done");
170
Igor Sysoeva1512b12003-11-03 17:33:31 +0000171 return NGX_OK;
Igor Sysoev65977492003-11-02 22:56:18 +0000172
173 } else if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
174
175 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
176 "invalid header in \"%s\"",
177 c->ctx.file.name.data);
Igor Sysoeva1512b12003-11-03 17:33:31 +0000178 return NGX_ERROR;
Igor Sysoev65977492003-11-02 22:56:18 +0000179 }
180
181 /* rc == NGX_AGAIN || rc == NGX_HTTP_PARSE_TOO_LONG_HEADER */
182
183 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
184 "\"proxy_header_buffer_size\" "
185 "is too small to read header from \"%s\"",
186 c->ctx.file.name.data);
Igor Sysoeva1512b12003-11-03 17:33:31 +0000187 return NGX_ERROR;
Igor Sysoev65977492003-11-02 22:56:18 +0000188 }
189}
190
191
192int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p)
193{
194 int rc;
195 ngx_hunk_t *h;
196 ngx_chain_t out;
197 ngx_http_request_t *r;
198
199 r = p->request;
200
Igor Sysoeva1512b12003-11-03 17:33:31 +0000201 r->headers_out.status = p->cache->status;
Igor Sysoev65977492003-11-02 22:56:18 +0000202
203#if 0
204 r->headers_out.content_length_n = -1;
205 r->headers_out.content_length = NULL;
206#endif
207
208 /* copy an cached header to r->headers_out */
209
210 if (ngx_http_proxy_copy_header(p, &p->cache->headers_in) == NGX_ERROR) {
211 return NGX_HTTP_INTERNAL_SERVER_ERROR;
212 }
213
214 /* we need to allocate all before the header would be sent */
215
216 if (!((h = ngx_calloc_hunk(r->pool)))) {
217 return NGX_HTTP_INTERNAL_SERVER_ERROR;
218 }
219
220 if (!((h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
221 return NGX_HTTP_INTERNAL_SERVER_ERROR;
222 }
223
224 rc = ngx_http_send_header(r);
225
226 /* NEEDED ??? */ p->header_sent = 1;
227
228 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
229 return rc;
230 }
231
232 /* TODO: part in p->header_in */
233
234 h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
235
236 h->file_pos = p->header_in->pos - p->header_in->start;
237 h->file_last = h->file_pos + p->cache->ctx.header.length;
238
239 h->file->fd = p->cache->ctx.file.fd;
240 h->file->log = r->connection->log;
241
242 out.hunk = h;
243 out.next = NULL;
244
245 return ngx_http_output_filter(r, &out);
246}
Igor Sysoeva1512b12003-11-03 17:33:31 +0000247
248
249int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
250{
251 if (p->cache == NULL) {
252 return NGX_OK;
253 }
254
255 return ngx_http_cache_update_file(p->request, &p->cache->ctx,
256 &p->upstream->event_pipe->temp_file->file.name);
257}