int ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, const u_char *key, size_t key_len, const u_char *value, size_t value_len) { ngx_str_t k; ngx_str_t v; if (r->connection->fd == (ngx_socket_t) -1) { /* fake request */ return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } if (r->http_version < NGX_HTTP_VERSION_10) { return NGX_DECLINED; } k.data = ngx_palloc(r->pool, key_len + 1); if (k.data == NULL) { return NGX_ERROR; } ngx_memcpy(k.data, key, key_len); k.data[key_len] = '\0'; k.len = key_len; if (value_len == 0) { v.data = NULL; v.len = 0; } else { v.data = ngx_palloc(r->pool, value_len + 1); if (v.data == NULL) { return NGX_ERROR; } ngx_memcpy(v.data, value, value_len); v.data[value_len] = '\0'; } v.len = value_len; if (ngx_http_lua_set_input_header(r, k, v, 1 /* override */) != NGX_OK) { return NGX_ERROR; } return NGX_OK; }
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_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_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; }