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_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_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_req_init_body(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_int_t rc; 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); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); 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 = r->headers_in.content_length_n; } } if (r->request_body == NULL) { #if 1 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"); } #endif rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return luaL_error(L, "out of memory"); } r->request_body = rb; } else { 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, "out of memory"); } rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "out of memory"); } rb->bufs->buf = rb->buf; rb->bufs->next = NULL; return 0; }