Skip to content

Commit af56b73

Browse files
committed
bugfix: srcache_fetch would use truncated responses from ngx_memc or other upstream modules. this usually happened when the upstream read time expired or the upstream prematurely closed the connection. this fix requires this patch for the nginx core: https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.2.3-nonbuffered-upstream-truncation.patch thanks Bryan Alger for reporting the issue.
1 parent 89b3819 commit af56b73

File tree

2 files changed

+231
-2
lines changed

2 files changed

+231
-2
lines changed

src/ngx_http_srcache_fetch.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,18 @@ ngx_http_srcache_fetch_post_subrequest(ngx_http_request_t *r, void *data,
274274
pr_ctx->from_cache = 0;
275275
}
276276

277+
if (r->headers_out.status >= NGX_HTTP_SPECIAL_RESPONSE
278+
|| rc == NGX_ERROR
279+
|| rc >= NGX_HTTP_SPECIAL_RESPONSE)
280+
{
281+
dd("HERE");
282+
pr_ctx->from_cache = 0;
283+
}
284+
277285
pr_ctx->waiting_subrequest = 0;
278286
pr_ctx->request_done = 1;
279287

280-
return rc;
288+
return NGX_OK;
281289
}
282290

283291

t/bugs.t

Lines changed: 222 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use Test::Nginx::Socket;
55

66
#repeat_each(2);
77

8-
plan tests => repeat_each() * (4 * blocks());
8+
plan tests => repeat_each() * (4 * blocks() + 2);
99

1010
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;
1111

