Mercurial > hg > nginx-ranges
comparison src/http/modules/ngx_http_range_filter_module.c @ 392:0b6053502c55 NGINX_0_7_7
nginx 0.7.7
*) Change: now the EAGAIN error returned by connect() is not considered
as temporary error.
*) Change: now the $ssl_client_cert variable value is a certificate
with TAB character intended before each line except first one; an
unchanged certificate is available in the $ssl_client_raw_cert
variable.
*) Feature: the "ask" parameter in the "ssl_verify_client" directive.
*) Feature: byte-range processing improvements.
Thanks to Maxim Dounin.
*) Feature: the "directio" directive.
*) Feature: MacOSX 1.5 sendfile() support.
*) Bugfix: now in MacOSX and Cygwin locations are tested in case
insensitive mode; however, the compare is provided by single-byte
locales only.
*) Bugfix: mail proxy SSL connections hanged, if select, poll, or
/dev/poll methods were used.
*) Bugfix: UTF-8 encoding usage in the ngx_http_autoindex_module.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Wed, 30 Jul 2008 00:00:00 +0400 |
parents | 984bb0b1399b |
children | 77df96611112 b246022ef454 |
comparison
equal
deleted
inserted
replaced
389:930e48a26dde | 392:0b6053502c55 |
---|---|
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 static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, | |
73 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); | |
74 | |
61 static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf); | 75 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); | 76 static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf); |
63 | 77 |
64 | 78 |
65 static ngx_http_module_t ngx_http_range_header_filter_module_ctx = { | 79 static ngx_http_module_t ngx_http_range_header_filter_module_ctx = { |
129 | 143 |
130 | 144 |
131 static ngx_int_t | 145 static ngx_int_t |
132 ngx_http_range_header_filter(ngx_http_request_t *r) | 146 ngx_http_range_header_filter(ngx_http_request_t *r) |
133 { | 147 { |
134 u_char *p; | |
135 size_t len; | |
136 off_t start, end; | |
137 time_t if_range; | 148 time_t if_range; |
138 ngx_int_t rc; | 149 ngx_int_t rc; |
139 ngx_uint_t suffix, i; | |
140 ngx_atomic_uint_t boundary; | |
141 ngx_table_elt_t *content_range; | |
142 ngx_http_range_t *range; | |
143 ngx_http_range_filter_ctx_t *ctx; | 150 ngx_http_range_filter_ctx_t *ctx; |
144 | 151 |
145 if (r->http_version < NGX_HTTP_VERSION_10 | 152 if (r->http_version < NGX_HTTP_VERSION_10 |
146 || r->headers_out.status != NGX_HTTP_OK | 153 || r->headers_out.status != NGX_HTTP_OK |
147 || r != r->main | 154 || r != r->main |
183 == NGX_ERROR) | 190 == NGX_ERROR) |
184 { | 191 { |
185 return NGX_ERROR; | 192 return NGX_ERROR; |
186 } | 193 } |
187 | 194 |
188 rc = 0; | 195 rc = ngx_http_range_parse(r, ctx); |
189 range = NULL; | 196 |
197 if (rc == NGX_OK) { | |
198 | |
199 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); | |
200 | |
201 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; | |
202 | |
203 if (ctx->ranges.nelts == 1) { | |
204 return ngx_http_range_singlepart_header(r, ctx); | |
205 } | |
206 | |
207 return ngx_http_range_multipart_header(r, ctx); | |
208 } | |
209 | |
210 if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) { | |
211 return ngx_http_range_not_satisfiable(r); | |
212 } | |
213 | |
214 /* rc == NGX_ERROR */ | |
215 | |
216 return rc; | |
217 | |
218 next_filter: | |
219 | |
220 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); | |
221 if (r->headers_out.accept_ranges == NULL) { | |
222 return NGX_ERROR; | |
223 } | |
224 | |
225 r->headers_out.accept_ranges->hash = 1; | |
226 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; | |
227 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; | |
228 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; | |
229 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; | |
230 | |
231 return ngx_http_next_header_filter(r); | |
232 } | |
233 | |
234 | |
235 ngx_int_t | |
236 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) | |
237 { | |
238 u_char *p; | |
239 off_t start, end; | |
240 ngx_uint_t suffix; | |
241 ngx_http_range_t *range; | |
242 | |
190 p = r->headers_in.range->value.data + 6; | 243 p = r->headers_in.range->value.data + 6; |
191 | 244 |
192 for ( ;; ) { | 245 for ( ;; ) { |
193 start = 0; | 246 start = 0; |
194 end = 0; | 247 end = 0; |
196 | 249 |
197 while (*p == ' ') { p++; } | 250 while (*p == ' ') { p++; } |
198 | 251 |
199 if (*p != '-') { | 252 if (*p != '-') { |
200 if (*p < '0' || *p > '9') { | 253 if (*p < '0' || *p > '9') { |
201 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 254 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
202 break; | |
203 } | 255 } |
204 | 256 |
205 while (*p >= '0' && *p <= '9') { | 257 while (*p >= '0' && *p <= '9') { |
206 start = start * 10 + *p++ - '0'; | 258 start = start * 10 + *p++ - '0'; |
207 } | 259 } |
208 | 260 |
209 while (*p == ' ') { p++; } | 261 while (*p == ' ') { p++; } |
210 | 262 |
211 if (*p++ != '-') { | 263 if (*p++ != '-') { |
212 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 264 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
213 break; | |
214 } | 265 } |
215 | 266 |
216 if (start >= r->headers_out.content_length_n) { | 267 if (start >= r->headers_out.content_length_n) { |
217 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 268 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
218 break; | |
219 } | 269 } |
220 | 270 |
221 while (*p == ' ') { p++; } | 271 while (*p == ' ') { p++; } |
222 | 272 |
223 if (*p == ',' || *p == '\0') { | 273 if (*p == ',' || *p == '\0') { |
228 | 278 |
229 range->start = start; | 279 range->start = start; |
230 range->end = r->headers_out.content_length_n; | 280 range->end = r->headers_out.content_length_n; |
231 | 281 |
232 if (*p++ != ',') { | 282 if (*p++ != ',') { |
233 break; | 283 return NGX_OK; |
234 } | 284 } |
235 | 285 |
236 continue; | 286 continue; |
237 } | 287 } |
238 | 288 |
240 suffix = 1; | 290 suffix = 1; |
241 p++; | 291 p++; |
242 } | 292 } |
243 | 293 |
244 if (*p < '0' || *p > '9') { | 294 if (*p < '0' || *p > '9') { |
245 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 295 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
246 break; | |
247 } | 296 } |
248 | 297 |
249 while (*p >= '0' && *p <= '9') { | 298 while (*p >= '0' && *p <= '9') { |
250 end = end * 10 + *p++ - '0'; | 299 end = end * 10 + *p++ - '0'; |
251 } | 300 } |
252 | 301 |
253 while (*p == ' ') { p++; } | 302 while (*p == ' ') { p++; } |
254 | 303 |
255 if (*p != ',' && *p != '\0') { | 304 if (*p != ',' && *p != '\0') { |
256 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 305 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
257 break; | |
258 } | 306 } |
259 | 307 |
260 if (suffix) { | 308 if (suffix) { |
261 start = r->headers_out.content_length_n - end; | 309 start = r->headers_out.content_length_n - end; |
262 end = r->headers_out.content_length_n - 1; | 310 end = r->headers_out.content_length_n - 1; |
263 } | 311 } |
264 | 312 |
265 if (start > end) { | 313 if (start > end) { |
266 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 314 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
267 break; | |
268 } | 315 } |
269 | 316 |
270 range = ngx_array_push(&ctx->ranges); | 317 range = ngx_array_push(&ctx->ranges); |
271 if (range == NULL) { | 318 if (range == NULL) { |
272 return NGX_ERROR; | 319 return NGX_ERROR; |
284 } else { | 331 } else { |
285 range->end = end + 1; | 332 range->end = end + 1; |
286 } | 333 } |
287 | 334 |
288 if (*p++ != ',') { | 335 if (*p++ != ',') { |
289 break; | 336 return NGX_OK; |
290 } | 337 } |
291 } | 338 } |
292 | 339 } |
293 if (rc) { | 340 |
294 | 341 |
295 /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ | 342 static ngx_int_t |
296 | 343 ngx_http_range_singlepart_header(ngx_http_request_t *r, |
297 r->headers_out.status = rc; | 344 ngx_http_range_filter_ctx_t *ctx) |
298 | 345 { |
299 content_range = ngx_list_push(&r->headers_out.headers); | 346 ngx_table_elt_t *content_range; |
300 if (content_range == NULL) { | 347 ngx_http_range_t *range; |
301 return NGX_ERROR; | 348 |
302 } | 349 content_range = ngx_list_push(&r->headers_out.headers); |
303 | 350 if (content_range == NULL) { |
304 r->headers_out.content_range = content_range; | 351 return NGX_ERROR; |
305 | 352 } |
306 content_range->hash = 1; | 353 |
307 content_range->key.len = sizeof("Content-Range") - 1; | 354 r->headers_out.content_range = content_range; |
308 content_range->key.data = (u_char *) "Content-Range"; | 355 |
309 | 356 content_range->hash = 1; |
310 content_range->value.data = ngx_pnalloc(r->pool, | 357 content_range->key.len = sizeof("Content-Range") - 1; |
311 sizeof("bytes */") - 1 + NGX_OFF_T_LEN); | 358 content_range->key.data = (u_char *) "Content-Range"; |
312 if (content_range->value.data == NULL) { | 359 |
313 return NGX_ERROR; | 360 content_range->value.data = ngx_pnalloc(r->pool, |
314 } | 361 sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); |
315 | 362 if (content_range->value.data == NULL) { |
316 content_range->value.len = ngx_sprintf(content_range->value.data, | 363 return NGX_ERROR; |
317 "bytes */%O", | 364 } |
318 r->headers_out.content_length_n) | 365 |
319 - content_range->value.data; | 366 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ |
320 | 367 |
321 ngx_http_clear_content_length(r); | 368 range = ctx->ranges.elts; |
322 | 369 |
323 return rc; | 370 content_range->value.len = ngx_sprintf(content_range->value.data, |
324 } | 371 "bytes %O-%O/%O", |
325 | 372 range->start, range->end - 1, |
326 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); | 373 r->headers_out.content_length_n) |
327 | 374 - content_range->value.data; |
328 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; | 375 |
329 | 376 r->headers_out.content_length_n = range->end - range->start; |
330 if (ctx->ranges.nelts == 1) { | 377 |
331 | 378 if (r->headers_out.content_length) { |
332 content_range = ngx_list_push(&r->headers_out.headers); | 379 r->headers_out.content_length->hash = 0; |
333 if (content_range == NULL) { | 380 r->headers_out.content_length = NULL; |
334 return NGX_ERROR; | 381 } |
335 } | 382 |
336 | 383 return ngx_http_next_header_filter(r); |
337 r->headers_out.content_range = content_range; | 384 } |
338 | 385 |
339 content_range->hash = 1; | 386 |
340 content_range->key.len = sizeof("Content-Range") - 1; | 387 static ngx_int_t |
341 content_range->key.data = (u_char *) "Content-Range"; | 388 ngx_http_range_multipart_header(ngx_http_request_t *r, |
342 | 389 ngx_http_range_filter_ctx_t *ctx) |
343 content_range->value.data = | 390 { |
344 ngx_pnalloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); | 391 size_t len; |
345 if (content_range->value.data == NULL) { | 392 ngx_uint_t i; |
346 return NGX_ERROR; | 393 ngx_http_range_t *range; |
347 } | 394 ngx_atomic_uint_t boundary; |
348 | |
349 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ | |
350 | |
351 content_range->value.len = ngx_sprintf(content_range->value.data, | |
352 "bytes %O-%O/%O", | |
353 range->start, range->end - 1, | |
354 r->headers_out.content_length_n) | |
355 - content_range->value.data; | |
356 | |
357 r->headers_out.content_length_n = range->end - range->start; | |
358 | |
359 if (r->headers_out.content_length) { | |
360 r->headers_out.content_length->hash = 0; | |
361 r->headers_out.content_length = NULL; | |
362 } | |
363 | |
364 return ngx_http_next_header_filter(r); | |
365 } | |
366 | |
367 | |
368 /* TODO: what if no content_type ?? */ | |
369 | 395 |
370 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN | 396 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN |
371 + sizeof(CRLF "Content-Type: ") - 1 | 397 + sizeof(CRLF "Content-Type: ") - 1 |
372 + r->headers_out.content_type.len | 398 + r->headers_out.content_type.len |
373 + sizeof(CRLF "Content-Range: bytes ") - 1; | 399 + sizeof(CRLF "Content-Range: bytes ") - 1; |
401 &r->headers_out.charset) | 427 &r->headers_out.charset) |
402 - ctx->boundary_header.data; | 428 - ctx->boundary_header.data; |
403 | 429 |
404 r->headers_out.charset.len = 0; | 430 r->headers_out.charset.len = 0; |
405 | 431 |
406 } else { | 432 } else if (r->headers_out.content_type.len) { |
407 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, | 433 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, |
408 CRLF "--%0muA" CRLF | 434 CRLF "--%0muA" CRLF |
409 "Content-Type: %V" CRLF | 435 "Content-Type: %V" CRLF |
410 "Content-Range: bytes ", | 436 "Content-Range: bytes ", |
411 boundary, | 437 boundary, |
412 &r->headers_out.content_type) | 438 &r->headers_out.content_type) |
413 - ctx->boundary_header.data; | 439 - ctx->boundary_header.data; |
440 | |
441 } else { | |
442 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, | |
443 CRLF "--%0muA" CRLF | |
444 "Content-Range: bytes ", | |
445 boundary) | |
446 - ctx->boundary_header.data; | |
414 } | 447 } |
415 | 448 |
416 r->headers_out.content_type.data = | 449 r->headers_out.content_type.data = |
417 ngx_pnalloc(r->pool, | 450 ngx_pnalloc(r->pool, |
418 sizeof("Content-Type: multipart/byteranges; boundary=") - 1 | 451 sizeof("Content-Type: multipart/byteranges; boundary=") - 1 |
463 r->headers_out.content_length->hash = 0; | 496 r->headers_out.content_length->hash = 0; |
464 r->headers_out.content_length = NULL; | 497 r->headers_out.content_length = NULL; |
465 } | 498 } |
466 | 499 |
467 return ngx_http_next_header_filter(r); | 500 return ngx_http_next_header_filter(r); |
468 | 501 } |
469 next_filter: | 502 |
470 | 503 |
471 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); | 504 static ngx_int_t |
472 if (r->headers_out.accept_ranges == NULL) { | 505 ngx_http_range_not_satisfiable(ngx_http_request_t *r) |
473 return NGX_ERROR; | 506 { |
474 } | 507 ngx_table_elt_t *content_range; |
475 | 508 |
476 r->headers_out.accept_ranges->hash = 1; | 509 r->headers_out.status = NGX_HTTP_RANGE_NOT_SATISFIABLE; |
477 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; | 510 |
478 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; | 511 content_range = ngx_list_push(&r->headers_out.headers); |
479 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; | 512 if (content_range == NULL) { |
480 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; | 513 return NGX_ERROR; |
481 | 514 } |
482 return ngx_http_next_header_filter(r); | 515 |
516 r->headers_out.content_range = content_range; | |
517 | |
518 content_range->hash = 1; | |
519 content_range->key.len = sizeof("Content-Range") - 1; | |
520 content_range->key.data = (u_char *) "Content-Range"; | |
521 | |
522 content_range->value.data = ngx_pnalloc(r->pool, | |
523 sizeof("bytes */") - 1 + NGX_OFF_T_LEN); | |
524 if (content_range->value.data == NULL) { | |
525 return NGX_ERROR; | |
526 } | |
527 | |
528 content_range->value.len = ngx_sprintf(content_range->value.data, | |
529 "bytes */%O", | |
530 r->headers_out.content_length_n) | |
531 - content_range->value.data; | |
532 | |
533 ngx_http_clear_content_length(r); | |
534 | |
535 return NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
483 } | 536 } |
484 | 537 |
485 | 538 |
486 static ngx_int_t | 539 static ngx_int_t |
487 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | 540 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) |
488 { | 541 { |
489 off_t start, last; | |
490 ngx_buf_t *b, *buf; | |
491 ngx_uint_t i; | |
492 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; | |
493 ngx_http_range_t *range; | |
494 ngx_http_range_filter_ctx_t *ctx; | 542 ngx_http_range_filter_ctx_t *ctx; |
495 | 543 |
496 if (in == NULL) { | 544 if (in == NULL) { |
497 return ngx_http_next_body_filter(r, in); | 545 return ngx_http_next_body_filter(r, in); |
498 } | 546 } |
501 | 549 |
502 if (ctx == NULL) { | 550 if (ctx == NULL) { |
503 return ngx_http_next_body_filter(r, in); | 551 return ngx_http_next_body_filter(r, in); |
504 } | 552 } |
505 | 553 |
506 buf = in->buf; | 554 if (ctx->ranges.nelts == 1) { |
555 return ngx_http_range_singlepart_body(r, ctx, in); | |
556 } | |
557 | |
558 /* | |
559 * multipart ranges are supported only if whole body is in a single buffer | |
560 */ | |
507 | 561 |
508 if (ngx_buf_special(in->buf)) { | 562 if (ngx_buf_special(in->buf)) { |
509 return ngx_http_next_body_filter(r, in); | 563 return ngx_http_next_body_filter(r, in); |
510 } | 564 } |
511 | 565 |
566 if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) { | |
567 return NGX_ERROR; | |
568 } | |
569 | |
570 return ngx_http_range_multipart_body(r, ctx, in); | |
571 } | |
572 | |
573 | |
574 static ngx_int_t | |
575 ngx_http_range_test_overlapped(ngx_http_request_t *r, | |
576 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) | |
577 { | |
578 off_t start, last; | |
579 ngx_buf_t *buf; | |
580 ngx_uint_t i; | |
581 ngx_http_range_t *range; | |
582 | |
512 if (ctx->offset) { | 583 if (ctx->offset) { |
513 goto overlapped; | 584 goto overlapped; |
514 } | 585 } |
515 | 586 |
516 range = ctx->ranges.elts; | 587 buf = in->buf; |
517 | 588 |
518 if (!buf->last_buf) { | 589 if (!buf->last_buf) { |
519 | 590 |
520 if (buf->in_file) { | 591 if (buf->in_file) { |
521 start = buf->file_pos + ctx->offset; | 592 start = buf->file_pos + ctx->offset; |
524 } else { | 595 } else { |
525 start = buf->pos - buf->start + ctx->offset; | 596 start = buf->pos - buf->start + ctx->offset; |
526 last = buf->last - buf->start + ctx->offset; | 597 last = buf->last - buf->start + ctx->offset; |
527 } | 598 } |
528 | 599 |
600 range = ctx->ranges.elts; | |
529 for (i = 0; i < ctx->ranges.nelts; i++) { | 601 for (i = 0; i < ctx->ranges.nelts; i++) { |
530 if (start > range[i].start || last < range[i].end) { | 602 if (start > range[i].start || last < range[i].end) { |
531 goto overlapped; | 603 goto overlapped; |
532 } | 604 } |
533 } | 605 } |
534 } | 606 } |
535 | 607 |
536 /* | |
537 * the optimized version for the responses | |
538 * that are passed in the single buffer | |
539 */ | |
540 | |
541 ctx->offset = ngx_buf_size(buf); | 608 ctx->offset = ngx_buf_size(buf); |
542 | 609 |
543 if (ctx->ranges.nelts == 1) { | 610 return NGX_OK; |
544 | 611 |
545 if (buf->in_file) { | 612 overlapped: |
546 buf->file_pos = range->start; | 613 |
547 buf->file_last = range->end; | 614 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |
548 } | 615 "range in overlapped buffers"); |
549 | 616 |
550 if (ngx_buf_in_memory(buf)) { | 617 return NGX_ERROR; |
551 buf->pos = buf->start + (size_t) range->start; | 618 } |
552 buf->last = buf->start + (size_t) range->end; | 619 |
553 } | 620 |
554 | 621 static ngx_int_t |
555 return ngx_http_next_body_filter(r, in); | 622 ngx_http_range_singlepart_body(ngx_http_request_t *r, |
556 } | 623 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) |
557 | 624 { |
625 off_t start, last; | |
626 ngx_buf_t *buf; | |
627 ngx_chain_t *out, *cl, **ll; | |
628 ngx_http_range_t *range; | |
629 | |
630 out = NULL; | |
558 ll = &out; | 631 ll = &out; |
632 range = ctx->ranges.elts; | |
633 | |
634 for (cl = in; cl; cl = cl->next) { | |
635 | |
636 buf = cl->buf; | |
637 | |
638 start = ctx->offset; | |
639 last = ctx->offset + ngx_buf_size(buf); | |
640 | |
641 ctx->offset = last; | |
642 | |
643 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
644 "http range body buf: %O-%O", start, last); | |
645 | |
646 if (ngx_buf_special(buf)) { | |
647 *ll = cl; | |
648 ll = &cl->next; | |
649 continue; | |
650 } | |
651 | |
652 if (range->end <= start || range->start >= last) { | |
653 | |
654 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
655 "http range body skip"); | |
656 | |
657 buf->pos = buf->last; | |
658 continue; | |
659 } | |
660 | |
661 if (range->start > start) { | |
662 | |
663 if (buf->in_file) { | |
664 buf->file_pos += range->start - start; | |
665 } | |
666 | |
667 if (ngx_buf_in_memory(buf)) { | |
668 buf->pos += (size_t) (range->start - start); | |
669 } | |
670 } | |
671 | |
672 if (range->end <= last) { | |
673 | |
674 if (buf->in_file) { | |
675 buf->file_last -= last - range->end; | |
676 } | |
677 | |
678 if (ngx_buf_in_memory(buf)) { | |
679 buf->last -= (size_t) (last - range->end); | |
680 } | |
681 | |
682 buf->last_buf = 1; | |
683 *ll = cl; | |
684 cl->next = NULL; | |
685 | |
686 break; | |
687 } | |
688 | |
689 *ll = cl; | |
690 ll = &cl->next; | |
691 } | |
692 | |
693 if (out == NULL) { | |
694 return NGX_OK; | |
695 } | |
696 | |
697 return ngx_http_next_body_filter(r, out); | |
698 } | |
699 | |
700 | |
701 static ngx_int_t | |
702 ngx_http_range_multipart_body(ngx_http_request_t *r, | |
703 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) | |
704 { | |
705 ngx_buf_t *b, *buf; | |
706 ngx_uint_t i; | |
707 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; | |
708 ngx_http_range_t *range; | |
709 | |
710 ll = &out; | |
711 buf = in->buf; | |
712 range = ctx->ranges.elts; | |
559 | 713 |
560 for (i = 0; i < ctx->ranges.nelts; i++) { | 714 for (i = 0; i < ctx->ranges.nelts; i++) { |
561 | 715 |
562 /* | 716 /* |
563 * The boundary header of the range: | 717 * The boundary header of the range: |
669 hcl->next = NULL; | 823 hcl->next = NULL; |
670 | 824 |
671 *ll = hcl; | 825 *ll = hcl; |
672 | 826 |
673 return ngx_http_next_body_filter(r, out); | 827 return ngx_http_next_body_filter(r, out); |
674 | |
675 overlapped: | |
676 | |
677 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
678 "range in overlapped buffers"); | |
679 | |
680 return NGX_ERROR; | |
681 } | 828 } |
682 | 829 |
683 | 830 |
684 static ngx_int_t | 831 static ngx_int_t |
685 ngx_http_range_header_filter_init(ngx_conf_t *cf) | 832 ngx_http_range_header_filter_init(ngx_conf_t *cf) |