Skip to content

Feature/connect improvements #254

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

Merged
merged 6 commits into from
Nov 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ local body = res.body
local httpc = require("resty.http").new()

-- First establish a connection
local ok, err = httpc:connect({
local ok, err, ssl_session = httpc:connect({
scheme = "https",
host = "127.0.0.1",
port = 8080,
Expand Down Expand Up @@ -153,7 +153,7 @@ Creates the HTTP connection object. In case of failures, returns `nil` and a str

## connect

`syntax: ok, err = httpc:connect(options)`
`syntax: ok, err, ssl_session = httpc:connect(options)`

Attempts to connect to the web server while incorporating the following activities:

Expand All @@ -172,6 +172,7 @@ The options table has the following fields:
* `pool_size`: option as per [OpenResty docs](https://github.com/openresty/lua-nginx-module#tcpsockconnect)
* `backlog`: option as per [OpenResty docs](https://github.com/openresty/lua-nginx-module#tcpsockconnect)
* `proxy_opts`: sub-table, defaults to the global proxy options set, see [set\_proxy\_options](#set_proxy_options).
* `ssl_reused_session`: option as per [OpenResty docs](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)
* `ssl_verify`: option as per [OpenResty docs](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake), except that it defaults to `true`.
* `ssl_server_name`: option as per [OpenResty docs](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)
* `ssl_send_status_req`: option as per [OpenResty docs](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)
Expand Down
2 changes: 1 addition & 1 deletion lib/resty/http.lua
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ end
do
local aio_connect = require "resty.http_connect"
-- Function signatures to support:
-- ok, err = httpc:connect(options_table)
-- ok, err, ssl_session = httpc:connect(options_table)
-- ok, err = httpc:connect(host, port, options_table?)
-- ok, err = httpc:connect("unix:/path/to/unix.sock", options_table?)
function _M.connect(self, options, ...)
Expand Down
17 changes: 11 additions & 6 deletions lib/resty/http_connect.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ client:connect {
backlog = nil,

-- ssl options as per: https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake
ssl_reused_session = nil
ssl_server_name = nil,
ssl_send_status_req = nil,
ssl_verify = true, -- NOTE: defaults to true
Expand Down Expand Up @@ -53,9 +54,10 @@ local function connect(self, options)
end

-- ssl settings
local ssl, ssl_server_name, ssl_verify, ssl_send_status_req
local ssl, ssl_reused_session, ssl_server_name, ssl_verify, ssl_send_status_req
if request_scheme == "https" then
ssl = true
ssl_reused_session = options.ssl_reused_session
ssl_server_name = options.ssl_server_name
ssl_send_status_req = options.ssl_send_status_req
ssl_verify = true -- default
Expand Down Expand Up @@ -133,7 +135,8 @@ local function connect(self, options)
end

if proxy then
local proxy_uri_t, err = self:parse_uri(proxy_uri)
local proxy_uri_t
proxy_uri_t, err = self:parse_uri(proxy_uri)
if not proxy_uri_t then
return nil, err
end
Expand Down Expand Up @@ -178,7 +181,8 @@ local function connect(self, options)
-- authority-form of RFC 7230 Section 5.3.3. See also RFC 7231 Section
-- 4.3.6 for more details about the CONNECT request
local destination = request_host .. ":" .. request_port
local res, err = self:request({
local res
res, err = self:request({
method = "CONNECT",
path = destination,
headers = {
Expand Down Expand Up @@ -211,10 +215,11 @@ local function connect(self, options)
end
end

local ssl_session
-- Now do the ssl handshake
if ssl and sock:getreusedtimes() == 0 then
local ok, err = sock:sslhandshake(nil, ssl_server_name, ssl_verify, ssl_send_status_req)
if not ok then
ssl_session, err = sock:sslhandshake(ssl_reused_session, ssl_server_name, ssl_verify, ssl_send_status_req)
if not ssl_session then
self:close()
return nil, err
end
Expand All @@ -228,7 +233,7 @@ local function connect(self, options)
self.http_proxy_auth = request_scheme ~= "https" and proxy_authorization or nil
self.path_prefix = path_prefix

return true
return true, nil, ssl_session
end

return connect
136 changes: 136 additions & 0 deletions t/19-ssl_reused_session.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use Test::Nginx::Socket::Lua 'no_plan';
use Cwd qw(abs_path realpath);
use File::Basename;

$ENV{TEST_NGINX_HTML_DIR} ||= html_dir();

$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8';
$ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__)));
$ENV{TEST_COVERAGE} ||= 0;

my $realpath = realpath();

our $HttpConfig = qq{
lua_package_path "$realpath/lib/?.lua;/usr/local/share/lua/5.1/?.lua;;";

init_by_lua_block {
if $ENV{TEST_COVERAGE} == 1 then
jit.off()
require("luacov.runner").init()
end

TEST_SERVER_SOCK = "unix:/$ENV{TEST_NGINX_HTML_DIR}/nginx.sock"

num_handshakes = 0
}

server {
listen unix:$ENV{TEST_NGINX_HTML_DIR}/nginx.sock ssl;
server_name example.com;
ssl_certificate $ENV{TEST_NGINX_CERT_DIR}/cert/test.crt;
ssl_certificate_key $ENV{TEST_NGINX_CERT_DIR}/cert/test.key;
ssl_session_tickets off;

server_tokens off;
}
};

no_long_string();
#no_diff();

run_tests();

__DATA__

=== TEST 1: connect returns session userdata
--- http_config eval: $::HttpConfig
--- config
server_tokens off;
resolver $TEST_NGINX_RESOLVER ipv6=off;
lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt;

location /t {
content_by_lua_block {
local httpc = assert(require("resty.http").new())
local ok, err, session = assert(httpc:connect {
scheme = "https",
host = TEST_SERVER_SOCK,
})

assert(type(session) == "userdata", "expected session to be userdata")
assert(httpc:close())
}
}

--- request
GET /t
--- no_error_log
[error]
[alert]


=== TEST 2: ssl_reused_session false does not return session userdata
--- http_config eval: $::HttpConfig
--- config
server_tokens off;
resolver $TEST_NGINX_RESOLVER ipv6=off;
lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt;

location /t {
content_by_lua_block {
local httpc = assert(require("resty.http").new())
local ok, err, session = assert(httpc:connect {
scheme = "https",
host = TEST_SERVER_SOCK,
ssl_reused_session = false,
})

assert(type(session) == "boolean", "expected session to be a boolean")
assert(session == true, "expected session to be true")
assert(httpc:close())
}
}

--- request
GET /t
--- no_error_log
[error]
[alert]


=== TEST 3: ssl_reused_session accepts userdata
--- http_config eval: $::HttpConfig
--- config
server_tokens off;
resolver $TEST_NGINX_RESOLVER ipv6=off;
lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt;

location /t {
content_by_lua_block {
local httpc = assert(require("resty.http").new())
local ok, err, session = assert(httpc:connect {
scheme = "https",
host = TEST_SERVER_SOCK,
})

assert(type(session) == "userdata", "expected session to be userdata")

local httpc2 = assert(require("resty.http").new())
local ok, err, session2 = assert(httpc2:connect {
scheme = "https",
host = TEST_SERVER_SOCK,
ssl_reused_session = session,
})

assert(type(session2) == "userdata", "expected session2 to be userdata")

assert(httpc:close())
assert(httpc2:close())
}
}

--- request
GET /t
--- no_error_log
[error]
[alert]
47 changes: 25 additions & 22 deletions t/cert/test.crt
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIJALL9eJPZ6neGMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
BAYTAkdCMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ0wCwYDVQQKEwRU
ZXN0MQ0wCwYDVQQLEwRUZXN0MQ0wCwYDVQQDEwR0ZXN0MB4XDTE1MTAyMTE2MjQ1
NloXDTE1MTEyMDE2MjQ1NlowWDELMAkGA1UEBhMCR0IxDTALBgNVBAgTBFRlc3Qx
DTALBgNVBAcTBFRlc3QxDTALBgNVBAoTBFRlc3QxDTALBgNVBAsTBFRlc3QxDTAL
BgNVBAMTBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDz/AoE
c+TPdm+Aqcchq8fLNWksFQZqbsCBGnq8rUG1b6MsVlAOkDUQGRlNPs9v0/+pzgX7
IYXPCFcV7YONNsTUfvBYTq43mfOycmAdb3SX6kBygxdhYsDRZR+vCAIkjoRmRB20
meh1motqM58spq3IcT8VADTRJl1OI48VTnxmXdCtmkOymU948DcauMoxm03eL/hU
6eniNEujbnbB305noNG0W5c3h6iz9CvqUAD1kwyjick+f1atB2YYn1bymA+db6YN
3iTo0v2raWmIc7D+qqpkNaCRxgMb2HN6X3/SfkijtNJidjqHMbs2ftlKJ5/lODPZ
rCPQOcYK6TT8MIZ1AgMBAAGjgbwwgbkwHQYDVR0OBBYEFFUC1GrAhUp7IvJH5iyf
+fJQliEIMIGJBgNVHSMEgYEwf4AUVQLUasCFSnsi8kfmLJ/58lCWIQihXKRaMFgx
CzAJBgNVBAYTAkdCMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ0wCwYD
VQQKEwRUZXN0MQ0wCwYDVQQLEwRUZXN0MQ0wCwYDVQQDEwR0ZXN0ggkAsv14k9nq
d4YwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAtaUQOr3Qn87KXmmP
GbSvCLSl+bScE09VYZsYaB6iq0pGN9y+Vh4/HjBUUsFexopw1dY25MEEJXEVi1xV
2krLYAsfKCM6c1QBVmdqfVuxUvxpXwr+CNRNAlzz6PhjkeY/Ds/j4sg7EqN8hMmT
gu8GuogX7+ZCgrzRSMMclWej+W8D1xSIuCC+rqv4w9SZdtVb3XGpCyizpTNsQAuV
ACXvq9KXkEEj+XNvKrNdWd4zG715RdMnVm+WM53d9PLp63P+4/kwhwHULYhXygQ3
DzzVPaojBBdw3VaHbbPHnv73FtAzOb7ky6zJ01DlmEPxEahCFpklMkY9T2uCdpj9
oOzaNA==
MIIEpDCCAowCCQDgS40Q0UNIKTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMjExMTIyMTQ0MDM2WhcNMjIxMTIyMTQ0MDM2WjAUMRIwEAYD
VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9
OVsD7qyres7qkLZPY4MyC00/ByESpUVFgWiTU2nBeNC/kBvOOOVTvrVHxlTjZ9JG
rCdYeIGkpkaJQ2QylHKRJolxh8x309/VkpKJYL357NuNeAk2l3tW4BMImXUGdVjD
0qT8WTyApEE7lyfOXKYKbbEwfdks0eBcEZBBn4QTaZ9lVj7yScurto8jDYMkBfO/
4QeuVe4ijgWU35Yd89Ya0HZr+1QBU1dMzbtf9mYPedRwRZgzKogZ6mZXs7GJ0ADM
L+fg/djROd01eA3ynAfxJbRv1R7S73ljQJhD+oYf3rJaHU2Ko5heF9K9bd771Ze/
sHGHZdLy3JZrPNdDPHG61H9m4zOUkNZvVkvHF9wg+uNs4VJxrkG6undOEyCyBefE
XRknEBvMLlWF9c9KT5tZz/vI6/e5xrpNCdUjthn5YFEf43MVqWWcU8t9ViK+8+rG
PQNKmxRiCOOmd6NhjWJInuMO3QiPJFqVs4UNpmE/4hi3LtwV7qH4jHWX5hRG27gz
8VbfkBkIoy0Esm2Dv5lErZztPhycpFUodpBXGtQjXQLvYVm+yKwWlD6gTRH0LXj3
3lp69m5/V9so3NsYWMxoNGvI4MqZuwGaiwxgkCWjUqQEX1y4i7Us01UDFpK2WuwG
MUQNzGV2jX9urnjndFPHjszqo5BsmJuHwihGOFvbpwIDAQABMA0GCSqGSIb3DQEB
CwUAA4ICAQAhXhf95xbkSw1fknoGhdgTAb3A+pKzcejZjqmQi3BJku8EILe06LGF
Pli4WlN7KMk20A/TO/L46tsWztFl0vhSs+ed/Z3/0ugB+DO0InpwDxutPTrVjkmy
W5HAKnW7MQAA9tcTcAPbiHIalwswQ1pab+kxl9fbsaC1CrSypa1eK6Hh/qJKxe2O
06ovTTHuZ/yWJBaIwmvP8lCMfCrLGOCGToM4FWtDPc47VVxpk0Ks0kRL8Bqo4CsG
rM+PpfsFBdPO/FftfVeMdzZCcK1CLWuE/uBdjDtU10qMVhQTxGG4eFv24xVQuCmH
AB5hTt62DLxHAs6kgvafZz9ST6aVDu0kuPABC4z4JQVBCRbw0mL75R4ziEYH3CIe
tmgYEXHfj3D3BDgX3ki6qqX7VtmkT0+VyrpQs+dhkCXlnqGmNM+gSsKve3ZH6a9J
fFeKjiJH4YjlPmLlCxpnDoBgjGjcUmVEBcpZ7H8lNC3ldPVfDq3PDrHgFMH5lmth
PZHbWROudoHVX5EBY2n08uzMWtl0xFwAfLG3Hk7xoBWBpebHxhw/yzm/iWHeBdi+
8uSMLM3/TjmKhh+mF7KRKSYKetKKYiwB0/yIQJLMLxpUc3Aae7i0djH/kFz80HU/
alsGmliI6PGyCt11DYS7Spl44pxl6N7pj2CJpyPOMwDI3VG097cYDQ==
-----END CERTIFICATE-----
79 changes: 52 additions & 27 deletions t/cert/test.key
Original file line number Diff line number Diff line change
@@ -1,27 +1,52 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA8/wKBHPkz3ZvgKnHIavHyzVpLBUGam7AgRp6vK1BtW+jLFZQ
DpA1EBkZTT7Pb9P/qc4F+yGFzwhXFe2DjTbE1H7wWE6uN5nzsnJgHW90l+pAcoMX
YWLA0WUfrwgCJI6EZkQdtJnodZqLajOfLKatyHE/FQA00SZdTiOPFU58Zl3QrZpD
splPePA3GrjKMZtN3i/4VOnp4jRLo252wd9OZ6DRtFuXN4eos/Qr6lAA9ZMMo4nJ
Pn9WrQdmGJ9W8pgPnW+mDd4k6NL9q2lpiHOw/qqqZDWgkcYDG9hzel9/0n5Io7TS
YnY6hzG7Nn7ZSief5Tgz2awj0DnGCuk0/DCGdQIDAQABAoIBAGjKc7L94+SHRdTJ
FtILacCJrCZW0W6dKulIajbnYzV+QWMlnzTiEyha31ciBw5My54u8rqt5z7Ioj60
yK+6OkfaTXhgMsuGv/iAz29VE4q7/fow+7XEKHTHLhiLJAB3hb42u1t6TzFTs1Vl
3pPa8wEIQsPOVuENzT1mYGoST7PW+LBIMr9ScMnRHfC0MNdV/ntQiXideOAd5PkA
4O7fNgYZ8CTAZ8rOLYTMFF76/c/jLiqfeghqbIhqMykk36kd7Lud//FRykVsn1aJ
REUva/SjVEth5kITot1hpMC4SIElWpha2YxiiZFoSXSaUbtHpymiUGV01cYtMWk0
MZ5HN3ECgYEA/74U8DpwPxd4up9syKyNqOqrCrYnhEEC/tdU/W5wECi4y5kppjdd
88lZzICVPzk2fezYXlCO9HiSHU1UfcEsY3u16qNCvylK7Qz1OqXV/Ncj59891Q5Z
K0UBcbnrv+YD6muZuhlHEbyDPqYO091G9Gf/BbL5JIBDzg1qFO9Dh9cCgYEA9Drt
O9PJ5Sjz3mXQVtVHpwyhOVnd7CUv8a1zkUQCK5uQeaiF5kal1FIo7pLOr3KAvG0C
pXbm/TobwlfAfcERQN88aPN8Z/l1CB0oKV6ipBMD2/XLzDRtx8lpTeh/BB8jIhrz
+FDJY54HCzLfW0P5kT+Cyw51ofjziPnFdO/Z6pMCgYEAon17gEchGnUnWCwDSl2Y
hELV+jBSW02TQag/b+bDfQDiqTnfpKR5JXRBghYQveL0JH5f200EB4C0FboUfPJH
6c2ogDTLK/poiMU66tCDbeqj/adx+fTr4votOL0QdRUIV+GWAxAcf8BvA1cvBJ4L
fy60ckKM2gxFCJ6tUC/VkHECgYBoMDNAUItSnXPbrmeAg5/7naGxy6qmsP6RBUPF
9tNOMyEhJUlqAT2BJEOd8zcFFb3hpEd6uwyzfnSVJcZSX2iy2gj1ZNnvqTXJ7lZR
v7N2dz4wOd1lEgC7OCsaN1LoOThNtl3Z0uz2+FVc66jpUEhJNGThpxt7q66JArS/
vAqkzQKBgFkzqA6QpnH5KhOCoZcuLQ4MtvnNHOx1xSm2B0gKDVJzGkHexTmOJvwM
ZhHXRl9txS4icejS+AGUXNBzCWEusfhDaZpZqS6zt6UxEjMsLj/Te7z++2KQn4t/
aI77jClydW1pJvICtqm5v+sukVZvQTTJza9ujta6fj7u2s671np9
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
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
xmyWhwxzeZdweoZDR6um1BRcJVJzdA==
-----END PRIVATE KEY-----