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,