comparison src/imap/ngx_imap_auth_http_module.c @ 76:da9a3b14312d NGINX_0_1_38

nginx 0.1.38 *) Feature: the "limit_rate" directive is supported in in proxy and FastCGI mode. *) Feature: the "X-Accel-Limit-Rate" response header line is supported in proxy and FastCGI mode. *) Feature: the "break" directive. *) Feature: the "log_not_found" directive. *) Bugfix: the response status code was not changed when request was redirected by the ""X-Accel-Redirect" header line. *) Bugfix: the variables set by the "set" directive could not be used in SSI. *) Bugfix: the segmentation fault may occurred if the SSI page has more than one remote subrequest. *) Bugfix: nginx treated the backend response as invalid if the status line in the header was transferred in two packets; bug appeared in 0.1.29. *) Feature: the "ssi_types" directive. *) Feature: the "autoindex_exact_size" directive. *) Bugfix: the ngx_http_autoindex_module did not support the long file names in UTF-8. *) Feature: the IMAP/POP3 proxy.
author Igor Sysoev <http://sysoev.ru>
date Fri, 08 Jul 2005 00:00:00 +0400
parents
children e916a291e9aa
comparison
equal deleted inserted replaced
75:985847bb65f9 76:da9a3b14312d
1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10 #include <ngx_event_connect.h>
11 #include <ngx_imap.h>
12
13
14 typedef struct {
15 ngx_peers_t *peers;
16
17 ngx_msec_t timeout;
18
19 ngx_str_t host_header;
20 ngx_str_t uri;
21 } ngx_imap_auth_http_conf_t;
22
23
24 typedef struct ngx_imap_auth_http_ctx_s ngx_imap_auth_http_ctx_t;
25
26 typedef void (*ngx_imap_auth_http_handler_pt)(ngx_imap_session_t *s,
27 ngx_imap_auth_http_ctx_t *ctx);
28
29 struct ngx_imap_auth_http_ctx_s {
30 ngx_buf_t *request;
31 ngx_buf_t *response;
32 ngx_peer_connection_t peer;
33
34 ngx_imap_auth_http_handler_pt handler;
35
36 ngx_uint_t state;
37 ngx_uint_t hash; /* no needed ? */
38
39 u_char *header_name_start;
40 u_char *header_name_end;
41 u_char *header_start;
42 u_char *header_end;
43
44 ngx_str_t addr;
45 ngx_str_t port;
46 ngx_str_t err;
47
48 ngx_msec_t sleep;
49
50 ngx_peers_t *peers;
51 };
52
53
54 static void ngx_imap_auth_http_write_handler(ngx_event_t *wev);
55 static void ngx_imap_auth_http_read_handler(ngx_event_t *rev);
56 static void ngx_imap_auth_http_ignore_status_line(ngx_imap_session_t *s,
57 ngx_imap_auth_http_ctx_t *ctx);
58 static void ngx_imap_auth_http_process_headers(ngx_imap_session_t *s,
59 ngx_imap_auth_http_ctx_t *ctx);
60 static void ngx_imap_auth_sleep_handler(ngx_event_t *rev);
61 static ngx_int_t ngx_imap_auth_http_parse_header_line(ngx_imap_session_t *s,
62 ngx_imap_auth_http_ctx_t *ctx);
63 static void ngx_imap_auth_http_block_read(ngx_event_t *rev);
64 static void ngx_imap_auth_http_dummy_handler(ngx_event_t *ev);
65 static ngx_buf_t *ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
66 ngx_imap_auth_http_conf_t *ahcf);
67
68 static void *ngx_imap_auth_http_create_conf(ngx_conf_t *cf);
69 static char *ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
70 void *child);
71 static char *ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
72
73
74 static ngx_command_t ngx_imap_auth_http_commands[] = {
75
76 { ngx_string("auth_http"),
77 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
78 ngx_imap_auth_http,
79 NGX_IMAP_SRV_CONF_OFFSET,
80 0,
81 NULL },
82
83 { ngx_string("auth_http_timeout"),
84 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
85 ngx_conf_set_msec_slot,
86 NGX_IMAP_SRV_CONF_OFFSET,
87 offsetof(ngx_imap_auth_http_conf_t, timeout),
88 NULL },
89
90 ngx_null_command
91 };
92
93
94 static ngx_imap_module_t ngx_imap_auth_http_module_ctx = {
95 NULL, /* create main configuration */
96 NULL, /* init main configuration */
97
98 ngx_imap_auth_http_create_conf, /* create server configuration */
99 ngx_imap_auth_http_merge_conf /* merge server configuration */
100 };
101
102
103 ngx_module_t ngx_imap_auth_http_module = {
104 NGX_MODULE_V1,
105 &ngx_imap_auth_http_module_ctx, /* module context */
106 ngx_imap_auth_http_commands, /* module directives */
107 NGX_IMAP_MODULE, /* module type */
108 NULL, /* init module */
109 NULL /* init process */
110 };
111
112
113 static char *ngx_imap_auth_http_protocol[] = { "pop3", "imap" };
114
115
116 void
117 ngx_imap_auth_http_init(ngx_imap_session_t *s)
118 {
119 ngx_int_t rc;
120 ngx_imap_auth_http_ctx_t *ctx;
121 ngx_imap_auth_http_conf_t *ahcf;
122
123 ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_auth_http_ctx_t));
124 if (ctx == NULL) {
125 ngx_imap_session_internal_server_error(s);
126 return;
127 }
128
129 ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module);
130
131 ctx->request = ngx_imap_auth_http_create_request(s, ahcf);
132 if (ctx->request == NULL) {
133 ngx_imap_session_internal_server_error(s);
134 return;
135 }
136
137 ngx_imap_set_ctx(s, ctx, ngx_imap_auth_http_module);
138
139 ctx->peer.peers = ahcf->peers;
140 ctx->peer.log = s->connection->log;
141 ctx->peer.log_error = NGX_ERROR_ERR;
142
143 rc = ngx_event_connect_peer(&ctx->peer);
144
145 if (rc == NGX_ERROR) {
146 ngx_imap_session_internal_server_error(s);
147 return;
148 }
149
150 ctx->peer.connection->data = s;
151 ctx->peer.connection->pool = s->connection->pool;
152
153 s->connection->read->handler = ngx_imap_auth_http_block_read;
154 ctx->peer.connection->read->handler = ngx_imap_auth_http_read_handler;
155 ctx->peer.connection->write->handler = ngx_imap_auth_http_write_handler;
156
157 ctx->handler = ngx_imap_auth_http_ignore_status_line;
158
159 if (rc == NGX_OK) {
160 ngx_imap_auth_http_write_handler(ctx->peer.connection->write);
161 return;
162 }
163
164 ngx_add_timer(ctx->peer.connection->read, ahcf->timeout);
165 ngx_add_timer(ctx->peer.connection->write, ahcf->timeout);
166 }
167
168
169 static void
170 ngx_imap_auth_http_write_handler(ngx_event_t *wev)
171 {
172 ssize_t n, size;
173 ngx_connection_t *c;
174 ngx_imap_session_t *s;
175 ngx_imap_auth_http_ctx_t *ctx;
176 ngx_imap_auth_http_conf_t *ahcf;
177
178 c = wev->data;
179 s = c->data;
180
181 ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module);
182
183 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, wev->log, 0,
184 "imap auth http write handler");
185
186 if (wev->timedout) {
187 ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
188 "auth http server timed out");
189 ngx_close_connection(ctx->peer.connection);
190 ngx_imap_session_internal_server_error(s);
191 return;
192 }
193
194 size = ctx->request->last - ctx->request->pos;
195
196 n = ngx_send(c, ctx->request->pos, size);
197
198 if (n == NGX_ERROR) {
199 ngx_close_connection(ctx->peer.connection);
200 ngx_imap_session_internal_server_error(s);
201 return;
202 }
203
204 if (n > 0) {
205 ctx->request->pos += n;
206
207 if (n == size) {
208 wev->handler = ngx_imap_auth_http_dummy_handler;
209
210 if (wev->timer_set) {
211 ngx_del_timer(wev);
212 }
213
214 return;
215 }
216 }
217
218 if (!wev->timer_set) {
219 ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module);
220 ngx_add_timer(wev, ahcf->timeout);
221 }
222 }
223
224
225 static void
226 ngx_imap_auth_http_read_handler(ngx_event_t *rev)
227 {
228 ssize_t n, size;
229 ngx_connection_t *c;
230 ngx_imap_session_t *s;
231 ngx_imap_auth_http_ctx_t *ctx;
232
233 c = rev->data;
234 s = c->data;
235
236 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
237 "imap auth http read handler");
238
239 ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module);
240
241 if (rev->timedout) {
242 ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
243 "auth http server timed out");
244 ngx_close_connection(ctx->peer.connection);
245 ngx_imap_session_internal_server_error(s);
246 return;
247 }
248
249 if (ctx->response == NULL) {
250 ctx->response = ngx_create_temp_buf(s->connection->pool, 1024);
251 if (ctx->response == NULL) {
252 ngx_close_connection(ctx->peer.connection);
253 ngx_imap_session_internal_server_error(s);
254 return;
255 }
256 }
257
258 size = ctx->response->end - ctx->response->last;
259
260 n = ngx_recv(c, ctx->response->pos, size);
261
262 if (n > 0) {
263 ctx->response->last += n;
264
265 ctx->handler(s, ctx);
266 return;
267 }
268
269 if (n == NGX_AGAIN) {
270 return;
271 }
272
273 ngx_close_connection(ctx->peer.connection);
274 ngx_imap_session_internal_server_error(s);
275 }
276
277
278 static void
279 ngx_imap_auth_http_ignore_status_line(ngx_imap_session_t *s,
280 ngx_imap_auth_http_ctx_t *ctx)
281 {
282 u_char *p, ch;
283 enum {
284 sw_start = 0,
285 sw_H,
286 sw_HT,
287 sw_HTT,
288 sw_HTTP,
289 sw_skip,
290 sw_almost_done
291 } state;
292
293 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
294 "imap auth http process status line");
295
296 state = ctx->state;
297
298 for (p = ctx->response->pos; p < ctx->response->last; p++) {
299 ch = *p;
300
301 switch (state) {
302
303 /* "HTTP/" */
304 case sw_start:
305 if (ch == 'H') {
306 state = sw_H;
307 break;
308 }
309 goto next;
310
311 case sw_H:
312 if (ch == 'T') {
313 state = sw_HT;
314 break;
315 }
316 goto next;
317
318 case sw_HT:
319 if (ch == 'T') {
320 state = sw_HTT;
321 break;
322 }
323 goto next;
324
325 case sw_HTT:
326 if (ch == 'P') {
327 state = sw_HTTP;
328 break;
329 }
330 goto next;
331
332 case sw_HTTP:
333 if (ch == '/') {
334 state = sw_skip;
335 break;
336 }
337 goto next;
338
339 /* any text until end of line */
340 case sw_skip:
341 switch (ch) {
342 case CR:
343 state = sw_almost_done;
344
345 break;
346 case LF:
347 goto done;
348 }
349 break;
350
351 /* end of status line */
352 case sw_almost_done:
353 if (ch == LF) {
354 goto done;
355 }
356
357 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
358 "auth http server sent invalid response");
359 ngx_close_connection(ctx->peer.connection);
360 ngx_imap_session_internal_server_error(s);
361 return;
362 }
363 }
364
365 ctx->response->pos = p;
366 ctx->state = state;
367
368 return;
369
370 next:
371
372 p = ctx->response->start - 1;
373
374 done:
375
376 ctx->response->pos = p + 1;
377 ctx->state = 0;
378 ctx->handler = ngx_imap_auth_http_process_headers;
379 ctx->handler(s, ctx);
380 }
381
382
383 static void
384 ngx_imap_auth_http_process_headers(ngx_imap_session_t *s,
385 ngx_imap_auth_http_ctx_t *ctx)
386 {
387 u_char *p;
388 size_t len, size;
389 ngx_int_t rc, port, n;
390 struct sockaddr_in *sin;
391
392 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
393 "imap auth http process headers");
394
395 for ( ;; ) {
396 rc = ngx_imap_auth_http_parse_header_line(s, ctx);
397
398 if (rc == NGX_OK) {
399
400 #if (NGX_DEBUG)
401 {
402 ngx_str_t key, value;
403
404 key.len = ctx->header_name_end - ctx->header_name_start;
405 key.data = ctx->header_name_start;
406 value.len = ctx->header_end - ctx->header_start;
407 value.data = ctx->header_start;
408
409 ngx_log_debug2(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
410 "auth http header: \"%V: %V\"",
411 &key, &value);
412 }
413 #endif
414
415 len = ctx->header_name_end - ctx->header_name_start;
416
417 if (len == sizeof("Auth-Status") - 1
418 && ngx_strncasecmp(ctx->header_name_start, "Auth-Status",
419 sizeof("Auth-Status") - 1) == 0)
420 {
421 len = ctx->header_end - ctx->header_start;
422
423 if (len == 2
424 && ctx->header_start[0] == 'O'
425 && ctx->header_start[1] == 'K')
426 {
427 continue;
428 }
429
430 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
431 size = sizeof("-ERR") - 1 + len + sizeof(CRLF) - 1;
432
433 } else {
434 size = s->tag.len + sizeof("NO") - 1 + len
435 + sizeof(CRLF) - 1;
436 }
437
438 p = ngx_pcalloc(s->connection->pool, size);
439 if (p == NULL) {
440 ngx_imap_session_internal_server_error(s);
441 return;
442 }
443
444 ctx->err.data = p;
445
446 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
447 *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R';
448
449 } else {
450 p = ngx_cpymem(p, s->tag.data, s->tag.len);
451 *p++ = 'N'; *p++ = 'O';
452 }
453
454 *p++ = ' ';
455 p = ngx_cpymem(p, ctx->header_start, len);
456 *p++ = CR; *p++ = LF;
457
458 ctx->err.len = p - ctx->err.data;
459
460 continue;
461 }
462
463 if (len == sizeof("Auth-Server") - 1
464 && ngx_strncasecmp(ctx->header_name_start, "Auth-Server",
465 sizeof("Auth-Server") - 1) == 0)
466 {
467 ctx->addr.len = ctx->header_end - ctx->header_start;
468 ctx->addr.data = ctx->header_start;
469
470 continue;
471 }
472
473 if (len == sizeof("Auth-Port") - 1
474 && ngx_strncasecmp(ctx->header_name_start, "Auth-Port",
475 sizeof("Auth-Port") - 1) == 0)
476 {
477 ctx->port.len = ctx->header_end - ctx->header_start;
478 ctx->port.data = ctx->header_start;
479
480 continue;
481 }
482
483 if (len == sizeof("Auth-User") - 1
484 && ngx_strncasecmp(ctx->header_name_start, "Auth-User",
485 sizeof("Auth-User") - 1) == 0)
486 {
487 s->login.len = ctx->header_end - ctx->header_start;
488 s->login.data = ctx->header_start;
489
490 continue;
491 }
492
493 if (len == sizeof("Auth-Wait") - 1
494 && ngx_strncasecmp(ctx->header_name_start, "Auth-Wait",
495 sizeof("Auth-Wait") - 1) == 0)
496 {
497 n = ngx_atoi(ctx->header_start,
498 ctx->header_end - ctx->header_start);
499
500 if (n != NGX_ERROR) {
501 ctx->sleep = n;
502 }
503
504 continue;
505 }
506
507 /* ignore other headers */
508
509 continue;
510 }
511
512 if (rc == NGX_DONE) {
513 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
514 "auth http header done");
515
516 ngx_close_connection(ctx->peer.connection);
517
518 if (ctx->err.len) {
519 (void) ngx_send(s->connection, ctx->err.data, ctx->err.len);
520
521 if (ctx->sleep == 0) {
522 ngx_imap_close_connection(s->connection);
523 return;
524 }
525
526 ngx_add_timer(s->connection->read, ctx->sleep * 1000);
527
528 s->connection->read->handler = ngx_imap_auth_sleep_handler;
529
530 return;
531 }
532
533 if (ctx->addr.len == 0 || ctx->port.len == 0) {
534 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
535 "auth http server did not send server or port");
536 ngx_imap_session_internal_server_error(s);
537 return;
538 }
539
540 ctx->peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t));
541 if (ctx->peers == NULL) {
542 ngx_imap_session_internal_server_error(s);
543 return;
544 }
545
546 sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
547 if (sin == NULL) {
548 ngx_imap_session_internal_server_error(s);
549 return;
550 }
551
552 sin->sin_family = AF_INET;
553
554 port = ngx_atoi(ctx->port.data, ctx->port.len);
555 if (port == NGX_ERROR || port < 1 || port > 65536) {
556 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
557 "auth http server sent invalid server "
558 "port:\"%V\"", &ctx->port);
559 ngx_imap_session_internal_server_error(s);
560 return;
561 }
562
563 sin->sin_port = htons((in_port_t) port);
564
565 ctx->addr.data[ctx->addr.len] = '\0';
566 sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
567 if (sin->sin_addr.s_addr == INADDR_NONE) {
568 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
569 "auth http server sent invalid server "
570 "address:\"%V\"", &ctx->addr);
571 ngx_imap_session_internal_server_error(s);
572 return;
573 }
574
575 ctx->peers->number = 1;
576
577 ctx->peers->peer[0].sockaddr = (struct sockaddr *) sin;
578 ctx->peers->peer[0].socklen = sizeof(struct sockaddr_in);
579
580 len = ctx->addr.len + 1 + ctx->port.len;
581
582 ctx->peers->peer[0].name.len = len;
583
584 ctx->peers->peer[0].name.data = ngx_palloc(s->connection->pool,
585 len);
586 if (ctx->peers->peer[0].name.data == NULL) {
587 ngx_imap_session_internal_server_error(s);
588 return;
589 }
590
591 len = ctx->addr.len;
592
593 ngx_memcpy(ctx->peers->peer[0].name.data, ctx->addr.data, len);
594
595 ctx->peers->peer[0].name.data[len++] = ':';
596
597 ngx_memcpy(ctx->peers->peer[0].name.data + len,
598 ctx->port.data, ctx->port.len);
599
600 ctx->peers->peer[0].uri_separator = "";
601
602 ngx_imap_proxy_init(s, ctx->peers);
603
604 return;
605 }
606
607 if (rc == NGX_AGAIN ) {
608 return;
609 }
610
611 /* rc == NGX_ERROR */
612
613 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
614 "auth http server sent invalid header in response");
615 ngx_close_connection(ctx->peer.connection);
616 ngx_imap_session_internal_server_error(s);
617
618 return;
619 }
620 }
621
622
623 static void
624 ngx_imap_auth_sleep_handler(ngx_event_t *rev)
625 {
626 ngx_connection_t *c;
627 ngx_imap_session_t *s;
628
629 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap auth sleep handler");
630
631 c = rev->data;
632 s = c->data;
633
634 if (rev->timedout) {
635
636 rev->timedout = 0;
637
638 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
639 s->imap_state = ngx_pop3_start;
640 s->connection->read->handler = ngx_pop3_auth_state;
641
642 } else {
643 s->imap_state = ngx_imap_start;
644 s->connection->read->handler = ngx_imap_auth_state;
645 }
646
647 if (rev->ready) {
648 s->connection->read->handler(rev);
649 return;
650 }
651
652 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
653 ngx_imap_close_connection(s->connection);
654 }
655
656 return;
657 }
658
659 if (rev->active) {
660 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
661 ngx_imap_close_connection(s->connection);
662 }
663 }
664 }
665
666
667 static ngx_int_t
668 ngx_imap_auth_http_parse_header_line(ngx_imap_session_t *s,
669 ngx_imap_auth_http_ctx_t *ctx)
670 {
671 u_char c, ch, *p;
672 ngx_uint_t hash;
673 enum {
674 sw_start = 0,
675 sw_name,
676 sw_space_before_value,
677 sw_value,
678 sw_space_after_value,
679 sw_almost_done,
680 sw_header_almost_done
681 } state;
682
683 state = ctx->state;
684 hash = ctx->hash;
685
686 for (p = ctx->response->pos; p < ctx->response->last; p++) {
687 ch = *p;
688
689 switch (state) {
690
691 /* first char */
692 case sw_start:
693
694 switch (ch) {
695 case CR:
696 ctx->header_end = p;
697 state = sw_header_almost_done;
698 break;
699 case LF:
700 ctx->header_end = p;
701 goto header_done;
702 default:
703 state = sw_name;
704 ctx->header_name_start = p;
705
706 c = (u_char) (ch | 0x20);
707 if (c >= 'a' && c <= 'z') {
708 hash = c;
709 break;
710 }
711
712 if (ch >= '0' && ch <= '9') {
713 hash = ch;
714 break;
715 }
716
717 return NGX_ERROR;
718 }
719 break;
720
721 /* header name */
722 case sw_name:
723 c = (u_char) (ch | 0x20);
724 if (c >= 'a' && c <= 'z') {
725 hash += c;
726 break;
727 }
728
729 if (ch == ':') {
730 ctx->header_name_end = p;
731 state = sw_space_before_value;
732 break;
733 }
734
735 if (ch == '-') {
736 hash += ch;
737 break;
738 }
739
740 if (ch >= '0' && ch <= '9') {
741 hash += ch;
742 break;
743 }
744
745 if (ch == CR) {
746 ctx->header_name_end = p;
747 ctx->header_start = p;
748 ctx->header_end = p;
749 state = sw_almost_done;
750 break;
751 }
752
753 if (ch == LF) {
754 ctx->header_name_end = p;
755 ctx->header_start = p;
756 ctx->header_end = p;
757 goto done;
758 }
759
760 return NGX_ERROR;
761
762 /* space* before header value */
763 case sw_space_before_value:
764 switch (ch) {
765 case ' ':
766 break;
767 case CR:
768 ctx->header_start = p;
769 ctx->header_end = p;
770 state = sw_almost_done;
771 break;
772 case LF:
773 ctx->header_start = p;
774 ctx->header_end = p;
775 goto done;
776 default:
777 ctx->header_start = p;
778 state = sw_value;
779 break;
780 }
781 break;
782
783 /* header value */
784 case sw_value:
785 switch (ch) {
786 case ' ':
787 ctx->header_end = p;
788 state = sw_space_after_value;
789 break;
790 case CR:
791 ctx->header_end = p;
792 state = sw_almost_done;
793 break;
794 case LF:
795 ctx->header_end = p;
796 goto done;
797 }
798 break;
799
800 /* space* before end of header line */
801 case sw_space_after_value:
802 switch (ch) {
803 case ' ':
804 break;
805 case CR:
806 state = sw_almost_done;
807 break;
808 case LF:
809 goto done;
810 default:
811 state = sw_value;
812 break;
813 }
814 break;
815
816 /* end of header line */
817 case sw_almost_done:
818 switch (ch) {
819 case LF:
820 goto done;
821 default:
822 return NGX_ERROR;
823 }
824
825 /* end of header */
826 case sw_header_almost_done:
827 switch (ch) {
828 case LF:
829 goto header_done;
830 default:
831 return NGX_ERROR;
832 }
833 }
834 }
835
836 ctx->response->pos = p;
837 ctx->state = state;
838 ctx->hash = hash;
839
840 return NGX_AGAIN;
841
842 done:
843
844 ctx->response->pos = p + 1;
845 ctx->state = sw_start;
846 ctx->hash = hash;
847
848 return NGX_OK;
849
850 header_done:
851
852 ctx->response->pos = p + 1;
853 ctx->state = sw_start;
854
855 return NGX_DONE;
856 }
857
858
859 static void
860 ngx_imap_auth_http_block_read(ngx_event_t *rev)
861 {
862 ngx_connection_t *c;
863 ngx_imap_session_t *s;
864 ngx_imap_auth_http_ctx_t *ctx;
865
866 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
867 "imap auth http block read");
868
869 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
870 c = rev->data;
871 s = c->data;
872
873 ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module);
874
875 ngx_close_connection(ctx->peer.connection);
876 ngx_imap_session_internal_server_error(s);
877 }
878 }
879
880
881 static void
882 ngx_imap_auth_http_dummy_handler(ngx_event_t *ev)
883 {
884 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0,
885 "imap auth http dummy handler");
886 }
887
888
889 static ngx_buf_t *
890 ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
891 ngx_imap_auth_http_conf_t *ahcf)
892 {
893 size_t len;
894 ngx_buf_t *b;
895
896 len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
897 + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
898 + sizeof("Auth-Method: plain" CRLF) - 1
899 + sizeof("Auth-User: ") - 1 + s->login.len + sizeof(CRLF) - 1
900 + sizeof("Auth-Pass: ") - 1 + s->passwd.len + sizeof(CRLF) - 1
901 + sizeof("Auth-Protocol: imap" CRLF) - 1
902 + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
903 + sizeof(CRLF) - 1
904 + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
905 + sizeof(CRLF) - 1
906 + sizeof(CRLF) - 1;
907
908 b = ngx_create_temp_buf(s->connection->pool, len);
909 if (b == NULL) {
910 return NULL;
911 }
912
913 b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1);
914 b->last = ngx_cpymem(b->last, ahcf->uri.data, ahcf->uri.len);
915 b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF,
916 sizeof(" HTTP/1.0" CRLF) - 1);
917
918 b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1);
919 b->last = ngx_cpymem(b->last, ahcf->host_header.data,
920 ahcf->host_header.len);
921 *b->last++ = CR; *b->last++ = LF;
922
923 b->last = ngx_cpymem(b->last, "Auth-Method: plain" CRLF,
924 sizeof("Auth-Method: plain" CRLF) - 1);
925
926 b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
927 b->last = ngx_cpymem(b->last, s->login.data, s->login.len);
928 *b->last++ = CR; *b->last++ = LF;
929
930 b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
931 b->last = ngx_cpymem(b->last, s->passwd.data, s->passwd.len);
932 *b->last++ = CR; *b->last++ = LF;
933
934 b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
935 sizeof("Auth-Protocol: ") - 1);
936 b->last = ngx_cpymem(b->last, ngx_imap_auth_http_protocol[s->protocol],
937 sizeof("imap") - 1);
938 *b->last++ = CR; *b->last++ = LF;
939
940 b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
941 s->login_attempt);
942
943 b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
944 b->last = ngx_cpymem(b->last, s->connection->addr_text.data,
945 s->connection->addr_text.len);
946 *b->last++ = CR; *b->last++ = LF;
947
948 /* add "\r\n" at the header end */
949 *b->last++ = CR; *b->last++ = LF;
950
951 #if (NGX_DEBUG)
952 {
953 ngx_str_t l;
954
955 l.len = b->last - b->pos;
956 l.data = b->pos;
957 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
958 "imap auth http header:\n\"%V\"", &l);
959 }
960 #endif
961
962 return b;
963 }
964
965
966 static void *
967 ngx_imap_auth_http_create_conf(ngx_conf_t *cf)
968 {
969 ngx_imap_auth_http_conf_t *ahcf;
970
971 ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_auth_http_conf_t));
972 if (ahcf == NULL) {
973 return NGX_CONF_ERROR;
974 }
975
976 ahcf->timeout = NGX_CONF_UNSET_MSEC;
977
978 return ahcf;
979 }
980
981
982 static char *
983 ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child)
984 {
985 ngx_imap_auth_http_conf_t *prev = parent;
986 ngx_imap_auth_http_conf_t *conf = child;
987
988 if (conf->peers == NULL) {
989 conf->peers = prev->peers;
990 conf->host_header = prev->host_header;
991 conf->uri = prev->uri;
992 }
993
994 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
995
996 return NGX_CONF_OK;
997 }
998
999
1000 static char *
1001 ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1002 {
1003 ngx_imap_auth_http_conf_t *ahcf = conf;
1004
1005 ngx_uint_t i;
1006 ngx_str_t *value, *url;
1007 ngx_inet_upstream_t inet_upstream;
1008 #if (NGX_HAVE_UNIX_DOMAIN)
1009 ngx_unix_domain_upstream_t unix_upstream;
1010 #endif
1011
1012 value = cf->args->elts;
1013
1014 url = &value[1];
1015
1016 if (ngx_strncasecmp(url->data, "unix:", 5) == 0) {
1017
1018 #if (NGX_HAVE_UNIX_DOMAIN)
1019
1020 ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
1021
1022 unix_upstream.name = *url;
1023 unix_upstream.url = *url;
1024 unix_upstream.uri_part = 1;
1025
1026 ahcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
1027 if (ahcf->peers == NULL) {
1028 return NGX_CONF_ERROR;
1029 }
1030
1031 ahcf->peers->peer[0].uri_separator = ":";
1032
1033 ahcf->host_header.len = sizeof("localhost") - 1;
1034 ahcf->host_header.data = (u_char *) "localhost";
1035 ahcf->uri = unix_upstream.uri;
1036
1037 #else
1038 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1039 "the unix domain sockets are not supported "
1040 "on this platform");
1041 return NGX_CONF_ERROR;
1042
1043 #endif
1044
1045 } else {
1046 ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
1047
1048 inet_upstream.name = *url;
1049 inet_upstream.url = *url;
1050 inet_upstream.default_port_value = 80;
1051 inet_upstream.uri_part = 1;
1052
1053 ahcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
1054 if (ahcf->peers == NULL) {
1055 return NGX_CONF_ERROR;
1056 }
1057
1058 for (i = 0; i < ahcf->peers->number; i++) {
1059 ahcf->peers->peer[i].uri_separator = "";
1060 }
1061
1062 ahcf->host_header = inet_upstream.host_header;
1063 ahcf->uri = inet_upstream.uri;
1064 }
1065
1066 return NGX_CONF_OK;
1067 }