Mercurial > hg > nginx
annotate src/stream/ngx_stream_upstream_round_robin.c @ 6749:f88a145b093e stable-1.10
HTTP/2: the "421 Misdirected Request" response (closes #848).
Since 4fbef397c753 nginx rejects with the 400 error any attempts of
requesting different host over the same connection, if the relevant
virtual server requires verification of a client certificate.
While requesting hosts other than negotiated isn't something legal
in HTTP/1.x, the HTTP/2 specification explicitly permits such requests
for connection reuse and has introduced a special response code 421.
According to RFC 7540 Section 9.1.2 this code can be sent by a server
that is not configured to produce responses for the combination of
scheme and authority that are included in the request URI. And the
client may retry the request over a different connection.
Now this code is used for requests that aren't authorized in current
connection. After receiving the 421 response a client will be able
to open a new connection, provide the required certificate and retry
the request.
Unfortunately, not all clients currently are able to handle it well.
Notably Chrome just shows an error, while at least the latest version
of Firefox retries the request over a new connection.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Fri, 20 May 2016 18:41:17 +0300 |
parents | 2cd019520210 |
children | 9757cffc1e2f |
rev | line source |
---|---|
6115 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_stream.h> | |
11 | |
12 | |
13 #define ngx_stream_upstream_tries(p) ((p)->number \ | |
14 + ((p)->next ? (p)->next->number : 0)) | |
15 | |
16 | |
17 static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_get_peer( | |
18 ngx_stream_upstream_rr_peer_data_t *rrp); | |
19 | |
20 #if (NGX_STREAM_SSL) | |
21 | |
22 static ngx_int_t ngx_stream_upstream_set_round_robin_peer_session( | |
23 ngx_peer_connection_t *pc, void *data); | |
24 static void ngx_stream_upstream_save_round_robin_peer_session( | |
25 ngx_peer_connection_t *pc, void *data); | |
26 | |
27 #endif | |
28 | |
29 | |
30 ngx_int_t | |
31 ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, | |
32 ngx_stream_upstream_srv_conf_t *us) | |
33 { | |
34 ngx_url_t u; | |
35 ngx_uint_t i, j, n, w; | |
36 ngx_stream_upstream_server_t *server; | |
37 ngx_stream_upstream_rr_peer_t *peer, **peerp; | |
38 ngx_stream_upstream_rr_peers_t *peers, *backup; | |
39 | |
40 us->peer.init = ngx_stream_upstream_init_round_robin_peer; | |
41 | |
42 if (us->servers) { | |
43 server = us->servers->elts; | |
44 | |
45 n = 0; | |
46 w = 0; | |
47 | |
48 for (i = 0; i < us->servers->nelts; i++) { | |
49 if (server[i].backup) { | |
50 continue; | |
51 } | |
52 | |
53 n += server[i].naddrs; | |
54 w += server[i].naddrs * server[i].weight; | |
55 } | |
56 | |
57 if (n == 0) { | |
58 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
59 "no servers in upstream \"%V\" in %s:%ui", | |
60 &us->host, us->file_name, us->line); | |
61 return NGX_ERROR; | |
62 } | |
63 | |
64 peers = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t)); | |
65 if (peers == NULL) { | |
66 return NGX_ERROR; | |
67 } | |
68 | |
69 peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t) * n); | |
70 if (peer == NULL) { | |
71 return NGX_ERROR; | |
72 } | |
73 | |
74 peers->single = (n == 1); | |
75 peers->number = n; | |
76 peers->weighted = (w != n); | |
77 peers->total_weight = w; | |
78 peers->name = &us->host; | |
79 | |
80 n = 0; | |
81 peerp = &peers->peer; | |
82 | |
83 for (i = 0; i < us->servers->nelts; i++) { | |
84 if (server[i].backup) { | |
85 continue; | |
86 } | |
87 | |
88 for (j = 0; j < server[i].naddrs; j++) { | |
89 peer[n].sockaddr = server[i].addrs[j].sockaddr; | |
90 peer[n].socklen = server[i].addrs[j].socklen; | |
91 peer[n].name = server[i].addrs[j].name; | |
92 peer[n].weight = server[i].weight; | |
93 peer[n].effective_weight = server[i].weight; | |
94 peer[n].current_weight = 0; | |
95 peer[n].max_fails = server[i].max_fails; | |
96 peer[n].fail_timeout = server[i].fail_timeout; | |
97 peer[n].down = server[i].down; | |
98 peer[n].server = server[i].name; | |
99 | |
100 *peerp = &peer[n]; | |
101 peerp = &peer[n].next; | |
102 n++; | |
103 } | |
104 } | |
105 | |
106 us->peer.data = peers; | |
107 | |
108 /* backup servers */ | |
109 | |
110 n = 0; | |
111 w = 0; | |
112 | |
113 for (i = 0; i < us->servers->nelts; i++) { | |
114 if (!server[i].backup) { | |
115 continue; | |
116 } | |
117 | |
118 n += server[i].naddrs; | |
119 w += server[i].naddrs * server[i].weight; | |
120 } | |
121 | |
122 if (n == 0) { | |
123 return NGX_OK; | |
124 } | |
125 | |
126 backup = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t)); | |
127 if (backup == NULL) { | |
128 return NGX_ERROR; | |
129 } | |
130 | |
131 peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t) * n); | |
132 if (peer == NULL) { | |
133 return NGX_ERROR; | |
134 } | |
135 | |
136 peers->single = 0; | |
137 backup->single = 0; | |
138 backup->number = n; | |
139 backup->weighted = (w != n); | |
140 backup->total_weight = w; | |
141 backup->name = &us->host; | |
142 | |
143 n = 0; | |
144 peerp = &backup->peer; | |
145 | |
146 for (i = 0; i < us->servers->nelts; i++) { | |
147 if (!server[i].backup) { | |
148 continue; | |
149 } | |
150 | |
151 for (j = 0; j < server[i].naddrs; j++) { | |
152 peer[n].sockaddr = server[i].addrs[j].sockaddr; | |
153 peer[n].socklen = server[i].addrs[j].socklen; | |
154 peer[n].name = server[i].addrs[j].name; | |
155 peer[n].weight = server[i].weight; | |
156 peer[n].effective_weight = server[i].weight; | |
157 peer[n].current_weight = 0; | |
158 peer[n].max_fails = server[i].max_fails; | |
159 peer[n].fail_timeout = server[i].fail_timeout; | |
160 peer[n].down = server[i].down; | |
161 peer[n].server = server[i].name; | |
162 | |
163 *peerp = &peer[n]; | |
164 peerp = &peer[n].next; | |
165 n++; | |
166 } | |
167 } | |
168 | |
169 peers->next = backup; | |
170 | |
171 return NGX_OK; | |
172 } | |
173 | |
174 | |
175 /* an upstream implicitly defined by proxy_pass, etc. */ | |
176 | |
177 if (us->port == 0) { | |
178 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
179 "no port in upstream \"%V\" in %s:%ui", | |
180 &us->host, us->file_name, us->line); | |
181 return NGX_ERROR; | |
182 } | |
183 | |
184 ngx_memzero(&u, sizeof(ngx_url_t)); | |
185 | |
186 u.host = us->host; | |
187 u.port = us->port; | |
188 | |
189 if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { | |
190 if (u.err) { | |
191 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
192 "%s in upstream \"%V\" in %s:%ui", | |
193 u.err, &us->host, us->file_name, us->line); | |
194 } | |
195 | |
196 return NGX_ERROR; | |
197 } | |
198 | |
199 n = u.naddrs; | |
200 | |
201 peers = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t)); | |
202 if (peers == NULL) { | |
203 return NGX_ERROR; | |
204 } | |
205 | |
206 peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t) * n); | |
207 if (peer == NULL) { | |
208 return NGX_ERROR; | |
209 } | |
210 | |
211 peers->single = (n == 1); | |
212 peers->number = n; | |
213 peers->weighted = 0; | |
214 peers->total_weight = n; | |
215 peers->name = &us->host; | |
216 | |
217 peerp = &peers->peer; | |
218 | |
219 for (i = 0; i < u.naddrs; i++) { | |
220 peer[i].sockaddr = u.addrs[i].sockaddr; | |
221 peer[i].socklen = u.addrs[i].socklen; | |
222 peer[i].name = u.addrs[i].name; | |
223 peer[i].weight = 1; | |
224 peer[i].effective_weight = 1; | |
225 peer[i].current_weight = 0; | |
226 peer[i].max_fails = 1; | |
227 peer[i].fail_timeout = 10; | |
228 *peerp = &peer[i]; | |
229 peerp = &peer[i].next; | |
230 } | |
231 | |
232 us->peer.data = peers; | |
233 | |
234 /* implicitly defined upstream has no backup servers */ | |
235 | |
236 return NGX_OK; | |
237 } | |
238 | |
239 | |
240 ngx_int_t | |
241 ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s, | |
242 ngx_stream_upstream_srv_conf_t *us) | |
243 { | |
244 ngx_uint_t n; | |
245 ngx_stream_upstream_rr_peer_data_t *rrp; | |
246 | |
247 rrp = s->upstream->peer.data; | |
248 | |
249 if (rrp == NULL) { | |
250 rrp = ngx_palloc(s->connection->pool, | |
251 sizeof(ngx_stream_upstream_rr_peer_data_t)); | |
252 if (rrp == NULL) { | |
253 return NGX_ERROR; | |
254 } | |
255 | |
256 s->upstream->peer.data = rrp; | |
257 } | |
258 | |
259 rrp->peers = us->peer.data; | |
260 rrp->current = NULL; | |
261 | |
262 n = rrp->peers->number; | |
263 | |
264 if (rrp->peers->next && rrp->peers->next->number > n) { | |
265 n = rrp->peers->next->number; | |
266 } | |
267 | |
268 if (n <= 8 * sizeof(uintptr_t)) { | |
269 rrp->tried = &rrp->data; | |
270 rrp->data = 0; | |
271 | |
272 } else { | |
273 n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t)); | |
274 | |
275 rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t)); | |
276 if (rrp->tried == NULL) { | |
277 return NGX_ERROR; | |
278 } | |
279 } | |
280 | |
281 s->upstream->peer.get = ngx_stream_upstream_get_round_robin_peer; | |
282 s->upstream->peer.free = ngx_stream_upstream_free_round_robin_peer; | |
283 s->upstream->peer.tries = ngx_stream_upstream_tries(rrp->peers); | |
284 #if (NGX_STREAM_SSL) | |
285 s->upstream->peer.set_session = | |
286 ngx_stream_upstream_set_round_robin_peer_session; | |
287 s->upstream->peer.save_session = | |
288 ngx_stream_upstream_save_round_robin_peer_session; | |
289 #endif | |
290 | |
291 return NGX_OK; | |
292 } | |
293 | |
294 | |
295 ngx_int_t | |
296 ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) | |
297 { | |
298 ngx_stream_upstream_rr_peer_data_t *rrp = data; | |
299 | |
300 ngx_int_t rc; | |
301 ngx_uint_t i, n; | |
302 ngx_stream_upstream_rr_peer_t *peer; | |
303 ngx_stream_upstream_rr_peers_t *peers; | |
304 | |
305 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
306 "get rr peer, try: %ui", pc->tries); | |
307 | |
308 pc->connection = NULL; | |
309 | |
310 peers = rrp->peers; | |
311 ngx_stream_upstream_rr_peers_wlock(peers); | |
312 | |
313 if (peers->single) { | |
314 peer = peers->peer; | |
315 | |
316 if (peer->down) { | |
317 goto failed; | |
318 } | |
319 | |
320 rrp->current = peer; | |
321 | |
322 } else { | |
323 | |
324 /* there are several peers */ | |
325 | |
326 peer = ngx_stream_upstream_get_peer(rrp); | |
327 | |
328 if (peer == NULL) { | |
329 goto failed; | |
330 } | |
331 | |
332 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
333 "get rr peer, current: %p %i", | |
334 peer, peer->current_weight); | |
335 } | |
336 | |
337 pc->sockaddr = peer->sockaddr; | |
338 pc->socklen = peer->socklen; | |
339 pc->name = &peer->name; | |
340 | |
341 peer->conns++; | |
342 | |
343 ngx_stream_upstream_rr_peers_unlock(peers); | |
344 | |
345 return NGX_OK; | |
346 | |
347 failed: | |
348 | |
349 if (peers->next) { | |
350 | |
351 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "backup servers"); | |
352 | |
353 rrp->peers = peers->next; | |
354 | |
355 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) | |
356 / (8 * sizeof(uintptr_t)); | |
357 | |
358 for (i = 0; i < n; i++) { | |
6474 | 359 rrp->tried[i] = 0; |
6115 | 360 } |
361 | |
362 ngx_stream_upstream_rr_peers_unlock(peers); | |
363 | |
364 rc = ngx_stream_upstream_get_round_robin_peer(pc, rrp); | |
365 | |
366 if (rc != NGX_BUSY) { | |
367 return rc; | |
368 } | |
369 | |
370 ngx_stream_upstream_rr_peers_wlock(peers); | |
371 } | |
372 | |
373 /* all peers failed, mark them as live for quick recovery */ | |
374 | |
375 for (peer = peers->peer; peer; peer = peer->next) { | |
376 peer->fails = 0; | |
377 } | |
378 | |
379 ngx_stream_upstream_rr_peers_unlock(peers); | |
380 | |
381 pc->name = peers->name; | |
382 | |
383 return NGX_BUSY; | |
384 } | |
385 | |
386 | |
387 static ngx_stream_upstream_rr_peer_t * | |
388 ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) | |
389 { | |
390 time_t now; | |
391 uintptr_t m; | |
392 ngx_int_t total; | |
393 ngx_uint_t i, n, p; | |
394 ngx_stream_upstream_rr_peer_t *peer, *best; | |
395 | |
396 now = ngx_time(); | |
397 | |
398 best = NULL; | |
399 total = 0; | |
400 | |
401 #if (NGX_SUPPRESS_WARN) | |
402 p = 0; | |
403 #endif | |
404 | |
405 for (peer = rrp->peers->peer, i = 0; | |
406 peer; | |
407 peer = peer->next, i++) | |
408 { | |
409 | |
410 n = i / (8 * sizeof(uintptr_t)); | |
411 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | |
412 | |
413 if (rrp->tried[n] & m) { | |
414 continue; | |
415 } | |
416 | |
417 if (peer->down) { | |
418 continue; | |
419 } | |
420 | |
421 if (peer->max_fails | |
422 && peer->fails >= peer->max_fails | |
423 && now - peer->checked <= peer->fail_timeout) | |
424 { | |
425 continue; | |
426 } | |
427 | |
428 peer->current_weight += peer->effective_weight; | |
429 total += peer->effective_weight; | |
430 | |
431 if (peer->effective_weight < peer->weight) { | |
432 peer->effective_weight++; | |
433 } | |
434 | |
435 if (best == NULL || peer->current_weight > best->current_weight) { | |
436 best = peer; | |
437 p = i; | |
438 } | |
439 } | |
440 | |
441 if (best == NULL) { | |
442 return NULL; | |
443 } | |
444 | |
445 rrp->current = best; | |
446 | |
447 n = p / (8 * sizeof(uintptr_t)); | |
448 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); | |
449 | |
450 rrp->tried[n] |= m; | |
451 | |
452 best->current_weight -= total; | |
453 | |
454 if (now - best->checked > best->fail_timeout) { | |
455 best->checked = now; | |
456 } | |
457 | |
458 return best; | |
459 } | |
460 | |
461 | |
462 void | |
463 ngx_stream_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data, | |
464 ngx_uint_t state) | |
465 { | |
466 ngx_stream_upstream_rr_peer_data_t *rrp = data; | |
467 | |
468 time_t now; | |
469 ngx_stream_upstream_rr_peer_t *peer; | |
470 | |
471 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
472 "free rr peer %ui %ui", pc->tries, state); | |
473 | |
474 peer = rrp->current; | |
475 | |
476 ngx_stream_upstream_rr_peers_rlock(rrp->peers); | |
477 ngx_stream_upstream_rr_peer_lock(rrp->peers, peer); | |
478 | |
479 if (rrp->peers->single) { | |
480 peer->conns--; | |
481 | |
482 ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer); | |
483 ngx_stream_upstream_rr_peers_unlock(rrp->peers); | |
484 | |
485 pc->tries = 0; | |
486 return; | |
487 } | |
488 | |
489 if (state & NGX_PEER_FAILED) { | |
490 now = ngx_time(); | |
491 | |
492 peer->fails++; | |
493 peer->accessed = now; | |
494 peer->checked = now; | |
495 | |
496 if (peer->max_fails) { | |
497 peer->effective_weight -= peer->weight / peer->max_fails; | |
6154
cca856715722
Upstream: report to error_log when max_fails is reached.
Ruslan Ermilov <ru@nginx.com>
parents:
6115
diff
changeset
|
498 |
cca856715722
Upstream: report to error_log when max_fails is reached.
Ruslan Ermilov <ru@nginx.com>
parents:
6115
diff
changeset
|
499 if (peer->fails >= peer->max_fails) { |
cca856715722
Upstream: report to error_log when max_fails is reached.
Ruslan Ermilov <ru@nginx.com>
parents:
6115
diff
changeset
|
500 ngx_log_error(NGX_LOG_WARN, pc->log, 0, |
cca856715722
Upstream: report to error_log when max_fails is reached.
Ruslan Ermilov <ru@nginx.com>
parents:
6115
diff
changeset
|
501 "upstream server temporarily disabled"); |
cca856715722
Upstream: report to error_log when max_fails is reached.
Ruslan Ermilov <ru@nginx.com>
parents:
6115
diff
changeset
|
502 } |
6115 | 503 } |
504 | |
505 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
506 "free rr peer failed: %p %i", | |
507 peer, peer->effective_weight); | |
508 | |
509 if (peer->effective_weight < 0) { | |
510 peer->effective_weight = 0; | |
511 } | |
512 | |
513 } else { | |
514 | |
515 /* mark peer live if check passed */ | |
516 | |
517 if (peer->accessed < peer->checked) { | |
518 peer->fails = 0; | |
519 } | |
520 } | |
521 | |
522 peer->conns--; | |
523 | |
524 ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer); | |
525 ngx_stream_upstream_rr_peers_unlock(rrp->peers); | |
526 | |
527 if (pc->tries) { | |
528 pc->tries--; | |
529 } | |
530 } | |
531 | |
532 | |
533 #if (NGX_STREAM_SSL) | |
534 | |
535 static ngx_int_t | |
536 ngx_stream_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc, | |
537 void *data) | |
538 { | |
539 ngx_stream_upstream_rr_peer_data_t *rrp = data; | |
540 | |
541 ngx_int_t rc; | |
542 ngx_ssl_session_t *ssl_session; | |
543 ngx_stream_upstream_rr_peer_t *peer; | |
544 #if (NGX_STREAM_UPSTREAM_ZONE) | |
545 int len; | |
546 #if OPENSSL_VERSION_NUMBER >= 0x0090707fL | |
547 const | |
548 #endif | |
549 u_char *p; | |
550 ngx_stream_upstream_rr_peers_t *peers; | |
551 u_char buf[NGX_SSL_MAX_SESSION_SIZE]; | |
552 #endif | |
553 | |
554 peer = rrp->current; | |
555 | |
556 #if (NGX_STREAM_UPSTREAM_ZONE) | |
557 peers = rrp->peers; | |
558 | |
559 if (peers->shpool) { | |
560 ngx_stream_upstream_rr_peers_rlock(peers); | |
561 ngx_stream_upstream_rr_peer_lock(peers, peer); | |
562 | |
563 if (peer->ssl_session == NULL) { | |
564 ngx_stream_upstream_rr_peer_unlock(peers, peer); | |
565 ngx_stream_upstream_rr_peers_unlock(peers); | |
566 return NGX_OK; | |
567 } | |
568 | |
569 len = peer->ssl_session_len; | |
570 | |
571 ngx_memcpy(buf, peer->ssl_session, len); | |
572 | |
573 ngx_stream_upstream_rr_peer_unlock(peers, peer); | |
574 ngx_stream_upstream_rr_peers_unlock(peers); | |
575 | |
576 p = buf; | |
577 ssl_session = d2i_SSL_SESSION(NULL, &p, len); | |
578 | |
579 rc = ngx_ssl_set_session(pc->connection, ssl_session); | |
580 | |
581 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
582 "set session: %p", ssl_session); | |
583 | |
584 ngx_ssl_free_session(ssl_session); | |
585 | |
586 return rc; | |
587 } | |
588 #endif | |
589 | |
590 ssl_session = peer->ssl_session; | |
591 | |
592 rc = ngx_ssl_set_session(pc->connection, ssl_session); | |
593 | |
594 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
595 "set session: %p", ssl_session); | |
596 | |
597 return rc; | |
598 } | |
599 | |
600 | |
601 static void | |
602 ngx_stream_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, | |
603 void *data) | |
604 { | |
605 ngx_stream_upstream_rr_peer_data_t *rrp = data; | |
606 | |
607 ngx_ssl_session_t *old_ssl_session, *ssl_session; | |
608 ngx_stream_upstream_rr_peer_t *peer; | |
609 #if (NGX_STREAM_UPSTREAM_ZONE) | |
610 int len; | |
611 u_char *p; | |
612 ngx_stream_upstream_rr_peers_t *peers; | |
613 u_char buf[NGX_SSL_MAX_SESSION_SIZE]; | |
614 #endif | |
615 | |
616 #if (NGX_STREAM_UPSTREAM_ZONE) | |
617 peers = rrp->peers; | |
618 | |
619 if (peers->shpool) { | |
620 | |
621 ssl_session = SSL_get0_session(pc->connection->ssl->connection); | |
622 | |
623 if (ssl_session == NULL) { | |
624 return; | |
625 } | |
626 | |
627 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
628 "save session: %p", ssl_session); | |
629 | |
630 len = i2d_SSL_SESSION(ssl_session, NULL); | |
631 | |
632 /* do not cache too big session */ | |
633 | |
634 if (len > NGX_SSL_MAX_SESSION_SIZE) { | |
635 return; | |
636 } | |
637 | |
638 p = buf; | |
639 (void) i2d_SSL_SESSION(ssl_session, &p); | |
640 | |
641 peer = rrp->current; | |
642 | |
643 ngx_stream_upstream_rr_peers_rlock(peers); | |
644 ngx_stream_upstream_rr_peer_lock(peers, peer); | |
645 | |
646 if (len > peer->ssl_session_len) { | |
647 ngx_shmtx_lock(&peers->shpool->mutex); | |
648 | |
649 if (peer->ssl_session) { | |
650 ngx_slab_free_locked(peers->shpool, peer->ssl_session); | |
651 } | |
652 | |
653 peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len); | |
654 | |
655 ngx_shmtx_unlock(&peers->shpool->mutex); | |
656 | |
657 if (peer->ssl_session == NULL) { | |
658 peer->ssl_session_len = 0; | |
659 | |
660 ngx_stream_upstream_rr_peer_unlock(peers, peer); | |
661 ngx_stream_upstream_rr_peers_unlock(peers); | |
662 return; | |
663 } | |
664 | |
665 peer->ssl_session_len = len; | |
666 } | |
667 | |
668 ngx_memcpy(peer->ssl_session, buf, len); | |
669 | |
670 ngx_stream_upstream_rr_peer_unlock(peers, peer); | |
671 ngx_stream_upstream_rr_peers_unlock(peers); | |
672 | |
673 return; | |
674 } | |
675 #endif | |
676 | |
677 ssl_session = ngx_ssl_get_session(pc->connection); | |
678 | |
679 if (ssl_session == NULL) { | |
680 return; | |
681 } | |
682 | |
683 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
684 "save session: %p", ssl_session); | |
685 | |
686 peer = rrp->current; | |
687 | |
688 old_ssl_session = peer->ssl_session; | |
689 peer->ssl_session = ssl_session; | |
690 | |
691 if (old_ssl_session) { | |
692 | |
693 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
694 "old session: %p", old_ssl_session); | |
695 | |
696 /* TODO: may block */ | |
697 | |
698 ngx_ssl_free_session(old_ssl_session); | |
699 } | |
700 } | |
701 | |
702 #endif |