Mercurial > hg > nginx
view src/core/ngx_resolver.h @ 9300:5be23505292b
SSI: fixed incorrect or duplicate stub output.
Following 3518:eb3aaf8bd2a9 (0.8.37), r->request_output is only set
if there are data in the first buffer sent in the subrequest. As a
result, following the change mentioned this flag cannot be used to
prevent duplicate ngx_http_ssi_stub_output() calls, since it is not
set if there was already some output, but the first buffer was empty.
Still, when there are multiple subrequests, even an empty subrequest
response might be delayed by the postpone filter, leading to a second
call of ngx_http_ssi_stub_output() during finalization from
ngx_http_writer() the subreqest buffers are released by the postpone
filter. Since r->request_output is not set after the first call, this
resulted in duplicate stub output.
Additionally, checking only the first buffer might be wrong in some
unusual cases. For example, the first buffer might be empty if
$r->flush() is called before printing any data in the embedded Perl
module.
Depending on the postpone_output value and corresponding sizes, this
issue can result in either duplicate or unexpected stub output, or
"zero size buf in writer" alerts.
Following 8124:f5515e727656 (1.23.4), it became slightly easier to
reproduce the issue, as empty static files and empty cache items now
result in a response with an empty buffer. Before the change, an empty
proxied response can be used to reproduce the issue.
Fix is check all buffers and set r->request_output if any non-empty
buffers are sent. This ensures that all unusual cases of non-empty
responses are covered, and also that r->request_output will be set
after the first stub output, preventing duplicate output.
Reported by Jan Gassen.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 04 Jul 2024 17:41:28 +0300 |
parents | 2a77754cd9fe |
children |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #ifndef _NGX_RESOLVER_H_INCLUDED_ #define _NGX_RESOLVER_H_INCLUDED_ #define NGX_RESOLVE_A 1 #define NGX_RESOLVE_CNAME 5 #define NGX_RESOLVE_PTR 12 #define NGX_RESOLVE_MX 15 #define NGX_RESOLVE_TXT 16 #if (NGX_HAVE_INET6) #define NGX_RESOLVE_AAAA 28 #endif #define NGX_RESOLVE_SRV 33 #define NGX_RESOLVE_DNAME 39 #define NGX_RESOLVE_FORMERR 1 #define NGX_RESOLVE_SERVFAIL 2 #define NGX_RESOLVE_NXDOMAIN 3 #define NGX_RESOLVE_NOTIMP 4 #define NGX_RESOLVE_REFUSED 5 #define NGX_RESOLVE_TIMEDOUT NGX_ETIMEDOUT #define NGX_NO_RESOLVER (void *) -1 #define NGX_RESOLVER_MAX_RECURSION 50 typedef struct ngx_resolver_s ngx_resolver_t; typedef struct { ngx_connection_t *udp; ngx_connection_t *tcp; struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t server; ngx_log_t log; ngx_buf_t *read_buf; ngx_buf_t *write_buf; ngx_resolver_t *resolver; } ngx_resolver_connection_t; typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t; typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx); typedef struct { struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t name; u_short priority; u_short weight; } ngx_resolver_addr_t; typedef struct { ngx_str_t name; u_short priority; u_short weight; u_short port; } ngx_resolver_srv_t; typedef struct { ngx_str_t name; u_short priority; u_short weight; u_short port; ngx_resolver_ctx_t *ctx; ngx_int_t state; ngx_uint_t naddrs; ngx_addr_t *addrs; } ngx_resolver_srv_name_t; typedef struct { ngx_rbtree_node_t node; ngx_queue_t queue; /* PTR: resolved name, A: name to resolve */ u_char *name; #if (NGX_HAVE_INET6) /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */ struct in6_addr addr6; #endif u_short nlen; u_short qlen; u_char *query; #if (NGX_HAVE_INET6) u_char *query6; #endif union { in_addr_t addr; in_addr_t *addrs; u_char *cname; ngx_resolver_srv_t *srvs; } u; u_char code; u_short naddrs; u_short nsrvs; u_short cnlen; #if (NGX_HAVE_INET6) union { struct in6_addr addr6; struct in6_addr *addrs6; } u6; u_short naddrs6; #endif time_t expire; time_t valid; uint32_t ttl; unsigned tcp:1; #if (NGX_HAVE_INET6) unsigned tcp6:1; #endif ngx_uint_t last_connection; ngx_resolver_ctx_t *waiting; } ngx_resolver_node_t; struct ngx_resolver_s { /* has to be pointer because of "incomplete type" */ ngx_event_t *event; void *dummy; ngx_log_t *log; /* event ident must be after 3 pointers as in ngx_connection_t */ ngx_int_t ident; /* simple round robin DNS peers balancer */ ngx_array_t connections; ngx_uint_t last_connection; ngx_rbtree_t name_rbtree; ngx_rbtree_node_t name_sentinel; ngx_rbtree_t srv_rbtree; ngx_rbtree_node_t srv_sentinel; ngx_rbtree_t addr_rbtree; ngx_rbtree_node_t addr_sentinel; ngx_queue_t name_resend_queue; ngx_queue_t srv_resend_queue; ngx_queue_t addr_resend_queue; ngx_queue_t name_expire_queue; ngx_queue_t srv_expire_queue; ngx_queue_t addr_expire_queue; unsigned ipv4:1; #if (NGX_HAVE_INET6) unsigned ipv6:1; ngx_rbtree_t addr6_rbtree; ngx_rbtree_node_t addr6_sentinel; ngx_queue_t addr6_resend_queue; ngx_queue_t addr6_expire_queue; #endif time_t resend_timeout; time_t tcp_timeout; time_t expire; time_t valid; ngx_uint_t log_level; }; struct ngx_resolver_ctx_s { ngx_resolver_ctx_t *next; ngx_resolver_t *resolver; ngx_resolver_node_t *node; /* event ident must be after 3 pointers as in ngx_connection_t */ ngx_int_t ident; ngx_int_t state; ngx_str_t name; ngx_str_t service; time_t valid; ngx_uint_t naddrs; ngx_resolver_addr_t *addrs; ngx_resolver_addr_t addr; struct sockaddr_in sin; ngx_uint_t count; ngx_uint_t nsrvs; ngx_resolver_srv_name_t *srvs; ngx_resolver_handler_pt handler; void *data; ngx_msec_t timeout; unsigned quick:1; unsigned async:1; unsigned cancelable:1; ngx_uint_t recursion; ngx_event_t *event; }; ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n); ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp); ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx); void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx); ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx); void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx); char *ngx_resolver_strerror(ngx_int_t err); #endif /* _NGX_RESOLVER_H_INCLUDED_ */