aboutsummaryrefslogtreecommitdiffstats
path: root/server/resty/http_connect.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server/resty/http_connect.lua')
-rw-r--r--server/resty/http_connect.lua274
1 files changed, 0 insertions, 274 deletions
diff --git a/server/resty/http_connect.lua b/server/resty/http_connect.lua
deleted file mode 100644
index 18a74b1..0000000
--- a/server/resty/http_connect.lua
+++ /dev/null
@@ -1,274 +0,0 @@
-local ngx_re_gmatch = ngx.re.gmatch
-local ngx_re_sub = ngx.re.sub
-local ngx_re_find = ngx.re.find
-local ngx_log = ngx.log
-local ngx_WARN = ngx.WARN
-
---[[
-A connection function that incorporates:
- - tcp connect
- - ssl handshake
- - http proxy
-Due to this it will be better at setting up a socket pool where connections can
-be kept alive.
-
-
-Call it with a single options table as follows:
-
-client:connect {
- scheme = "https" -- scheme to use, or nil for unix domain socket
- host = "myhost.com", -- target machine, or a unix domain socket
- port = nil, -- port on target machine, will default to 80/443 based on scheme
- pool = nil, -- connection pool name, leave blank! this function knows best!
- pool_size = nil, -- options as per: https://github.com/openresty/lua-nginx-module#tcpsockconnect
- 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
- ctx = nil, -- NOTE: not supported
-
- -- mTLS options (experimental!)
- --
- -- !!! IMPORTANT !!! These options require support for mTLS in cosockets,
- -- which is currently only available in the following unmerged PRs.
- --
- -- * https://github.com/openresty/lua-nginx-module/pull/1602
- -- * https://github.com/openresty/lua-resty-core/pull/278
- --
- -- The details of this feature may change. You have been warned!
- --
- ssl_client_cert = nil,
- ssl_client_priv_key = nil,
-
- proxy_opts, -- proxy opts, defaults to global proxy options
-}
-]]
-local function connect(self, options)
- local sock = self.sock
- if not sock then
- return nil, "not initialized"
- end
-
- local ok, err
-
- local request_scheme = options.scheme
- local request_host = options.host
- local request_port = options.port
-
- local poolname = options.pool
- local pool_size = options.pool_size
- local backlog = options.backlog
-
- if request_scheme and not request_port then
- request_port = (request_scheme == "https" and 443 or 80)
- elseif request_port and not request_scheme then
- return nil, "'scheme' is required when providing a port"
- end
-
- -- ssl settings
- local ssl, ssl_reused_session, ssl_server_name
- local ssl_verify, ssl_send_status_req, ssl_client_cert, ssl_client_priv_key
- 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
- if options.ssl_verify == false then
- ssl_verify = false
- end
- ssl_client_cert = options.ssl_client_cert
- ssl_client_priv_key = options.ssl_client_priv_key
- end
-
- -- proxy related settings
- local proxy, proxy_uri, proxy_authorization, proxy_host, proxy_port, path_prefix
- proxy = options.proxy_opts or self.proxy_opts
-
- if proxy then
- if request_scheme == "https" then
- proxy_uri = proxy.https_proxy
- proxy_authorization = proxy.https_proxy_authorization
- else
- proxy_uri = proxy.http_proxy
- proxy_authorization = proxy.http_proxy_authorization
- -- When a proxy is used, the target URI must be in absolute-form
- -- (RFC 7230, Section 5.3.2.). That is, it must be an absolute URI
- -- to the remote resource with the scheme, host and an optional port
- -- in place.
- --
- -- Since _format_request() constructs the request line by concatenating
- -- params.path and params.query together, we need to modify the path
- -- to also include the scheme, host and port so that the final form
- -- in conformant to RFC 7230.
- path_prefix = "http://" .. request_host .. (request_port == 80 and "" or (":" .. request_port))
- end
- if not proxy_uri then
- proxy = nil
- proxy_authorization = nil
- path_prefix = nil
- end
- end
-
- if proxy and proxy.no_proxy then
- -- Check if the no_proxy option matches this host. Implementation adapted
- -- from lua-http library (https://github.com/daurnimator/lua-http)
- if proxy.no_proxy == "*" then
- -- all hosts are excluded
- proxy = nil
-
- else
- local host = request_host
- local no_proxy_set = {}
- -- wget allows domains in no_proxy list to be prefixed by "."
- -- e.g. no_proxy=.mit.edu
- for host_suffix in ngx_re_gmatch(proxy.no_proxy, "\\.?([^,]+)") do
- no_proxy_set[host_suffix[1]] = true
- end
-
- -- From curl docs:
- -- matched as either a domain which contains the hostname, or the
- -- hostname itself. For example local.com would match local.com,
- -- local.com:80, and www.local.com, but not www.notlocal.com.
- --
- -- Therefore, we keep stripping subdomains from the host, compare
- -- them to the ones in the no_proxy list and continue until we find
- -- a match or until there's only the TLD left
- repeat
- if no_proxy_set[host] then
- proxy = nil
- proxy_uri = nil
- proxy_authorization = nil
- break
- end
-
- -- Strip the next level from the domain and check if that one
- -- is on the list
- host = ngx_re_sub(host, "^[^.]+\\.", "")
- until not ngx_re_find(host, "\\.")
- end
- end
-
- if proxy then
- local proxy_uri_t
- proxy_uri_t, err = self:parse_uri(proxy_uri)
- if not proxy_uri_t then
- return nil, "uri parse error: ", err
- end
-
- local proxy_scheme = proxy_uri_t[1]
- if proxy_scheme ~= "http" then
- return nil, "protocol " .. tostring(proxy_scheme) ..
- " not supported for proxy connections"
- end
- proxy_host = proxy_uri_t[2]
- proxy_port = proxy_uri_t[3]
- end
-
- -- construct a poolname unique within proxy and ssl info
- if not poolname then
- poolname = (request_scheme or "")
- .. ":" .. request_host
- .. ":" .. tostring(request_port)
- .. ":" .. tostring(ssl)
- .. ":" .. (ssl_server_name or "")
- .. ":" .. tostring(ssl_verify)
- .. ":" .. (proxy_uri or "")
- .. ":" .. (request_scheme == "https" and proxy_authorization or "")
- -- in the above we only add the 'proxy_authorization' as part of the poolname
- -- when the request is https. Because in that case the CONNECT request (which
- -- carries the authorization header) is part of the connect procedure, whereas
- -- with a plain http request the authorization is part of the actual request.
- end
-
- -- do TCP level connection
- local tcp_opts = { pool = poolname, pool_size = pool_size, backlog = backlog }
- if proxy then
- -- proxy based connection
- ok, err = sock:connect(proxy_host, proxy_port, tcp_opts)
- if not ok then
- return nil, "failed to connect to: " .. (proxy_host or "") ..
- ":" .. (proxy_port or "") ..
- ": ", err
- end
-
- if ssl and sock:getreusedtimes() == 0 then
- -- Make a CONNECT request to create a tunnel to the destination through
- -- the proxy. The request-target and the Host header must be in the
- -- 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
- res, err = self:request({
- method = "CONNECT",
- path = destination,
- headers = {
- ["Host"] = destination,
- ["Proxy-Authorization"] = proxy_authorization,
- }
- })
-
- if not res then
- return nil, "failed to issue CONNECT to proxy:", err
- end
-
- if res.status < 200 or res.status > 299 then
- return nil, "failed to establish a tunnel through a proxy: " .. res.status
- end
- end
-
- elseif not request_port then
- -- non-proxy, without port -> unix domain socket
- ok, err = sock:connect(request_host, tcp_opts)
- if not ok then
- return nil, err
- end
-
- else
- -- non-proxy, regular network tcp
- ok, err = sock:connect(request_host, request_port, tcp_opts)
- if not ok then
- return nil, err
- end
- end
-
- local ssl_session
- -- Now do the ssl handshake
- if ssl and sock:getreusedtimes() == 0 then
-
- -- Experimental mTLS support
- if ssl_client_cert and ssl_client_priv_key then
- if type(sock.setclientcert) ~= "function" then
- ngx_log(ngx_WARN, "cannot use SSL client cert and key without mTLS support")
-
- else
- -- currently no return value
- ok, err = sock:setclientcert(ssl_client_cert, ssl_client_priv_key)
- if not ok then
- ngx_log(ngx_WARN, "could not set client certificate: ", err)
- end
- end
- end
-
- 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
- end
-
- self.host = request_host
- self.port = request_port
- self.keepalive = true
- self.ssl = ssl
- -- set only for http, https has already been handled
- self.http_proxy_auth = request_scheme ~= "https" and proxy_authorization or nil
- self.path_prefix = path_prefix
-
- return true, nil, ssl_session
-end
-
-return connect