Mercurial > hg > nginx
comparison src/http/modules/ngx_http_range_filter.c @ 461:a88a3e4e158f release-0.1.5
nginx-0.1.5-RELEASE import
*) 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 <igor@sysoev.ru> |
---|---|
date | Thu, 11 Nov 2004 14:07:14 +0000 |
parents | 295d97d70c69 |
children | bbd6b0b4a2b1 |
comparison
equal
deleted
inserted
replaced
460:5f8319142dfc | 461:a88a3e4e158f |
---|---|
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 |