comparison src/http/modules/ngx_http_range_filter.c @ 10:46833bd150cb NGINX_0_1_5

nginx 0.1.5 *) Bugfix: on Solaris and Linux there may be too many "recvmsg() returned not enough data" alerts. *) Bugfix: there were the "writev() failed (22: Invalid argument)" errors on Solaris in proxy mode without sendfile. On other platforms that do not support sendfile at all the process got caught in an endless loop. *) Bugfix: segmentation fault on Solaris in proxy mode and using sendfile. *) Bugfix: segmentation fault on Solaris. *) Bugfix: on-line upgrade did not work on Linux. *) Bugfix: the ngx_http_autoindex_module module did not escape the spaces, the quotes, and the percent signs in the directory listing. *) Change: the decrease of the copy operations. *) Feature: the userid_p3p directive.
author Igor Sysoev <http://sysoev.ru>
date Thu, 11 Nov 2004 00:00:00 +0300
parents 4b2dafa26fe2
children 74b1868dd3cd
comparison
equal deleted inserted replaced
9:77eee314ddbd 10:46833bd150cb
105 static ngx_http_output_body_filter_pt ngx_http_next_body_filter; 105 static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
106 106
107 107
108 static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r) 108 static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r)
109 { 109 {
110 ngx_int_t rc;
111 ngx_uint_t boundary, suffix, i;
112 u_char *p; 110 u_char *p;
113 size_t len; 111 size_t len;
114 off_t start, end; 112 off_t start, end;
113 ngx_int_t rc;
114 uint32_t boundary;
115 ngx_uint_t suffix, i;
116 ngx_table_elt_t *content_range;
115 ngx_http_range_t *range; 117 ngx_http_range_t *range;
116 ngx_http_range_filter_ctx_t *ctx; 118 ngx_http_range_filter_ctx_t *ctx;
117 119
118 if (r->http_version < NGX_HTTP_VERSION_10 120 if (r->http_version < NGX_HTTP_VERSION_10
119 || r->headers_out.status != NGX_HTTP_OK 121 || r->headers_out.status != NGX_HTTP_OK
139 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; 141 r->headers_out.accept_ranges->value.data = (u_char *) "bytes";
140 142
141 return ngx_http_next_header_filter(r); 143 return ngx_http_next_header_filter(r);
142 } 144 }
143 145
144 ngx_init_array(r->headers_out.ranges, r->pool, 5, sizeof(ngx_http_range_t), 146 if (ngx_array_init(&r->headers_out.ranges, r->pool, 5,
145 NGX_ERROR); 147 sizeof(ngx_http_range_t)) == NGX_ERROR)
148 {
149 return NGX_ERROR;
150 }
146 151
147 rc = 0; 152 rc = 0;
148 range = NULL; 153 range = NULL;
149 p = r->headers_in.range->value.data + 6; 154 p = r->headers_in.range->value.data + 6;
150 155
178 } 183 }
179 184
180 while (*p == ' ') { p++; } 185 while (*p == ' ') { p++; }
181 186
182 if (*p == ',' || *p == '\0') { 187 if (*p == ',' || *p == '\0') {
183 ngx_test_null(range, ngx_push_array(&r->headers_out.ranges), 188 if (!(range = ngx_array_push(&r->headers_out.ranges))) {
184 NGX_ERROR); 189 return NGX_ERROR;
190 }
191
185 range->start = start; 192 range->start = start;
186 range->end = r->headers_out.content_length_n; 193 range->end = r->headers_out.content_length_n;
187 194
188 if (*p++ != ',') { 195 if (*p++ != ',') {
189 break; 196 break;
221 if (start > end) { 228 if (start > end) {
222 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; 229 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
223 break; 230 break;
224 } 231 }
225 232
226 ngx_test_null(range, ngx_push_array(&r->headers_out.ranges), NGX_ERROR); 233 if (!(range = ngx_array_push(&r->headers_out.ranges))) {
234 return NGX_ERROR;
235 }
236
227 range->start = start; 237 range->start = start;
228 238
229 if (end >= r->headers_out.content_length_n) { 239 if (end >= r->headers_out.content_length_n) {
230 /* 240 /*
231 * Download Accelerator sends the last byte position 241 * Download Accelerator sends the last byte position
247 /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ 257 /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */
248 258
249 r->headers_out.status = rc; 259 r->headers_out.status = rc;
250 r->headers_out.ranges.nelts = 0; 260 r->headers_out.ranges.nelts = 0;
251 261
252 r->headers_out.content_range = ngx_list_push(&r->headers_out.headers); 262 if (!(content_range = ngx_list_push(&r->headers_out.headers))) {
253 if (r->headers_out.content_range == NULL) { 263 return NGX_ERROR;
254 return NGX_ERROR; 264 }
255 } 265
256 266 r->headers_out.content_range = content_range;
257 r->headers_out.content_range->key.len = sizeof("Content-Range") - 1; 267
258 r->headers_out.content_range->key.data = (u_char *) "Content-Range"; 268 content_range->key.len = sizeof("Content-Range") - 1;
259 269 content_range->key.data = (u_char *) "Content-Range";
260 r->headers_out.content_range->value.data = 270
261 ngx_palloc(r->pool, 8 + 20 + 1); 271 content_range->value.data =
262 if (r->headers_out.content_range->value.data == NULL) { 272 ngx_palloc(r->pool, sizeof("bytes */") - 1 + NGX_OFF_T_LEN);
263 return NGX_ERROR; 273
264 } 274 if (content_range->value.data == NULL) {
265 275 return NGX_ERROR;
266 r->headers_out.content_range->value.len = 276 }
267 ngx_sprintf(r->headers_out.content_range->value.data, 277
268 "bytes */%O", r->headers_out.content_length_n) 278 content_range->value.len = ngx_sprintf(content_range->value.data,
269 - r->headers_out.content_range->value.data; 279 "bytes */%O",
270 #if 0 280 r->headers_out.content_length_n)
271 ngx_snprintf((char *) r->headers_out.content_range->value.data, 281 - content_range->value.data;
272 8 + 20 + 1, "bytes */" OFF_T_FMT,
273 r->headers_out.content_length_n);
274 #endif
275 282
276 r->headers_out.content_length_n = -1; 283 r->headers_out.content_length_n = -1;
277 if (r->headers_out.content_length) { 284 if (r->headers_out.content_length) {
278 r->headers_out.content_length->key.len = 0; 285 r->headers_out.content_length->key.len = 0;
279 r->headers_out.content_length = NULL; 286 r->headers_out.content_length = NULL;
280 } 287 }
281 288
282 return rc; 289 return rc;
290 }
291
292 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
293
294 if (r->headers_out.ranges.nelts == 1) {
295
296 if (!(content_range = ngx_list_push(&r->headers_out.headers))) {
297 return NGX_ERROR;
298 }
299
300 r->headers_out.content_range = content_range;
301
302 content_range->key.len = sizeof("Content-Range") - 1;
303 content_range->key.data = (u_char *) "Content-Range";
304
305 content_range->value.data =
306 ngx_palloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN);
307 if (content_range->value.data == NULL) {
308 return NGX_ERROR;
309 }
310
311 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */
312
313 content_range->value.len = ngx_sprintf(content_range->value.data,
314 "bytes %O-%O/%O",
315 range->start, range->end - 1,
316 r->headers_out.content_length_n)
317 - content_range->value.data;
318
319 r->headers_out.content_length_n = range->end - range->start;
320
321 return ngx_http_next_header_filter(r);
322 }
323
324
325 /* TODO: what if no content_type ?? */
326
327 ngx_http_create_ctx(r, ctx, ngx_http_range_body_filter_module,
328 sizeof(ngx_http_range_filter_ctx_t), NGX_ERROR);
329
330
331 len = sizeof(CRLF "--0123456789" CRLF "Content-Type: ") - 1
332 + r->headers_out.content_type->value.len
333 + sizeof(CRLF "Content-Range: bytes ") - 1;
334
335 if (r->headers_out.charset.len) {
336 len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
337 }
338
339 if (!(ctx->boundary_header.data = ngx_palloc(r->pool, len))) {
340 return NGX_ERROR;
341 }
342
343 boundary = ngx_next_temp_number(0);
344
345 /*
346 * The boundary header of the range:
347 * CRLF
348 * "--0123456789" CRLF
349 * "Content-Type: image/jpeg" CRLF
350 * "Content-Range: bytes "
351 */
352
353 if (r->headers_out.charset.len) {
354 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
355 CRLF "--%010ud" CRLF
356 "Content-Type: %V; charset=%V" CRLF
357 "Content-Range: bytes ",
358 boundary,
359 &r->headers_out.content_type->value,
360 &r->headers_out.charset)
361 - ctx->boundary_header.data;
362
363 r->headers_out.charset.len = 0;
283 364
284 } else { 365 } else {
285 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; 366 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
286 367 CRLF "--%010ud" CRLF
287 if (r->headers_out.ranges.nelts == 1) { 368 "Content-Type: %V" CRLF
288 369 "Content-Range: bytes ",
289 r->headers_out.content_range = 370 boundary,
290 ngx_list_push(&r->headers_out.headers); 371 &r->headers_out.content_type->value)
291 if (r->headers_out.content_range == NULL) { 372 - ctx->boundary_header.data;
292 return NGX_ERROR; 373 }
293 } 374
294 375 r->headers_out.content_type->value.data =
295 r->headers_out.content_range->key.len = sizeof("Content-Range") - 1; 376 ngx_palloc(r->pool, sizeof("Content-Type: multipart/byteranges; "
296 r->headers_out.content_range->key.data = (u_char *) "Content-Range"; 377 "boundary=0123456789") - 1);
297 378
298 ngx_test_null(r->headers_out.content_range->value.data, 379 if (r->headers_out.content_type->value.data == NULL) {
299 ngx_palloc(r->pool, 6 + 20 + 1 + 20 + 1 + 20 + 1), 380 return NGX_ERROR;
300 NGX_ERROR); 381 }
301 382
302 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ 383 /* "Content-Type: multipart/byteranges; boundary=0123456789" */
303 384
304 r->headers_out.content_range->value.len = 385 r->headers_out.content_type->value.len =
305 ngx_sprintf(r->headers_out.content_range->value.data, 386 ngx_sprintf(r->headers_out.content_type->value.data,
306 "bytes %O-%O/%O", 387 "multipart/byteranges; boundary=%010ud",
307 range->start, range->end - 1, 388 boundary)
308 r->headers_out.content_length_n) 389 - r->headers_out.content_type->value.data;
309 - r->headers_out.content_range->value.data; 390
310 391 /* the size of the last boundary CRLF "--0123456789--" CRLF */
311 #if 0 392 len = sizeof(CRLF "--0123456789--" CRLF) - 1;
312 ngx_snprintf((char *) 393
313 r->headers_out.content_range->value.data, 394 range = r->headers_out.ranges.elts;
314 6 + 20 + 1 + 20 + 1 + 20 + 1, 395 for (i = 0; i < r->headers_out.ranges.nelts; i++) {
315 "bytes " OFF_T_FMT "-" OFF_T_FMT "/" OFF_T_FMT, 396
316 range->start, range->end - 1, 397 /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */
317 r->headers_out.content_length_n); 398
318 #endif 399 range[i].content_range.data =
319 400 ngx_palloc(r->pool, 3 * NGX_OFF_T_LEN + 2 + 4);
320 r->headers_out.content_length_n = range->end - range->start; 401
321 402 if (range[i].content_range.data == NULL) {
322 } else { 403 return NGX_ERROR;
323 404 }
324 #if 0 405
325 /* TODO: what if no content_type ?? */ 406 range[i].content_range.len = ngx_sprintf(range[i].content_range.data,
326 407 "%O-%O/%O" CRLF CRLF,
327 if (!(r->headers_out.content_type = 408 range[i].start, range[i].end - 1,
328 ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) 409 r->headers_out.content_length_n)
329 { 410 - range[i].content_range.data;
330 return NGX_ERROR; 411
331 } 412 len += ctx->boundary_header.len + range[i].content_range.len
332 #endif
333
334 ngx_http_create_ctx(r, ctx, ngx_http_range_body_filter_module,
335 sizeof(ngx_http_range_filter_ctx_t), NGX_ERROR);
336
337 len = 4 + 10 + 2 + 14 + r->headers_out.content_type->value.len
338 + 2 + 21 + 1;
339
340 if (r->headers_out.charset.len) {
341 len += 10 + r->headers_out.charset.len;
342 }
343
344 ngx_test_null(ctx->boundary_header.data, ngx_palloc(r->pool, len),
345 NGX_ERROR);
346
347 boundary = ngx_next_temp_number(0);
348
349 /*
350 * The boundary header of the range:
351 * CRLF
352 * "--0123456789" CRLF
353 * "Content-Type: image/jpeg" CRLF
354 * "Content-Range: bytes "
355 */
356
357 if (r->headers_out.charset.len) {
358 ctx->boundary_header.len =
359 ngx_sprintf(ctx->boundary_header.data,
360 CRLF "--%010ui" CRLF
361 "Content-Type: %s; charset=%s" CRLF
362 "Content-Range: bytes ",
363 boundary,
364 r->headers_out.content_type->value.data,
365 r->headers_out.charset.data)
366 - ctx->boundary_header.data;
367 #if 0
368 ngx_snprintf((char *) ctx->boundary_header.data, len,
369 CRLF "--%010" NGX_UINT_T_FMT CRLF
370 "Content-Type: %s; charset=%s" CRLF
371 "Content-Range: bytes ",
372 boundary,
373 r->headers_out.content_type->value.data,
374 r->headers_out.charset.data);
375 #endif
376
377 r->headers_out.charset.len = 0;
378
379 } else {
380 ctx->boundary_header.len =
381 ngx_sprintf(ctx->boundary_header.data,
382 CRLF "--%010ui" CRLF
383 "Content-Type: %s" CRLF
384 "Content-Range: bytes ",
385 boundary,
386 r->headers_out.content_type->value.data)
387 - ctx->boundary_header.data;
388
389 #if 0
390 ngx_snprintf((char *) ctx->boundary_header.data, len,
391 CRLF "--%010" NGX_UINT_T_FMT CRLF
392 "Content-Type: %s" CRLF
393 "Content-Range: bytes ",
394 boundary,
395 r->headers_out.content_type->value.data);
396
397 #endif
398 }
399
400 ngx_test_null(r->headers_out.content_type->value.data,
401 ngx_palloc(r->pool, 31 + 10 + 1),
402 NGX_ERROR);
403
404 /* "Content-Type: multipart/byteranges; boundary=0123456789" */
405
406 r->headers_out.content_type->value.len =
407 ngx_sprintf(r->headers_out.content_type->value.data,
408 "multipart/byteranges; boundary=%010ui",
409 boundary)
410 - r->headers_out.content_type->value.data;
411 #if 0
412 ngx_snprintf((char *)
413 r->headers_out.content_type->value.data,
414 31 + 10 + 1,
415 "multipart/byteranges; boundary=%010"
416 NGX_UINT_T_FMT,
417 boundary);
418 #endif
419
420 /* the size of the last boundary CRLF "--0123456789--" CRLF */
421 len = 4 + 10 + 4;
422
423 range = r->headers_out.ranges.elts;
424 for (i = 0; i < r->headers_out.ranges.nelts; i++) {
425 ngx_test_null(range[i].content_range.data,
426 ngx_palloc(r->pool, 20 + 1 + 20 + 1 + 20 + 5),
427 NGX_ERROR);
428
429 /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */
430
431 range[i].content_range.len =
432 ngx_sprintf(range[i].content_range.data,
433 "%O-%O/%O" CRLF CRLF,
434 range[i].start, range[i].end - 1,
435 r->headers_out.content_length_n)
436 - range[i].content_range.data;
437 #if 0
438 ngx_snprintf((char *) range[i].content_range.data,
439 20 + 1 + 20 + 1 + 20 + 5,
440 OFF_T_FMT "-" OFF_T_FMT "/" OFF_T_FMT CRLF CRLF,
441 range[i].start, range[i].end - 1,
442 r->headers_out.content_length_n);
443 #endif
444
445 len += ctx->boundary_header.len + range[i].content_range.len
446 + (size_t) (range[i].end - range[i].start); 413 + (size_t) (range[i].end - range[i].start);
447 } 414 }
448 415
449 r->headers_out.content_length_n = len; 416 r->headers_out.content_length_n = len;
450 r->headers_out.content_length = NULL; 417 r->headers_out.content_length = NULL;
451 }
452 }
453 418
454 return ngx_http_next_header_filter(r); 419 return ngx_http_next_header_filter(r);
455 } 420 }
456 421
457 422
494 * "--0123456789" CRLF 459 * "--0123456789" CRLF
495 * "Content-Type: image/jpeg" CRLF 460 * "Content-Type: image/jpeg" CRLF
496 * "Content-Range: bytes " 461 * "Content-Range: bytes "
497 */ 462 */
498 463
499 ngx_test_null(b, ngx_calloc_buf(r->pool), NGX_ERROR); 464 if (!(b = ngx_calloc_buf(r->pool))) {
465 return NGX_ERROR;
466 }
467
500 b->memory = 1; 468 b->memory = 1;
501 b->pos = ctx->boundary_header.data; 469 b->pos = ctx->boundary_header.data;
502 b->last = ctx->boundary_header.data + ctx->boundary_header.len; 470 b->last = ctx->boundary_header.data + ctx->boundary_header.len;
503 471
504 ngx_test_null(hcl, ngx_alloc_chain_link(r->pool), NGX_ERROR); 472 if (!(hcl = ngx_alloc_chain_link(r->pool))) {
473 return NGX_ERROR;
474 }
475
505 hcl->buf = b; 476 hcl->buf = b;
506 477
478
507 /* "SSSS-EEEE/TTTT" CRLF CRLF */ 479 /* "SSSS-EEEE/TTTT" CRLF CRLF */
508 480
509 ngx_test_null(b, ngx_calloc_buf(r->pool), NGX_ERROR); 481 if (!(b = ngx_calloc_buf(r->pool))) {
482 return NGX_ERROR;
483 }
484
510 b->temporary = 1; 485 b->temporary = 1;
511 b->pos = range[i].content_range.data; 486 b->pos = range[i].content_range.data;
512 b->last = range[i].content_range.data + range[i].content_range.len; 487 b->last = range[i].content_range.data + range[i].content_range.len;
513 488
514 ngx_test_null(rcl, ngx_alloc_chain_link(r->pool), NGX_ERROR); 489 if (!(rcl = ngx_alloc_chain_link(r->pool))) {
490 return NGX_ERROR;
491 }
492
515 rcl->buf = b; 493 rcl->buf = b;
516 494
495
517 /* the range data */ 496 /* the range data */
518 497
519 ngx_test_null(b, ngx_calloc_buf(r->pool), NGX_ERROR); 498 if (!(b = ngx_calloc_buf(r->pool))) {
499 return NGX_ERROR;
500 }
501
520 b->in_file = 1; 502 b->in_file = 1;
521 b->file_pos = range[i].start; 503 b->file_pos = range[i].start;
522 b->file_last = range[i].end; 504 b->file_last = range[i].end;
523 b->file = in->buf->file; 505 b->file = in->buf->file;
524 506
525 ngx_alloc_link_and_set_buf(dcl, b, r->pool, NGX_ERROR); 507 if (!(dcl = ngx_alloc_chain_link(r->pool))) {
508 return NGX_ERROR;
509 }
510
511 dcl->buf = b;
526 512
527 *ll = hcl; 513 *ll = hcl;
528 hcl->next = rcl; 514 hcl->next = rcl;
529 rcl->next = dcl; 515 rcl->next = dcl;
530 ll = &dcl->next; 516 ll = &dcl->next;
531 } 517 }
532 518
533 /* the last boundary CRLF "--0123456789--" CRLF */ 519 /* the last boundary CRLF "--0123456789--" CRLF */
534 520
535 ngx_test_null(b, ngx_calloc_buf(r->pool), NGX_ERROR); 521 if (!(b = ngx_calloc_buf(r->pool))) {
522 return NGX_ERROR;
523 }
524
536 b->temporary = 1; 525 b->temporary = 1;
537 b->last_buf = 1; 526 b->last_buf = 1;
538 ngx_test_null(b->pos, ngx_palloc(r->pool, 4 + 10 + 4), NGX_ERROR); 527
528 b->pos = ngx_palloc(r->pool, sizeof(CRLF "--0123456789--" CRLF) - 1);
529 if (b->pos == NULL) {
530 return NGX_ERROR;
531 }
532
539 b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10); 533 b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10);
540 *b->last++ = '-'; *b->last++ = '-'; 534 *b->last++ = '-'; *b->last++ = '-';
541 *b->last++ = CR; *b->last++ = LF; 535 *b->last++ = CR; *b->last++ = LF;
542 536
543 ngx_alloc_link_and_set_buf(hcl, b, r->pool, NGX_ERROR); 537 if (!(hcl = ngx_alloc_chain_link(r->pool))) {
538 return NGX_ERROR;
539 }
540
541 hcl->buf = b;
542 hcl->next = NULL;
543
544 *ll = hcl; 544 *ll = hcl;
545 545
546 return ngx_http_next_body_filter(r, out); 546 return ngx_http_next_body_filter(r, out);
547 } 547 }
548 548