~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/mail/ngx_mail_auth_http_module.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  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_mail.h>
 12 
 13 
 14 typedef struct {
 15     ngx_peer_addr_t                *peer;
 16 
 17     ngx_msec_t                      timeout;
 18 
 19     ngx_str_t                       host_header;
 20     ngx_str_t                       uri;
 21     ngx_str_t                       header;
 22 
 23     ngx_array_t                    *headers;
 24 
 25     u_char                         *file;
 26     ngx_uint_t                      line;
 27 } ngx_mail_auth_http_conf_t;
 28 
 29 
 30 typedef struct ngx_mail_auth_http_ctx_s  ngx_mail_auth_http_ctx_t;
 31 
 32 typedef void (*ngx_mail_auth_http_handler_pt)(ngx_mail_session_t *s,
 33     ngx_mail_auth_http_ctx_t *ctx);
 34 
 35 struct ngx_mail_auth_http_ctx_s {
 36     ngx_buf_t                      *request;
 37     ngx_buf_t                      *response;
 38     ngx_peer_connection_t           peer;
 39 
 40     ngx_mail_auth_http_handler_pt   handler;
 41 
 42     ngx_uint_t                      state;
 43 
 44     u_char                         *header_name_start;
 45     u_char                         *header_name_end;
 46     u_char                         *header_start;
 47     u_char                         *header_end;
 48 
 49     ngx_str_t                       addr;
 50     ngx_str_t                       port;
 51     ngx_str_t                       err;
 52     ngx_str_t                       errmsg;
 53     ngx_str_t                       errcode;
 54 
 55     time_t                          sleep;
 56 
 57     ngx_pool_t                     *pool;
 58 };
 59 
 60 
 61 static void ngx_mail_auth_http_write_handler(ngx_event_t *wev);
 62 static void ngx_mail_auth_http_read_handler(ngx_event_t *rev);
 63 static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
 64     ngx_mail_auth_http_ctx_t *ctx);
 65 static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
 66     ngx_mail_auth_http_ctx_t *ctx);
 67 static void ngx_mail_auth_sleep_handler(ngx_event_t *rev);
 68 static ngx_int_t ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
 69     ngx_mail_auth_http_ctx_t *ctx);
 70 static void ngx_mail_auth_http_block_read(ngx_event_t *rev);
 71 static void ngx_mail_auth_http_dummy_handler(ngx_event_t *ev);
 72 static ngx_buf_t *ngx_mail_auth_http_create_request(ngx_mail_session_t *s,
 73     ngx_pool_t *pool, ngx_mail_auth_http_conf_t *ahcf);
 74 static ngx_int_t ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text,
 75     ngx_str_t *escaped);
 76 
 77 static void *ngx_mail_auth_http_create_conf(ngx_conf_t *cf);
 78 static char *ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
 79     void *child);
 80 static char *ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 81 static char *ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd,
 82     void *conf);
 83 
 84 
 85 static ngx_command_t  ngx_mail_auth_http_commands[] = {
 86 
 87     { ngx_string("auth_http"),
 88       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
 89       ngx_mail_auth_http,
 90       NGX_MAIL_SRV_CONF_OFFSET,
 91       0,
 92       NULL },
 93 
 94     { ngx_string("auth_http_timeout"),
 95       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
 96       ngx_conf_set_msec_slot,
 97       NGX_MAIL_SRV_CONF_OFFSET,
 98       offsetof(ngx_mail_auth_http_conf_t, timeout),
 99       NULL },
100 
101     { ngx_string("auth_http_header"),
102       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2,
103       ngx_mail_auth_http_header,
104       NGX_MAIL_SRV_CONF_OFFSET,
105       0,
106       NULL },
107 
108       ngx_null_command
109 };
110 
111 
112 static ngx_mail_module_t  ngx_mail_auth_http_module_ctx = {
113     NULL,                                  /* protocol */
114 
115     NULL,                                  /* create main configuration */
116     NULL,                                  /* init main configuration */
117 
118     ngx_mail_auth_http_create_conf,        /* create server configuration */
119     ngx_mail_auth_http_merge_conf          /* merge server configuration */
120 };
121 
122 
123 ngx_module_t  ngx_mail_auth_http_module = {
124     NGX_MODULE_V1,
125     &ngx_mail_auth_http_module_ctx,        /* module context */
126     ngx_mail_auth_http_commands,           /* module directives */
127     NGX_MAIL_MODULE,                       /* module type */
128     NULL,                                  /* init master */
129     NULL,                                  /* init module */
130     NULL,                                  /* init process */
131     NULL,                                  /* init thread */
132     NULL,                                  /* exit thread */
133     NULL,                                  /* exit process */
134     NULL,                                  /* exit master */
135     NGX_MODULE_V1_PADDING
136 };
137 
138 
139 static ngx_str_t   ngx_mail_auth_http_method[] = {
140     ngx_string("plain"),
141     ngx_string("plain"),
142     ngx_string("plain"),
143     ngx_string("apop"),
144     ngx_string("cram-md5"),
145     ngx_string("none")
146 };
147 
148 static ngx_str_t   ngx_mail_smtp_errcode = ngx_string("535 5.7.0");
149 
150 
151 void
152 ngx_mail_auth_http_init(ngx_mail_session_t *s)
153 {
154     ngx_int_t                   rc;
155     ngx_pool_t                 *pool;
156     ngx_mail_auth_http_ctx_t   *ctx;
157     ngx_mail_auth_http_conf_t  *ahcf;
158 
159     s->connection->log->action = "in http auth state";
160 
161     pool = ngx_create_pool(2048, s->connection->log);
162     if (pool == NULL) {
163         ngx_mail_session_internal_server_error(s);
164         return;
165     }
166 
167     ctx = ngx_pcalloc(pool, sizeof(ngx_mail_auth_http_ctx_t));
168     if (ctx == NULL) {
169         ngx_destroy_pool(pool);
170         ngx_mail_session_internal_server_error(s);
171         return;
172     }
173 
174     ctx->pool = pool;
175 
176     ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
177 
178     ctx->request = ngx_mail_auth_http_create_request(s, pool, ahcf);
179     if (ctx->request == NULL) {
180         ngx_destroy_pool(ctx->pool);
181         ngx_mail_session_internal_server_error(s);
182         return;
183     }
184 
185     ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module);
186 
187     ctx->peer.sockaddr = ahcf->peer->sockaddr;
188     ctx->peer.socklen = ahcf->peer->socklen;
189     ctx->peer.name = &ahcf->peer->name;
190     ctx->peer.get = ngx_event_get_peer;
191     ctx->peer.log = s->connection->log;
192     ctx->peer.log_error = NGX_ERROR_ERR;
193 
194     rc = ngx_event_connect_peer(&ctx->peer);
195 
196     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
197         if (ctx->peer.connection) {
198             ngx_close_connection(ctx->peer.connection);
199         }
200 
201         ngx_destroy_pool(ctx->pool);
202         ngx_mail_session_internal_server_error(s);
203         return;
204     }
205 
206     ctx->peer.connection->data = s;
207     ctx->peer.connection->pool = s->connection->pool;
208 
209     s->connection->read->handler = ngx_mail_auth_http_block_read;
210     ctx->peer.connection->read->handler = ngx_mail_auth_http_read_handler;
211     ctx->peer.connection->write->handler = ngx_mail_auth_http_write_handler;
212 
213     ctx->handler = ngx_mail_auth_http_ignore_status_line;
214 
215     ngx_add_timer(ctx->peer.connection->read, ahcf->timeout);
216     ngx_add_timer(ctx->peer.connection->write, ahcf->timeout);
217 
218     if (rc == NGX_OK) {
219         ngx_mail_auth_http_write_handler(ctx->peer.connection->write);
220         return;
221     }
222 }
223 
224 
225 static void
226 ngx_mail_auth_http_write_handler(ngx_event_t *wev)
227 {
228     ssize_t                     n, size;
229     ngx_connection_t           *c;
230     ngx_mail_session_t         *s;
231     ngx_mail_auth_http_ctx_t   *ctx;
232     ngx_mail_auth_http_conf_t  *ahcf;
233 
234     c = wev->data;
235     s = c->data;
236 
237     ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
238 
239     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0,
240                    "mail auth http write handler");
241 
242     if (wev->timedout) {
243         ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
244                       "auth http server %V timed out", ctx->peer.name);
245         ngx_close_connection(c);
246         ngx_destroy_pool(ctx->pool);
247         ngx_mail_session_internal_server_error(s);
248         return;
249     }
250 
251     size = ctx->request->last - ctx->request->pos;
252 
253     n = ngx_send(c, ctx->request->pos, size);
254 
255     if (n == NGX_ERROR) {
256         ngx_close_connection(c);
257         ngx_destroy_pool(ctx->pool);
258         ngx_mail_session_internal_server_error(s);
259         return;
260     }
261 
262     if (n > 0) {
263         ctx->request->pos += n;
264 
265         if (n == size) {
266             wev->handler = ngx_mail_auth_http_dummy_handler;
267 
268             if (wev->timer_set) {
269                 ngx_del_timer(wev);
270             }
271 
272             if (ngx_handle_write_event(wev, 0) != NGX_OK) {
273                 ngx_close_connection(c);
274                 ngx_destroy_pool(ctx->pool);
275                 ngx_mail_session_internal_server_error(s);
276             }
277 
278             return;
279         }
280     }
281 
282     if (!wev->timer_set) {
283         ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
284         ngx_add_timer(wev, ahcf->timeout);
285     }
286 }
287 
288 
289 static void
290 ngx_mail_auth_http_read_handler(ngx_event_t *rev)
291 {
292     ssize_t                     n, size;
293     ngx_connection_t          *c;
294     ngx_mail_session_t        *s;
295     ngx_mail_auth_http_ctx_t  *ctx;
296 
297     c = rev->data;
298     s = c->data;
299 
300     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
301                    "mail auth http read handler");
302 
303     ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
304 
305     if (rev->timedout) {
306         ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
307                       "auth http server %V timed out", ctx->peer.name);
308         ngx_close_connection(c);
309         ngx_destroy_pool(ctx->pool);
310         ngx_mail_session_internal_server_error(s);
311         return;
312     }
313 
314     if (ctx->response == NULL) {
315         ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
316         if (ctx->response == NULL) {
317             ngx_close_connection(c);
318             ngx_destroy_pool(ctx->pool);
319             ngx_mail_session_internal_server_error(s);
320             return;
321         }
322     }
323 
324     size = ctx->response->end - ctx->response->last;
325 
326     n = ngx_recv(c, ctx->response->pos, size);
327 
328     if (n > 0) {
329         ctx->response->last += n;
330 
331         ctx->handler(s, ctx);
332         return;
333     }
334 
335     if (n == NGX_AGAIN) {
336         return;
337     }
338 
339     ngx_close_connection(c);
340     ngx_destroy_pool(ctx->pool);
341     ngx_mail_session_internal_server_error(s);
342 }
343 
344 
345 static void
346 ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
347     ngx_mail_auth_http_ctx_t *ctx)
348 {
349     u_char  *p, ch;
350     enum  {
351         sw_start = 0,
352         sw_H,
353         sw_HT,
354         sw_HTT,
355         sw_HTTP,
356         sw_skip,
357         sw_almost_done
358     } state;
359 
360     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
361                    "mail auth http process status line");
362 
363     state = ctx->state;
364 
365     for (p = ctx->response->pos; p < ctx->response->last; p++) {
366         ch = *p;
367 
368         switch (state) {
369 
370         /* "HTTP/" */
371         case sw_start:
372             if (ch == 'H') {
373                 state = sw_H;
374                 break;
375             }
376             goto next;
377 
378         case sw_H:
379             if (ch == 'T') {
380                 state = sw_HT;
381                 break;
382             }
383             goto next;
384 
385         case sw_HT:
386             if (ch == 'T') {
387                 state = sw_HTT;
388                 break;
389             }
390             goto next;
391 
392         case sw_HTT:
393             if (ch == 'P') {
394                 state = sw_HTTP;
395                 break;
396             }
397             goto next;
398 
399         case sw_HTTP:
400             if (ch == '/') {
401                 state = sw_skip;
402                 break;
403             }
404             goto next;
405 
406         /* any text until end of line */
407         case sw_skip:
408             switch (ch) {
409             case CR:
410                 state = sw_almost_done;
411 
412                 break;
413             case LF:
414                 goto done;
415             }
416             break;
417 
418         /* end of status line */
419         case sw_almost_done:
420             if (ch == LF) {
421                 goto done;
422             }
423 
424             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
425                           "auth http server &V sent invalid response",
426                           ctx->peer.name);
427             ngx_close_connection(ctx->peer.connection);
428             ngx_destroy_pool(ctx->pool);
429             ngx_mail_session_internal_server_error(s);
430             return;
431         }
432     }
433 
434     ctx->response->pos = p;
435     ctx->state = state;
436 
437     return;
438 
439 next:
440 
441     p = ctx->response->start - 1;
442 
443 done:
444 
445     ctx->response->pos = p + 1;
446     ctx->state = 0;
447     ctx->handler = ngx_mail_auth_http_process_headers;
448     ctx->handler(s, ctx);
449 }
450 
451 
452 static void
453 ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
454     ngx_mail_auth_http_ctx_t *ctx)
455 {
456     u_char              *p;
457     time_t               timer;
458     size_t               len, size;
459     ngx_int_t            rc, port, n;
460     ngx_peer_addr_t     *peer;
461     struct sockaddr_in  *sin;
462 
463     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
464                    "mail auth http process headers");
465 
466     for ( ;; ) {
467         rc = ngx_mail_auth_http_parse_header_line(s, ctx);
468 
469         if (rc == NGX_OK) {
470 
471 #if (NGX_DEBUG)
472             {
473             ngx_str_t  key, value;
474 
475             key.len = ctx->header_name_end - ctx->header_name_start;
476             key.data = ctx->header_name_start;
477             value.len = ctx->header_end - ctx->header_start;
478             value.data = ctx->header_start;
479 
480             ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
481                            "mail auth http header: \"%V: %V\"",
482                            &key, &value);
483             }
484 #endif
485 
486             len = ctx->header_name_end - ctx->header_name_start;
487 
488             if (len == sizeof("Auth-Status") - 1
489                 && ngx_strncasecmp(ctx->header_name_start,
490                                    (u_char *) "Auth-Status",
491                                    sizeof("Auth-Status") - 1)
492                    == 0)
493             {
494                 len = ctx->header_end - ctx->header_start;
495 
496                 if (len == 2
497                     && ctx->header_start[0] == 'O'
498                     && ctx->header_start[1] == 'K')
499                 {
500                     continue;
501                 }
502 
503                 if (len == 4
504                     && ctx->header_start[0] == 'W'
505                     && ctx->header_start[1] == 'A'
506                     && ctx->header_start[2] == 'I'
507                     && ctx->header_start[3] == 'T')
508                 {
509                     s->auth_wait = 1;
510                     continue;
511                 }
512 
513                 ctx->errmsg.len = len;
514                 ctx->errmsg.data = ctx->header_start;
515 
516                 switch (s->protocol) {
517 
518                 case NGX_MAIL_POP3_PROTOCOL:
519                     size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1;
520                     break;
521 
522                 case NGX_MAIL_IMAP_PROTOCOL:
523                     size = s->tag.len + sizeof("NO ") - 1 + len
524                            + sizeof(CRLF) - 1;
525                     break;
526 
527                 default: /* NGX_MAIL_SMTP_PROTOCOL */
528                     ctx->err = ctx->errmsg;
529                     continue;
530                 }
531 
532                 p = ngx_pnalloc(s->connection->pool, size);
533                 if (p == NULL) {
534                     ngx_close_connection(ctx->peer.connection);
535                     ngx_destroy_pool(ctx->pool);
536                     ngx_mail_session_internal_server_error(s);
537                     return;
538                 }
539 
540                 ctx->err.data = p;
541 
542                 switch (s->protocol) {
543 
544                 case NGX_MAIL_POP3_PROTOCOL:
545                     *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' ';
546                     break;
547 
548                 case NGX_MAIL_IMAP_PROTOCOL:
549                     p = ngx_cpymem(p, s->tag.data, s->tag.len);
550                     *p++ = 'N'; *p++ = 'O'; *p++ = ' ';
551                     break;
552 
553                 default: /* NGX_MAIL_SMTP_PROTOCOL */
554                     break;
555                 }
556 
557                 p = ngx_cpymem(p, ctx->header_start, len);
558                 *p++ = CR; *p++ = LF;
559 
560                 ctx->err.len = p - ctx->err.data;
561 
562                 continue;
563             }
564 
565             if (len == sizeof("Auth-Server") - 1
566                 && ngx_strncasecmp(ctx->header_name_start,
567                                    (u_char *) "Auth-Server",
568                                    sizeof("Auth-Server") - 1)
569                     == 0)
570             {
571                 ctx->addr.len = ctx->header_end - ctx->header_start;
572                 ctx->addr.data = ctx->header_start;
573 
574                 continue;
575             }
576 
577             if (len == sizeof("Auth-Port") - 1
578                 && ngx_strncasecmp(ctx->header_name_start,
579                                    (u_char *) "Auth-Port",
580                                    sizeof("Auth-Port") - 1)
581                    == 0)
582             {
583                 ctx->port.len = ctx->header_end - ctx->header_start;
584                 ctx->port.data = ctx->header_start;
585 
586                 continue;
587             }
588 
589             if (len == sizeof("Auth-User") - 1
590                 && ngx_strncasecmp(ctx->header_name_start,
591                                    (u_char *) "Auth-User",
592                                    sizeof("Auth-User") - 1)
593                    == 0)
594             {
595                 s->login.len = ctx->header_end - ctx->header_start;
596 
597                 s->login.data = ngx_pnalloc(s->connection->pool, s->login.len);
598                 if (s->login.data == NULL) {
599                     ngx_close_connection(ctx->peer.connection);
600                     ngx_destroy_pool(ctx->pool);
601                     ngx_mail_session_internal_server_error(s);
602                     return;
603                 }
604 
605                 ngx_memcpy(s->login.data, ctx->header_start, s->login.len);
606 
607                 continue;
608             }
609 
610             if (len == sizeof("Auth-Pass") - 1
611                 && ngx_strncasecmp(ctx->header_name_start,
612                                    (u_char *) "Auth-Pass",
613                                    sizeof("Auth-Pass") - 1)
614                    == 0)
615             {
616                 s->passwd.len = ctx->header_end - ctx->header_start;
617 
618                 s->passwd.data = ngx_pnalloc(s->connection->pool,
619                                              s->passwd.len);
620                 if (s->passwd.data == NULL) {
621                     ngx_close_connection(ctx->peer.connection);
622                     ngx_destroy_pool(ctx->pool);
623                     ngx_mail_session_internal_server_error(s);
624                     return;
625                 }
626 
627                 ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len);
628 
629                 continue;
630             }
631 
632             if (len == sizeof("Auth-Wait") - 1
633                 && ngx_strncasecmp(ctx->header_name_start,
634                                    (u_char *) "Auth-Wait",
635                                    sizeof("Auth-Wait") - 1)
636                    == 0)
637             {
638                 n = ngx_atoi(ctx->header_start,
639                              ctx->header_end - ctx->header_start);
640 
641                 if (n != NGX_ERROR) {
642                     ctx->sleep = n;
643                 }
644 
645                 continue;
646             }
647 
648             if (len == sizeof("Auth-Error-Code") - 1
649                 && ngx_strncasecmp(ctx->header_name_start,
650                                    (u_char *) "Auth-Error-Code",
651                                    sizeof("Auth-Error-Code") - 1)
652                    == 0)
653             {
654                 ctx->errcode.len = ctx->header_end - ctx->header_start;
655 
656                 ctx->errcode.data = ngx_pnalloc(s->connection->pool,
657                                                 ctx->errcode.len);
658                 if (ctx->errcode.data == NULL) {
659                     ngx_close_connection(ctx->peer.connection);
660                     ngx_destroy_pool(ctx->pool);
661                     ngx_mail_session_internal_server_error(s);
662                     return;
663                 }
664 
665                 ngx_memcpy(ctx->errcode.data, ctx->header_start,
666                            ctx->errcode.len);
667 
668                 continue;
669             }
670 
671             /* ignore other headers */
672 
673             continue;
674         }
675 
676         if (rc == NGX_DONE) {
677             ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
678                            "mail auth http header done");
679 
680             ngx_close_connection(ctx->peer.connection);
681 
682             if (ctx->err.len) {
683 
684                 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
685                               "client login failed: \"%V\"", &ctx->errmsg);
686 
687                 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) {
688 
689                     if (ctx->errcode.len == 0) {
690                         ctx->errcode = ngx_mail_smtp_errcode;
691                     }
692 
693                     ctx->err.len = ctx->errcode.len + ctx->errmsg.len
694                                    + sizeof(" " CRLF) - 1;
695 
696                     p = ngx_pnalloc(s->connection->pool, ctx->err.len);
697                     if (p == NULL) {
698                         ngx_close_connection(ctx->peer.connection);
699                         ngx_destroy_pool(ctx->pool);
700                         ngx_mail_session_internal_server_error(s);
701                         return;
702                     }
703 
704                     ctx->err.data = p;
705 
706                     p = ngx_cpymem(p, ctx->errcode.data, ctx->errcode.len);
707                     *p++ = ' ';
708                     p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len);
709                     *p++ = CR; *p = LF;
710                 }
711 
712                 s->out = ctx->err;
713                 timer = ctx->sleep;
714 
715                 ngx_destroy_pool(ctx->pool);
716 
717                 if (timer == 0) {
718                     s->quit = 1;
719                     ngx_mail_send(s->connection->write);
720                     return;
721                 }
722 
723                 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
724 
725                 s->connection->read->handler = ngx_mail_auth_sleep_handler;
726 
727                 return;
728             }
729 
730             if (s->auth_wait) {
731                 timer = ctx->sleep;
732 
733                 ngx_destroy_pool(ctx->pool);
734 
735                 if (timer == 0) {
736                     ngx_mail_auth_http_init(s);
737                     return;
738                 }
739 
740                 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
741 
742                 s->connection->read->handler = ngx_mail_auth_sleep_handler;
743 
744                 return;
745             }
746 
747             if (ctx->addr.len == 0 || ctx->port.len == 0) {
748                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
749                               "auth http server %V did not send server or port",
750                               ctx->peer.name);
751                 ngx_destroy_pool(ctx->pool);
752                 ngx_mail_session_internal_server_error(s);
753                 return;
754             }
755 
756             if (s->passwd.data == NULL
757                 && s->protocol != NGX_MAIL_SMTP_PROTOCOL)
758             {
759                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
760                               "auth http server %V did not send password",
761                               ctx->peer.name);
762                 ngx_destroy_pool(ctx->pool);
763                 ngx_mail_session_internal_server_error(s);
764                 return;
765             }
766 
767             peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
768             if (peer == NULL) {
769                 ngx_destroy_pool(ctx->pool);
770                 ngx_mail_session_internal_server_error(s);
771                 return;
772             }
773 
774             /* AF_INET only */
775 
776             sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
777             if (sin == NULL) {
778                 ngx_destroy_pool(ctx->pool);
779                 ngx_mail_session_internal_server_error(s);
780                 return;
781             }
782 
783             sin->sin_family = AF_INET;
784 
785             port = ngx_atoi(ctx->port.data, ctx->port.len);
786             if (port == NGX_ERROR || port < 1 || port > 65536) {
787                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
788                               "auth http server %V sent invalid server "
789                               "port:\"%V\"",
790                               ctx->peer.name, &ctx->port);
791                 ngx_destroy_pool(ctx->pool);
792                 ngx_mail_session_internal_server_error(s);
793                 return;
794             }
795 
796             sin->sin_port = htons((in_port_t) port);
797 
798             ctx->addr.data[ctx->addr.len] = '\0';
799             sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
800             if (sin->sin_addr.s_addr == INADDR_NONE) {
801                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
802                               "auth http server %V sent invalid server "
803                               "address:\"%V\"",
804                               ctx->peer.name, &ctx->addr);
805                 ngx_destroy_pool(ctx->pool);
806                 ngx_mail_session_internal_server_error(s);
807                 return;
808             }
809 
810             peer->sockaddr = (struct sockaddr *) sin;
811             peer->socklen = sizeof(struct sockaddr_in);
812 
813             len = ctx->addr.len + 1 + ctx->port.len;
814 
815             peer->name.len = len;
816 
817             peer->name.data = ngx_pnalloc(s->connection->pool, len);
818             if (peer->name.data == NULL) {
819                 ngx_destroy_pool(ctx->pool);
820                 ngx_mail_session_internal_server_error(s);
821                 return;
822             }
823 
824             len = ctx->addr.len;
825 
826             ngx_memcpy(peer->name.data, ctx->addr.data, len);
827 
828             peer->name.data[len++] = ':';
829 
830             ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);
831 
832             ngx_destroy_pool(ctx->pool);
833             ngx_mail_proxy_init(s, peer);
834 
835             return;
836         }
837 
838         if (rc == NGX_AGAIN ) {
839             return;
840         }
841 
842         /* rc == NGX_ERROR */
843 
844         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
845                       "auth http server %V sent invalid header in response",
846                       ctx->peer.name);
847         ngx_close_connection(ctx->peer.connection);
848         ngx_destroy_pool(ctx->pool);
849         ngx_mail_session_internal_server_error(s);
850 
851         return;
852     }
853 }
854 
855 
856 static void
857 ngx_mail_auth_sleep_handler(ngx_event_t *rev)
858 {
859     ngx_connection_t          *c;
860     ngx_mail_session_t        *s;
861     ngx_mail_core_srv_conf_t  *cscf;
862 
863     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail auth sleep handler");
864 
865     c = rev->data;
866     s = c->data;
867 
868     if (rev->timedout) {
869 
870         rev->timedout = 0;
871 
872         if (s->auth_wait) {
873             s->auth_wait = 0;
874             ngx_mail_auth_http_init(s);
875             return;
876         }
877 
878         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
879 
880         rev->handler = cscf->protocol->auth_state;
881 
882         s->mail_state = 0;
883         s->auth_method = NGX_MAIL_AUTH_PLAIN;
884 
885         c->log->action = "in auth state";
886 
887         ngx_mail_send(c->write);
888 
889         if (c->destroyed) {
890             return;
891         }
892 
893         ngx_add_timer(rev, cscf->timeout);
894 
895         if (rev->ready) {
896             rev->handler(rev);
897             return;
898         }
899 
900         if (ngx_handle_read_event(rev, 0) != NGX_OK) {
901             ngx_mail_close_connection(c);
902         }
903 
904         return;
905     }
906 
907     if (rev->active) {
908         if (ngx_handle_read_event(rev, 0) != NGX_OK) {
909             ngx_mail_close_connection(c);
910         }
911     }
912 }
913 
914 
915 static ngx_int_t
916 ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
917     ngx_mail_auth_http_ctx_t *ctx)
918 {
919     u_char      c, ch, *p;
920     enum {
921         sw_start = 0,
922         sw_name,
923         sw_space_before_value,
924         sw_value,
925         sw_space_after_value,
926         sw_almost_done,
927         sw_header_almost_done
928     } state;
929 
930     state = ctx->state;
931 
932     for (p = ctx->response->pos; p < ctx->response->last; p++) {
933         ch = *p;
934 
935         switch (state) {
936 
937         /* first char */
938         case sw_start:
939 
940             switch (ch) {
941             case CR:
942                 ctx->header_end = p;
943                 state = sw_header_almost_done;
944                 break;
945             case LF:
946                 ctx->header_end = p;
947                 goto header_done;
948             default:
949                 state = sw_name;
950                 ctx->header_name_start = p;
951 
952                 c = (u_char) (ch | 0x20);
953                 if (c >= 'a' && c <= 'z') {
954                     break;
955                 }
956 
957                 if (ch >= '' && ch <= '9') {
958                     break;
959                 }
960 
961                 return NGX_ERROR;
962             }
963             break;
964 
965         /* header name */
966         case sw_name:
967             c = (u_char) (ch | 0x20);
968             if (c >= 'a' && c <= 'z') {
969                 break;
970             }
971 
972             if (ch == ':') {
973                 ctx->header_name_end = p;
974                 state = sw_space_before_value;
975                 break;
976             }
977 
978             if (ch == '-') {
979                 break;
980             }
981 
982             if (ch >= '' && ch <= '9') {
983                 break;
984             }
985 
986             if (ch == CR) {
987                 ctx->header_name_end = p;
988                 ctx->header_start = p;
989                 ctx->header_end = p;
990                 state = sw_almost_done;
991                 break;
992             }
993 
994             if (ch == LF) {
995                 ctx->header_name_end = p;
996                 ctx->header_start = p;
997                 ctx->header_end = p;
998                 goto done;
999             }
1000 
1001             return NGX_ERROR;
1002 
1003         /* space* before header value */
1004         case sw_space_before_value:
1005             switch (ch) {
1006             case ' ':
1007                 break;
1008             case CR:
1009                 ctx->header_start = p;
1010                 ctx->header_end = p;
1011                 state = sw_almost_done;
1012                 break;
1013             case LF:
1014                 ctx->header_start = p;
1015                 ctx->header_end = p;
1016                 goto done;
1017             default:
1018                 ctx->header_start = p;
1019                 state = sw_value;
1020                 break;
1021             }
1022             break;
1023 
1024         /* header value */
1025         case sw_value:
1026             switch (ch) {
1027             case ' ':
1028                 ctx->header_end = p;
1029                 state = sw_space_after_value;
1030                 break;
1031             case CR:
1032                 ctx->header_end = p;
1033                 state = sw_almost_done;
1034                 break;
1035             case LF:
1036                 ctx->header_end = p;
1037                 goto done;
1038             }
1039             break;
1040 
1041         /* space* before end of header line */
1042         case sw_space_after_value:
1043             switch (ch) {
1044             case ' ':
1045                 break;
1046             case CR:
1047                 state = sw_almost_done;
1048                 break;
1049             case LF:
1050                 goto done;
1051             default:
1052                 state = sw_value;
1053                 break;
1054             }
1055             break;
1056 
1057         /* end of header line */
1058         case sw_almost_done:
1059             switch (ch) {
1060             case LF:
1061                 goto done;
1062             default:
1063                 return NGX_ERROR;
1064             }
1065 
1066         /* end of header */
1067         case sw_header_almost_done:
1068             switch (ch) {
1069             case LF:
1070                 goto header_done;
1071             default:
1072                 return NGX_ERROR;
1073             }
1074         }
1075     }
1076 
1077     ctx->response->pos = p;
1078     ctx->state = state;
1079 
1080     return NGX_AGAIN;
1081 
1082 done:
1083 
1084     ctx->response->pos = p + 1;
1085     ctx->state = sw_start;
1086 
1087     return NGX_OK;
1088 
1089 header_done:
1090 
1091     ctx->response->pos = p + 1;
1092     ctx->state = sw_start;
1093 
1094     return NGX_DONE;
1095 }
1096 
1097 
1098 static void
1099 ngx_mail_auth_http_block_read(ngx_event_t *rev)
1100 {
1101     ngx_connection_t          *c;
1102     ngx_mail_session_t        *s;
1103     ngx_mail_auth_http_ctx_t  *ctx;
1104 
1105     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
1106                    "mail auth http block read");
1107 
1108     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1109         c = rev->data;
1110         s = c->data;
1111 
1112         ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
1113 
1114         ngx_close_connection(ctx->peer.connection);
1115         ngx_destroy_pool(ctx->pool);
1116         ngx_mail_session_internal_server_error(s);
1117     }
1118 }
1119 
1120 
1121 static void
1122 ngx_mail_auth_http_dummy_handler(ngx_event_t *ev)
1123 {
1124     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, ev->log, 0,
1125                    "mail auth http dummy handler");
1126 }
1127 
1128 
1129 static ngx_buf_t *
1130 ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
1131     ngx_mail_auth_http_conf_t *ahcf)
1132 {
1133     size_t                     len;
1134     ngx_buf_t                 *b;
1135     ngx_str_t                  login, passwd;
1136     ngx_mail_core_srv_conf_t  *cscf;
1137 
1138     if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
1139         return NULL;
1140     }
1141 
1142     if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
1143         return NULL;
1144     }
1145 
1146     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1147 
1148     len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
1149           + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
1150           + sizeof("Auth-Method: ") - 1
1151                 + ngx_mail_auth_http_method[s->auth_method].len
1152                 + sizeof(CRLF) - 1
1153           + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
1154           + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
1155           + sizeof("Auth-Salt: ") - 1 + s->salt.len
1156           + sizeof("Auth-Protocol: ") - 1 + cscf->protocol->name.len
1157                 + sizeof(CRLF) - 1
1158           + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
1159                 + sizeof(CRLF) - 1
1160           + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
1161                 + sizeof(CRLF) - 1
1162           + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1
1163           + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len
1164           + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len
1165           + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len
1166           + ahcf->header.len
1167           + sizeof(CRLF) - 1;
1168 
1169     b = ngx_create_temp_buf(pool, len);
1170     if (b == NULL) {
1171         return NULL;
1172     }
1173 
1174     b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1);
1175     b->last = ngx_copy(b->last, ahcf->uri.data, ahcf->uri.len);
1176     b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF,
1177                          sizeof(" HTTP/1.0" CRLF) - 1);
1178 
1179     b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1);
1180     b->last = ngx_copy(b->last, ahcf->host_header.data,
1181                          ahcf->host_header.len);
1182     *b->last++ = CR; *b->last++ = LF;
1183 
1184     b->last = ngx_cpymem(b->last, "Auth-Method: ",
1185                          sizeof("Auth-Method: ") - 1);
1186     b->last = ngx_cpymem(b->last,
1187                          ngx_mail_auth_http_method[s->auth_method].data,
1188                          ngx_mail_auth_http_method[s->auth_method].len);
1189     *b->last++ = CR; *b->last++ = LF;
1190 
1191     b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
1192     b->last = ngx_copy(b->last, login.data, login.len);
1193     *b->last++ = CR; *b->last++ = LF;
1194 
1195     b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
1196     b->last = ngx_copy(b->last, passwd.data, passwd.len);
1197     *b->last++ = CR; *b->last++ = LF;
1198 
1199     if (s->auth_method != NGX_MAIL_AUTH_PLAIN && s->salt.len) {
1200         b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
1201         b->last = ngx_copy(b->last, s->salt.data, s->salt.len);
1202 
1203         s->passwd.data = NULL;
1204     }
1205 
1206     b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
1207                          sizeof("Auth-Protocol: ") - 1);
1208     b->last = ngx_cpymem(b->last, cscf->protocol->name.data,
1209                          cscf->protocol->name.len);
1210     *b->last++ = CR; *b->last++ = LF;
1211 
1212     b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
1213                           s->login_attempt);
1214 
1215     b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
1216     b->last = ngx_copy(b->last, s->connection->addr_text.data,
1217                        s->connection->addr_text.len);
1218     *b->last++ = CR; *b->last++ = LF;
1219 
1220     if (s->host.len) {
1221         b->last = ngx_cpymem(b->last, "Client-Host: ",
1222                              sizeof("Client-Host: ") - 1);
1223         b->last = ngx_copy(b->last, s->host.data, s->host.len);
1224         *b->last++ = CR; *b->last++ = LF;
1225     }
1226 
1227     if (s->auth_method == NGX_MAIL_AUTH_NONE) {
1228 
1229         /* HELO, MAIL FROM, and RCPT TO can't contain CRLF, no need to escape */
1230 
1231         b->last = ngx_cpymem(b->last, "Auth-SMTP-Helo: ",
1232                              sizeof("Auth-SMTP-Helo: ") - 1);
1233         b->last = ngx_copy(b->last, s->smtp_helo.data, s->smtp_helo.len);
1234         *b->last++ = CR; *b->last++ = LF;
1235 
1236         b->last = ngx_cpymem(b->last, "Auth-SMTP-From: ",
1237                              sizeof("Auth-SMTP-From: ") - 1);
1238         b->last = ngx_copy(b->last, s->smtp_from.data, s->smtp_from.len);
1239         *b->last++ = CR; *b->last++ = LF;
1240 
1241         b->last = ngx_cpymem(b->last, "Auth-SMTP-To: ",
1242                              sizeof("Auth-SMTP-To: ") - 1);
1243         b->last = ngx_copy(b->last, s->smtp_to.data, s->smtp_to.len);
1244         *b->last++ = CR; *b->last++ = LF;
1245 
1246     }
1247 
1248     if (ahcf->header.len) {
1249         b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
1250     }
1251 
1252     /* add "\r\n" at the header end */
1253     *b->last++ = CR; *b->last++ = LF;
1254 
1255 #if (NGX_DEBUG_MAIL_PASSWD)
1256     {
1257     ngx_str_t  l;
1258 
1259     l.len = b->last - b->pos;
1260     l.data = b->pos;
1261     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
1262                    "mail auth http header:\n\"%V\"", &l);
1263     }
1264 #endif
1265 
1266     return b;
1267 }
1268 
1269 
1270 static ngx_int_t
1271 ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text, ngx_str_t *escaped)
1272 {
1273     u_char     *p;
1274     uintptr_t   n;
1275 
1276     n = ngx_escape_uri(NULL, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);
1277 
1278     if (n == 0) {
1279         *escaped = *text;
1280         return NGX_OK;
1281     }
1282 
1283     escaped->len = text->len + n * 2;
1284 
1285     p = ngx_pnalloc(pool, escaped->len);
1286     if (p == NULL) {
1287         return NGX_ERROR;
1288     }
1289 
1290     (void) ngx_escape_uri(p, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);
1291 
1292     escaped->data = p;
1293 
1294     return NGX_OK;
1295 }
1296 
1297 
1298 static void *
1299 ngx_mail_auth_http_create_conf(ngx_conf_t *cf)
1300 {
1301     ngx_mail_auth_http_conf_t  *ahcf;
1302 
1303     ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t));
1304     if (ahcf == NULL) {
1305         return NULL;
1306     }
1307 
1308     ahcf->timeout = NGX_CONF_UNSET_MSEC;
1309 
1310     ahcf->file = cf->conf_file->file.name.data;
1311     ahcf->line = cf->conf_file->line;
1312 
1313     return ahcf;
1314 }
1315 
1316 
1317 static char *
1318 ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child)
1319 {
1320     ngx_mail_auth_http_conf_t *prev = parent;
1321     ngx_mail_auth_http_conf_t *conf = child;
1322 
1323     u_char           *p;
1324     size_t            len;
1325     ngx_uint_t        i;
1326     ngx_table_elt_t  *header;
1327 
1328     if (conf->peer == NULL) {
1329         conf->peer = prev->peer;
1330         conf->host_header = prev->host_header;
1331         conf->uri = prev->uri;
1332 
1333         if (conf->peer == NULL) {
1334             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
1335                           "no \"http_auth\" is defined for server in %s:%ui",
1336                           conf->file, conf->line);
1337 
1338             return NGX_CONF_ERROR;
1339         }
1340     }
1341 
1342     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
1343 
1344     if (conf->headers == NULL) {
1345         conf->headers = prev->headers;
1346         conf->header = prev->header;
1347     }
1348 
1349     if (conf->headers && conf->header.len == 0) {
1350         len = 0;
1351         header = conf->headers->elts;
1352         for (i = 0; i < conf->headers->nelts; i++) {
1353             len += header[i].key.len + 2 + header[i].value.len + 2;
1354         }
1355 
1356         p = ngx_pnalloc(cf->pool, len);
1357         if (p == NULL) {
1358             return NGX_CONF_ERROR;
1359         }
1360 
1361         conf->header.len = len;
1362         conf->header.data = p;
1363 
1364         for (i = 0; i < conf->headers->nelts; i++) {
1365             p = ngx_cpymem(p, header[i].key.data, header[i].key.len);
1366             *p++ = ':'; *p++ = ' ';
1367             p = ngx_cpymem(p, header[i].value.data, header[i].value.len);
1368             *p++ = CR; *p++ = LF;
1369         }
1370     }
1371 
1372     return NGX_CONF_OK;
1373 }
1374 
1375 
1376 static char *
1377 ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1378 {
1379     ngx_mail_auth_http_conf_t *ahcf = conf;
1380 
1381     ngx_str_t  *value;
1382     ngx_url_t   u;
1383 
1384     value = cf->args->elts;
1385 
1386     ngx_memzero(&u, sizeof(ngx_url_t));
1387 
1388     u.url = value[1];
1389     u.default_port = 80;
1390     u.uri_part = 1;
1391     u.one_addr = 1;
1392 
1393     if (ngx_strncmp(u.url.data, "http://", 7) == 0) {
1394         u.url.len -= 7;
1395         u.url.data += 7;
1396     }
1397 
1398     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
1399         if (u.err) {
1400             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1401                                "%s in auth_http \"%V\"", u.err, &u.url);
1402         }
1403 
1404         return NGX_CONF_ERROR;
1405     }
1406 
1407     ahcf->peer = u.addrs;
1408 
1409     ahcf->host_header = u.host;
1410     ahcf->uri = u.uri;
1411 
1412     if (ahcf->uri.len == 0) {
1413         ahcf->uri.len = sizeof("/") - 1;
1414         ahcf->uri.data = (u_char *) "/";
1415     }
1416 
1417     return NGX_CONF_OK;
1418 }
1419 
1420 
1421 static char *
1422 ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1423 {
1424     ngx_mail_auth_http_conf_t *ahcf = conf;
1425 
1426     ngx_str_t        *value;
1427     ngx_table_elt_t  *header;
1428 
1429     if (ahcf->headers == NULL) {
1430         ahcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_table_elt_t));
1431         if (ahcf->headers == NULL) {
1432             return NGX_CONF_ERROR;
1433         }
1434     }
1435 
1436     header = ngx_array_push(ahcf->headers);
1437     if (header == NULL) {
1438         return NGX_CONF_ERROR;
1439     }
1440 
1441     value = cf->args->elts;
1442 
1443     header->key = value[1];
1444     header->value = value[2];
1445 
1446     return NGX_CONF_OK;
1447 }
1448 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.