comparison src/http/modules/ngx_http_range_filter_module.c @ 396:77df96611112

Merge with current.
author Maxim Dounin <mdounin@mdounin.ru>
date Tue, 05 Aug 2008 02:12:51 +0400
parents 1d9bef53cd8e 0b6053502c55
children 44a61c599bb2
comparison
equal deleted inserted replaced
391:1d9bef53cd8e 396:77df96611112
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,
62 ngx_http_range_filter_ctx_t *ctx);
63 static ngx_int_t ngx_http_range_singlepart_header(ngx_http_request_t *r,
64 ngx_http_range_filter_ctx_t *ctx);
65 static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r,
66 ngx_http_range_filter_ctx_t *ctx);
67 static ngx_int_t ngx_http_range_not_satisfiable(ngx_http_request_t *r);
68 static ngx_int_t ngx_http_range_test_overlapped(ngx_http_request_t *r,
69 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in);
70 static ngx_int_t ngx_http_range_singlepart_body(ngx_http_request_t *r,
71 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in,
72 ngx_http_output_body_filter_pt ngx_http_next_body_filter);
73 static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r,
74 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in,
75 ngx_http_output_body_filter_pt ngx_http_next_body_filter);
76
61 static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf); 77 static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf);
62 static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf); 78 static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf);
63 static ngx_int_t ngx_http_range_late_filter_init(ngx_conf_t *cf); 79 static ngx_int_t ngx_http_range_late_filter_init(ngx_conf_t *cf);
64 80
65 81
162 178
163 179
164 static ngx_int_t 180 static ngx_int_t
165 ngx_http_range_header_filter(ngx_http_request_t *r) 181 ngx_http_range_header_filter(ngx_http_request_t *r)
166 { 182 {
167 u_char *p;
168 size_t len;
169 off_t start, end;
170 time_t if_range; 183 time_t if_range;
171 ngx_int_t rc; 184 ngx_int_t rc;
172 ngx_uint_t suffix, i;
173 ngx_atomic_uint_t boundary;
174 ngx_table_elt_t *content_range;
175 ngx_http_range_t *range;
176 ngx_http_range_filter_ctx_t *ctx; 185 ngx_http_range_filter_ctx_t *ctx;
177 186
178 if (r->http_version < NGX_HTTP_VERSION_10 187 if (r->http_version < NGX_HTTP_VERSION_10
179 || r->headers_out.status != NGX_HTTP_OK 188 || r->headers_out.status != NGX_HTTP_OK
180 || r != r->main 189 || r != r->main
216 == NGX_ERROR) 225 == NGX_ERROR)
217 { 226 {
218 return NGX_ERROR; 227 return NGX_ERROR;
219 } 228 }
220 229
221 rc = 0; 230 rc = ngx_http_range_parse(r, ctx);
222 range = NULL; 231
232 if (rc == NGX_OK) {
233
234 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
235
236 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
237
238 if (ctx->ranges.nelts == 1) {
239 return ngx_http_range_singlepart_header(r, ctx);
240 }
241
242 return ngx_http_range_multipart_header(r, ctx);
243 }
244
245 if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) {
246 return ngx_http_range_not_satisfiable(r);
247 }
248
249 /* rc == NGX_ERROR */
250
251 return rc;
252
253 next_filter:
254
255 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers);
256 if (r->headers_out.accept_ranges == NULL) {
257 return NGX_ERROR;
258 }
259
260 r->headers_out.accept_ranges->hash = 1;
261 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1;
262 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges";
263 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1;
264 r->headers_out.accept_ranges->value.data = (u_char *) "bytes";
265
266 return ngx_http_next_header_filter(r);
267 }
268
269
270 ngx_int_t
271 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx)
272 {
273 u_char *p;
274 off_t start, end;
275 ngx_uint_t suffix;
276 ngx_http_range_t *range;
277
223 p = r->headers_in.range->value.data + 6; 278 p = r->headers_in.range->value.data + 6;
224 279
225 for ( ;; ) { 280 for ( ;; ) {
226 start = 0; 281 start = 0;
227 end = 0; 282 end = 0;
229 284
230 while (*p == ' ') { p++; } 285 while (*p == ' ') { p++; }
231 286
232 if (*p != '-') { 287 if (*p != '-') {
233 if (*p < '0' || *p > '9') { 288 if (*p < '0' || *p > '9') {
234 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; 289 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
235 break;
236 } 290 }
237 291
238 while (*p >= '0' && *p <= '9') { 292 while (*p >= '0' && *p <= '9') {
239 start = start * 10 + *p++ - '0'; 293 start = start * 10 + *p++ - '0';
240 } 294 }
241 295
242 while (*p == ' ') { p++; } 296 while (*p == ' ') { p++; }
243 297
244 if (*p++ != '-') { 298 if (*p++ != '-') {
245 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; 299 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
246 break;
247 } 300 }
248 301
249 if (start >= r->headers_out.content_length_n) { 302 if (start >= r->headers_out.content_length_n) {
250 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; 303 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
251 break;
252 } 304 }
253 305
254 while (*p == ' ') { p++; } 306 while (*p == ' ') { p++; }
255 307
256 if (*p == ',' || *p == '\0') { 308 if (*p == ',' || *p == '\0') {
261 313
262 range->start = start; 314 range->start = start;
263 range->end = r->headers_out.content_length_n; 315 range->end = r->headers_out.content_length_n;
264 316
265 if (*p++ != ',') { 317 if (*p++ != ',') {
266 break; 318 return NGX_OK;
267 } 319 }
268 320
269 continue; 321 continue;
270 } 322 }
271 323
273 suffix = 1; 325 suffix = 1;
274 p++; 326 p++;
275 } 327 }
276 328
277 if (*p < '0' || *p > '9') { 329 if (*p < '0' || *p > '9') {
278 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; 330 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
279 break;
280 } 331 }
281 332
282 while (*p >= '0' && *p <= '9') { 333 while (*p >= '0' && *p <= '9') {
283 end = end * 10 + *p++ - '0'; 334 end = end * 10 + *p++ - '0';
284 } 335 }
285 336
286 while (*p == ' ') { p++; } 337 while (*p == ' ') { p++; }
287 338
288 if (*p != ',' && *p != '\0') { 339 if (*p != ',' && *p != '\0') {
289 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; 340 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
290 break;
291 } 341 }
292 342
293 if (suffix) { 343 if (suffix) {
294 start = r->headers_out.content_length_n - end; 344 start = r->headers_out.content_length_n - end;
295 end = r->headers_out.content_length_n - 1; 345 end = r->headers_out.content_length_n - 1;
296 } 346 }
297 347
298 if (start > end) { 348 if (start > end) {
299 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; 349 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
300 break;
301 } 350 }
302 351
303 range = ngx_array_push(&ctx->ranges); 352 range = ngx_array_push(&ctx->ranges);
304 if (range == NULL) { 353 if (range == NULL) {
305 return NGX_ERROR; 354 return NGX_ERROR;
317 } else { 366 } else {
318 range->end = end + 1; 367 range->end = end + 1;
319 } 368 }
320 369
321 if (*p++ != ',') { 370 if (*p++ != ',') {
322 break; 371 return NGX_OK;
323 } 372 }
324 } 373 }
325 374 }
326 if (rc) { 375
327 376
328 /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ 377 static ngx_int_t
329 378 ngx_http_range_singlepart_header(ngx_http_request_t *r,
330 r->headers_out.status = rc; 379 ngx_http_range_filter_ctx_t *ctx)
331 380 {
332 content_range = ngx_list_push(&r->headers_out.headers); 381 ngx_table_elt_t *content_range;
333 if (content_range == NULL) { 382 ngx_http_range_t *range;
334 return NGX_ERROR; 383
335 } 384 content_range = ngx_list_push(&r->headers_out.headers);
336 385 if (content_range == NULL) {
337 r->headers_out.content_range = content_range; 386 return NGX_ERROR;
338 387 }
339 content_range->hash = 1; 388
340 content_range->key.len = sizeof("Content-Range") - 1; 389 r->headers_out.content_range = content_range;
341 content_range->key.data = (u_char *) "Content-Range"; 390
342 391 content_range->hash = 1;
343 content_range->value.data = ngx_pnalloc(r->pool, 392 content_range->key.len = sizeof("Content-Range") - 1;
344 sizeof("bytes */") - 1 + NGX_OFF_T_LEN); 393 content_range->key.data = (u_char *) "Content-Range";
345 if (content_range->value.data == NULL) { 394
346 return NGX_ERROR; 395 content_range->value.data = ngx_pnalloc(r->pool,
347 } 396 sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN);
348 397 if (content_range->value.data == NULL) {
349 content_range->value.len = ngx_sprintf(content_range->value.data, 398 return NGX_ERROR;
350 "bytes */%O", 399 }
351 r->headers_out.content_length_n) 400
352 - content_range->value.data; 401 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */
353 402
354 ngx_http_clear_content_length(r); 403 range = ctx->ranges.elts;
355 404
356 return rc; 405 content_range->value.len = ngx_sprintf(content_range->value.data,
357 } 406 "bytes %O-%O/%O",
358 407 range->start, range->end - 1,
359 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); 408 r->headers_out.content_length_n)
360 409 - content_range->value.data;
361 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; 410
362 411 r->headers_out.content_length_n = range->end - range->start;
363 if (ctx->ranges.nelts == 1) { 412
364 413 if (r->headers_out.content_length) {
365 content_range = ngx_list_push(&r->headers_out.headers); 414 r->headers_out.content_length->hash = 0;
366 if (content_range == NULL) { 415 r->headers_out.content_length = NULL;
367 return NGX_ERROR; 416 }
368 } 417
369 418 return ngx_http_next_header_filter(r);
370 r->headers_out.content_range = content_range; 419 }
371 420
372 content_range->hash = 1; 421
373 content_range->key.len = sizeof("Content-Range") - 1; 422 static ngx_int_t
374 content_range->key.data = (u_char *) "Content-Range"; 423 ngx_http_range_multipart_header(ngx_http_request_t *r,
375 424 ngx_http_range_filter_ctx_t *ctx)
376 content_range->value.data = 425 {
377 ngx_pnalloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); 426 size_t len;
378 if (content_range->value.data == NULL) { 427 ngx_uint_t i;
379 return NGX_ERROR; 428 ngx_http_range_t *range;
380 } 429 ngx_atomic_uint_t boundary;
381
382 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */
383
384 content_range->value.len = ngx_sprintf(content_range->value.data,
385 "bytes %O-%O/%O",
386 range->start, range->end - 1,
387 r->headers_out.content_length_n)
388 - content_range->value.data;
389
390 r->headers_out.content_length_n = range->end - range->start;
391
392 if (r->headers_out.content_length) {
393 r->headers_out.content_length->hash = 0;
394 r->headers_out.content_length = NULL;
395 }
396
397 return ngx_http_next_header_filter(r);
398 }
399
400
401 /* TODO: what if no content_type ?? */
402 430
403 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN 431 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
404 + sizeof(CRLF "Content-Type: ") - 1 432 + sizeof(CRLF "Content-Type: ") - 1
405 + r->headers_out.content_type.len 433 + r->headers_out.content_type.len
406 + sizeof(CRLF "Content-Range: bytes ") - 1; 434 + sizeof(CRLF "Content-Range: bytes ") - 1;
434 &r->headers_out.charset) 462 &r->headers_out.charset)
435 - ctx->boundary_header.data; 463 - ctx->boundary_header.data;
436 464
437 r->headers_out.charset.len = 0; 465 r->headers_out.charset.len = 0;
438 466
439 } else { 467 } else if (r->headers_out.content_type.len) {
440 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, 468 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
441 CRLF "--%0muA" CRLF 469 CRLF "--%0muA" CRLF
442 "Content-Type: %V" CRLF 470 "Content-Type: %V" CRLF
443 "Content-Range: bytes ", 471 "Content-Range: bytes ",
444 boundary, 472 boundary,
445 &r->headers_out.content_type) 473 &r->headers_out.content_type)
446 - ctx->boundary_header.data; 474 - ctx->boundary_header.data;
475
476 } else {
477 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
478 CRLF "--%0muA" CRLF
479 "Content-Range: bytes ",
480 boundary)
481 - ctx->boundary_header.data;
447 } 482 }
448 483
449 r->headers_out.content_type.data = 484 r->headers_out.content_type.data =
450 ngx_pnalloc(r->pool, 485 ngx_pnalloc(r->pool,
451 sizeof("Content-Type: multipart/byteranges; boundary=") - 1 486 sizeof("Content-Type: multipart/byteranges; boundary=") - 1
496 r->headers_out.content_length->hash = 0; 531 r->headers_out.content_length->hash = 0;
497 r->headers_out.content_length = NULL; 532 r->headers_out.content_length = NULL;
498 } 533 }
499 534
500 return ngx_http_next_header_filter(r); 535 return ngx_http_next_header_filter(r);
501 536 }
502 next_filter: 537
503 538
504 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); 539 static ngx_int_t
505 if (r->headers_out.accept_ranges == NULL) { 540 ngx_http_range_not_satisfiable(ngx_http_request_t *r)
506 return NGX_ERROR; 541 {
507 } 542 ngx_table_elt_t *content_range;
508 543
509 r->headers_out.accept_ranges->hash = 1; 544 r->headers_out.status = NGX_HTTP_RANGE_NOT_SATISFIABLE;
510 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; 545
511 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; 546 content_range = ngx_list_push(&r->headers_out.headers);
512 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; 547 if (content_range == NULL) {
513 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; 548 return NGX_ERROR;
514 549 }
515 return ngx_http_next_header_filter(r); 550
551 r->headers_out.content_range = content_range;
552
553 content_range->hash = 1;
554 content_range->key.len = sizeof("Content-Range") - 1;
555 content_range->key.data = (u_char *) "Content-Range";
556
557 content_range->value.data = ngx_pnalloc(r->pool,
558 sizeof("bytes */") - 1 + NGX_OFF_T_LEN);
559 if (content_range->value.data == NULL) {
560 return NGX_ERROR;
561 }
562
563 content_range->value.len = ngx_sprintf(content_range->value.data,
564 "bytes */%O",
565 r->headers_out.content_length_n)
566 - content_range->value.data;
567
568 ngx_http_clear_content_length(r);
569
570 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
516 } 571 }
517 572
518 573
519 static ngx_int_t 574 static ngx_int_t
520 ngx_http_range_body_generic_filter(ngx_http_request_t *r, ngx_chain_t *in, 575 ngx_http_range_body_generic_filter(ngx_http_request_t *r, ngx_chain_t *in,
521 ngx_http_output_body_filter_pt ngx_http_next_body_filter) 576 ngx_http_output_body_filter_pt ngx_http_next_body_filter)
522 { 577 {
523 off_t start, last;
524 ngx_buf_t *b, *buf;
525 ngx_uint_t i;
526 ngx_chain_t *out, *cl, *hcl, *rcl, *dcl, **ll;
527 ngx_http_range_t *range;
528 ngx_http_range_filter_ctx_t *ctx; 578 ngx_http_range_filter_ctx_t *ctx;
529 579
530 if (in == NULL) { 580 if (in == NULL) {
531 return ngx_http_next_body_filter(r, in); 581 return ngx_http_next_body_filter(r, in);
532 } 582 }
535 585
536 if (ctx == NULL) { 586 if (ctx == NULL) {
537 return ngx_http_next_body_filter(r, in); 587 return ngx_http_next_body_filter(r, in);
538 } 588 }
539 589
540 buf = in->buf; 590 if (ctx->ranges.nelts == 1) {
591 return ngx_http_range_singlepart_body(r, ctx, in,
592 ngx_http_next_body_filter);
593 }
594
595 /*
596 * multipart ranges are supported only if whole body is in a single buffer
597 */
541 598
542 if (ngx_buf_special(in->buf)) { 599 if (ngx_buf_special(in->buf)) {
543 return ngx_http_next_body_filter(r, in); 600 return ngx_http_next_body_filter(r, in);
544 } 601 }
545 602
546 range = ctx->ranges.elts; 603 if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) {
547 604 return NGX_ERROR;
548 if (ctx->ranges.nelts > 1) { 605 }
549 goto multipart; 606
550 } 607 return ngx_http_range_multipart_body(r, ctx, in,
551 608 ngx_http_next_body_filter);
552 /* 609 }
553 * the optimized version for the responses 610
554 * that are passed in the single buffer 611
555 */ 612 static ngx_int_t
556 613 ngx_http_range_test_overlapped(ngx_http_request_t *r,
557 out = NULL; 614 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in)
558 ll = &out; 615 {
559 616 off_t start, last;
560 for (cl = in; cl; cl = cl->next) { 617 ngx_buf_t *buf;
561 618 ngx_uint_t i;
562 buf = cl->buf; 619 ngx_http_range_t *range;
563
564 start = ctx->offset;
565 last = ctx->offset + ngx_buf_size(buf);
566
567 ctx->offset = last;
568
569 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
570 "range body filter: %O-%O", start, last);
571
572 if (ngx_buf_special(buf)) {
573 /* pass anyway */
574 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
575 "range body filter: pass special");
576 *ll = cl;
577 ll = &cl->next;
578 continue;
579 }
580
581 if (range->end <= start || range->start >= last) {
582 /* skip buffer */
583 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
584 "range body filter: skip");
585 buf->pos = buf->last;
586 continue;
587 }
588
589 if (range->start > start) {
590 if (buf->in_file) {
591 buf->file_pos += range->start - start;
592 }
593 if (ngx_buf_in_memory(buf)) {
594 buf->pos += (size_t) (range->start - start);
595 }
596 }
597
598 if (range->end <= last) {
599 if (buf->in_file) {
600 buf->file_last -= last - range->end;
601 }
602 if (ngx_buf_in_memory(buf)) {
603 buf->last -= (size_t) (last - range->end);
604 }
605
606 /* we are done */
607
608 buf->last_buf = 1;
609 *ll = cl;
610 cl->next = NULL;
611
612 break;
613 }
614
615 *ll = cl;
616 ll = &cl->next;
617 }
618
619 if (out == NULL) {
620 return NGX_OK;
621 }
622
623 return ngx_http_next_body_filter(r, out);
624
625 multipart:
626 620
627 if (ctx->offset) { 621 if (ctx->offset) {
628 goto overlapped; 622 goto overlapped;
629 } 623 }
624
625 buf = in->buf;
630 626
631 if (!buf->last_buf) { 627 if (!buf->last_buf) {
632 628
633 if (buf->in_file) { 629 if (buf->in_file) {
634 start = buf->file_pos + ctx->offset; 630 start = buf->file_pos + ctx->offset;
637 } else { 633 } else {
638 start = buf->pos - buf->start + ctx->offset; 634 start = buf->pos - buf->start + ctx->offset;
639 last = buf->last - buf->start + ctx->offset; 635 last = buf->last - buf->start + ctx->offset;
640 } 636 }
641 637
638 range = ctx->ranges.elts;
642 for (i = 0; i < ctx->ranges.nelts; i++) { 639 for (i = 0; i < ctx->ranges.nelts; i++) {
643 if (start > range[i].start || last < range[i].end) { 640 if (start > range[i].start || last < range[i].end) {
644 goto overlapped; 641 goto overlapped;
645 } 642 }
646 } 643 }
647 } 644 }
648 645
649 ctx->offset = ngx_buf_size(buf); 646 ctx->offset = ngx_buf_size(buf);
650 647
648 return NGX_OK;
649
650 overlapped:
651
652 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
653 "range in overlapped buffers");
654
655 return NGX_ERROR;
656 }
657
658
659 static ngx_int_t
660 ngx_http_range_singlepart_body(ngx_http_request_t *r,
661 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in,
662 ngx_http_output_body_filter_pt ngx_http_next_body_filter)
663 {
664 off_t start, last;
665 ngx_buf_t *buf;
666 ngx_chain_t *out, *cl, **ll;
667 ngx_http_range_t *range;
668
669 out = NULL;
651 ll = &out; 670 ll = &out;
671 range = ctx->ranges.elts;
672
673 for (cl = in; cl; cl = cl->next) {
674
675 buf = cl->buf;
676
677 start = ctx->offset;
678 last = ctx->offset + ngx_buf_size(buf);
679
680 ctx->offset = last;
681
682 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
683 "http range body buf: %O-%O", start, last);
684
685 if (ngx_buf_special(buf)) {
686 *ll = cl;
687 ll = &cl->next;
688 continue;
689 }
690
691 if (range->end <= start || range->start >= last) {
692
693 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
694 "http range body skip");
695
696 buf->pos = buf->last;
697 continue;
698 }
699
700 if (range->start > start) {
701
702 if (buf->in_file) {
703 buf->file_pos += range->start - start;
704 }
705
706 if (ngx_buf_in_memory(buf)) {
707 buf->pos += (size_t) (range->start - start);
708 }
709 }
710
711 if (range->end <= last) {
712
713 if (buf->in_file) {
714 buf->file_last -= last - range->end;
715 }
716
717 if (ngx_buf_in_memory(buf)) {
718 buf->last -= (size_t) (last - range->end);
719 }
720
721 buf->last_buf = 1;
722 *ll = cl;
723 cl->next = NULL;
724
725 break;
726 }
727
728 *ll = cl;
729 ll = &cl->next;
730 }
731
732 if (out == NULL) {
733 return NGX_OK;
734 }
735
736 return ngx_http_next_body_filter(r, out);
737 }
738
739
740 static ngx_int_t
741 ngx_http_range_multipart_body(ngx_http_request_t *r,
742 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in,
743 ngx_http_output_body_filter_pt ngx_http_next_body_filter)
744 {
745 ngx_buf_t *b, *buf;
746 ngx_uint_t i;
747 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll;
748 ngx_http_range_t *range;
749
750 ll = &out;
751 buf = in->buf;
752 range = ctx->ranges.elts;
652 753
653 for (i = 0; i < ctx->ranges.nelts; i++) { 754 for (i = 0; i < ctx->ranges.nelts; i++) {
654 755
655 /* 756 /*
656 * The boundary header of the range: 757 * The boundary header of the range:
762 hcl->next = NULL; 863 hcl->next = NULL;
763 864
764 *ll = hcl; 865 *ll = hcl;
765 866
766 return ngx_http_next_body_filter(r, out); 867 return ngx_http_next_body_filter(r, out);
767
768 overlapped:
769
770 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
771 "range in overlapped buffers");
772
773 return NGX_ERROR;
774 } 868 }
775 869
776 870
777 static ngx_int_t 871 static ngx_int_t
778 ngx_http_range_body_early_filter(ngx_http_request_t *r, ngx_chain_t *in) 872 ngx_http_range_body_early_filter(ngx_http_request_t *r, ngx_chain_t *in)