static ngx_http_google_ctx_t * ngx_http_google_create_ctx(ngx_http_request_t * r) { ngx_http_google_loc_conf_t * glcf; glcf = ngx_http_get_module_loc_conf(r, ngx_http_google_filter_module); ngx_http_google_ctx_t * ctx; ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_google_ctx_t)); if (!ctx) return NULL; ctx->host = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); if (!ctx->host) return NULL; ctx->conf = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); if (!ctx->conf) return NULL; ctx->pass = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); if (!ctx->pass) return NULL; ctx->arg = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); if (!ctx->arg) return NULL; ctx->domain = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); if (!ctx->domain) return NULL; // default conf key ngx_str_set(ctx->conf, "PREF"); ctx->uri = &r->unparsed_uri; ctx->host = &r->headers_in.host->value; ctx->lang = &glcf->language; ctx->type = ngx_http_google_type_main; ngx_str_t domain = *ctx->host; u_char * last = domain.data + domain.len, * find; if ((find = ngx_strlchr(domain.data, last, ':'))) { domain.len = find - domain.data; } ctx->domain->len = domain.len + 1; ctx->domain->data = ngx_pcalloc(r->pool, ctx->domain->len); if (!ctx->domain->data) return NULL; ngx_snprintf(ctx->domain->data, ctx->domain->len, ".%V", &domain); if (ngx_inet_addr(domain.data, domain.len) != INADDR_NONE) { ctx->domain->data++; ctx->domain->len --; } // default language if (!ctx->lang->len) { ngx_str_set(ctx->lang, "zh-CN"); } ctx->robots = (ctx->uri->len == 11 && !ngx_strncmp(ctx->uri->data, "/robots.txt", 11)); #if (NGX_HTTP_SSL) ngx_http_ssl_srv_conf_t * sscf; sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (sscf->enable || r->http_connection->addr_conf->ssl) ctx->ssl = 1; #endif return ctx; }
//比较etag是否发生了变化 r->headers_out.etag为nginx服务器端最新的etag,header->value为浏览器请求头部行中携带的etag信息 static ngx_uint_t ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header, ngx_uint_t weak) //ngx_http_test_if_match验证客户端过来的etag, ngx_http_set_etag设置最新etag { u_char *start, *end, ch; ngx_str_t etag, *list; list = &header->value; if (list->len == 1 && list->data[0] == '*') { return 1; } //如果客户端在第一次请求文件和第二次请求文件这段时间,文件修改了,则etag会发生变化 if (r->headers_out.etag == NULL) { return 0; } etag = r->headers_out.etag->value; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http im:\"%V\" etag:%V", list, &etag); if (weak && etag.len > 2 && etag.data[0] == 'W' && etag.data[1] == '/') //见ngx_http_weak_etag { etag.len -= 2; etag.data += 2; } //去掉前面的W/字符, start = list->data; end = list->data + list->len; while (start < end) { if (weak && end - start > 2 && start[0] == 'W' && start[1] == '/') { start += 2; //去掉前面的W/字符, } if (etag.len > (size_t) (end - start)) { return 0; } if (ngx_strncmp(start, etag.data, etag.len) != 0) { goto skip; } start += etag.len; while (start < end) { ch = *start; if (ch == ' ' || ch == '\t') { start++; continue; } break; } if (start == end || *start == ',') { return 1; } skip: while (start < end && *start != ',') { start++; } while (start < end) { ch = *start; if (ch == ' ' || ch == '\t' || ch == ',') { start++; continue; } break; } } return 0; }
static ngx_int_t ngx_http_redis_filter(void *data, ssize_t bytes) { ngx_http_redis_ctx_t *ctx = data; u_char *last; ngx_buf_t *b; ngx_chain_t *cl, **ll; ngx_http_upstream_t *u; u = ctx->request->upstream; b = &u->buffer; if (u->length == (ssize_t) ctx->rest) { if (ngx_strncmp(b->last, ngx_http_redis_end + NGX_HTTP_REDIS_END - ctx->rest, bytes) != 0) { ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, "redis sent invalid trailer"); u->length = 0; ctx->rest = 0; return NGX_OK; } u->length -= bytes; ctx->rest -= bytes; if (u->length == 0) { u->keepalive = 1; } return NGX_OK; } for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { ll = &cl->next; } cl = ngx_chain_get_free_buf(ctx->request->pool, &u->free_bufs); if (cl == NULL) { return NGX_ERROR; } cl->buf->flush = 1; cl->buf->memory = 1; *ll = cl; last = b->last; cl->buf->pos = last; b->last += bytes; cl->buf->last = b->last; cl->buf->tag = u->output.tag; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, "redis filter bytes:%z size:%z length:%z rest:%z", bytes, b->last - b->pos, u->length, ctx->rest); if (bytes <= (ssize_t) (u->length - NGX_HTTP_REDIS_END)) { u->length -= bytes; return NGX_OK; } last += u->length - NGX_HTTP_REDIS_END; if (ngx_strncmp(last, ngx_http_redis_end, b->last - last) != 0) { ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, "redis sent invalid trailer"); b->last = last; cl->buf->last = last; u->length = 0; ctx->rest = 0; return NGX_OK; } ctx->rest -= b->last - last; b->last = last; cl->buf->last = last; u->length = ctx->rest; if (u->length == 0) { u->keepalive = 1; } return NGX_OK; }
//http://blog.csdn.net/lengzijian/article/details/7575813 ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) { void *rv; char **senv, **env; ngx_uint_t i, n; ngx_log_t *log; ngx_time_t *tp; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; ngx_shm_zone_t *shm_zone, *oshm_zone; ngx_list_part_t *part, *opart; ngx_open_file_t *file; ngx_listening_t *ls, *nls; ngx_core_conf_t *ccf, *old_ccf; ngx_core_module_t *module; char hostname[NGX_MAXHOSTNAMELEN]; ngx_timezone_update(); /* force localtime update with a new timezone */ tp = ngx_timeofday(); tp->sec = 0; ngx_time_update(); log = old_cycle->log; pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (pool == NULL) { return NULL; } pool->log = log; cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)); if (cycle == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->pool = pool; cycle->log = log; cycle->old_cycle = old_cycle; cycle->conf_prefix.len = old_cycle->conf_prefix.len; cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix); if (cycle->conf_prefix.data == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->prefix.len = old_cycle->prefix.len; cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix); if (cycle->prefix.data == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_file.len = old_cycle->conf_file.len; cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1); if (cycle->conf_file.data == NULL) { ngx_destroy_pool(pool); return NULL; } ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data, old_cycle->conf_file.len + 1); cycle->conf_param.len = old_cycle->conf_param.len; cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param); if (cycle->conf_param.data == NULL) { ngx_destroy_pool(pool); return NULL; } n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10; cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)); if (cycle->paths.elts == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->paths.nelts = 0; cycle->paths.size = sizeof(ngx_path_t *); cycle->paths.nalloc = n; cycle->paths.pool = pool; if (old_cycle->open_files.part.nelts) { n = old_cycle->open_files.part.nelts; for (part = old_cycle->open_files.part.next; part; part = part->next) { n += part->nelts; } } else { n = 20; } if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; } if (old_cycle->shared_memory.part.nelts) { n = old_cycle->shared_memory.part.nelts; for (part = old_cycle->shared_memory.part.next; part; part = part->next) { n += part->nelts; } } else { n = 1; } //ngx_list_init主要是初始链表的elts,并为其申请内存 if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; } n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); if (cycle->listening.elts == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->listening.nelts = 0; cycle->listening.size = sizeof(ngx_listening_t); cycle->listening.nalloc = n; cycle->listening.pool = pool; //初始化双向链表。主要存储着可反复用的连接ngx_connection_t ngx_queue_init(&cycle->reusable_connections_queue); cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); if (cycle->conf_ctx == NULL) { ngx_destroy_pool(pool); return NULL; } if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {//获取主机名称 ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed"); ngx_destroy_pool(pool); return NULL; } /* on Linux gethostname() silently truncates name that does not fit */ hostname[NGX_MAXHOSTNAMELEN - 1] = '\0'; cycle->hostname.len = ngx_strlen(hostname); cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len); if (cycle->hostname.data == NULL) { ngx_destroy_pool(pool); return NULL; } ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len); //调用全部NGX_CORE_MODULE的create_conf构建配置结构体。并保存在conf_ctx数组里面 for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { //event 和http 和core 三个module continue; } //上下文操作 //static ngx_core_module_t ngx_events_module_ctx = { //ngx_string("events"), //NULL, //ngx_event_init_conf //}; //static ngx_core_module_t ngx_http_module_ctx = { //ngx_string("http"), //NULL, //NULL //}; //static ngx_core_module_t ngx_core_module_ctx = { // ngx_string("core"), //ngx_core_module_create_conf, // ngx_core_module_init_conf //}; // module = ngx_modules[i]->ctx; //core module 模块只有create 和 init 两个回调函数 其他 if (module->create_conf) { // rv 返回ngx_core_conf_t rv = module->create_conf(cycle); if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_ctx[ngx_modules[i]->index] = rv; //倒数第二级指针存放的是每个模块的create-conf 的指针 } } senv = environ; ngx_memzero(&conf, sizeof(ngx_conf_t)); /* STUB: init array ? */ conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t)); if (conf.args == NULL) { ngx_destroy_pool(pool); return NULL; } conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (conf.temp_pool == NULL) { ngx_destroy_pool(pool); return NULL; } conf.ctx = cycle->conf_ctx; conf.cycle = cycle; conf.pool = pool; conf.log = log; conf.module_type = NGX_CORE_MODULE; conf.cmd_type = NGX_MAIN_CONF; #if 0 log->log_level = NGX_LOG_DEBUG_ALL; #endif //2.4从命令行和配置文件里把全部配置更新到cycle的conf_ctx中:首先调用ngx_conf_param把命令行中的指令(-g directives)转换为配置结构并把指针增加到cycle.conf_ctx中;接着调用ngx_conf_parse(..,filename)把配置文件里的指令转换为配置结构并把指针增加到cycle.conf_ctx中。 if (ngx_conf_param(&conf) != NGX_CONF_OK) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_test_config && !ngx_quiet_mode) { ngx_log_stderr(0, "the configuration file %s syntax is ok", cycle->conf_file.data); } //2.5调用全部核心模块的init函数初始化全部核心模块的配置结构体 for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; } module = ngx_modules[i]->ctx; if (module->init_conf) {//调用模块的init_conf初始化全部核心模块的配置结构体 if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) == NGX_CONF_ERROR) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } } } if (ngx_process == NGX_PROCESS_SIGNALLER) { return cycle; } //2.6获得核心模块ngx_core_dodule的配置结构,然后调用ngx_create_pidfile创建pid文件 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_test_config) { if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } } else if (!ngx_is_init_cycle(old_cycle)) { /* * we do not create the pid file in the first ngx_init_cycle() call * because we need to write the demonized process pid */ old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx, ngx_core_module); if (ccf->pid.len != old_ccf->pid.len || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0) { /* new pid file name */ if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } ngx_delete_pidfile(old_cycle); } } if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) { goto failed; } if (ngx_create_paths(cycle, ccf->user) != NGX_OK) { goto failed; } if (ngx_log_open_default(cycle) != NGX_OK) { goto failed; } /* open the new files */ part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].name.len == 0) { continue; } file[i].fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS); ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0, "log: %p %d \"%s\"", &file[i], file[i].fd, file[i].name.data); if (file[i].fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, ngx_open_file_n " \"%s\" failed", file[i].name.data); goto failed; } #if !(NGX_WIN32) if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fcntl(FD_CLOEXEC) \"%s\" failed", file[i].name.data); goto failed; } #endif } cycle->log = &cycle->new_log; pool->log = &cycle->new_log; /* create shared memory */ part = &cycle->shared_memory.part; shm_zone = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (shm_zone[i].shm.size == 0) { ngx_log_error(NGX_LOG_EMERG, log, 0, "zero size shared memory zone \"%V\"", &shm_zone[i].shm.name); goto failed; } shm_zone[i].shm.log = cycle->log; opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (n = 0; /* void */ ; n++) { if (n >= opart->nelts) { if (opart->next == NULL) { break; } opart = opart->next; oshm_zone = opart->elts; n = 0; } if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { continue; } if (ngx_strncmp(shm_zone[i].shm.name.data, oshm_zone[n].shm.name.data, shm_zone[i].shm.name.len) != 0) { continue; } if (shm_zone[i].tag == oshm_zone[n].tag && shm_zone[i].shm.size == oshm_zone[n].shm.size && !shm_zone[i].noreuse) { shm_zone[i].shm.addr = oshm_zone[n].shm.addr; #if (NGX_WIN32) shm_zone[i].shm.handle = oshm_zone[n].shm.handle; #endif if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data) != NGX_OK) { goto failed; } goto shm_zone_found; } ngx_shm_free(&oshm_zone[n].shm); break; } if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) { goto failed; } if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) { goto failed; } if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) { goto failed; } shm_zone_found: continue; } /* handle the listening sockets */ //2.8打开新文件,在第2步的时候提到cycle->open_files这个链表是空的。仅仅是给它预先分配了空间,并没有数据。这里之所以可能会有文件被打开,预计是前面读配置文件的时候,调用各个钩子的过程中,填充了这个链表,把ngx_open_file_t结构变量填充进来(结构体中包括要打开文件的路径信息),接着改动一下cycle的成员:cycle->log = &cycle->new_log;pool->log = &cycle->new_log; //2.9创建共享内存,和open_files类似,在第2步的时候cycle->share_memory也初始化为一个空的链表。也是预分配了空间,假设此时链表中已经被填充了ngx_shm_zone_t结构变量(当中包括须要共享内存的尺寸和标识等信息)。那么这里就会分配共享内存,而且调用合适的初始化钩子初始化分配的共享内存,每块共享内存都会有name标识。这里也会做一些排重,已经分配的就不会再去分配。从对open_files和share_memory的处理过程能够看出,nginx在资源管理上是集中分配的,请求资源的时候分配说明性的结构变量,然后在恰当的时机才去真正分配资源。 //2.10处理listening sockets,cycle->listening是ngx_listening_t结构的数组。把cycle->listening于old_cycle->listening进行比較。设置cycle->listening的一些状态信息。接着调用ngx_open_listening_sockets(cycle)启动cycle->listening中的全部监听socket,循环调用socket,bind,listen完毕服务端监听socket的启动。接着调用ngx_configure_listening_sockets(cycle)配置监听socket。会依据ngx_listening_t中的状态信息设置socket的读写缓存和TCP_DEFER_ACCEPT。 if (old_cycle->listening.nelts) { ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { ls[i].remain = 0; } nls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { for (i = 0; i < old_cycle->listening.nelts; i++) { if (ls[i].ignore) {//标识位为1表示跳过设置ngx_lisenting_t中的套接字。 continue; //为0表示正常初始化套接字 } if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, ls[i].sockaddr, ls[i].socklen, 1) == NGX_OK) { nls[n].fd = ls[i].fd; nls[n].previous = &ls[i]; ls[i].remain = 1;//不关闭已经打开的套接字 if (ls[i].backlog != nls[n].backlog) { nls[n].listen = 1;//套接字已监听 } #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) /* * FreeBSD, except the most recent versions, * could not remove accept filter */ nls[n].deferred_accept = ls[i].deferred_accept; if (ls[i].accept_filter && nls[n].accept_filter) { if (ngx_strcmp(ls[i].accept_filter, nls[n].accept_filter) != 0) { nls[n].delete_deferred = 1; nls[n].add_deferred = 1; } } else if (ls[i].accept_filter) { nls[n].delete_deferred = 1; } else if (nls[n].accept_filter) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[i].deferred_accept && !nls[n].deferred_accept) { nls[n].delete_deferred = 1; } else if (ls[i].deferred_accept != nls[n].deferred_accept) { nls[n].add_deferred = 1; } #endif break; } } if (nls[n].fd == (ngx_socket_t) -1) { nls[n].open = 1; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) if (nls[n].accept_filter) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (nls[n].deferred_accept) { nls[n].add_deferred = 1; } #endif } } } else { ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].open = 1; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) if (ls[i].accept_filter) { ls[i].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[i].deferred_accept) { ls[i].add_deferred = 1; } #endif } } //在ngx_open_listening_sockets函数的代码中可以看到bind、 //listen等套接字函数的调用。最终创建完的监听套接字就在 //cycle结构体的listening域里 主程序中完成socket的基础设置,完成监听操作。 if (ngx_open_listening_sockets(cycle) != NGX_OK) { goto failed; } if (!ngx_test_config) { ngx_configure_listening_sockets(cycle); } /* commit the new cycle configuration */ if (!ngx_use_stderr) { (void) ngx_log_redirect_stderr(cycle); } pool->log = cycle->log; for (i = 0; ngx_modules[i]; i++) {// 调用全部模块的init_module if (ngx_modules[i]->init_module) { if (ngx_modules[i]->init_module(cycle) != NGX_OK) { /* fatal */ exit(1); } } } /* close and delete stuff that lefts from an old cycle */ /* free the unnecessary shared memory */ opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (i = 0; /* void */ ; i++) { if (i >= opart->nelts) { if (opart->next == NULL) { goto old_shm_zone_done; } opart = opart->next; oshm_zone = opart->elts; i = 0; } part = &cycle->shared_memory.part; shm_zone = part->elts; for (n = 0; /* void */ ; n++) { if (n >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; n = 0; } if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len && ngx_strncmp(oshm_zone[i].shm.name.data, shm_zone[n].shm.name.data, oshm_zone[i].shm.name.len) == 0) { goto live_shm_zone; } } ngx_shm_free(&oshm_zone[i].shm); live_shm_zone: continue; } old_shm_zone_done: /* close the unnecessary listening sockets */ ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) { continue; } if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " listening socket on %V failed", &ls[i].addr_text); } #if (NGX_HAVE_UNIX_DOMAIN) if (ls[i].sockaddr->sa_family == AF_UNIX) { u_char *name; name = ls[i].addr_text.data + sizeof("unix:") - 1; ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "deleting socket %s", name); if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_delete_file_n " %s failed", name); } } #endif } /* close the unnecessary open files */ part = &old_cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { continue; } if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, ngx_close_file_n " \"%s\" failed", file[i].name.data); } } ngx_destroy_pool(conf.temp_pool); if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { /* * perl_destruct() frees environ, if it is not the same as it was at * perl_construct() time, therefore we save the previous cycle * environment before ngx_conf_parse() where it will be changed. */ env = environ; environ = senv; ngx_destroy_pool(old_cycle->pool); cycle->old_cycle = NULL; environ = env; return cycle; } if (ngx_temp_pool == NULL) { ngx_temp_pool = ngx_create_pool(128, cycle->log); if (ngx_temp_pool == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "could not create ngx_temp_pool"); exit(1); } n = 10; ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool, n * sizeof(ngx_cycle_t *)); if (ngx_old_cycles.elts == NULL) { exit(1); } ngx_old_cycles.nelts = 0; ngx_old_cycles.size = sizeof(ngx_cycle_t *); ngx_old_cycles.nalloc = n; ngx_old_cycles.pool = ngx_temp_pool; ngx_cleaner_event.handler = ngx_clean_old_cycles; ngx_cleaner_event.log = cycle->log; ngx_cleaner_event.data = &dumb; dumb.fd = (ngx_socket_t) -1; } ngx_temp_pool->log = cycle->log; old = ngx_array_push(&ngx_old_cycles); if (old == NULL) { exit(1); } *old = old_cycle; if (!ngx_cleaner_event.timer_set) { ngx_add_timer(&ngx_cleaner_event, 30000); ngx_cleaner_event.timer_set = 1; } return cycle; failed: if (!ngx_is_init_cycle(old_cycle)) { old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx, ngx_core_module); if (old_ccf->environment) { environ = old_ccf->environment; } } /* rollback the new cycle configuration */ part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { continue; } if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, ngx_close_file_n " \"%s\" failed", file[i].name.data); } } if (ngx_test_config) { ngx_destroy_cycle_pools(&conf); return NULL; } ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { if (ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) { continue; } if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } } ngx_destroy_cycle_pools(&conf); return NULL; }
static ngx_int_t ngx_rtmp_init_event_handlers(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf) { ngx_hash_init_t calls_hash; ngx_rtmp_handler_pt *eh; ngx_rtmp_amf_handler_t *h; ngx_hash_key_t *ha; size_t n, m; static size_t pm_events[] = { NGX_RTMP_MSG_CHUNK_SIZE, NGX_RTMP_MSG_ABORT, NGX_RTMP_MSG_ACK, NGX_RTMP_MSG_ACK_SIZE, NGX_RTMP_MSG_BANDWIDTH }; static size_t amf_events[] = { NGX_RTMP_MSG_AMF_CMD, NGX_RTMP_MSG_AMF_META, NGX_RTMP_MSG_AMF_SHARED, NGX_RTMP_MSG_AMF3_CMD, NGX_RTMP_MSG_AMF3_META, NGX_RTMP_MSG_AMF3_SHARED }; /* init standard protocol events */ for(n = 0; n < sizeof(pm_events) / sizeof(pm_events[0]); ++n) { eh = ngx_array_push(&cmcf->events[pm_events[n]]); *eh = ngx_rtmp_protocol_message_handler; } /* init amf events */ for(n = 0; n < sizeof(amf_events) / sizeof(amf_events[0]); ++n) { eh = ngx_array_push(&cmcf->events[amf_events[n]]); *eh = ngx_rtmp_amf_message_handler; } /* init user protocol events */ eh = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_USER]); *eh = ngx_rtmp_user_message_handler; /* aggregate to audio/video map */ eh = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AGGREGATE]); *eh = ngx_rtmp_aggregate_message_handler; /* init amf callbacks */ ngx_array_init(&cmcf->amf_arrays, cf->pool, 1, sizeof(ngx_hash_key_t)); h = cmcf->amf.elts; for(n = 0; n < cmcf->amf.nelts; ++n, ++h) { ha = cmcf->amf_arrays.elts; for(m = 0; m < cmcf->amf_arrays.nelts; ++m, ++ha) { if (h->name.len == ha->key.len && !ngx_strncmp(h->name.data, ha->key.data, ha->key.len)) { break; } } if (m == cmcf->amf_arrays.nelts) { ha = ngx_array_push(&cmcf->amf_arrays); ha->key = h->name; ha->key_hash = ngx_hash_key_lc(ha->key.data, ha->key.len); ha->value = ngx_array_create(cf->pool, 1, sizeof(ngx_rtmp_handler_pt)); if (ha->value == NULL) { return NGX_ERROR; } } eh = ngx_array_push((ngx_array_t*)ha->value); *eh = h->handler; } calls_hash.hash = &cmcf->amf_hash; calls_hash.key = ngx_hash_key_lc; calls_hash.max_size = 512; calls_hash.bucket_size = ngx_cacheline_size; calls_hash.name = "amf_hash"; calls_hash.pool = cf->pool; calls_hash.temp_pool = NULL; if (ngx_hash_init(&calls_hash, cmcf->amf_arrays.elts, cmcf->amf_arrays.nelts) != NGX_OK) { return NGX_ERROR; } return NGX_OK; }
static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r) { u_char *p, *host, *last, ch; size_t len, root; ngx_err_t err; ngx_int_t rc, depth; ngx_uint_t overwrite, slash, dir, flags; ngx_str_t path, uri, duri, args; ngx_tree_ctx_t tree; ngx_copy_file_t cf; ngx_file_info_t fi; ngx_table_elt_t *dest, *over; ngx_ext_rename_file_t ext; ngx_http_dav_copy_ctx_t copy; ngx_http_dav_loc_conf_t *dlcf; if (r->headers_in.content_length_n > 0) { return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } dest = r->headers_in.destination; if (dest == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent no \"Destination\" header"); return NGX_HTTP_BAD_REQUEST; } p = dest->value.data; /* there is always '\0' even after empty header value */ if (p[0] == '/') { last = p + dest->value.len; goto destination_done; } len = r->headers_in.server.len; if (len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent no \"Host\" header"); return NGX_HTTP_BAD_REQUEST; } #if (NGX_HTTP_SSL) if (r->connection->ssl) { if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1) != 0) { goto invalid_destination; } host = dest->value.data + sizeof("https://") - 1; } else #endif { if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1) != 0) { goto invalid_destination; } host = dest->value.data + sizeof("http://") - 1; } if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Destination\" URI \"%V\" is handled by " "different repository than the source URI", &dest->value); return NGX_HTTP_BAD_REQUEST; } last = dest->value.data + dest->value.len; for (p = host + len; p < last; p++) { if (*p == '/') { goto destination_done; } } invalid_destination: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Destination\" header: \"%V\"", &dest->value); return NGX_HTTP_BAD_REQUEST; destination_done: duri.len = last - p; duri.data = p; flags = 0; if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) { goto invalid_destination; } if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "both URI \"%V\" and \"Destination\" URI \"%V\" " "should be either collections or non-collections", &r->uri, &dest->value); return NGX_HTTP_CONFLICT; } depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { if (r->method == NGX_HTTP_COPY) { if (depth != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be 0 or infinity"); return NGX_HTTP_BAD_REQUEST; } } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be infinity"); return NGX_HTTP_BAD_REQUEST; } } over = r->headers_in.overwrite; if (over) { if (over->value.len == 1) { ch = over->value.data[0]; if (ch == 'T' || ch == 't') { overwrite = 1; goto overwrite_done; } if (ch == 'F' || ch == 'f') { overwrite = 0; goto overwrite_done; } } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Overwrite\" header: \"%V\"", &over->value); return NGX_HTTP_BAD_REQUEST; } overwrite = 1; overwrite_done: ngx_http_map_uri_to_path(r, &path, &root, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy from: \"%s\"", path.data); uri = r->uri; r->uri = duri; ngx_http_map_uri_to_path(r, ©.path, &root, 0); r->uri = uri; copy.path.len--; /* omit "\0" */ if (copy.path.data[copy.path.len - 1] == '/') { slash = 1; copy.path.len--; copy.path.data[copy.path.len] = '\0'; } else { slash = 0; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy to: \"%s\"", copy.path.data); if (ngx_link_info(copy.path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { return ngx_http_dav_error(r->connection->log, err, NGX_HTTP_NOT_FOUND, ngx_link_info_n, copy.path.data); } /* destination does not exist */ overwrite = 0; dir = 0; } else { /* destination exists */ if (ngx_is_dir(&fi) && !slash) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"%V\" could not be %Ved to collection \"%V\"", &r->uri, &r->method_name, &dest->value); return NGX_HTTP_CONFLICT; } if (!overwrite) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST, "\"%s\" could not be created", copy.path.data); return NGX_HTTP_PRECONDITION_FAILED; } dir = ngx_is_dir(&fi); } if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_link_info_n, path.data); } if (ngx_is_dir(&fi)) { if (r->uri.data[r->uri.len - 1] != '/') { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"%V\" is collection", &r->uri); return NGX_HTTP_BAD_REQUEST; } if (overwrite) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete: \"%s\"", copy.path.data); rc = ngx_http_dav_delete_path(r, ©.path, dir); if (rc != NGX_OK) { return rc; } } } if (ngx_is_dir(&fi)) { path.len -= 2; /* omit "/\0" */ if (r->method == NGX_HTTP_MOVE) { if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) { return NGX_HTTP_CREATED; } } if (ngx_create_dir(copy.path.data, ngx_file_access(&fi)) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_create_dir_n, copy.path.data); } copy.len = path.len; tree.init_handler = NULL; tree.file_handler = ngx_http_dav_copy_tree_file; tree.pre_tree_handler = ngx_http_dav_copy_dir; tree.post_tree_handler = ngx_http_dav_copy_dir_time; tree.spec_handler = ngx_http_dav_noop; tree.data = © tree.alloc = 0; tree.log = r->connection->log; if (ngx_walk_tree(&tree, &path) == NGX_OK) { if (r->method == NGX_HTTP_MOVE) { rc = ngx_http_dav_delete_path(r, &path, 1); if (rc != NGX_OK) { return rc; } } return NGX_HTTP_CREATED; } } else { if (r->method == NGX_HTTP_MOVE) { dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); ext.access = 0; ext.path_access = dlcf->access; ext.time = -1; ext.create_path = 1; ext.delete_file = 0; ext.log = r->connection->log; if (ngx_ext_rename_file(&path, ©.path, &ext) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } return NGX_HTTP_INTERNAL_SERVER_ERROR; } dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); cf.size = ngx_file_size(&fi); cf.buf_size = 0; cf.access = dlcf->access; cf.time = ngx_file_mtime(&fi); cf.log = r->connection->log; if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } } return NGX_HTTP_INTERNAL_SERVER_ERROR; }
static char * ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_limit_req_conf_t *lzcf = conf; ngx_int_t burst; ngx_str_t *value, s; ngx_uint_t i; if (lzcf->shm_zone) { return "is duplicate"; } value = cf->args->elts; burst = 0; for (i = 1; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { s.len = value[i].len - 5; s.data = value[i].data + 5; lzcf->shm_zone = ngx_shared_memory_add(cf, &s, 0, &ngx_http_limit_req_module); if (lzcf->shm_zone == NULL) { return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "burst=", 6) == 0) { burst = ngx_atoi(value[i].data + 6, value[i].len - 6); if (burst <= 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid burst rate \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) { lzcf->nodelay = 1; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (lzcf->shm_zone == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" must have \"zone\" parameter", &cmd->name); return NGX_CONF_ERROR; } if (lzcf->shm_zone->data == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unknown limit_req_zone \"%V\"", &lzcf->shm_zone->name); return NGX_CONF_ERROR; } lzcf->burst = burst * 1000; return NGX_CONF_OK; }
static char * ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_stream_core_srv_conf_t *cscf = conf; ngx_str_t *value; ngx_url_t u; ngx_uint_t i, backlog; ngx_stream_listen_t *ls, *als; ngx_stream_core_main_conf_t *cmcf; cscf->listen = 1; value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); u.url = value[1]; u.listen = 1; if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in \"%V\" of the \"listen\" directive", u.err, &u.url); } return NGX_CONF_ERROR; } cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); ls = ngx_array_push(&cmcf->listen); if (ls == NULL) { return NGX_CONF_ERROR; } ngx_memzero(ls, sizeof(ngx_stream_listen_t)); ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen); ls->socklen = u.socklen; ls->backlog = NGX_LISTEN_BACKLOG; ls->type = SOCK_STREAM; ls->wildcard = u.wildcard; ls->ctx = cf->ctx; #if (NGX_HAVE_INET6) ls->ipv6only = 1; #endif backlog = 0; for (i = 2; i < cf->args->nelts; i++) { #if !(NGX_WIN32) if (ngx_strcmp(value[i].data, "udp") == 0) { ls->type = SOCK_DGRAM; continue; } #endif if (ngx_strcmp(value[i].data, "bind") == 0) { ls->bind = 1; continue; } if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) { ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8); ls->bind = 1; if (ls->backlog == NGX_ERROR || ls->backlog == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid backlog \"%V\"", &value[i]); return NGX_CONF_ERROR; } backlog = 1; continue; } if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) size_t len; u_char buf[NGX_SOCKADDR_STRLEN]; if (ls->sockaddr.sockaddr.sa_family == AF_INET6) { if (ngx_strcmp(&value[i].data[10], "n") == 0) { ls->ipv6only = 1; } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { ls->ipv6only = 0; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid ipv6only flags \"%s\"", &value[i].data[9]); return NGX_CONF_ERROR; } ls->bind = 1; } else { len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf, NGX_SOCKADDR_STRLEN, 1); ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "ipv6only is not supported " "on addr \"%*s\", ignored", len, buf); } continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "bind ipv6only is not supported " "on this platform"); return NGX_CONF_ERROR; #endif } if (ngx_strcmp(value[i].data, "reuseport") == 0) { #if (NGX_HAVE_REUSEPORT) ls->reuseport = 1; ls->bind = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "reuseport is not supported " "on this platform, ignored"); #endif continue; } if (ngx_strcmp(value[i].data, "ssl") == 0) { #if (NGX_STREAM_SSL) ls->ssl = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"ssl\" parameter requires " "ngx_stream_ssl_module"); return NGX_CONF_ERROR; #endif } if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[i].data[13], "on") == 0) { ls->so_keepalive = 1; } else if (ngx_strcmp(&value[i].data[13], "off") == 0) { ls->so_keepalive = 2; } else { #if (NGX_HAVE_KEEPALIVE_TUNABLE) u_char *p, *end; ngx_str_t s; end = value[i].data + value[i].len; s.data = value[i].data + 13; p = ngx_strlchr(s.data, end, ':'); if (p == NULL) { p = end; } if (p > s.data) { s.len = p - s.data; ls->tcp_keepidle = ngx_parse_time(&s, 1); if (ls->tcp_keepidle == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } s.data = (p < end) ? (p + 1) : end; p = ngx_strlchr(s.data, end, ':'); if (p == NULL) { p = end; } if (p > s.data) { s.len = p - s.data; ls->tcp_keepintvl = ngx_parse_time(&s, 1); if (ls->tcp_keepintvl == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } s.data = (p < end) ? (p + 1) : end; if (s.data < end) { s.len = end - s.data; ls->tcp_keepcnt = ngx_atoi(s.data, s.len); if (ls->tcp_keepcnt == NGX_ERROR) { goto invalid_so_keepalive; } } if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0 && ls->tcp_keepcnt == 0) { goto invalid_so_keepalive; } ls->so_keepalive = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"so_keepalive\" parameter accepts " "only \"on\" or \"off\" on this platform"); return NGX_CONF_ERROR; #endif } ls->bind = 1; continue; #if (NGX_HAVE_KEEPALIVE_TUNABLE) invalid_so_keepalive: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid so_keepalive value: \"%s\"", &value[i].data[13]); return NGX_CONF_ERROR; #endif } if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { ls->proxy_protocol = 1; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[i]); return NGX_CONF_ERROR; } if (ls->type == SOCK_DGRAM) { if (backlog) { return "\"backlog\" parameter is incompatible with \"udp\""; } #if (NGX_STREAM_SSL) if (ls->ssl) { return "\"ssl\" parameter is incompatible with \"udp\""; } #endif if (ls->so_keepalive) { return "\"so_keepalive\" parameter is incompatible with \"udp\""; } if (ls->proxy_protocol) { return "\"proxy_protocol\" parameter is incompatible with \"udp\""; } } als = cmcf->listen.elts; for (i = 0; i < cmcf->listen.nelts - 1; i++) { if (ls->type != als[i].type) { continue; } if (ngx_cmp_sockaddr(&als[i].sockaddr.sockaddr, als[i].socklen, &ls->sockaddr.sockaddr, ls->socklen, 1) != NGX_OK) { continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate \"%V\" address and port pair", &u.url); return NGX_CONF_ERROR; } return NGX_CONF_OK; }
ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t allow_underscores) { u_char c, ch, *p; ngx_uint_t hash, i; enum { sw_start = 0, sw_name, sw_space_before_value, sw_value, sw_space_after_value, sw_ignore_line, sw_almost_done, sw_header_almost_done } state; /* the last '\0' is not needed because string is zero terminated */ static u_char lowcase[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; state = r->state; hash = r->header_hash; i = r->lowcase_index; for (p = b->pos; p < b->last; p++) { ch = *p; switch (state) { /* first char */ case sw_start: r->header_name_start = p; r->invalid_header = 0; switch (ch) { case CR: r->header_end = p; state = sw_header_almost_done; break; case LF: r->header_end = p; goto header_done; default: state = sw_name; c = lowcase[ch]; if (c) { hash = ngx_hash(0, c); r->lowcase_header[0] = c; i = 1; break; } r->invalid_header = 1; break; } break; /* header name */ case sw_name: c = lowcase[ch]; if (c) { hash = ngx_hash(hash, c); r->lowcase_header[i++] = c; i &= (NGX_HTTP_LC_HEADER_LEN - 1); break; } if (ch == '_') { if (allow_underscores) { hash = ngx_hash(hash, ch); r->lowcase_header[i++] = ch; i &= (NGX_HTTP_LC_HEADER_LEN - 1); } else { r->invalid_header = 1; } break; } if (ch == ':') { r->header_name_end = p; state = sw_space_before_value; break; } if (ch == CR) { r->header_name_end = p; r->header_start = p; r->header_end = p; state = sw_almost_done; break; } if (ch == LF) { r->header_name_end = p; r->header_start = p; r->header_end = p; goto done; } /* IIS may send the duplicate "HTTP/1.1 ..." lines */ if (ch == '/' && r->upstream && p - r->header_name_start == 4 && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0) { state = sw_ignore_line; break; } r->invalid_header = 1; break; /* space* before header value */ case sw_space_before_value: switch (ch) { case ' ': break; case CR: r->header_start = p; r->header_end = p; state = sw_almost_done; break; case LF: r->header_start = p; r->header_end = p; goto done; default: r->header_start = p; state = sw_value; break; } break; /* header value */ case sw_value: switch (ch) { case ' ': r->header_end = p; state = sw_space_after_value; break; case CR: r->header_end = p; state = sw_almost_done; break; case LF: r->header_end = p; goto done; } break; /* space* before end of header line */ case sw_space_after_value: switch (ch) { case ' ': break; case CR: state = sw_almost_done; break; case LF: goto done; default: state = sw_value; break; } break; /* ignore header line */ case sw_ignore_line: switch (ch) { case LF: state = sw_start; break; default: break; } break; /* end of header line */ case sw_almost_done: switch (ch) { case LF: goto done; case CR: break; default: return NGX_HTTP_PARSE_INVALID_HEADER; } break; /* end of header */ case sw_header_almost_done: switch (ch) { case LF: goto header_done; default: return NGX_HTTP_PARSE_INVALID_HEADER; } } } b->pos = p; r->state = state; r->header_hash = hash; r->lowcase_index = i; return NGX_AGAIN; done: b->pos = p + 1; r->state = sw_start; r->header_hash = hash; r->lowcase_index = i; return NGX_OK; header_done: b->pos = p + 1; r->state = sw_start; return NGX_HTTP_PARSE_HEADER_DONE; }
/* Syntax: thread_pool name threads=number [max_queue=number]; Default: thread_pool default threads=32 max_queue=65536; threads参数为该pool中线程个数,max_queue表示等待被线程调度的任务数 */ static char * ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_str_t *value; ngx_uint_t i; ngx_thread_pool_t *tp; value = cf->args->elts; tp = ngx_thread_pool_add(cf, &value[1]); if (tp == NULL) { return NGX_CONF_ERROR; } if (tp->threads) { //说明配置了同样的thread_pool name threads xx,重复,如果threads数不同,还是可以满足条件的,后配置的会覆盖前面配置的 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate thread pool \"%V\"", &tp->name); return NGX_CONF_ERROR; } tp->max_queue = 65536; for (i = 2; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "threads=", 8) == 0) { tp->threads = ngx_atoi(value[i].data + 8, value[i].len - 8); if (tp->threads == (ngx_uint_t) NGX_ERROR || tp->threads == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid threads value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) { tp->max_queue = ngx_atoi(value[i].data + 10, value[i].len - 10); if (tp->max_queue == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid max_queue value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } } if (tp->threads == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" must have \"threads\" parameter", &cmd->name); return NGX_CONF_ERROR; } return NGX_CONF_OK; }
static ngx_int_t ngx_http_mcset_cache_parse_header( ngx_http_request_t *r, ngx_str_t* v ) { ngx_http_upstream_t* u; u_char* b; u_char* e; ngx_mcset_module_ctx_t* ctx; u = r->upstream; b = u->buffer.pos; e = u->buffer.last; ctx = ngx_http_get_module_ctx( r, ngx_http_mcset_module ); if ( ctx->state == MCSET_STATE_MC_SET ) { if ( e - b != (ssize_t) MC_STR_STORED.len || ngx_strncmp( b, MC_STR_STORED.data, MC_STR_STORED.len ) != 0 ) return NGX_ERROR; return NGX_OK; } if ( e - b < (ssize_t) MC_STR_END.len ) return NGX_AGAIN; if ( ngx_strncmp( e - MC_STR_END.len, MC_STR_END.data, MC_STR_END.len ) != 0 ) return NGX_AGAIN; e -= MC_STR_END.len; if ( e == b ) { v->len = 0; u->buffer.last = u->buffer.pos; return NGX_OK; // not found } e -= 2; // CRLF if ( e - b < (ssize_t) MC_STR_VALUE.len || ngx_strncmp( b, MC_STR_VALUE.data, MC_STR_VALUE.len ) != 0 ) return NGX_ERROR; b += MC_STR_VALUE.len; if ( e - b < (ssize_t) ctx->cache_id.len || ngx_strncmp( b, ctx->cache_id.data, ctx->cache_id.len ) != 0 ) return NGX_ERROR; b += ctx->cache_id.len; uint8_t s = 0; for( ; b <= e && s != 4; b++ ) { switch( s ) { case 0: // space before flags if ( *b != ' ' ) return NGX_ERROR; s = 1; break; case 1: // flags if ( *b != ' ' ) continue; s = 2; break; case 2: // len if ( *b != '\r' ) continue; s = 3; break; case 3: if ( *b != '\n' ) return NGX_ERROR; s = 4; break; } } v->data = b; v->len = e - b; u->buffer.pos = b; u->buffer.last = e; return NGX_OK; }
ngx_http_variable_value_t * ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key, ngx_uint_t nowarn) { ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len); if (v) { if (v->flags & NGX_HTTP_VAR_INDEXED) { return ngx_http_get_indexed_variable(r, v->index); } else { vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv && v->get_handler(r, vv, v->data) == NGX_OK) { return vv; } return NULL; } } vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return NULL; } if (ngx_strncmp(name->data, "http_", 5) == 0) { if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "sent_http_", 10) == 0) { if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "upstream_http_", 10) == 0) { if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "cookie_", 7) == 0) { if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } if (ngx_strncmp(name->data, "arg_", 4) == 0) { if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) { return vv; } return NULL; } vv->not_found = 1; if (nowarn == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unknown \"%V\" variable", name); } return vv; }
ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf) { ngx_uint_t i, n; ngx_hash_key_t *key; ngx_hash_init_t hash; ngx_http_variable_t *v, *av; ngx_http_core_main_conf_t *cmcf; /* set the handlers for the indexed http variables */ cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); v = cmcf->variables.elts; key = cmcf->variables_keys->keys.elts; for (i = 0; i < cmcf->variables.nelts; i++) { for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) { av = key[n].value; if (av->get_handler && v[i].name.len == key[n].key.len && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len) == 0) { v[i].get_handler = av->get_handler; v[i].data = av->data; av->flags |= NGX_HTTP_VAR_INDEXED; v[i].flags = av->flags; av->index = i; goto next; } } if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) { v[i].get_handler = ngx_http_variable_unknown_header_in; v[i].data = (uintptr_t) &v[i].name; continue; } if (ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) { v[i].get_handler = ngx_http_variable_unknown_header_out; v[i].data = (uintptr_t) &v[i].name; continue; } if (ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) { v[i].get_handler = ngx_http_upstream_header_variable; v[i].data = (uintptr_t) &v[i].name; v[i].flags = NGX_HTTP_VAR_NOCACHEABLE; continue; } if (ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) { v[i].get_handler = ngx_http_variable_cookie; v[i].data = (uintptr_t) &v[i].name; continue; } if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) { v[i].get_handler = ngx_http_variable_argument; v[i].data = (uintptr_t) &v[i].name; continue; } ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "unknown \"%V\" variable", &v[i].name); return NGX_ERROR; next: continue; } for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) { av = key[n].value; if (av->flags & NGX_HTTP_VAR_NOHASH) { key[n].key.data = NULL; } } hash.hash = &cmcf->variables_hash; hash.key = ngx_hash_key; hash.max_size = cmcf->variables_hash_max_size; hash.bucket_size = cmcf->variables_hash_bucket_size; hash.name = "variables_hash"; hash.pool = cf->pool; hash.temp_pool = NULL; if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts, cmcf->variables_keys->keys.nelts) != NGX_OK) { return NGX_ERROR; } cmcf->variables_keys = NULL; return NGX_OK; }
static ngx_int_t ngx_http_google_request_parse_scholar(ngx_http_request_t * r, ngx_http_google_ctx_t * ctx) { if (ngx_http_google_request_parse_cookie_conf(r, ctx)) return NGX_ERROR; if (ctx->uri->len == 12 && ctx->args) { u_char * refer = ctx->uri->data + 9; if (!ngx_strncmp(refer, "bib", 3) || !ngx_strncmp(refer, "enw", 3) || !ngx_strncmp(refer, "ris", 3) || !ngx_strncmp(refer, "rfw", 3)) { ngx_uint_t i; ngx_keyval_t * kv, * hd = ctx->args->elts; for (i = 0; i < ctx->args->nelts; i++) { kv = hd + i; if (!kv->key.len || *kv->key.data != 'q') continue; u_char * last = kv->value.data + kv->value.len; u_char * find = ngx_strlcasestrn(kv->value.data, last, ctx->host->data, ctx->host->len - 1); if (!find) break; kv->value.len = find - kv->value.data; ngx_str_t nval; nval.len = kv->value.len + sizeof("scholar.google.com"); nval.data = ngx_pcalloc(r->pool, nval.len); if (!nval.data) return NGX_ERROR; ngx_snprintf(nval.data, nval.len, "%Vscholar.google.com/", &kv->value); kv->value = nval; break; } // end of for args } // end of if refer } else { if (!ngx_strncasecmp(ctx->uri->data, (u_char *)"/schhp", 6) || !ctx->args->nelts) { ngx_str_set(ctx->uri, "/"); } if (!ngx_strncasecmp(ctx->uri->data, (u_char *)"/scholar", 8)) { ngx_uint_t i, strip = 1; ngx_keyval_t * kv, * hd = ctx->args->elts; for (i = 0; i < ctx->args->nelts; i++) { kv = hd + i; if (!kv->key.len) continue; if (kv->key.len == 1 && *kv->key.data == 'q') { strip = 0; break; } if (kv->key.len == 5 && !ngx_strncasecmp(kv->key.data, (u_char *)"cites", 5)) { strip = 0; break; } if (kv->key.len == 7 && !ngx_strncasecmp(kv->key.data, (u_char *)"cluster", 7)) { strip = 0; break; } } if (ctx->uri->len > 8) switch (ctx->uri->data[8]) { case '?': case '/': break; default: strip = 0; break; } if (strip) { ctx->uri->data += 8; ctx->uri->len -= 8; } } } if (!ctx->ncr && ctx->uri->len == 1) { ngx_str_set(ctx->uri, "/ncr"); } ngx_str_set(ctx->pass, "scholar.google.com"); return NGX_OK; }
static ngx_int_t ngx_http_echo_parse_method_name(ngx_str_t **method_name_ptr) { const ngx_str_t* method_name = *method_name_ptr; switch (method_name->len) { case 3: if (ngx_str3cmp(method_name->data, 'G', 'E', 'T')) { *method_name_ptr = &ngx_http_echo_get_method; return NGX_HTTP_GET; break; } if (ngx_str3cmp(method_name->data, 'P', 'U', 'T')) { *method_name_ptr = &ngx_http_echo_put_method; return NGX_HTTP_PUT; break; } return NGX_HTTP_UNKNOWN; break; case 4: if (ngx_str4cmp(method_name->data, 'P', 'O', 'S', 'T')) { *method_name_ptr = &ngx_http_echo_post_method; return NGX_HTTP_POST; break; } if (ngx_str4cmp(method_name->data, 'H', 'E', 'A', 'D')) { *method_name_ptr = &ngx_http_echo_head_method; return NGX_HTTP_HEAD; break; } if (ngx_str4cmp(method_name->data, 'C', 'O', 'P', 'Y')) { *method_name_ptr = &ngx_http_echo_copy_method; return NGX_HTTP_COPY; break; } if (ngx_str4cmp(method_name->data, 'M', 'O', 'V', 'E')) { *method_name_ptr = &ngx_http_echo_move_method; return NGX_HTTP_MOVE; break; } if (ngx_str4cmp(method_name->data, 'L', 'O', 'C', 'K')) { *method_name_ptr = &ngx_http_echo_lock_method; return NGX_HTTP_LOCK; break; } return NGX_HTTP_UNKNOWN; break; case 5: if (ngx_strncmp("MKCOL", method_name->data, method_name->len) == 0) { *method_name_ptr = &ngx_http_echo_mkcol_method; return NGX_HTTP_MKCOL; break; } if (ngx_strncmp("TRACE", method_name->data, method_name->len) == 0) { *method_name_ptr = &ngx_http_echo_trace_method; return NGX_HTTP_TRACE; break; } return NGX_HTTP_UNKNOWN; break; case 6: if (ngx_str6cmp(method_name->data, 'D', 'E', 'L', 'E', 'T', 'E')) { *method_name_ptr = &ngx_http_echo_delete_method; return NGX_HTTP_DELETE; break; } if (ngx_str6cmp(method_name->data, 'U', 'N', 'L', 'O', 'C', 'K')) { *method_name_ptr = &ngx_http_echo_unlock_method; return NGX_HTTP_UNLOCK; break; } return NGX_HTTP_UNKNOWN; break; case 7: if (ngx_strncmp("OPTIONS", method_name->data, method_name->len) == 0) { *method_name_ptr = &ngx_http_echo_options_method; return NGX_HTTP_OPTIONS; break; } return NGX_HTTP_UNKNOWN; break; case 8: if (ngx_strncmp("PROPFIND", method_name->data, method_name->len) == 0) { *method_name_ptr = &ngx_http_echo_propfind_method; return NGX_HTTP_PROPFIND; break; } return NGX_HTTP_UNKNOWN; break; case 9: if (ngx_strncmp("PROPPATCH", method_name->data, method_name->len) == 0) { *method_name_ptr = &ngx_http_echo_proppatch_method; return NGX_HTTP_PROPPATCH; break; } return NGX_HTTP_UNKNOWN; break; default: return NGX_HTTP_UNKNOWN; break; } return NGX_HTTP_UNKNOWN; }
static char * ngx_tcp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { size_t len, off; in_port_t port; ngx_str_t *value; ngx_url_t u; ngx_uint_t i; struct sockaddr *sa; ngx_tcp_listen_t *ls; struct sockaddr_in *sin; ngx_tcp_core_main_conf_t *cmcf; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); u.url = value[1]; u.listen = 1; if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in \"%V\" of the \"listen\" directive", u.err, &u.url); } return NGX_CONF_ERROR; } cmcf = ngx_tcp_conf_get_module_main_conf(cf, ngx_tcp_core_module); ls = cmcf->listen.elts; for (i = 0; i < cmcf->listen.nelts; i++) { sa = (struct sockaddr *) ls[i].sockaddr; if (sa->sa_family != u.family) { continue; } switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: off = offsetof(struct sockaddr_in6, sin6_addr); len = 16; sin6 = (struct sockaddr_in6 *) sa; port = sin6->sin6_port; break; #endif default: /* AF_INET */ off = offsetof(struct sockaddr_in, sin_addr); len = 4; sin = (struct sockaddr_in *) sa; port = sin->sin_port; break; } if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) { continue; } if (port != u.port) { continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate \"%V\" address and port pair", &u.url); return NGX_CONF_ERROR; } ls = ngx_array_push(&cmcf->listen); if (ls == NULL) { return NGX_CONF_ERROR; } ngx_memzero(ls, sizeof(ngx_tcp_listen_t)); ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen); ls->socklen = u.socklen; ls->wildcard = u.wildcard; ls->ctx = cf->ctx; ls->conf = conf; for (i = 2; i < cf->args->nelts; i++) { if (ngx_strcmp(value[i].data, "bind") == 0) { ls->bind = 1; continue; } if (ngx_strcmp(value[i].data, "default") == 0) { ls->default_port = 1; continue; } if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) struct sockaddr *sa; u_char buf[NGX_SOCKADDR_STRLEN]; sa = (struct sockaddr *) ls->sockaddr; if (sa->sa_family == AF_INET6) { if (ngx_strcmp(&value[i].data[10], "n") == 0) { ls->ipv6only = 1; } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { ls->ipv6only = 2; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid ipv6only flags \"%s\"", &value[i].data[9]); return NGX_CONF_ERROR; } ls->bind = 1; } else { #if defined(nginx_version) && nginx_version >= 1005003 len = ngx_sock_ntop(sa, ls->socklen, buf, NGX_SOCKADDR_STRLEN, 1); #else len = ngx_sock_ntop(sa, buf, NGX_SOCKADDR_STRLEN, 1); #endif ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "ipv6only is not supported " "on addr \"%*s\", ignored", len, buf); } continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "bind ipv6only is not supported " "on this platform"); return NGX_CONF_ERROR; #endif } if (ngx_strcmp(value[i].data, "ssl") == 0) { #if (NGX_TCP_SSL) ls->ssl = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"ssl\" parameter requires " "ngx_tcp_ssl_module"); return NGX_CONF_ERROR; #endif } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[i]); return NGX_CONF_ERROR; } return NGX_CONF_OK; }
static char * ngx_rtmp_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s) { size_t i, len; u_char *data, *d, c; ngx_uint_t bracket; ngx_str_t *value, var; ngx_rtmp_log_op_t *op; ngx_rtmp_log_var_t *v; value = args->elts; for (; s < args->nelts; ++s) { i = 0; len = value[s].len; d = value[s].data; while (i < len) { op = ngx_array_push(ops); if (op == NULL) { return NGX_CONF_ERROR; } ngx_memzero(op, sizeof(*op)); data = &d[i]; if (d[i] == '$') { if (++i == len) { goto invalid; } if (d[i] == '{') { bracket = 1; if (++i == len) { goto invalid; } } else { bracket = 0; } var.data = &d[i]; for (var.len = 0; i < len; ++i, ++var.len) { c = d[i]; if (c == '}' && bracket) { ++i; bracket = 0; break; } if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '_')) { continue; } break; } if (bracket) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "missing closing bracket in \"%V\"", &var); return NGX_CONF_ERROR; } if (var.len == 0) { goto invalid; } for (v = ngx_rtmp_log_vars; v->name.len; ++v) { if (v->name.len == var.len && ngx_strncmp(v->name.data, var.data, var.len) == 0) { op->getlen = v->getlen; op->getdata = v->getdata; op->offset = v->offset; break; } } if (v->name.len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unknown variable \"%V\"", &var); return NGX_CONF_ERROR; } continue; } ++i; while (i < len && d[i] != '$') { ++i; } op->getlen = ngx_rtmp_log_var_default_getlen; op->getdata = ngx_rtmp_log_var_default_getdata; op->value.len = &d[i] - data; op->value.data = ngx_pnalloc(cf->pool, op->value.len); if (op->value.data == NULL) { return NGX_CONF_ERROR; } ngx_memcpy(op->value.data, data, op->value.len); } } return NGX_CONF_OK; invalid: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data); return NGX_CONF_ERROR; }
static char * ngx_tcp_log_set_access_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_tcp_core_srv_conf_t *cscf = conf; ngx_tcp_log_srv_conf_t *lscf = cscf->access_log; ssize_t size; ngx_str_t *value, name; ngx_tcp_log_t *log; #if (nginx_version) >= 1003010 || (nginx_version) >= 1002007 && (nginx_version) < 1003000 ngx_tcp_log_buf_t *buffer; #endif value = cf->args->elts; if (ngx_strcmp(value[1].data, "off") == 0) { lscf->off = 1; if (cf->args->nelts == 2) { return NGX_CONF_OK; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[2]); return NGX_CONF_ERROR; } if (lscf->logs == NULL) { lscf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_tcp_log_t)); if (lscf->logs == NULL) { return NGX_CONF_ERROR; } } log = ngx_array_push(lscf->logs); if (log == NULL) { return NGX_CONF_ERROR; } ngx_memzero(log, sizeof(ngx_tcp_log_t)); log->file = ngx_conf_open_file(cf->cycle, &value[1]); if (log->file == NULL) { return NGX_CONF_ERROR; } if (cf->args->nelts == 3) { if (ngx_strncmp(value[2].data, "buffer=", 7) != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[2]); return NGX_CONF_ERROR; } name.len = value[2].len - 7; name.data = value[2].data + 7; size = ngx_parse_size(&name); if (size == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[2]); return NGX_CONF_ERROR; } #if (nginx_version) >= 1003010 || (nginx_version) >= 1002007 && (nginx_version) < 1003000 if (log->file->data) { buffer = log->file->data; if (buffer->last - buffer->pos != size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "access_log \"%V\" already defined " "with different buffer size", &value[1]); return NGX_CONF_ERROR; } return NGX_CONF_OK; } buffer = ngx_pcalloc(cf->pool, sizeof(ngx_tcp_log_buf_t)); if (buffer == NULL) { return NGX_CONF_ERROR; } buffer->start = ngx_palloc(cf->pool, size); if (buffer->start == NULL) { return NGX_CONF_ERROR; } buffer->pos = buffer->start; buffer->last = buffer->start + size; log->file->data = buffer; #else if (log->file->buffer) { if (log->file->last - log->file->pos != size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "access_log \"%V\" already defined " "with different buffer size", &value[1]); return NGX_CONF_ERROR; } return NGX_CONF_OK; } log->file->buffer = ngx_palloc(cf->pool, size); if (log->file->buffer == NULL) { return NGX_CONF_ERROR; } log->file->pos = log->file->buffer; log->file->last = log->file->buffer + size; #endif } return NGX_CONF_OK; }
static char * ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { u_char *p; size_t size, len; ngx_str_t *value, name, s; ngx_int_t rate, scale; ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_http_limit_req_ctx_t *ctx; value = cf->args->elts; ctx = NULL; size = 0; rate = 1; scale = 1; name.len = 0; for (i = 1; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { name.data = value[i].data + 5; p = (u_char *) ngx_strchr(name.data, ':'); if (p) { name.len = p - name.data; p++; s.len = value[i].data + value[i].len - p; s.data = p; size = ngx_parse_size(&s); if (size > 8191) { continue; } } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid zone size \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (ngx_strncmp(value[i].data, "rate=", 5) == 0) { len = value[i].len; p = value[i].data + len - 3; if (ngx_strncmp(p, "r/s", 3) == 0) { scale = 1; len -= 3; } else if (ngx_strncmp(p, "r/m", 3) == 0) { scale = 60; len -= 3; } rate = ngx_atoi(value[i].data + 5, len - 5); if (rate <= NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid rate \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (value[i].data[0] == '$') { value[i].len--; value[i].data++; ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } ctx->index = ngx_http_get_variable_index(cf, &value[i]); if (ctx->index == NGX_ERROR) { return NGX_CONF_ERROR; } ctx->var = value[i]; continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (name.len == 0 || size == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" must have \"zone\" parameter", &cmd->name); return NGX_CONF_ERROR; } if (ctx == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no variable is defined for limit_req_zone \"%V\"", &cmd->name); return NGX_CONF_ERROR; } ctx->rate = rate * 1000 / scale; shm_zone = ngx_shared_memory_add(cf, &name, size, &ngx_http_limit_req_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } if (shm_zone->data) { ctx = shm_zone->data; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_req_zone \"%V\" is already bound to variable \"%V\"", &value[1], &ctx->var); return NGX_CONF_ERROR; } shm_zone->init = ngx_http_limit_req_init_zone; shm_zone->data = ctx; return NGX_CONF_OK; }
static char * ngx_http_tfs_poll_rcs(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_tfs_main_conf_t *tmcf = conf; ngx_msec_t interval; ngx_str_t *value, s; ngx_uint_t i; ngx_int_t rcs_kp_enable; value = cf->args->elts; for (i = 1; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "lock_file=", 10) == 0) { s.data = value[i].data + 10; s.len = value[i].len - 10; if (ngx_conf_full_name(cf->cycle, &s, 0) != NGX_OK) { goto rcs_timers_error; } tmcf->lock_file = s; continue; } if (ngx_strncmp(value[i].data, "interval=", 9) == 0) { s.data = value[i].data + 9; s.len = value[i].len - 9; interval = ngx_parse_time(&s, 0); if (interval == (ngx_msec_t) NGX_ERROR) { return "invalid value"; } tmcf->rcs_interval = interval; continue; } if (ngx_strncmp(value[i].data, "enable=", 7) == 0) { s.data = value[i].data + 7; s.len = value[i].len - 7; rcs_kp_enable = ngx_atoi(s.data, s.len); if (rcs_kp_enable == NGX_ERROR) { goto rcs_timers_error; } tmcf->rcs_kp_enable = rcs_kp_enable; continue; } goto rcs_timers_error; } if (tmcf->lock_file.len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "tfs_poll directive must have lock file"); return NGX_CONF_ERROR; } if (tmcf->rcs_interval < NGX_HTTP_TFS_MIN_TIMER_DELAY) { tmcf->rcs_interval = NGX_HTTP_TFS_MIN_TIMER_DELAY; ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "tfs_poll interval is small, so reset this value to 1000"); } return NGX_CONF_OK; rcs_timers_error: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\" in \"%V\" directive", &value[i], &cmd->name); return NGX_CONF_ERROR; }
ngx_shm_zone_t * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) { ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_list_part_t *part; part = &cf->cycle->shared_memory.part; shm_zone = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (name->len != shm_zone[i].shm.name.len) { continue; } if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) != 0) { continue; } if (tag != shm_zone[i].tag) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the shared memory zone \"%V\" is " "already declared for a different use", &shm_zone[i].shm.name); return NULL; } if (shm_zone[i].shm.size == 0) { shm_zone[i].shm.size = size; } if (size && size != shm_zone[i].shm.size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the size %uz of shared memory zone \"%V\" " "conflicts with already declared size %uz", size, &shm_zone[i].shm.name, shm_zone[i].shm.size); return NULL; } return &shm_zone[i]; } shm_zone = ngx_list_push(&cf->cycle->shared_memory); if (shm_zone == NULL) { return NULL; } shm_zone->data = NULL; shm_zone->shm.log = cf->cycle->log; shm_zone->shm.size = size; shm_zone->shm.name = *name; shm_zone->shm.exists = 0; shm_zone->init = NULL; shm_zone->tag = tag; shm_zone->noreuse = 0; return shm_zone; }
static char * ngx_http_tfs_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_int_t enable; ngx_str_t *value, s; ngx_http_tfs_main_conf_t *tmcf; ngx_http_tfs_srv_conf_t *tscf; ngx_http_core_loc_conf_t *clcf; value = cf->args->elts; if (ngx_strncmp(value[1].data, "enable=", 7) == 0) { s.len = value[1].len - 7; s.data = value[1].data + 7; enable = ngx_atoi(s.data, s.len); if (!enable) { return NGX_CONF_OK; } } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); tscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_tfs_module); tmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_tfs_module); clcf->handler = ngx_http_tfs_handler; if (clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } if (tmcf->enable_rcs == NGX_CONF_UNSET) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "in tfs module must assign enable rcs, use directives \"tfs_enable_rcs\" "); return NGX_CONF_ERROR; } if (tmcf->enable_rcs) { if (tscf->local_addr_text[0] == '\0') { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "in tfs module must assign net device name, use directives \"tfs_net_device\" "); return NGX_CONF_ERROR; } s.data = (u_char *) NGX_HTTP_TFS_RCS_ZONE_NAME; s.len = sizeof(NGX_HTTP_TFS_RCS_ZONE_NAME) - 1; tmcf->rcs_shm_zone = ngx_shared_memory_add(cf, &s, 0, &ngx_http_tfs_module); if (tmcf->rcs_shm_zone == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "in tfs module must assign rcs shm zone, use directives \"tfs_rcs_zone\" "); return NGX_CONF_ERROR; } } if (tmcf->local_block_cache_ctx != NULL) { s.data = (u_char *) NGX_HTTP_TFS_BLOCK_CACHE_ZONE_NAME; s.len = sizeof(NGX_HTTP_TFS_BLOCK_CACHE_ZONE_NAME) - 1; tmcf->block_cache_shm_zone = ngx_shared_memory_add(cf, &s, 0, &ngx_http_tfs_module); if (tmcf->block_cache_shm_zone == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "in tfs module must assign block cache shm zone,"\ "use directives \"tfs_block_cache_zone\" "); return NGX_CONF_ERROR; } } return NGX_CONF_OK; }
// make our proposed ZIP-file chunk map ngx_int_t ngx_http_zip_generate_pieces(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx) { ngx_uint_t i, piece_i; off_t offset = 0; time_t unix_time = 0; ngx_uint_t dos_time = 0; ngx_http_zip_file_t *file; ngx_http_zip_piece_t *header_piece, *file_piece, *trailer_piece, *cd_piece; ngx_http_variable_value_t *vv; if ((vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t))) == NULL) return NGX_ERROR; ctx->unicode_path = 0; #ifdef NGX_ZIP_HAVE_ICONV iconv_t *iconv_cd = NULL; #endif // Let's try to find special header that contains separator string. // What for this strange separator string you ask? // Sometimes there might be a problem converting UTF-8 to zips native // charset(CP866), because it's not 1:1 conversion. So my solution is to // developers provide their own version of converted filename and pass it // to mod_zip along with UTF-8 filename which will go straight to Unicode // path extra field (thanks to tony2001). So separator is a solution that doesn't // break current format. And allows passing file name in both formats as one string. // // Normally we pass: // CRC32 <size> <path> <filename>\n // ... // * <filename> passed to archive as filename w/o conversion // * UFT-8 flag for filename is set // // tony2001's X-Archive-Charset: <charset> way: // CRC32 <size> <path> <filename>\n // ... // * <filename> is accepted to be UTF-8 string // * <filename>, converted to <charset> and passed to archive as filename // * <filename> passed to Unicode path extra field // * UFT-8 flag for filename is not set // // My X-Archive-Name-Sep: <sep> solution: // CRC32 <size> <path> <native-filename><sep><utf8-filename>\n // ... // * <native-filename> passed to archive as filename w/o conversion // * <utf8-filename> passed to Unicode path extra field // * UFT-8 flag for filename is not set // // You just need to provide separator that won't interfere with file names. I suggest using '/' // as it is ASCII character and forbidden on most (if not all) platforms as a part of filename. // // Empty separator string means no UTF-8 version provided. Usefull when we need to pass only // names encoded in native charset. It's equal to 'X-Archive-Charset: native;'. // Note: Currently it is impossible after '[PATCH] Support for UTF-8 file names.'(4f61592b) // because UFT-8 flag (zip_utf8_flag) is set default for templates. if(ngx_http_upstream_header_variable(r, vv, (uintptr_t)(&ngx_http_zip_header_name_separator)) == NGX_OK && !vv->not_found) { ctx->native_charset = 1; if(vv->len) ctx->unicode_path = 1; } else { #ifdef NGX_ZIP_HAVE_ICONV if (ngx_http_upstream_header_variable(r, vv, (uintptr_t)(&ngx_http_zip_header_charset_name)) == NGX_OK && !vv->not_found && ngx_strncmp(vv->data, "utf8", sizeof("utf8") - 1) != 0) { if(ngx_strncmp(vv->data, "native", sizeof("native") - 1)) { char encoding[ICONV_CSNMAXLEN]; snprintf(encoding, sizeof(encoding), "%s//TRANSLIT//IGNORE", vv->data); iconv_cd = iconv_open((const char *)encoding, "utf-8"); if (iconv_cd == (iconv_t)(-1)) { ngx_log_error(NGX_LOG_WARN, r->connection->log, errno, "mod_zip: iconv_open('%s', 'utf-8') failed", vv->data); iconv_cd = NULL; } else { ctx->unicode_path = 1; ctx->native_charset = 1; } } else ctx->native_charset = 1; } #endif } // pieces: for each file: header, data, footer (if needed) -> 2 or 3 per file // plus file footer (CD + [zip64 end + zip64 locator +] end of cd) in one chunk ctx->pieces_n = ctx->files.nelts * (2 + (!!ctx->missing_crc32)) + 1; if ((ctx->pieces = ngx_palloc(r->pool, sizeof(ngx_http_zip_piece_t) * ctx->pieces_n)) == NULL) return NGX_ERROR; ctx->cd_size = 0; unix_time = time(NULL); dos_time = ngx_dos_time(unix_time); for (piece_i = i = 0; i < ctx->files.nelts; i++) { file = &((ngx_http_zip_file_t *)ctx->files.elts)[i]; file->offset = offset; file->unix_time = unix_time; file->dos_time = dos_time; if(ctx->unicode_path) { #ifdef NGX_ZIP_HAVE_ICONV if (iconv_cd) { size_t inlen = file->filename.len, outlen, outleft; u_char *p, *in; //inbuf file->filename_utf8.data = ngx_pnalloc(r->pool, file->filename.len + 1); ngx_memcpy(file->filename_utf8.data, file->filename.data, file->filename.len); file->filename_utf8.len = file->filename.len; file->filename_utf8.data[file->filename.len] = '\0'; //outbuf outlen = outleft = inlen * sizeof(int) + 15; file->filename.data = ngx_pnalloc(r->pool, outlen + 1); in = file->filename_utf8.data; p = file->filename.data; //reset state iconv(iconv_cd, NULL, NULL, NULL, NULL); //convert the string iconv(iconv_cd, (char **)&in, &inlen, (char **)&p, &outleft); //XXX if (res == (size_t)-1) { ? } file->filename.len = outlen - outleft; file->filename_utf8_crc32 = ngx_crc32_long(file->filename_utf8.data, file->filename_utf8.len); } #endif else if(vv->len) { const char * sep = ngx_http_zip_strnrstr((const char*)file->filename.data, file->filename.len, (const char*)vv->data, vv->len); if(sep) { size_t utf8_len = file->filename.len - vv->len - (size_t)(sep - (const char *)file->filename.data); file->filename_utf8.data = ngx_pnalloc(r->pool, utf8_len); file->filename_utf8.len = utf8_len; ngx_memcpy(file->filename_utf8.data, sep + vv->len, utf8_len); file->filename.len -= utf8_len + vv->len; file->filename_utf8_crc32 = ngx_crc32_long(file->filename_utf8.data, file->filename_utf8.len); } /* else { } */ // Separator not found. Okay, no extra field for this one then. } } if(offset >= (off_t) NGX_MAX_UINT32_VALUE) ctx->zip64_used = file->need_zip64_offset = 1; if(file->size >= (off_t) NGX_MAX_UINT32_VALUE) ctx->zip64_used = file->need_zip64 = 1; ctx->cd_size += sizeof(ngx_zip_central_directory_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_central_t) + (file->need_zip64_offset ? (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_offset_t) : sizeof(ngx_zip_extra_field_zip64_offset_only_t)) : (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_only_t) : 0) + (ctx->unicode_path && file->filename_utf8.len ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0) ); header_piece = &ctx->pieces[piece_i++]; header_piece->type = zip_header_piece; header_piece->file = file; header_piece->range.start = offset; header_piece->range.end = offset += sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t) + (file->need_zip64? sizeof(ngx_zip_extra_field_zip64_sizes_only_t):0) + (ctx->unicode_path && file->filename_utf8.len ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0); file_piece = &ctx->pieces[piece_i++]; file_piece->type = zip_file_piece; file_piece->file = file; file_piece->range.start = offset; file_piece->range.end = offset += file->size; //!note: (sizeless chunks): we need file size here / or mark it and modify ranges after if (file->missing_crc32) { // if incomplete header -> add footer with that info to file trailer_piece = &ctx->pieces[piece_i++]; trailer_piece->type = zip_trailer_piece; trailer_piece->file = file; trailer_piece->range.start = offset; trailer_piece->range.end = offset += file->need_zip64? sizeof(ngx_zip_data_descriptor_zip64_t) : sizeof(ngx_zip_data_descriptor_t); //!!TODO: if we want Ranges support - here we know it is impossible for this set //? check conf/some state and abort? } } #ifdef NGX_ZIP_HAVE_ICONV if (iconv_cd) { iconv_close(iconv_cd); } #endif ctx->zip64_used |= offset >= (off_t) NGX_MAX_UINT32_VALUE || ctx->files.nelts >= NGX_MAX_UINT16_VALUE; ctx->cd_size += sizeof(ngx_zip_end_of_central_directory_record_t); if (ctx->zip64_used) ctx->cd_size += sizeof(ngx_zip_zip64_end_of_central_directory_record_t) + sizeof(ngx_zip_zip64_end_of_central_directory_locator_t); cd_piece = &ctx->pieces[piece_i++]; cd_piece->type = zip_central_directory_piece; cd_piece->range.start = offset; cd_piece->range.end = offset += ctx->cd_size; ctx->pieces_n = piece_i; //!! nasty hack (truncating allocated array without reallocation) ctx->archive_size = offset; return NGX_OK; }
static ngx_int_t ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { u_char *p, *ref, *last; size_t len; ngx_str_t *uri; ngx_uint_t i, key; ngx_http_referer_conf_t *rlcf; u_char buf[256]; rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); if (rlcf->hash.hash.buckets == NULL && rlcf->hash.wc_head == NULL && rlcf->hash.wc_tail == NULL #if (NGX_PCRE) && rlcf->regex == NULL #endif ) { goto valid; } if (r->headers_in.referer == NULL) { if (rlcf->no_referer) { goto valid; } goto invalid; } len = r->headers_in.referer->value.len; ref = r->headers_in.referer->value.data; if (len >= sizeof("http://i.ru") - 1) { last = ref + len; if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) { ref += 7; len -= 7; goto valid_scheme; } else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) { ref += 8; len -= 8; goto valid_scheme; } } if (rlcf->blocked_referer) { goto valid; } goto invalid; valid_scheme: i = 0; key = 0; for (p = ref; p < last; p++) { if (*p == '/' || *p == ':') { break; } buf[i] = ngx_tolower(*p); key = ngx_hash(key, buf[i++]); if (i == 256) { goto invalid; } } uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref); if (uri) { goto uri; } #if (NGX_PCRE) if (rlcf->regex) { ngx_int_t rc; ngx_str_t referer; referer.len = len; referer.data = ref; rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log); if (rc == NGX_OK) { goto valid; } if (rc == NGX_ERROR) { return rc; } /* NGX_DECLINED */ } #endif invalid: *v = ngx_http_variable_true_value; return NGX_OK; uri: for ( /* void */ ; p < last; p++) { if (*p == '/') { break; } } len = last - p; if (uri == NGX_HTTP_REFERER_NO_URI_PART) { goto valid; } if (len < uri->len || ngx_strncmp(uri->data, p, uri->len) != 0) { goto invalid; } valid: *v = ngx_http_variable_null_value; return NGX_OK; }
char * ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { off_t max_size; u_char *last, *p; time_t inactive; ssize_t size; ngx_str_t s, name, *value; ngx_int_t loader_files; ngx_msec_t loader_sleep, loader_threshold; ngx_uint_t i, n; ngx_http_file_cache_t *cache; cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t)); if (cache == NULL) { return NGX_CONF_ERROR; } cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); if (cache->path == NULL) { return NGX_CONF_ERROR; } inactive = 600; loader_files = 100; loader_sleep = 50; loader_threshold = 200; name.len = 0; size = 0; max_size = NGX_MAX_OFF_T_VALUE; value = cf->args->elts; cache->path->name = value[1]; if (cache->path->name.data[cache->path->name.len - 1] == '/') { cache->path->name.len--; } if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) { return NGX_CONF_ERROR; } for (i = 2; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "levels=", 7) == 0) { p = value[i].data + 7; last = value[i].data + value[i].len; for (n = 0; n < 3 && p < last; n++) { if (*p > '0' && *p < '3') { cache->path->level[n] = *p++ - '0'; cache->path->len += cache->path->level[n] + 1; if (p == last) { break; } if (*p++ == ':' && n < 2 && p != last) { continue; } goto invalid_levels; } goto invalid_levels; } if (cache->path->len < 10 + 3) { continue; } invalid_levels: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid \"levels\" \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) { name.data = value[i].data + 10; p = (u_char *) ngx_strchr(name.data, ':'); if (p) { name.len = p - name.data; p++; s.len = value[i].data + value[i].len - p; s.data = p; size = ngx_parse_size(&s); if (size > 8191) { continue; } } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid keys zone size \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { s.len = value[i].len - 9; s.data = value[i].data + 9; inactive = ngx_parse_time(&s, 1); if (inactive == (time_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid inactive value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) { s.len = value[i].len - 9; s.data = value[i].data + 9; max_size = ngx_parse_offset(&s); if (max_size < 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid max_size value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) { loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13); if (loader_files == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid loader_files value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) { s.len = value[i].len - 13; s.data = value[i].data + 13; loader_sleep = ngx_parse_time(&s, 0); if (loader_sleep == (ngx_msec_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid loader_sleep value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) { s.len = value[i].len - 17; s.data = value[i].data + 17; loader_threshold = ngx_parse_time(&s, 0); if (loader_threshold == (ngx_msec_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid loader_threshold value \"%V\"", &value[i]); return NGX_CONF_ERROR; } continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } if (name.len == 0 || size == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%V\" must have \"keys_zone\" parameter", &cmd->name); return NGX_CONF_ERROR; } cache->path->manager = ngx_http_file_cache_manager; cache->path->loader = ngx_http_file_cache_loader; cache->path->data = cache; cache->path->conf_file = cf->conf_file->file.name.data; cache->path->line = cf->conf_file->line; cache->loader_files = loader_files; cache->loader_sleep = loader_sleep; cache->loader_threshold = loader_threshold; if (ngx_add_path(cf, &cache->path) != NGX_OK) { return NGX_CONF_ERROR; } cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post); if (cache->shm_zone == NULL) { return NGX_CONF_ERROR; } if (cache->shm_zone->data) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate zone \"%V\"", &name); return NGX_CONF_ERROR; } cache->shm_zone->init = ngx_http_file_cache_init; cache->shm_zone->data = cache; cache->inactive = inactive; cache->max_size = max_size; return NGX_CONF_OK; }
ngx_int_t ngx_postgres_process_response(ngx_http_request_t *r, PGresult *res) { ngx_postgres_loc_conf_t *pglcf; ngx_postgres_ctx_t *pgctx; ngx_postgres_rewrite_conf_t *pgrcf; ngx_postgres_variable_t *pgvar; ngx_str_t *store; char *affected; size_t affected_len; ngx_uint_t i; ngx_int_t rc; dd("entering"); pglcf = ngx_http_get_module_loc_conf(r, ngx_postgres_module); pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module); /* set $postgres_columns */ pgctx->var_cols = PQnfields(res); /* set $postgres_rows */ pgctx->var_rows = PQntuples(res); /* set $postgres_affected */ if (ngx_strncmp(PQcmdStatus(res), "SELECT", sizeof("SELECT") - 1)) { affected = PQcmdTuples(res); affected_len = ngx_strlen(affected); if (affected_len) { pgctx->var_affected = ngx_atoi((u_char *) affected, affected_len); } } if (pglcf->rewrites) { /* process rewrites */ pgrcf = pglcf->rewrites->elts; for (i = 0; i < pglcf->rewrites->nelts; i++) { rc = pgrcf[i].handler(r, &pgrcf[i]); if (rc != NGX_DECLINED) { if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { dd("returning NGX_DONE, status %d", (int) rc); pgctx->status = rc; return NGX_DONE; } pgctx->status = rc; break; } } } if (pglcf->variables) { /* set custom variables */ pgvar = pglcf->variables->elts; store = pgctx->variables->elts; for (i = 0; i < pglcf->variables->nelts; i++) { store[i] = ngx_postgres_variable_set_custom(r, res, &pgvar[i]); if ((store[i].len == 0) && (pgvar[i].value.required)) { dd("returning NGX_DONE, status NGX_HTTP_INTERNAL_SERVER_ERROR"); pgctx->status = NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_DONE; } } } if (pglcf->output_handler) { /* generate output */ dd("returning"); return pglcf->output_handler(r, res); } dd("returning NGX_DONE"); return NGX_DONE; }
ngx_http_reqstat_rbnode_t * ngx_http_reqstat_rbtree_lookup(ngx_shm_zone_t *shm_zone, ngx_str_t *val) { size_t size; uint32_t hash; ngx_int_t rc, excess; ngx_time_t *tp; ngx_msec_t now; ngx_queue_t *q; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_reqstat_ctx_t *ctx; ngx_http_reqstat_rbnode_t *rs; ctx = shm_zone->data; hash = ngx_murmur_hash2(val->data, val->len); node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ngx_shmtx_lock(&ctx->shpool->mutex); while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ rs = (ngx_http_reqstat_rbnode_t *) &node->color; /* len < node->len */ if (val->len < (size_t) rs->len) { node = node->left; continue; } rc = ngx_strncmp(val->data, rs->data, (size_t) rs->len); if (rc == 0) { ms = (ngx_msec_int_t) (now - rs->last_visit); rs->excess = rs->excess - ngx_abs(ms) * ctx->recycle_rate / 1000 + 1000; if (rs->excess > 0) { ngx_queue_remove(&rs->visit); ngx_queue_insert_head(&ctx->sh->visit, &rs->visit); } ngx_log_debug2(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup exist: %*s", rs->len, rs->data); ngx_shmtx_unlock(&ctx->shpool->mutex); return rs; } node = (rc < 0) ? node->left : node->right; } size = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_reqstat_rbnode_t, data) + ctx->key_len; node = ngx_slab_alloc_locked(ctx->shpool, size); if (node == NULL) { /* try to free a vacant node */ q = ngx_queue_last(&ctx->sh->visit); rs = ngx_queue_data(q, ngx_http_reqstat_rbnode_t, visit); ms = (ngx_msec_int_t) (now - rs->last_visit); excess = rs->excess - ngx_abs(ms) * ctx->recycle_rate / 1000; ngx_log_debug3(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup try recycle: %*s, %d", rs->len, rs->data, excess); if (excess < 0) { node = (ngx_rbtree_node_t *) ((char *) rs - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_queue_remove(&rs->visit); ngx_queue_remove(&rs->queue); ngx_log_debug2(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup recycle: %*s", rs->len, rs->data); ngx_memzero(node, size); } else { ngx_shmtx_unlock(&ctx->shpool->mutex); return NULL; } } node->key = hash; rs = (ngx_http_reqstat_rbnode_t *) &node->color; rs->len = ngx_min(ctx->key_len, (ssize_t) val->len); ngx_memcpy(rs->data, val->data, rs->len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &rs->queue); ngx_queue_insert_head(&ctx->sh->visit, &rs->visit); rs->last_visit = now; rs->excess = 1000; ngx_log_debug2(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup build: %*s", rs->len, rs->data); ngx_shmtx_unlock(&ctx->shpool->mutex); return rs; }
static ngx_int_t ngx_http_echo_parse_subrequest_spec(ngx_http_request_t *r, ngx_array_t *computed_args, ngx_http_echo_subrequest_t **parsed_sr_ptr) { ngx_str_t *computed_arg_elts, *arg; ngx_str_t **to_write = NULL; ngx_str_t *method_name; ngx_str_t *body_str = NULL; ngx_uint_t i; ngx_flag_t expecting_opt; ngx_http_request_body_t *rb = NULL; ngx_buf_t *b; ngx_http_echo_subrequest_t *parsed_sr; *parsed_sr_ptr = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_subrequest_t)); parsed_sr = *parsed_sr_ptr; computed_arg_elts = computed_args->elts; method_name = &computed_arg_elts[0]; parsed_sr->location = &computed_arg_elts[1]; if (parsed_sr->location->len == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } expecting_opt = 1; for (i = 2; i < computed_args->nelts; i++) { arg = &computed_arg_elts[i]; if (!expecting_opt) { if (to_write == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "echo_subrequest_async: to_write should NOT be NULL"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } *to_write = arg; to_write = NULL; expecting_opt = 1; continue; } if (arg->len == 2) { if (ngx_strncmp("-q", arg->data, arg->len) == 0) { to_write = &parsed_sr->query_string; expecting_opt = 0; continue; } if (ngx_strncmp("-b", arg->data, arg->len) == 0) { to_write = &body_str; expecting_opt = 0; continue; } } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Unknown option for echo_subrequest_async: %V", arg); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (body_str != NULL && body_str->len != 0) { rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } parsed_sr->content_length_n = body_str->len; b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->temporary = 1; /* b->memory = 1; */ b->start = b->pos = body_str->data; b->end = b->last = body_str->data + body_str->len; rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->bufs->buf = b; rb->bufs->next = NULL; rb->buf = b; } parsed_sr->request_body = rb; parsed_sr->method = ngx_http_echo_parse_method_name(&method_name); parsed_sr->method_name = method_name; return NGX_OK; }
static char * ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_stream_ssl_conf_t *scf = conf; size_t len; ngx_str_t *value, name, size; ngx_int_t n; ngx_uint_t i, j; value = cf->args->elts; for (i = 1; i < cf->args->nelts; i++) { if (ngx_strcmp(value[i].data, "off") == 0) { scf->builtin_session_cache = NGX_SSL_NO_SCACHE; continue; } if (ngx_strcmp(value[i].data, "none") == 0) { scf->builtin_session_cache = NGX_SSL_NONE_SCACHE; continue; } if (ngx_strcmp(value[i].data, "builtin") == 0) { scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; continue; } if (value[i].len > sizeof("builtin:") - 1 && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1) == 0) { n = ngx_atoi(value[i].data + sizeof("builtin:") - 1, value[i].len - (sizeof("builtin:") - 1)); if (n == NGX_ERROR) { goto invalid; } scf->builtin_session_cache = n; continue; } if (value[i].len > sizeof("shared:") - 1 && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1) == 0) { len = 0; for (j = sizeof("shared:") - 1; j < value[i].len; j++) { if (value[i].data[j] == ':') { break; } len++; } if (len == 0) { goto invalid; } name.len = len; name.data = value[i].data + sizeof("shared:") - 1; size.len = value[i].len - j - 1; size.data = name.data + len + 1; n = ngx_parse_size(&size); if (n == NGX_ERROR) { goto invalid; } if (n < (ngx_int_t)(8 * ngx_pagesize)) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "session cache \"%V\" is too small", &value[i]); return NGX_CONF_ERROR; } scf->shm_zone = ngx_shared_memory_add(cf, &name, n, &ngx_stream_ssl_module); if (scf->shm_zone == NULL) { return NGX_CONF_ERROR; } scf->shm_zone->init = ngx_ssl_session_cache_init; continue; } goto invalid; } if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) { scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; } return NGX_CONF_OK; invalid: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid session cache \"%V\"", &value[i]); return NGX_CONF_ERROR; }
static char * ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf) { ngx_core_conf_t *ccf = conf; #if (NGX_HAVE_CPU_AFFINITY) ngx_int_t i, n; CPU_SET_T *mask; #endif if (!ccf->worker_processes) { ccf->worker_processes = NGX_CONF_UNSET; } ngx_conf_init_value(ccf->worker_processes, ngx_ncpu); ngx_conf_init_value(ccf->daemon, 1); ngx_conf_init_value(ccf->master, 1); ngx_conf_init_msec_value(ccf->timer_resolution, 0); ngx_conf_init_value(ccf->debug_points, 0); #if (NGX_HAVE_CPU_AFFINITY) /* in default, disable cpu affinity */ if (ccf->cpu_affinity_n == 0 && ccf->cpu_affinity == NULL) { ccf->cpu_affinity_n = 1; } if (ccf->cpu_affinity_n == 0) { n = ngx_ncpu - 1; if (ngx_ncpu > 0 && ngx_ncpu <= CPU_SETSIZE) { mask = ngx_palloc(cycle->pool, ccf->worker_processes * sizeof(CPU_SET_T)); if (mask == NULL) { return NGX_CONF_ERROR; } ccf->cpu_affinity_n = ccf->worker_processes; ccf->cpu_affinity = mask; /* RR for cpu assign */ for (i = 0; i < ccf->worker_processes; i++) { CPU_ZERO(&mask[i]); CPU_SET(n, &mask[i]); if (--n < 0) { n = ngx_ncpu - 1; } } } else { ccf->cpu_affinity_n = 0; ccf->cpu_affinity = NULL; } } if (ccf->cpu_affinity_n && ccf->cpu_affinity_n != 1 && ccf->cpu_affinity_n != (ngx_uint_t) ccf->worker_processes) { ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "the number of \"worker_processes\" is not equal to " "the number of \"worker_cpu_affinity\" masks, " "using last mask for remaining worker processes"); } #endif #if (NGX_THREADS) ngx_conf_init_value(ccf->worker_threads, 0); ngx_threads_n = ccf->worker_threads; ngx_conf_init_size_value(ccf->thread_stack_size, 2 * 1024 * 1024); #endif if (ccf->pid.len == 0) { ngx_str_set(&ccf->pid, NGX_PID_PATH); } if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { return NGX_CONF_ERROR; } ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); if (ccf->oldpid.data == NULL) { return NGX_CONF_ERROR; } ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); #if !(NGX_WIN32) if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) { struct group *grp; struct passwd *pwd; ngx_set_errno(0); pwd = getpwnam(NGX_USER); if (pwd == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "getpwnam(\"" NGX_USER "\") failed"); return NGX_CONF_ERROR; } ccf->username = NGX_USER; ccf->user = pwd->pw_uid; ngx_set_errno(0); grp = getgrnam(NGX_GROUP); if (grp == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "getgrnam(\"" NGX_GROUP "\") failed"); return NGX_CONF_ERROR; } ccf->group = grp->gr_gid; } if (ccf->lock_file.len == 0) { ngx_str_set(&ccf->lock_file, NGX_LOCK_PATH); } if (ngx_conf_full_name(cycle, &ccf->lock_file, 0) != NGX_OK) { return NGX_CONF_ERROR; } { ngx_str_t lock_file; lock_file = cycle->old_cycle->lock_file; if (lock_file.len) { lock_file.len--; if (ccf->lock_file.len != lock_file.len || ngx_strncmp(ccf->lock_file.data, lock_file.data, lock_file.len) != 0) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "\"lock_file\" could not be changed, ignored"); } cycle->lock_file.len = lock_file.len + 1; lock_file.len += sizeof(".accept"); cycle->lock_file.data = ngx_pstrdup(cycle->pool, &lock_file); if (cycle->lock_file.data == NULL) { return NGX_CONF_ERROR; } } else { cycle->lock_file.len = ccf->lock_file.len + 1; cycle->lock_file.data = ngx_pnalloc(cycle->pool, ccf->lock_file.len + sizeof(".accept")); if (cycle->lock_file.data == NULL) { return NGX_CONF_ERROR; } ngx_memcpy(ngx_cpymem(cycle->lock_file.data, ccf->lock_file.data, ccf->lock_file.len), ".accept", sizeof(".accept")); } } #endif return NGX_CONF_OK; }