void* init_hash(ngx_pool_t *pool, ngx_hash_keys_arrays_t *ha, ngx_hash_combined_t *hash) { ngx_hash_init_t hinit; ngx_cacheline_size = 32; //here this variable for nginx must be defined hinit.hash = NULL; //if hinit.hash is NULL, it will alloc memory for it in ngx_hash_init hinit.key = &ngx_hash_key_lc; //hash function hinit.max_size = Max_Size; hinit.bucket_size = Bucket_Size; hinit.name = "my_hash_sample"; hinit.pool = pool; //the hash table exists in the memory pool hinit.temp_pool = ha->temp_pool; if (ha->keys.nelts) { //无通配 hinit.hash = &hash->hash; if (ngx_hash_init(&hinit, ha->keys.elts, ha->keys.nelts) != NGX_OK) { goto failed; } } if (ha->dns_wc_head.nelts) { //前缀通配 hinit.hash = NULL; ngx_qsort(ha->dns_wc_head.elts, (size_t) ha->dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); if (ngx_hash_wildcard_init(&hinit, ha->dns_wc_head.elts, ha->dns_wc_head.nelts) != NGX_OK) { goto failed; } hash->wc_head = (ngx_hash_wildcard_t *) hinit.hash; } if (ha->dns_wc_tail.nelts) { //后缀通配 ngx_qsort(ha->dns_wc_tail.elts, (size_t) ha->dns_wc_tail.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); hinit.hash = NULL; if (ngx_hash_wildcard_init(&hinit, ha->dns_wc_tail.elts, ha->dns_wc_tail.nelts) != NGX_OK) { goto failed; } hash->wc_tail = (ngx_hash_wildcard_t *) hinit.hash; } //ngx_destroy_pool(ha->temp_pool); return hash; failed: //ngx_destroy_pool(ha->temp_pool); return NULL; }
static void ngx_http_sla_init_quantiles (const ngx_http_sla_pool_t* pool, ngx_http_sla_pool_shm_t* counter) { double r; ngx_uint_t i; ngx_uint_t j; ngx_uint_t quantile_diff[NGX_HTTP_SLA_MAX_QUANTILES_LEN]; const ngx_uint_t* quantile; /* 1. Set the initial estimate S equal to the q-th sample quantile */ ngx_qsort(counter->quantiles_fifo, NGX_HTTP_SLA_QUANTILE_M, sizeof(ngx_uint_t), ngx_http_sla_compare_uint); quantile = pool->quantiles.elts; for (i = 0; i < pool->quantiles.nelts; i++) { counter->quantiles[i] = counter->quantiles_fifo[NGX_HTTP_SLA_QUANTILE_M * quantile[i] / 100]; } /* 2.1. Estimate the scale r by the difference of the 75 and 25 sample quantiles */ r = ngx_max( (double)0.001, (double)( counter->quantiles_fifo[NGX_HTTP_SLA_QUANTILE_M * 75 / 100] - counter->quantiles_fifo[NGX_HTTP_SLA_QUANTILE_M * 25 / 100] ) ); /* 2.2. Than take c */ counter->quantiles_c = 0; for (i = 0; i < NGX_HTTP_SLA_QUANTILE_M; i++) { counter->quantiles_c += (double)1 / sqrt(i + 1); } counter->quantiles_c = r / (double)NGX_HTTP_SLA_QUANTILE_M * counter->quantiles_c; /* 3. Take f */ ngx_memzero(quantile_diff, sizeof(ngx_uint_t) * NGX_HTTP_SLA_MAX_QUANTILES_LEN); for (i = 0; i < NGX_HTTP_SLA_QUANTILE_M; i++) { for (j = 0; j < pool->quantiles.nelts; j++) { if (abs((double)counter->quantiles_fifo[i] - counter->quantiles[j]) <= counter->quantiles_c) { quantile_diff[j]++; } } } for (i = 0; i < pool->quantiles.nelts; i++) { counter->quantiles_f[i] = (double)1 / ((double)2 * counter->quantiles_c * (double)NGX_HTTP_SLA_QUANTILE_M) * (double)ngx_max(1, quantile_diff[i]); } }
static ngx_int_t ngx_http_upstream_init_q_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { unsigned char hash_data[HASH_DATA_LENGTH] = {}; ngx_http_upstream_q_chash_ring *q_chash_ring; ngx_http_upstream_q_chash_srv_conf_t *uchscf; ngx_http_upstream_rr_peers_t *peers; ngx_uint_t vnode_num, i, j, k, fill_next; ngx_int_t si; uint32_t point; uchscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_q_chash_module); if (uchscf == NULL) { return NGX_ERROR; } q_chash_ring = ngx_pcalloc(cf->pool, sizeof(*q_chash_ring)); if(q_chash_ring == NULL) return NGX_ERROR; if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { return NGX_ERROR; } us->peer.init = ngx_http_upstream_init_q_chash_peer; uchscf->q_chash_ring = q_chash_ring; peers = us->peer.data; for(i = 0; i < peers->number; i++) { if(!peers->peer[i].down) q_chash_ring->nr_valid_peers ++; } // old_cycle's log_level is NGX_LOG_NOTICE //ngx_log_debug(NGX_LOG_DEBUG_HTTP, cf->log, 0, "upstream %V nr_valid_peers %ui", peers->name, q_chash_ring->nr_valid_peers); // no need to hash if(q_chash_ring->nr_valid_peers <= 1) { return NGX_OK; } // create vnodes, peer_index field, sort q_chash_ring->vnodes = ngx_palloc(cf->pool, sizeof(q_chash_vnode_t) * peers->total_weight * NR_VNODE); if(q_chash_ring->vnodes == NULL) { return NGX_ERROR; } for(i = 0; i < peers->number; i++) { if(peers->peer[i].down) { continue; } vnode_num = peers->peer[i].weight * NR_VNODE; for(j = 0; j < vnode_num / 4; j++) { ngx_snprintf(hash_data, HASH_DATA_LENGTH, "%V-%ui%Z", &peers->peer[i].name, j); u_char md5[16]; ngx_md5_t ctx; ngx_md5_init(&ctx); ngx_md5_update(&ctx, hash_data, ngx_strlen(hash_data)); ngx_md5_final(md5, &ctx); for(k = 0; k < 4; k++) { point = *(uint32_t *)&md5[k * 4]; q_chash_ring->vnodes[q_chash_ring->nr_vnodes].peer_index = i; q_chash_ring->vnodes[q_chash_ring->nr_vnodes].point = point; q_chash_ring->nr_vnodes ++; } } } // old_cycle's log_level is NGX_LOG_NOTICE //ngx_log_debug(NGX_LOG_DEBUG_HTTP, cf->log, 0, "upstream %V nr_vnodes %ui", peers->name, q_chash_ring->nr_vnodes); ngx_qsort(q_chash_ring->vnodes, q_chash_ring->nr_vnodes, sizeof(q_chash_vnode_t), (const void *)compare_vnodes_point); // fill vnode's next field for(i = 1; ; i ++) { if(q_chash_ring->vnodes[0].peer_index == q_chash_ring->vnodes[i].peer_index) continue; q_chash_ring->vnodes[0].next = i; break; } fill_next = 0; for(si = q_chash_ring->nr_vnodes - 1; si >= 0; si--) { if(q_chash_ring->vnodes[si].peer_index == q_chash_ring->vnodes[fill_next].peer_index) { q_chash_ring->vnodes[si].next = q_chash_ring->vnodes[fill_next].next; } else { q_chash_ring->vnodes[si].next = fill_next; fill_next = si; } } // old_cycle's log_level is NGX_LOG_NOTICE /* for(i = 0; i < q_chash_ring->nr_vnodes; i++) { ngx_log_debug(NGX_LOG_DEBUG_HTTP, cf->log, 0, "%ui, next %ui peer_index %ui point %uD", i, q_chash_ring->vnodes[i].next, q_chash_ring->vnodes[i].peer_index, q_chash_ring->vnodes[i].point); } */ // calculate peer ratio for debug ~ ngx_uint_t *statistic_array = ngx_pcalloc(cf->pool, sizeof(uint32_t) * peers->number); if(statistic_array == NULL) return NGX_OK; uint32_t before_point = 0; for(i = 1; i < q_chash_ring->nr_vnodes; i++) { statistic_array[q_chash_ring->vnodes[i].peer_index] += q_chash_ring->vnodes[i].point - before_point; before_point = q_chash_ring->vnodes[i].point; } statistic_array[q_chash_ring->vnodes[0].peer_index] += 0xFFFFFFFF - before_point; for(i = 0; i < peers->number; i++) { if(peers->peer[i].down) continue; ngx_log_error(NGX_LOG_NOTICE, cf->log, 0, "upstream %V %V weight %ui actually ratio %.2f%%", peers->name, &peers->peer[i].name, peers->peer[i].weight, 100 * (double)statistic_array[i] / 0xFFFFFFFF); } ngx_pfree(cf->pool, statistic_array); return NGX_OK; }
/* location / { index index11.html #必须保证新uri所在目录存在并且该目录下面没有index11.html,autoindex对应的ngx_http_autoindex_handler才会生效 autoindex on; } 只有在index11.html文件不存在的时候才会执行autoindex,如果没有设置index则默认打开index.html,必须保证index.html的uri目录存在,如果不存在,是一个不存在的目录也不会执行autoindex */ static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r) //只有在index-module不编译进来的时候该模块才会生效 { //获取uri目录中的所有文件信息组包发送给客户端浏览器 u_char *last, *filename; size_t len, allocated, root; ngx_err_t err; ngx_buf_t *b; ngx_int_t rc; ngx_str_t path, callback; ngx_dir_t dir; ngx_uint_t level, format; ngx_pool_t *pool; ngx_chain_t out; ngx_array_t entries; ngx_http_autoindex_entry_t *entry; ngx_http_autoindex_loc_conf_t *alcf; if (r->uri.data[r->uri.len - 1] != '/') { //autoindex的uri必须是目录形式,最末尾字符/ return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); //如果没有配置index或者try_files,则匹配location / {}到后会默认使用html/index.html if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); if (!alcf->enable) { return NGX_DECLINED; } /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */ last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_AUTOINDEX_PREALLOCATE); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data; if (path.len > 1) { path.len--; } path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex: \"%s\"", path.data); format = alcf->format; if (format == NGX_HTTP_AUTOINDEX_JSONP) { if (ngx_http_autoindex_jsonp_callback(r, &callback) != NGX_OK) { return NGX_HTTP_BAD_REQUEST; } if (callback.len == 0) { format = NGX_HTTP_AUTOINDEX_JSON; } } if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } #if (NGX_SUPPRESS_WARN) /* MSVC thinks 'entries' may be used without having been initialized */ ngx_memzero(&entries, sizeof(ngx_array_t)); #endif /* TODO: pool should be temporary pool */ pool = r->pool; if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t)) != NGX_OK) { return ngx_http_autoindex_error(r, &dir, &path); } r->headers_out.status = NGX_HTTP_OK; switch (format) { case NGX_HTTP_AUTOINDEX_JSON: ngx_str_set(&r->headers_out.content_type, "application/json"); break; case NGX_HTTP_AUTOINDEX_JSONP: ngx_str_set(&r->headers_out.content_type, "application/javascript"); break; case NGX_HTTP_AUTOINDEX_XML: ngx_str_set(&r->headers_out.content_type, "text/xml"); ngx_str_set(&r->headers_out.charset, "utf-8"); break; default: /* NGX_HTTP_AUTOINDEX_HTML */ ngx_str_set(&r->headers_out.content_type, "text/html"); break; } r->headers_out.content_type_len = r->headers_out.content_type.len; r->headers_out.content_type_lowcase = NULL; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } return rc; } filename = path.data; filename[path.len] = '/'; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_autoindex_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex file: \"%s\"", ngx_de_name(&dir)); len = ngx_de_namelen(&dir); if (ngx_de_name(&dir)[0] == '.') { continue; } if (!dir.valid_info) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_AUTOINDEX_PREALLOCATE; filename = ngx_pnalloc(pool, allocated); if (filename == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT && err != NGX_ELOOP) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); if (err == NGX_EACCES) { continue; } return ngx_http_autoindex_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_autoindex_error(r, &dir, &path); } } } entry = ngx_array_push(&entries); if (entry == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } entry->name.len = len; entry->name.data = ngx_pnalloc(pool, len + 1); if (entry->name.data == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); entry->dir = ngx_de_is_dir(&dir); entry->file = ngx_de_is_file(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } if (entries.nelts > 1) { ngx_qsort(entries.elts, (size_t) entries.nelts, sizeof(ngx_http_autoindex_entry_t), ngx_http_autoindex_cmp_entries); } switch (format) { case NGX_HTTP_AUTOINDEX_JSON: b = ngx_http_autoindex_json(r, &entries, NULL); break; case NGX_HTTP_AUTOINDEX_JSONP: b = ngx_http_autoindex_json(r, &entries, &callback); break; case NGX_HTTP_AUTOINDEX_XML: b = ngx_http_autoindex_xml(r, &entries); break; default: /* NGX_HTTP_AUTOINDEX_HTML */ b = ngx_http_autoindex_html(r, &entries); break; } if (b == NULL) { return NGX_ERROR; } /* TODO: free temporary pool */ if (r == r->main) { b->last_buf = 1; } b->last_in_chain = 1; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_upstream_init_consistent(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { ngx_uint_t i, j, continuum_index, pointer_index, pointer_per_server, pointer_counter, value; ngx_http_upstream_server_t *server; ngx_http_upstream_consistent_peer_t *peers; ngx_http_upstream_consistent_data_t *ucd; ngx_http_upstream_consistent_continuum_item_t *continuum; uint64_t total_weight; us->peer.init = ngx_http_upstream_init_consistent_peer; ucd = us->peer.data; if (!us->servers) { return NGX_ERROR; } server = us->servers->elts; peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_peer_t) * us->servers->nelts); if (peers == NULL) { return NGX_ERROR; } total_weight = 0; for (i = 0; i < us->servers->nelts; i++) { peers[i].server = &server[i]; total_weight += server[i].weight; } ucd->continuum_count = us->servers->nelts + CONTINUUM_ADDITION; continuum = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_continuum_item_t) * ucd->continuum_count * POINTS_PER_SERVER); if (continuum == NULL) { return NGX_ERROR; } pointer_counter = continuum_index = 0; for (i = 0; i < us->servers->nelts; ++i) { float pct = (float)peers[i].server->weight / (float)total_weight; pointer_per_server = (ngx_uint_t) ((floorf((float) (pct * POINTS_PER_SERVER / 4 * (float) us->servers->nelts + 0.0000000001))) * 4); // 4 == pointer_per_hash for (pointer_index = 1; pointer_index <= pointer_per_server / 4; pointer_index++) { u_char *sort_host; sort_host = ngx_pcalloc(cf->pool, MAX_HOST_SORT_LENGTH); if (sort_host == NULL) { return NGX_ERROR; } if (ngx_strstr(peers[i].server->addrs->name.data, ":11211") != NULL) { peers[i].server->addrs->name.len -= 6; peers[i].server->addrs->name.data[peers[i].server->addrs->name.len] = '\0'; } ngx_snprintf(sort_host, MAX_HOST_SORT_LENGTH, "%V-%ui%Z", &peers[i].server->addrs->name, pointer_index-1); // 4 == pointer_per_hash for (j = 0; j < 4; j++) { value = ngx_http_upstream_consistent_ketama_hash(sort_host, ngx_strlen(sort_host), j); continuum[continuum_index].index = i; continuum[continuum_index++].value = value; } } pointer_counter += pointer_per_server; } ngx_qsort(continuum, pointer_counter, sizeof(ngx_http_upstream_consistent_continuum_item_t), ngx_http_upstream_consistent_continuum_item_cmp); ucd->peers = peers; ucd->continuum_points_counter = pointer_counter; ucd->continuum = continuum; /* for (i = 0; i < continuum_index; i++) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, "upstream_consistent: %i", continuum[i].value); } */ return NGX_OK; }
static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_http_referer_conf_t *prev = parent; ngx_http_referer_conf_t *conf = child; ngx_hash_init_t hash; if (conf->keys == NULL) { conf->hash = prev->hash; #if (NGX_PCRE) ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); #endif ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); return NGX_CONF_OK; } if ((conf->no_referer == 1 || conf->blocked_referer == 1) && conf->keys->keys.nelts == 0 && conf->keys->dns_wc_head.nelts == 0 && conf->keys->dns_wc_tail.nelts == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "the \"none\" or \"blocked\" referers are specified " "in the \"valid_referers\" directive " "without any valid referer"); return NGX_CONF_ERROR; } hash.key = ngx_hash_key_lc; hash.max_size = 2048; /* TODO: referer_hash_max_size; */ hash.bucket_size = 64; /* TODO: referer_hash_bucket_size; */ hash.name = "referers_hash"; hash.pool = cf->pool; if (conf->keys->keys.nelts) { hash.hash = &conf->hash.hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) != NGX_OK) { return NGX_CONF_ERROR; } } if (conf->keys->dns_wc_head.nelts) { ngx_qsort(conf->keys->dns_wc_head.elts, (size_t) conf->keys->dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_referer_wildcards); hash.hash = NULL; hash.temp_pool = cf->temp_pool; if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts, conf->keys->dns_wc_head.nelts) != NGX_OK) { return NGX_CONF_ERROR; } conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; } if (conf->keys->dns_wc_tail.nelts) { ngx_qsort(conf->keys->dns_wc_tail.elts, (size_t) conf->keys->dns_wc_tail.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_referer_wildcards); hash.hash = NULL; hash.temp_pool = cf->temp_pool; if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_tail.elts, conf->keys->dns_wc_tail.nelts) != NGX_OK) { return NGX_CONF_ERROR; } conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } #if (NGX_PCRE) ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); #endif if (conf->no_referer == NGX_CONF_UNSET) { conf->no_referer = 0; } if (conf->blocked_referer == NGX_CONF_UNSET) { conf->blocked_referer = 0; } conf->keys = NULL; return NGX_CONF_OK; }
static ngx_int_t ngx_http_req_status_show_handler(ngx_http_request_t *r) { size_t size, item_size; u_char long_num, full_info, clear_status; ngx_int_t rc; ngx_buf_t *b; ngx_uint_t i; ngx_array_t items; ngx_queue_t *q; ngx_chain_t out; ngx_http_req_status_zone_t **pzone; ngx_http_req_status_node_t *rsn; ngx_http_req_status_main_conf_t *rmcf; ngx_http_req_status_print_item_t *item; static u_char header[] = "zone_name\tkey\tmax_active\tmax_bw\ttraffic\trequests\t" "active\tbandwidth\tresptime\n"; if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } ngx_str_set(&r->headers_out.content_type, "text/plain"); if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } } #define NGX_STRCHR(s, u) \ (ngx_strlchr((s)->data, (s)->data + (s)->len, u) != NULL) full_info = NGX_STRCHR(&r->args, 'f'); long_num = NGX_STRCHR(&r->args, 'l'); clear_status = NGX_STRCHR(&r->args, 'c'); item_size = sizeof(ngx_http_req_status_print_item_t) + (clear_status ? sizeof(ngx_http_req_status_data_t) : 0); if (ngx_array_init(&items, r->pool, 40, item_size) != NGX_OK){ return NGX_HTTP_INTERNAL_SERVER_ERROR; } size = sizeof(header) - 1; rmcf = ngx_http_get_module_main_conf(r, ngx_http_req_status_module); pzone = rmcf->zones.elts; for (i = 0; i < rmcf->zones.nelts; i++){ ngx_shmtx_lock(&pzone[i]->shpool->mutex); for (q = ngx_queue_last(&pzone[i]->sh->queue); q != ngx_queue_sentinel(&pzone[i]->sh->queue); q = ngx_queue_prev(q)) { rsn = ngx_queue_data(q, ngx_http_req_status_node_t, queue); if (!rsn->data.requests){ continue; } if (rsn->last_traffic){ if (ngx_current_msec > rsn->last_traffic_update && ngx_current_msec - rsn->last_traffic_update >= rmcf->interval){ rsn->last_traffic_start = 0; rsn->last_traffic = 0; rsn->data.bandwidth = 0; rsn->last_traffic_update = ngx_current_msec; } } size += pzone[i]->shm_zone->shm.name.len + rsn->len + (sizeof("\t") - 1) * 8 + (NGX_INT64_LEN) * 7; // 6 change to 7, for rt, if (full_info){ size += (NGX_INT64_LEN) * 3 + (sizeof("\t") - 1) * 3; } item = ngx_array_push(&items); if (item == NULL){ return NGX_HTTP_INTERNAL_SERVER_ERROR; } item->zone_name = &pzone[i]->shm_zone->shm.name; item->node = rsn; if (clear_status){ item->pdata = NULL; ngx_memcpy(&item->data[0], &rsn->data, sizeof(ngx_http_req_status_data_t)); ngx_memzero(&rsn->data, sizeof(ngx_http_req_status_data_t)); } else { item->pdata = &rsn->data; } } pzone[i]->sh->expire_lock = ngx_time() + rmcf->lock_time; ngx_shmtx_unlock(&pzone[i]->shpool->mutex); } if (items.nelts > 1) { ngx_qsort(items.elts, (size_t) items.nelts, item_size, ngx_http_req_status_cmp_items); } b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); item = items.elts; for (i = 0; i < items.nelts; i++){ if (i) { item = (ngx_http_req_status_print_item_t *) ((u_char *)item + item_size); } /* set pdata here because of qsort above */ if (item->pdata == NULL){ item->pdata = &item->data[0]; } b->last = ngx_cpymem(b->last, item->zone_name->data, item->zone_name->len); *b->last ++ = '\t'; b->last = ngx_cpymem(b->last, item->node->key, item->node->len); *b->last ++ = '\t'; if (long_num){ b->last = ngx_sprintf(b->last, "%ui\t%ui\t%ui\t%ui\t%ui\t%ui\t%ui", item->pdata->max_active, item->pdata->max_bandwidth * 8, item->pdata->traffic * 8, item->pdata->requests, item->node->active, item->pdata->bandwidth * 8, item->pdata->rt); } else { b->last = ngx_sprintf(b->last, "%ui\t", item->pdata->max_active); b->last = ngx_http_req_status_format_size(b->last, item->pdata->max_bandwidth * 8); *b->last ++ = '\t'; b->last = ngx_http_req_status_format_size(b->last, item->pdata->traffic * 8); *b->last ++ = '\t'; b->last = ngx_sprintf(b->last, "%ui\t", item->pdata->requests); b->last = ngx_sprintf(b->last, "%ui\t", item->node->active); b->last = ngx_http_req_status_format_size(b->last, item->pdata->bandwidth * 8); *b->last ++ = '\t'; b->last = ngx_sprintf(b->last, "%ui", item->pdata->rt); } if (full_info){ b->last = ngx_sprintf(b->last, "\t%ui\t%ui\t%ui", item->node->last_traffic * 8, item->node->last_traffic_start, item->node->last_traffic_update); } *b->last ++ = '\n'; } out.buf = b; out.next = NULL; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; b->last_buf = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_req_status_show_json_handler(ngx_http_request_t *r) { size_t item_size; ngx_int_t rc; ngx_buf_t *b; ngx_uint_t i; ngx_array_t items; ngx_queue_t *q; ngx_chain_t out; ngx_http_req_status_zone_t **pzone; ngx_http_req_status_node_t *rsn; ngx_http_req_status_main_conf_t *rmcf; ngx_http_req_status_print_item_t *item; #define NGX_HTTP_REQ_STATUS_JSON_BUFFER_SIZE (int) 262144 #define NGX_HTTP_REQ_STATUS_JSON_FMT_S "{" #define NGX_HTTP_REQ_STATUS_JSON_FMT_E "}" #define NGX_HTTP_REQ_STATUS_JSON_FMT_NEXT "," #define NGX_HTTP_REQ_STATUS_JSON_FMT_ZONE_LIST_S "\"zone_list\":[" #define NGX_HTTP_REQ_STATUS_JSON_FMT_ZONE_LIST_E "]" #define NGX_HTTP_REQ_STATUS_JSON_FMT_STAT_ITEM \ "{" \ "\"zone_name\":\"%s\"," \ "\"key\":\"%s\"," \ "\"max_active\":%ui," \ "\"max_bw\":%ui," \ "\"traffic\":%ui," \ "\"requests\":%ui," \ "\"active\":%ui," \ "\"bandwith\":%ui" \ "}" if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } ngx_str_set(&r->headers_out.content_type, "application/json"); if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } } item_size = sizeof(ngx_http_req_status_print_item_t); if (ngx_array_init(&items, r->pool, 40, item_size) != NGX_OK){ return NGX_HTTP_INTERNAL_SERVER_ERROR; } rmcf = ngx_http_get_module_main_conf(r, ngx_http_req_status_module); pzone = rmcf->zones.elts; for (i = 0; i < rmcf->zones.nelts; i++){ ngx_shmtx_lock(&pzone[i]->shpool->mutex); for (q = ngx_queue_last(&pzone[i]->sh->queue); q != ngx_queue_sentinel(&pzone[i]->sh->queue); q = ngx_queue_prev(q)) { rsn = ngx_queue_data(q, ngx_http_req_status_node_t, queue); if (!rsn->data.requests){ continue; } if (rsn->last_traffic){ if (ngx_current_msec > rsn->last_traffic_update && ngx_current_msec - rsn->last_traffic_update >= rmcf->interval){ rsn->last_traffic_start = 0; rsn->last_traffic = 0; rsn->data.bandwidth = 0; rsn->last_traffic_update = ngx_current_msec; } } item = ngx_array_push(&items); if (item == NULL){ return NGX_HTTP_INTERNAL_SERVER_ERROR; } item->zone_name = &pzone[i]->shm_zone->shm.name; item->node = rsn; item->pdata = &rsn->data; } pzone[i]->sh->expire_lock = ngx_time() + rmcf->lock_time; ngx_shmtx_unlock(&pzone[i]->shpool->mutex); } if (items.nelts > 1) { ngx_qsort(items.elts, (size_t) items.nelts, item_size, ngx_http_req_status_cmp_items); } b = ngx_create_temp_buf(r->pool, NGX_HTTP_REQ_STATUS_JSON_BUFFER_SIZE); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->last = ngx_sprintf(b->last, NGX_HTTP_REQ_STATUS_JSON_FMT_S); b->last = ngx_sprintf(b->last, NGX_HTTP_REQ_STATUS_JSON_FMT_ZONE_LIST_S); item = items.elts; for (i = 0; i < items.nelts; i++){ if (i) { item = (ngx_http_req_status_print_item_t *) ((u_char *)item + item_size); } /* set pdata here because of qsort above */ if (item->pdata == NULL){ item->pdata = &item->data[0]; } b->last = ngx_sprintf(b->last, NGX_HTTP_REQ_STATUS_JSON_FMT_STAT_ITEM, item->zone_name->data, item->node->key, item->pdata->max_active, item->pdata->max_bandwidth * 8, item->pdata->traffic * 8, item->pdata->requests, item->node->active, item->pdata->bandwidth * 8); if(i+1 != items.nelts) { b->last = ngx_sprintf(b->last, NGX_HTTP_REQ_STATUS_JSON_FMT_NEXT); } } b->last = ngx_sprintf(b->last, NGX_HTTP_REQ_STATUS_JSON_FMT_ZONE_LIST_E); b->last = ngx_sprintf(b->last, NGX_HTTP_REQ_STATUS_JSON_FMT_E); out.buf = b; out.next = NULL; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; b->last_buf = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r) { u_char *last, *filename, scale; off_t length; size_t len, utf_len, allocated, root; ngx_tm_t tm; ngx_err_t err; ngx_buf_t *b; ngx_int_t rc, size; ngx_str_t path; ngx_dir_t dir; ngx_uint_t i, level, utf8; ngx_pool_t *pool; ngx_time_t *tp; ngx_chain_t out; ngx_array_t entries; ngx_http_autoindex_entry_t *entry; ngx_http_autoindex_loc_conf_t *alcf; static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); if (!alcf->enable) { return NGX_DECLINED; } /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */ last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_AUTOINDEX_PREALLOCATE); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data; if (path.len > 1) { path.len--; } path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } #if (NGX_SUPPRESS_WARN) /* MSVC thinks 'entries' may be used without having been initialized */ ngx_memzero(&entries, sizeof(ngx_array_t)); #endif /* TODO: pool should be temporary pool */ pool = r->pool; if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t)) != NGX_OK) { return ngx_http_autoindex_error(r, &dir, &path); } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_type_len = sizeof("text/html") - 1; ngx_str_set(&r->headers_out.content_type, "text/html"); rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } return rc; } filename = path.data; filename[path.len] = '/'; if (r->headers_out.charset.len == 5 && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5) == 0) { utf8 = 1; } else { utf8 = 0; } for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_autoindex_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex file: \"%s\"", ngx_de_name(&dir)); len = ngx_de_namelen(&dir); if (ngx_de_name(&dir)[0] == '.') { continue; } if (!dir.valid_info) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_AUTOINDEX_PREALLOCATE; filename = ngx_pnalloc(pool, allocated); if (filename == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); if (err == NGX_EACCES) { continue; } return ngx_http_autoindex_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_autoindex_error(r, &dir, &path); } } } entry = ngx_array_push(&entries); if (entry == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } entry->name.len = len; entry->name.data = ngx_pnalloc(pool, len + 1); if (entry->name.data == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, NGX_ESCAPE_HTML); if (utf8) { entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); } else { entry->utf_len = len; } entry->colon = (ngx_strchr(entry->name.data, ':') != NULL); entry->dir = ngx_de_is_dir(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } len = sizeof(title) - 1 + r->uri.len + sizeof(header) - 1 + r->uri.len + sizeof("</h1>") - 1 + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1 + sizeof("</pre><hr>") - 1 + sizeof(tail) - 1; entry = entries.elts; for (i = 0; i < entries.nelts; i++) { len += sizeof("<a href=\"") - 1 + entry[i].name.len + entry[i].escape + 1 /* 1 is for "/" */ + sizeof("\">") - 1 + entry[i].name.len - entry[i].utf_len + entry[i].colon * 2 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 + sizeof("</a>") - 1 + sizeof(" 28-Sep-1970 12:00 ") - 1 + 20 /* the file size */ + 2; } b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (entries.nelts > 1) { ngx_qsort(entry, (size_t) entries.nelts, sizeof(ngx_http_autoindex_entry_t), ngx_http_autoindex_cmp_entries); } b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1); b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF, sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1); tp = ngx_timeofday(); for (i = 0; i < entries.nelts; i++) { b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1); if (entry[i].colon) { *b->last++ = '.'; *b->last++ = '/'; } if (entry[i].escape) { ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len, NGX_ESCAPE_HTML); b->last += entry[i].name.len + entry[i].escape; } else { b->last = ngx_cpymem(b->last, entry[i].name.data, entry[i].name.len); } if (entry[i].dir) { *b->last++ = '/'; } *b->last++ = '"'; *b->last++ = '>'; len = entry[i].utf_len; if (entry[i].name.len != len) { if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; } else { utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; } b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, utf_len, entry[i].name.len + 1); last = b->last; } else { b->last = ngx_cpystrn(b->last, entry[i].name.data, NGX_HTTP_AUTOINDEX_NAME_LEN + 1); last = b->last - 3; } if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { b->last = ngx_cpymem(last, "..></a>", sizeof("..></a>") - 1); } else { if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) { *b->last++ = '/'; len++; } b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1); ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len); b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len; } *b->last++ = ' '; ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ", tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1], tm.ngx_tm_year, tm.ngx_tm_hour, tm.ngx_tm_min); if (alcf->exact_size) { if (entry[i].dir) { b->last = ngx_cpymem(b->last, " -", sizeof(" -") - 1); } else { b->last = ngx_sprintf(b->last, "%19O", entry[i].size); } } else { if (entry[i].dir) { b->last = ngx_cpymem(b->last, " -", sizeof(" -") - 1); } else { length = entry[i].size; if (length > 1024 * 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024 * 1024)); if ((length % (1024 * 1024 * 1024)) > (1024 * 1024 * 1024 / 2 - 1)) { size++; } scale = 'G'; } else if (length > 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024)); if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { size++; } scale = 'M'; } else if (length > 9999) { size = (ngx_int_t) (length / 1024); if (length % 1024 > 511) { size++; } scale = 'K'; } else { size = (ngx_int_t) length; scale = '\0'; } if (scale) { b->last = ngx_sprintf(b->last, "%6i%c", size, scale); } else { b->last = ngx_sprintf(b->last, " %6i", size); } } } *b->last++ = CR; *b->last++ = LF; } /* TODO: free temporary pool */ b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1); b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); if (r == r->main) { b->last_buf = 1; } b->last_in_chain = 1; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
ngx_int_t ngx_http_vhost_traffic_status_filter_unique(ngx_pool_t *pool, ngx_array_t **keys) { uint32_t hash; u_char *p; ngx_str_t key; ngx_uint_t i, n; ngx_array_t *uniqs, *filter_keys; ngx_http_vhost_traffic_status_filter_t *filter, *filters; ngx_http_vhost_traffic_status_filter_uniq_t *filter_uniqs; if (*keys == NULL) { return NGX_OK; } uniqs = ngx_array_create(pool, 1, sizeof(ngx_http_vhost_traffic_status_filter_uniq_t)); if (uniqs == NULL) { return NGX_ERROR; } /* init array */ filter_keys = NULL; filter_uniqs = NULL; filters = (*keys)->elts; n = (*keys)->nelts; for (i = 0; i < n; i++) { key.len = filters[i].filter_key.value.len + filters[i].filter_name.value.len; key.data = ngx_pcalloc(pool, key.len); if (key.data == NULL) { return NGX_ERROR; } p = key.data; p = ngx_cpymem(p, filters[i].filter_key.value.data, filters[i].filter_key.value.len); ngx_memcpy(p, filters[i].filter_name.value.data, filters[i].filter_name.value.len); hash = ngx_crc32_short(key.data, key.len); filter_uniqs = ngx_array_push(uniqs); if (filter_uniqs == NULL) { return NGX_ERROR; } filter_uniqs->hash = hash; filter_uniqs->index = i; if (p != NULL) { ngx_pfree(pool, key.data); } } filter_uniqs = uniqs->elts; n = uniqs->nelts; ngx_qsort(filter_uniqs, (size_t) n, sizeof(ngx_http_vhost_traffic_status_filter_uniq_t), ngx_http_traffic_status_filter_cmp_hashs); hash = 0; for (i = 0; i < n; i++) { if (filter_uniqs[i].hash == hash) { continue; } hash = filter_uniqs[i].hash; if (filter_keys == NULL) { filter_keys = ngx_array_create(pool, 1, sizeof(ngx_http_vhost_traffic_status_filter_t)); if (filter_keys == NULL) { return NGX_ERROR; } } filter = ngx_array_push(filter_keys); if (filter == NULL) { return NGX_ERROR; } ngx_memcpy(filter, &filters[filter_uniqs[i].index], sizeof(ngx_http_vhost_traffic_status_filter_t)); } if ((*keys)->nelts != filter_keys->nelts) { *keys = filter_keys; } return NGX_OK; }
static ngx_inline ngx_int_t make_content_buf( ngx_http_request_t *r, ngx_buf_t **pb, ngx_http_fancyindex_loc_conf_t *alcf) { ngx_http_fancyindex_entry_t *entry; off_t length; size_t len, root, copy, allocated; u_char *filename, *last, scale; ngx_tm_t tm; ngx_array_t entries; ngx_time_t *tp; ngx_uint_t i; ngx_int_t size; ngx_str_t path; ngx_dir_t dir; ngx_buf_t *b; static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; /* * NGX_DIR_MASK_LEN is lesser than NGX_HTTP_FANCYINDEX_PREALLOCATE */ if ((last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_FANCYINDEX_PREALLOCATE)) == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; allocated = path.len; path.len = last - path.data - 1; path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { ngx_int_t rc, err = ngx_errno; ngx_uint_t level; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } #if (NGX_SUPPRESS_WARN) /* MSVC thinks 'entries' may be used without having been initialized */ ngx_memzero(&entries, sizeof(ngx_array_t)); #endif /* NGX_SUPPRESS_WARN */ if (ngx_array_init(&entries, r->pool, 40, sizeof(ngx_http_fancyindex_entry_t)) != NGX_OK) return ngx_http_fancyindex_error(r, &dir, &path); filename = path.data; filename[path.len] = '/'; /* Read directory entries and their associated information. */ for (;;) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { ngx_int_t err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_fancyindex_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex file: \"%s\"", ngx_de_name(&dir)); len = ngx_de_namelen(&dir); if (ngx_de_name(&dir)[0] == '.') continue; #if NGX_PCRE { ngx_str_t str = { len, ngx_de_name(&dir) }; if (alcf->ignore && ngx_regex_exec_array(alcf->ignore, &str, r->connection->log) != NGX_DECLINED) { continue; } } #else /* !NGX_PCRE */ if (alcf->ignore) { u_int match_found = 0; ngx_str_t *s = alcf->ignore->elts; for (i = 0; i < alcf->ignore->nelts; i++, s++) { if (ngx_strcmp(ngx_de_name(&dir), s->data) == 0) { match_found = 1; break; } } if (match_found) { continue; } } #endif /* NGX_PCRE */ if (!dir.valid_info) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_FANCYINDEX_PREALLOCATE; if ((filename = ngx_palloc(r->pool, allocated)) == NULL) return ngx_http_fancyindex_error(r, &dir, &path); last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { ngx_int_t err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_ERR, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); continue; } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_fancyindex_error(r, &dir, &path); } } } if ((entry = ngx_array_push(&entries)) == NULL) return ngx_http_fancyindex_error(r, &dir, &path); entry->name.len = len; entry->name.data = ngx_palloc(r->pool, len + 1); if (entry->name.data == NULL) return ngx_http_fancyindex_error(r, &dir, &path); ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); entry->escape = 2 * ngx_fancyindex_escape_uri(NULL, ngx_de_name(&dir), len); entry->dir = ngx_de_is_dir(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); entry->utf_len = (r->headers_out.charset.len == 5 && ngx_strncasecmp(r->headers_out.charset.data, (u_char*) "utf-8", 5) == 0) ? ngx_utf8_length(entry->name.data, entry->name.len) : len; } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } /* * Calculate needed buffer length. */ len = r->uri.len + ngx_sizeof_ssz(t05_body2) + ngx_sizeof_ssz(t06_list1) + ngx_sizeof_ssz(t07_list2) ; entry = entries.elts; for (i = 0; i < entries.nelts; i++) { /* * Genearated table rows are as follows, unneeded whitespace * is stripped out: * * <tr class="X"> * <td><a href="U">fname</a></td> * <td>size</td><td>date</td> * </tr> */ len += ngx_sizeof_ssz("<tr class=\"X\"><td><a href=\"") + entry[i].name.len + entry[i].escape /* Escaped URL */ + ngx_sizeof_ssz("\">") + entry[i].name.len + entry[i].utf_len + NGX_HTTP_FANCYINDEX_NAME_LEN + ngx_sizeof_ssz(">") + ngx_sizeof_ssz("</a></td><td>") + 20 /* File size */ + ngx_sizeof_ssz("</td><td>") + ngx_sizeof_ssz(" 28-Sep-1970 12:00 ") + ngx_sizeof_ssz("</td></tr>\n") + 2 /* CR LF */ ; } if ((b = ngx_create_temp_buf(r->pool, len)) == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; /* Sort entries, if needed */ if (entries.nelts > 1) { ngx_qsort(entry, (size_t) entries.nelts, sizeof(ngx_http_fancyindex_entry_t), ngx_http_fancyindex_cmp_entries); } b->last = ngx_cpymem_str(b->last, r->uri); b->last = ngx_cpymem_ssz(b->last, t05_body2); b->last = ngx_cpymem_ssz(b->last, t06_list1); tp = ngx_timeofday(); for (i = 0; i < entries.nelts; i++) { static const char _evenodd[] = { 'e', 'o' }; b->last = ngx_cpymem_ssz(b->last, "<tr class=\""); *b->last++ = _evenodd[i & 0x01]; /* * Alternative implementation: * *b->last++ = (i & 0x01) ? 'e' : 'o'; */ b->last = ngx_cpymem_ssz(b->last, "\"><td><a href=\""); if (entry[i].escape) { ngx_fancyindex_escape_uri(b->last, entry[i].name.data, entry[i].name.len); b->last += entry[i].name.len + entry[i].escape; } else { b->last = ngx_cpymem_str(b->last, entry[i].name); } if (entry[i].dir) { *b->last++ = '/'; } *b->last++ = '"'; *b->last++ = '>'; len = entry[i].utf_len; if (entry[i].name.len - len) { if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { copy = NGX_HTTP_FANCYINDEX_NAME_LEN - 3 + 1; } else { copy = NGX_HTTP_FANCYINDEX_NAME_LEN + 1; } b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, copy, entry[i].name.len); last = b->last; } else { b->last = ngx_cpystrn(b->last, entry[i].name.data, NGX_HTTP_FANCYINDEX_NAME_LEN + 1); last = b->last - 3; } if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { b->last = ngx_cpymem_ssz(last, "..></a></td><td>"); } else { if (entry[i].dir && NGX_HTTP_FANCYINDEX_NAME_LEN - len > 0) { *b->last++ = '/'; len++; } b->last = ngx_cpymem_ssz(b->last, "</a></td><td>"); } if (alcf->exact_size) { if (entry[i].dir) { *b->last++ = '-'; } else { b->last = ngx_sprintf(b->last, "%19O", entry[i].size); } } else { if (entry[i].dir) { *b->last++ = '-'; } else { length = entry[i].size; if (length > 1024 * 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024 * 1024)); if ((length % (1024 * 1024 * 1024)) > (1024 * 1024 * 1024 / 2 - 1)) { size++; } scale = 'G'; } else if (length > 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024)); if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { size++; } scale = 'M'; } else if (length > 9999) { size = (ngx_int_t) (length / 1024); if (length % 1024 > 511) { size++; } scale = 'K'; } else { size = (ngx_int_t) length; scale = '\0'; } if (scale) { b->last = ngx_sprintf(b->last, "%6i%c", size, scale); } else { b->last = ngx_sprintf(b->last, " %6i", size); } } } ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); b->last = ngx_sprintf(b->last, "</td><td>%02d-%s-%d %02d:%02d</td></tr>", tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1], tm.ngx_tm_year, tm.ngx_tm_hour, tm.ngx_tm_min); *b->last++ = CR; *b->last++ = LF; } /* Output table bottom */ b->last = ngx_cpymem_ssz(b->last, t07_list2); *pb = b; return NGX_OK; }
static ngx_int_t ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { u_char hash_buf[256]; ngx_int_t j, weight; ngx_uint_t sid, id, hash_len; ngx_uint_t i, n, *number, rnindex; ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_chash_server_t *server; ngx_http_upstream_chash_srv_conf_t *ucscf; if (ngx_http_upstream_init_round_robin(cf, us) == NGX_ERROR) { return NGX_ERROR; } ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_consistent_hash_module); if (ucscf == NULL) { return NGX_ERROR; } us->peer.init = ngx_http_upstream_init_chash_peer; peers = (ngx_http_upstream_rr_peers_t *) us->peer.data; if (peers == NULL) { return NGX_ERROR; } n = peers->number; ucscf->number = 0; ucscf->real_node = ngx_pcalloc(cf->pool, n * sizeof(ngx_http_upstream_chash_server_t**)); if (ucscf->real_node == NULL) { return NGX_ERROR; } for (i = 0; i < n; i++) { ucscf->number += peers->peer[i].weight * NGX_CHASH_VIRTUAL_NODE_NUMBER; ucscf->real_node[i] = ngx_pcalloc(cf->pool, (peers->peer[i].weight * NGX_CHASH_VIRTUAL_NODE_NUMBER + 1) * sizeof(ngx_http_upstream_chash_server_t*)); if (ucscf->real_node[i] == NULL) { return NGX_ERROR; } } ucscf->servers = ngx_pcalloc(cf->pool, (ucscf->number + 1) * sizeof(ngx_http_upstream_chash_server_t)); if (ucscf->servers == NULL) { return NGX_ERROR; } ucscf->d_servers = ngx_pcalloc(cf->pool, (ucscf->number + 1) * sizeof(ngx_http_upstream_chash_down_server_t)); if (ucscf->d_servers == NULL) { return NGX_ERROR; } ucscf->number = 0; for (i = 0; i < n; i++) { peer = &peers->peer[i]; sid = (ngx_uint_t) ngx_atoi(peer->id.data, peer->id.len); if (sid == (ngx_uint_t) NGX_ERROR || sid > 65535) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "server id %d", sid); ngx_snprintf(hash_buf, 256, "%V%Z", &peer->name); hash_len = ngx_strlen(hash_buf); sid = ngx_murmur_hash2(hash_buf, hash_len); } weight = peer->weight * NGX_CHASH_VIRTUAL_NODE_NUMBER; if (weight >= 1 << 14) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, "weigth[%d] is too large, is must be less than %d", weight / NGX_CHASH_VIRTUAL_NODE_NUMBER, (1 << 14) / NGX_CHASH_VIRTUAL_NODE_NUMBER); weight = 1 << 14; } for (j = 0; j < weight; j++) { server = &ucscf->servers[++ucscf->number]; server->peer = peer; server->rnindex = i; id = sid * 256 * 16 + j; server->hash = ngx_murmur_hash2((u_char *) (&id), 4); } } ngx_qsort(ucscf->servers + 1, ucscf->number, sizeof(ngx_http_upstream_chash_server_t), (const void *)ngx_http_upstream_chash_cmp); number = ngx_calloc(n * sizeof(ngx_uint_t), cf->log); if (number == NULL) { return NGX_ERROR; } for (i = 1; i <= ucscf->number; i++) { ucscf->servers[i].index = i; ucscf->d_servers[i].id = i; rnindex = ucscf->servers[i].rnindex; ucscf->real_node[rnindex][number[rnindex]] = &ucscf->servers[i]; number[rnindex]++; } ngx_free(number); ucscf->tree = ngx_pcalloc(cf->pool, sizeof(ngx_segment_tree_t)); if (ucscf->tree == NULL) { return NGX_ERROR; } ngx_segment_tree_init(ucscf->tree, ucscf->number, cf->pool); ucscf->tree->build(ucscf->tree, 1, 1, ucscf->number); ngx_queue_init(&ucscf->down_servers); return NGX_OK; }
ngx_int_t ngx_http_upstream_init_consistent_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { /* ip max 15, :port max 6, maxweight is highest number of uchar */ u_char *last, hash_data[28]; uint32_t step; ngx_uint_t i, j, k, n; ngx_uint_t real_nodes, points_per_node; ngx_http_upstream_server_t *server; ngx_http_upstream_rr_peer_t *rr_peer; ngx_http_upstream_rr_peers_t *prr_peers; ngx_http_upstream_consistent_hash_buckets *buckets; ngx_http_upstream_consistent_hash_continuum *continuum; ngx_http_upstream_consistent_hash_srv_conf_t *uchscf; uchscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_consistent_hash_module); if (uchscf == NULL) { return NGX_ERROR; } if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { return NGX_ERROR; } prr_peers = us->peer.data; us->peer.init = ngx_http_upstream_init_consistent_hash_peer; buckets = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_buckets)); if (!us->servers) { return NGX_ERROR; } server = us->servers->elts; n = real_nodes = 0; for (i = 0; i < us->servers->nelts; i++) { n += server[i].naddrs; real_nodes += server[i].weight * server[i].naddrs; } /* * The optimal points number is Q/S * See the section 6.2 from the paper 'Dynamo: Amazon's Highly Available * Key-value Store' */ points_per_node = (ngx_uint_t) MMC_CONSISTENT_BUCKETS / real_nodes; if (points_per_node == 0) { points_per_node = 1; } continuum = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_continuum)); continuum->nodes = ngx_palloc(cf->pool, sizeof(ngx_http_upstream_consistent_hash_node) * MMC_CONSISTENT_BUCKETS); for (i = 0; i < us->servers->nelts; i++) { for (j = 0; j < server[i].naddrs; j++) { rr_peer = ngx_http_upstream_consistent_hash_find_rr_peer(prr_peers, server[i].addrs[j].sockaddr); if (rr_peer == NULL) { return NGX_ERROR; } for (k = 0; k < (points_per_node * server[i].weight); k++) { last = ngx_snprintf(hash_data, 28, "%V-%ui", &server[i].addrs[j].name, k); continuum->nodes[continuum->nnodes].point = ngx_http_upstream_consistent_hash_node_point(hash_data, (last - hash_data)); continuum->nodes[continuum->nnodes].rr_peer = rr_peer; continuum->nnodes++; } } } ngx_qsort(continuum->nodes, continuum->nnodes, sizeof(ngx_http_upstream_consistent_hash_node), (const void*) ngx_http_upstream_consistent_hash_compare_continuum_nodes); step = (uint32_t) (0xffffffff / MMC_CONSISTENT_BUCKETS); for (i = 0; i < MMC_CONSISTENT_BUCKETS; i++) { buckets->bucket[i] = ngx_http_upstream_consistent_hash_find(continuum, step * i); } #if (CONSISTENT_DEBUG) ngx_http_upstream_consistent_hash_print_continuum(cf, continuum); ngx_http_upstream_consistent_hash_print_buckets(cf, buckets); #endif buckets->continuum = continuum; uchscf->data = buckets; return NGX_OK; }
static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_http_referer_conf_t *prev = parent; ngx_http_referer_conf_t *conf = child; ngx_uint_t n; ngx_hash_init_t hash; ngx_http_server_name_t *sn; ngx_http_core_srv_conf_t *cscf; if (conf->keys == NULL) { conf->hash = prev->hash; #if (NGX_PCRE) ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); ngx_conf_merge_ptr_value(conf->server_name_regex, prev->server_name_regex, NULL); #endif ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); ngx_conf_merge_uint_value(conf->referer_hash_max_size, prev->referer_hash_max_size, 2048); ngx_conf_merge_uint_value(conf->referer_hash_bucket_size, prev->referer_hash_bucket_size, 64); return NGX_CONF_OK; } if (conf->server_names == 1) { cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); sn = cscf->server_names.elts; for (n = 0; n < cscf->server_names.nelts; n++) { #if (NGX_PCRE) if (sn[n].regex) { if (ngx_http_add_regex_server_name(cf, conf, sn[n].regex) != NGX_OK) { return NGX_CONF_ERROR; } continue; } #endif if (ngx_http_add_referer(cf, conf->keys, &sn[n].name, NULL) != NGX_OK) { return NGX_CONF_ERROR; } } } if ((conf->no_referer == 1 || conf->blocked_referer == 1) && conf->keys->keys.nelts == 0 && conf->keys->dns_wc_head.nelts == 0 && conf->keys->dns_wc_tail.nelts == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "the \"none\" or \"blocked\" referers are specified " "in the \"valid_referers\" directive " "without any valid referer"); return NGX_CONF_ERROR; } ngx_conf_merge_uint_value(conf->referer_hash_max_size, prev->referer_hash_max_size, 2048); ngx_conf_merge_uint_value(conf->referer_hash_bucket_size, prev->referer_hash_bucket_size, 64); conf->referer_hash_bucket_size = ngx_align(conf->referer_hash_bucket_size, ngx_cacheline_size); hash.key = ngx_hash_key_lc; hash.max_size = conf->referer_hash_max_size; hash.bucket_size = conf->referer_hash_bucket_size; hash.name = "referer_hash"; hash.pool = cf->pool; if (conf->keys->keys.nelts) { hash.hash = &conf->hash.hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) != NGX_OK) { return NGX_CONF_ERROR; } } if (conf->keys->dns_wc_head.nelts) { ngx_qsort(conf->keys->dns_wc_head.elts, (size_t) conf->keys->dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_referer_wildcards); hash.hash = NULL; hash.temp_pool = cf->temp_pool; if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts, conf->keys->dns_wc_head.nelts) != NGX_OK) { return NGX_CONF_ERROR; } conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; } if (conf->keys->dns_wc_tail.nelts) { ngx_qsort(conf->keys->dns_wc_tail.elts, (size_t) conf->keys->dns_wc_tail.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_referer_wildcards); hash.hash = NULL; hash.temp_pool = cf->temp_pool; if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_tail.elts, conf->keys->dns_wc_tail.nelts) != NGX_OK) { return NGX_CONF_ERROR; } conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } #if (NGX_PCRE) ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); ngx_conf_merge_ptr_value(conf->server_name_regex, prev->server_name_regex, NULL); #endif if (conf->no_referer == NGX_CONF_UNSET) { conf->no_referer = 0; } if (conf->blocked_referer == NGX_CONF_UNSET) { conf->blocked_referer = 0; } conf->keys = NULL; return NGX_CONF_OK; }
static char * ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_map_conf_t *mcf = conf; char *rv; ngx_str_t *value, name; ngx_conf_t save; ngx_pool_t *pool; ngx_hash_init_t hash; ngx_http_map_ctx_t *map; ngx_http_variable_t *var; ngx_http_map_conf_ctx_t ctx; ngx_http_compile_complex_value_t ccv; if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) { mcf->hash_max_size = 2048; } if (mcf->hash_bucket_size == NGX_CONF_UNSET_UINT) { mcf->hash_bucket_size = ngx_cacheline_size; } else { mcf->hash_bucket_size = ngx_align(mcf->hash_bucket_size, ngx_cacheline_size); } map = ngx_pcalloc(cf->pool, sizeof(ngx_http_map_ctx_t)); if (map == NULL) { return NGX_CONF_ERROR; } value = cf->args->elts; ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); ccv.cf = cf; ccv.value = &value[1]; ccv.complex_value = &map->value; if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } name = value[2]; if (name.data[0] != '$') { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid variable name \"%V\"", &name); return NGX_CONF_ERROR; } name.len--; name.data++; var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); if (var == NULL) { return NGX_CONF_ERROR; } var->get_handler = ngx_http_map_variable; var->data = (uintptr_t) map; pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); if (pool == NULL) { return NGX_CONF_ERROR; } ctx.keys.pool = cf->pool; ctx.keys.temp_pool = pool; if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } ctx.values_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * ctx.keys.hsize); if (ctx.values_hash == NULL) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } #if (NGX_PCRE) if (ngx_array_init(&ctx.regexes, cf->pool, 2, sizeof(ngx_http_map_regex_t)) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } #endif ctx.default_value = NULL; ctx.cf = &save; ctx.hostnames = 0; ctx.no_cacheable = 0; save = *cf; cf->pool = pool; cf->ctx = &ctx; cf->handler = ngx_http_map; cf->handler_conf = conf; rv = ngx_conf_parse(cf, NULL); *cf = save; if (rv != NGX_CONF_OK) { ngx_destroy_pool(pool); return rv; } if (ctx.no_cacheable) { var->flags |= NGX_HTTP_VAR_NOCACHEABLE; } map->default_value = ctx.default_value ? ctx.default_value: &ngx_http_variable_null_value; map->hostnames = ctx.hostnames; hash.key = ngx_hash_key_lc; hash.max_size = mcf->hash_max_size; hash.bucket_size = mcf->hash_bucket_size; hash.name = "map_hash"; hash.pool = cf->pool; if (ctx.keys.keys.nelts) { hash.hash = &map->map.hash.hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } } if (ctx.keys.dns_wc_head.nelts) { ngx_qsort(ctx.keys.dns_wc_head.elts, (size_t) ctx.keys.dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = pool; if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts, ctx.keys.dns_wc_head.nelts) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; } if (ctx.keys.dns_wc_tail.nelts) { ngx_qsort(ctx.keys.dns_wc_tail.elts, (size_t) ctx.keys.dns_wc_tail.nelts, sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = pool; if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts, ctx.keys.dns_wc_tail.nelts) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } #if (NGX_PCRE) if (ctx.regexes.nelts) { map->map.regex = ctx.regexes.elts; map->map.nregex = ctx.regexes.nelts; } #endif ngx_destroy_pool(pool); return rv; }
static ngx_int_t ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_http_conf_addr_t *addr) { ngx_int_t rc; ngx_uint_t n, s; ngx_hash_init_t hash; ngx_hash_keys_arrays_t ha; ngx_http_server_name_t *name; ngx_http_core_srv_conf_t **cscfp; #if (NGX_PCRE) ngx_uint_t regex, i; regex = 0; #endif ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t)); ha.temp_pool = ngx_create_pool(16384, cf->log); if (ha.temp_pool == NULL) { return NGX_ERROR; } ha.pool = cf->pool; if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { goto failed; } cscfp = addr->servers.elts; for (s = 0; s < addr->servers.nelts; s++) { name = cscfp[s]->server_names.elts; for (n = 0; n < cscfp[s]->server_names.nelts; n++) { #if (NGX_PCRE) if (name[n].regex) { regex++; continue; } #endif rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server, NGX_HASH_WILDCARD_KEY); if (rc == NGX_ERROR) { return NGX_ERROR; } if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "invalid server name or wildcard \"%V\" on %s", &name[n].name, addr->opt.addr); return NGX_ERROR; } if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, "conflicting server name \"%V\" on %s, ignored", &name[n].name, addr->opt.addr); } } } hash.key = ngx_hash_key_lc; hash.max_size = cmcf->server_names_hash_max_size; hash.bucket_size = cmcf->server_names_hash_bucket_size; hash.name = "server_names_hash"; hash.pool = cf->pool; if (ha.keys.nelts) { hash.hash = &addr->hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) { goto failed; } } if (ha.dns_wc_head.nelts) { ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = ha.temp_pool; if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, ha.dns_wc_head.nelts) != NGX_OK) { goto failed; } addr->wc_head = (ngx_hash_wildcard_t *) hash.hash; } if (ha.dns_wc_tail.nelts) { ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = ha.temp_pool; if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts, ha.dns_wc_tail.nelts) != NGX_OK) { goto failed; } addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash; } ngx_destroy_pool(ha.temp_pool); #if (NGX_PCRE) if (regex == 0) { return NGX_OK; } addr->nregex = regex; addr->regex = ngx_palloc(cf->pool, regex * sizeof(ngx_http_server_name_t)); if (addr->regex == NULL) { return NGX_ERROR; } i = 0; for (s = 0; s < addr->servers.nelts; s++) { name = cscfp[s]->server_names.elts; for (n = 0; n < cscfp[s]->server_names.nelts; n++) { if (name[n].regex) { addr->regex[i++] = name[n]; } } } #endif return NGX_OK; failed: ngx_destroy_pool(ha.temp_pool); return NGX_ERROR; }
static char * ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_map_conf_t *mcf = conf; char *rv; ngx_str_t *value, name; ngx_conf_t save; ngx_pool_t *pool; ngx_hash_init_t hash; ngx_http_map_ctx_t *map; ngx_http_variable_t *var; ngx_http_map_conf_ctx_t ctx; if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) { mcf->hash_max_size = 2048; } if (mcf->hash_bucket_size == NGX_CONF_UNSET_UINT) { mcf->hash_bucket_size = ngx_cacheline_size; } else { mcf->hash_bucket_size = ngx_align(mcf->hash_bucket_size, ngx_cacheline_size); } map = ngx_pcalloc(cf->pool, sizeof(ngx_http_map_ctx_t)); if (map == NULL) { return NGX_CONF_ERROR; } value = cf->args->elts; name = value[1]; name.len--; name.data++; map->index = ngx_http_get_variable_index(cf, &name); if (map->index == NGX_ERROR) { return NGX_CONF_ERROR; } name = value[2]; name.len--; name.data++; var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); if (var == NULL) { return NGX_CONF_ERROR; } var->get_handler = ngx_http_map_variable; var->data = (uintptr_t) map; pool = ngx_create_pool(16384, cf->log); if (pool == NULL) { return NGX_CONF_ERROR; } ctx.keys.pool = cf->pool; ctx.keys.temp_pool = pool; if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } ctx.values_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * ctx.keys.hsize); if (ctx.values_hash == NULL) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } ctx.default_value = NULL; ctx.hostnames = 0; save = *cf; cf->pool = pool; cf->ctx = &ctx; cf->handler = ngx_http_map; cf->handler_conf = conf; rv = ngx_conf_parse(cf, NULL); *cf = save; if (rv != NGX_CONF_OK) { ngx_destroy_pool(pool); return rv; } map->default_value = ctx.default_value ? ctx.default_value: &ngx_http_variable_null_value; hash.key = ngx_hash_key_lc; hash.max_size = mcf->hash_max_size; hash.bucket_size = mcf->hash_bucket_size; hash.name = "map_hash"; hash.pool = cf->pool; if (ctx.keys.keys.nelts) { hash.hash = &map->hash.hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } } if (ctx.keys.dns_wc_head.nelts) { ngx_qsort(ctx.keys.dns_wc_head.elts, (size_t) ctx.keys.dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = pool; if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts, ctx.keys.dns_wc_head.nelts) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } map->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; } if (ctx.keys.dns_wc_tail.nelts) { ngx_qsort(ctx.keys.dns_wc_tail.elts, (size_t) ctx.keys.dns_wc_tail.nelts, sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = pool; if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts, ctx.keys.dns_wc_tail.nelts) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } map->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } ngx_destroy_pool(pool); return rv; }
static char * ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_http_browser_conf_t *prev = parent; ngx_http_browser_conf_t *conf = child; ngx_uint_t i, n; ngx_http_modern_browser_t *browsers, *opera; /* * At the merge the skip field is used to store the browser slot, * it will be used in sorting and then will overwritten * with a real skip value. The zero value means Opera. */ if (conf->modern_browsers == NULL) { conf->modern_browsers = prev->modern_browsers; } else { browsers = conf->modern_browsers->elts; for (i = 0; i < conf->modern_browsers->nelts; i++) { if (browsers[i].skip == 0) { goto found; } } /* * Opera may contain MSIE string, so if Opera was not enumerated * as modern browsers, then add it and set a unreachable version */ opera = ngx_array_push(conf->modern_browsers); if (opera == NULL) { return NGX_CONF_ERROR; } opera->skip = 0; opera->version = 4001000000U; browsers = conf->modern_browsers->elts; found: ngx_qsort(browsers, (size_t) conf->modern_browsers->nelts, sizeof(ngx_http_modern_browser_t), ngx_http_modern_browser_sort); for (i = 0; i < conf->modern_browsers->nelts; i++) { n = browsers[i].skip; browsers[i].skip = ngx_http_modern_browser_masks[n].skip; browsers[i].add = ngx_http_modern_browser_masks[n].add; (void) ngx_cpystrn(browsers[i].name, ngx_http_modern_browser_masks[n].name, 12); } } if (conf->ancient_browsers == NULL) { conf->ancient_browsers = prev->ancient_browsers; } if (conf->modern_browser_value == NULL) { conf->modern_browser_value = prev->modern_browser_value; } if (conf->modern_browser_value == NULL) { conf->modern_browser_value = &ngx_http_variable_true_value; } if (conf->ancient_browser_value == NULL) { conf->ancient_browser_value = prev->ancient_browser_value; } if (conf->ancient_browser_value == NULL) { conf->ancient_browser_value = &ngx_http_variable_true_value; } return NGX_CONF_OK; }