Mercurial > hg > nginx-vendor-current
comparison src/http/modules/ngx_http_range_filter_module.c @ 636:943566b4d82e NGINX_1_1_2
nginx 1.1.2
*) Change: now if total size of all ranges is greater than source
response size, then nginx disables ranges and returns just the source
response.
*) Feature: the "max_ranges" directive.
*) Bugfix: the "ssl_verify_client", "ssl_verify_depth", and
"ssl_prefer_server_ciphers" directives might work incorrectly if SNI
was used.
*) Bugfix: in the "proxy/fastcgi/scgi/uwsgi_ignore_client_abort"
directives.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 05 Sep 2011 00:00:00 +0400 |
parents | 8246d8a2c2be |
children | d0f7a625f27c |
comparison
equal
deleted
inserted
replaced
635:5d94f8b3e01d | 636:943566b4d82e |
---|---|
56 ngx_str_t boundary_header; | 56 ngx_str_t boundary_header; |
57 ngx_array_t ranges; | 57 ngx_array_t ranges; |
58 } ngx_http_range_filter_ctx_t; | 58 } ngx_http_range_filter_ctx_t; |
59 | 59 |
60 | 60 |
61 ngx_int_t ngx_http_range_parse(ngx_http_request_t *r, | 61 static ngx_int_t ngx_http_range_parse(ngx_http_request_t *r, |
62 ngx_http_range_filter_ctx_t *ctx); | 62 ngx_http_range_filter_ctx_t *ctx, ngx_uint_t ranges); |
63 static ngx_int_t ngx_http_range_singlepart_header(ngx_http_request_t *r, | 63 static ngx_int_t ngx_http_range_singlepart_header(ngx_http_request_t *r, |
64 ngx_http_range_filter_ctx_t *ctx); | 64 ngx_http_range_filter_ctx_t *ctx); |
65 static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r, | 65 static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r, |
66 ngx_http_range_filter_ctx_t *ctx); | 66 ngx_http_range_filter_ctx_t *ctx); |
67 static ngx_int_t ngx_http_range_not_satisfiable(ngx_http_request_t *r); | 67 static ngx_int_t ngx_http_range_not_satisfiable(ngx_http_request_t *r); |
144 | 144 |
145 static ngx_int_t | 145 static ngx_int_t |
146 ngx_http_range_header_filter(ngx_http_request_t *r) | 146 ngx_http_range_header_filter(ngx_http_request_t *r) |
147 { | 147 { |
148 time_t if_range; | 148 time_t if_range; |
149 ngx_int_t rc; | 149 ngx_http_core_loc_conf_t *clcf; |
150 ngx_http_range_filter_ctx_t *ctx; | 150 ngx_http_range_filter_ctx_t *ctx; |
151 | 151 |
152 if (r->http_version < NGX_HTTP_VERSION_10 | 152 if (r->http_version < NGX_HTTP_VERSION_10 |
153 || r->headers_out.status != NGX_HTTP_OK | 153 || r->headers_out.status != NGX_HTTP_OK |
154 || r != r->main | 154 || r != r->main |
156 || !r->allow_ranges) | 156 || !r->allow_ranges) |
157 { | 157 { |
158 return ngx_http_next_header_filter(r); | 158 return ngx_http_next_header_filter(r); |
159 } | 159 } |
160 | 160 |
161 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
162 | |
163 if (clcf->max_ranges == 0) { | |
164 return ngx_http_next_header_filter(r); | |
165 } | |
166 | |
161 if (r->headers_in.range == NULL | 167 if (r->headers_in.range == NULL |
162 || r->headers_in.range->value.len < 7 | 168 || r->headers_in.range->value.len < 7 |
163 || ngx_strncasecmp(r->headers_in.range->value.data, | 169 || ngx_strncasecmp(r->headers_in.range->value.data, |
164 (u_char *) "bytes=", 6) | 170 (u_char *) "bytes=", 6) |
165 != 0) | 171 != 0) |
190 != NGX_OK) | 196 != NGX_OK) |
191 { | 197 { |
192 return NGX_ERROR; | 198 return NGX_ERROR; |
193 } | 199 } |
194 | 200 |
195 rc = ngx_http_range_parse(r, ctx); | 201 switch (ngx_http_range_parse(r, ctx, clcf->max_ranges)) { |
196 | 202 |
197 if (rc == NGX_OK) { | 203 case NGX_OK: |
198 | |
199 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); | 204 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); |
200 | 205 |
201 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; | 206 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; |
202 r->headers_out.status_line.len = 0; | 207 r->headers_out.status_line.len = 0; |
203 | 208 |
204 if (ctx->ranges.nelts == 1) { | 209 if (ctx->ranges.nelts == 1) { |
205 return ngx_http_range_singlepart_header(r, ctx); | 210 return ngx_http_range_singlepart_header(r, ctx); |
206 } | 211 } |
207 | 212 |
208 return ngx_http_range_multipart_header(r, ctx); | 213 return ngx_http_range_multipart_header(r, ctx); |
209 } | 214 |
210 | 215 case NGX_HTTP_RANGE_NOT_SATISFIABLE: |
211 if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) { | |
212 return ngx_http_range_not_satisfiable(r); | 216 return ngx_http_range_not_satisfiable(r); |
213 } | 217 |
214 | 218 case NGX_ERROR: |
215 /* rc == NGX_ERROR */ | 219 return NGX_ERROR; |
216 | 220 |
217 return rc; | 221 default: /* NGX_DECLINED */ |
222 break; | |
223 } | |
218 | 224 |
219 next_filter: | 225 next_filter: |
220 | 226 |
221 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); | 227 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); |
222 if (r->headers_out.accept_ranges == NULL) { | 228 if (r->headers_out.accept_ranges == NULL) { |
229 | 235 |
230 return ngx_http_next_header_filter(r); | 236 return ngx_http_next_header_filter(r); |
231 } | 237 } |
232 | 238 |
233 | 239 |
234 ngx_int_t | 240 static ngx_int_t |
235 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) | 241 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, |
242 ngx_uint_t ranges) | |
236 { | 243 { |
237 u_char *p; | 244 u_char *p; |
238 off_t start, end; | 245 off_t start, end, size, content_length; |
239 ngx_uint_t suffix; | 246 ngx_uint_t suffix; |
240 ngx_http_range_t *range; | 247 ngx_http_range_t *range; |
241 | 248 |
242 p = r->headers_in.range->value.data + 6; | 249 p = r->headers_in.range->value.data + 6; |
250 size = 0; | |
251 content_length = r->headers_out.content_length_n; | |
243 | 252 |
244 for ( ;; ) { | 253 for ( ;; ) { |
245 start = 0; | 254 start = 0; |
246 end = 0; | 255 end = 0; |
247 suffix = 0; | 256 suffix = 0; |
261 | 270 |
262 if (*p++ != '-') { | 271 if (*p++ != '-') { |
263 return NGX_HTTP_RANGE_NOT_SATISFIABLE; | 272 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
264 } | 273 } |
265 | 274 |
266 if (start >= r->headers_out.content_length_n) { | |
267 return NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
268 } | |
269 | |
270 while (*p == ' ') { p++; } | 275 while (*p == ' ') { p++; } |
271 | 276 |
272 if (*p == ',' || *p == '\0') { | 277 if (*p == ',' || *p == '\0') { |
273 range = ngx_array_push(&ctx->ranges); | 278 end = content_length; |
274 if (range == NULL) { | 279 goto found; |
275 return NGX_ERROR; | |
276 } | |
277 | |
278 range->start = start; | |
279 range->end = r->headers_out.content_length_n; | |
280 | |
281 if (*p++ != ',') { | |
282 return NGX_OK; | |
283 } | |
284 | |
285 continue; | |
286 } | 280 } |
287 | 281 |
288 } else { | 282 } else { |
289 suffix = 1; | 283 suffix = 1; |
290 p++; | 284 p++; |
303 if (*p != ',' && *p != '\0') { | 297 if (*p != ',' && *p != '\0') { |
304 return NGX_HTTP_RANGE_NOT_SATISFIABLE; | 298 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
305 } | 299 } |
306 | 300 |
307 if (suffix) { | 301 if (suffix) { |
308 start = r->headers_out.content_length_n - end; | 302 start = content_length - end; |
309 end = r->headers_out.content_length_n - 1; | 303 end = content_length - 1; |
310 } | 304 } |
311 | 305 |
312 if (start > end) { | 306 if (end >= content_length) { |
313 return NGX_HTTP_RANGE_NOT_SATISFIABLE; | 307 end = content_length; |
314 } | |
315 | |
316 range = ngx_array_push(&ctx->ranges); | |
317 if (range == NULL) { | |
318 return NGX_ERROR; | |
319 } | |
320 | |
321 range->start = start; | |
322 | |
323 if (end >= r->headers_out.content_length_n) { | |
324 /* | |
325 * Download Accelerator sends the last byte position | |
326 * that equals to the file length | |
327 */ | |
328 range->end = r->headers_out.content_length_n; | |
329 | 308 |
330 } else { | 309 } else { |
331 range->end = end + 1; | 310 end++; |
311 } | |
312 | |
313 found: | |
314 | |
315 if (start < end) { | |
316 range = ngx_array_push(&ctx->ranges); | |
317 if (range == NULL) { | |
318 return NGX_ERROR; | |
319 } | |
320 | |
321 range->start = start; | |
322 range->end = end; | |
323 | |
324 size += end - start; | |
325 | |
326 if (ranges-- == 0) { | |
327 return NGX_DECLINED; | |
328 } | |
332 } | 329 } |
333 | 330 |
334 if (*p++ != ',') { | 331 if (*p++ != ',') { |
335 return NGX_OK; | 332 break; |
336 } | 333 } |
337 } | 334 } |
335 | |
336 if (ctx->ranges.nelts == 0) { | |
337 return NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
338 } | |
339 | |
340 if (size > content_length) { | |
341 return NGX_DECLINED; | |
342 } | |
343 | |
344 return NGX_OK; | |
338 } | 345 } |
339 | 346 |
340 | 347 |
341 static ngx_int_t | 348 static ngx_int_t |
342 ngx_http_range_singlepart_header(ngx_http_request_t *r, | 349 ngx_http_range_singlepart_header(ngx_http_request_t *r, |