fastcgi_split_path_info
Igor Sysoev
13 years ago
21 | 21 | |
22 | 22 | ngx_array_t *fastcgi_lengths; |
23 | 23 | ngx_array_t *fastcgi_values; |
24 | ||
25 | #if (NGX_PCRE) | |
26 | ngx_regex_t *split_regex; | |
27 | ngx_str_t split_name; | |
28 | #endif | |
24 | 29 | } ngx_http_fastcgi_loc_conf_t; |
25 | 30 | |
26 | 31 | |
55 | 60 | ngx_uint_t fastcgi_stdout; /* unsigned :1 */ |
56 | 61 | |
57 | 62 | ngx_array_t *split_parts; |
63 | ||
64 | ngx_str_t script_name; | |
65 | ngx_str_t path_info; | |
58 | 66 | } ngx_http_fastcgi_ctx_t; |
59 | 67 | |
60 | 68 | |
124 | 132 | void *parent, void *child); |
125 | 133 | static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, |
126 | 134 | ngx_http_variable_value_t *v, uintptr_t data); |
135 | static ngx_int_t ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r, | |
136 | ngx_http_variable_value_t *v, uintptr_t data); | |
137 | static ngx_int_t ngx_http_fastcgi_split(ngx_http_request_t *r, | |
138 | ngx_http_fastcgi_ctx_t *f, ngx_http_fastcgi_loc_conf_t *flcf); | |
127 | 139 | |
128 | 140 | static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, |
129 | 141 | void *conf); |
142 | static char *ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, | |
143 | ngx_command_t *cmd, void *conf); | |
130 | 144 | static char *ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, |
131 | 145 | void *conf); |
132 | 146 | static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, |
168 | 182 | ngx_conf_set_str_slot, |
169 | 183 | NGX_HTTP_LOC_CONF_OFFSET, |
170 | 184 | offsetof(ngx_http_fastcgi_loc_conf_t, index), |
185 | NULL }, | |
186 | ||
187 | { ngx_string("fastcgi_split_path_info"), | |
188 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
189 | ngx_http_fastcgi_split_path_info, | |
190 | NGX_HTTP_LOC_CONF_OFFSET, | |
191 | 0, | |
171 | 192 | NULL }, |
172 | 193 | |
173 | 194 | { ngx_string("fastcgi_store"), |
389 | 410 | }; |
390 | 411 | |
391 | 412 | |
392 | static ngx_str_t ngx_http_fastcgi_script_name = | |
393 | ngx_string("fastcgi_script_name"); | |
413 | static ngx_http_variable_t ngx_http_fastcgi_vars[] = { | |
414 | ||
415 | { ngx_string("fastcgi_script_name"), NULL, | |
416 | ngx_http_fastcgi_script_name_variable, 0, | |
417 | NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, | |
418 | ||
419 | { ngx_string("fastcgi_path_info"), NULL, | |
420 | ngx_http_fastcgi_path_info_variable, 0, | |
421 | NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, | |
422 | ||
423 | { ngx_null_string, NULL, NULL, 0, 0, 0 } | |
424 | }; | |
394 | 425 | |
395 | 426 | |
396 | 427 | static ngx_str_t ngx_http_fastcgi_hide_headers[] = { |
409 | 440 | { |
410 | 441 | ngx_int_t rc; |
411 | 442 | ngx_http_upstream_t *u; |
443 | ngx_http_fastcgi_ctx_t *f; | |
412 | 444 | ngx_http_fastcgi_loc_conf_t *flcf; |
413 | 445 | |
414 | 446 | if (r->subrequest_in_memory) { |
418 | 450 | return NGX_HTTP_INTERNAL_SERVER_ERROR; |
419 | 451 | } |
420 | 452 | |
421 | ngx_http_set_ctx(r, NULL, ngx_http_fastcgi_module); | |
453 | f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); | |
454 | if (f == NULL) { | |
455 | return NGX_ERROR; | |
456 | } | |
457 | ||
458 | ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); | |
422 | 459 | |
423 | 460 | u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); |
424 | 461 | if (u == NULL) { |
932 | 969 | |
933 | 970 | umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); |
934 | 971 | |
935 | if (f == NULL) { | |
936 | f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); | |
937 | if (f == NULL) { | |
938 | return NGX_ERROR; | |
939 | } | |
940 | ||
941 | ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); | |
942 | } | |
943 | ||
944 | 972 | u = r->upstream; |
945 | 973 | |
946 | 974 | for ( ;; ) { |
1665 | 1693 | static ngx_int_t |
1666 | 1694 | ngx_http_fastcgi_add_variables(ngx_conf_t *cf) |
1667 | 1695 | { |
1668 | ngx_http_variable_t *var; | |
1669 | ||
1670 | var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, | |
1671 | NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE); | |
1672 | if (var == NULL) { | |
1673 | return NGX_ERROR; | |
1674 | } | |
1675 | ||
1676 | var->get_handler = ngx_http_fastcgi_script_name_variable; | |
1696 | ngx_http_variable_t *var, *v; | |
1697 | ||
1698 | for (v = ngx_http_fastcgi_vars; v->name.len; v++) { | |
1699 | var = ngx_http_add_variable(cf, &v->name, v->flags); | |
1700 | if (var == NULL) { | |
1701 | return NGX_ERROR; | |
1702 | } | |
1703 | ||
1704 | var->get_handler = v->get_handler; | |
1705 | var->data = v->data; | |
1706 | } | |
1677 | 1707 | |
1678 | 1708 | return NGX_OK; |
1679 | 1709 | } |
1932 | 1962 | conf->fastcgi_values = prev->fastcgi_values; |
1933 | 1963 | } |
1934 | 1964 | |
1965 | #if (NGX_PCRE) | |
1966 | if (conf->split_regex == NULL) { | |
1967 | conf->split_regex = prev->split_regex; | |
1968 | conf->split_name = prev->split_name; | |
1969 | } | |
1970 | #endif | |
1971 | ||
1935 | 1972 | if (conf->params_source == NULL) { |
1936 | 1973 | conf->flushes = prev->flushes; |
1937 | 1974 | conf->params_len = prev->params_len; |
2070 | 2107 | ngx_http_variable_value_t *v, uintptr_t data) |
2071 | 2108 | { |
2072 | 2109 | u_char *p; |
2110 | ngx_http_fastcgi_ctx_t *f; | |
2073 | 2111 | ngx_http_fastcgi_loc_conf_t *flcf; |
2074 | 2112 | |
2075 | if (r->uri.len) { | |
2113 | f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); | |
2114 | flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); | |
2115 | ||
2116 | if (ngx_http_fastcgi_split(r, f, flcf) != NGX_OK) { | |
2117 | return NGX_ERROR; | |
2118 | } | |
2119 | ||
2120 | if (f->script_name.len == 0 | |
2121 | || f->script_name.data[f->script_name.len - 1] != '/') | |
2122 | { | |
2123 | v->len = f->script_name.len; | |
2076 | 2124 | v->valid = 1; |
2077 | 2125 | v->no_cacheable = 0; |
2078 | 2126 | v->not_found = 0; |
2079 | ||
2080 | flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); | |
2081 | ||
2082 | if (r->uri.data[r->uri.len - 1] != '/') { | |
2083 | v->len = r->uri.len; | |
2084 | v->data = r->uri.data; | |
2085 | return NGX_OK; | |
2086 | } | |
2087 | ||
2088 | v->len = r->uri.len + flcf->index.len; | |
2089 | ||
2090 | v->data = ngx_pnalloc(r->pool, v->len); | |
2091 | if (v->data == NULL) { | |
2092 | return NGX_ERROR; | |
2093 | } | |
2094 | ||
2095 | p = ngx_copy(v->data, r->uri.data, r->uri.len); | |
2096 | ngx_memcpy(p, flcf->index.data, flcf->index.len); | |
2097 | ||
2098 | } else { | |
2099 | v->len = 0; | |
2100 | v->valid = 1; | |
2101 | v->no_cacheable = 0; | |
2102 | v->not_found = 0; | |
2103 | v->data = NULL; | |
2127 | v->data = f->script_name.data; | |
2104 | 2128 | |
2105 | 2129 | return NGX_OK; |
2106 | 2130 | } |
2107 | 2131 | |
2132 | v->len = f->script_name.len + flcf->index.len; | |
2133 | ||
2134 | v->data = ngx_pnalloc(r->pool, v->len); | |
2135 | if (v->data == NULL) { | |
2136 | return NGX_ERROR; | |
2137 | } | |
2138 | ||
2139 | p = ngx_copy(v->data, f->script_name.data, f->script_name.len); | |
2140 | ngx_memcpy(p, flcf->index.data, flcf->index.len); | |
2141 | ||
2108 | 2142 | return NGX_OK; |
2143 | } | |
2144 | ||
2145 | ||
2146 | static ngx_int_t | |
2147 | ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r, | |
2148 | ngx_http_variable_value_t *v, uintptr_t data) | |
2149 | { | |
2150 | ngx_http_fastcgi_ctx_t *f; | |
2151 | ngx_http_fastcgi_loc_conf_t *flcf; | |
2152 | ||
2153 | f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); | |
2154 | flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); | |
2155 | ||
2156 | if (ngx_http_fastcgi_split(r, f, flcf) != NGX_OK) { | |
2157 | return NGX_ERROR; | |
2158 | } | |
2159 | ||
2160 | v->len = f->path_info.len; | |
2161 | v->valid = 1; | |
2162 | v->no_cacheable = 0; | |
2163 | v->not_found = 0; | |
2164 | v->data = f->path_info.data; | |
2165 | ||
2166 | return NGX_OK; | |
2167 | } | |
2168 | ||
2169 | ||
2170 | static ngx_int_t | |
2171 | ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_ctx_t *f, | |
2172 | ngx_http_fastcgi_loc_conf_t *flcf) | |
2173 | { | |
2174 | #if (NGX_PCRE) | |
2175 | ngx_int_t n; | |
2176 | int captures[(1 + 2) * 3]; | |
2177 | ||
2178 | if (f->script_name.len) { | |
2179 | return NGX_OK; | |
2180 | } | |
2181 | ||
2182 | if (flcf->split_regex == NULL) { | |
2183 | f->script_name = r->uri; | |
2184 | return NGX_OK; | |
2185 | } | |
2186 | ||
2187 | n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3); | |
2188 | ||
2189 | if (n == NGX_REGEX_NO_MATCHED) { | |
2190 | f->script_name = r->uri; | |
2191 | return NGX_OK; | |
2192 | } | |
2193 | ||
2194 | if (n < 0) { | |
2195 | ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
2196 | ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", | |
2197 | n, &r->uri, &flcf->split_name); | |
2198 | return NGX_ERROR; | |
2199 | } | |
2200 | ||
2201 | /* match */ | |
2202 | ||
2203 | f->script_name.len = captures[3] - captures[2]; | |
2204 | f->script_name.data = r->uri.data; | |
2205 | ||
2206 | f->path_info.len = captures[5] - captures[4]; | |
2207 | f->path_info.data = r->uri.data + f->script_name.len; | |
2208 | ||
2209 | return NGX_OK; | |
2210 | ||
2211 | #else | |
2212 | ||
2213 | f->script_name = r->uri; | |
2214 | ||
2215 | return NGX_OK; | |
2216 | ||
2217 | #endif | |
2109 | 2218 | } |
2110 | 2219 | |
2111 | 2220 | |
2167 | 2276 | } |
2168 | 2277 | |
2169 | 2278 | return NGX_CONF_OK; |
2279 | } | |
2280 | ||
2281 | ||
2282 | static char * | |
2283 | ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
2284 | { | |
2285 | #if (NGX_PCRE) | |
2286 | ngx_http_fastcgi_loc_conf_t *flcf = conf; | |
2287 | ||
2288 | ngx_int_t n; | |
2289 | ngx_str_t *value, err; | |
2290 | u_char errstr[NGX_MAX_CONF_ERRSTR]; | |
2291 | ||
2292 | value = cf->args->elts; | |
2293 | ||
2294 | flcf->split_name = value[1]; | |
2295 | ||
2296 | err.len = NGX_MAX_CONF_ERRSTR; | |
2297 | err.data = errstr; | |
2298 | ||
2299 | flcf->split_regex = ngx_regex_compile(&value[1], 0, cf->pool, &err); | |
2300 | ||
2301 | if (flcf->split_regex == NULL) { | |
2302 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); | |
2303 | return NGX_CONF_ERROR; | |
2304 | } | |
2305 | ||
2306 | n = ngx_regex_capture_count(flcf->split_regex); | |
2307 | ||
2308 | if (n < 0) { | |
2309 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2310 | ngx_regex_capture_count_n " failed for " | |
2311 | "pattern \"%V\"", &value[1]); | |
2312 | return NGX_CONF_ERROR; | |
2313 | } | |
2314 | ||
2315 | if (n != 2) { | |
2316 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2317 | "pattern \"%V\" must have 2 captures", &value[1]); | |
2318 | return NGX_CONF_ERROR; | |
2319 | } | |
2320 | ||
2321 | return NGX_CONF_OK; | |
2322 | ||
2323 | #else | |
2324 | ||
2325 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2326 | "\"%V\" requires PCRE library", &cmd->name); | |
2327 | return NGX_CONF_ERROR; | |
2328 | ||
2329 | #endif | |
2170 | 2330 | } |
2171 | 2331 | |
2172 | 2332 |