int ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, size_t key_len, int value_type, u_char *str_value_buf, size_t str_value_len, double num_value, int exptime, int user_flags, char **errmsg, int *forcible) { int i, n; u_char c, *p; uint32_t hash; ngx_int_t rc; ngx_time_t *tp; ngx_rbtree_node_t *node; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; if (zone == NULL) { return NGX_ERROR; } dd("exptime: %d", exptime); ctx = zone->data; *forcible = 0; hash = ngx_crc32_short(key, key_len); switch (value_type) { case LUA_TSTRING: /* do nothing */ break; case LUA_TNUMBER: dd("num value: %lf", num_value); str_value_buf = (u_char *) &num_value; str_value_len = sizeof(double); break; case LUA_TBOOLEAN: c = num_value ? 1 : 0; str_value_buf = &c; str_value_len = sizeof(u_char); break; case LUA_TNIL: if (op & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) { *errmsg = "attempt to add or replace nil values"; return NGX_ERROR; } str_value_buf = NULL; str_value_len = 0; break; default: *errmsg = "unsupported value type"; return NGX_ERROR; } ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); dd("lookup returns %d", (int) rc); if (op & NGX_HTTP_LUA_SHDICT_REPLACE) { if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "not found"; return NGX_DECLINED; } /* rc == NGX_OK */ goto replace; } if (op & NGX_HTTP_LUA_SHDICT_ADD) { if (rc == NGX_OK) { ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "exists"; return NGX_DECLINED; } if (rc == NGX_DONE) { /* exists but expired */ dd("go to replace"); goto replace; } /* rc == NGX_DECLINED */ dd("go to insert"); goto insert; } if (rc == NGX_OK || rc == NGX_DONE) { if (value_type == LUA_TNIL) { goto remove; } replace: if (str_value_buf && str_value_len == (size_t) sd->value_len) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry and value " "size matched, reusing it"); ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); sd->key_len = (u_short) key_len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) exptime; } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) str_value_len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key, key_len); ngx_memcpy(p, str_value_buf, str_value_len); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry bug value size " "NOT matched, removing it first"); remove: ngx_queue_remove(&sd->queue); node = (ngx_rbtree_node_t *) ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_slab_free_locked(ctx->shpool, node); } insert: /* rc == NGX_DECLINED or value size unmatch */ if (str_value_buf == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: creating a new entry"); n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_lua_shdict_node_t, data) + key_len + str_value_len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { if (op & NGX_HTTP_LUA_SHDICT_SAFE_STORE) { ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "no memory"; return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: overriding non-expired items " "due to memory shortage for entry \"%*s\"", key_len, key); for (i = 0; i < 30; i++) { if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { break; } *forcible = 1; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node != NULL) { goto allocated; } } ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "no memory"; return NGX_ERROR; } allocated: sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; sd->key_len = (u_short) key_len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) exptime; } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) str_value_len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key, key_len); ngx_memcpy(p, str_value_buf, str_value_len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; }
static int ngx_http_lua_ngx_req_raw_header(lua_State *L) { int n, line_break_len; u_char *data, *p, *last, *pos; unsigned no_req_line = 0, found; size_t size; ngx_buf_t *b, *first = NULL; ngx_int_t i, j; ngx_connection_t *c; ngx_http_request_t *r, *mr; ngx_http_connection_t *hc; n = lua_gettop(L); if (n > 0) { no_req_line = lua_toboolean(L, 1); } dd("no req line: %d", (int) no_req_line); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); mr = r->main; hc = mr->http_connection; c = mr->connection; #if 1 dd("hc->nbusy: %d", (int) hc->nbusy); if (hc->nbusy) { dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos, hc->busy[0]->last, hc->busy[0]->end); } dd("request line: %p %p", mr->request_line.data, mr->request_line.data + mr->request_line.len); dd("header in: %p %p %p %p", mr->header_in->start, mr->header_in->pos, mr->header_in->last, mr->header_in->end); dd("c->buffer: %p %p %p %p", c->buffer->start, c->buffer->pos, c->buffer->last, c->buffer->end); #endif size = 0; b = c->buffer; if (mr->request_line.data[mr->request_line.len] == CR) { line_break_len = 2; } else { line_break_len = 1; } if (mr->request_line.data >= b->start && mr->request_line.data + mr->request_line.len + line_break_len <= b->pos) { first = b; size += b->pos - mr->request_line.data; } dd("size: %d", (int) size); if (hc->nbusy) { b = NULL; for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start), b->start); if (first == NULL) { if (mr->request_line.data >= b->pos || mr->request_line.data + mr->request_line.len + line_break_len <= b->start) { continue; } dd("found first at %d", (int) i); first = b; } dd("adding size %d", (int) (b->pos - b->start)); size += b->pos - b->start; } } size++; /* plus the null terminator, as required by the later ngx_strstr() call */ dd("header size: %d", (int) size); data = lua_newuserdata(L, size); last = data; b = c->buffer; found = 0; if (first == b) { found = 1; pos = b->pos; if (no_req_line) { last = ngx_copy(data, mr->request_line.data + mr->request_line.len + line_break_len, pos - mr->request_line.data - mr->request_line.len - line_break_len); } else { last = ngx_copy(data, mr->request_line.data, pos - mr->request_line.data); } if (b != mr->header_in) { /* skip truncated header entries (if any) */ while (last > data && last[-1] != LF) { last--; } } i = 0; for (p = data; p != last; p++) { if (*p == '\0') { i++; if (p + 1 != last && *(p + 1) == LF) { *p = CR; } else if (i % 2 == 1) { *p = ':'; } else { *p = LF; } } } } if (hc->nbusy) { for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; if (!found) { if (b != first) { continue; } dd("found first"); found = 1; } p = last; pos = b->pos; if (b == first) { dd("request line: %.*s", (int) mr->request_line.len, mr->request_line.data); if (no_req_line) { last = ngx_copy(last, mr->request_line.data + mr->request_line.len + line_break_len, pos - mr->request_line.data - mr->request_line.len - line_break_len); } else { last = ngx_copy(last, mr->request_line.data, pos - mr->request_line.data); } } else { last = ngx_copy(last, b->start, pos - b->start); } #if 1 /* skip truncated header entries (if any) */ while (last > p && last[-1] != LF) { last--; } #endif j = 0; for (; p != last; p++) { if (*p == '\0') { j++; if (p + 1 == last) { /* XXX this should not happen */ dd("found string end!!"); } else if (*(p + 1) == LF) { *p = CR; } else if (j % 2 == 1) { *p = ':'; } else { *p = LF; } } } if (b == mr->header_in) { break; } } } *last++ = '\0'; if (last - data > (ssize_t) size) { return luaL_error(L, "buffer error: %d", (int) (last - data - size)); } /* strip the leading part (if any) of the request body in our header. * the first part of the request body could slip in because nginx core's * ngx_http_request_body_length_filter and etc can move r->header_in->pos * in case that some of the body data has been preread into r->header_in. */ if ((p = (u_char *) ngx_strstr(data, CRLF CRLF)) != NULL) { last = p + sizeof(CRLF CRLF) - 1; } else if ((p = (u_char *) ngx_strstr(data, CRLF "\n")) != NULL) { last = p + sizeof(CRLF "\n") - 1; } else if ((p = (u_char *) ngx_strstr(data, "\n" CRLF)) != NULL) { last = p + sizeof("\n" CRLF) - 1; } else { for (p = last - 1; p - data >= 2; p--) { if (p[0] == LF && p[-1] == CR) { p[-1] = LF; last = p + 1; break; } if (p[0] == LF && p[-1] == LF) { last = p + 1; break; } } } lua_pushlstring(L, (char *) data, last - data); return 1; }
static int ngx_proc_luashm_backup_recover(ngx_http_lua_shdict_ctx_t *ctx,ngx_http_lua_shdict_node_ext_t *extsd){ ngx_http_lua_shdict_node_t *sd; ngx_rbtree_node_t *node; int i, n; uint32_t hash; int32_t user_flags = 0; u_char *p,*key,*value; int key_len,value_len; int value_type; double *num_value; key = extsd->data; key_len=extsd->key_len; value = extsd->data+key_len; value_len=extsd->value_len; value_type=extsd->value_type; user_flags=extsd->user_flags; switch (extsd->value_type) { case LUA_TSTRING: dd("key:%s, key_len:%d,value:%s,value_len:%d,exptime:%lu",key,key_len,value,value_len,extsd->expires); break; case LUA_TNUMBER: num_value=value; dd("key:%s, key_len:%d,value:%f,value_len:%d,exptime:%lu",key,key_len,*num_value,value_len,extsd->expires); break; case LUA_TBOOLEAN: dd("key:%s, key_len:%d,value:%c,value_len:%d,exptime:%lu",key,key_len,value[0],value_len,extsd->expires); break; } hash = ngx_crc32_short(key, key_len); /* rc == NGX_DECLINED or value size unmatch */ //dd("lua shared dict set: creating a new entry"); n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_lua_shdict_node_t, data) + key_len + value_len; ngx_shmtx_lock(&ctx->shpool->mutex); node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { dd("lua shared dict set: overriding non-expired items " "due to memory shortage for entry \"%s\"", key); for (i = 0; i < 30; i++) { if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { break; } node = ngx_slab_alloc_locked(ctx->shpool, n); if (node != NULL) { goto allocated; } } ngx_shmtx_unlock(&ctx->shpool->mutex); ngx_log_error(NGX_LOG_EMERG, ctx->log, 0, "no memory"); return NGX_ERROR; } allocated: sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; sd->key_len = (u_short) key_len; sd->expires = extsd->expires; sd->user_flags = user_flags; sd->value_len = (uint32_t) value_len; //dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key, key_len); ngx_memcpy(p, value, value_len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; }
static int ngx_http_lua_ngx_exec(lua_State *L) { int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t uri; ngx_str_t args, user_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; const char *msg; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting one or two arguments, but got %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_str_null(&args); /* read the 1st argument (uri) */ p = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { return luaL_error(L, "The uri argument is empty"); } uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(uri.data, p, len); uri.len = len; 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); ngx_http_lua_check_if_abortable(L, ctx); if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (n == 2) { /* read the 2nd argument (args) */ dd("args type: %s", luaL_typename(L, 2)); switch (lua_type(L, 2)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 2, &len); user_args.data = ngx_palloc(r->pool, len); if (user_args.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(user_args.data, p, len); user_args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 2, &user_args); dd("user_args: %.*s", (int) user_args.len, user_args.data); break; case LUA_TNIL: ngx_str_null(&user_args); break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 2, msg); } } else { user_args.data = NULL; user_args.len = 0; } if (user_args.len) { if (args.len == 0) { args = user_args; } else { p = ngx_palloc(r->pool, args.len + user_args.len + 1); if (p == NULL) { return luaL_error(L, "no memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, user_args.data, user_args.len); args.data = p; args.len += user_args.len + 1; } } if (r->header_sent || ctx->header_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } ctx->exec_uri = uri; ctx->exec_args = args; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exec \"%V?%V\"", &ctx->exec_uri, &ctx->exec_args); return lua_yield(L, 0); }
ngx_int_t ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) { ngx_http_request_t *pr; ngx_http_lua_ctx_t *pr_ctx; ngx_http_lua_ctx_t *ctx; /* subrequest ctx */ ngx_http_lua_co_ctx_t *pr_coctx; size_t len; ngx_str_t *body_str; u_char *p; ngx_chain_t *cl; ngx_http_lua_post_subrequest_data_t *psr_data = data; ctx = psr_data->ctx; if (ctx->run_post_subrequest) { if (r != r->connection->data) { r->connection->data = r; } return NGX_OK; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run post subrequest handler, rc:%i c:%ud", rc, r->main->count); ctx->run_post_subrequest = 1; pr = r->parent; pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_lua_module); if (pr_ctx == NULL) { return NGX_ERROR; } pr_coctx = psr_data->pr_co_ctx; pr_coctx->pending_subreqs--; if (pr_coctx->pending_subreqs == 0) { dd("all subrequests are done"); pr_ctx->no_abort = 0; pr_ctx->resume_handler = ngx_http_lua_subrequest_resume; pr_ctx->cur_co_ctx = pr_coctx; } if (pr_ctx->entered_content_phase) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua restoring write event handler"); pr->write_event_handler = ngx_http_lua_content_wev_handler; } else { pr->write_event_handler = ngx_http_core_run_phases; } dd("status rc = %d", (int) rc); dd("status headers_out.status = %d", (int) r->headers_out.status); dd("uri: %.*s", (int) r->uri.len, r->uri.data); /* capture subrequest response status */ pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; if (pr_coctx->sr_statuses[ctx->index] == 0) { if (rc == NGX_OK) { rc = NGX_HTTP_OK; } if (rc == NGX_ERROR) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } if (rc >= 100) { pr_coctx->sr_statuses[ctx->index] = rc; } } if (!ctx->seen_last_for_subreq) { pr_coctx->sr_flags[ctx->index] |= NGX_HTTP_LUA_SUBREQ_TRUNCATED; } dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ pr_coctx->sr_headers[ctx->index] = &r->headers_out; /* copy subrequest response body */ body_str = &pr_coctx->sr_bodies[ctx->index]; len = 0; for (cl = ctx->body; cl; cl = cl->next) { /* ignore all non-memory buffers */ len += cl->buf->last - cl->buf->pos; } body_str->len = len; if (len == 0) { body_str->data = NULL; } else { p = ngx_palloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } body_str->data = p; /* copy from and then free the data buffers */ for (cl = ctx->body; cl; cl = cl->next) { p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); cl->buf->last = cl->buf->pos; #if 0 dd("free body chain link buf ASAP"); ngx_pfree(r->pool, cl->buf->start); #endif } } if (ctx->body) { #if defined(nginx_version) && nginx_version >= 1001004 ngx_chain_update_chains(r->pool, #else ngx_chain_update_chains( #endif &pr_ctx->free_bufs, &pr_ctx->busy_bufs, &ctx->body, (ngx_buf_tag_t) &ngx_http_lua_module); dd("free bufs: %p", pr_ctx->free_bufs); }
static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r) { u_char *p; size_t len; ngx_str_t host, *status_line; ngx_buf_t *b; ngx_uint_t status, i, port; ngx_chain_t out; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif u_char addr[NGX_SOCKADDR_STRLEN]; #if (NGX_HTTP_STATUS_PAGE) if (r->header_sent && (ngx_http_status_page_test_old_header(r) == 0)) { return NGX_OK; } #else if (r->header_sent) { return NGX_OK; } #endif r->header_sent = 1; if (r != r->main) { return NGX_OK; } if (r->http_version < NGX_HTTP_VERSION_10) { return NGX_OK; } if (r->method == NGX_HTTP_HEAD) { r->header_only = 1; } if (r->headers_out.last_modified_time != -1) { if (r->headers_out.status != NGX_HTTP_OK && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) { r->headers_out.last_modified_time = -1; r->headers_out.last_modified = NULL; } } len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; /* status line */ if (r->headers_out.status_line.len) { len += r->headers_out.status_line.len; status_line = &r->headers_out.status_line; #if (NGX_SUPPRESS_WARN) status = 0; #endif } else { status = r->headers_out.status; #if (NGX_HTTP_STATUS_PAGE) if (ngx_http_status_page_test_change_status(r)) { status = ngx_http_status_page_get_status(r); } #endif if (status >= NGX_HTTP_OK && status < NGX_HTTP_LAST_2XX) { /* 2XX */ if (status == NGX_HTTP_NO_CONTENT) { r->header_only = 1; ngx_str_null(&r->headers_out.content_type); r->headers_out.last_modified_time = -1; r->headers_out.last_modified = NULL; r->headers_out.content_length = NULL; r->headers_out.content_length_n = -1; } status -= NGX_HTTP_OK; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_MOVED_PERMANENTLY && status < NGX_HTTP_LAST_3XX) { /* 3XX */ if (status == NGX_HTTP_NOT_MODIFIED) { r->header_only = 1; } status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_BAD_REQUEST && status < NGX_HTTP_LAST_4XX) { /* 4XX */ status = status - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR && status < NGX_HTTP_LAST_5XX) { /* 5XX */ status = status - NGX_HTTP_INTERNAL_SERVER_ERROR + NGX_HTTP_OFF_5XX; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else { len += NGX_INT_T_LEN; status_line = NULL; } if (status_line && status_line->len == 0) { status = r->headers_out.status; len += NGX_INT_T_LEN; status_line = NULL; } } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_out.server == NULL) { len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1: sizeof(ngx_http_server_string) - 1; } if (r->headers_out.date == NULL) { len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } if (r->headers_out.content_type.len) { len += sizeof("Content-Type: ") - 1 + r->headers_out.content_type.len + 2; if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2; } if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } c = r->connection; if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') { r->headers_out.location->hash = 0; if (clcf->server_name_in_redirect) { cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); host = cscf->server_name; } else if (r->headers_in.server.len) { host = r->headers_in.server; } else { host.len = NGX_SOCKADDR_STRLEN; host.data = addr; if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) { return NGX_ERROR; } } switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) c->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: port = 0; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) c->local_sockaddr; port = ntohs(sin->sin_port); break; } len += sizeof("Location: https://") - 1 + host.len + r->headers_out.location->value.len + 2; if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL) if (c->ssl) port = (port == 443) ? 0 : port; else #endif port = (port == 80) ? 0 : port; } else { port = 0; } if (port) { len += sizeof(":65535") - 1; } } else { ngx_str_null(&host); port = 0; } if (r->chunked) { len += sizeof("Transfer-Encoding: chunked" CRLF) - 1; } if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { len += sizeof("Connection: upgrade" CRLF) - 1; } else if (r->keepalive) { len += sizeof("Connection: keep-alive" CRLF) - 1; /* * MSIE and Opera ignore the "Keep-Alive: timeout=<N>" header. * MSIE keeps the connection alive for about 60-65 seconds. * Opera keeps the connection alive very long. * Mozilla keeps the connection alive for N plus about 1-10 seconds. * Konqueror keeps the connection alive for about N seconds. */ if (clcf->keepalive_header) { len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2; } } else { len += sizeof("Connection: close" CRLF) - 1; } #if (NGX_HTTP_GZIP) if (r->gzip_vary) { if (clcf->gzip_vary) { len += sizeof("Vary: Accept-Encoding" CRLF) - 1; } else { r->gzip_vary = 0; } } #endif part = &r->headers_out.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len + sizeof(CRLF) - 1; } b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } /* "HTTP/1.x " */ b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1); /* status line */ if (status_line) { b->last = ngx_copy(b->last, status_line->data, status_line->len); } else { b->last = ngx_sprintf(b->last, "%03ui", status); } *b->last++ = CR; *b->last++ = LF; if (r->headers_out.server == NULL) { if (clcf->server_tokens) { p = (u_char *) ngx_http_server_full_string; len = sizeof(ngx_http_server_full_string) - 1; } else { p = (u_char *) ngx_http_server_string; len = sizeof(ngx_http_server_string) - 1; } b->last = ngx_cpymem(b->last, p, len); } if (r->headers_out.date == NULL) { b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1); b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, ngx_cached_http_time.len); *b->last++ = CR; *b->last++ = LF; } if (r->headers_out.content_type.len) { b->last = ngx_cpymem(b->last, "Content-Type: ", sizeof("Content-Type: ") - 1); p = b->last; b->last = ngx_copy(b->last, r->headers_out.content_type.data, r->headers_out.content_type.len); if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { b->last = ngx_cpymem(b->last, "; charset=", sizeof("; charset=") - 1); b->last = ngx_copy(b->last, r->headers_out.charset.data, r->headers_out.charset.len); /* update r->headers_out.content_type for possible logging */ r->headers_out.content_type.len = b->last - p; r->headers_out.content_type.data = p; } *b->last++ = CR; *b->last++ = LF; } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF, r->headers_out.content_length_n); } if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { b->last = ngx_cpymem(b->last, "Last-Modified: ", sizeof("Last-Modified: ") - 1); b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); *b->last++ = CR; *b->last++ = LF; } if (host.data) { p = b->last + sizeof("Location: ") - 1; b->last = ngx_cpymem(b->last, "Location: http", sizeof("Location: http") - 1); #if (NGX_HTTP_SSL) if (c->ssl) { *b->last++ ='s'; } #endif *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/'; b->last = ngx_copy(b->last, host.data, host.len); if (port) { b->last = ngx_sprintf(b->last, ":%ui", port); } b->last = ngx_copy(b->last, r->headers_out.location->value.data, r->headers_out.location->value.len); /* update r->headers_out.location->value for possible logging */ r->headers_out.location->value.len = b->last - p; r->headers_out.location->value.data = p; ngx_str_set(&r->headers_out.location->key, "Location"); *b->last++ = CR; *b->last++ = LF; } if (r->chunked) { b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF, sizeof("Transfer-Encoding: chunked" CRLF) - 1); } if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { b->last = ngx_cpymem(b->last, "Connection: upgrade" CRLF, sizeof("Connection: upgrade" CRLF) - 1); } else if (r->keepalive) { b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF, sizeof("Connection: keep-alive" CRLF) - 1); if (clcf->keepalive_header) { b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF, clcf->keepalive_header); } } else { b->last = ngx_cpymem(b->last, "Connection: close" CRLF, sizeof("Connection: close" CRLF) - 1); } #if (NGX_HTTP_GZIP) if (r->gzip_vary) { b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF, sizeof("Vary: Accept-Encoding" CRLF) - 1); } #endif part = &r->headers_out.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); *b->last++ = ':'; *b->last++ = ' '; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = CR; *b->last++ = LF; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "%*s", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ *b->last++ = CR; *b->last++ = LF; r->header_size = b->last - b->pos; if (r->header_only) { b->last_buf = 1; } out.buf = b; out.next = NULL; return ngx_http_write_filter(r, &out); }
static int ngx_http_lua_ngx_req_set_body_data(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_temp_file_t *tf; ngx_buf_t *b; ngx_str_t body, key, value; #if 1 ngx_int_t rc; #endif ngx_chain_t *cl; ngx_buf_tag_t tag; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "expecting 1 arguments but seen %d", n); } body.data = (u_char *) luaL_checklstring(L, 1, &body.len); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } if (r->request_body == NULL) { return luaL_error(L, "request body not read yet"); } rb = r->request_body; tag = (ngx_buf_tag_t) &ngx_http_lua_module; tf = rb->temp_file; if (tf) { if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } rb->temp_file = NULL; } if (body.len == 0) { if (rb->bufs) { for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } } rb->bufs = NULL; rb->buf = NULL; dd("request body is set to empty string"); goto set_header; } if (rb->bufs) { for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } rb->bufs->next = NULL; b = rb->bufs->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->temporary = 1; b->tag = tag; b->start = ngx_palloc(r->pool, body.len); if (b->start == NULL) { return luaL_error(L, "no memory"); } b->end = b->start + body.len; b->pos = b->start; b->last = ngx_copy(b->pos, body.data, body.len); } else { rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "no memory"); } rb->bufs->next = NULL; b = ngx_create_temp_buf(r->pool, body.len); if (b == NULL) { return luaL_error(L, "no memory"); } b->tag = tag; b->last = ngx_copy(b->pos, body.data, body.len); rb->bufs->buf = b; rb->buf = b; } set_header: /* override input header Content-Length (value must be null terminated) */ value.data = ngx_palloc(r->pool, NGX_SIZE_T_LEN + 1); if (value.data == NULL) { return luaL_error(L, "no memory"); } value.len = ngx_sprintf(value.data, "%uz", body.len) - value.data; value.data[value.len] = '\0'; dd("setting request Content-Length to %.*s (%d)", (int) value.len, value.data, (int) body.len); r->headers_in.content_length_n = body.len; if (r->headers_in.content_length) { r->headers_in.content_length->value.data = value.data; r->headers_in.content_length->value.len = value.len; } else { ngx_str_set(&key, "Content-Length"); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " "input header"); } } 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); }
static void ngx_mysql_read_server_greeting(ngx_event_t *rev) { size_t len; u_char *p; ssize_t n; ngx_uint_t i, capacity; ngx_mysql_t *m; ngx_connection_t *c; ngx_mysql_greeting1_pkt_t *gr1; ngx_mysql_greeting2_pkt_t *gr2; ngx_mysql_auth_pkt_t *auth; ngx_sha1_t sha; u_char hash1[20], hash2[20]; c = rev->data; m = c->data; if (rev->timedout) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, "mysql server %V timed out", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } if (m->buf == NULL) { m->peer.log->action = "reading mysql server greeting"; m->buf = ngx_create_temp_buf(m->pool, /* STUB */ 1024); if (m->buf == NULL) { ngx_mysql_close(m, NGX_ERROR); return; } } n = ngx_recv(m->peer.connection, m->buf->pos, /* STUB */ 1024); if (n == NGX_AGAIN) { return; } if (n < 5) { ngx_mysql_close(m, NGX_ERROR); return; } gr1 = (ngx_mysql_greeting1_pkt_t *) m->buf->pos; if (ngx_m24toh(gr1->pktlen) > n - 4) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent incomplete greeting packet", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } if (gr1->protocol < 10) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "mysql server %V sent unsupported protocol version %ud", m->peer.name, gr1->protocol); ngx_mysql_close(m, NGX_ERROR); return; } gr2 = (ngx_mysql_greeting2_pkt_t *) (gr1->version + ngx_strlen(gr1->version) + 1); capacity = ngx_m16toh(gr2->capacity); ngx_log_debug8(NGX_LOG_DEBUG_MYSQL, rev->log, 0, "mysql version: %ud, \"%s\", thread: %ud, salt: \"%s\", " "capacity: %Xd, charset: %ud, status: %ud, salt rest \"%s\"", gr1->protocol, gr1->version, ngx_m32toh(gr2->thread), gr2->salt1, capacity, gr2->charset, ngx_m16toh(gr2->status), &gr2->salt2); capacity = NGX_MYSQL_LONG_PASSWORD | NGX_MYSQL_CONNECT_WITH_DB | NGX_MYSQL_PROTOCOL_41 | NGX_MYSQL_SECURE_CONNECTION; len = 4 + 4 + 4 + 1 + 23 + m->login->len + 1 + 1 + m->database->len + 1; if (m->passwd->len) { len += 20; } auth = ngx_pnalloc(m->pool, len); if (auth == NULL) { ngx_mysql_close(m, NGX_ERROR); return; } ngx_htom24(auth->pktlen, len - 4); auth->pktn = (u_char) (gr1->pktn + 1); ngx_htom32(auth->capacity, capacity); ngx_htom32(auth->max_packet, 0x01000000); /* max packet size 2^24 */ ngx_memzero(auth->zero, 24); auth->charset = gr2->charset; p = ngx_copy(auth->login, m->login->data, m->login->len); *p++ = '\0'; if (m->passwd->len) { *p++ = (u_char) 20; ngx_sha1_init(&sha); ngx_sha1_update(&sha, m->passwd->data, m->passwd->len); ngx_sha1_final(hash1, &sha); ngx_sha1_init(&sha); ngx_sha1_update(&sha, hash1, 20); ngx_sha1_final(hash2, &sha); ngx_sha1_init(&sha); ngx_sha1_update(&sha, gr2->salt1, 8); ngx_sha1_update(&sha, gr2->salt2, 12); ngx_sha1_update(&sha, hash2, 20); ngx_sha1_final(hash2, &sha); for (i = 0; i < 20; i++) { *p++ = (u_char) (hash1[i] ^ hash2[i]); } } else { *p++ = '\0'; } p = ngx_copy(p, m->database->data, m->database->len); *p = '\0'; n = ngx_send(m->peer.connection, (void *) auth, len); if (n < (ssize_t) len) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "the incomplete packet was sent to mysql server %V", m->peer.name); ngx_mysql_close(m, NGX_ERROR); return; } m->peer.connection->read->handler = ngx_mysql_read_auth_result; ngx_add_timer(m->peer.connection->read, /* STUB */ 5000); }
static int ngx_http_lua_ngx_req_get_body_data(lua_State *L) { ngx_http_request_t *r; int n; size_t len; ngx_chain_t *cl; u_char *p; u_char *buf; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "expecting 0 arguments but seen %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); if (r->request_body == NULL || r->request_body->temp_file || r->request_body->bufs == NULL) { lua_pushnil(L); return 1; } cl = r->request_body->bufs; if (cl->next == NULL) { len = cl->buf->last - cl->buf->pos; if (len == 0) { lua_pushnil(L); return 1; } lua_pushlstring(L, (char *) cl->buf->pos, len); return 1; } /* found multi-buffer body */ len = 0; for (; cl; cl = cl->next) { dd("body chunk len: %d", (int) ngx_buf_size(cl->buf)); len += cl->buf->last - cl->buf->pos; } if (len == 0) { lua_pushnil(L); return 1; } buf = (u_char *) lua_newuserdata(L, len); p = buf; for (cl = r->request_body->bufs; cl; cl = cl->next) { p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); } lua_pushlstring(L, (char *) buf, len); return 1; }
int ngx_http_lua_ngx_req_get_post_args(lua_State *L) { ngx_http_request_t *r; u_char *buf; int retval; size_t len; ngx_chain_t *cl; u_char *p; u_char *last; if (lua_gettop(L) != 0) { return luaL_error(L, "expecting 0 arguments but seen %d", lua_gettop(L)); } lua_getglobal(L, GLOBALS_SYMBOL_REQUEST); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } if (r->discard_body) { lua_createtable(L, 0, 4); return 1; } if (r->request_body == NULL) { return luaL_error(L, "no request body found; " "maybe you should turn on lua_need_request_body?"); } if (r->request_body->temp_file) { return luaL_error(L, "requesty body in temp file not supported"); } lua_createtable(L, 0, 4); if (r->request_body->bufs == NULL) { return 1; } /* we copy r->request_body->bufs over to buf to simplify * unescaping query arg keys and values */ len = 0; for (cl = r->request_body->bufs; cl; cl = cl->next) { len += cl->buf->last - cl->buf->pos; } dd("post body length: %d", (int) len); buf = ngx_palloc(r->pool, len); if (buf == NULL) { return luaL_error(L, "out of memory"); } p = buf; for (cl = r->request_body->bufs; cl; cl = cl->next) { p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); } dd("post body: %.*s", (int) len, buf); last = buf + len; retval = ngx_http_lua_parse_args(r, L, buf, last); ngx_pfree(r->pool, buf); return retval; }
static ngx_int_t hexin_http_percn_create_subrequest(ngx_http_request_t *r, hexin_http_percn_subrequest_t **parsed_sr_ptr) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "进入 hexin_http_percn_create_subrequest"); size_t body_len; ngx_buf_t *b; ngx_chain_t *cl; hexin_http_percn_ctx_t *ctx; hexin_http_percn_subrequest_t *parsed_sr; ngx_http_request_body_t *rb; *parsed_sr_ptr = ngx_pcalloc(r->pool, sizeof(hexin_http_percn_subrequest_t)); if (*parsed_sr_ptr == NULL) { return NGX_ERROR; } parsed_sr = *parsed_sr_ptr; parsed_sr->location = &subpath; ngx_str_t *method_name; method_name = &post_method_name; parsed_sr->method = hexin_http_percn_parse_method_name(&method_name); parsed_sr->method_name = method_name; ctx = ngx_http_get_module_ctx(r, hexin_http_percn_module); body_len = ngx_strlen("receivers=") + ctx->receivers_part_val_len + ctx->common->len; rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } parsed_sr->content_length_n = body_len; b = ngx_create_temp_buf(r->pool, body_len); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->temporary = 1; /* b->memory = 1; */ cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = b; cl->next = NULL; rb->buf = b; rb->bufs = cl; *b->last++ = 'r'; *b->last++ = 'e'; *b->last++ = 'c'; *b->last++ = 'e'; *b->last++ = 'i'; *b->last++ = 'v'; *b->last++ = 'e'; *b->last++ = 'r'; *b->last++ = 's'; *b->last++ = '='; b->last = ngx_copy(b->last, ctx->receivers_part_val, ctx->receivers_part_val_len); b->last = ngx_copy(b->last, ctx->common->data, ctx->common->len); parsed_sr->request_body = rb; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http percn body:\n\"%*s\"", (size_t) (b->last - b->pos), b->pos); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "hexin_http_percn_create_subrequest 结束"); return NGX_OK; }
static int ngx_http_lua_shdict_set_helper(lua_State *L, int flags) { int i, n; ngx_str_t key; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; ngx_str_t value; int value_type; double num; u_char c; lua_Number exptime = 0; u_char *p; ngx_rbtree_node_t *node; ngx_time_t *tp; ngx_shm_zone_t *zone; int forcible = 0; /* indicates whether to foricibly override other * valid entries */ int32_t user_flags = 0; n = lua_gettop(L); if (n != 3 && n != 4 && n != 5) { return luaL_error(L, "expecting 3, 4 or 5 arguments, " "but only seen %d", n); } zone = lua_touserdata(L, 1); if (zone == NULL) { return luaL_error(L, "bad \"zone\" argument"); } ctx = zone->data; if (lua_isnil(L, 2)) { lua_pushnil(L); lua_pushliteral(L, "nil key"); return 2; } key.data = (u_char *) luaL_checklstring(L, 2, &key.len); if (key.len == 0) { lua_pushnil(L); lua_pushliteral(L, "empty key"); return 2; } if (key.len > 65535) { lua_pushnil(L); lua_pushliteral(L, "key too long"); return 2; } hash = ngx_crc32_short(key.data, key.len); value_type = lua_type(L, 3); switch (value_type) { case LUA_TSTRING: value.data = (u_char *) lua_tolstring(L, 3, &value.len); break; case LUA_TNUMBER: value.len = sizeof(double); num = lua_tonumber(L, 3); value.data = (u_char *) # break; case LUA_TBOOLEAN: value.len = sizeof(u_char); c = lua_toboolean(L, 3) ? 1 : 0; value.data = &c; break; case LUA_TNIL: if (flags & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) { lua_pushnil(L); lua_pushliteral(L, "attempt to add or replace nil values"); return 2; } ngx_str_null(&value); break; default: lua_pushnil(L); lua_pushliteral(L, "bad value type"); return 2; } if (n >= 4) { exptime = luaL_checknumber(L, 4); if (exptime < 0) { exptime = 0; } } if (n == 5) { user_flags = (uint32_t) luaL_checkinteger(L, 5); } ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returned %d", (int) rc); if (flags & NGX_HTTP_LUA_SHDICT_REPLACE) { if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "not found"); lua_pushboolean(L, forcible); return 3; } /* rc == NGX_OK */ goto replace; } if (flags & NGX_HTTP_LUA_SHDICT_ADD) { if (rc == NGX_OK) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "exists"); lua_pushboolean(L, forcible); return 3; } if (rc == NGX_DONE) { /* exists but expired */ dd("go to replace"); goto replace; } /* rc == NGX_DECLINED */ dd("go to insert"); goto insert; } if (rc == NGX_OK || rc == NGX_DONE) { if (value_type == LUA_TNIL) { goto remove; } replace: if (value.data && value.len == (size_t) sd->value_len) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry and value " "size matched, reusing it"); ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); sd->key_len = (u_short) key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) (exptime * 1000); } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) value.len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, forcible); return 3; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry bug value size " "NOT matched, removing it first"); remove: ngx_queue_remove(&sd->queue); node = (ngx_rbtree_node_t *) ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_slab_free_locked(ctx->shpool, node); } insert: /* rc == NGX_DECLINED or value size unmatch */ if (value.data == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, 0); return 3; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: creating a new entry"); n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_lua_shdict_node_t, data) + key.len + value.len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { if (flags & NGX_HTTP_LUA_SHDICT_SAFE_STORE) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "no memory"); return 2; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: overriding non-expired items " "due to memory shortage for entry \"%V\"", &key); for (i = 0; i < 30; i++) { if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { break; } forcible = 1; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node != NULL) { goto allocated; } } ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "no memory"); lua_pushboolean(L, forcible); return 3; } allocated: sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; sd->key_len = (u_short) key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) (exptime * 1000); } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) value.len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, forcible); return 3; }
static ngx_buf_t * __encode_head( uint8_t method, ngx_bool_t has_tb, const ngx_str_t * version, const char * key, const char * tb, uint32_t ttl, uint64_t score, int8_t opt, ngx_pool_t * pool) { if (!key || !pool || !version) { return NULL; } uint32_t ver = version->data ? ngx_atoi(version->data, version->len) : 0; uint32_t key_len = strlen(key); uint32_t key_crc = ngx_crc((u_char *) key, (size_t) key_len); uint32_t tb_len = has_tb ? strlen(tb) : 0; uint32_t tb_crc = has_tb ? ngx_crc((u_char *) tb, (size_t) tb_len) : 0; uint32_t head_len = 0; typedef struct { const void * data; size_t len; } head_item_t; head_item_t heads[] = { { &head_len, sizeof(head_len) }, { &method, sizeof(method) }, { &ver, sizeof(ver) }, { &key_len, sizeof(key_len) }, { key, (size_t) key_len }, { &key_crc, sizeof(key_crc) }, { &ttl, sizeof(ttl) }, { &tb_len, sizeof(tb_len) }, { tb, (size_t) tb_len }, { &tb_crc, sizeof(tb_crc) }, { &score, sizeof(score) }, { &opt, sizeof(opt) } }; size_t size = sizeof(heads) / sizeof(head_item_t); size_t i = 0; for (i = 0; i < size; ++i) { head_len += heads[i].len; } ngx_buf_t * buf = ngx_create_temp_buf(pool, head_len + 1); if (!buf) { return NULL; } memset(buf->pos, 0, head_len + 1); buf->last = buf->pos; for (i = 0; i < size; ++i) { if (heads[i].data && heads[i].len > 0) { buf->last = ngx_copy(buf->last, heads[i].data, heads[i].len); } } return buf; }
static ngx_int_t ngx_http_eval_handler(ngx_http_request_t *r) { /* size_t loc_len; */ ngx_str_t args; ngx_str_t subrequest_uri; ngx_uint_t flags; /* ngx_http_core_loc_conf_t *clcf; */ ngx_http_eval_loc_conf_t *ecf; ngx_http_eval_ctx_t *ctx; ngx_http_eval_ctx_t *sr_ctx; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_post_subrequest_t *psr; u_char *p; /* if(r != r->main) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); loc_len = r->valid_location ? clcf->name.len : 0; if(r->uri.len != loc_len) { r->uri.data += loc_len; r->uri.len -= loc_len; } else { r->uri.len = 1; } } */ ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); if(ecf->variables == NULL || !ecf->variables->nelts) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); if(ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->base_conf = ecf; ngx_http_set_ctx(r, ctx, ngx_http_eval_module); } if (ctx->done) { dd("subrequest done"); if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) { return NGX_DECLINED; } dd("status: %d", (int) ctx->status); return ctx->status; } if (ctx->in_progress) { dd("still in progress"); return NGX_DONE; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } if(ngx_http_eval_init_variables(r, ctx, ecf) != NGX_OK) { return NGX_ERROR; } args = r->args; flags = 0; subrequest_uri.len = ecf->eval_location.len + r->uri.len; p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len); if(p == NULL) { return NGX_ERROR; } p = ngx_copy(p, ecf->eval_location.data, ecf->eval_location.len); p = ngx_copy(p, r->uri.data, r->uri.len); if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } psr->handler = ngx_http_eval_post_subrequest_handler; psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_WAITED; dd("subrequest in memory : %d", (int) ecf->subrequest_in_memory); if (ecf->subrequest_in_memory) { flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY; } else { } dd("issue subrequest"); rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags); if (rc == NGX_ERROR || rc == NGX_DONE) { return rc; } sr->discard_body = 1; ctx->in_progress = 1; /* XXX we don't allow eval in subrequests, i think? */ sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (sr_ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(sr, sr_ctx, ngx_http_eval_module); dd("wait for subrequest to complete"); return NGX_DONE; }
ngx_int_t ngx_http_sticky_misc_set_cookie(ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value, ngx_str_t *domain, ngx_str_t *path, time_t expires, unsigned secure, unsigned httponly) { u_char *cookie, *p; size_t len; ngx_table_elt_t *set_cookie, *elt; ngx_str_t remove; ngx_list_part_t *part; ngx_uint_t i; char expires_str[80]; int expires_len; if (value == NULL) { ngx_str_set(&remove, "_remove_"); value = &remove; } /* name = value */ len = name->len + 1 + value->len; /*; Domain= */ if (domain->len > 0) { len += sizeof("; Domain=") - 1 + domain->len; } /*; Expires= */ if (expires != NGX_CONF_UNSET) { expires_len = cookie_expires(expires_str, sizeof(expires_str), time(NULL) + expires); len += sizeof("; Expires=") - 1 + expires_len; } /* ; Path= */ if (path->len > 0) { len += sizeof("; Path=") - 1 + path->len; } /* ; Secure */ if (secure) { len += sizeof("; Secure") - 1; } /* ; HttpOnly */ if (httponly) { len += sizeof("; HttpOnly") - 1; } cookie = ngx_pnalloc(r->pool, len); if (cookie == NULL) { return NGX_ERROR; } p = ngx_copy(cookie, name->data, name->len); *p++ = '='; p = ngx_copy(p, value->data, value->len); if (domain->len > 0) { p = ngx_copy(p, "; Domain=", sizeof("; Domain=") - 1); p = ngx_copy(p, domain->data, domain->len); } if (expires != NGX_CONF_UNSET) { p = ngx_copy(p, "; Expires=", sizeof("; Expires=") - 1); p = ngx_copy(p, expires_str, expires_len); } if (path->len > 0) { p = ngx_copy(p, "; Path=", sizeof("; Path=") - 1); p = ngx_copy(p, path->data, path->len); } if (secure) { p = ngx_copy(p, "; Secure", sizeof("; Secure") - 1); } if (httponly) { p = ngx_copy(p, "; HttpOnly", sizeof("; HttpOnly") - 1); } part = &r->headers_out.headers.part; elt = part->elts; set_cookie = NULL; for (i=0 ;; i++) { if (part->nelts > 1 || i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; elt = part->elts; i = 0; } /* ... */ if (ngx_strncmp(elt->value.data, name->data, name->len) == 0) { set_cookie = elt; break; } } /* found a Set-Cookie header with the same name: replace it */ if (set_cookie != NULL) { set_cookie->value.len = p - cookie; set_cookie->value.data = cookie; return NGX_OK; } set_cookie = ngx_list_push(&r->headers_out.headers); if (set_cookie == NULL) { return NGX_ERROR; } set_cookie->hash = 1; ngx_str_set(&set_cookie->key, "Set-Cookie"); set_cookie->value.len = p - cookie; set_cookie->value.data = cookie; return NGX_OK; }
static ngx_int_t ngx_http_eval_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_eval_ctx_t *ctx; ngx_chain_t *cl; ngx_buf_t *b; ngx_http_eval_loc_conf_t *conf; size_t len; ssize_t rest; dd("in body filter"); if (r == r->main) { return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } dd("in body filter"); conf = ngx_http_get_module_loc_conf(r->parent, ngx_http_eval_module); if (conf->subrequest_in_memory) { return ngx_http_next_body_filter(r, in); } b = &ctx->buffer; if (b->start == NULL) { dd("allocate buffer"); b->start = ngx_palloc(r->pool, conf->buffer_size); if (b->start == NULL) { return NGX_ERROR; } b->end = b->start + conf->buffer_size; b->pos = b->last = b->start; } for (cl = in; cl; cl = cl->next) { rest = b->end - b->last; if (rest == 0) { break; } if ( ! ngx_buf_in_memory(cl->buf)) { dd("buf not in memory!"); continue; } len = cl->buf->last - cl->buf->pos; if (len == 0) { continue; } if (len > (size_t) rest) { /* we truncate the exceeding part of the response body */ dd("truncate and ignore exceeding bufs"); len = rest; } dd("copied data '%.*s' (len %d, c0: %d)", (int) len, cl->buf->pos, (int) len, (int) *(cl->buf->pos)); b->last = ngx_copy(b->last, cl->buf->pos, len); } ngx_http_eval_discard_bufs(r->pool, in); return NGX_OK; }
static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, ngx_array_t *extra_vars) { ngx_http_core_main_conf_t *cmcf; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; u_char *val; u_char *p; ngx_uint_t i, hash; ngx_str_t name; size_t len; ngx_hash_t *variables_hash; ngx_keyval_t *var; /* set any extra variables that were passed to the subrequest */ if (extra_vars == NULL || extra_vars->nelts == 0) { return NGX_OK; } cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); variables_hash = &cmcf->variables_hash; var = extra_vars->elts; for (i = 0; i < extra_vars->nelts; i++, var++) { /* copy the variable's name and value because they are allocated * by the lua VM */ len = var->key.len + var->value.len; p = ngx_pnalloc(sr->pool, len); if (p == NULL) { return NGX_ERROR; } name.data = p; name.len = var->key.len; p = ngx_copy(p, var->key.data, var->key.len); hash = ngx_hash_strlow(name.data, name.data, name.len); val = p; len = var->value.len; ngx_memcpy(p, var->value.data, len); v = ngx_hash_find(variables_hash, hash, name.data, name.len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0, "variable \"%V\" not changeable", &name); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (v->set_handler) { vv = ngx_palloc(sr->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return NGX_ERROR; } vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; v->set_handler(sr, vv, v->data); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0, "variable \"%V\" set to value \"%v\"", &name, vv); continue; } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &sr->variables[v->index]; vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0, "variable \"%V\" set to value \"%v\"", &name, vv); continue; } } ngx_log_error(NGX_LOG_ERR, sr->connection->log, 0, "variable \"%V\" cannot be assigned a value (maybe you " "forgot to define it first?) ", &name); return NGX_ERROR; } return NGX_OK; }
ngx_int_t ngx_http_request_parser_post_arg(ngx_http_request_t *r, u_char *arg_name, size_t arg_len, ngx_str_t *value) { u_char *p, *v, *last, *buf; ngx_chain_t *cl; size_t len = 0; ngx_buf_t *b; ngx_str_set(value, ""); /* we read data from r->request_body->bufs */ if (r->request_body == NULL || r->request_body->bufs == NULL) { return NGX_OK; } if (r->request_body->bufs->next != NULL) { /* more than one buffer...we should copy the data out... */ len = 0; for (cl = r->request_body->bufs; cl; cl = cl->next) { b = cl->buf; if (b->in_file) { return NGX_OK; } len += b->last - b->pos; } if (len == 0) { return NGX_OK; } buf = ngx_palloc(r->pool, len); if (buf == NULL) { return NGX_ERROR; } p = buf; last = p + len; for (cl = r->request_body->bufs; cl; cl = cl->next) { p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); } } else { b = r->request_body->bufs->buf; if (ngx_buf_size(b) == 0) { return NGX_OK; } buf = b->pos; last = b->last; } for (p = buf; p < last; p++) { /* we need '=' after name, so drop one char from last */ p = ngx_strlcasestrn(p, last - 1, arg_name, arg_len - 1); if (p == NULL) { return NGX_OK; } if ((p == buf || *(p - 1) == '&') && *(p + arg_len) == '=') { v = p + arg_len + 1; p = ngx_strlchr(v, last, '&'); if (p == NULL) { p = last; } else { } value->data = v; value->len = p - v; return NGX_OK; } } return NGX_OK; }
static int ngx_http_lua_ngx_quote_sql_str(lua_State *L) { ngx_http_request_t *r; size_t len, dlen, escape; u_char *p; u_char *src, *dst; lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); } src = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { dst = (u_char *) "''"; dlen = sizeof("''") - 1; lua_pushlstring(L, (char *) dst, dlen); return 1; } escape = ngx_http_lua_ngx_escape_sql_str(NULL, src, len); dlen = sizeof("''") - 1 + len + escape; p = ngx_palloc(r->pool, dlen); if (p == NULL) { return luaL_error(L, "out of memory"); } dst = p; *p++ = '\''; if (escape == 0) { p = ngx_copy(p, src, len); } else { p = (u_char *) ngx_http_lua_ngx_escape_sql_str(p, src, len); } *p++ = '\''; if (p != dst + dlen) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx.quote_sql_str: buffer error"); return NGX_ERROR; } lua_pushlstring(L, (char *) dst, p - dst); return 1; }
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { u_char *last, *location; size_t root, len; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; //ngx_str_t temp = ngx_string("/test1.js"); //r->uri= temp; myChain=&out; r->uri.data=value; r->uri.len=valueLen; /*in=&out; in =in;*/ if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } log = r->connection->log; /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } r->root_tested = !r->error_page; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); ngx_http_clear_location(r); r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = path.data + clcf->root.len; *last = '/'; } else { if (r->args.len) { len += r->args.len + 1; } location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(location, r->uri.data, r->uri.len); *last = '/'; if (r->args.len) { *++last = '?'; ngx_memcpy(++last, r->args.data, r->args.len); } } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "GZIP HANDLER 1"); return 1; }
static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r) { size_t len; uintptr_t escape; ngx_buf_t *b; ngx_chain_t *cl; ngx_http_memcached_ctx_t *ctx; ngx_http_variable_value_t *vv; ngx_http_memcached_loc_conf_t *mlcf; mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); vv = ngx_http_get_indexed_variable(r, mlcf->index); if (vv == NULL || vv->not_found || vv->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$memcached_key\" variable is not set"); return NGX_ERROR; } escape = 2 * ngx_escape_uri(NULL, vv->data, vv->len, NGX_ESCAPE_MEMCACHED); len = sizeof("get ") - 1 + vv->len + escape + sizeof(CRLF) - 1; b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; r->upstream->request_bufs = cl; *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' '; ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); ctx->key.data = b->last; if (escape == 0) { b->last = ngx_copy(b->last, vv->data, vv->len); } else { b->last = (u_char *) ngx_escape_uri(b->last, vv->data, vv->len, NGX_ESCAPE_MEMCACHED); } ctx->key.len = b->last - ctx->key.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http memcached request: \"%V\"", &ctx->key); *b->last++ = CR; *b->last++ = LF; return NGX_OK; }
void ngx_http_lua_wev_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ngx_http_lua_main_conf_t *lmcf; lua_State *cc; ngx_chain_t *cl; size_t len; u_char *pos, *last; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { goto error; } dd("request done: %d", (int) r->done); dd("cleanup done: %p", ctx->cleanup); #if 1 if (ctx->cleanup == NULL) { return; } #endif if (ctx->waiting && ! ctx->done) { if (r->main->posted_requests && r->main->posted_requests->request != r) { dd("postpone our wev handler"); #if defined(nginx_version) && nginx_version >= 8012 ngx_http_post_request(r, NULL); #else ngx_http_post_request(r); #endif return; } } ctx->done = 0; len = 0; for (cl = ctx->sr_body; cl; cl = cl->next) { /* ignore all non-memory buffers */ len += cl->buf->last - cl->buf->pos; } if (len == 0) { pos = NULL; } else { last = pos = ngx_palloc(r->pool, len); if (pos == NULL) { goto error; } for (cl = ctx->sr_body; cl; cl = cl->next) { /* ignore all non-memory buffers */ last = ngx_copy(last, cl->buf->pos, cl->buf->last - cl->buf->pos); } } cc = ctx->cc; /* {{{ construct ret value */ lua_newtable(cc); /* copy captured status */ lua_pushinteger(cc, ctx->sr_status); lua_setfield(cc, -2, "status"); /* copy captured body */ lua_pushlstring(cc, (const char*)pos, len); lua_setfield(cc, -2, "body"); /* }}} */ lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); dd("about to run thread..."); rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 1); dd("already run thread..."); if (rc == NGX_AGAIN || rc == NGX_DONE) { ctx->waiting = 1; ctx->done = 0; } else { ctx->waiting = 0; ctx->done = 1; ngx_http_finalize_request(r, rc); } return; error: ngx_http_finalize_request(r, ctx->headers_sent ? NGX_ERROR: NGX_HTTP_INTERNAL_SERVER_ERROR); return; }
static ngx_int_t ngx_http_vod_extract_uri_params( ngx_http_request_t* r, ngx_hash_t* params_hash, ngx_str_t* uri, media_sequence_t* sequence, uint32_t* clip_id, media_clip_source_t* source_clip, media_clip_t** result) { ngx_http_vod_uri_param_def_t* param_def = NULL; media_clip_rate_filter_t* rate_filter = NULL; request_context_t request_context; ngx_uint_t cur_key_hash = 0; ngx_str_t cur_param; ngx_int_t rc; uint32_t parsed_params_mask = 0; uint32_t param_index; u_char param_name[MAX_URI_PARAM_NAME_LEN + 1]; u_char* param_name_end = param_name + sizeof(param_name); u_char* param_name_pos = param_name; u_char* copy_start = uri->data; u_char* cur_pos; u_char* end_pos = uri->data + uri->len; u_char* last_slash = NULL; u_char* p; // set the source defaults vod_memzero(source_clip, sizeof(*source_clip)); source_clip->base.type = MEDIA_CLIP_SOURCE; source_clip->base.id = (*clip_id)++; source_clip->clip_to = UINT_MAX; source_clip->tracks_mask[MEDIA_TYPE_AUDIO] = 0xffffffff; source_clip->tracks_mask[MEDIA_TYPE_VIDEO] = 0xffffffff; source_clip->uri = *uri; source_clip->sequence = sequence; *result = &source_clip->base; // allocate the stripped uri p = ngx_palloc(r->pool, uri->len + 1); if (p == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_extract_uri_params: ngx_palloc failed (1)"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } source_clip->stripped_uri.data = p; for (cur_pos = uri->data; cur_pos <= end_pos; cur_pos++) { if (cur_pos < end_pos && *cur_pos != '/') { if (param_name_pos < param_name_end) { *param_name_pos = ngx_tolower(*cur_pos); cur_key_hash = ngx_hash(cur_key_hash, *param_name_pos); param_name_pos++; } continue; } if (last_slash == NULL) { last_slash = cur_pos; cur_key_hash = 0; param_name_pos = param_name; continue; } if (param_def == NULL) { param_def = ngx_hash_find(params_hash, cur_key_hash, param_name, param_name_pos - param_name); if (param_def != NULL) { p = ngx_copy(p, copy_start, last_slash - copy_start); copy_start = last_slash; } } else { param_index = param_def - uri_param_defs; if ((parsed_params_mask & (1 << param_index)) == 0) // first instance of a param takes priority { parsed_params_mask |= (1 << param_index); cur_param.data = last_slash + 1; cur_param.len = cur_pos - (last_slash + 1); if (param_def->name_conf_offset == offsetof(ngx_http_vod_loc_conf_t, speed_param_name)) { request_context.pool = r->pool; request_context.log = r->connection->log; rc = rate_filter_create_from_string( &request_context, &cur_param, &source_clip->base, &rate_filter); if (rc != VOD_OK) { return ngx_http_vod_status_to_ngx_error(rc); } if (rate_filter->rate.nom != rate_filter->rate.denom) { rate_filter->base.id = (*clip_id)++; *result = &rate_filter->base; } } else { rc = param_def->parser(&cur_param, source_clip, param_def->target_offset); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_extract_uri_params: %s parser failed %i", param_def->name, rc); return rc; } } } copy_start = cur_pos; param_def = NULL; } last_slash = cur_pos; cur_key_hash = 0; param_name_pos = param_name; } if (source_clip->clip_from >= source_clip->clip_to) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_extract_uri_params: clip from %uD is larger than clip to %uD", source_clip->clip_from, source_clip->clip_to); return NGX_HTTP_BAD_REQUEST; } p = ngx_copy(p, copy_start, end_pos - copy_start); *p = '\0'; source_clip->stripped_uri.len = p - source_clip->stripped_uri.data; source_clip->mapped_uri = source_clip->stripped_uri; return NGX_OK; }
static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) { u_char *p, *name; size_t len, root, reserve, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_uint_t i, dir_tested; ngx_http_index_t *index; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_index_loc_conf_t *ilcf; ngx_http_script_len_code_pt lcode; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); allocated = 0; root = 0; dir_tested = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; index = ilcf->indices->elts; for (i = 0; i < ilcf->indices->nelts; i++) { if (index[i].lengths == NULL) { if (index[i].name.data[0] == '/') { return ngx_http_internal_redirect(r, &index[i].name, &r->args); } reserve = ilcf->max_index_len; len = index[i].name.len; } else { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = index[i].lengths->elts; e.request = r; e.flushed = 1; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } /* 16 bytes are preallocation */ reserve = len + 16; } if (reserve > allocated) { name = ngx_http_map_uri_to_path(r, &path, &root, reserve); if (name == NULL) { return NGX_ERROR; } allocated = path.data + path.len - name; } if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ ngx_memcpy(name, index[i].name.data, index[i].name.len); path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } if (*name == '/') { uri.len = len - 1; uri.data = name; return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "open index \"%V\"", &path); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) { return ngx_http_index_error(r, clcf, path.data, of.err); } if (!dir_tested) { rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } dir_tested = 1; } if (of.err == NGX_ENOENT) { continue; } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len = r->uri.len + len - 1; if (!clcf->alias) { uri.data = path.data + root; } else { uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(p, name, len - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); } return NGX_DECLINED; }
static ngx_int_t ngx_http_redis_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; ngx_http_redis_ctx_t *ctx; ngx_http_redis_loc_conf_t *rlcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module); if (rlcf->complex_target) { ngx_str_t target; ngx_url_t url; /* variables used in the redis_pass directive */ if (ngx_http_complex_value(r, rlcf->complex_target, &target) != NGX_OK) { return NGX_ERROR; } if (target.len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "handler: empty \"redis_pass\" target"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } url.host = target; url.port = 0; url.default_port = 6379; url.no_resolve = 1; rlcf->upstream.upstream = ngx_http_redis_upstream_add(r, &url); if (rlcf->upstream.upstream == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "redis: upstream \"%V\" not found", &target); return NGX_HTTP_INTERNAL_SERVER_ERROR; } } #if defined nginx_version && nginx_version >= 8011 if (ngx_http_upstream_create(r) != NGX_OK) { #else u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); if (u == NULL) { #endif return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if defined nginx_version && nginx_version >= 8011 u = r->upstream; #endif #if defined nginx_version && nginx_version >= 8037 ngx_str_set(&u->schema, "redis://"); #else u->schema.len = sizeof("redis://") - 1; u->schema.data = (u_char *) "redis://"; #endif #if defined nginx_version && nginx_version >= 8011 u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module; #else u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; #endif #if !defined(nginx_version) || nginx_version < 8011 u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module; #endif u->conf = &rlcf->upstream; u->create_request = ngx_http_redis_create_request; u->reinit_request = ngx_http_redis_reinit_request; u->process_header = ngx_http_redis_process_header; u->abort_request = ngx_http_redis_abort_request; u->finalize_request = ngx_http_redis_finalize_request; #if defined nginx_version && nginx_version < 8011 r->upstream = u; #endif ctx = ngx_palloc(r->pool, sizeof(ngx_http_redis_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->rest = NGX_HTTP_REDIS_END; ctx->request = r; ngx_http_set_ctx(r, ctx, ngx_http_redis_module); u->input_filter_init = ngx_http_redis_filter_init; u->input_filter = ngx_http_redis_filter; u->input_filter_ctx = ctx; #if defined nginx_version && nginx_version >= 8011 r->main->count++; #endif ngx_http_upstream_init(r); return NGX_DONE; } static ngx_int_t ngx_http_redis_create_request(ngx_http_request_t *r) { size_t len = 0; uintptr_t escape; ngx_buf_t *b; ngx_chain_t *cl; ngx_http_redis_ctx_t *ctx; ngx_http_variable_value_t *vv[3]; ngx_http_redis_loc_conf_t *rlcf; u_char lenbuf[NGX_INT_T_LEN]; rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module); vv[0] = ngx_http_get_indexed_variable(r, ngx_http_redis_auth_index); if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "no auth command provided" ); } else { len += sizeof("*2\r\n$4\r\nauth\r\n$") - 1; len += ngx_sprintf(lenbuf, "%d", vv[0]->len) - lenbuf; len += sizeof(CRLF) - 1 + vv[0]->len; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth info: %s", vv[0]->data); } len += sizeof(CRLF) - 1; vv[1] = ngx_http_get_indexed_variable(r, ngx_http_redis_db_index); /* * If user do not select redis database in nginx.conf by redis_db * variable, just add size of "select 0" to request. This is add * some overhead in talk with redis, but this way simplify parsing * the redis answer in ngx_http_redis_process_header(). */ if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select 0 redis database" ); len += sizeof("*2\r\n$6\r\nselect\r\n$1\r\n0") - 1; } else { len += sizeof("*2\r\n$6\r\nselect\r\n$") - 1; len += ngx_sprintf(lenbuf, "%d", vv[1]->len) - lenbuf; len += sizeof(CRLF) - 1 + vv[1]->len; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select %s redis database", vv[1]->data); } len += sizeof(CRLF) - 1; vv[2] = ngx_http_get_indexed_variable(r, rlcf->index); /* If nginx.conf have no redis_key return error. */ if (vv[2] == NULL || vv[2]->not_found || vv[2]->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$redis_key\" variable is not set"); return NGX_ERROR; } /* Count have space required escape symbols. */ escape = 2 * ngx_escape_uri(NULL, vv[2]->data, vv[2]->len, NGX_ESCAPE_REDIS); len += sizeof("*2\r\n$3\r\nget\r\n$") - 1; len += ngx_sprintf(lenbuf, "%d", vv[2]->len) - lenbuf; len += sizeof(CRLF) - 1 + vv[2]->len + escape + sizeof(CRLF) - 1; /* Create temporary buffer for request with size len. */ b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; r->upstream->request_bufs = cl; /* add "auth " for request */ if (vv[0] != NULL && !(vv[0]->not_found) && vv[0]->len != 0) { /* Add "auth " for request. */ b->last = ngx_sprintf(b->last, "*2\r\n$4\r\nauth\r\n$%d\r\n", vv[0]->len); b->last = ngx_copy(b->last, vv[0]->data, vv[0]->len); *b->last++ = CR; *b->last++ = LF; } /* Get context redis_db from configuration file. */ ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module); ctx->key.data = b->last; /* * Add "0" as redis number db to request if redis_db undefined, * othervise add real number from context. */ if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) { b->last = ngx_sprintf(b->last, "*2\r\n$6\r\nselect\r\n$1\r\n0"); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select 0 redis database" ); } else { b->last = ngx_sprintf(b->last, "*2\r\n$6\r\nselect\r\n$%d\r\n", vv[1]->len); b->last = ngx_copy(b->last, vv[1]->data, vv[1]->len); ctx->key.len = b->last - ctx->key.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select %V redis database", &ctx->key); } /* Add "\r\n". */ *b->last++ = CR; *b->last++ = LF; b->last = ngx_sprintf(b->last, "*2\r\n$3\r\nget\r\n$%d\r\n", vv[2]->len); /* Get context redis_key from nginx.conf. */ ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module); ctx->key.data = b->last; /* * If no escape symbols then copy data as is, othervise use * escape-copy function. */ if (escape == 0) { b->last = ngx_copy(b->last, vv[2]->data, vv[2]->len); } else { b->last = (u_char *) ngx_escape_uri(b->last, vv[2]->data, vv[2]->len, NGX_ESCAPE_REDIS); } ctx->key.len = b->last - ctx->key.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http redis request: \"%V\"", &ctx->key); /* Add one more "\r\n". */ *b->last++ = CR; *b->last++ = LF; /* * Summary, the request looks like this: * "auth $redis_auth\r\nselect $redis_db\r\nget $redis_key\r\n", where * $redis_auth, $redis_db and $redis_key are variable's values. */ return NGX_OK; }
char * ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { u_char *p; u_char *name; ngx_str_t *value; ngx_http_lua_srv_conf_t *lscf = conf; ngx_http_upstream_srv_conf_t *uscf; dd("enter"); /* must specifiy a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } if (lscf->balancer.handler) { return "is duplicate"; } value = cf->args->elts; lscf->balancer.handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; if (cmd->post == ngx_http_lua_balancer_handler_file) { /* Lua code in an external file */ name = ngx_http_lua_rebase_path(cf->pool, value[1].data, value[1].len); if (name == NULL) { return NGX_CONF_ERROR; } lscf->balancer.src.data = name; lscf->balancer.src.len = ngx_strlen(name); p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); if (p == NULL) { return NGX_CONF_ERROR; } lscf->balancer.src_key = p; p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); *p = '\0'; } else { /* inlined Lua code */ lscf->balancer.src = value[1]; p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); if (p == NULL) { return NGX_CONF_ERROR; } lscf->balancer.src_key = p; p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); *p = '\0'; } uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); if (uscf->peer.init_upstream) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "load balancing method redefined"); } uscf->peer.init_upstream = ngx_http_lua_balancer_init; uscf->flags = NGX_HTTP_UPSTREAM_CREATE |NGX_HTTP_UPSTREAM_WEIGHT |NGX_HTTP_UPSTREAM_MAX_FAILS |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT |NGX_HTTP_UPSTREAM_DOWN; return NGX_CONF_OK; }