src/mail/ngx_mail_auth_http_module.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_event_connect.h>
  9. #include <ngx_mail.h>


  10. typedef struct {
  11.     ngx_addr_t                     *peer;

  12.     ngx_msec_t                      timeout;

  13.     ngx_str_t                       host_header;
  14.     ngx_str_t                       uri;
  15.     ngx_str_t                       header;

  16.     ngx_array_t                    *headers;

  17.     u_char                         *file;
  18.     ngx_uint_t                      line;
  19. } ngx_mail_auth_http_conf_t;


  20. typedef struct ngx_mail_auth_http_ctx_s  ngx_mail_auth_http_ctx_t;

  21. typedef void (*ngx_mail_auth_http_handler_pt)(ngx_mail_session_t *s,
  22.     ngx_mail_auth_http_ctx_t *ctx);

  23. struct ngx_mail_auth_http_ctx_s {
  24.     ngx_buf_t                      *request;
  25.     ngx_buf_t                      *response;
  26.     ngx_peer_connection_t           peer;

  27.     ngx_mail_auth_http_handler_pt   handler;

  28.     ngx_uint_t                      state;

  29.     u_char                         *header_name_start;
  30.     u_char                         *header_name_end;
  31.     u_char                         *header_start;
  32.     u_char                         *header_end;

  33.     ngx_str_t                       addr;
  34.     ngx_str_t                       port;
  35.     ngx_str_t                       err;
  36.     ngx_str_t                       errmsg;
  37.     ngx_str_t                       errcode;

  38.     time_t                          sleep;

  39.     ngx_pool_t                     *pool;
  40. };


  41. static void ngx_mail_auth_http_write_handler(ngx_event_t *wev);
  42. static void ngx_mail_auth_http_read_handler(ngx_event_t *rev);
  43. static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
  44.     ngx_mail_auth_http_ctx_t *ctx);
  45. static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
  46.     ngx_mail_auth_http_ctx_t *ctx);
  47. static void ngx_mail_auth_sleep_handler(ngx_event_t *rev);
  48. static ngx_int_t ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
  49.     ngx_mail_auth_http_ctx_t *ctx);
  50. static void ngx_mail_auth_http_block_read(ngx_event_t *rev);
  51. static void ngx_mail_auth_http_dummy_handler(ngx_event_t *ev);
  52. static ngx_buf_t *ngx_mail_auth_http_create_request(ngx_mail_session_t *s,
  53.     ngx_pool_t *pool, ngx_mail_auth_http_conf_t *ahcf);
  54. static ngx_int_t ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text,
  55.     ngx_str_t *escaped);

  56. static void *ngx_mail_auth_http_create_conf(ngx_conf_t *cf);
  57. static char *ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
  58.     void *child);
  59. static char *ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  60. static char *ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd,
  61.     void *conf);


  62. static ngx_command_t  ngx_mail_auth_http_commands[] = {

  63.     { ngx_string("auth_http"),
  64.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  65.       ngx_mail_auth_http,
  66.       NGX_MAIL_SRV_CONF_OFFSET,
  67.       0,
  68.       NULL },

  69.     { ngx_string("auth_http_timeout"),
  70.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  71.       ngx_conf_set_msec_slot,
  72.       NGX_MAIL_SRV_CONF_OFFSET,
  73.       offsetof(ngx_mail_auth_http_conf_t, timeout),
  74.       NULL },

  75.     { ngx_string("auth_http_header"),
  76.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2,
  77.       ngx_mail_auth_http_header,
  78.       NGX_MAIL_SRV_CONF_OFFSET,
  79.       0,
  80.       NULL },

  81.       ngx_null_command
  82. };


  83. static ngx_mail_module_t  ngx_mail_auth_http_module_ctx = {
  84.     NULL,                                  /* protocol */

  85.     NULL,                                  /* create main configuration */
  86.     NULL,                                  /* init main configuration */

  87.     ngx_mail_auth_http_create_conf,        /* create server configuration */
  88.     ngx_mail_auth_http_merge_conf          /* merge server configuration */
  89. };


  90. ngx_module_t  ngx_mail_auth_http_module = {
  91.     NGX_MODULE_V1,
  92.     &ngx_mail_auth_http_module_ctx,        /* module context */
  93.     ngx_mail_auth_http_commands,           /* module directives */
  94.     NGX_MAIL_MODULE,                       /* module type */
  95.     NULL,                                  /* init master */
  96.     NULL,                                  /* init module */
  97.     NULL,                                  /* init process */
  98.     NULL,                                  /* init thread */
  99.     NULL,                                  /* exit thread */
  100.     NULL,                                  /* exit process */
  101.     NULL,                                  /* exit master */
  102.     NGX_MODULE_V1_PADDING
  103. };


  104. static ngx_str_t   ngx_mail_auth_http_method[] = {
  105.     ngx_string("plain"),
  106.     ngx_string("plain"),
  107.     ngx_string("plain"),
  108.     ngx_string("apop"),
  109.     ngx_string("cram-md5"),
  110.     ngx_string("none")
  111. };

  112. static ngx_str_t   ngx_mail_smtp_errcode = ngx_string("535 5.7.0");


  113. void
  114. ngx_mail_auth_http_init(ngx_mail_session_t *s)
  115. {
  116.     ngx_int_t                   rc;
  117.     ngx_pool_t                 *pool;
  118.     ngx_mail_auth_http_ctx_t   *ctx;
  119.     ngx_mail_auth_http_conf_t  *ahcf;

  120.     s->connection->log->action = "in http auth state";

  121.     pool = ngx_create_pool(2048, s->connection->log);
  122.     if (pool == NULL) {
  123.         ngx_mail_session_internal_server_error(s);
  124.         return;
  125.     }

  126.     ctx = ngx_pcalloc(pool, sizeof(ngx_mail_auth_http_ctx_t));
  127.     if (ctx == NULL) {
  128.         ngx_destroy_pool(pool);
  129.         ngx_mail_session_internal_server_error(s);
  130.         return;
  131.     }

  132.     ctx->pool = pool;

  133.     ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);

  134.     ctx->request = ngx_mail_auth_http_create_request(s, pool, ahcf);
  135.     if (ctx->request == NULL) {
  136.         ngx_destroy_pool(ctx->pool);
  137.         ngx_mail_session_internal_server_error(s);
  138.         return;
  139.     }

  140.     ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module);

  141.     ctx->peer.sockaddr = ahcf->peer->sockaddr;
  142.     ctx->peer.socklen = ahcf->peer->socklen;
  143.     ctx->peer.name = &ahcf->peer->name;
  144.     ctx->peer.get = ngx_event_get_peer;
  145.     ctx->peer.log = s->connection->log;
  146.     ctx->peer.log_error = NGX_ERROR_ERR;

  147.     rc = ngx_event_connect_peer(&ctx->peer);

  148.     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
  149.         if (ctx->peer.connection) {
  150.             ngx_close_connection(ctx->peer.connection);
  151.         }

  152.         ngx_destroy_pool(ctx->pool);
  153.         ngx_mail_session_internal_server_error(s);
  154.         return;
  155.     }

  156.     ctx->peer.connection->data = s;
  157.     ctx->peer.connection->pool = s->connection->pool;

  158.     s->connection->read->handler = ngx_mail_auth_http_block_read;
  159.     ctx->peer.connection->read->handler = ngx_mail_auth_http_read_handler;
  160.     ctx->peer.connection->write->handler = ngx_mail_auth_http_write_handler;

  161.     ctx->handler = ngx_mail_auth_http_ignore_status_line;

  162.     ngx_add_timer(ctx->peer.connection->read, ahcf->timeout);
  163.     ngx_add_timer(ctx->peer.connection->write, ahcf->timeout);

  164.     if (rc == NGX_OK) {
  165.         ngx_mail_auth_http_write_handler(ctx->peer.connection->write);
  166.         return;
  167.     }
  168. }


  169. static void
  170. ngx_mail_auth_http_write_handler(ngx_event_t *wev)
  171. {
  172.     ssize_t                     n, size;
  173.     ngx_connection_t           *c;
  174.     ngx_mail_session_t         *s;
  175.     ngx_mail_auth_http_ctx_t   *ctx;
  176.     ngx_mail_auth_http_conf_t  *ahcf;

  177.     c = wev->data;
  178.     s = c->data;

  179.     ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);

  180.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0,
  181.                    "mail auth http write handler");

  182.     if (wev->timedout) {
  183.         ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
  184.                       "auth http server %V timed out", ctx->peer.name);
  185.         ngx_close_connection(c);
  186.         ngx_destroy_pool(ctx->pool);
  187.         ngx_mail_session_internal_server_error(s);
  188.         return;
  189.     }

  190.     size = ctx->request->last - ctx->request->pos;

  191.     n = ngx_send(c, ctx->request->pos, size);

  192.     if (n == NGX_ERROR) {
  193.         ngx_close_connection(c);
  194.         ngx_destroy_pool(ctx->pool);
  195.         ngx_mail_session_internal_server_error(s);
  196.         return;
  197.     }

  198.     if (n > 0) {
  199.         ctx->request->pos += n;

  200.         if (n == size) {
  201.             wev->handler = ngx_mail_auth_http_dummy_handler;

  202.             if (wev->timer_set) {
  203.                 ngx_del_timer(wev);
  204.             }

  205.             if (ngx_handle_write_event(wev, 0) != NGX_OK) {
  206.                 ngx_close_connection(c);
  207.                 ngx_destroy_pool(ctx->pool);
  208.                 ngx_mail_session_internal_server_error(s);
  209.             }

  210.             return;
  211.         }
  212.     }

  213.     if (!wev->timer_set) {
  214.         ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
  215.         ngx_add_timer(wev, ahcf->timeout);
  216.     }
  217. }


  218. static void
  219. ngx_mail_auth_http_read_handler(ngx_event_t *rev)
  220. {
  221.     ssize_t                     n, size;
  222.     ngx_connection_t          *c;
  223.     ngx_mail_session_t        *s;
  224.     ngx_mail_auth_http_ctx_t  *ctx;

  225.     c = rev->data;
  226.     s = c->data;

  227.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  228.                    "mail auth http read handler");

  229.     ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);

  230.     if (rev->timedout) {
  231.         ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
  232.                       "auth http server %V timed out", ctx->peer.name);
  233.         ngx_close_connection(c);
  234.         ngx_destroy_pool(ctx->pool);
  235.         ngx_mail_session_internal_server_error(s);
  236.         return;
  237.     }

  238.     if (ctx->response == NULL) {
  239.         ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
  240.         if (ctx->response == NULL) {
  241.             ngx_close_connection(c);
  242.             ngx_destroy_pool(ctx->pool);
  243.             ngx_mail_session_internal_server_error(s);
  244.             return;
  245.         }
  246.     }

  247.     size = ctx->response->end - ctx->response->last;

  248.     n = ngx_recv(c, ctx->response->pos, size);

  249.     if (n > 0) {
  250.         ctx->response->last += n;

  251.         ctx->handler(s, ctx);
  252.         return;
  253.     }

  254.     if (n == NGX_AGAIN) {
  255.         return;
  256.     }

  257.     ngx_close_connection(c);
  258.     ngx_destroy_pool(ctx->pool);
  259.     ngx_mail_session_internal_server_error(s);
  260. }


  261. static void
  262. ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
  263.     ngx_mail_auth_http_ctx_t *ctx)
  264. {
  265.     u_char  *p, ch;
  266.     enum  {
  267.         sw_start = 0,
  268.         sw_H,
  269.         sw_HT,
  270.         sw_HTT,
  271.         sw_HTTP,
  272.         sw_skip,
  273.         sw_almost_done
  274.     } state;

  275.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  276.                    "mail auth http process status line");

  277.     state = ctx->state;

  278.     for (p = ctx->response->pos; p < ctx->response->last; p++) {
  279.         ch = *p;

  280.         switch (state) {

  281.         /* "HTTP/" */
  282.         case sw_start:
  283.             if (ch == 'H') {
  284.                 state = sw_H;
  285.                 break;
  286.             }
  287.             goto next;

  288.         case sw_H:
  289.             if (ch == 'T') {
  290.                 state = sw_HT;
  291.                 break;
  292.             }
  293.             goto next;

  294.         case sw_HT:
  295.             if (ch == 'T') {
  296.                 state = sw_HTT;
  297.                 break;
  298.             }
  299.             goto next;

  300.         case sw_HTT:
  301.             if (ch == 'P') {
  302.                 state = sw_HTTP;
  303.                 break;
  304.             }
  305.             goto next;

  306.         case sw_HTTP:
  307.             if (ch == '/') {
  308.                 state = sw_skip;
  309.                 break;
  310.             }
  311.             goto next;

  312.         /* any text until end of line */
  313.         case sw_skip:
  314.             switch (ch) {
  315.             case CR:
  316.                 state = sw_almost_done;

  317.                 break;
  318.             case LF:
  319.                 goto done;
  320.             }
  321.             break;

  322.         /* end of status line */
  323.         case sw_almost_done:
  324.             if (ch == LF) {
  325.                 goto done;
  326.             }

  327.             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  328.                           "auth http server &V sent invalid response",
  329.                           ctx->peer.name);
  330.             ngx_close_connection(ctx->peer.connection);
  331.             ngx_destroy_pool(ctx->pool);
  332.             ngx_mail_session_internal_server_error(s);
  333.             return;
  334.         }
  335.     }

  336.     ctx->response->pos = p;
  337.     ctx->state = state;

  338.     return;

  339. next:

  340.     p = ctx->response->start - 1;

  341. done:

  342.     ctx->response->pos = p + 1;
  343.     ctx->state = 0;
  344.     ctx->handler = ngx_mail_auth_http_process_headers;
  345.     ctx->handler(s, ctx);
  346. }


  347. static void
  348. ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
  349.     ngx_mail_auth_http_ctx_t *ctx)
  350. {
  351.     u_char               *p;
  352.     time_t                timer;
  353.     size_t                len, size;
  354.     ngx_int_t             rc, port, n;
  355.     ngx_addr_t           *peer;
  356.     struct sockaddr_in   *sin;
  357. #if (NGX_HAVE_INET6)
  358.     struct sockaddr_in6  *sin6;
  359. #endif

  360.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  361.                    "mail auth http process headers");

  362.     for ( ;; ) {
  363.         rc = ngx_mail_auth_http_parse_header_line(s, ctx);

  364.         if (rc == NGX_OK) {

  365. #if (NGX_DEBUG)
  366.             {
  367.             ngx_str_t  key, value;

  368.             key.len = ctx->header_name_end - ctx->header_name_start;
  369.             key.data = ctx->header_name_start;
  370.             value.len = ctx->header_end - ctx->header_start;
  371.             value.data = ctx->header_start;

  372.             ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  373.                            "mail auth http header: \"%V: %V\"",
  374.                            &key, &value);
  375.             }
  376. #endif

  377.             len = ctx->header_name_end - ctx->header_name_start;

  378.             if (len == sizeof("Auth-Status") - 1
  379.                 && ngx_strncasecmp(ctx->header_name_start,
  380.                                    (u_char *) "Auth-Status",
  381.                                    sizeof("Auth-Status") - 1)
  382.                    == 0)
  383.             {
  384.                 len = ctx->header_end - ctx->header_start;

  385.                 if (len == 2
  386.                     && ctx->header_start[0] == 'O'
  387.                     && ctx->header_start[1] == 'K')
  388.                 {
  389.                     continue;
  390.                 }

  391.                 if (len == 4
  392.                     && ctx->header_start[0] == 'W'
  393.                     && ctx->header_start[1] == 'A'
  394.                     && ctx->header_start[2] == 'I'
  395.                     && ctx->header_start[3] == 'T')
  396.                 {
  397.                     s->auth_wait = 1;
  398.                     continue;
  399.                 }

  400.                 ctx->errmsg.len = len;
  401.                 ctx->errmsg.data = ctx->header_start;

  402.                 switch (s->protocol) {

  403.                 case NGX_MAIL_POP3_PROTOCOL:
  404.                     size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1;
  405.                     break;

  406.                 case NGX_MAIL_IMAP_PROTOCOL:
  407.                     size = s->tag.len + sizeof("NO ") - 1 + len
  408.                            + sizeof(CRLF) - 1;
  409.                     break;

  410.                 default: /* NGX_MAIL_SMTP_PROTOCOL */
  411.                     ctx->err = ctx->errmsg;
  412.                     continue;
  413.                 }

  414.                 p = ngx_pnalloc(s->connection->pool, size);
  415.                 if (p == NULL) {
  416.                     ngx_close_connection(ctx->peer.connection);
  417.                     ngx_destroy_pool(ctx->pool);
  418.                     ngx_mail_session_internal_server_error(s);
  419.                     return;
  420.                 }

  421.                 ctx->err.data = p;

  422.                 switch (s->protocol) {

  423.                 case NGX_MAIL_POP3_PROTOCOL:
  424.                     *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' ';
  425.                     break;

  426.                 case NGX_MAIL_IMAP_PROTOCOL:
  427.                     p = ngx_cpymem(p, s->tag.data, s->tag.len);
  428.                     *p++ = 'N'; *p++ = 'O'; *p++ = ' ';
  429.                     break;

  430.                 default: /* NGX_MAIL_SMTP_PROTOCOL */
  431.                     break;
  432.                 }

  433.                 p = ngx_cpymem(p, ctx->header_start, len);
  434.                 *p++ = CR; *p++ = LF;

  435.                 ctx->err.len = p - ctx->err.data;

  436.                 continue;
  437.             }

  438.             if (len == sizeof("Auth-Server") - 1
  439.                 && ngx_strncasecmp(ctx->header_name_start,
  440.                                    (u_char *) "Auth-Server",
  441.                                    sizeof("Auth-Server") - 1)
  442.                     == 0)
  443.             {
  444.                 ctx->addr.len = ctx->header_end - ctx->header_start;
  445.                 ctx->addr.data = ctx->header_start;

  446.                 continue;
  447.             }

  448.             if (len == sizeof("Auth-Port") - 1
  449.                 && ngx_strncasecmp(ctx->header_name_start,
  450.                                    (u_char *) "Auth-Port",
  451.                                    sizeof("Auth-Port") - 1)
  452.                    == 0)
  453.             {
  454.                 ctx->port.len = ctx->header_end - ctx->header_start;
  455.                 ctx->port.data = ctx->header_start;

  456.                 continue;
  457.             }

  458.             if (len == sizeof("Auth-User") - 1
  459.                 && ngx_strncasecmp(ctx->header_name_start,
  460.                                    (u_char *) "Auth-User",
  461.                                    sizeof("Auth-User") - 1)
  462.                    == 0)
  463.             {
  464.                 s->login.len = ctx->header_end - ctx->header_start;

  465.                 s->login.data = ngx_pnalloc(s->connection->pool, s->login.len);
  466.                 if (s->login.data == NULL) {
  467.                     ngx_close_connection(ctx->peer.connection);
  468.                     ngx_destroy_pool(ctx->pool);
  469.                     ngx_mail_session_internal_server_error(s);
  470.                     return;
  471.                 }

  472.                 ngx_memcpy(s->login.data, ctx->header_start, s->login.len);

  473.                 continue;
  474.             }

  475.             if (len == sizeof("Auth-Pass") - 1
  476.                 && ngx_strncasecmp(ctx->header_name_start,
  477.                                    (u_char *) "Auth-Pass",
  478.                                    sizeof("Auth-Pass") - 1)
  479.                    == 0)
  480.             {
  481.                 s->passwd.len = ctx->header_end - ctx->header_start;

  482.                 s->passwd.data = ngx_pnalloc(s->connection->pool,
  483.                                              s->passwd.len);
  484.                 if (s->passwd.data == NULL) {
  485.                     ngx_close_connection(ctx->peer.connection);
  486.                     ngx_destroy_pool(ctx->pool);
  487.                     ngx_mail_session_internal_server_error(s);
  488.                     return;
  489.                 }

  490.                 ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len);

  491.                 continue;
  492.             }

  493.             if (len == sizeof("Auth-Wait") - 1
  494.                 && ngx_strncasecmp(ctx->header_name_start,
  495.                                    (u_char *) "Auth-Wait",
  496.                                    sizeof("Auth-Wait") - 1)
  497.                    == 0)
  498.             {
  499.                 n = ngx_atoi(ctx->header_start,
  500.                              ctx->header_end - ctx->header_start);

  501.                 if (n != NGX_ERROR) {
  502.                     ctx->sleep = n;
  503.                 }

  504.                 continue;
  505.             }

  506.             if (len == sizeof("Auth-Error-Code") - 1
  507.                 && ngx_strncasecmp(ctx->header_name_start,
  508.                                    (u_char *) "Auth-Error-Code",
  509.                                    sizeof("Auth-Error-Code") - 1)
  510.                    == 0)
  511.             {
  512.                 ctx->errcode.len = ctx->header_end - ctx->header_start;

  513.                 ctx->errcode.data = ngx_pnalloc(s->connection->pool,
  514.                                                 ctx->errcode.len);
  515.                 if (ctx->errcode.data == NULL) {
  516.                     ngx_close_connection(ctx->peer.connection);
  517.                     ngx_destroy_pool(ctx->pool);
  518.                     ngx_mail_session_internal_server_error(s);
  519.                     return;
  520.                 }

  521.                 ngx_memcpy(ctx->errcode.data, ctx->header_start,
  522.                            ctx->errcode.len);

  523.                 continue;
  524.             }

  525.             /* ignore other headers */

  526.             continue;
  527.         }

  528.         if (rc == NGX_DONE) {
  529.             ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  530.                            "mail auth http header done");

  531.             ngx_close_connection(ctx->peer.connection);

  532.             if (ctx->err.len) {

  533.                 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  534.                               "client login failed: \"%V\"", &ctx->errmsg);

  535.                 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) {

  536.                     if (ctx->errcode.len == 0) {
  537.                         ctx->errcode = ngx_mail_smtp_errcode;
  538.                     }

  539.                     ctx->err.len = ctx->errcode.len + ctx->errmsg.len
  540.                                    + sizeof(" " CRLF) - 1;

  541.                     p = ngx_pnalloc(s->connection->pool, ctx->err.len);
  542.                     if (p == NULL) {
  543.                         ngx_destroy_pool(ctx->pool);
  544.                         ngx_mail_session_internal_server_error(s);
  545.                         return;
  546.                     }

  547.                     ctx->err.data = p;

  548.                     p = ngx_cpymem(p, ctx->errcode.data, ctx->errcode.len);
  549.                     *p++ = ' ';
  550.                     p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len);
  551.                     *p++ = CR; *p = LF;
  552.                 }

  553.                 s->out = ctx->err;
  554.                 timer = ctx->sleep;

  555.                 ngx_destroy_pool(ctx->pool);

  556.                 if (timer == 0) {
  557.                     s->quit = 1;
  558.                     ngx_mail_send(s->connection->write);
  559.                     return;
  560.                 }

  561.                 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));

  562.                 s->connection->read->handler = ngx_mail_auth_sleep_handler;

  563.                 return;
  564.             }

  565.             if (s->auth_wait) {
  566.                 timer = ctx->sleep;

  567.                 ngx_destroy_pool(ctx->pool);

  568.                 if (timer == 0) {
  569.                     ngx_mail_auth_http_init(s);
  570.                     return;
  571.                 }

  572.                 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));

  573.                 s->connection->read->handler = ngx_mail_auth_sleep_handler;

  574.                 return;
  575.             }

  576.             if (ctx->addr.len == 0 || ctx->port.len == 0) {
  577.                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  578.                               "auth http server %V did not send server or port",
  579.                               ctx->peer.name);
  580.                 ngx_destroy_pool(ctx->pool);
  581.                 ngx_mail_session_internal_server_error(s);
  582.                 return;
  583.             }

  584.             if (s->passwd.data == NULL
  585.                 && s->protocol != NGX_MAIL_SMTP_PROTOCOL)
  586.             {
  587.                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  588.                               "auth http server %V did not send password",
  589.                               ctx->peer.name);
  590.                 ngx_destroy_pool(ctx->pool);
  591.                 ngx_mail_session_internal_server_error(s);
  592.                 return;
  593.             }

  594.             peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_addr_t));
  595.             if (peer == NULL) {
  596.                 ngx_destroy_pool(ctx->pool);
  597.                 ngx_mail_session_internal_server_error(s);
  598.                 return;
  599.             }

  600.             rc = ngx_parse_addr(s->connection->pool, peer,
  601.                                 ctx->addr.data, ctx->addr.len);

  602.             switch (rc) {
  603.             case NGX_OK:
  604.                 break;

  605.             case NGX_DECLINED:
  606.                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  607.                               "auth http server %V sent invalid server "
  608.                               "address:\"%V\"",
  609.                               ctx->peer.name, &ctx->addr);
  610.                 /* fall through */

  611.             default:
  612.                 ngx_destroy_pool(ctx->pool);
  613.                 ngx_mail_session_internal_server_error(s);
  614.                 return;
  615.             }

  616.             port = ngx_atoi(ctx->port.data, ctx->port.len);
  617.             if (port == NGX_ERROR || port < 1 || port > 65535) {
  618.                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  619.                               "auth http server %V sent invalid server "
  620.                               "port:\"%V\"",
  621.                               ctx->peer.name, &ctx->port);
  622.                 ngx_destroy_pool(ctx->pool);
  623.                 ngx_mail_session_internal_server_error(s);
  624.                 return;
  625.             }

  626.             switch (peer->sockaddr->sa_family) {

  627. #if (NGX_HAVE_INET6)
  628.             case AF_INET6:
  629.                 sin6 = (struct sockaddr_in6 *) peer->sockaddr;
  630.                 sin6->sin6_port = htons((in_port_t) port);
  631.                 break;
  632. #endif

  633.             default: /* AF_INET */
  634.                 sin = (struct sockaddr_in *) peer->sockaddr;
  635.                 sin->sin_port = htons((in_port_t) port);
  636.                 break;
  637.             }

  638.             len = ctx->addr.len + 1 + ctx->port.len;

  639.             peer->name.len = len;

  640.             peer->name.data = ngx_pnalloc(s->connection->pool, len);
  641.             if (peer->name.data == NULL) {
  642.                 ngx_destroy_pool(ctx->pool);
  643.                 ngx_mail_session_internal_server_error(s);
  644.                 return;
  645.             }

  646.             len = ctx->addr.len;

  647.             ngx_memcpy(peer->name.data, ctx->addr.data, len);

  648.             peer->name.data[len++] = ':';

  649.             ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);

  650.             ngx_destroy_pool(ctx->pool);
  651.             ngx_mail_proxy_init(s, peer);

  652.             return;
  653.         }

  654.         if (rc == NGX_AGAIN ) {
  655.             return;
  656.         }

  657.         /* rc == NGX_ERROR */

  658.         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  659.                       "auth http server %V sent invalid header in response",
  660.                       ctx->peer.name);
  661.         ngx_close_connection(ctx->peer.connection);
  662.         ngx_destroy_pool(ctx->pool);
  663.         ngx_mail_session_internal_server_error(s);

  664.         return;
  665.     }
  666. }


  667. static void
  668. ngx_mail_auth_sleep_handler(ngx_event_t *rev)
  669. {
  670.     ngx_connection_t          *c;
  671.     ngx_mail_session_t        *s;
  672.     ngx_mail_core_srv_conf_t  *cscf;

  673.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail auth sleep handler");

  674.     c = rev->data;
  675.     s = c->data;

  676.     if (rev->timedout) {

  677.         rev->timedout = 0;

  678.         if (s->auth_wait) {
  679.             s->auth_wait = 0;
  680.             ngx_mail_auth_http_init(s);
  681.             return;
  682.         }

  683.         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  684.         rev->handler = cscf->protocol->auth_state;

  685.         s->mail_state = 0;
  686.         s->auth_method = NGX_MAIL_AUTH_PLAIN;

  687.         c->log->action = "in auth state";

  688.         ngx_mail_send(c->write);

  689.         if (c->destroyed) {
  690.             return;
  691.         }

  692.         ngx_add_timer(rev, cscf->timeout);

  693.         if (rev->ready) {
  694.             rev->handler(rev);
  695.             return;
  696.         }

  697.         if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  698.             ngx_mail_close_connection(c);
  699.         }

  700.         return;
  701.     }

  702.     if (rev->active) {
  703.         if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  704.             ngx_mail_close_connection(c);
  705.         }
  706.     }
  707. }


  708. static ngx_int_t
  709. ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
  710.     ngx_mail_auth_http_ctx_t *ctx)
  711. {
  712.     u_char      c, ch, *p;
  713.     enum {
  714.         sw_start = 0,
  715.         sw_name,
  716.         sw_space_before_value,
  717.         sw_value,
  718.         sw_space_after_value,
  719.         sw_almost_done,
  720.         sw_header_almost_done
  721.     } state;

  722.     state = ctx->state;

  723.     for (p = ctx->response->pos; p < ctx->response->last; p++) {
  724.         ch = *p;

  725.         switch (state) {

  726.         /* first char */
  727.         case sw_start:

  728.             switch (ch) {
  729.             case CR:
  730.                 ctx->header_end = p;
  731.                 state = sw_header_almost_done;
  732.                 break;
  733.             case LF:
  734.                 ctx->header_end = p;
  735.                 goto header_done;
  736.             default:
  737.                 state = sw_name;
  738.                 ctx->header_name_start = p;

  739.                 c = (u_char) (ch | 0x20);
  740.                 if (c >= 'a' && c <= 'z') {
  741.                     break;
  742.                 }

  743.                 if (ch >= '0' && ch <= '9') {
  744.                     break;
  745.                 }

  746.                 return NGX_ERROR;
  747.             }
  748.             break;

  749.         /* header name */
  750.         case sw_name:
  751.             c = (u_char) (ch | 0x20);
  752.             if (c >= 'a' && c <= 'z') {
  753.                 break;
  754.             }

  755.             if (ch == ':') {
  756.                 ctx->header_name_end = p;
  757.                 state = sw_space_before_value;
  758.                 break;
  759.             }

  760.             if (ch == '-') {
  761.                 break;
  762.             }

  763.             if (ch >= '0' && ch <= '9') {
  764.                 break;
  765.             }

  766.             if (ch == CR) {
  767.                 ctx->header_name_end = p;
  768.                 ctx->header_start = p;
  769.                 ctx->header_end = p;
  770.                 state = sw_almost_done;
  771.                 break;
  772.             }

  773.             if (ch == LF) {
  774.                 ctx->header_name_end = p;
  775.                 ctx->header_start = p;
  776.                 ctx->header_end = p;
  777.                 goto done;
  778.             }

  779.             return NGX_ERROR;

  780.         /* space* before header value */
  781.         case sw_space_before_value:
  782.             switch (ch) {
  783.             case ' ':
  784.                 break;
  785.             case CR:
  786.                 ctx->header_start = p;
  787.                 ctx->header_end = p;
  788.                 state = sw_almost_done;
  789.                 break;
  790.             case LF:
  791.                 ctx->header_start = p;
  792.                 ctx->header_end = p;
  793.                 goto done;
  794.             default:
  795.                 ctx->header_start = p;
  796.                 state = sw_value;
  797.                 break;
  798.             }
  799.             break;

  800.         /* header value */
  801.         case sw_value:
  802.             switch (ch) {
  803.             case ' ':
  804.                 ctx->header_end = p;
  805.                 state = sw_space_after_value;
  806.                 break;
  807.             case CR:
  808.                 ctx->header_end = p;
  809.                 state = sw_almost_done;
  810.                 break;
  811.             case LF:
  812.                 ctx->header_end = p;
  813.                 goto done;
  814.             }
  815.             break;

  816.         /* space* before end of header line */
  817.         case sw_space_after_value:
  818.             switch (ch) {
  819.             case ' ':
  820.                 break;
  821.             case CR:
  822.                 state = sw_almost_done;
  823.                 break;
  824.             case LF:
  825.                 goto done;
  826.             default:
  827.                 state = sw_value;
  828.                 break;
  829.             }
  830.             break;

  831.         /* end of header line */
  832.         case sw_almost_done:
  833.             switch (ch) {
  834.             case LF:
  835.                 goto done;
  836.             default:
  837.                 return NGX_ERROR;
  838.             }

  839.         /* end of header */
  840.         case sw_header_almost_done:
  841.             switch (ch) {
  842.             case LF:
  843.                 goto header_done;
  844.             default:
  845.                 return NGX_ERROR;
  846.             }
  847.         }
  848.     }

  849.     ctx->response->pos = p;
  850.     ctx->state = state;

  851.     return NGX_AGAIN;

  852. done:

  853.     ctx->response->pos = p + 1;
  854.     ctx->state = sw_start;

  855.     return NGX_OK;

  856. header_done:

  857.     ctx->response->pos = p + 1;
  858.     ctx->state = sw_start;

  859.     return NGX_DONE;
  860. }


  861. static void
  862. ngx_mail_auth_http_block_read(ngx_event_t *rev)
  863. {
  864.     ngx_connection_t          *c;
  865.     ngx_mail_session_t        *s;
  866.     ngx_mail_auth_http_ctx_t  *ctx;

  867.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  868.                    "mail auth http block read");

  869.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  870.         c = rev->data;
  871.         s = c->data;

  872.         ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);

  873.         ngx_close_connection(ctx->peer.connection);
  874.         ngx_destroy_pool(ctx->pool);
  875.         ngx_mail_session_internal_server_error(s);
  876.     }
  877. }


  878. static void
  879. ngx_mail_auth_http_dummy_handler(ngx_event_t *ev)
  880. {
  881.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, ev->log, 0,
  882.                    "mail auth http dummy handler");
  883. }


  884. static ngx_buf_t *
  885. ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
  886.     ngx_mail_auth_http_conf_t *ahcf)
  887. {
  888.     size_t                     len;
  889.     ngx_buf_t                 *b;
  890.     ngx_str_t                  login, passwd;
  891.     ngx_mail_core_srv_conf_t  *cscf;

  892.     if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
  893.         return NULL;
  894.     }

  895.     if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
  896.         return NULL;
  897.     }

  898.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  899.     len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
  900.           + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
  901.           + sizeof("Auth-Method: ") - 1
  902.                 + ngx_mail_auth_http_method[s->auth_method].len
  903.                 + sizeof(CRLF) - 1
  904.           + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
  905.           + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
  906.           + sizeof("Auth-Salt: ") - 1 + s->salt.len
  907.           + sizeof("Auth-Protocol: ") - 1 + cscf->protocol->name.len
  908.                 + sizeof(CRLF) - 1
  909.           + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
  910.                 + sizeof(CRLF) - 1
  911.           + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
  912.                 + sizeof(CRLF) - 1
  913.           + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1
  914.           + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len
  915.           + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len
  916.           + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len
  917.           + ahcf->header.len
  918.           + sizeof(CRLF) - 1;

  919.     b = ngx_create_temp_buf(pool, len);
  920.     if (b == NULL) {
  921.         return NULL;
  922.     }

  923.     b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1);
  924.     b->last = ngx_copy(b->last, ahcf->uri.data, ahcf->uri.len);
  925.     b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF,
  926.                          sizeof(" HTTP/1.0" CRLF) - 1);

  927.     b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1);
  928.     b->last = ngx_copy(b->last, ahcf->host_header.data,
  929.                          ahcf->host_header.len);
  930.     *b->last++ = CR; *b->last++ = LF;

  931.     b->last = ngx_cpymem(b->last, "Auth-Method: ",
  932.                          sizeof("Auth-Method: ") - 1);
  933.     b->last = ngx_cpymem(b->last,
  934.                          ngx_mail_auth_http_method[s->auth_method].data,
  935.                          ngx_mail_auth_http_method[s->auth_method].len);
  936.     *b->last++ = CR; *b->last++ = LF;

  937.     b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
  938.     b->last = ngx_copy(b->last, login.data, login.len);
  939.     *b->last++ = CR; *b->last++ = LF;

  940.     b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
  941.     b->last = ngx_copy(b->last, passwd.data, passwd.len);
  942.     *b->last++ = CR; *b->last++ = LF;

  943.     if (s->auth_method != NGX_MAIL_AUTH_PLAIN && s->salt.len) {
  944.         b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
  945.         b->last = ngx_copy(b->last, s->salt.data, s->salt.len);

  946.         s->passwd.data = NULL;
  947.     }

  948.     b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
  949.                          sizeof("Auth-Protocol: ") - 1);
  950.     b->last = ngx_cpymem(b->last, cscf->protocol->name.data,
  951.                          cscf->protocol->name.len);
  952.     *b->last++ = CR; *b->last++ = LF;

  953.     b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
  954.                           s->login_attempt);

  955.     b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
  956.     b->last = ngx_copy(b->last, s->connection->addr_text.data,
  957.                        s->connection->addr_text.len);
  958.     *b->last++ = CR; *b->last++ = LF;

  959.     if (s->host.len) {
  960.         b->last = ngx_cpymem(b->last, "Client-Host: ",
  961.                              sizeof("Client-Host: ") - 1);
  962.         b->last = ngx_copy(b->last, s->host.data, s->host.len);
  963.         *b->last++ = CR; *b->last++ = LF;
  964.     }

  965.     if (s->auth_method == NGX_MAIL_AUTH_NONE) {

  966.         /* HELO, MAIL FROM, and RCPT TO can't contain CRLF, no need to escape */

  967.         b->last = ngx_cpymem(b->last, "Auth-SMTP-Helo: ",
  968.                              sizeof("Auth-SMTP-Helo: ") - 1);
  969.         b->last = ngx_copy(b->last, s->smtp_helo.data, s->smtp_helo.len);
  970.         *b->last++ = CR; *b->last++ = LF;

  971.         b->last = ngx_cpymem(b->last, "Auth-SMTP-From: ",
  972.                              sizeof("Auth-SMTP-From: ") - 1);
  973.         b->last = ngx_copy(b->last, s->smtp_from.data, s->smtp_from.len);
  974.         *b->last++ = CR; *b->last++ = LF;

  975.         b->last = ngx_cpymem(b->last, "Auth-SMTP-To: ",
  976.                              sizeof("Auth-SMTP-To: ") - 1);
  977.         b->last = ngx_copy(b->last, s->smtp_to.data, s->smtp_to.len);
  978.         *b->last++ = CR; *b->last++ = LF;

  979.     }

  980.     if (ahcf->header.len) {
  981.         b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
  982.     }

  983.     /* add "\r\n" at the header end */
  984.     *b->last++ = CR; *b->last++ = LF;

  985. #if (NGX_DEBUG_MAIL_PASSWD)
  986.     {
  987.     ngx_str_t  l;

  988.     l.len = b->last - b->pos;
  989.     l.data = b->pos;
  990.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  991.                    "mail auth http header:%N\"%V\"", &l);
  992.     }
  993. #endif

  994.     return b;
  995. }


  996. static ngx_int_t
  997. ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text, ngx_str_t *escaped)
  998. {
  999.     u_char     *p;
  1000.     uintptr_t   n;

  1001.     n = ngx_escape_uri(NULL, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);

  1002.     if (n == 0) {
  1003.         *escaped = *text;
  1004.         return NGX_OK;
  1005.     }

  1006.     escaped->len = text->len + n * 2;

  1007.     p = ngx_pnalloc(pool, escaped->len);
  1008.     if (p == NULL) {
  1009.         return NGX_ERROR;
  1010.     }

  1011.     (void) ngx_escape_uri(p, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);

  1012.     escaped->data = p;

  1013.     return NGX_OK;
  1014. }


  1015. static void *
  1016. ngx_mail_auth_http_create_conf(ngx_conf_t *cf)
  1017. {
  1018.     ngx_mail_auth_http_conf_t  *ahcf;

  1019.     ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t));
  1020.     if (ahcf == NULL) {
  1021.         return NULL;
  1022.     }

  1023.     ahcf->timeout = NGX_CONF_UNSET_MSEC;

  1024.     ahcf->file = cf->conf_file->file.name.data;
  1025.     ahcf->line = cf->conf_file->line;

  1026.     return ahcf;
  1027. }


  1028. static char *
  1029. ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child)
  1030. {
  1031.     ngx_mail_auth_http_conf_t *prev = parent;
  1032.     ngx_mail_auth_http_conf_t *conf = child;

  1033.     u_char           *p;
  1034.     size_t            len;
  1035.     ngx_uint_t        i;
  1036.     ngx_table_elt_t  *header;

  1037.     if (conf->peer == NULL) {
  1038.         conf->peer = prev->peer;
  1039.         conf->host_header = prev->host_header;
  1040.         conf->uri = prev->uri;

  1041.         if (conf->peer == NULL) {
  1042.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  1043.                           "no \"auth_http\" is defined for server in %s:%ui",
  1044.                           conf->file, conf->line);

  1045.             return NGX_CONF_ERROR;
  1046.         }
  1047.     }

  1048.     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);

  1049.     if (conf->headers == NULL) {
  1050.         conf->headers = prev->headers;
  1051.         conf->header = prev->header;
  1052.     }

  1053.     if (conf->headers && conf->header.len == 0) {
  1054.         len = 0;
  1055.         header = conf->headers->elts;
  1056.         for (i = 0; i < conf->headers->nelts; i++) {
  1057.             len += header[i].key.len + 2 + header[i].value.len + 2;
  1058.         }

  1059.         p = ngx_pnalloc(cf->pool, len);
  1060.         if (p == NULL) {
  1061.             return NGX_CONF_ERROR;
  1062.         }

  1063.         conf->header.len = len;
  1064.         conf->header.data = p;

  1065.         for (i = 0; i < conf->headers->nelts; i++) {
  1066.             p = ngx_cpymem(p, header[i].key.data, header[i].key.len);
  1067.             *p++ = ':'; *p++ = ' ';
  1068.             p = ngx_cpymem(p, header[i].value.data, header[i].value.len);
  1069.             *p++ = CR; *p++ = LF;
  1070.         }
  1071.     }

  1072.     return NGX_CONF_OK;
  1073. }


  1074. static char *
  1075. ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1076. {
  1077.     ngx_mail_auth_http_conf_t *ahcf = conf;

  1078.     ngx_str_t  *value;
  1079.     ngx_url_t   u;

  1080.     value = cf->args->elts;

  1081.     ngx_memzero(&u, sizeof(ngx_url_t));

  1082.     u.url = value[1];
  1083.     u.default_port = 80;
  1084.     u.uri_part = 1;

  1085.     if (ngx_strncmp(u.url.data, "http://", 7) == 0) {
  1086.         u.url.len -= 7;
  1087.         u.url.data += 7;
  1088.     }

  1089.     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
  1090.         if (u.err) {
  1091.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1092.                                "%s in auth_http \"%V\"", u.err, &u.url);
  1093.         }

  1094.         return NGX_CONF_ERROR;
  1095.     }

  1096.     ahcf->peer = u.addrs;

  1097.     if (u.family != AF_UNIX) {
  1098.         ahcf->host_header = u.host;

  1099.     } else {
  1100.         ngx_str_set(&ahcf->host_header, "localhost");
  1101.     }

  1102.     ahcf->uri = u.uri;

  1103.     if (ahcf->uri.len == 0) {
  1104.         ngx_str_set(&ahcf->uri, "/");
  1105.     }

  1106.     return NGX_CONF_OK;
  1107. }


  1108. static char *
  1109. ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1110. {
  1111.     ngx_mail_auth_http_conf_t *ahcf = conf;

  1112.     ngx_str_t        *value;
  1113.     ngx_table_elt_t  *header;

  1114.     if (ahcf->headers == NULL) {
  1115.         ahcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_table_elt_t));
  1116.         if (ahcf->headers == NULL) {
  1117.             return NGX_CONF_ERROR;
  1118.         }
  1119.     }

  1120.     header = ngx_array_push(ahcf->headers);
  1121.     if (header == NULL) {
  1122.         return NGX_CONF_ERROR;
  1123.     }

  1124.     value = cf->args->elts;

  1125.     header->key = value[1];
  1126.     header->value = value[2];

  1127.     return NGX_CONF_OK;
  1128. }