src/mail/ngx_mail_handler.c - nginx-1.7.10

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_mail.h>


  9. static void ngx_mail_init_session(ngx_connection_t *c);

  10. #if (NGX_MAIL_SSL)
  11. static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
  12. static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
  13. #endif


  14. void
  15. ngx_mail_init_connection(ngx_connection_t *c)
  16. {
  17.     size_t                 len;
  18.     ngx_uint_t             i;
  19.     ngx_mail_port_t       *port;
  20.     struct sockaddr       *sa;
  21.     struct sockaddr_in    *sin;
  22.     ngx_mail_log_ctx_t    *ctx;
  23.     ngx_mail_in_addr_t    *addr;
  24.     ngx_mail_session_t    *s;
  25.     ngx_mail_addr_conf_t  *addr_conf;
  26.     u_char                 text[NGX_SOCKADDR_STRLEN];
  27. #if (NGX_HAVE_INET6)
  28.     struct sockaddr_in6   *sin6;
  29.     ngx_mail_in6_addr_t   *addr6;
  30. #endif


  31.     /* find the server configuration for the address:port */

  32.     port = c->listening->servers;

  33.     if (port->naddrs > 1) {

  34.         /*
  35.          * There are several addresses on this port and one of them
  36.          * is the "*:port" wildcard so getsockname() is needed to determine
  37.          * the server address.
  38.          *
  39.          * AcceptEx() already gave this address.
  40.          */

  41.         if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
  42.             ngx_mail_close_connection(c);
  43.             return;
  44.         }

  45.         sa = c->local_sockaddr;

  46.         switch (sa->sa_family) {

  47. #if (NGX_HAVE_INET6)
  48.         case AF_INET6:
  49.             sin6 = (struct sockaddr_in6 *) sa;

  50.             addr6 = port->addrs;

  51.             /* the last address is "*" */

  52.             for (i = 0; i < port->naddrs - 1; i++) {
  53.                 if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
  54.                     break;
  55.                 }
  56.             }

  57.             addr_conf = &addr6[i].conf;

  58.             break;
  59. #endif

  60.         default: /* AF_INET */
  61.             sin = (struct sockaddr_in *) sa;

  62.             addr = port->addrs;

  63.             /* the last address is "*" */

  64.             for (i = 0; i < port->naddrs - 1; i++) {
  65.                 if (addr[i].addr == sin->sin_addr.s_addr) {
  66.                     break;
  67.                 }
  68.             }

  69.             addr_conf = &addr[i].conf;

  70.             break;
  71.         }

  72.     } else {
  73.         switch (c->local_sockaddr->sa_family) {

  74. #if (NGX_HAVE_INET6)
  75.         case AF_INET6:
  76.             addr6 = port->addrs;
  77.             addr_conf = &addr6[0].conf;
  78.             break;
  79. #endif

  80.         default: /* AF_INET */
  81.             addr = port->addrs;
  82.             addr_conf = &addr[0].conf;
  83.             break;
  84.         }
  85.     }

  86.     s = ngx_pcalloc(c->pool, sizeof(ngx_mail_session_t));
  87.     if (s == NULL) {
  88.         ngx_mail_close_connection(c);
  89.         return;
  90.     }

  91.     s->signature = NGX_MAIL_MODULE;

  92.     s->main_conf = addr_conf->ctx->main_conf;
  93.     s->srv_conf = addr_conf->ctx->srv_conf;

  94.     s->addr_text = &addr_conf->addr_text;

  95.     c->data = s;
  96.     s->connection = c;

  97.     len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);

  98.     ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
  99.                   c->number, len, text, s->addr_text);

  100.     ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
  101.     if (ctx == NULL) {
  102.         ngx_mail_close_connection(c);
  103.         return;
  104.     }

  105.     ctx->client = &c->addr_text;
  106.     ctx->session = s;

  107.     c->log->connection = c->number;
  108.     c->log->handler = ngx_mail_log_error;
  109.     c->log->data = ctx;
  110.     c->log->action = "sending client greeting line";

  111.     c->log_error = NGX_ERROR_INFO;

  112. #if (NGX_MAIL_SSL)
  113.     {
  114.     ngx_mail_ssl_conf_t  *sslcf;

  115.     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);

  116.     if (sslcf->enable) {
  117.         c->log->action = "SSL handshaking";

  118.         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
  119.         return;
  120.     }

  121.     if (addr_conf->ssl) {

  122.         c->log->action = "SSL handshaking";

  123.         if (sslcf->ssl.ctx == NULL) {
  124.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  125.                           "no \"ssl_certificate\" is defined "
  126.                           "in server listening on SSL port");
  127.             ngx_mail_close_connection(c);
  128.             return;
  129.         }

  130.         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
  131.         return;
  132.     }

  133.     }
  134. #endif

  135.     ngx_mail_init_session(c);
  136. }


  137. #if (NGX_MAIL_SSL)

  138. void
  139. ngx_mail_starttls_handler(ngx_event_t *rev)
  140. {
  141.     ngx_connection_t     *c;
  142.     ngx_mail_session_t   *s;
  143.     ngx_mail_ssl_conf_t  *sslcf;

  144.     c = rev->data;
  145.     s = c->data;
  146.     s->starttls = 1;

  147.     c->log->action = "in starttls state";

  148.     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);

  149.     ngx_mail_ssl_init_connection(&sslcf->ssl, c);
  150. }


  151. static void
  152. ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
  153. {
  154.     ngx_mail_session_t        *s;
  155.     ngx_mail_core_srv_conf_t  *cscf;

  156.     if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) {
  157.         ngx_mail_close_connection(c);
  158.         return;
  159.     }

  160.     if (ngx_ssl_handshake(c) == NGX_AGAIN) {

  161.         s = c->data;

  162.         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  163.         ngx_add_timer(c->read, cscf->timeout);

  164.         c->ssl->handler = ngx_mail_ssl_handshake_handler;

  165.         return;
  166.     }

  167.     ngx_mail_ssl_handshake_handler(c);
  168. }


  169. static void
  170. ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
  171. {
  172.     ngx_mail_session_t        *s;
  173.     ngx_mail_core_srv_conf_t  *cscf;

  174.     if (c->ssl->handshaked) {

  175.         s = c->data;

  176.         if (s->starttls) {
  177.             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  178.             c->read->handler = cscf->protocol->init_protocol;
  179.             c->write->handler = ngx_mail_send;

  180.             cscf->protocol->init_protocol(c->read);

  181.             return;
  182.         }

  183.         c->read->ready = 0;

  184.         ngx_mail_init_session(c);
  185.         return;
  186.     }

  187.     ngx_mail_close_connection(c);
  188. }

  189. #endif


  190. static void
  191. ngx_mail_init_session(ngx_connection_t *c)
  192. {
  193.     ngx_mail_session_t        *s;
  194.     ngx_mail_core_srv_conf_t  *cscf;

  195.     s = c->data;

  196.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  197.     s->protocol = cscf->protocol->type;

  198.     s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
  199.     if (s->ctx == NULL) {
  200.         ngx_mail_session_internal_server_error(s);
  201.         return;
  202.     }

  203.     c->write->handler = ngx_mail_send;

  204.     cscf->protocol->init_session(s, c);
  205. }


  206. ngx_int_t
  207. ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
  208.     ngx_mail_core_srv_conf_t *cscf)
  209. {
  210.     s->salt.data = ngx_pnalloc(c->pool,
  211.                                sizeof(" <18446744073709551616.@>" CRLF) - 1
  212.                                + NGX_TIME_T_LEN
  213.                                + cscf->server_name.len);
  214.     if (s->salt.data == NULL) {
  215.         return NGX_ERROR;
  216.     }

  217.     s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
  218.                               ngx_random(), ngx_time(), &cscf->server_name)
  219.                   - s->salt.data;

  220.     return NGX_OK;
  221. }


  222. #if (NGX_MAIL_SSL)

  223. ngx_int_t
  224. ngx_mail_starttls_only(ngx_mail_session_t *s, ngx_connection_t *c)
  225. {
  226.     ngx_mail_ssl_conf_t  *sslcf;

  227.     if (c->ssl) {
  228.         return 0;
  229.     }

  230.     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);

  231.     if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
  232.         return 1;
  233.     }

  234.     return 0;
  235. }

  236. #endif


  237. ngx_int_t
  238. ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c, ngx_uint_t n)
  239. {
  240.     u_char     *p, *last;
  241.     ngx_str_t  *arg, plain;

  242.     arg = s->args.elts;

  243. #if (NGX_DEBUG_MAIL_PASSWD)
  244.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  245.                    "mail auth plain: \"%V\"", &arg[n]);
  246. #endif

  247.     plain.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
  248.     if (plain.data == NULL) {
  249.         return NGX_ERROR;
  250.     }

  251.     if (ngx_decode_base64(&plain, &arg[n]) != NGX_OK) {
  252.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  253.             "client sent invalid base64 encoding in AUTH PLAIN command");
  254.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  255.     }

  256.     p = plain.data;
  257.     last = p + plain.len;

  258.     while (p < last && *p++) { /* void */ }

  259.     if (p == last) {
  260.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  261.                       "client sent invalid login in AUTH PLAIN command");
  262.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  263.     }

  264.     s->login.data = p;

  265.     while (p < last && *p) { p++; }

  266.     if (p == last) {
  267.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  268.                       "client sent invalid password in AUTH PLAIN command");
  269.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  270.     }

  271.     s->login.len = p++ - s->login.data;

  272.     s->passwd.len = last - p;
  273.     s->passwd.data = p;

  274. #if (NGX_DEBUG_MAIL_PASSWD)
  275.     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
  276.                    "mail auth plain: \"%V\" \"%V\"", &s->login, &s->passwd);
  277. #endif

  278.     return NGX_DONE;
  279. }


  280. ngx_int_t
  281. ngx_mail_auth_login_username(ngx_mail_session_t *s, ngx_connection_t *c,
  282.     ngx_uint_t n)
  283. {
  284.     ngx_str_t  *arg;

  285.     arg = s->args.elts;

  286.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  287.                    "mail auth login username: \"%V\"", &arg[n]);

  288.     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
  289.     if (s->login.data == NULL) {
  290.         return NGX_ERROR;
  291.     }

  292.     if (ngx_decode_base64(&s->login, &arg[n]) != NGX_OK) {
  293.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  294.             "client sent invalid base64 encoding in AUTH LOGIN command");
  295.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  296.     }

  297.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  298.                    "mail auth login username: \"%V\"", &s->login);

  299.     return NGX_OK;
  300. }


  301. ngx_int_t
  302. ngx_mail_auth_login_password(ngx_mail_session_t *s, ngx_connection_t *c)
  303. {
  304.     ngx_str_t  *arg;

  305.     arg = s->args.elts;

  306. #if (NGX_DEBUG_MAIL_PASSWD)
  307.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  308.                    "mail auth login password: \"%V\"", &arg[0]);
  309. #endif

  310.     s->passwd.data = ngx_pnalloc(c->pool,
  311.                                  ngx_base64_decoded_length(arg[0].len));
  312.     if (s->passwd.data == NULL) {
  313.         return NGX_ERROR;
  314.     }

  315.     if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
  316.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  317.             "client sent invalid base64 encoding in AUTH LOGIN command");
  318.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  319.     }

  320. #if (NGX_DEBUG_MAIL_PASSWD)
  321.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  322.                    "mail auth login password: \"%V\"", &s->passwd);
  323. #endif

  324.     return NGX_DONE;
  325. }


  326. ngx_int_t
  327. ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
  328.     char *prefix, size_t len)
  329. {
  330.     u_char      *p;
  331.     ngx_str_t    salt;
  332.     ngx_uint_t   n;

  333.     p = ngx_pnalloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2);
  334.     if (p == NULL) {
  335.         return NGX_ERROR;
  336.     }

  337.     salt.data = ngx_cpymem(p, prefix, len);
  338.     s->salt.len -= 2;

  339.     ngx_encode_base64(&salt, &s->salt);

  340.     s->salt.len += 2;
  341.     n = len + salt.len;
  342.     p[n++] = CR; p[n++] = LF;

  343.     s->out.len = n;
  344.     s->out.data = p;

  345.     return NGX_OK;
  346. }


  347. ngx_int_t
  348. ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c)
  349. {
  350.     u_char     *p, *last;
  351.     ngx_str_t  *arg;

  352.     arg = s->args.elts;

  353.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  354.                    "mail auth cram-md5: \"%V\"", &arg[0]);

  355.     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len));
  356.     if (s->login.data == NULL) {
  357.         return NGX_ERROR;
  358.     }

  359.     if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
  360.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  361.             "client sent invalid base64 encoding in AUTH CRAM-MD5 command");
  362.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  363.     }

  364.     p = s->login.data;
  365.     last = p + s->login.len;

  366.     while (p < last) {
  367.         if (*p++ == ' ') {
  368.             s->login.len = p - s->login.data - 1;
  369.             s->passwd.len = last - p;
  370.             s->passwd.data = p;
  371.             break;
  372.         }
  373.     }

  374.     if (s->passwd.len != 32) {
  375.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  376.             "client sent invalid CRAM-MD5 hash in AUTH CRAM-MD5 command");
  377.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  378.     }

  379.     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
  380.                    "mail auth cram-md5: \"%V\" \"%V\"", &s->login, &s->passwd);

  381.     s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;

  382.     return NGX_DONE;
  383. }


  384. void
  385. ngx_mail_send(ngx_event_t *wev)
  386. {
  387.     ngx_int_t                  n;
  388.     ngx_connection_t          *c;
  389.     ngx_mail_session_t        *s;
  390.     ngx_mail_core_srv_conf_t  *cscf;

  391.     c = wev->data;
  392.     s = c->data;

  393.     if (wev->timedout) {
  394.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
  395.         c->timedout = 1;
  396.         ngx_mail_close_connection(c);
  397.         return;
  398.     }

  399.     if (s->out.len == 0) {
  400.         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
  401.             ngx_mail_close_connection(c);
  402.         }

  403.         return;
  404.     }

  405.     n = c->send(c, s->out.data, s->out.len);

  406.     if (n > 0) {
  407.         s->out.data += n;
  408.         s->out.len -= n;

  409.         if (s->out.len != 0) {
  410.             goto again;
  411.         }

  412.         if (wev->timer_set) {
  413.             ngx_del_timer(wev);
  414.         }

  415.         if (s->quit) {
  416.             ngx_mail_close_connection(c);
  417.             return;
  418.         }

  419.         if (s->blocked) {
  420.             c->read->handler(c->read);
  421.         }

  422.         return;
  423.     }

  424.     if (n == NGX_ERROR) {
  425.         ngx_mail_close_connection(c);
  426.         return;
  427.     }

  428.     /* n == NGX_AGAIN */

  429. again:

  430.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  431.     ngx_add_timer(c->write, cscf->timeout);

  432.     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
  433.         ngx_mail_close_connection(c);
  434.         return;
  435.     }
  436. }


  437. ngx_int_t
  438. ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
  439. {
  440.     ssize_t                    n;
  441.     ngx_int_t                  rc;
  442.     ngx_str_t                  l;
  443.     ngx_mail_core_srv_conf_t  *cscf;

  444.     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);

  445.     if (n == NGX_ERROR || n == 0) {
  446.         ngx_mail_close_connection(c);
  447.         return NGX_ERROR;
  448.     }

  449.     if (n > 0) {
  450.         s->buffer->last += n;
  451.     }

  452.     if (n == NGX_AGAIN) {
  453.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  454.             ngx_mail_session_internal_server_error(s);
  455.             return NGX_ERROR;
  456.         }

  457.         if (s->buffer->pos == s->buffer->last) {
  458.             return NGX_AGAIN;
  459.         }
  460.     }

  461.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  462.     rc = cscf->protocol->parse_command(s);

  463.     if (rc == NGX_AGAIN) {

  464.         if (s->buffer->last < s->buffer->end) {
  465.             return rc;
  466.         }

  467.         l.len = s->buffer->last - s->buffer->start;
  468.         l.data = s->buffer->start;

  469.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  470.                       "client sent too long command \"%V\"", &l);

  471.         s->quit = 1;

  472.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  473.     }

  474.     if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
  475.         return rc;
  476.     }

  477.     if (rc == NGX_ERROR) {
  478.         ngx_mail_close_connection(c);
  479.         return NGX_ERROR;
  480.     }

  481.     return NGX_OK;
  482. }


  483. void
  484. ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
  485. {
  486.     s->args.nelts = 0;

  487.     if (s->buffer->pos == s->buffer->last) {
  488.         s->buffer->pos = s->buffer->start;
  489.         s->buffer->last = s->buffer->start;
  490.     }

  491.     s->state = 0;

  492.     if (c->read->timer_set) {
  493.         ngx_del_timer(c->read);
  494.     }

  495.     s->login_attempt++;

  496.     ngx_mail_auth_http_init(s);
  497. }


  498. void
  499. ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
  500. {
  501.     ngx_mail_core_srv_conf_t  *cscf;

  502.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  503.     s->out = cscf->protocol->internal_server_error;
  504.     s->quit = 1;

  505.     ngx_mail_send(s->connection->write);
  506. }


  507. void
  508. ngx_mail_close_connection(ngx_connection_t *c)
  509. {
  510.     ngx_pool_t  *pool;

  511.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  512.                    "close mail connection: %d", c->fd);

  513. #if (NGX_MAIL_SSL)

  514.     if (c->ssl) {
  515.         if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
  516.             c->ssl->handler = ngx_mail_close_connection;
  517.             return;
  518.         }
  519.     }

  520. #endif

  521. #if (NGX_STAT_STUB)
  522.     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
  523. #endif

  524.     c->destroyed = 1;

  525.     pool = c->pool;

  526.     ngx_close_connection(c);

  527.     ngx_destroy_pool(pool);
  528. }


  529. u_char *
  530. ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len)
  531. {
  532.     u_char              *p;
  533.     ngx_mail_session_t  *s;
  534.     ngx_mail_log_ctx_t  *ctx;

  535.     if (log->action) {
  536.         p = ngx_snprintf(buf, len, " while %s", log->action);
  537.         len -= p - buf;
  538.         buf = p;
  539.     }

  540.     ctx = log->data;

  541.     p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
  542.     len -= p - buf;
  543.     buf = p;

  544.     s = ctx->session;

  545.     if (s == NULL) {
  546.         return p;
  547.     }

  548.     p = ngx_snprintf(buf, len, "%s, server: %V",
  549.                      s->starttls ? " using starttls" : "",
  550.                      s->addr_text);
  551.     len -= p - buf;
  552.     buf = p;

  553.     if (s->login.len == 0) {
  554.         return p;
  555.     }

  556.     p = ngx_snprintf(buf, len, ", login: \"%V\"", &s->login);
  557.     len -= p - buf;
  558.     buf = p;

  559.     if (s->proxy == NULL) {
  560.         return p;
  561.     }

  562.     p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name);

  563.     return p;
  564. }