diff options
Diffstat (limited to 'src/http/modules/proxy')
-rw-r--r-- | src/http/modules/proxy/ngx_http_proxy_cache.c | 115 | ||||
-rw-r--r-- | src/http/modules/proxy/ngx_http_proxy_handler.c | 98 | ||||
-rw-r--r-- | src/http/modules/proxy/ngx_http_proxy_handler.h | 37 | ||||
-rw-r--r-- | src/http/modules/proxy/ngx_http_proxy_header.c | 6 | ||||
-rw-r--r-- | src/http/modules/proxy/ngx_http_proxy_parse.c | 6 | ||||
-rw-r--r-- | src/http/modules/proxy/ngx_http_proxy_upstream.c | 46 |
6 files changed, 250 insertions, 58 deletions
diff --git a/src/http/modules/proxy/ngx_http_proxy_cache.c b/src/http/modules/proxy/ngx_http_proxy_cache.c index 6309b398d..b01e5871f 100644 --- 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(ngx_http_proxy_ctx_t *p) 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(ngx_http_proxy_ctx_t *p) } +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) { diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c index 7c9fa9e8f..8aa6e6823 100644 --- 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_masks[] = { { 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_commands[] = { 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_commands[] = { 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_in[] = { 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,41 +247,50 @@ static int ngx_http_proxy_handler(ngx_http_request_t *r) /* TODO: we currently support reverse proxy only */ p->accel = 1; - if (!p->lcf->cache || r->bypass_cache) { - return ngx_http_proxy_request_upstream(p); + 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; } - rc = ngx_http_proxy_get_cached_response(p); - if (rc == NGX_OK) { - return ngx_http_proxy_send_cached_response(p); - } + if (!p->lcf->cache) { + p->state->cache = NGX_HTTP_PROXY_CACHE_PASS; - if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { - return rc; + } 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 (rc == NGX_DECLINED || rc == NGX_STALE) { + + if (p->state->cache) { return ngx_http_proxy_request_upstream(p); } - return NGX_DONE; -} - + rc = ngx_http_proxy_get_cached_response(p); -int ngx_http_proxy_log_state(ngx_http_proxy_ctx_t *p, int status) -{ - ngx_http_proxy_state_t *state; + if (rc == NGX_OK) { + return ngx_http_proxy_send_cached_response(p); + } - if (!(state = ngx_push_array(&p->states))) { - return NGX_ERROR; + if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { + return rc; } - state->status = status; - state->peer = - &p->upstream->peer.peers->peers[p->upstream->peer.cur_peer].addr_port_text; + /* rc == NGX_DECLINED || NGX_HTTP_CACHE_STALE || NGX_HTTP_CACHE_AGED */ - return NGX_OK; + return ngx_http_proxy_request_upstream(p); } @@ -386,6 +429,10 @@ static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) 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_conf(ngx_conf_t *cf, 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; } diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h index f29498f01..f3334b25e 100644 --- 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_http_proxy_ctx_t *p); 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); diff --git a/src/http/modules/proxy/ngx_http_proxy_header.c b/src/http/modules/proxy/ngx_http_proxy_header.c index 18e27976a..4dda797bf 100644 --- 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_proxy_ctx_t *p, || &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; diff --git a/src/http/modules/proxy/ngx_http_proxy_parse.c b/src/http/modules/proxy/ngx_http_proxy_parse.c index 85c406ea7..1729542d0 100644 --- 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_http_proxy_ctx_t *p) 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_http_proxy_ctx_t *p) 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; } diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c index f969f33f0..3c9118e7b 100644 --- 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_handler(ngx_event_t *wev); 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_http_proxy_ctx_t *p) 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_upstream(ngx_http_proxy_ctx_t *p) 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_http_proxy_ctx_t *p) 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_http_proxy_ctx_t *p) 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_upstream_headers(ngx_event_t *rev) 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_upstream_headers(ngx_event_t *rev) } -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_upstream_header(ngx_http_proxy_ctx_t *p) 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(ngx_event_t *ev) } 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->log, "next upstream: %d" _ ft_type); } 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)) { |