Mercurial > hg > nginx
annotate src/stream/ngx_stream_handler.c @ 6605:f379b32e4733
Sub filter: eliminate unnecessary buffering.
Previously, when a buffer was processed by the sub filter, its final bytes
could be buffered by the filter even if they don't match any pattern.
This happened because the Boyer-Moore algorithm, employed by the sub filter
since b9447fc457b4 (1.9.4), matches the last characters of patterns prior to
checking other characters. If the last character is out of scope, initial
bytes of a potential match are buffered until the last character is available.
Now, after receiving a flush or recycled buffer, the filter performs
additional checks to reduce the number of buffered bytes. The potential match
is checked against the initial parts of all patterns. Non-matching bytes are
not buffered. This improves processing of a chunked response from upstream
by sending the entire chunks without buffering unless a partial match is found
at the end of a chunk.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Sat, 02 Jul 2016 15:59:53 +0300 |
parents | a01e315b3a78 |
children | c70b7f4537e1 |
rev | line source |
---|---|
6115 | 1 |
2 /* | |
3 * Copyright (C) Roman Arutyunyan | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_event.h> | |
11 #include <ngx_stream.h> | |
12 | |
13 | |
14 static u_char *ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len); | |
15 static void ngx_stream_init_session(ngx_connection_t *c); | |
16 | |
17 #if (NGX_STREAM_SSL) | |
18 static void ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); | |
19 static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); | |
20 #endif | |
21 | |
22 | |
23 void | |
24 ngx_stream_init_connection(ngx_connection_t *c) | |
25 { | |
6221
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
26 int tcp_nodelay; |
6175 | 27 u_char text[NGX_SOCKADDR_STRLEN]; |
28 size_t len; | |
29 ngx_int_t rc; | |
30 ngx_uint_t i; | |
31 struct sockaddr *sa; | |
32 ngx_stream_port_t *port; | |
33 struct sockaddr_in *sin; | |
34 ngx_stream_in_addr_t *addr; | |
35 ngx_stream_session_t *s; | |
36 ngx_stream_addr_conf_t *addr_conf; | |
6115 | 37 #if (NGX_HAVE_INET6) |
6175 | 38 struct sockaddr_in6 *sin6; |
39 ngx_stream_in6_addr_t *addr6; | |
6115 | 40 #endif |
6175 | 41 ngx_stream_core_srv_conf_t *cscf; |
42 ngx_stream_core_main_conf_t *cmcf; | |
6115 | 43 |
44 /* find the server configuration for the address:port */ | |
45 | |
46 port = c->listening->servers; | |
47 | |
48 if (port->naddrs > 1) { | |
49 | |
50 /* | |
51 * There are several addresses on this port and one of them | |
52 * is the "*:port" wildcard so getsockname() is needed to determine | |
53 * the server address. | |
54 * | |
6436 | 55 * AcceptEx() and recvmsg() already gave this address. |
6115 | 56 */ |
57 | |
58 if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { | |
59 ngx_stream_close_connection(c); | |
60 return; | |
61 } | |
62 | |
63 sa = c->local_sockaddr; | |
64 | |
65 switch (sa->sa_family) { | |
66 | |
67 #if (NGX_HAVE_INET6) | |
68 case AF_INET6: | |
69 sin6 = (struct sockaddr_in6 *) sa; | |
70 | |
71 addr6 = port->addrs; | |
72 | |
73 /* the last address is "*" */ | |
74 | |
75 for (i = 0; i < port->naddrs - 1; i++) { | |
76 if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { | |
77 break; | |
78 } | |
79 } | |
80 | |
81 addr_conf = &addr6[i].conf; | |
82 | |
83 break; | |
84 #endif | |
85 | |
86 default: /* AF_INET */ | |
87 sin = (struct sockaddr_in *) sa; | |
88 | |
89 addr = port->addrs; | |
90 | |
91 /* the last address is "*" */ | |
92 | |
93 for (i = 0; i < port->naddrs - 1; i++) { | |
94 if (addr[i].addr == sin->sin_addr.s_addr) { | |
95 break; | |
96 } | |
97 } | |
98 | |
99 addr_conf = &addr[i].conf; | |
100 | |
101 break; | |
102 } | |
103 | |
104 } else { | |
105 switch (c->local_sockaddr->sa_family) { | |
106 | |
107 #if (NGX_HAVE_INET6) | |
108 case AF_INET6: | |
109 addr6 = port->addrs; | |
110 addr_conf = &addr6[0].conf; | |
111 break; | |
112 #endif | |
113 | |
114 default: /* AF_INET */ | |
115 addr = port->addrs; | |
116 addr_conf = &addr[0].conf; | |
117 break; | |
118 } | |
119 } | |
120 | |
121 s = ngx_pcalloc(c->pool, sizeof(ngx_stream_session_t)); | |
122 if (s == NULL) { | |
123 ngx_stream_close_connection(c); | |
124 return; | |
125 } | |
126 | |
127 s->signature = NGX_STREAM_MODULE; | |
128 s->main_conf = addr_conf->ctx->main_conf; | |
129 s->srv_conf = addr_conf->ctx->srv_conf; | |
130 | |
131 s->connection = c; | |
132 c->data = s; | |
133 | |
134 cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); | |
135 | |
6129
187aa751ad62
Core: the ngx_set_connection_log() macro.
Vladimir Homutov <vl@nginx.com>
parents:
6115
diff
changeset
|
136 ngx_set_connection_log(c, cscf->error_log); |
6115 | 137 |
138 len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); | |
139 | |
6461
a01e315b3a78
Stream: additional logging for UDP.
Vladimir Homutov <vl@nginx.com>
parents:
6436
diff
changeset
|
140 ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA %sclient %*s connected to %V", |
a01e315b3a78
Stream: additional logging for UDP.
Vladimir Homutov <vl@nginx.com>
parents:
6436
diff
changeset
|
141 c->number, c->type == SOCK_DGRAM ? "udp " : "", |
a01e315b3a78
Stream: additional logging for UDP.
Vladimir Homutov <vl@nginx.com>
parents:
6436
diff
changeset
|
142 len, text, &addr_conf->addr_text); |
6115 | 143 |
144 c->log->connection = c->number; | |
145 c->log->handler = ngx_stream_log_error; | |
146 c->log->data = s; | |
147 c->log->action = "initializing connection"; | |
148 c->log_error = NGX_ERROR_INFO; | |
149 | |
6175 | 150 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); |
151 | |
6197
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
152 if (cmcf->limit_conn_handler) { |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
153 rc = cmcf->limit_conn_handler(s); |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
154 |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
155 if (rc != NGX_DECLINED) { |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
156 ngx_stream_close_connection(c); |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
157 return; |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
158 } |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
159 } |
0dcef374b8bb
Stream: connection limiting module.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
160 |
6175 | 161 if (cmcf->access_handler) { |
162 rc = cmcf->access_handler(s); | |
163 | |
164 if (rc != NGX_OK && rc != NGX_DECLINED) { | |
165 ngx_stream_close_connection(c); | |
166 return; | |
167 } | |
168 } | |
169 | |
6436 | 170 if (c->type == SOCK_STREAM |
171 && cscf->tcp_nodelay | |
172 && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) | |
173 { | |
6221
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
174 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
175 |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
176 tcp_nodelay = 1; |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
177 |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
178 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
179 (const void *) &tcp_nodelay, sizeof(int)) == -1) |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
180 { |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
181 ngx_connection_error(c, ngx_socket_errno, |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
182 "setsockopt(TCP_NODELAY) failed"); |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
183 ngx_stream_close_connection(c); |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
184 return; |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
185 } |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
186 |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
187 c->tcp_nodelay = NGX_TCP_NODELAY_SET; |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
188 } |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
189 |
7565e056fad6
Stream: the "tcp_nodelay" directive.
Vladimir Homutov <vl@nginx.com>
parents:
6197
diff
changeset
|
190 |
6115 | 191 #if (NGX_STREAM_SSL) |
192 { | |
193 ngx_stream_ssl_conf_t *sslcf; | |
194 | |
195 sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); | |
196 | |
197 if (addr_conf->ssl) { | |
198 c->log->action = "SSL handshaking"; | |
199 | |
200 if (sslcf->ssl.ctx == NULL) { | |
201 ngx_log_error(NGX_LOG_ERR, c->log, 0, | |
202 "no \"ssl_certificate\" is defined " | |
203 "in server listening on SSL port"); | |
204 ngx_stream_close_connection(c); | |
205 return; | |
206 } | |
207 | |
208 ngx_stream_ssl_init_connection(&sslcf->ssl, c); | |
209 return; | |
210 } | |
211 } | |
212 #endif | |
213 | |
214 ngx_stream_init_session(c); | |
215 } | |
216 | |
217 | |
218 static void | |
219 ngx_stream_init_session(ngx_connection_t *c) | |
220 { | |
221 ngx_stream_session_t *s; | |
222 ngx_stream_core_srv_conf_t *cscf; | |
223 | |
224 s = c->data; | |
225 c->log->action = "handling client connection"; | |
226 | |
227 cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); | |
228 | |
229 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module); | |
230 if (s->ctx == NULL) { | |
231 ngx_stream_close_connection(c); | |
232 return; | |
233 } | |
234 | |
235 cscf->handler(s); | |
236 } | |
237 | |
238 | |
239 #if (NGX_STREAM_SSL) | |
240 | |
241 static void | |
242 ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) | |
243 { | |
244 ngx_stream_session_t *s; | |
245 ngx_stream_ssl_conf_t *sslcf; | |
246 | |
247 if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { | |
248 ngx_stream_close_connection(c); | |
249 return; | |
250 } | |
251 | |
252 if (ngx_ssl_handshake(c) == NGX_AGAIN) { | |
253 | |
254 s = c->data; | |
255 | |
256 sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); | |
257 | |
258 ngx_add_timer(c->read, sslcf->handshake_timeout); | |
259 | |
260 c->ssl->handler = ngx_stream_ssl_handshake_handler; | |
261 | |
262 return; | |
263 } | |
264 | |
265 ngx_stream_ssl_handshake_handler(c); | |
266 } | |
267 | |
268 | |
269 static void | |
270 ngx_stream_ssl_handshake_handler(ngx_connection_t *c) | |
271 { | |
272 if (!c->ssl->handshaked) { | |
273 ngx_stream_close_connection(c); | |
274 return; | |
275 } | |
276 | |
277 if (c->read->timer_set) { | |
278 ngx_del_timer(c->read); | |
279 } | |
280 | |
281 ngx_stream_init_session(c); | |
282 } | |
283 | |
284 #endif | |
285 | |
286 | |
287 void | |
288 ngx_stream_close_connection(ngx_connection_t *c) | |
289 { | |
290 ngx_pool_t *pool; | |
291 | |
292 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, | |
293 "close stream connection: %d", c->fd); | |
294 | |
295 #if (NGX_STREAM_SSL) | |
296 | |
297 if (c->ssl) { | |
298 if (ngx_ssl_shutdown(c) == NGX_AGAIN) { | |
299 c->ssl->handler = ngx_stream_close_connection; | |
300 return; | |
301 } | |
302 } | |
303 | |
304 #endif | |
305 | |
306 #if (NGX_STAT_STUB) | |
307 (void) ngx_atomic_fetch_add(ngx_stat_active, -1); | |
308 #endif | |
309 | |
310 pool = c->pool; | |
311 | |
312 ngx_close_connection(c); | |
313 | |
314 ngx_destroy_pool(pool); | |
315 } | |
316 | |
317 | |
318 static u_char * | |
319 ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len) | |
320 { | |
321 u_char *p; | |
322 ngx_stream_session_t *s; | |
323 | |
324 if (log->action) { | |
325 p = ngx_snprintf(buf, len, " while %s", log->action); | |
326 len -= p - buf; | |
327 buf = p; | |
328 } | |
329 | |
330 s = log->data; | |
331 | |
6461
a01e315b3a78
Stream: additional logging for UDP.
Vladimir Homutov <vl@nginx.com>
parents:
6436
diff
changeset
|
332 p = ngx_snprintf(buf, len, ", %sclient: %V, server: %V", |
a01e315b3a78
Stream: additional logging for UDP.
Vladimir Homutov <vl@nginx.com>
parents:
6436
diff
changeset
|
333 s->connection->type == SOCK_DGRAM ? "udp " : "", |
6115 | 334 &s->connection->addr_text, |
335 &s->connection->listening->addr_text); | |
6223
d1f94042c29c
Stream: fixed potential error log buffer overrun.
Vladimir Homutov <vl@nginx.com>
parents:
6221
diff
changeset
|
336 len -= p - buf; |
d1f94042c29c
Stream: fixed potential error log buffer overrun.
Vladimir Homutov <vl@nginx.com>
parents:
6221
diff
changeset
|
337 buf = p; |
6115 | 338 |
339 if (s->log_handler) { | |
6223
d1f94042c29c
Stream: fixed potential error log buffer overrun.
Vladimir Homutov <vl@nginx.com>
parents:
6221
diff
changeset
|
340 p = s->log_handler(log, buf, len); |
6115 | 341 } |
342 | |
343 return p; | |
344 } |