comparison src/core/ngx_inet.c @ 400:6ebbca3d5ed7 NGINX_0_7_12

nginx 0.7.12 *) Feature: the "server_name" directive supports empty name "". *) Feature: the "gzip_disable" directive supports special "msie6" mask. *) Bugfix: if the "max_fails=0" parameter was used in upstream with several servers, then a worker process exited on a SIGFPE signal. Thanks to Maxim Dounin. *) Bugfix: a request body was dropped while redirection via an "error_page" directive. *) Bugfix: a full response was returned for request method HEAD while redirection via an "error_page" directive. *) Bugfix: the $r->header_in() method did not return value of the "Host", "User-Agent", and "Connection" request header lines; the bug had appeared in 0.7.0.
author Igor Sysoev <http://sysoev.ru>
date Tue, 26 Aug 2008 00:00:00 +0400
parents 984bb0b1399b
children b4f69f2ef02c
comparison
equal deleted inserted replaced
399:59e324e4d6d3 400:6ebbca3d5ed7
6 6
7 #include <ngx_config.h> 7 #include <ngx_config.h>
8 #include <ngx_core.h> 8 #include <ngx_core.h>
9 9
10 10
11 static size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len); 11 static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
12 static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
12 13
13 14
14 /* AF_INET only */ 15 /* AF_INET only */
15 16
16 in_addr_t 17 in_addr_t
54 55
55 return INADDR_NONE; 56 return INADDR_NONE;
56 } 57 }
57 58
58 59
59 /*
60 * ngx_sock_ntop() and ngx_inet_ntop() may be implemented as
61 * "ngx_sprintf(text, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3])", however,
62 * they had been implemented long before the ngx_sprintf() had appeared
63 * and they are faster by 1.5-2.5 times, so it is worth to keep them.
64 *
65 * By the way, the implementation using ngx_sprintf() is faster by 2.5-3 times
66 * than using FreeBSD libc's snprintf().
67 */
68
69 /* AF_INET only */ 60 /* AF_INET only */
70 61
71 size_t 62 size_t
72 ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len) 63 ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len)
73 { 64 {
74 u_char *p; 65 u_char *p;
75 size_t n;
76 ngx_uint_t i;
77 struct sockaddr_in *sin; 66 struct sockaddr_in *sin;
78 67
79 if (len == 0) { 68 if (sa->sa_family == AF_INET) {
80 return 0; 69
81 } 70 sin = (struct sockaddr_in *) sa;
82 71 p = (u_char *) &sin->sin_addr;
83 if (family != AF_INET) { 72
84 return 0; 73 return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
85 } 74 p[0], p[1], p[2], p[3])
86 75 - text;
87 sin = (struct sockaddr_in *) sa; 76 }
88 p = (u_char *) &sin->sin_addr; 77
89 78 return 0;
90 if (len > INET_ADDRSTRLEN) {
91 len = INET_ADDRSTRLEN;
92 }
93
94 n = ngx_sprint_uchar(text, p[0], len);
95
96 i = 1;
97
98 do {
99 if (len == n) {
100 text[n - 1] = '\0';
101 return n;
102 }
103
104 text[n++] = '.';
105
106 if (len == n) {
107 text[n - 1] = '\0';
108 return n;
109 }
110
111 n += ngx_sprint_uchar(&text[n], p[i++], len - n);
112
113 } while (i < 4);
114
115 if (len == n) {
116 text[n] = '\0';
117 return n;
118 }
119
120 text[n] = '\0';
121
122 return n;
123 } 79 }
124 80
125 81
126 size_t 82 size_t
127 ngx_inet_ntop(int family, void *addr, u_char *text, size_t len) 83 ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
128 { 84 {
129 u_char *p; 85 u_char *p;
130 size_t n; 86
131 ngx_uint_t i; 87 if (family == AF_INET) {
132 88
133 if (len == 0) { 89 p = (u_char *) addr;
134 return 0; 90
135 } 91 return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
136 92 p[0], p[1], p[2], p[3])
137 if (family != AF_INET) { 93 - text;
138 return 0; 94 }
139 } 95
140 96 return 0;
141 p = (u_char *) addr;
142
143 if (len > INET_ADDRSTRLEN) {
144 len = INET_ADDRSTRLEN;
145 }
146
147 n = ngx_sprint_uchar(text, p[0], len);
148
149 i = 1;
150
151 do {
152 if (len == n) {
153 text[n - 1] = '\0';
154 return n;
155 }
156
157 text[n++] = '.';
158
159 if (len == n) {
160 text[n - 1] = '\0';
161 return n;
162 }
163
164 n += ngx_sprint_uchar(&text[n], p[i++], len - n);
165
166 } while (i < 4);
167
168 if (len == n) {
169 text[n] = '\0';
170 return n;
171 }
172
173 text[n] = '\0';
174
175 return n;
176 }
177
178
179 static size_t
180 ngx_sprint_uchar(u_char *text, u_char c, size_t len)
181 {
182 size_t n;
183 ngx_uint_t c1, c2;
184
185 n = 0;
186
187 if (len == n) {
188 return n;
189 }
190
191 c1 = c / 100;
192
193 if (c1) {
194 *text++ = (u_char) (c1 + '0');
195 n++;
196
197 if (len == n) {
198 return n;
199 }
200 }
201
202 c2 = (c % 100) / 10;
203
204 if (c1 || c2) {
205 *text++ = (u_char) (c2 + '0');
206 n++;
207
208 if (len == n) {
209 return n;
210 }
211 }
212
213 c2 = c % 10;
214
215 *text = (u_char) (c2 + '0');
216 n++;
217
218 return n;
219 } 97 }
220 98
221 99
222 /* AF_INET only */ 100 /* AF_INET only */
223 101
224 ngx_int_t 102 ngx_int_t
225 ngx_ptocidr(ngx_str_t *text, void *cidr) 103 ngx_ptocidr(ngx_str_t *text, void *cidr)
226 { 104 {
227 ngx_int_t m; 105 u_char *addr, *mask, *last;
228 ngx_uint_t i; 106 ngx_int_t shift;
229 ngx_inet_cidr_t *in_cidr; 107 ngx_inet_cidr_t *in_cidr;
230 108
231 in_cidr = cidr; 109 in_cidr = cidr;
232 110 addr = text->data;
233 for (i = 0; i < text->len; i++) { 111 last = addr + text->len;
234 if (text->data[i] == '/') { 112
235 break; 113 mask = ngx_strlchr(addr, last, '/');
236 } 114
237 } 115 in_cidr->addr = ngx_inet_addr(addr, (mask ? mask : last) - addr);
238 116
239 if (i == text->len) {
240 return NGX_ERROR;
241 }
242
243 text->data[i] = '\0';
244 in_cidr->addr = inet_addr((char *) text->data);
245 text->data[i] = '/';
246 if (in_cidr->addr == INADDR_NONE) { 117 if (in_cidr->addr == INADDR_NONE) {
247 return NGX_ERROR; 118 return NGX_ERROR;
248 } 119 }
249 120
250 m = ngx_atoi(&text->data[i + 1], text->len - (i + 1)); 121 if (mask == NULL) {
251 if (m == NGX_ERROR) { 122 in_cidr->mask = 0xffffffff;
252 return NGX_ERROR; 123 return NGX_OK;
253 } 124 }
254 125
255 if (m == 0) { 126 mask++;
127
128 shift = ngx_atoi(mask, last - mask);
129 if (shift == NGX_ERROR) {
130 return NGX_ERROR;
131 }
132
133 if (shift == 0) {
256 134
257 /* the x86 compilers use the shl instruction that shifts by modulo 32 */ 135 /* the x86 compilers use the shl instruction that shifts by modulo 32 */
258 136
259 in_cidr->mask = 0; 137 in_cidr->mask = 0;
260 return NGX_OK; 138
261 } 139 if (in_cidr->addr == 0) {
262 140 return NGX_OK;
263 in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - m)))); 141 }
142
143 return NGX_DONE;
144 }
145
146 in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
264 147
265 if (in_cidr->addr == (in_cidr->addr & in_cidr->mask)) { 148 if (in_cidr->addr == (in_cidr->addr & in_cidr->mask)) {
266 return NGX_OK; 149 return NGX_OK;
267 } 150 }
268 151
273 156
274 157
275 ngx_int_t 158 ngx_int_t
276 ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) 159 ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
277 { 160 {
278 u_char *p, *host, *port_start; 161 u_char *p;
279 size_t len, port_len; 162
280 ngx_int_t port; 163 p = u->url.data;
281 ngx_uint_t i; 164
282 struct hostent *h; 165 if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
166 return ngx_parse_unix_domain_url(pool, u);
167 }
168
169 if ((p[0] == ':' || p[0] == '/') && !u->listen) {
170 u->err = "invalid host";
171 return NGX_ERROR;
172 }
173
174 return ngx_parse_inet_url(pool, u);
175 }
176
177
178 static ngx_int_t
179 ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
180 {
283 #if (NGX_HAVE_UNIX_DOMAIN) 181 #if (NGX_HAVE_UNIX_DOMAIN)
182 u_char *path, *uri, *last;
183 size_t len;
284 struct sockaddr_un *saun; 184 struct sockaddr_un *saun;
185
186 len = u->url.len;
187 path = u->url.data;
188
189 path += 5;
190 len -= 5;
191
192 if (u->uri_part) {
193
194 last = path + len;
195 uri = ngx_strlchr(path, last, ':');
196
197 if (uri) {
198 len = uri - path;
199 uri++;
200 u->uri.len = last - uri;
201 u->uri.data = uri;
202 }
203 }
204
205 if (len == 0) {
206 u->err = "no path in the unix domain socket";
207 return NGX_ERROR;
208 }
209
210 u->host.len = len++;
211 u->host.data = path;
212 u->family = AF_UNIX;
213
214 if (len > sizeof(saun->sun_path)) {
215 u->err = "too long path in the unix domain socket";
216 return NGX_ERROR;
217 }
218
219 u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
220 if (u->addrs == NULL) {
221 return NGX_ERROR;
222 }
223
224 saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
225 if (saun == NULL) {
226 return NGX_ERROR;
227 }
228
229 u->naddrs = 1;
230
231 saun->sun_family = AF_UNIX;
232 (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
233
234 u->addrs[0].sockaddr = (struct sockaddr *) saun;
235 u->addrs[0].socklen = sizeof(struct sockaddr_un);
236 u->addrs[0].name.len = len + 4;
237 u->addrs[0].name.data = u->url.data;
238
239 return NGX_OK;
240
241 #else
242
243 u->err = "the unix domain sockets are not supported on this platform";
244
245 return NGX_ERROR;
246
285 #endif 247 #endif
286 248 }
287 len = u->url.len; 249
288 p = u->url.data; 250
289 251 static ngx_int_t
290 if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { 252 ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
291 253 {
292 #if (NGX_HAVE_UNIX_DOMAIN) 254 u_char *p, *host, *port, *last, *uri;
293 255 size_t len;
294 p += 5; 256 ngx_int_t n;
295 len -= 5; 257 struct hostent *h;
296 258
297 u->uri.len = len; 259 u->family = AF_INET;
298 u->uri.data = p; 260
299 261 host = u->url.data;
300 if (u->uri_part) { 262
301 for (i = 0; i < len; i++) { 263 last = host + u->url.len;
302 264
303 if (p[i] == ':') { 265 port = ngx_strlchr(host, last, ':');
304 len = i; 266
305 267 uri = ngx_strlchr(port ? port : host, last, '/');
306 u->uri.len -= len + 1; 268
307 u->uri.data += len + 1; 269 if (uri) {
308 270 if (u->listen || !u->uri_part) {
309 break; 271 u->err = "invalid host";
272 return NGX_ERROR;
273 }
274
275 u->uri.len = last - uri;
276 u->uri.data = uri;
277
278 last = uri;
279 }
280
281 if (port) {
282 port++;
283
284 len = last - port;
285
286 if (len == 0) {
287 u->err = "invalid port";
288 return NGX_ERROR;
289 }
290
291 n = ngx_atoi(port, len);
292
293 if (n < 1 || n > 65536) {
294 u->err = "invalid port";
295 return NGX_ERROR;
296 }
297
298 u->port = (in_port_t) n;
299
300 u->port_text.len = len;
301 u->port_text.data = port;
302
303 last = port - 1;
304
305 } else {
306 if (uri == NULL) {
307
308 if (u->listen) {
309
310 /* test value as port only */
311
312 n = ngx_atoi(host, last - host);
313
314 if (n != NGX_ERROR) {
315
316 if (n < 1 || n > 65536) {
317 u->err = "invalid port";
318 return NGX_ERROR;
319 }
320
321 u->port = (in_port_t) n;
322
323 u->port_text.len = last - host;
324 u->port_text.data = host;
325
326 return NGX_OK;
310 } 327 }
311 } 328 }
312 } 329 }
313 330
314 if (len == 0) { 331 u->no_port = 1;
315 u->err = "no path in the unix domain socket"; 332 }
316 return NGX_ERROR; 333
317 } 334 len = last - host;
318 335
319 if (len + 1 > sizeof(saun->sun_path)) { 336 if (len == 0) {
320 u->err = "too long path in the unix domain socket"; 337 u->err = "no host";
321 return NGX_ERROR; 338 return NGX_ERROR;
322 } 339 }
323 340
324 u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); 341 if (len == 1 && *host == '*') {
325 if (u->addrs == NULL) { 342 len = 0;
326 return NGX_ERROR; 343 }
327 } 344
328 345 u->host.len = len;
329 saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un)); 346 u->host.data = host;
330 if (saun == NULL) { 347
331 return NGX_ERROR; 348 if (u->no_resolve) {
332 }
333
334 u->naddrs = 1;
335
336 saun->sun_family = AF_UNIX;
337 (void) ngx_cpystrn((u_char *) saun->sun_path, p, len + 1);
338
339 u->addrs[0].sockaddr = (struct sockaddr *) saun;
340 u->addrs[0].socklen = sizeof(struct sockaddr_un);
341 u->addrs[0].name.len = len + 5;
342 u->addrs[0].name.data = u->url.data;
343
344 u->host.len = len;
345 u->host.data = p;
346
347 u->unix_socket = 1;
348
349 return NGX_OK; 349 return NGX_OK;
350 350 }
351 #else 351
352 u->err = "the unix domain sockets are not supported on this platform"; 352 if (len++) {
353 353
354 return NGX_ERROR; 354 p = ngx_alloc(len, pool->log);
355 355 if (p == NULL) {
356 #endif 356 return NGX_ERROR;
357 } 357 }
358 358
359 if ((p[0] == ':' || p[0] == '/') && !u->listen) { 359 (void) ngx_cpystrn(p, host, len);
360 u->err = "invalid host"; 360
361 return NGX_ERROR; 361 u->addr.in_addr = inet_addr((const char *) p);
362 } 362
363 363 if (u->addr.in_addr == INADDR_NONE) {
364 u->host.data = p; 364 h = gethostbyname((const char *) p);
365 365
366 port_start = NULL; 366 if (h == NULL || h->h_addr_list[0] == NULL) {
367 port_len = 0; 367 ngx_free(p);
368 368 u->err = "host not found";
369 for (i = 0; i < len; i++) {
370
371 if (p[i] == ':') {
372 port_start = &p[i + 1];
373 u->host.len = i;
374
375 if (!u->uri_part) {
376 port_len = len - (i + 1);
377 break;
378 }
379 }
380
381 if (p[i] == '/') {
382 u->uri.len = len - i;
383 u->uri.data = &p[i];
384
385 if (u->host.len == 0) {
386 u->host.len = i;
387 }
388
389 if (port_start == NULL) {
390 u->no_port = 1;
391 goto no_port;
392 }
393
394 port_len = &p[i] - port_start;
395
396 if (port_len == 0) {
397 u->err = "invalid port";
398 return NGX_ERROR; 369 return NGX_ERROR;
399 } 370 }
400 371
401 break; 372 u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]);
402 } 373 }
403 } 374
404 375 ngx_free(p);
405 if (port_start) {
406
407 if (port_len == 0) {
408 port_len = &p[i] - port_start;
409
410 if (port_len == 0) {
411 u->err = "invalid port";
412 return NGX_ERROR;
413 }
414 }
415
416 port = ngx_atoi(port_start, port_len);
417
418 if (port == NGX_ERROR || port < 1 || port > 65536) {
419 u->err = "invalid port";
420 return NGX_ERROR;
421 }
422
423 u->port_text.len = port_len;
424 u->port_text.data = port_start;
425 376
426 } else { 377 } else {
427 port = ngx_atoi(p, len); 378 u->addr.in_addr = INADDR_ANY;
428
429 if (port == NGX_ERROR) {
430 u->host.len = len;
431 u->no_port = 1;
432
433 goto no_port;
434 }
435
436 u->wildcard = 1;
437 }
438
439 u->port = (in_port_t) port;
440
441 no_port:
442
443 if (u->listen) {
444
445 if (u->port == 0) {
446 if (u->default_port == 0) {
447 u->err = "no port";
448 return NGX_ERROR;
449 }
450
451 u->port = u->default_port;
452 }
453
454 if (u->host.len == 1 && u->host.data[0] == '*') {
455 u->host.len = 0;
456 }
457
458 /* AF_INET only */
459
460 if (u->host.len) {
461
462 host = ngx_alloc(u->host.len + 1, pool->log);
463 if (host == NULL) {
464 return NGX_ERROR;
465 }
466
467 (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
468
469 u->addr.in_addr = inet_addr((const char *) host);
470
471 if (u->addr.in_addr == INADDR_NONE) {
472 h = gethostbyname((const char *) host);
473
474 if (h == NULL || h->h_addr_list[0] == NULL) {
475 ngx_free(host);
476 u->err = "host not found";
477 return NGX_ERROR;
478 }
479
480 u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]);
481 }
482
483 ngx_free(host);
484
485 } else {
486 u->addr.in_addr = INADDR_ANY;
487 }
488
489 return NGX_OK;
490 }
491
492 if (u->host.len == 0) {
493 u->err = "no host";
494 return NGX_ERROR;
495 }
496
497 if (u->no_resolve) {
498 return NGX_OK;
499 } 379 }
500 380
501 if (u->no_port) { 381 if (u->no_port) {
502 u->port = u->default_port; 382 u->port = u->default_port;
503 } 383 }
504 384
505 if (u->port == 0) { 385 if (u->listen) {
506 u->err = "no port"; 386 return NGX_OK;
507 return NGX_ERROR;
508 } 387 }
509 388
510 if (ngx_inet_resolve_host(pool, u) != NGX_OK) { 389 if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
511 return NGX_ERROR; 390 return NGX_ERROR;
512 } 391 }
574 sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); 453 sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
575 454
576 u->addrs[i].sockaddr = (struct sockaddr *) sin; 455 u->addrs[i].sockaddr = (struct sockaddr *) sin;
577 u->addrs[i].socklen = sizeof(struct sockaddr_in); 456 u->addrs[i].socklen = sizeof(struct sockaddr_in);
578 457
579 len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1; 458 len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
580 459
581 p = ngx_pnalloc(pool, len); 460 p = ngx_pnalloc(pool, len);
582 if (p == NULL) { 461 if (p == NULL) {
583 return NGX_ERROR; 462 return NGX_ERROR;
584 } 463 }
585 464
586 len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, p, len); 465 len = ngx_sock_ntop((struct sockaddr *) sin, p, len);
587 466
588 u->addrs[i].name.len = ngx_sprintf(&p[len], ":%d", u->port) - p; 467 u->addrs[i].name.len = ngx_sprintf(&p[len], ":%d", u->port) - p;
589 u->addrs[i].name.data = p; 468 u->addrs[i].name.data = p;
590 } 469 }
591 470