@@ -268,3 +268,224 @@ world
268268
--- error_log
269269
srcache_store: request Content-Length: 55
270270
271+
272+
273+
=== TEST 11: read timed out when receiving upstream response body in srcache_fetch
274+
--- config
275+
memc_read_timeout 200ms;
276+
location /foo {
277+
satisfy any;
278+
279+
default_type text/css;
280+
281+
srcache_fetch GET /memc $uri;
282+
#srcache_store PUT /memc $uri;
283+
284+
echo I do like you;
285+
}
286+
287+
location /memc {
288+
internal;
289+
290+
set $memc_key 'foo';
291+
#set $memc_exptime 300;
292+
memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT;
293+
}
294+
--- request
295+
GET /foo
296+
--- stap
297+
F(ngx_http_upstream_finalize_request) {
298+
printf("upstream fin req: error=%d eof=%d rc=%d\n",
299+
$r->upstream->peer->connection->read->error,
300+
$r->upstream->peer->connection->read->eof,
301+
$rc)
302+
#print_ubacktrace()
303+
}
304+
F(ngx_connection_error) {
305+
printf("conn err: %d: %s\n", $err, user_string($text))
306+
#print_ubacktrace()
307+
}
308+
F(ngx_http_srcache_fetch_post_subrequest) {
309+
printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status)
310+
#print_ubacktrace()
311+
}
312+
F(ngx_http_finalize_request) {
313+
printf("finalize: %d\n", $rc)
314+
}
315+
316+
--- stap_out
317+
finalize: -4
318+
conn err: 110: upstream timed out
319+
upstream fin req: error=0 eof=0 rc=0
320+
finalize: 0
321+
post subreq: rc=0, status=504
322+
finalize: 0
323+
324+
--- tcp_listen: 19112
325+
--- tcp_no_close
326+
--- tcp_reply eval
327+
"VALUE foo 0 1024\r\nHTTP/1.1 200 OK\r\n\r\nhello world"
328+
--- response_headers
329+
Content-Type: text/css
330+
--- response_body
331+
I do like you
332+
--- error_log
333+
upstream timed out
334+
335+
336+
337+
=== TEST 12: exit(ngx.ERROR) in srcache_fetch
338+
--- config
339+
memc_read_timeout 200ms;
340+
location /foo {
341+
satisfy any;
342+
343+
default_type text/css;
344+
345+
srcache_fetch GET /sub;
346+
#srcache_store PUT /memc $uri;
347+
348+
echo I do like you;
349+
}
350+
351+
location /sub {
352+
content_by_lua '
353+
ngx.exit(ngx.ERROR)
354+
';
355+
}
356+
--- request
357+
GET /foo
358+
--- stap2
359+
F(ngx_http_upstream_finalize_request) {
360+
printf("upstream fin req: error=%d eof=%d rc=%d\n",
361+
$r->upstream->peer->connection->read->error,
362+
$r->upstream->peer->connection->read->eof,
363+
$rc)
364+
print_ubacktrace()
365+
}
366+
F(ngx_connection_error) {
367+
printf("conn err: %d: %s\n", $err, user_string($text))
368+
#print_ubacktrace()
369+
}
370+
F(ngx_http_srcache_fetch_post_subrequest) {
371+
printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status)
372+
#print_ubacktrace()
373+
}
374+
F(ngx_http_finalize_request) {
375+
printf("finalize: %d\n", $rc)
376+
}
377+
--- response_headers
378+
Content-Type: text/css
379+
--- response_body
380+
I do like you
381+
--- no_error_log
382+
[error]
383+
384+
385+
386+
=== TEST 13: exit(500) in srcache_fetch
387+
--- config
388+
memc_read_timeout 200ms;
389+
location /foo {
390+
satisfy any;
391+
392+
default_type text/css;
393+
394+
srcache_fetch GET /sub;
395+
#srcache_store PUT /memc $uri;
396+
397+
echo I do like you;
398+
}
399+
400+
location /sub {
401+
return 500;
402+
}
403+
--- request
404+
GET /foo
405+
--- stap2
406+
F(ngx_http_upstream_finalize_request) {
407+
printf("upstream fin req: error=%d eof=%d rc=%d\n",
408+
$r->upstream->peer->connection->read->error,
409+
$r->upstream->peer->connection->read->eof,
410+
$rc)
411+
print_ubacktrace()
412+
}
413+
F(ngx_connection_error) {
414+
printf("conn err: %d: %s\n", $err, user_string($text))
415+
#print_ubacktrace()
416+
}
417+
F(ngx_http_srcache_fetch_post_subrequest) {
418+
printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status)
419+
#print_ubacktrace()
420+
}
421+
F(ngx_http_finalize_request) {
422+
printf("finalize: %d\n", $rc)
423+
}
424+
--- response_headers
425+
Content-Type: text/css
426+
--- response_body
427+
I do like you
428+
--- no_error_log
429+
[error]
430+
431+
432+
433+
=== TEST 14: read timed out when receiving upstream response body in srcache_fetch
434+
--- config
435+
memc_read_timeout 200ms;
436+
location /foo {
437+
satisfy any;
438+
439+
default_type text/css;
440+
441+
srcache_fetch GET /memc $uri;
442+
#srcache_store PUT /memc $uri;
443+
444+
echo I do like you;
445+
}
446+
447+
location /memc {
448+
internal;
449+
450+
set $memc_key 'foo';
451+
#set $memc_exptime 300;
452+
memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT;
453+
}
454+
--- request
455+
GET /foo
456+
--- stap
457+
F(ngx_http_upstream_finalize_request) {
458+
printf("upstream fin req: error=%d eof=%d rc=%d\n",
459+
$r->upstream->peer->connection->read->error,
460+
$r->upstream->peer->connection->read->eof,
461+
$rc)
462+
#print_ubacktrace()
463+
}
464+
F(ngx_connection_error) {
465+
printf("conn err: %d: %s\n", $err, user_string($text))
466+
#print_ubacktrace()
467+
}
468+
F(ngx_http_srcache_fetch_post_subrequest) {
469+
printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status)
470+
#print_ubacktrace()
471+
}
472+
F(ngx_http_finalize_request) {
473+
printf("finalize: %d\n", $rc)
474+
}
475+
--- stap_out
476+
finalize: -4
477+
upstream fin req: error=0 eof=1 rc=0
478+
finalize: 0
479+
post subreq: rc=0, status=502
480+
finalize: 0
481+
482+
--- tcp_listen: 19112
483+
--- tcp_reply eval
484+
"VALUE foo 0 1024\r\nHTTP/1.1 200 OK\r\n\r\nhello world"
485+
--- response_headers
486+
Content-Type: text/css
487+
--- response_body
488+
I do like you
489+
--- no_error_log
490+
[error]
491+

0 commit comments

Comments
 (0)