Mercurial > hg > nginx
view src/mail/ngx_mail.c @ 9260:ac5635650bc6
Request body: handling of body after unbuffered reading.
As long as unbuffered reading of the request body was used, and an attempt
to read the request body is made again, such as when redirecting the request
to an error page, the request body is now cleared to make sure it can be
used safely.
Further, the r->reading_body flag, if it is still set, is cleared (along with
disabling keepalive and enabling lingering close), so the code which uses
the request body, such as when proxying, is not confused and doesn't try
to use "Transfer-Encoding: chunked".
Note that this change makes the workaround for HTTP/2 issues with unbuffered
proxying and error pages, as introduced in 7561:9f1f9d6e056a, ineffective
(since r->reading_body now cleared along with r->reading_body_no_buffering).
Though the workaround is anyway not needed after 7924:d9e009b39596, hence
it is removed.
This makes it safer to use complex processing of error pages with unbuffered
proxying.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sat, 27 Apr 2024 18:22:07 +0300 |
parents | 12ea1de7d87c |
children |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> #include <ngx_mail.h> static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, ngx_mail_listen_t *listen); static char *ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports); static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, ngx_mail_conf_addr_t *addr); #if (NGX_HAVE_INET6) static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, ngx_mail_conf_addr_t *addr); #endif static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two); ngx_uint_t ngx_mail_max_module; static ngx_command_t ngx_mail_commands[] = { { ngx_string("mail"), NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_mail_block, 0, 0, NULL }, ngx_null_command }; static ngx_core_module_t ngx_mail_module_ctx = { ngx_string("mail"), NULL, NULL }; ngx_module_t ngx_mail_module = { NGX_MODULE_V1, &ngx_mail_module_ctx, /* module context */ ngx_mail_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING }; static char * ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; ngx_uint_t i, m, mi, s; ngx_conf_t pcf; ngx_array_t ports; ngx_mail_listen_t *listen; ngx_mail_module_t *module; ngx_mail_conf_ctx_t *ctx; ngx_mail_core_srv_conf_t **cscfp; ngx_mail_core_main_conf_t *cmcf; if (*(ngx_mail_conf_ctx_t **) conf) { return "is duplicate"; } /* the main mail context */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } *(ngx_mail_conf_ctx_t **) conf = ctx; /* count the number of the mail modules and set up their indices */ ngx_mail_max_module = ngx_count_modules(cf->cycle, NGX_MAIL_MODULE); /* the mail main_conf context, it is the same in the all mail contexts */ ctx->main_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module); if (ctx->main_conf == NULL) { return NGX_CONF_ERROR; } /* * the mail null srv_conf context, it is used to merge * the server{}s' srv_conf's */ ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module); if (ctx->srv_conf == NULL) { return NGX_CONF_ERROR; } /* * create the main_conf's and the null srv_conf's of the all mail modules */ for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) { continue; } module = cf->cycle->modules[m]->ctx; mi = cf->cycle->modules[m]->ctx_index; if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); if (ctx->main_conf[mi] == NULL) { return NGX_CONF_ERROR; } } if (module->create_srv_conf) { ctx->srv_conf[mi] = module->create_srv_conf(cf); if (ctx->srv_conf[mi] == NULL) { return NGX_CONF_ERROR; } } } /* parse inside the mail{} block */ pcf = *cf; cf->ctx = ctx; cf->module_type = NGX_MAIL_MODULE; cf->cmd_type = NGX_MAIL_MAIN_CONF; rv = ngx_conf_parse(cf, NULL); if (rv != NGX_CONF_OK) { *cf = pcf; return rv; } /* init mail{} main_conf's, merge the server{}s' srv_conf's */ cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index]; cscfp = cmcf->servers.elts; for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) { continue; } module = cf->cycle->modules[m]->ctx; mi = cf->cycle->modules[m]->ctx_index; /* init mail{} main_conf's */ cf->ctx = ctx; if (module->init_main_conf) { rv = module->init_main_conf(cf, ctx->main_conf[mi]); if (rv != NGX_CONF_OK) { *cf = pcf; return rv; } } for (s = 0; s < cmcf->servers.nelts; s++) { /* merge the server{}s' srv_conf's */ cf->ctx = cscfp[s]->ctx; if (module->merge_srv_conf) { rv = module->merge_srv_conf(cf, ctx->srv_conf[mi], cscfp[s]->ctx->srv_conf[mi]); if (rv != NGX_CONF_OK) { *cf = pcf; return rv; } } } } *cf = pcf; if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t)) != NGX_OK) { return NGX_CONF_ERROR; } listen = cmcf->listen.elts; for (i = 0; i < cmcf->listen.nelts; i++) { if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) { return NGX_CONF_ERROR; } } return ngx_mail_optimize_servers(cf, &ports); } static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, ngx_mail_listen_t *listen) { in_port_t p; ngx_uint_t i; struct sockaddr *sa; ngx_mail_conf_port_t *port; ngx_mail_conf_addr_t *addr; sa = listen->sockaddr; p = ngx_inet_get_port(sa); port = ports->elts; for (i = 0; i < ports->nelts; i++) { if (p == port[i].port && sa->sa_family == port[i].family) { /* a port is already in the port list */ port = &port[i]; goto found; } } /* add a port to the port list */ port = ngx_array_push(ports); if (port == NULL) { return NGX_ERROR; } port->family = sa->sa_family; port->port = p; if (ngx_array_init(&port->addrs, cf->temp_pool, 2, sizeof(ngx_mail_conf_addr_t)) != NGX_OK) { return NGX_ERROR; } found: addr = ngx_array_push(&port->addrs); if (addr == NULL) { return NGX_ERROR; } addr->opt = *listen; return NGX_OK; } static char * ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) { ngx_uint_t i, p, last, bind_wildcard; ngx_listening_t *ls; ngx_mail_port_t *mport; ngx_mail_conf_port_t *port; ngx_mail_conf_addr_t *addr; ngx_mail_core_srv_conf_t *cscf; port = ports->elts; for (p = 0; p < ports->nelts; p++) { ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs); addr = port[p].addrs.elts; last = port[p].addrs.nelts; /* * if there is the binding to the "*:port" then we need to bind() * to the "*:port" only and ignore the other bindings */ if (addr[last - 1].opt.wildcard) { addr[last - 1].opt.bind = 1; bind_wildcard = 1; } else { bind_wildcard = 0; } i = 0; while (i < last) { if (bind_wildcard && !addr[i].opt.bind) { i++; continue; } ls = ngx_create_listening(cf, addr[i].opt.sockaddr, addr[i].opt.socklen); if (ls == NULL) { return NGX_CONF_ERROR; } ls->addr_ntop = 1; ls->handler = ngx_mail_init_connection; ls->pool_size = 256; cscf = addr->opt.ctx->srv_conf[ngx_mail_core_module.ctx_index]; ls->logp = cscf->error_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; ls->backlog = addr[i].opt.backlog; ls->rcvbuf = addr[i].opt.rcvbuf; ls->sndbuf = addr[i].opt.sndbuf; ls->keepalive = addr[i].opt.so_keepalive; #if (NGX_HAVE_KEEPALIVE_TUNABLE) ls->keepidle = addr[i].opt.tcp_keepidle; ls->keepintvl = addr[i].opt.tcp_keepintvl; ls->keepcnt = addr[i].opt.tcp_keepcnt; #endif #if (NGX_HAVE_INET6) ls->ipv6only = addr[i].opt.ipv6only; #endif mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t)); if (mport == NULL) { return NGX_CONF_ERROR; } ls->servers = mport; mport->naddrs = i + 1; switch (ls->sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) { return NGX_CONF_ERROR; } break; #endif default: /* AF_INET */ if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) { return NGX_CONF_ERROR; } break; } addr++; last--; } } return NGX_CONF_OK; } static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, ngx_mail_conf_addr_t *addr) { ngx_uint_t i; ngx_mail_in_addr_t *addrs; struct sockaddr_in *sin; mport->addrs = ngx_pcalloc(cf->pool, mport->naddrs * sizeof(ngx_mail_in_addr_t)); if (mport->addrs == NULL) { return NGX_ERROR; } addrs = mport->addrs; for (i = 0; i < mport->naddrs; i++) { sin = (struct sockaddr_in *) addr[i].opt.sockaddr; addrs[i].addr = sin->sin_addr.s_addr; addrs[i].conf.ctx = addr[i].opt.ctx; #if (NGX_MAIL_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs[i].conf.addr_text = addr[i].opt.addr_text; } return NGX_OK; } #if (NGX_HAVE_INET6) static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, ngx_mail_conf_addr_t *addr) { ngx_uint_t i; ngx_mail_in6_addr_t *addrs6; struct sockaddr_in6 *sin6; mport->addrs = ngx_pcalloc(cf->pool, mport->naddrs * sizeof(ngx_mail_in6_addr_t)); if (mport->addrs == NULL) { return NGX_ERROR; } addrs6 = mport->addrs; for (i = 0; i < mport->naddrs; i++) { sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr; addrs6[i].addr6 = sin6->sin6_addr; addrs6[i].conf.ctx = addr[i].opt.ctx; #if (NGX_MAIL_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs6[i].conf.addr_text = addr[i].opt.addr_text; } return NGX_OK; } #endif static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two) { ngx_mail_conf_addr_t *first, *second; first = (ngx_mail_conf_addr_t *) one; second = (ngx_mail_conf_addr_t *) two; if (first->opt.wildcard) { /* a wildcard must be the last resort, shift it to the end */ return 1; } if (second->opt.wildcard) { /* a wildcard must be the last resort, shift it to the end */ return -1; } if (first->opt.bind && !second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return -1; } if (!first->opt.bind && second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return 1; } /* do not sort by default */ return 0; }