-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Major cosockets patch #290
Conversation
…header that determines whether or not to replace underscores with hyphens. Previously, underscores were replaced unconditionally. Currently each of the functions has another boolean argument. If it's false, underscores would not be touched. If it's true, they would. The default value of the argument is true.
…ptions), in which the only possible option currently is replace_underscores.
- Now receive and send operations can be done simultaneous from several threads. - A different timeout can be set for receive and send. - Added fake_close for the client socket (ngx.req.socket), so that a thread that receives on this socket can be notified that we don't want to read from it anymore.
…s to receive just like BSD's recv call, meaning the maximum number of bytes given. This will only work only when a number is given as the first parameter for receive. Note that this differs from the original LuaSocket API.
@agentzh I have not yet tested this patch (I will try it out soon). I suppose that you are reviewing the changes. Do you have an estimate when these changes are going to be pulled to OpenResty bundle release? I understand that changes are quite big, and that they warrant further investigation as this separation of read-write state affects all the libs, e.g. lua resty mysql. lua resty redis, and lua resty websocket. I may test this soon myself, and will report to this thread my findings. |
@bungle I'm currently working on the pool-based connection number limiting feature in ngx_lua. I'll look into the patch for the full duplex support for cosocket after that. |
…cket is finalized, so that if `ngx_http_lua_wev_handler` runs after the raw downstream socket is closed, it won't try to call its read/write handler.
…or handling functions, as if both read and write are done simultaenously, they may override each others preapre_retvals function.
….connection` is NULL in case there was an error in the client socket, causing a SEGFAULT.
Fixed merge issue (some function that were moved to a different file became duplicate).
👍 |
Also closing the connection if any error has happened during the handshake.
…is an optional argument in the options table of tcpsock:connect()
Any updates on this? I'm pretty eager to try it out as I already have a few use cases, but would rather prefer not to patch openresty manually on each update. |
@blablacio No progress here yet. I've been busy with other things. Sorry. |
FYI:: This can be worked around by setting up an http->https proxy for a custom location in nginx proper. While not optimal, it's quite fast...we had to do this because one of our services absolutely required https, even for internal calls. |
@DorianGray Not sure I follow, care to explain what you mean? |
a very minimal example for http... server { then you would send http requests to this server and it would reverse proxy to the backend service that requires https. |
Okay, I see what you mean. The patch actually contains other bits that I'm using, so I wasn't sure. Thanks for the clarification, it's greatly appreciated. |
@aviramc and others: I've come up with a patch for the full duplex cosocket feature mostly based on @ashun's patch in #367 and committed to the "duplex-socket" branch on GitHub (as commit 934e33e). It'll be great if you can review the patch and try it out on your side. Many thanks! And sorry for the long delay on my side. |
FYI, the full-duplex stream-typed cosocket feature has already been included in the v0.9.9 release of ngx_lua. |
Excellent! What about SSL support? I would like to test the new release, but I'm using the SSL patch too. |
@blablacio The SSL cosocket support will probably land in the next release (0.9.10) or beyond. I am still thinking about the implementation details. I'm not happy with the current API in this pull request and I may probably introduce an explicit |
@aviramc I'm thinking about the following API for SSL cosockets: local ok, err = sock:connect(host, port)
local session, err = sock:sslhandshake(reused_session, verify) Basically, the My plan is to include the first version of SSL cosockets in the 0.9.11 release of ngx_lua (I've already missed the 0.9.10 release's merge window). What do you think? |
@agentzh the API looks fine, but what are the additional arguments that can be passed? I think that one should be the name of the host that should be verified (I guess that the verify parameter is boolean). |
@aviramc I'll keep the first implementation of SSL cosockets simple. Basically only the "session" and "verify_host" arguments (or just the first one) will be supported for now. |
* added new method sslhandshake() to the stream-typed cosocket objects. * added new configuration directives lua_ssl_trusted_certificate, lua_ssl_verify_depth, lua_ssl_crl, lua_ssl_protocols, and lua_ssl_ciphers. Thanks aviramc for the original patch in #290.
@aviramc Okay, I've finally finished the first implementation of SSL cosockets based on your patch. It has been committed to the git branch ssl-cosocket as commit d10bcc7. The local session, err = sock:sslhandshake(session, host, verify) The first The 2nd The 3rd All the 3 arguments are optional. I haven't written formal documentation for this new feature yet. For now, the most comprehensive "documentation" is the new test cases: https://github.com/openresty/lua-nginx-module/blob/ssl-cosocket/t/129-ssl-socket.t Also added new nginx config directives The @daurnimator Right now you need separate locations to have separate sets of trusted certificates. In the (near) future, we can add support for a 4th argument similar to luasec's "context" object (but not 100% compatible). Patches welcome :) @lhmwzy The MySQL server allows SSL and non-SSL connections share the same server port by postponing the standard SSL handshake after its own (clear-text) handshake. Please check out MySQL's documentation on this trick: http://dev.mysql.com/doc/internals/en/ssl.html This also justifies the design of a separate Feedback welcome! |
* added new method sslhandshake() to the stream-typed cosocket objects. * added new configuration directives lua_ssl_trusted_certificate, lua_ssl_verify_depth, lua_ssl_crl, lua_ssl_protocols, and lua_ssl_ciphers. Thanks aviramc for the original patch in #290.
Regarding my previous comment, I've just fixed a bug in the commit for SSL cosockets that the Thanks! |
* added new method sslhandshake() to the stream-typed cosocket objects. * added new configuration directives lua_ssl_trusted_certificate, lua_ssl_verify_depth, lua_ssl_crl, lua_ssl_protocols, and lua_ssl_ciphers. Thanks aviramc for the original patch in #290.
Okay, I've just merged the Also, I've fixed a memory leak regression (when connection pool is used and lua_code_cache is off) in my cosocket patch in the new commit a6a0ed5. |
@lhmwzy I've prepared the following patch for diff --git a/lib/resty/mysql.lua b/lib/resty/mysql.lua
index a629daa..2e310de 100644
--- a/lib/resty/mysql.lua
+++ b/lib/resty/mysql.lua
@@ -38,6 +38,7 @@ local STATE_CONNECTED = 1
local STATE_COMMAND_SENT = 2
local COM_QUERY = 0x03
+local CLIENT_SSL = 0x0800
local SERVER_MORE_RESULTS_EXISTS = 8
@@ -136,7 +137,7 @@ local function _dump(data)
local len = #data
local bytes = new_tab(len, 0)
for i = 1, len do
- bytes[i] = strbyte(data, i)
+ bytes[i] = string.format("%x", strbyte(data, i))
end
return concat(bytes, " ")
end
@@ -175,11 +176,13 @@ local function _send_packet(self, req, size)
self.packet_no = self.packet_no + 1
- --print("packet no: ", self.packet_no)
+ -- print("packet no: ", self.packet_no)
local packet = _set_byte3(size) .. strchar(self.packet_no) .. req
- --print("sending packet...")
+ -- print("sending packet: ", _dump(packet))
+
+ -- print("sending packet... of size " .. #packet)
return sock:send(packet)
end
@@ -562,9 +565,10 @@ function _M.connect(self, opts)
pos = pos + 9 -- skip filler
-- two lower bytes
- self._server_capabilities, pos = _get_byte2(packet, pos)
+ local server_capabilities
+ server_capabilities, pos = _get_byte2(packet, pos)
- --print("server capabilities: ", self._server_capabilities)
+ -- print(string.format("server capabilities: %#x", server_capabilities))
self._server_lang = strbyte(packet, pos)
pos = pos + 1
@@ -578,8 +582,8 @@ function _M.connect(self, opts)
local more_capabilities
more_capabilities, pos = _get_byte2(packet, pos)
- self._server_capabilities = bor(self._server_capabilities,
- lshift(more_capabilities, 16))
+ server_capabilities = bor(server_capabilities,
+ lshift(more_capabilities, 16))
--print("server capabilities: ", self._server_capabilities)
@@ -598,13 +602,36 @@ function _M.connect(self, opts)
scramble = scramble .. scramble_part2
--print("scramble: ", _dump(scramble))
+ -- local client_flags = self._server_capabilities
+ local client_flags = 0x3f7cf;
+
+ if opts.ssl then
+ if band(server_capabilities, CLIENT_SSL) == 0 then
+ return nil, "ssl disabled on server"
+ end
+
+ -- send a SSL Request Packet
+ local req = _set_byte4(bor(client_flags, CLIENT_SSL))
+ .. _set_byte4(self._max_packet_size)
+ .. "\0" -- TODO: add support for charset encoding
+ .. strrep("\0", 23)
+
+ local packet_len = 4 + 4 + 1 + 23
+ local bytes, err = _send_packet(self, req, packet_len)
+ if not bytes then
+ return nil, "failed to send client authentication packet: " .. err
+ end
+
+ local ok, err = sock:sslhandshake(false)
+ if not ok then
+ return nil, "failed to do ssl handshake: " .. (err or "")
+ end
+ end
+
local password = opts.password or ""
local token = _compute_token(password, scramble)
- -- local client_flags = self._server_capabilities
- local client_flags = 260047;
-
--print("token: ", _dump(token))
local req = _set_byte4(client_flags)
diff --git a/t/ssl.t b/t/ssl.t
new file mode 100644
index 0000000..1f7f998
--- /dev/null
+++ b/t/ssl.t
@@ -0,0 +1,89 @@
+# vim:set ft= ts=4 sw=4 et:
+
+use Test::Nginx::Socket::Lua;
+use Cwd qw(cwd);
+
+repeat_each(2);
+
+plan tests => repeat_each() * (3 * blocks() + 4);
+
+my $pwd = cwd();
+
+our $HttpConfig = qq{
+ resolver \$TEST_NGINX_RESOLVER;
+ lua_package_path "$pwd/lib/?.lua;$pwd/t/lib/?.lua;;";
+ lua_package_cpath "/usr/local/openresty-debug/lualib/?.so;/usr/local/openresty/lualib/?.so;;";
+};
+
+$ENV{TEST_NGINX_RESOLVER} = '8.8.8.8';
+$ENV{TEST_NGINX_MYSQL_PORT} ||= 3306;
+$ENV{TEST_NGINX_MYSQL_HOST} ||= '127.0.0.1';
+$ENV{TEST_NGINX_MYSQL_PATH} ||= '/var/run/mysql/mysql.sock';
+
+#log_level 'warn';
+
+no_long_string();
+no_shuffle();
+check_accum_error_log();
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: send query w/o result set
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua '
+ local mysql = require "resty.mysql"
+ local db = mysql:new()
+
+ db:set_timeout(1000) -- 1 sec
+
+ local ok, err, errno, sqlstate = db:connect({
+ host = "$TEST_NGINX_MYSQL_HOST",
+ port = $TEST_NGINX_MYSQL_PORT,
+ database = "ngx_test",
+ user = "ngx_test",
+ password = "ngx_test",
+ ssl = true,
+ })
+
+ if not ok then
+ ngx.say("failed to connect: ", err, ": ", errno, " ", sqlstate)
+ return
+ end
+
+ ngx.say("connected to mysql ", db:server_ver(), ".")
+
+ local bytes, err = db:send_query("drop table if exists cats")
+ if not bytes then
+ ngx.say("failed to send query: ", err)
+ end
+
+ ngx.say("sent ", bytes, " bytes.")
+
+ local res, err, errno, sqlstate = db:read_result()
+ if not res then
+ ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".")
+ end
+
+ local ljson = require "ljson"
+ ngx.say("result: ", ljson.encode(res))
+
+ local ok, err = db:close()
+ if not ok then
+ ngx.say("failed to close: ", err)
+ return
+ end
+ ';
+ }
+--- request
+GET /t
+--- response_body_like chop
+^connected to mysql \d\.\S+\.
+sent 30 bytes\.
+result: \{"affected_rows":0,"insert_id":0,"server_status":2,"warning_count":[01]\}$
+--- no_error_log
+[error]
+ SSL verification support has not yet been added nor tested yet, but should work easily as well :) |
@lhmwzy Okay, I've added both "ssl" and "ssl_verify" boolean-value options to openresty/lua-resty-mysql@ecc50848 Please try it out on your side :) |
Hey guys! I've just documented the SSL cosocket feature here: Please review the current behavior and API semantics before it becomes too late to change ;) Thank you for your time! |
Will reopen new pull requests for each of the required features |
This includes the following changes:
The is a part of pull request #286