static ngx_int_t ngx_buffer_cache_init(ngx_shm_zone_t *shm_zone, void *data) { ngx_buffer_cache_sh_t *sh; ngx_buffer_cache_t *ocache = data; ngx_buffer_cache_t *cache; u_char* p; cache = shm_zone->data; if (ocache) { cache->sh = ocache->sh; cache->shpool = ocache->shpool; return NGX_OK; } cache->shpool = (ngx_slab_pool_t *)shm_zone->shm.addr; if (shm_zone->shm.exists) { cache->sh = cache->shpool->data; return NGX_OK; } // start following the ngx_slab_pool_t that was allocated at the beginning of the chunk p = shm_zone->shm.addr + sizeof(ngx_slab_pool_t); // initialize the log context cache->shpool->log_ctx = p; p = ngx_sprintf(cache->shpool->log_ctx, " in buffer cache \"%V\"%Z", &shm_zone->shm.name); // allocate the shared cache state p = ngx_align_ptr(p, sizeof(void *)); sh = (ngx_buffer_cache_sh_t*)p; p += sizeof(*sh); cache->sh = sh; cache->shpool->data = sh; // initialize fixed cache fields p = ngx_align_ptr(p, sizeof(void *)); sh->entries_start = (ngx_buffer_cache_entry_t*)p; sh->buffers_end = shm_zone->shm.addr + shm_zone->shm.size; sh->access_time = 0; // reset the stats ngx_memzero(&sh->stats, sizeof(sh->stats)); // reset the cache status ngx_buffer_cache_reset(sh); sh->reset = 0; return NGX_OK; }
ngx_int_t ngx_crc32_table_init(void) { void *p; if (((uintptr_t) ngx_crc32_table_short & ~((uintptr_t) ngx_cacheline_size - 1)) == (uintptr_t) ngx_crc32_table_short) { return NGX_OK; } p = ngx_alloc(16 * sizeof(uint32_t) + ngx_cacheline_size, ngx_cycle->log); if (p == NULL) { return NGX_ERROR; } p = ngx_align_ptr(p, ngx_cacheline_size); ngx_memcpy(p, ngx_crc32_table16, 16 * sizeof(uint32_t)); ngx_crc32_table_short = p; return NGX_OK; }
void * ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len) { ngx_uint_t i; ngx_hash_elt_t *elt; #if 0 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%*s\"", len, name); #endif elt = hash->buckets[key % hash->size]; if (elt == NULL) { return NULL; } while (elt->value) { if (len != (size_t) elt->len) { goto next; } for (i = 0; i < len; i++) { if (name[i] != elt->name[i]) { goto next; } } return elt->value; next: elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); continue; } return NULL; }
static void * ngx_palloc_block(ngx_pool_t *pool, size_t size) { unsigned char *m; size_t psize = (size_t)(pool->d.end - (unsigned char *)pool); ngx_pool_t *p, *p_new; m = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); if (!m) return NULL; p_new = (ngx_pool_t *)m; p_new->d.end = m + psize; p_new->d.next = NULL; p_new->d.failed = 0; m += sizeof(ngx_pool_data_t); m = ngx_align_ptr(m, NGX_ALIGNMENT); p_new->d.last = m + size; for (p = pool->curr; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) pool->curr = p->d.next; } p->d.next = p_new; return m; }
void * ngx_palloc(ngx_pool_t *pool, size_t size) { u_char *m; ngx_pool_t *p; if (size <= pool->max) { p = pool->current; do { m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); if ((size_t) (p->d.end - m) >= size) { p->d.last = m + size; return m; } p = p->d.next; } while (p); return ngx_palloc_block(pool, size); } return ngx_palloc_large(pool, size); }
ngx_array_t *dvt_stringhash_to_array(dvt_stringhash_t* hash, ngx_pool_t* pool) { ngx_array_t* result; dvt_stringhash_elt_t *elt; int i; int* v; result = ngx_array_create(pool, 32, sizeof(int)); for (i = 0; i<hash->size; ++i) { if (hash->buckets[i] == NULL) { continue; } while(elt->value) { v = ngx_array_push(result); *v = *((int *)elt->value); elt = (dvt_stringhash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); } } return result; }
void ngx_http_lua_limit_data_segment(void) { if (sbrk(0) < (void *) 0x40000000LL) { mmap(ngx_align_ptr(sbrk(0), getpagesize()), 1, PROT_READ, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); } }
void dump_hash_wildcard(ngx_hash_t *hash) { ngx_uint_t loop; char prefix[] = " "; ngx_hash_wildcard_t *wdc; if (hash == NULL) return; printf("hash = %p: **buckets = %p, size = %d\n", hash, hash->buckets, hash->size); for (loop = 0; loop < hash->size; loop++) { ngx_hash_elt_t *elt = hash->buckets[loop]; printf(" %p: buckets[%d] = %p\n", &(hash->buckets[loop]), loop, elt); if (elt) { while (elt->value) { uintptr_t value = (uintptr_t)elt->value; if ((value & 3) == 0 || (value & 3) == 1) //注意位操作与逻辑运算符的优先级 { value &= (uintptr_t)~3; //值得参考的是%.*s的输出,通过参数控制输出字符的个数 printf(" buckets %d: 0x%p {value = \"%.*s\"%.*s, len = %d, name = \"%.*s\"%.*s}\n", loop, elt, ((ngx_str_t*)value)->len, ((ngx_str_t*)value)->data, Max_Ip_Len - ((ngx_str_t*)value)->len, prefix, elt->len, elt->len, elt->name, Max_Url_Len - elt->len, prefix); } else { wdc = (ngx_hash_wildcard_t *)(value & (uintptr_t)~3); printf(" buckets %d: %p: {value = \"%-16p\", len = %d, name = \"%.*s\"%.*s}\n", loop, elt, wdc, elt->len, elt->len, elt->name, Max_Url_Len - elt->len, prefix); dump_hash_wildcard(&wdc->hash); } elt = (ngx_hash_elt_t *)ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); } } } }
static void * ngx_palloc_block(ngx_pool_t *pool, size_t size) { u_char *m; size_t psize; ngx_pool_t *p, *newp, *current; psize = (size_t) (pool->d.end - (u_char *) pool); m = (u_char*)ngx_memalign(NGX_POOL_ALIGNMENT, psize/*, pool->log*/); if (m == NULL) { return NULL; } newp = (ngx_pool_t *) m; newp->d.end = m + psize; newp->d.next = NULL; newp->d.failed = 0; m += sizeof(ngx_pool_data_t); m = ngx_align_ptr(m, NGX_ALIGNMENT); newp->d.last = m + size; current = pool->current; for (p = current; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) { current = p->d.next; } } p->d.next = newp; pool->current = current ? current : newp; return m; }
ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { u_char *elts; size_t len; u_short *test; ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; for (n = 0; n < nelts; n++) { if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should " "increase %s_bucket_size: %i", hinit->name, hinit->name, hinit->bucket_size); return NGX_ERROR; } } test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log); if (test == NULL) { return NGX_ERROR; } bucket_size = hinit->bucket_size - sizeof(void *); start = nelts / (bucket_size / (2 * sizeof(void *))); start = start ? start : 1; if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) { start = hinit->max_size - 1000; } for (size = start; size <= hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %ui %ui \"%V\"", size, key, test[key], &names[n].key); #endif if (test[key] > (u_short) bucket_size) { goto next; } } goto found; next: continue; } ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0, "could not build optimal %s, you should increase " "either %s_max_size: %i or %s_bucket_size: %i; " "ignoring %s_bucket_size", hinit->name, hinit->name, hinit->max_size, hinit->name, hinit->bucket_size, hinit->name); found: for (i = 0; i < size; i++) { test[i] = sizeof(void *); } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } len = 0; for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size)); len += test[i]; } if (hinit->hash == NULL) { hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + size * sizeof(ngx_hash_elt_t *)); if (hinit->hash == NULL) { ngx_free(test); return NGX_ERROR; } buckets = (ngx_hash_elt_t **) ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t)); } else { buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *)); if (buckets == NULL) { ngx_free(test); return NGX_ERROR; } } elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size); if (elts == NULL) { ngx_free(test); return NGX_ERROR; } elts = ngx_align_ptr(elts, ngx_cacheline_size); for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; } for (i = 0; i < size; i++) { test[i] = 0; } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]); elt->value = names[n].value; elt->len = (u_short) names[n].key.len; ngx_strlow(elt->name, names[n].key.data, names[n].key.len); test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } for (i = 0; i < size; i++) { if (buckets[i] == NULL) { continue; } elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]); elt->value = NULL; } ngx_free(test); hinit->hash->buckets = buckets; hinit->hash->size = size; #if 0 for (i = 0; i < size; i++) { ngx_str_t val; ngx_uint_t key; elt = buckets[i]; if (elt == NULL) { ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: NULL", i); continue; } while (elt->value) { val.len = elt->len; val.data = &elt->name[0]; key = hinit->key(val.data, val.len); ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %p \"%V\" %ui", i, elt, &val, key); elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); } } #endif return NGX_OK; }
static ngx_int_t ngx_wd_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { u_char *elts; size_t len; u_short *test; ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; for (n = 0; n < nelts; n++) { if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should " "increase %s_bucket_size: %i", hinit->name, hinit->name, hinit->bucket_size); return NGX_ERROR; } } test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log); if (test == NULL) { return NGX_ERROR; } bucket_size = hinit->bucket_size - sizeof(void *); start = nelts / (bucket_size / (2 * sizeof(void *))); start = start ? start : 1; if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) { start = hinit->max_size - 1000; } for (size = start; size < hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); if (test[key] > (u_short) bucket_size) { goto next; } } goto found; next: continue; } ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should increase " "either %s_max_size: %i or %s_bucket_size: %i", hinit->name, hinit->name, hinit->max_size, hinit->name, hinit->bucket_size); ngx_free(test); return NGX_ERROR; found: for (i = 0; i < size; i++) { test[i] = sizeof(void *); } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } len = 0; for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size)); len += test[i]; } if (hinit->hash == NULL) { hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + size * sizeof(ngx_hash_elt_t *)); if (hinit->hash == NULL) { ngx_free(test); return NGX_ERROR; } buckets = (ngx_hash_elt_t **) ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t)); } else { buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *)); if (buckets == NULL) { ngx_free(test); return NGX_ERROR; } } elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size); if (elts == NULL) { ngx_free(test); return NGX_ERROR; } elts = ngx_align_ptr(elts, ngx_cacheline_size); for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; } for (i = 0; i < size; i++) { test[i] = 0; } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]); elt->value = names[n].value; elt->len = (u_short) names[n].key.len; strncpy((char *)elt->name, (char *)names[n].key.data, names[n].key.len); test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } for (i = 0; i < size; i++) { if (buckets[i] == NULL) { continue; } elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]); elt->value = NULL; } ngx_free(test); hinit->hash->buckets = buckets; hinit->hash->size = size; return NGX_OK; }
void ngx_slab_init(ngx_slab_pool_t *pool) { u_char *p; size_t size; ngx_int_t m; ngx_uint_t i, n, pages; ngx_slab_page_t *slots, *page; pool->min_size = (size_t) 1 << pool->min_shift; slots = ngx_slab_slots(pool); p = (u_char *) slots; size = pool->end - p; ngx_slab_junk(p, size); n = ngx_pagesize_shift - pool->min_shift; for (i = 0; i < n; i++) { /* only "next" is used in list head */ slots[i].slab = 0; slots[i].next = &slots[i]; slots[i].prev = 0; } p += n * sizeof(ngx_slab_page_t); pool->stats = (ngx_slab_stat_t *) p; ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t)); p += n * sizeof(ngx_slab_stat_t); size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t)); pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t))); pool->pages = (ngx_slab_page_t *) p; ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t)); page = pool->pages; /* only "next" is used in list head */ pool->free.slab = 0; pool->free.next = page; pool->free.prev = 0; page->slab = pages; page->next = &pool->free; page->prev = (uintptr_t) &pool->free; pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t), ngx_pagesize); m = pages - (pool->end - pool->start) / ngx_pagesize; if (m > 0) { pages -= m; page->slab = pages; } pool->last = pool->pages + pages; pool->pfree = pages; pool->log_nomem = 1; pool->log_ctx = &pool->zero; pool->zero = '\0'; }
int main(int argc, char *const *argv) { void *ret; void *freeptr; ngx_pool_t *curptr; ngx_int_t rlt; printf("--------pool Test---------\n"); ngx_pool_t *pool; int i=0; unit_create_log(); /*The the value of the ngx_pool_s.max be wrong if missing this call. *Because the ngx_pagesize = getpagesize() should be call for getting real page size. *In function ngx_create_pool: * #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1) * size = size - sizeof(ngx_pool_t); * p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL; *The max will be size - sizeof(ngx_pool_t) */ ngx_os_init(mylog); ngx_log_error_core(NGX_LOG_NOTICE, mylog, 0,"ngx_create_pool size:%d", NGX_CYCLE_POOL_SIZE); printf("--System memory setting---------\n"); printf("Value of NGX_DEFAULT_POOL_SIZE size = %d\n", NGX_CYCLE_POOL_SIZE); printf("Value of ngx_pagesize:getpagesize() = %d\n", getpagesize()); printf("Value of NGX_MAX_ALLOC_FROM_POOL£ºngx_pagesize-1= %d\n", NGX_MAX_ALLOC_FROM_POOL); printf("size of ngx_pool_data_t = %d\n", sizeof(ngx_pool_data_t)); printf("size of ngx_pool_t = %d\n", sizeof(ngx_pool_t)); printf("size of ngx_pool_large_t= %d\n", sizeof(ngx_pool_large_t)); printf("\n\n--------ngx_create_pool--------\n"); //#define NGX_DEFAULT_POOL_SIZE (16 * 1024) printf("ngx_create_pool using NGX_DEFAULT_POOL_SIZE size = %d\n", NGX_CYCLE_POOL_SIZE); printf("--------------------------------------\n"); pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, mylog); if (pool == NULL) { return NULL; } dump_pool(pool); printf("\n--------size of ngx_align_ptr(p, a):--------\n"); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); printf("NGX_ALIGNMENT = %d\n", NGX_ALIGNMENT); printf("\n--------alloc block 1024 from the pool:--------\n"); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); ret = ngx_palloc(pool, 1024); printf("--------return address:0x%p--------\n",ret); dump_pool(pool); printf("--------alloc block 1000 from the pool:--------\n"); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); ret = ngx_palloc(pool, 1000); printf("--------return address:0x%p--------\n",ret); dump_pool(pool); #if (TEST_ngx_palloc_large) printf("--------alloc large block 3 from the pool:--------\n"); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); ret = ngx_palloc(pool, 3*1024); printf("--------return address:0x%p--------\n",ret); dump_pool(pool); printf("--------alloc large block 4 from the pool:--------\n"); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); ret = ngx_palloc(pool, 4*1024); freeptr = ret; printf("--------return address:0x%p--------\n",ret); dump_pool(pool); printf("--------alloc large block 5 from the pool:--------\n"); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); ret = ngx_palloc(pool, 5*1024); printf("--------return address:0x%p--------\n",ret); dump_pool(pool); printf("--------free large block 4 from the pool:--------\n"); printf("block 4 address = p\n", freeptr); rlt = ngx_pfree(pool,freeptr); if (rlt == NGX_OK){ printf("block 4 address deleted\n"); dump_pool(pool); } else{ printf("ngx_pfree return error=%d\n",rlt); } printf("--------alloc large block 6 from the pool:--------\n"); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); ret = ngx_palloc(pool, 6*1024); printf("--------return address:0x%p--------\n",ret); dump_pool(pool); #endif #if (TEST_ngx_palloc_block) for(i=0;i<30;i++){ printf("--------Loop alloc block 1024 from the pool:[%d]--------\n",i); printf("pool->d.last=%p,size of ngx_align_ptr(p, a) = %p\n",pool->d.last,ngx_align_ptr(pool->d.last, NGX_ALIGNMENT)); ret = ngx_palloc(pool, 4095); printf("--------return address:0x%p--------\n",ret); dump_pool(pool); } #endif #if (TEST_ngx_pool_cleanup_add) printf("\n--------test for ngx_pool_cleanup_add : --------\n"); ngx_pool_cleanup_t *cln; void *buf; buf = ngx_pcalloc(pool, 100); cln = ngx_pool_cleanup_add(pool, 0); if (cln == NULL) { printf("\n--------ngx_pool_cleanup_add failure --------\n"); return NGX_ERROR; } cln->handler = ngx_cleanup_callback; cln->data = buf; #endif printf("\n--------call ngx_destroy_pool--------\n"); dump_pool(pool); ngx_destroy_pool(pool); return 0; }
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; ngx_http_request_t *sr = NULL; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; ngx_array_t *extra_vars; ngx_str_t uri; ngx_str_t args; ngx_str_t extra_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; size_t nargs; int rc; int n; int always_forward_body = 0; ngx_uint_t method; ngx_http_request_body_t *body; int type; ngx_buf_t *b; unsigned vars_action; ngx_uint_t nsubreqs; ngx_uint_t index; size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; size_t sr_flags_len; size_t ofs1, ofs2; unsigned custom_ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_post_subrequest_data_t *psr_data; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument is expected, but got %d", n); } luaL_checktype(L, 1, LUA_TTABLE); nsubreqs = lua_objlen(L, 1); if (nsubreqs == 0) { return luaL_error(L, "at least one subrequest should be specified"); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua location capture, uri:\"%V\" c:%ud", &r->uri, r->main->count); sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); sr_flags_len = nsubreqs * sizeof(uint8_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_len + sr_flags_len); if (p == NULL) { return luaL_error(L, "no memory"); } coctx->sr_statuses = (void *) p; p += sr_statuses_len; coctx->sr_headers = (void *) p; p += sr_headers_len; coctx->sr_bodies = (void *) p; p += sr_bodies_len; coctx->sr_flags = (void *) p; coctx->nsubreqs = nsubreqs; coctx->pending_subreqs = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { coctx->pending_subreqs++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { return luaL_error(L, "only array-like tables are allowed"); } dd("queries query: top %d", lua_gettop(L)); if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " "but a %s", index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ dd("queries query uri: %d", lua_gettop(L)); dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1))); body = NULL; ngx_str_null(&extra_args); if (extra_vars != NULL) { /* flush out existing elements in the array */ extra_vars->nelts = 0; } vars_action = 0; custom_ctx = 0; if (nargs == 2) { /* check out the options table */ lua_rawgeti(L, 2, 2); /* queries query uri opts */ dd("queries query uri opts: %d", lua_gettop(L)); if (lua_type(L, 4) != LUA_TTABLE) { return luaL_error(L, "expecting table as the 2nd argument for " "subrequest %d, but got %s", index, luaL_typename(L, 4)); } dd("queries query uri opts: %d", lua_gettop(L)); /* check the args option */ lua_getfield(L, 4, "args"); type = lua_type(L, -1); switch (type) { case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, -1, &extra_args); break; case LUA_TNIL: /* do nothing */ break; case LUA_TNUMBER: case LUA_TSTRING: extra_args.data = (u_char *) lua_tolstring(L, -1, &len); extra_args.len = len; break; default: return luaL_error(L, "Bad args option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the vars option */ lua_getfield(L, 4, "vars"); switch (lua_type(L, -1)) { case LUA_TTABLE: ngx_http_lua_process_vars_option(r, L, -1, &extra_vars); dd("post process vars top: %d", lua_gettop(L)); break; case LUA_TNIL: /* do nothing */ break; default: return luaL_error(L, "Bad vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the share_all_vars option */ lua_getfield(L, 4, "share_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS; } break; default: return luaL_error(L, "Bad share_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the copy_all_vars option */ lua_getfield(L, 4, "copy_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS; } break; default: return luaL_error(L, "Bad copy_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "forward_body" option */ lua_getfield(L, 4, "always_forward_body"); always_forward_body = lua_toboolean(L, -1); lua_pop(L, 1); dd("always foward body: %d", always_forward_body); /* check the "method" option */ lua_getfield(L, 4, "method"); type = lua_type(L, -1); if (type == LUA_TNIL) { method = NGX_HTTP_GET; } else { if (type != LUA_TNUMBER) { return luaL_error(L, "Bad http request method"); } method = (ngx_uint_t) lua_tonumber(L, -1); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "ctx" option */ lua_getfield(L, 4, "ctx"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TTABLE) { return luaL_error(L, "Bad ctx option value type %s, " "expected a Lua table", lua_typename(L, type)); } custom_ctx = 1; } else { lua_pop(L, 1); } dd("queries query uri opts ctx?: %d", lua_gettop(L)); /* check the "body" option */ lua_getfield(L, 4, "body"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TSTRING && type != LUA_TNUMBER) { return luaL_error(L, "Bad http request body"); } body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (body == NULL) { return luaL_error(L, "no memory"); } q = (u_char *) lua_tolstring(L, -1, &len); dd("request body: [%.*s]", (int) len, q); if (len) { b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return luaL_error(L, "no memory"); } b->last = ngx_copy(b->last, q, len); body->bufs = ngx_alloc_chain_link(r->pool); if (body->bufs == NULL) { return luaL_error(L, "no memory"); } body->bufs->buf = b; body->bufs->next = NULL; body->buf = b; } } lua_pop(L, 1); /* pop the body */ /* stack: queries query uri opts ctx? */ lua_remove(L, 4); /* stack: queries query uri ctx? */ dd("queries query uri ctx?: %d", lua_gettop(L)); } else { method = NGX_HTTP_GET; } /* stack: queries query uri ctx? */ p = (u_char *) luaL_checklstring(L, 3, &len); uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "memory allocation error"); } ngx_memcpy(uri.data, p, len); uri.len = len; ngx_str_null(&args); flags = 0; rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags); if (rc != NGX_OK) { dd("rc = %d", (int) rc); return luaL_error(L, "unsafe uri in argument #1: %s", p); } if (args.len == 0) { if (extra_args.len) { p = ngx_palloc(r->pool, extra_args.len); if (p == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(p, extra_args.data, extra_args.len); args.data = p; args.len = extra_args.len; } } else if (extra_args.len) { /* concatenate the two parts of args together */ len = args.len + (sizeof("&") - 1) + extra_args.len; p = ngx_palloc(r->pool, len); if (p == NULL) { return luaL_error(L, "no memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, extra_args.data, extra_args.len); args.data = p; args.len = len; } ofs1 = ngx_align(sizeof(ngx_http_post_subrequest_t), sizeof(void *)); ofs2 = ngx_align(sizeof(ngx_http_lua_ctx_t), sizeof(void *)); p = ngx_palloc(r->pool, ofs1 + ofs2 + sizeof(ngx_http_lua_post_subrequest_data_t)); if (p == NULL) { return luaL_error(L, "no memory"); } psr = (ngx_http_post_subrequest_t *) p; p += ofs1; sr_ctx = (ngx_http_lua_ctx_t *) p; ngx_http_lua_assert((void *) sr_ctx == ngx_align_ptr(sr_ctx, sizeof(void *))); p += ofs2; psr_data = (ngx_http_lua_post_subrequest_data_t *) p; ngx_http_lua_assert((void *) psr_data == ngx_align_ptr(psr_data, sizeof(void *))); ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t)); /* set by ngx_memzero: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL * sr_ctx->body = NULL */ psr_data->ctx = sr_ctx; psr_data->pr_co_ctx = coctx; psr->handler = ngx_http_lua_post_subrequest; psr->data = psr_data; rc = ngx_http_lua_subrequest(r, &uri, &args, &sr, psr, 0); if (rc != NGX_OK) { return luaL_error(L, "failed to issue subrequest: %d", (int) rc); } ngx_http_lua_init_ctx(sr, sr_ctx); sr_ctx->capture = 1; sr_ctx->index = index; sr_ctx->last_body = &sr_ctx->body; sr_ctx->vm_state = ctx->vm_state; ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body, body, vars_action, extra_vars); if (rc != NGX_OK) { ngx_http_lua_cancel_subreq(sr); return luaL_error(L, "failed to adjust the subrequest: %d", (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); /* stack: queries query uri ctx? */ if (custom_ctx) { ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1); lua_pop(L, 3); } else { lua_pop(L, 2); } /* stack: queries */ } if (extra_vars) { ngx_array_destroy(extra_vars); } ctx->no_abort = 1; return lua_yield(L, 0); }