static int ngx_http_lua_ngx_req_set_keepalive(lua_State *L) { int n; ngx_http_request_t *r; int keepalive; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument expected but got %d", n); } keepalive = lua_toboolean(L, 1); 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); r->keepalive = keepalive; return 1; }
static int ngx_http_lua_ngx_req_discard_body(lua_State *L) { ngx_http_request_t *r; ngx_int_t rc; int n; 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); rc = ngx_http_discard_request_body(r); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return luaL_error(L, "failed to discard request body"); } return 0; }
static int ngx_http_lua_ngx_req_http_version(lua_State *L) { ngx_http_request_t *r; 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); switch (r->http_version) { case NGX_HTTP_VERSION_9: lua_pushnumber(L, 0.9); break; case NGX_HTTP_VERSION_10: lua_pushnumber(L, 1.0); break; case NGX_HTTP_VERSION_11: lua_pushnumber(L, 1.1); break; default: lua_pushnil(L); break; } return 1; }
static int ngx_http_lua_ngx_set(lua_State *L) { ngx_http_request_t *r; u_char *p; size_t len; /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } if (r->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to set ngx.status after sending out " "response headers"); return 0; } ngx_http_lua_check_fake_request(L, r); /* get the value */ r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3); if (r->headers_out.status == 101) { /* * XXX work-around a bug in the Nginx core that 101 does * not have a default status line */ ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols"); } else { r->headers_out.status_line.len = 0; } return 0; } if (len == sizeof("ctx") - 1 && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } return ngx_http_lua_ngx_set_ctx(L); } lua_rawset(L, -3); return 0; }
static int ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { ngx_http_request_t *r; ngx_str_t args; const char *msg; size_t len; u_char *p; if (lua_gettop(L) != 1) { return luaL_error(L, "expecting 1 argument but seen %d", lua_gettop(L)); } 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); switch (lua_type(L, 1)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 1, &len); args.data = ngx_palloc(r->pool, len); if (args.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(args.data, p, len); args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 1, &args); dd("args: %.*s", (int) args.len, args.data); break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 1, msg); } dd("args: %.*s", (int) args.len, args.data); r->args.data = args.data; r->args.len = args.len; r->valid_unparsed_uri = 0; return 0; }
static int ngx_http_lua_ngx_req_get_uri_args(lua_State *L) { ngx_http_request_t *r; u_char *buf; u_char *last; int retval; int n; int max; n = lua_gettop(L); if (n != 0 && n != 1) { return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n); } if (n == 1) { max = luaL_checkinteger(L, 1); lua_pop(L, 1); } else { max = NGX_HTTP_LUA_MAX_ARGS; } 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"); } ngx_http_lua_check_fake_request(L, r); lua_createtable(L, 0, 4); /* we copy r->args over to buf to simplify * unescaping query arg keys and values */ buf = ngx_palloc(r->pool, r->args.len); if (buf == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(buf, r->args.data, r->args.len); last = buf + r->args.len; retval = ngx_http_lua_parse_args(r, L, buf, last, max); ngx_pfree(r->pool, buf); return retval; }
static int ngx_http_lua_ngx_header_get(lua_State *L) { ngx_http_request_t *r; u_char *p; ngx_str_t key; ngx_uint_t i; size_t len; ngx_http_lua_loc_conf_t *llcf; 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"); } ngx_http_lua_check_fake_request(L, r); /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers) { /* replace "_" with "-" */ for (i = 0; i < len; i++) { if (p[i] == '_') { p[i] = '-'; } } } key.data = ngx_palloc(r->pool, len + 1); if (key.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(key.data, p, len); key.data[len] = '\0'; key.len = len; return ngx_http_lua_get_output_header(L, r, &key); }
static int ngx_http_lua_ngx_header_get(lua_State *L) { ngx_http_request_t *r; u_char *p, c; ngx_str_t key; ngx_uint_t i; size_t len; ngx_http_lua_loc_conf_t *llcf; 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); /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(p, '_', len) != NULL) { key.data = (u_char *) lua_newuserdata(L, len); if (key.data == NULL) { return luaL_error(L, "no memory"); } /* replace "_" with "-" */ for (i = 0; i < len; i++) { c = p[i]; if (c == '_') { c = '-'; } key.data[i] = c; } } else { key.data = p; } key.len = len; return ngx_http_lua_get_output_header(L, r, &key); }
static int ngx_http_lua_ngx_req_get_keepalive(lua_State *L) { int n; ngx_http_request_t *r; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "no arguments expected but got %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); lua_pushboolean(L, r->keepalive); return 1; }
static int ngx_http_lua_ngx_req_get_method(lua_State *L) { int n; ngx_http_request_t *r; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "only one argument expected but got %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); lua_pushlstring(L, (char *) r->method_name.data, r->method_name.len); return 1; }
static int ngx_http_lua_ngx_req_get_body_file(lua_State *L) { ngx_http_request_t *r; int n; 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 == NULL) { lua_pushnil(L); return 1; } dd("XXX file directio: %u, f:%u, m:%u, t:%u, end - pos %d, size %d", r->request_body->temp_file->file.directio, r->request_body->bufs->buf->in_file, r->request_body->bufs->buf->memory, r->request_body->bufs->buf->temporary, (int) (r->request_body->bufs->buf->end - r->request_body->bufs->buf->pos), (int) ngx_buf_size(r->request_body->bufs->buf)); lua_pushlstring(L, (char *) r->request_body->temp_file->file.name.data, r->request_body->temp_file->file.name.len); return 1; }
static int ngx_http_lua_ngx_req_http_version(lua_State *L) { ngx_http_request_t *r; 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"); } ngx_http_lua_check_fake_request(L, r); switch (r->http_version) { case NGX_HTTP_VERSION_9: lua_pushnumber(L, 0.9); break; case NGX_HTTP_VERSION_10: lua_pushnumber(L, 1.0); break; case NGX_HTTP_VERSION_11: lua_pushnumber(L, 1.1); break; default: lua_pushnil(L); break; } return 1; }
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; }
static int ngx_http_lua_ngx_req_get_headers(lua_State *L) { ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_request_t *r; ngx_uint_t i; int n; int max; int raw = 0; int count = 0; n = lua_gettop(L); if (n >= 1) { if (lua_isnil(L, 1)) { max = NGX_HTTP_LUA_MAX_HEADERS; } else { max = luaL_checkinteger(L, 1); } if (n >= 2) { raw = lua_toboolean(L, 2); } } else { max = NGX_HTTP_LUA_MAX_HEADERS; } 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); part = &r->headers_in.headers.part; count = part->nelts; while (part->next) { part = part->next; count += part->nelts; } if (max > 0 && count > max) { count = max; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exceeding request header limit %d", max); } lua_createtable(L, 0, count); if (!raw) { lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { dd("stack top: %d", lua_gettop(L)); if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (raw) { lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); } else { lua_pushlstring(L, (char *) header[i].lowcase_key, header[i].key.len); } /* stack: table key */ lua_pushlstring(L, (char *) header[i].value.data, header[i].value.len); /* stack: table key value */ ngx_http_lua_set_multi_value_table(L, -3); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua request header: \"%V: %V\"", &header[i].key, &header[i].value); if (--count == 0) { return 1; } } return 1; }
static int ngx_http_lua_ngx_req_set_body_file(lua_State *L) { u_char *p; 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 name; ngx_int_t rc; int clean; ngx_open_file_info_t of; ngx_str_t key, value; ngx_pool_cleanup_t *cln; ngx_pool_cleanup_file_t *clnf; ngx_err_t err; ngx_chain_t *cl; ngx_buf_tag_t tag; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n); } p = (u_char *) luaL_checklstring(L, 1, &name.len); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request 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"); } name.data = ngx_palloc(r->pool, name.len + 1); if (name.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(name.data, p, name.len); name.data[name.len] = '\0'; if (n == 2) { luaL_checktype(L, 2, LUA_TBOOLEAN); clean = lua_toboolean(L, 2); } else { clean = 0; } dd("clean: %d", (int) clean); rb = r->request_body; /* clean up existing r->request_body->bufs (if any) */ tag = (ngx_buf_tag_t) &ngx_http_lua_module; if (rb->bufs) { dd("XXX reusing buf"); 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->tag = tag; rb->buf = NULL; } else { dd("XXX creating new buf"); rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "no memory"); } rb->bufs->next = NULL; b = ngx_calloc_buf(r->pool); if (b == NULL) { return luaL_error(L, "no memory"); } b->tag = tag; rb->bufs->buf = b; rb->buf = NULL; } b->last_in_chain = 1; /* just make r->request_body->temp_file a bare stub */ 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); ngx_memzero(tf, sizeof(ngx_temp_file_t)); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } } else { tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return luaL_error(L, "no memory"); } tf->file.fd = NGX_INVALID_FILE; rb->temp_file = tf; } /* read the file info and construct an in-file buf */ ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; if (ngx_http_lua_open_and_stat_file(name.data, &of, r->connection->log) != NGX_OK) { return luaL_error(L, "%s \"%s\" failed", of.failed, name.data); } dd("XXX new body file fd: %d", of.fd); tf->file.fd = of.fd; tf->file.name = name; tf->file.log = r->connection->log; tf->file.directio = 0; if (of.size == 0) { if (clean) { if (ngx_delete_file(name.data) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_delete_file_n " \"%s\" failed", name.data); } } } if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } r->request_body->bufs = NULL; r->request_body->buf = NULL; goto set_header; } /* register file cleanup hook */ cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t)); if (cln == NULL) { return luaL_error(L, "no memory"); } cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file; clnf = cln->data; clnf->fd = of.fd; clnf->name = name.data; clnf->log = r->pool->log; b->file = &tf->file; if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } dd("XXX file size: %d", (int) of.size); b->file_pos = 0; b->file_last = of.size; b->in_file = 1; dd("buf file: %p, f:%u", b->file, b->in_file); set_header: /* override input header Content-Length (value must be null terminated) */ value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN + 1); if (value.data == NULL) { return luaL_error(L, "no memory"); } value.len = ngx_sprintf(value.data, "%O", of.size) - value.data; value.data[value.len] = '\0'; r->headers_in.content_length_n = of.size; 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_req_body_finish(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_buf_t *b; size_t size; ngx_str_t value; ngx_str_t key; ngx_int_t rc; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "expecting 0 argument but seen %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ngx_http_lua_check_fake_request(L, r); if (r->request_body == NULL || r->request_body->buf == NULL || r->request_body->bufs == NULL) { return luaL_error(L, "request_body not initalized"); } rb = r->request_body; if (rb->temp_file) { /* save the last part */ if (ngx_http_lua_write_request_body(r, rb->bufs) != NGX_OK) { return luaL_error(L, "fail to write file"); } b = ngx_calloc_buf(r->pool); if (b == NULL) { return luaL_error(L, "no memory"); } b->in_file = 1; b->file_pos = 0; b->file_last = rb->temp_file->file.offset; b->file = &rb->temp_file->file; if (rb->bufs->next) { rb->bufs->next->buf = b; } else { rb->bufs->buf = b; } } /* 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"); } size = (size_t) r->headers_in.content_length_n; value.len = ngx_sprintf(value.data, "%uz", size) - value.data; value.data[value.len] = '\0'; dd("setting request Content-Length to %.*s (%d)", (int) value.len, value.data, (int) size); 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_req_append_body(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_str_t body; size_t size, rest; size_t offset = 0; 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, "no request found"); } ngx_http_lua_check_fake_request(L, r); if (r->request_body == NULL || r->request_body->buf == NULL || r->request_body->bufs == NULL) { return luaL_error(L, "request_body not initalized"); } rb = r->request_body; rest = body.len; while (rest > 0) { if (rb->buf->last == rb->buf->end) { if (ngx_http_lua_write_request_body(r, rb->bufs) != NGX_OK) { return luaL_error(L, "fail to write file"); } rb->buf->last = rb->buf->start; } size = rb->buf->end - rb->buf->last; if (size > rest) { size = rest; } ngx_memcpy(rb->buf->last, body.data + offset, size); rb->buf->last += size; rest -= size; offset += size; r->headers_in.content_length_n += size; } return 0; }
static int ngx_http_lua_ngx_req_init_body(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; size_t size; lua_Integer num; #if 1 ngx_temp_file_t *tf; #endif ngx_http_core_loc_conf_t *clcf; n = lua_gettop(L); if (n != 1 && n != 0) { return luaL_error(L, "expecting 0 or 1 argument but seen %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request 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"); } if (n == 1) { num = luaL_checkinteger(L, 1); if (num <= 0) { return luaL_error(L, "bad size argument: %d", (int) num); } size = (size_t) num; } else { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); size = clcf->client_body_buffer_size; size += size >> 2; /* avoid allocating an unnecessary large buffer */ if (size > (size_t) r->headers_in.content_length_n) { size = (size_t) r->headers_in.content_length_n; } } rb = r->request_body; #if 1 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); ngx_memzero(tf, sizeof(ngx_temp_file_t)); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } rb->temp_file = NULL; } #endif r->request_body_in_clean_file = 1; r->headers_in.content_length_n = 0; rb->buf = ngx_create_temp_buf(r->pool, size); if (rb->buf == NULL) { return luaL_error(L, "no memory"); } rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "no memory"); } rb->bufs->buf = rb->buf; rb->bufs->next = NULL; return 0; }
static int ngx_http_lua_ngx_get(lua_State *L) { int status; ngx_http_request_t *r; u_char *p; size_t len; ngx_http_lua_ctx_t *ctx; r = ngx_http_lua_get_req(L); if (r == NULL) { lua_pushnil(L); return 1; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { lua_pushnil(L); return 1; } p = (u_char *) luaL_checklstring(L, -1, &len); dd("ngx get %s", p); if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { ngx_http_lua_check_fake_request(L, r); if (r->err_status) { status = r->err_status; } else if (r->headers_out.status) { status = r->headers_out.status; } else if (r->http_version == NGX_HTTP_VERSION_9) { status = 9; } else { status = 0; } lua_pushinteger(L, status); return 1; } if (len == sizeof("ctx") - 1 && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { return ngx_http_lua_ngx_get_ctx(L); } if (len == sizeof("is_subrequest") - 1 && ngx_strncmp(p, "is_subrequest", sizeof("is_subrequest") - 1) == 0) { lua_pushboolean(L, r != r->main); return 1; } if (len == sizeof("headers_sent") - 1 && ngx_strncmp(p, "headers_sent", sizeof("headers_sent") - 1) == 0) { ngx_http_lua_check_fake_request(L, r); dd("headers sent: %d", r->header_sent || ctx->header_sent); lua_pushboolean(L, r->header_sent || ctx->header_sent); return 1; } dd("key %s not matched", p); lua_pushnil(L); return 1; }
static int ngx_http_lua_ngx_req_raw_header(lua_State *L) { int n; 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; 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 0 dd("hc->nbusy: %d", (int) 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 >= b->start && mr->request_line.data + mr->request_line.len + 2 <= b->pos) { first = b; if (mr->header_in == b) { size += mr->header_end + 2 - mr->request_line.data; } else { /* the subsequent part of the header is in the large header * buffers */ #if 1 p = b->pos; size += p - mr->request_line.data; /* skip truncated header entries (if any) */ while (b->pos > b->start && b->pos[-1] != LF) { b->pos--; size--; } #endif } } 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 + 2 <= b->start) { continue; } dd("found first at %d", (int) i); first = b; } if (b == mr->header_in) { size += mr->header_end + 2 - b->start; break; } size += b->pos - b->start; } } data = lua_newuserdata(L, size); last = data; b = c->buffer; if (first == b) { if (mr->header_in == b) { pos = mr->header_end + 2; } else { pos = b->pos; } if (no_req_line) { last = ngx_copy(data, mr->request_line.data + mr->request_line.len + 2, pos - mr->request_line.data - mr->request_line.len - 2); } else { last = ngx_copy(data, mr->request_line.data, pos - mr->request_line.data); } for (p = data; p != last; p++) { if (*p == '\0') { if (p + 1 != last && *(p + 1) == LF) { *p = CR; } else { *p = ':'; } } } } if (hc->nbusy) { found = (b == c->buffer); for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; if (!found) { if (b != first) { continue; } dd("found first"); found = 1; } p = last; if (b == mr->header_in) { pos = mr->header_end + 2; } else { 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 + 2, pos - mr->request_line.data - mr->request_line.len - 2); } 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 for (; p != last; p++) { if (*p == '\0') { if (p + 1 == last) { /* XXX this should not happen */ dd("found string end!!"); } else if (*(p + 1) == LF) { *p = CR; } else { *p = ':'; } } } if (b == mr->header_in) { break; } } } if (last - data > (ssize_t) size) { return luaL_error(L, "buffer error: %d", (int) (last - data - size)); } lua_pushlstring(L, (char *) data, last - data); return 1; }
static int ngx_http_lua_ngx_resp_get_headers(lua_State *L) { ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_request_t *r; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; int n; int max; int raw = 0; int count = 0; n = lua_gettop(L); if (n >= 1) { if (lua_isnil(L, 1)) { max = NGX_HTTP_LUA_MAX_HEADERS; } else { max = luaL_checkinteger(L, 1); } if (n >= 2) { raw = lua_toboolean(L, 2); } } else { max = NGX_HTTP_LUA_MAX_HEADERS; } 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); part = &r->headers_out.headers.part; count = part->nelts; while (part->next) { part = part->next; count += part->nelts; } if (max > 0 && count > max) { count = max; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exceeding request header limit %d", max); } lua_createtable(L, 0, count); if (!raw) { lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } part = &r->headers_out.headers.part; header = part->elts; for (i = 0; /* void */; i++) { dd("stack top: %d", lua_gettop(L)); if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } if (raw) { lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); } else { /* nginx does not even bother initializing output header entry's * "lowcase_key" field. so we cannot count on that at all. */ if (header[i].key.len > lowcase_key_sz) { lowcase_key_sz = header[i].key.len * 2; /* we allocate via Lua's GC to prevent in-request * leaks in the nginx request memory pools */ lowcase_key = lua_newuserdata(L, lowcase_key_sz); lua_insert(L, 1); } ngx_strlow(lowcase_key, header[i].key.data, header[i].key.len); lua_pushlstring(L, (char *) lowcase_key, header[i].key.len); } /* stack: [udata] table key */ lua_pushlstring(L, (char *) header[i].value.data, header[i].value.len); /* stack: [udata] table key value */ ngx_http_lua_set_multi_value_table(L, -3); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua response header: \"%V: %V\"", &header[i].key, &header[i].value); if (--count == 0) { return 1; } } return 1; }
static int ngx_http_lua_ngx_req_set_method(lua_State *L) { int n; int method; ngx_http_request_t *r; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument expected but got %d", n); } method = luaL_checkint(L, 1); 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); r->method = method; switch (method) { case NGX_HTTP_GET: r->method_name = ngx_http_lua_get_method; break; case NGX_HTTP_POST: r->method_name = ngx_http_lua_post_method; break; case NGX_HTTP_PUT: r->method_name = ngx_http_lua_put_method; break; case NGX_HTTP_HEAD: r->method_name = ngx_http_lua_head_method; break; case NGX_HTTP_DELETE: r->method_name = ngx_http_lua_delete_method; break; case NGX_HTTP_OPTIONS: r->method_name = ngx_http_lua_options_method; break; case NGX_HTTP_MKCOL: r->method_name = ngx_http_lua_mkcol_method; break; case NGX_HTTP_COPY: r->method_name = ngx_http_lua_copy_method; break; case NGX_HTTP_MOVE: r->method_name = ngx_http_lua_move_method; break; case NGX_HTTP_PROPFIND: r->method_name = ngx_http_lua_propfind_method; break; case NGX_HTTP_PROPPATCH: r->method_name = ngx_http_lua_proppatch_method; break; case NGX_HTTP_LOCK: r->method_name = ngx_http_lua_lock_method; break; case NGX_HTTP_UNLOCK: r->method_name = ngx_http_lua_unlock_method; break; case NGX_HTTP_PATCH: r->method_name = ngx_http_lua_patch_method; break; case NGX_HTTP_TRACE: r->method_name = ngx_http_lua_trace_method; break; default: return luaL_error(L, "unsupported HTTP method: %d", method); } return 0; }
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; }
/** * Get nginx internal variables content * * @retval Always return a string or nil on Lua stack. Return nil when failed * to get content, and actual content string when found the specified variable. * @seealso ngx_http_lua_var_set * */ static int ngx_http_lua_var_get(lua_State *L) { ngx_http_request_t *r; u_char *p, *lowcase; size_t len; ngx_uint_t hash; ngx_str_t name; ngx_http_variable_value_t *vv; #if (NGX_PCRE) u_char *val; ngx_uint_t n; LUA_NUMBER index; int *cap; #endif 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); #if (NGX_PCRE) if (lua_type(L, -1) == LUA_TNUMBER) { /* it is a regex capturing variable */ index = lua_tonumber(L, -1); if (index <= 0) { lua_pushnil(L); return 1; } n = (ngx_uint_t) index * 2; dd("n = %d, ncaptures = %d", (int) n, (int) r->ncaptures); if (r->captures == NULL || r->captures_data == NULL || n >= r->ncaptures) { lua_pushnil(L); return 1; } /* n >= 0 && n < r->ncaptures */ cap = r->captures; p = r->captures_data; val = &p[cap[n]]; lua_pushlstring(L, (const char *) val, (size_t) (cap[n + 1] - cap[n])); return 1; } #endif if (lua_type(L, -1) != LUA_TSTRING) { return luaL_error(L, "bad variable name"); } p = (u_char *) lua_tolstring(L, -1, &len); lowcase = lua_newuserdata(L, len); hash = ngx_hash_strlow(lowcase, p, len); name.len = len; name.data = lowcase; vv = ngx_http_get_variable(r, &name, hash); if (vv == NULL || vv->not_found) { lua_pushnil(L); return 1; } lua_pushlstring(L, (const char *) vv->data, (size_t) vv->len); return 1; }
/** * Set nginx internal variable content * * @retval Always return a boolean on Lua stack. Return true when variable * content was modified successfully, false otherwise. * @seealso ngx_http_lua_var_get * */ static int ngx_http_lua_var_set(lua_State *L) { ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; u_char *p, *lowcase, *val; size_t len; ngx_str_t name; ngx_uint_t hash; ngx_http_request_t *r; int value_type; const char *msg; 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); /* we skip the first argument that is the table */ /* we read the variable name */ if (lua_type(L, 2) != LUA_TSTRING) { return luaL_error(L, "bad variable name"); } p = (u_char *) lua_tolstring(L, 2, &len); lowcase = lua_newuserdata(L, len + 1); hash = ngx_hash_strlow(lowcase, p, len); lowcase[len] = '\0'; name.len = len; name.data = lowcase; /* we read the variable new value */ value_type = lua_type(L, 3); switch (value_type) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) luaL_checklstring(L, 3, &len); val = ngx_palloc(r->pool, len); if (val == NULL) { return luaL_error(L, "memory allocation erorr"); } ngx_memcpy(val, p, len); break; case LUA_TNIL: /* undef the variable */ val = NULL; len = 0; break; default: msg = lua_pushfstring(L, "string, number, or nil expected, " "but got %s", lua_typename(L, value_type)); return luaL_argerror(L, 1, msg); } /* we fetch the variable itself */ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, hash, name.data, name.len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { return luaL_error(L, "variable \"%s\" not changeable", lowcase); } if (v->set_handler) { dd("set variables with set_handler"); vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { return luaL_error(L, "no memory"); } if (value_type == LUA_TNIL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; } v->set_handler(r, vv, v->data); return 0; } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &r->variables[v->index]; dd("set indexed variable"); if (value_type == LUA_TNIL) { vv->valid = 0; vv->not_found = 1; vv->no_cacheable = 0; vv->data = NULL; vv->len = 0; } else { vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = len; } return 0; } return luaL_error(L, "variable \"%s\" cannot be assigned a value", lowcase); } /* variable not found */ return luaL_error(L, "variable \"%s\" not found for writing; " "maybe it is a built-in variable that is not changeable " "or you forgot to use \"set $%s '';\" " "in the config file to define it first", lowcase, lowcase); }
static int ngx_http_lua_ngx_get(lua_State *L) { ngx_http_request_t *r; u_char *p; size_t len; ngx_http_lua_ctx_t *ctx; 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"); } p = (u_char *) luaL_checklstring(L, -1, &len); dd("ngx get %s", p); if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { ngx_http_lua_check_fake_request(L, r); lua_pushnumber(L, (lua_Number) r->headers_out.status); return 1; } if (len == sizeof("ctx") - 1 && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { return ngx_http_lua_ngx_get_ctx(L); } if (len == sizeof("is_subrequest") - 1 && ngx_strncmp(p, "is_subrequest", sizeof("is_subrequest") - 1) == 0) { lua_pushboolean(L, r != r->main); return 1; } if (len == sizeof("headers_sent") - 1 && ngx_strncmp(p, "headers_sent", sizeof("headers_sent") - 1) == 0) { ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx"); } ngx_http_lua_check_fake_request2(L, r, ctx); dd("headers sent: %d", ctx->headers_sent); lua_pushboolean(L, ctx->headers_sent ? 1 : 0); return 1; } dd("key %s not matched", p); lua_pushnil(L); return 1; }
static int ngx_http_lua_ngx_header_set(lua_State *L) { ngx_http_request_t *r; u_char *p; ngx_str_t key; ngx_str_t value; ngx_uint_t i; size_t len; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; ngx_uint_t n; ngx_http_lua_loc_conf_t *llcf; 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"); } ngx_http_lua_check_fake_request(L, r); if (r->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " "set ngx.header.HEADER after sending out " "response headers"); return 0; } /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); key.data = ngx_palloc(r->pool, len + 1); if (key.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(key.data, p, len); key.data[len] = '\0'; key.len = len; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers) { /* replace "_" with "-" */ p = key.data; for (i = 0; i < len; i++) { if (p[i] == '_') { p[i] = '-'; } } } if (!ctx->headers_set) { rc = ngx_http_lua_set_content_type(r); if (rc != NGX_OK) { return luaL_error(L, "failed to set default content type: %d", (int) rc); } ctx->headers_set = 1; } if (lua_type(L, 3) == LUA_TNIL) { value.data = NULL; value.len = 0; } else if (lua_type(L, 3) == LUA_TTABLE) { n = luaL_getn(L, 3); if (n == 0) { value.data = NULL; value.len = 0; } else { for (i = 1; i <= n; i++) { dd("header value table index %d", (int) i); lua_rawgeti(L, 3, i); p = (u_char *) luaL_checklstring(L, -1, &len); value.data = ngx_palloc(r->pool, len); if (value.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(value.data, p, len); value.len = len; rc = ngx_http_lua_set_output_header(r, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } } return 0; } } else { p = (u_char *) luaL_checklstring(L, 3, &len); value.data = ngx_palloc(r->pool, len); if (value.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(value.data, p, len); value.len = len; } dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } return 0; }
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_req_header_set_helper(lua_State *L) { ngx_http_request_t *r; u_char *p; ngx_str_t key; ngx_str_t value; ngx_uint_t i; size_t len; ngx_int_t rc; ngx_uint_t n; 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); if (r->http_version < NGX_HTTP_VERSION_10) { return 0; } p = (u_char *) luaL_checklstring(L, 1, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); #if 0 /* replace "_" with "-" */ for (i = 0; i < len; i++) { if (p[i] == '_') { p[i] = '-'; } } #endif key.data = ngx_palloc(r->pool, len + 1); if (key.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(key.data, p, len); key.data[len] = '\0'; key.len = len; if (lua_type(L, 2) == LUA_TNIL) { value.data = NULL; value.len = 0; } else if (lua_type(L, 2) == LUA_TTABLE) { n = luaL_getn(L, 2); if (n == 0) { value.data = NULL; value.len = 0; } else { for (i = 1; i <= n; i++) { dd("header value table index %d, top: %d", (int) i, lua_gettop(L)); lua_rawgeti(L, 2, i); p = (u_char *) luaL_checklstring(L, -1, &len); /* * we also copy the trailling '\0' char here because nginx * header values must be null-terminated * */ value.data = ngx_palloc(r->pool, len + 1); if (value.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(value.data, p, len + 1); value.len = len; rc = ngx_http_lua_set_input_header(r, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } } return 0; } } else { /* * we also copy the trailling '\0' char here because nginx * header values must be null-terminated * */ p = (u_char *) luaL_checklstring(L, 2, &len); value.data = ngx_palloc(r->pool, len + 1); if (value.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(value.data, p, len + 1); value.len = len; } dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", key.data, (int) rc); } return 0; }
static 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; int n; int max; n = lua_gettop(L); if (n != 0 && n != 1) { return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n); } if (n == 1) { max = luaL_checkinteger(L, 1); lua_pop(L, 1); } else { max = NGX_HTTP_LUA_MAX_ARGS; } 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"); } ngx_http_lua_check_fake_request(L, r); if (r->discard_body) { lua_createtable(L, 0, 0); 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, max); ngx_pfree(r->pool, buf); return retval; }