Skip to content

Commit

Permalink
Websocket: Add a option to define a api backend using wss url
Browse files Browse the repository at this point in the history
This commit add support to add wss protocol in the api_backend
definition, so users can define it easily.

Signed-off-by: Eloy Coto <[email protected]>
  • Loading branch information
eloycoto committed Jan 14, 2020
1 parent 0fb840c commit f338ffc
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 2 deletions.
12 changes: 10 additions & 2 deletions gateway/src/apicast/upstream.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,16 @@ local _M = {
}

local function proxy_pass(upstream)
return str_format('%s://%s', upstream.uri.scheme, upstream.upstream_name)
local scheme = upstream.uri.scheme
if upstream.uri.scheme == "wss" then
scheme = "https"
end

if upstream.uri.scheme == "ws" then
scheme = "http"
end

return str_format('%s://%s', scheme, upstream.upstream_name)
end

local mt = {
Expand All @@ -38,7 +47,6 @@ function _M.new(url)
if not url or url == cjson.null then
return nil, 'Upstream cannot be null'
end

local uri, err = url_helper.parse_url(url)
if err then
return nil, 'invalid upstream'
Expand Down
11 changes: 11 additions & 0 deletions spec/upstream_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,17 @@ describe('Upstream', function()

assert.equal('http://upstream', ngx.var.proxy_pass)
end)

it('works with websocket url', function()
local upstream = Upstream.new('ws://example.com')
upstream:call({})
assert.equal('http://upstream', ngx.var.proxy_pass)

upstream = Upstream.new('wss://example.com')
upstream:call({})
assert.equal('https://upstream', ngx.var.proxy_pass)
end)

end)
end)

Expand Down
157 changes: 157 additions & 0 deletions t/apicast-policy-websocket.t
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,163 @@ received: Data: Sending from client Type: text
[error]


=== TEST 2: No websocket connection with policy does not change Upgrade header
--- configuration
{
"services": [
{
"id": 42,
"backend_version": 1,
"backend_authentication_type": "service_token",
"backend_authentication_value": "token-value",
"proxy": {
"hosts": [
"localhost"
],
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/",
"proxy_rules": [
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 2 }
],
"policy_chain": [
{
"name": "apicast",
"version": "builtin",
"configuration": {}
},
{
"name": "websocket",
"version": "builtin",
"configuration": {}
}
]
}
}
]
}
--- backend
location /transactions/authrep.xml {
content_by_lua_block {
ngx.exit(200)
}
}
--- upstream env
location / {
content_by_lua_block {
local headers = ngx.req.get_headers()
assert(headers["Upgrade"] == nil)
}
}
--- request
GET /?user_key=value
--- error_code: 200
--- no_error_log
[error]


=== TEST 3: Websocket using ws url in the api_backend
--- configuration
{
"services": [
{
"id": 42,
"backend_version": 1,
"backend_authentication_type": "service_token",
"backend_authentication_value": "token-value",
"proxy": {
"hosts": [
"127.0.0.1"
],
"api_backend": "ws://test:$TEST_NGINX_SERVER_PORT/",
"proxy_rules": [
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 2 }
],
"policy_chain": [
{
"name": "apicast",
"version": "builtin",
"configuration": {}
},
{
"name": "websocket",
"version": "builtin",
"configuration": {}
}
]
}
}
]
}
--- backend
location /transactions/authrep.xml {
content_by_lua_block {
ngx.exit(200)
}
}
--- upstream env
location / {
access_by_lua_block {
local server = require "resty.websocket.server"

local wb, err = server:new{
timeout = 5000, -- in milliseconds
max_payload_len = 65535,
}
if not wb then
ngx.log(ngx.ERR, "failed to new websocket: ", err)
return ngx.exit(444)
end

local data, typ, err = wb:recv_frame()
if not data then
if not string.find(err, "timeout", 1, true) then
ngx.log(ngx.ERR, "failed to receive a frame: ", err)
return ngx.exit(444)
end
end

bytes, err = wb:send_text("Data: "..data.." Type: "..typ)
if not bytes then
ngx.log(ngx.ERR, "failed to send a text frame: ", err)
return ngx.exit(444)
end
}
}

--- test
content_by_lua_block {
local client = require "resty.websocket.client"
local wb, err = client:new()
local server = ngx.var.server_addr
local apicast_port = ngx.var.apicast_port
local uri = "ws://"..server.. ":"..apicast_port.."/?user_key=foo"
local ok, err = wb:connect(uri)
if not ok then
ngx.say("failed to connect: " .. err)
return
end

local bytes, err = wb:send_text("Sending from client")
if not bytes then
ngx.say("failed to send frame: ", err)
return
end

local data, typ, err = wb:recv_frame()
if not data then
ngx.say("failed to receive the frame: ",apicast_port, err)
return
end

ngx.say("received: ", data)
}
--- response_body env
received: Data: Sending from client Type: text
--- error_code: 200
--- timeout: 10
--- no_error_log
[error]


=== TEST 2: No websocket connection with policy does not change Upgrade header
--- configuration
{
Expand Down

0 comments on commit f338ffc

Please sign in to comment.