Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 1 | |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 8 | static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p); |
| 9 | |
| 10 | |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 11 | int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p) |
| 12 | { |
Igor Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 13 | 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 Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 18 | |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 25 | p->cache = c; |
| 26 | |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 27 | 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 Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 56 | |
| 57 | rc = ngx_http_cache_get_file(r, &c->ctx); |
| 58 | |
Igor Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 59 | if (rc == NGX_STALE) { |
| 60 | p->stale = 1; |
| 61 | } |
| 62 | |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 63 | if (rc == NGX_OK || rc == NGX_STALE) { |
Igor Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 64 | 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 Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 68 | |
| 69 | } else if (rc == NGX_DECLINED) { |
Igor Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 70 | p->header_in->pos += c->ctx.header_size; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 71 | p->header_in->last = p->header_in->pos; |
| 72 | } |
| 73 | |
| 74 | return rc; |
| 75 | } |
| 76 | |
| 77 | |
Igor Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 78 | static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p) |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 79 | { |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 95 | return NGX_ERROR; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 96 | } |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 102 | return NGX_ERROR; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 103 | } |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 111 | return NGX_ERROR; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 112 | } |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 130 | return NGX_ERROR; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 131 | } |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 139 | return NGX_ERROR; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 140 | } |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 171 | return NGX_OK; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 172 | |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 178 | return NGX_ERROR; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 179 | } |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 187 | return NGX_ERROR; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 188 | } |
| 189 | } |
| 190 | |
| 191 | |
| 192 | int 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 201 | r->headers_out.status = p->cache->status; |
Igor Sysoev | 6597749 | 2003-11-02 22:56:18 +0000 | [diff] [blame] | 202 | |
| 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 Sysoev | a1512b1 | 2003-11-03 17:33:31 +0000 | [diff] [blame^] | 247 | |
| 248 | |
| 249 | int 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 | } |