diff --git a/.travis.yml b/.travis.yml
index fc2e4c20bf..bf433bef5e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -86,6 +86,7 @@ install:
- git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core
- git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache
- git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql
+ - git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string
- git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2
diff --git a/README.markdown b/README.markdown
index ecaec83a5a..4bac43760d 100644
--- a/README.markdown
+++ b/README.markdown
@@ -5181,7 +5181,7 @@ ngx.req.socket
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
-Returns a read-only cosocket object that wraps the downstream connection. Only [receive](#tcpsockreceive) and [receiveuntil](#tcpsockreceiveuntil) methods are supported on this object.
+Returns a read-only cosocket object that wraps the downstream connection. Only [receive](#tcpsockreceive), [receiveany](#tcpsockreceiveany) and [receiveuntil](#tcpsockreceiveuntil) methods are supported on this object.
In case of error, `nil` will be returned as well as a string describing the error.
@@ -5190,7 +5190,7 @@ The socket object returned by this method is usually used to read the current re
If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading.
Chunked request bodies are not yet supported in this API.
-Since the `v0.9.0` release, this function accepts an optional boolean `raw` argument. When this argument is `true`, this function returns a full-duplex cosocket object wrapping around the raw downstream connection socket, upon which you can call the [receive](#tcpsockreceive), [receiveuntil](#tcpsockreceiveuntil), and [send](#tcpsocksend) methods.
+Since the `v0.9.0` release, this function accepts an optional boolean `raw` argument. When this argument is `true`, this function returns a full-duplex cosocket object wrapping around the raw downstream connection socket, upon which you can call the [receive](#tcpsockreceive), [receiveany](#tcpsockreceiveany), [receiveuntil](#tcpsockreceiveuntil), and [send](#tcpsocksend) methods.
When the `raw` argument is `true`, it is required that no pending data from any previous [ngx.say](#ngxsay), [ngx.print](#ngxprint), or [ngx.send_headers](#ngxsend_headers) calls exists. So if you have these downstream output calls previously, you should call [ngx.flush(true)](#ngxflush) before calling `ngx.req.socket(true)` to ensure that there is no pending output data. If the request body has not been read yet, then this "raw socket" can also be used to read the request body.
@@ -7269,7 +7269,7 @@ See also [ngx.socket.udp](#ngxsocketudp).
tcpsock:connect
---------------
-**syntax:** *ok, err = tcpsock:connect(host, port, options_table?)*
+**syntax:** *ok, err = tcpsock:connect(host, port?, options_table?)*
**syntax:** *ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)*
@@ -7288,6 +7288,8 @@ Both IP addresses and domain names can be specified as the `host` argument. In c
If the nameserver returns multiple IP addresses for the host name, this method will pick up one randomly.
+`port` is optional and accept nil (for compatibility with host is a unix domain), and it default value is zero.
+
In case of error, the method returns `nil` followed by a string describing the error. In case of success, the method returns `1`.
Here is an example for connecting to a TCP server:
diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki
index 215a5d5196..ae8c41af9a 100644
--- a/doc/HttpLuaModule.wiki
+++ b/doc/HttpLuaModule.wiki
@@ -4342,7 +4342,7 @@ See also [[#ngx.req.init_body|ngx.req.init_body]].
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
-Returns a read-only cosocket object that wraps the downstream connection. Only [[#tcpsock:receive|receive]] and [[#tcpsock:receiveuntil|receiveuntil]] methods are supported on this object.
+Returns a read-only cosocket object that wraps the downstream connection. Only [[#tcpsock:receive|receive]], [[#tcpsock:receiveany|receiveany]] and [[#tcpsock:receiveuntil|receiveuntil]] methods are supported on this object.
In case of error, nil
will be returned as well as a string describing the error.
@@ -4351,7 +4351,7 @@ The socket object returned by this method is usually used to read the current re
If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading.
Chunked request bodies are not yet supported in this API.
-Since the v0.9.0
release, this function accepts an optional boolean raw
argument. When this argument is true
, this function returns a full-duplex cosocket object wrapping around the raw downstream connection socket, upon which you can call the [[#tcpsock:receive|receive]], [[#tcpsock:receiveuntil|receiveuntil]], and [[#tcpsock:send|send]] methods.
+Since the v0.9.0
release, this function accepts an optional boolean raw
argument. When this argument is true
, this function returns a full-duplex cosocket object wrapping around the raw downstream connection socket, upon which you can call the [[#tcpsock:receive|receive]], [[#tcpsock:receiveany|receiveany]], [[#tcpsock:receiveuntil|receiveuntil]], and [[#tcpsock:send|send]] methods.
When the raw
argument is true
, it is required that no pending data from any previous [[#ngx.say|ngx.say]], [[#ngx.print|ngx.print]], or [[#ngx.send_headers|ngx.send_headers]] calls exists. So if you have these downstream output calls previously, you should call [[#ngx.flush|ngx.flush(true)]] before calling ngx.req.socket(true)
to ensure that there is no pending output data. If the request body has not been read yet, then this "raw socket" can also be used to read the request body.
@@ -6157,7 +6157,7 @@ See also [[#ngx.socket.udp|ngx.socket.udp]].
== tcpsock:connect ==
-'''syntax:''' ''ok, err = tcpsock:connect(host, port, options_table?)''
+'''syntax:''' ''ok, err = tcpsock:connect(host, port?, options_table?)''
'''syntax:''' ''ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)''
@@ -6175,6 +6175,8 @@ Both IP addresses and domain names can be specified as the host
arg
If the nameserver returns multiple IP addresses for the host name, this method will pick up one randomly.
+port
is optional and accept nil (for compatibility with host is a unix domain), and it default value is zero.
+
In case of error, the method returns nil
followed by a string describing the error. In case of success, the method returns 1
.
Here is an example for connecting to a TCP server:
diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c
index 7b7d5eae6c..1280846545 100644
--- a/src/ngx_http_lua_args.c
+++ b/src/ngx_http_lua_args.c
@@ -55,6 +55,7 @@ ngx_http_lua_escape_args(u_char *dst, u_char *src, size_t size)
if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
n++;
}
+
src++;
size--;
}
@@ -72,6 +73,7 @@ ngx_http_lua_escape_args(u_char *dst, u_char *src, size_t size)
} else {
*dst++ = *src++;
}
+
size--;
}
diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h
index 781a2454a1..1232984911 100644
--- a/src/ngx_http_lua_common.h
+++ b/src/ngx_http_lua_common.h
@@ -44,6 +44,15 @@ typedef struct {
#endif
+/**
+ * max positive +1.7976931348623158e+308
+ * min positive +2.2250738585072014e-308
+ */
+#ifndef NGX_DOUBLE_LEN
+#define NGX_DOUBLE_LEN 25
+#endif
+
+
#if (NGX_PCRE)
#include
# if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21)
diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c
index 8f7e7fbef3..6b7ccc7cbe 100644
--- a/src/ngx_http_lua_directive.c
+++ b/src/ngx_http_lua_directive.c
@@ -1378,6 +1378,7 @@ ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd)
if (dst == NULL) {
return NGX_CONF_ERROR;
}
+
dst->len = len;
dst->len--; /* skip the trailing '}' block terminator */
@@ -1385,6 +1386,7 @@ ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd)
if (p == NULL) {
return NGX_CONF_ERROR;
}
+
dst->data = p;
for (i = 0; i < cf->args->nelts; i++) {
diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c
index b638277bd7..75985a1130 100644
--- a/src/ngx_http_lua_headers.c
+++ b/src/ngx_http_lua_headers.c
@@ -500,6 +500,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L)
} else {
lua_pushliteral(L, "close");
}
+
lua_rawset(L, -3);
if (r->chunked) {
diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c
index 713818efc2..fff8bafb92 100644
--- a/src/ngx_http_lua_headers_in.c
+++ b/src/ngx_http_lua_headers_in.c
@@ -359,6 +359,7 @@ ngx_http_lua_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
if (dot_pos == i - 1) {
return NGX_DECLINED;
}
+
dot_pos = i;
break;
@@ -754,6 +755,7 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur,
if (part->next == NULL) {
return NGX_ERROR;
}
+
part = part->next;
}
@@ -798,6 +800,7 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur,
if (part->next == NULL) {
return NGX_ERROR;
}
+
part = part->next;
}
diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c
index fa094a2e8b..94de796ade 100644
--- a/src/ngx_http_lua_initworkerby.c
+++ b/src/ngx_http_lua_initworkerby.c
@@ -148,6 +148,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle)
if (part->next == NULL) {
break;
}
+
part = part->next;
ofile = part->elts;
i = 0;
diff --git a/src/ngx_http_lua_log.c b/src/ngx_http_lua_log.c
index 5411831a18..43ab82095a 100644
--- a/src/ngx_http_lua_log.c
+++ b/src/ngx_http_lua_log.c
@@ -14,6 +14,7 @@
#include "ngx_http_lua_log.h"
#include "ngx_http_lua_util.h"
#include "ngx_http_lua_log_ringbuf.h"
+#include "ngx_http_lua_output.h"
static int ngx_http_lua_print(lua_State *L);
@@ -121,6 +122,7 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level,
if (*p == '/' || *p == '\\') {
name.data = p + 1;
}
+
p++;
}
@@ -142,6 +144,9 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level,
type = lua_type(L, i);
switch (type) {
case LUA_TNUMBER:
+ size += ngx_http_lua_get_num_len(L, i);
+ break;
+
case LUA_TSTRING:
lua_tolstring(L, i, &len);
size += len;
@@ -210,6 +215,9 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level,
type = lua_type(L, i);
switch (type) {
case LUA_TNUMBER:
+ p = ngx_http_lua_write_num(L, i, p);
+ break;
+
case LUA_TSTRING:
q = (u_char *) lua_tolstring(L, i, &len);
p = ngx_copy(p, q, len);
diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c
index 0fe8840f95..7c7403f667 100644
--- a/src/ngx_http_lua_output.c
+++ b/src/ngx_http_lua_output.c
@@ -93,6 +93,9 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline)
switch (type) {
case LUA_TNUMBER:
+ size += ngx_http_lua_get_num_len(L, i);
+ break;
+
case LUA_TSTRING:
lua_tolstring(L, i, &len);
@@ -173,6 +176,9 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline)
type = lua_type(L, i);
switch (type) {
case LUA_TNUMBER:
+ b->last = ngx_http_lua_write_num(L, i, b->last);
+ break;
+
case LUA_TSTRING:
p = lua_tolstring(L, i, &len);
b->last = ngx_copy(b->last, (u_char *) p, len);
@@ -301,8 +307,10 @@ ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i,
switch (type) {
case LUA_TNUMBER:
- case LUA_TSTRING:
+ size += ngx_http_lua_get_num_len(L, -1);
+ break;
+ case LUA_TSTRING:
lua_tolstring(L, -1, &len);
size += len;
break;
@@ -396,6 +404,9 @@ ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst)
type = lua_type(L, -1);
switch (type) {
case LUA_TNUMBER:
+ dst = ngx_http_lua_write_num(L, -1, dst);
+ break;
+
case LUA_TSTRING:
p = (u_char *) lua_tolstring(L, -1, &len);
dst = ngx_copy(dst, p, len);
diff --git a/src/ngx_http_lua_output.h b/src/ngx_http_lua_output.h
index 109a4b44b8..ec1db6d050 100644
--- a/src/ngx_http_lua_output.h
+++ b/src/ngx_http_lua_output.h
@@ -23,6 +23,50 @@ ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r,
ngx_http_lua_ctx_t *ctx);
+/* Get the maximum possible length, not the actual length */
+static ngx_inline size_t
+ngx_http_lua_get_num_len(lua_State *L, int idx)
+{
+ double num;
+
+ num = (double) lua_tonumber(L, idx);
+ if (num == (double) (long) num) {
+ return NGX_INT64_LEN;
+ }
+
+ return NGX_DOUBLE_LEN;
+}
+
+
+static ngx_inline u_char *
+ngx_http_lua_write_num(lua_State *L, int idx, u_char *dst)
+{
+ double num;
+ int n;
+
+ num = (double) lua_tonumber(L, idx);
+ if (num == (double) (long) num) {
+ dst = ngx_snprintf(dst, NGX_INT64_LEN, "%l", (long) num);
+
+ } else {
+ /**
+ * The maximum number of significant digits is 14 in lua.
+ * Please refer to lj_strfmt.c for more details.
+ */
+ n = snprintf((char *) dst, NGX_DOUBLE_LEN, "%.14g", num);
+ if (n < 0) {
+ ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno,
+ "snprintf(\"%f\") failed");
+
+ } else {
+ dst += n;
+ }
+ }
+
+ return dst;
+}
+
+
#endif /* _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c
index 5fe4564e89..d6e5640a0b 100644
--- a/src/ngx_http_lua_req_body.c
+++ b/src/ngx_http_lua_req_body.c
@@ -443,6 +443,7 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L)
if (b->start == NULL) {
return luaL_error(L, "no memory");
}
+
b->end = b->start + body.len;
b->pos = b->start;
@@ -454,6 +455,7 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L)
if (rb->bufs == NULL) {
return luaL_error(L, "no memory");
}
+
rb->bufs->next = NULL;
b = ngx_create_temp_buf(r->pool, body.len);
@@ -899,6 +901,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L)
if (rb->bufs == NULL) {
return luaL_error(L, "no memory");
}
+
rb->bufs->next = NULL;
b = ngx_calloc_buf(r->pool);
diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c
index 472fff0f87..f289dc19b4 100644
--- a/src/ngx_http_lua_socket_tcp.c
+++ b/src/ngx_http_lua_socket_tcp.c
@@ -255,11 +255,14 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L)
/* {{{req socket object metatable */
lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
req_socket_metatable_key));
- lua_createtable(L, 0 /* narr */, 5 /* nrec */);
+ lua_createtable(L, 0 /* narr */, 6 /* nrec */);
lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive);
lua_setfield(L, -2, "receive");
+ lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveany);
+ lua_setfield(L, -2, "receiveany");
+
lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil);
lua_setfield(L, -2, "receiveuntil");
@@ -278,11 +281,14 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L)
/* {{{raw req socket object metatable */
lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
raw_req_socket_metatable_key));
- lua_createtable(L, 0 /* narr */, 6 /* nrec */);
+ lua_createtable(L, 0 /* narr */, 7 /* nrec */);
lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive);
lua_setfield(L, -2, "receive");
+ lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveany);
+ lua_setfield(L, -2, "receiveany");
+
lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil);
lua_setfield(L, -2, "receiveuntil");
@@ -964,7 +970,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L)
n--;
}
- if (n == 3) {
+ if (n == 3 && !lua_isnil(L, 3)) {
port = luaL_checkinteger(L, 3);
if (port < 0 || port > 65535) {
@@ -981,7 +987,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L)
dd("socket key: %s", lua_tostring(L, -1));
- } else { /* n == 2 */
+ } else { /* n == 2 || lua_isnil(L, 3) */
port = 0;
}
@@ -2735,11 +2741,15 @@ ngx_http_lua_socket_tcp_send(lua_State *L)
type = lua_type(L, 2);
switch (type) {
case LUA_TNUMBER:
+ len = ngx_http_lua_get_num_len(L, 2);
+ break;
+
case LUA_TSTRING:
lua_tolstring(L, 2, &len);
break;
case LUA_TTABLE:
+ /* The maximum possible length, not the actual length */
len = ngx_http_lua_calc_strlen_in_table(L, 2, 2, 1 /* strict */);
break;
@@ -2783,13 +2793,16 @@ ngx_http_lua_socket_tcp_send(lua_State *L)
switch (type) {
case LUA_TNUMBER:
+ b->last = ngx_http_lua_write_num(L, 2, b->last);
+ break;
+
case LUA_TSTRING:
- p = (u_char *) lua_tolstring(L, -1, &len);
+ p = (u_char *) lua_tolstring(L, 2, &len);
b->last = ngx_copy(b->last, (u_char *) p, len);
break;
case LUA_TTABLE:
- b->last = ngx_http_lua_copy_str_in_table(L, -1, b->last);
+ b->last = ngx_http_lua_copy_str_in_table(L, 2, b->last);
break;
case LUA_TNIL:
@@ -2821,6 +2834,10 @@ ngx_http_lua_socket_tcp_send(lua_State *L)
u->request_bufs = cl;
+ lua_assert(b->last - b->start <= len);
+
+ len = b->last - b->start;
+
u->request_len = len;
/* mimic ngx_http_upstream_init_request here */
@@ -4884,6 +4901,7 @@ ngx_http_lua_req_socket(lua_State *L)
if (rb == NULL) {
return luaL_error(L, "no memory");
}
+
r->request_body = rb;
}
diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c
index f9d8fc0307..fd3e074270 100644
--- a/src/ngx_http_lua_socket_udp.c
+++ b/src/ngx_http_lua_socket_udp.c
@@ -727,6 +727,7 @@ ngx_http_lua_socket_udp_send(lua_State *L)
ssize_t n;
ngx_http_request_t *r;
u_char *p;
+ u_char *str;
size_t len;
ngx_http_lua_socket_udp_upstream_t *u;
int type;
@@ -781,11 +782,15 @@ ngx_http_lua_socket_udp_send(lua_State *L)
type = lua_type(L, 2);
switch (type) {
case LUA_TNUMBER:
+ len = ngx_http_lua_get_num_len(L, 2);
+ break;
+
case LUA_TSTRING:
lua_tolstring(L, 2, &len);
break;
case LUA_TTABLE:
+ /* The maximum possible length, not the actual length */
len = ngx_http_lua_calc_strlen_in_table(L, 2, 2, 1 /* strict */);
break;
@@ -812,29 +817,29 @@ ngx_http_lua_socket_udp_send(lua_State *L)
}
query.data = lua_newuserdata(L, len);
- query.len = len;
+ p = query.data;
switch (type) {
case LUA_TNUMBER:
+ p = ngx_http_lua_write_num(L, 2, p);
+ break;
+
case LUA_TSTRING:
- p = (u_char *) lua_tolstring(L, 2, &len);
- ngx_memcpy(query.data, (u_char *) p, len);
+ str = (u_char *) lua_tolstring(L, 2, &len);
+ p = ngx_cpymem(p, (u_char *) str, len);
break;
case LUA_TTABLE:
- (void) ngx_http_lua_copy_str_in_table(L, 2, query.data);
+ p = ngx_http_lua_copy_str_in_table(L, 2, p);
break;
case LUA_TNIL:
- p = query.data;
*p++ = 'n';
*p++ = 'i';
*p++ = 'l';
break;
case LUA_TBOOLEAN:
- p = query.data;
-
if (lua_toboolean(L, 2)) {
*p++ = 't';
*p++ = 'r';
@@ -855,6 +860,9 @@ ngx_http_lua_socket_udp_send(lua_State *L)
return luaL_error(L, "impossible to reach here");
}
+ query.len = p - query.data;
+ ngx_http_lua_assert(query.len <= len);
+
u->ft_type = 0;
/* mimic ngx_http_upstream_init_request here */
diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c
index a94e181745..4c755f67f3 100644
--- a/src/ngx_http_lua_string.c
+++ b/src/ngx_http_lua_string.c
@@ -133,6 +133,7 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size)
break;
}
}
+
src++;
size--;
}
@@ -192,9 +193,11 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size)
*dst++ = *src;
break;
}
+
} else {
*dst++ = *src;
}
+
src++;
size--;
} /* while (size) */
diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c
index 272906cb96..4b4f2c7c6f 100644
--- a/src/ngx_http_lua_util.c
+++ b/src/ngx_http_lua_util.c
@@ -2067,6 +2067,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
n++;
}
+
src++;
size--;
}
@@ -2084,6 +2085,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
} else {
*dst++ = *src++;
}
+
size--;
}
@@ -3886,6 +3888,7 @@ ngx_http_lua_init_vm(lua_State **new_vm, lua_State *parent_vm,
if (state == NULL) {
return NGX_ERROR;
}
+
state->vm = L;
state->count = 1;
diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h
index 2d928f96cf..57c0814bfb 100644
--- a/src/ngx_http_lua_util.h
+++ b/src/ngx_http_lua_util.h
@@ -31,12 +31,12 @@
#define NGX_HTTP_LUA_ESCAPE_HEADER_VALUE 8
-#define NGX_HTTP_LUA_CONTEXT_YIELDABLE NGX_HTTP_LUA_CONTEXT_REWRITE \
+#define NGX_HTTP_LUA_CONTEXT_YIELDABLE (NGX_HTTP_LUA_CONTEXT_REWRITE \
| NGX_HTTP_LUA_CONTEXT_ACCESS \
| NGX_HTTP_LUA_CONTEXT_CONTENT \
| NGX_HTTP_LUA_CONTEXT_TIMER \
| NGX_HTTP_LUA_CONTEXT_SSL_CERT \
- | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH
+ | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH)
/* key in Lua vm registry for all the "ngx.ctx" tables */
diff --git a/t/000--init.t b/t/000--init.t
index 5865755372..0dd08fe188 100644
--- a/t/000--init.t
+++ b/t/000--init.t
@@ -10,7 +10,8 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;
$ENV{TEST_NGINX_MYSQL_PORT} ||= 3306;
our $http_config = <<'_EOC_';
- lua_package_path "../lua-resty-mysql/lib/?.lua;;";
+ # lua-resty-string is required for lua-resty-mysql
+ lua_package_path "../lua-resty-mysql/lib/?.lua;../lua-resty-string/lib/?.lua;;";
_EOC_
no_shuffle();
diff --git a/t/009-log.t b/t/009-log.t
index cb3895b8b2..c4597698ef 100644
--- a/t/009-log.t
+++ b/t/009-log.t
@@ -548,3 +548,23 @@ ok
[error]
--- error_log eval
"2: hello\0world, client: "
+
+
+
+=== TEST 27: test log-level STDERR
+Note: maximum number of digits after the decimal-point character is 13
+--- config
+ location /log {
+ content_by_lua_block {
+ ngx.say("before log")
+ ngx.log(ngx.STDERR, 3.14159265357939723846)
+ ngx.say("after log")
+ }
+ }
+--- request
+GET /log
+--- response_body
+before log
+after log
+--- error_log eval
+qr/\[\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: 3.1415926535794/
diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t
index 6ac67e0849..a7fc07ad72 100644
--- a/t/058-tcp-socket.t
+++ b/t/058-tcp-socket.t
@@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua;
repeat_each(2);
-plan tests => repeat_each() * 222;
+plan tests => repeat_each() * 231;
our $HtmlDir = html_dir;
@@ -1493,7 +1493,7 @@ GET /t
-=== TEST 25: send tables of string fragments
+=== TEST 25: send tables of string fragments (with integers too)
--- config
server_tokens off;
location /t {
@@ -4158,3 +4158,205 @@ orld
[error]
--- error_log
lua tcp socket calling receiveany() method to read at most 7 bytes
+
+
+
+=== TEST 70: send tables of string fragments (with floating point number too)
+--- config
+ server_tokens off;
+ location /t {
+ #set $port 5000;
+ set $port $TEST_NGINX_SERVER_PORT;
+
+ content_by_lua_block {
+ local sock = ngx.socket.tcp()
+ local port = ngx.var.port
+ local ok, err = sock:connect("127.0.0.1", port)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ ngx.say("connected: ", ok)
+
+ local req = {"GET", " ", "/foo", " HTTP/", 1, ".", 0, "\r\n",
+ "Host: localhost\r\n", "Connection: close\r\n",
+ "Foo: ", 3.1415926, "\r\n",
+ "\r\n"}
+ -- req = "OK"
+
+ local bytes, err = sock:send(req)
+ if not bytes then
+ ngx.say("failed to send request: ", err)
+ return
+ end
+
+ ngx.say("request sent: ", bytes)
+
+ while true do
+ local line, err, part = sock:receive()
+ if line then
+ ngx.say("received: ", line)
+
+ else
+ ngx.say("failed to receive a line: ", err, " [", part, "]")
+ break
+ end
+ end
+
+ ok, err = sock:close()
+ ngx.say("close: ", ok, " ", err)
+ }
+ }
+
+ location /foo {
+ content_by_lua_block {
+ ngx.say(ngx.req.get_headers()["Foo"])
+ }
+ more_clear_headers Date;
+ }
+--- request
+GET /t
+--- response_body
+connected: 1
+request sent: 73
+received: HTTP/1.1 200 OK
+received: Server: nginx
+received: Content-Type: text/plain
+received: Content-Length: 10
+received: Connection: close
+received:
+received: 3.1415926
+failed to receive a line: closed []
+close: 1 nil
+--- no_error_log
+[error]
+
+
+
+=== TEST 71: send numbers
+the maximum number of significant digits is 14 in lua
+--- config
+ server_tokens off;
+ location /t {
+ #set $port 5000;
+ set $port $TEST_NGINX_SERVER_PORT;
+
+ content_by_lua_block {
+ local sock = ngx.socket.tcp()
+ local port = ngx.var.port
+ local ok, err = sock:connect("127.0.0.1", port)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ ngx.say("connected: ", ok)
+
+ local req = {"GET", " ", "/foo", " HTTP/", 1, ".", 0, "\r\n",
+ "Host: localhost\r\n", "Connection: close\r\n",
+ "Foo: "}
+ -- req = "OK"
+
+ local total_bytes = 0;
+ local bytes, err = sock:send(req)
+ if not bytes then
+ ngx.say("failed to send request: ", err)
+ return
+ end
+ total_bytes = total_bytes + bytes;
+
+ bytes, err = sock:send(3.14159265357939723846)
+ if not bytes then
+ ngx.say("failed to send request: ", err)
+ return
+ end
+ total_bytes = total_bytes + bytes;
+
+ bytes, err = sock:send(31415926)
+ if not bytes then
+ ngx.say("failed to send request: ", err)
+ return
+ end
+ total_bytes = total_bytes + bytes;
+
+ bytes, err = sock:send("\r\n\r\n")
+ if not bytes then
+ ngx.say("failed to send request: ", err)
+ return
+ end
+ total_bytes = total_bytes + bytes;
+
+ ngx.say("request sent: ", total_bytes)
+
+ while true do
+ local line, err, part = sock:receive()
+ if line then
+ ngx.say("received: ", line)
+
+ else
+ ngx.say("failed to receive a line: ", err, " [", part, "]")
+ break
+ end
+ end
+
+ ok, err = sock:close()
+ ngx.say("close: ", ok, " ", err)
+ }
+ }
+
+ location /foo {
+ content_by_lua_block {
+ ngx.say(ngx.req.get_headers()["Foo"])
+ }
+ more_clear_headers Date;
+ }
+--- request
+GET /t
+--- response_body
+connected: 1
+request sent: 87
+received: HTTP/1.1 200 OK
+received: Server: nginx
+received: Content-Type: text/plain
+received: Content-Length: 24
+received: Connection: close
+received:
+received: 3.141592653579431415926
+failed to receive a line: closed []
+close: 1 nil
+--- no_error_log
+[error]
+
+
+
+=== TEST 72: port is optional and accept nil, default is 0
+--- config
+ server_tokens off;
+ location = /t {
+ set $port $TEST_NGINX_SERVER_PORT;
+ content_by_lua_block {
+ local sock = ngx.socket.tcp()
+ sock:settimeout(500)
+ local ok, err = sock:connect("127.0.0.1")
+ if ok then
+ ngx.say("connect success")
+ return
+ end
+
+ local ok, err = sock:connect("127.0.0.1", nil)
+ if ok then
+ ngx.say("connect success")
+ return
+ end
+
+ ngx.say("ok")
+ }
+ }
+
+--- request
+GET /t
+--- response_body
+ok
+--- error_log
+connect to 127.0.0.1:0
diff --git a/t/059-unix-socket.t b/t/059-unix-socket.t
index b06ba6e2ee..c9d8d9b7e9 100644
--- a/t/059-unix-socket.t
+++ b/t/059-unix-socket.t
@@ -201,3 +201,71 @@ received:
received: foo
failed to receive a line: closed
close: 1 nil
+
+
+
+=== TEST 5: second parameter is nil
+--- http_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
+ default_type 'text/plain';
+
+ server_tokens off;
+ location /foo {
+ content_by_lua 'ngx.say("foo")';
+ more_clear_headers Date;
+ }
+ }
+--- config
+ location /test {
+ content_by_lua '
+ local sock = ngx.socket.tcp()
+ local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock", nil)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ ngx.say("connected: ", ok)
+
+ local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n"
+ -- req = "OK"
+
+ local bytes, err = sock:send(req)
+ if not bytes then
+ ngx.say("failed to send request: ", err)
+ return
+ end
+
+ ngx.say("request sent: ", bytes)
+
+ while true do
+ print("calling receive")
+ local line, err = sock:receive()
+ if line then
+ ngx.say("received: ", line)
+
+ else
+ ngx.say("failed to receive a line: ", err)
+ break
+ end
+ end
+
+ ok, err = sock:close()
+ ngx.say("close: ", ok, " ", err)
+ ';
+ }
+--- request
+ GET /test
+--- response_body
+connected: 1
+request sent: 57
+received: HTTP/1.1 200 OK
+received: Server: nginx
+received: Content-Type: text/plain
+received: Content-Length: 4
+received: Connection: close
+received:
+received: foo
+failed to receive a line: closed
+close: 1 nil
diff --git a/t/062-count.t b/t/062-count.t
index ffb769a50d..841923b86d 100644
--- a/t/062-count.t
+++ b/t/062-count.t
@@ -259,7 +259,7 @@ n = 10
POST /test
hello world
--- response_body
-n = 5
+n = 6
--- no_error_log
[error]
@@ -512,7 +512,7 @@ n = 6
--- request
GET /test
--- response_body
-n = 6
+n = 7
--- no_error_log
[error]
diff --git a/t/067-req-socket.t b/t/067-req-socket.t
index 6593360e4c..c5b2631e5e 100644
--- a/t/067-req-socket.t
+++ b/t/067-req-socket.t
@@ -1096,3 +1096,73 @@ done
--- grep_error_log_out
lua finalize socket
GC cycle done
+
+
+
+=== TEST 18: receiveany
+--- config
+ location = /t {
+ content_by_lua_block {
+ local sock = ngx.socket.tcp()
+ local ok, err = sock:connect("127.0.0.1", ngx.var.server_port)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ local bytes, err = sock:send("POST /back HTTP/1.0\r\nHost: localhost\r\nContent-Length: 1024\r\n\r\nabc")
+ if not bytes then
+ ngx.say("failed to send: ", err)
+ end
+
+ ngx.sleep(0.2)
+
+ local bytes, err = sock:send("hello world\n")
+ if not bytes then
+ ngx.say("failed to send: ", err)
+ end
+
+ local reader = sock:receiveuntil("\r\n\r\n")
+ local header, err = reader()
+ if not header then
+ ngx.say("failed to receive header: ", err)
+ return
+ end
+
+ local line, err = sock:receive()
+ if not line then
+ ngx.say("failed to receive line: ", err)
+ return
+ end
+ ngx.say("received: ", line)
+ }
+ }
+
+ location = /back {
+ content_by_lua_block {
+ ngx.send_headers()
+ ngx.flush(true)
+
+ local sock, err = ngx.req.socket()
+
+ if not sock then
+ ngx.say("failed to get socket: ", err)
+ return nil
+ end
+
+ local data, err = sock:receiveany(4096)
+ if not data then
+ ngx.say("err: ", err)
+ return nil
+ end
+
+ ngx.say("received: ", data)
+ }
+ }
+
+--- request
+GET /t
+--- response_body
+received: received: abc
+--- no_error_log
+[error]
diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t
index b3d5e824f0..fc467d769a 100644
--- a/t/087-udp-socket.t
+++ b/t/087-udp-socket.t
@@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua;
repeat_each(2);
-plan tests => repeat_each() * (3 * blocks() + 13);
+plan tests => repeat_each() * (3 * blocks() + 15);
our $HtmlDir = html_dir;
@@ -1117,3 +1117,105 @@ qr/send: fd:\d+ 4 of 4
send: fd:\d+ 5 of 5
send: fd:\d+ 3 of 3/
--- log_level: debug
+
+
+
+=== TEST 21: send numbers
+Note: maximum number of digits after the decimal-point character is 13
+--- config
+ server_tokens off;
+ location /t {
+ set $port $TEST_NGINX_MEMCACHED_PORT;
+
+ content_by_lua_block {
+ local socket = ngx.socket
+ local udp = socket.udp()
+ local port = ngx.var.port
+ udp:settimeout(1000) -- 1 sec
+
+ local ok, err = udp:setpeername("127.0.0.1", ngx.var.port)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ local function send(data)
+ local bytes, err = udp:send(data)
+ if not bytes then
+ ngx.say("failed to send: ", err)
+ return
+ end
+ ngx.say("sent ok")
+ end
+
+ send(123456)
+ send(3.141926)
+ send(3.141592653579397238)
+ }
+ }
+--- request
+GET /t
+--- response_body
+sent ok
+sent ok
+sent ok
+--- no_error_log
+[error]
+--- grep_error_log eval
+qr/send: fd:\d+ \d+ of \d+/
+--- grep_error_log_out eval
+qr/send: fd:\d+ 6 of 6
+send: fd:\d+ 8 of 8
+send: fd:\d+ 15 of 15/
+--- log_level: debug
+
+
+
+=== TEST 22: send tables of string framents (with numbers too)
+the maximum number of significant digits is 14 in lua
+--- config
+ server_tokens off;
+ location /t {
+ set $port $TEST_NGINX_MEMCACHED_PORT;
+
+ content_by_lua_block {
+ local socket = ngx.socket
+ local udp = socket.udp()
+ local port = ngx.var.port
+ udp:settimeout(1000) -- 1 sec
+
+ local ok, err = udp:setpeername("127.0.0.1", ngx.var.port)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ local function send(data)
+ local bytes, err = udp:send(data)
+ if not bytes then
+ ngx.say("failed to send: ", err)
+ return
+ end
+ ngx.say("sent ok")
+ end
+
+ send({"integer: ", 1234567890123})
+ send({"float: ", 3.1419265})
+ send({"float: ", 3.141592653579397238})
+ }
+ }
+--- request
+GET /t
+--- response_body
+sent ok
+sent ok
+sent ok
+--- no_error_log
+[error]
+--- grep_error_log eval
+qr/send: fd:\d+ \d+ of \d+/
+--- grep_error_log_out eval
+qr/send: fd:\d+ 22 of 22
+send: fd:\d+ 16 of 16
+send: fd:\d+ 22 of 22/
+--- log_level: debug
diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t
index ab06ee4a31..4dfb92664e 100644
--- a/t/116-raw-req-socket.t
+++ b/t/116-raw-req-socket.t
@@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua;
repeat_each(2);
-plan tests => repeat_each() * 40;
+plan tests => repeat_each() * 43;
our $HtmlDir = html_dir;
@@ -876,3 +876,96 @@ request body: hey, hello world
--- no_error_log
[error]
[alert]
+
+
+
+=== TEST 16: receiveany
+--- config
+ server_tokens off;
+ location = /t {
+ #set $port 5000;
+ set $port $TEST_NGINX_SERVER_PORT;
+
+ content_by_lua_block {
+ local sock = ngx.socket.tcp()
+ local port = ngx.var.port
+ local ok, err = sock:connect("127.0.0.1", port)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ local req = "GET /mysock HTTP/1.1\r\nUpgrade: mysock\r\nHost: localhost\r\nConnection: close\r\n\r\nhello"
+ -- req = "OK"
+
+ local bytes, err = sock:send(req)
+ if not bytes then
+ ngx.say("failed to send request: ", err)
+ return
+ end
+
+ -- Will return to I/O loop, causing receiveany() in /mysock location to be called
+ ngx.sleep(1)
+
+ local bytes, err = sock:send(", world")
+ if not bytes then
+ ngx.say("failed to send packet 1: ", err)
+ return
+ end
+
+ local reader = sock:receiveuntil("\r\n\r\n")
+ local data, err, partial = reader()
+ if not data then
+ ngx.say("no response header found")
+ return
+ end
+
+ local msg, err = sock:receive()
+ if not msg then
+ ngx.say("failed to receive: ", err)
+ return
+ end
+
+ ngx.say("msg: ", msg)
+
+ ok, err = sock:close()
+ if not ok then
+ ngx.say("failed to close socket: ", err)
+ return
+ end
+ }
+ }
+
+ location = /mysock {
+ content_by_lua_block {
+ ngx.status = 101
+ ngx.send_headers()
+ ngx.flush(true)
+ ngx.req.read_body()
+ local sock, err = ngx.req.socket(true)
+ if not sock then
+ ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err)
+ return
+ end
+
+ local data, err = sock:receiveany(1024)
+ if not data then
+ ngx.log(ngx.ERR, "server: failed to receive: ", err)
+ return
+ end
+
+ local bytes, err = sock:send("1: received: " .. data .. "\n")
+ if not bytes then
+ ngx.log(ngx.ERR, "server: failed to send: ", err)
+ return
+ end
+ }
+ more_clear_headers Date;
+ }
+
+--- request
+GET /t
+--- response_body
+msg: 1: received: hello
+--- no_error_log
+[error]
diff --git a/t/164-say.t b/t/164-say.t
new file mode 100644
index 0000000000..6114d2459e
--- /dev/null
+++ b/t/164-say.t
@@ -0,0 +1,55 @@
+# vim:set ft= ts=4 sw=4 et fdm=marker:
+
+use Test::Nginx::Socket::Lua;
+
+repeat_each(2);
+
+plan tests => blocks() * repeat_each() * 2;
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: ngx.say (integer)
+--- config
+ location /lua {
+ content_by_lua_block {
+ ngx.say(2)
+ }
+ }
+--- request
+GET /lua
+--- response_body
+2
+
+
+
+=== TEST 2: ngx.say (floating point number)
+the maximum number of significant digits is 14 in lua
+--- config
+ location /lua {
+ content_by_lua_block {
+ ngx.say(3.1415926)
+ ngx.say(3.14159265357939723846)
+ }
+ }
+--- request
+GET /lua
+--- response_body
+3.1415926
+3.1415926535794
+
+
+
+=== TEST 3: ngx.say (table with number)
+--- config
+ location /lua {
+ content_by_lua_block {
+ local data = {123," ", 3.1415926}
+ ngx.say(data)
+ }
+ }
+--- request
+GET /lua
+--- response_body
+123 3.1415926