pax_global_header00006660000000000000000000000064147526123610014521gustar00rootroot0000000000000052 comment=54005878971567ef733f27b8b6b26ed0f85a1228 openresty-lua-resty-websocket-5400587/000077500000000000000000000000001475261236100176565ustar00rootroot00000000000000openresty-lua-resty-websocket-5400587/.gitattributes000066400000000000000000000000331475261236100225450ustar00rootroot00000000000000*.t linguist-language=Text openresty-lua-resty-websocket-5400587/.gitignore000066400000000000000000000000771475261236100216520ustar00rootroot00000000000000*.swp *.swo *~ go t/servroot/ reindex *.t_ tags a.patch *.html openresty-lua-resty-websocket-5400587/.travis.yml000066400000000000000000000062341475261236100217740ustar00rootroot00000000000000sudo: required dist: focal branches: only: - "master" os: linux language: c compiler: - gcc addons: apt: packages: - axel - cpanminus cache: apt: true directories: - download-cache env: global: - JOBS=3 - NGX_BUILD_JOBS=$JOBS - LUAJIT_PREFIX=/opt/luajit21 - LUAJIT_LIB=$LUAJIT_PREFIX/lib - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - LUA_CMODULE_DIR=/lib - OPENSSL_PREFIX=/opt/ssl - OPENSSL_LIB=$OPENSSL_PREFIX/lib - OPENSSL_INC=$OPENSSL_PREFIX/include - OPENSSL_VER=1.1.1w - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH - TEST_NGINX_SLEEP=0.006 matrix: - NGINX_VERSION=1.25.3 - NGINX_VERSION=1.27.1 install: - if [ ! -d download-cache ]; then mkdir download-cache; fi - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -O download-cache/openssl-$OPENSSL_VER.tar.gz https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz; fi - sudo cpanm --notest Test::Nginx Protocol::WebSocket > build.log 2>&1 || (cat build.log && exit 1) - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/nginx-devel-utils.git - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module - 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/no-pool-nginx.git ../no-pool-nginx - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git - git clone https://github.com/openresty/mockeagain.git script: - cd luajit2/ - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > build.log 2>&1 || (cat build.log && exit 1) - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) - cd .. - tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz - cd openssl-$OPENSSL_VER/ - ./config shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) - make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) - sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1) - cd ../mockeagain/ && make CC=$CC -j$JOBS && cd .. - export PATH=$PWD/work/nginx/sbin:$PWD/nginx-devel-utils:$PATH - export LD_PRELOAD=$PWD/mockeagain/mockeagain.so - export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH - export TEST_NGINX_RESOLVER=8.8.4.4 - export NGX_BUILD_CC=$CC - disable_pcre2=--without-pcre2; answer=`nginx-devel-utils/ngx-ver-ge "$NGINX_VERSION" 1.25.1`; if [ "$answer" = "N" ]; then disable_pcre2=""; fi; export disable_pcre2; - ngx-build $NGINX_VERSION $disable_pcre2 --with-ipv6 --with-http_realip_module --with-http_ssl_module --with-cc-opt="-I$OPENSSL_INC" --with-ld-opt="-L$OPENSSL_LIB -Wl,-rpath,$OPENSSL_LIB" --add-module=../ndk-nginx-module --add-module=../lua-nginx-module --with-debug > build.log 2>&1 || (cat build.log && exit 1) - nginx -V - ldd `which nginx`|grep -E 'luajit|ssl|pcre' - prove -I. -r t openresty-lua-resty-websocket-5400587/Makefile000066400000000000000000000007021475261236100213150ustar00rootroot00000000000000OPENRESTY_PREFIX=/usr/local/openresty PREFIX ?= /usr/local LUA_INCLUDE_DIR ?= $(PREFIX)/include LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) INSTALL ?= install .PHONY: all test install all: ; install: all $(INSTALL) -d $(DESTDIR)/$(LUA_LIB_DIR)/resty/websocket $(INSTALL) lib/resty/websocket/*.lua $(DESTDIR)/$(LUA_LIB_DIR)/resty/websocket/ test: all PATH=$(OPENRESTY_PREFIX)/nginx/sbin:$$PATH prove -I../test-nginx/lib -r t openresty-lua-resty-websocket-5400587/README.markdown000066400000000000000000000636201475261236100223660ustar00rootroot00000000000000Name ==== lua-resty-websocket - Lua WebSocket implementation for the ngx_lua module Table of Contents ================= * [Name](#name) * [Status](#status) * [Description](#description) * [Synopsis](#synopsis) * [Modules](#modules) * [resty.websocket.server](#restywebsocketserver) * [Methods](#methods) * [new](#new) * [set_timeout](#set_timeout) * [send_text](#send_text) * [send_binary](#send_binary) * [send_ping](#send_ping) * [send_pong](#send_pong) * [send_close](#send_close) * [send_frame](#send_frame) * [recv_frame](#recv_frame) * [resty.websocket.client](#restywebsocketclient) * [Methods](#methods) * [client:new](#clientnew) * [client:connect](#clientconnect) * [client:close](#clientclose) * [client:set_keepalive](#clientset_keepalive) * [client:set_timeout](#clientset_timeout) * [client:send_text](#clientsend_text) * [client:send_binary](#clientsend_binary) * [client:send_ping](#clientsend_ping) * [client:send_pong](#clientsend_pong) * [client:send_close](#clientsend_close) * [client:send_frame](#clientsend_frame) * [client:recv_frame](#clientrecv_frame) * [resty.websocket.protocol](#restywebsocketprotocol) * [Methods](#methods) * [protocol.recv_frame](#protocolrecv_frame) * [protocol.build_frame](#protocolbuild_frame) * [protocol.send_frame](#protocolsend_frame) * [Automatic Error Logging](#automatic-error-logging) * [Limitations](#limitations) * [Installation](#installation) * [TODO](#todo) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This library is considered production ready. Description =========== This Lua library implements a WebSocket server and client libraries based on the [ngx_lua module](http://wiki.nginx.org/HttpLuaModule). This Lua library takes advantage of ngx_lua's cosocket API, which ensures 100% nonblocking behavior. Note that only [RFC 6455](http://tools.ietf.org/html/rfc6455) is supported. Earlier protocol revisions like "hybi-10", "hybi-07", and "hybi-00" are not and will not be considered. Synopsis ======== ```lua 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 if typ == "close" then -- for typ "close", err contains the status code local code = err -- send a close frame back: local bytes, err = wb:send_close(1000, "enough, enough!") if not bytes then ngx.log(ngx.ERR, "failed to send the close frame: ", err) return end ngx.log(ngx.INFO, "closing with status code ", code, " and message ", data) return end if typ == "ping" then -- send a pong frame back: local bytes, err = wb:send_pong(data) if not bytes then ngx.log(ngx.ERR, "failed to send frame: ", err) return end elseif typ == "pong" then -- just discard the incoming pong frame else ngx.log(ngx.INFO, "received a frame of type ", typ, " and payload ", data) end wb:set_timeout(1000) -- change the network timeout to 1 second bytes, err = wb:send_text("Hello world") if not bytes then ngx.log(ngx.ERR, "failed to send a text frame: ", err) return ngx.exit(444) end bytes, err = wb:send_binary("blah blah blah...") if not bytes then ngx.log(ngx.ERR, "failed to send a binary frame: ", err) return ngx.exit(444) end local bytes, err = wb:send_close(1000, "enough, enough!") if not bytes then ngx.log(ngx.ERR, "failed to send the close frame: ", err) return end ``` [Back to TOC](#table-of-contents) Modules ======= [Back to TOC](#table-of-contents) resty.websocket.server ---------------------- To load this module, just do this ```lua local server = require "resty.websocket.server" ``` [Back to TOC](#table-of-contents) ### Methods [Back to TOC](#table-of-contents) #### new `syntax: wb, err = server:new()` `syntax: wb, err = server:new(opts)` Performs the websocket handshake process on the server side and returns a WebSocket server object. In case of error, it returns `nil` and a string describing the error. An optional options table can be specified. The following options are as follows: * `max_payload_len` Specifies the maximal length of payload allowed when sending and receiving WebSocket frames. Defaults to `65535`. * `max_recv_len` Specifies the maximal length of payload allowed when receiving WebSocket frames. Defaults to the value of `max_payload_len`. * `max_send_len` Specifies the maximal length of payload allowed when sending WebSocket frames. Defaults to the value of `max_payload_len`. * `send_masked` Specifies whether to send out masked WebSocket frames. When it is `true`, masked frames are always sent. Default to `false`. * `timeout` Specifies the network timeout threshold in milliseconds. You can change this setting later via the `set_timeout` method call. Note that this timeout setting does not affect the HTTP response header sending process for the websocket handshake; you need to configure the [send_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#send_timeout) directive at the same time. [Back to TOC](#table-of-contents) #### set_timeout `syntax: wb:set_timeout(ms)` Sets the timeout delay (in milliseconds) for the network-related operations. [Back to TOC](#table-of-contents) #### send_text `syntax: bytes, err = wb:send_text(text)` Sends the `text` argument out as an unfragmented data frame of the `text` type. Returns the number of bytes that have actually been sent on the TCP level. In case of errors, returns `nil` and a string describing the error. [Back to TOC](#table-of-contents) #### send_binary `syntax: bytes, err = wb:send_binary(data)` Sends the `data` argument out as an unfragmented data frame of the `binary` type. Returns the number of bytes that have actually been sent on the TCP level. In case of errors, returns `nil` and a string describing the error. [Back to TOC](#table-of-contents) #### send_ping `syntax: bytes, err = wb:send_ping()` `syntax: bytes, err = wb:send_ping(msg)` Sends out a `ping` frame with an optional message specified by the `msg` argument. Returns the number of bytes that have actually been sent on the TCP level. In case of errors, returns `nil` and a string describing the error. Note that this method does not wait for a pong frame from the remote end. [Back to TOC](#table-of-contents) #### send_pong `syntax: bytes, err = wb:send_pong()` `syntax: bytes, err = wb:send_pong(msg)` Sends out a `pong` frame with an optional message specified by the `msg` argument. Returns the number of bytes that have actually been sent on the TCP level. In case of errors, returns `nil` and a string describing the error. [Back to TOC](#table-of-contents) #### send_close `syntax: bytes, err = wb:send_close()` `syntax: bytes, err = wb:send_close(code, msg)` Sends out a `close` frame with an optional status code and a message. In case of errors, returns `nil` and a string describing the error. For a list of valid status code, see the following document: http://tools.ietf.org/html/rfc6455#section-7.4.1 Note that this method does not wait for a `close` frame from the remote end. [Back to TOC](#table-of-contents) #### send_frame `syntax: bytes, err = wb:send_frame(fin, opcode, payload)` Sends out a raw websocket frame by specifying the `fin` field (boolean value), the opcode, and the payload. For a list of valid opcode, see http://tools.ietf.org/html/rfc6455#section-5.2 In case of errors, returns `nil` and a string describing the error. To control the maximal payload length allowed, you can pass the `max_payload_len` option to the `new` constructor. To control whether to send masked frames, you can pass `true` to the `send_masked` option in the `new` constructor method. By default, unmasked frames are sent. [Back to TOC](#table-of-contents) #### recv_frame `syntax: data, typ, err = wb:recv_frame()` Receives a WebSocket frame from the wire. In case of an error, returns two `nil` values and a string describing the error. The second return value is always the frame type, which could be one of `continuation`, `text`, `binary`, `close`, `ping`, `pong`, or `nil` (for unknown types). For `close` frames, returns 3 values: the extra status message (which could be an empty string), the string "close", and a Lua number for the status code (if any). For possible closing status codes, see http://tools.ietf.org/html/rfc6455#section-7.4.1 For other types of frames, just returns the payload and the type. For fragmented frames, the `err` return value is the Lua string "again". [Back to TOC](#table-of-contents) resty.websocket.client ---------------------- To load this module, just do this ```lua local client = require "resty.websocket.client" ``` A simple example to demonstrate the usage: ```lua local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local ok, err, res = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive the frame: ", err) return end ngx.say("received: ", data, " (", typ, "): ", err) local bytes, err = wb:send_text("copy: " .. data) if not bytes then ngx.say("failed to send frame: ", err) return end local bytes, err = wb:send_close() if not bytes then ngx.say("failed to send frame: ", err) return end ``` [Back to TOC](#table-of-contents) ### Methods [Back to TOC](#table-of-contents) #### client:new `syntax: wb, err = client:new()` `syntax: wb, err = client:new(opts)` Instantiates a WebSocket client object. In case of error, it returns `nil` and a string describing the error. An optional options table can be specified. The following options are as follows: * `max_payload_len` Specifies the maximal length of payload allowed when sending and receiving WebSocket frames. Defaults to `65536`. * `max_recv_len` Specifies the maximal length of payload allowed when receiving WebSocket frames. Defaults to the value of `max_payload_len`. * `max_send_len` Specifies the maximal length of payload allowed when sending WebSocket frames. Defaults to the value of `max_payload_len`. * `send_unmasked` Specifies whether to send out an unmasked WebSocket frames. When it is `true`, unmasked frames are always sent. Default to `false`. RFC 6455 requires, however, that the client MUST send masked frames to the server, so never set this option to `true` unless you know what you are doing. * `timeout` Specifies the default network timeout threshold in milliseconds. You can change this setting later via the `set_timeout` method call. [Back to TOC](#table-of-contents) #### client:connect `syntax: ok, err, res = wb:connect("ws://:/")` `syntax: ok, err, res = wb:connect("wss://:/")` `syntax: ok, err, res = wb:connect("ws://:/", options)` `syntax: ok, err, res = wb:connect("wss://:/", options)` Connects to the remote WebSocket service port and performs the websocket handshake process on the client side. Before actually resolving the host name and connecting to the remote backend, this method will always look up the connection pool for matched idle connections created by previous calls of this method. The third return value of this method contains the raw, plain-text response (status line and headers) to the handshake request. This allows the caller to perform additional validation and/or extract the response headers. When the connection is reused and no handshake request is sent, the string `"connection reused"` is returned in lieu of the response. An optional Lua table can be specified as the last argument to this method to specify various connect options: * `protocols` Specifies all the subprotocols used for the current WebSocket session. It could be a Lua table holding all the subprotocol names or just a single Lua string. * `origin` Specifies the value of the `Origin` request header. * `pool` Specifies a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template `:`. * `pool_size` specify the size of the connection pool. If omitted and no `backlog` option was provided, no pool will be created. If omitted but `backlog` was provided, the pool will be created with a default size equal to the value of the [lua_socket_pool_size](https://github.com/openresty/lua-nginx-module/tree/master#lua_socket_pool_size) directive. The connection pool holds up to `pool_size` alive connections ready to be reused by subsequent calls to [connect](#client:connect), but note that there is no upper limit to the total number of opened connections outside of the pool. If you need to restrict the total number of opened connections, specify the `backlog` option. When the connection pool would exceed its size limit, the least recently used (kept-alive) connection already in the pool will be closed to make room for the current connection. Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. Also note that the size of the connection pool cannot be changed once it has been created. This option was first introduced in the `v0.10.14` release. * `backlog` if specified, this module will limit the total number of opened connections for this pool. No more connections than `pool_size` can be opened for this pool at any time. If the connection pool is full, subsequent connect operations will be queued into a queue equal to this option's value (the "backlog" queue). If the number of queued connect operations is equal to `backlog`, subsequent connect operations will fail and return `nil` plus the error string `"too many waiting connect operations"`. The queued connect operations will be resumed once the number of connections in the pool is less than `pool_size`. The queued connect operation will abort once they have been queued for more than `connect_timeout`, controlled by [settimeouts](#client:set_timeout), and will return `nil` plus the error string `"timeout"`. This option was first introduced in the `v0.10.14` release. * `ssl_verify` Specifies whether to perform SSL certificate verification during the SSL handshake if the `wss://` scheme is used. * `headers` Specifies custom headers to be sent in the handshake request. The table is expected to contain strings in the format `{"a-header: a header value", "another-header: another header value"}`. * `client_cert` Specifies a client certificate chain cdata object that will be used while TLS handshaking with remote server. These objects can be created using [ngx.ssl.parse_pem_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) function provided by lua-resty-core. Note that specifying the `client_cert` option requires corresponding `client_priv_key` be provided too. See below. * `client_priv_key` Specifies a private key corresponds to the `client_cert` option above. These objects can be created using [ngx.ssl.parse_pem_priv_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) function provided by lua-resty-core. * `host` Specifies the value of the `Host` header sent in the handshake request. If not provided, the `Host` header will be derived from the hostname/address and port in the connection URI. * `server_name` Specifies the server name (SNI) to use when performing the TLS handshake with the server. If not provided, the `host` value or the `:` from the connection URI will be used. * `key` Specifies the value of the `Sec-WebSocket-Key` header in the handshake request. The value should be a base64-encoded, 16 byte string conforming to the client handshake requirements of the [WebSocket RFC](https://datatracker.ietf.org/doc/html/rfc6455#section-4.1). If not provided, a key is randomly generated. The SSL connection mode (`wss://`) requires at least `ngx_lua` 0.9.11 or OpenResty 1.7.4.1. [Back to TOC](#table-of-contents) #### client:close `syntax: ok, err = wb:close()` Closes the current WebSocket connection. If no `close` frame is sent yet, then the `close` frame will be automatically sent. [Back to TOC](#table-of-contents) #### client:set_keepalive `syntax: ok, err = wb:set_keepalive(max_idle_timeout, pool_size)` Puts the current WebSocket connection immediately into the `ngx_lua` cosocket connection pool. You can specify the max idle timeout (in ms) when the connection is in the pool and the maximal size of the pool every nginx worker process. In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. Only call this method in the place you would have called the `close` method instead. Calling this method will immediately turn the current WebSocket object into the `closed` state. Any subsequent operations other than `connect()` on the current objet will return the `closed` error. [Back to TOC](#table-of-contents) #### client:set_timeout `syntax: wb:set_timeout(ms)` Identical to the `set_timeout` method of the `resty.websocket.server` objects. [Back to TOC](#table-of-contents) #### client:send_text `syntax: bytes, err = wb:send_text(text)` Identical to the [send_text](#send_text) method of the `resty.websocket.server` objects. [Back to TOC](#table-of-contents) #### client:send_binary `syntax: bytes, err = wb:send_binary(data)` Identical to the [send_binary](#send_binary) method of the `resty.websocket.server` objects. [Back to TOC](#table-of-contents) #### client:send_ping `syntax: bytes, err = wb:send_ping()` `syntax: bytes, err = wb:send_ping(msg)` Identical to the [send_ping](#send_ping) method of the `resty.websocket.server` objects. [Back to TOC](#table-of-contents) #### client:send_pong `syntax: bytes, err = wb:send_pong()` `syntax: bytes, err = wb:send_pong(msg)` Identical to the [send_pong](#send_pong) method of the `resty.websocket.server` objects. [Back to TOC](#table-of-contents) #### client:send_close `syntax: bytes, err = wb:send_close()` `syntax: bytes, err = wb:send_close(code, msg)` Identical to the [send_close](#send_close) method of the `resty.websocket.server` objects. [Back to TOC](#table-of-contents) #### client:send_frame `syntax: bytes, err = wb:send_frame(fin, opcode, payload)` Identical to the [send_frame](#send_frame) method of the `resty.websocket.server` objects. To control whether to send unmasked frames, you can pass `true` to the `send_unmasked` option in the `new` constructor method. By default, masked frames are sent. [Back to TOC](#table-of-contents) #### client:recv_frame `syntax: data, typ, err = wb:recv_frame()` Identical to the [recv_frame](#recv_frame) method of the `resty.websocket.server` objects. [Back to TOC](#table-of-contents) resty.websocket.protocol ------------------------ To load this module, just do this ```lua local protocol = require "resty.websocket.protocol" ``` [Back to TOC](#table-of-contents) ### Methods [Back to TOC](#table-of-contents) #### protocol.recv_frame `syntax: data, typ, err = protocol.recv_frame(socket, max_payload_len, force_masking)` Receives a WebSocket frame from the wire. [Back to TOC](#table-of-contents) #### protocol.build_frame `syntax: frame = protocol.build_frame(fin, opcode, payload_len, payload, masking)` Builds a raw WebSocket frame. [Back to TOC](#table-of-contents) #### protocol.send_frame `syntax: bytes, err = protocol.send_frame(socket, fin, opcode, payload, max_payload_len, masking)` Sends a raw WebSocket frame. [Back to TOC](#table-of-contents) Automatic Error Logging ======================= By default the underlying [ngx_lua](http://wiki.nginx.org/HttpLuaModule) module does error logging when socket errors happen. If you are already doing proper error handling in your own Lua code, then you are recommended to disable this automatic error logging by turning off [ngx_lua](http://wiki.nginx.org/HttpLuaModule)'s [lua_socket_log_errors](http://wiki.nginx.org/HttpLuaModule#lua_socket_log_errors) directive, that is, ```nginx lua_socket_log_errors off; ``` [Back to TOC](#table-of-contents) Limitations =========== * This library cannot be used in code contexts like init_by_lua*, set_by_lua*, log_by_lua*, and header_filter_by_lua* where the ngx_lua cosocket API is not available. * The `resty.websocket` object instance cannot be stored in a Lua variable at the Lua module level, because it will then be shared by all the concurrent requests handled by the same nginx worker process (see http://wiki.nginx.org/HttpLuaModule#Data_Sharing_within_an_Nginx_Worker ) and result in bad race conditions when concurrent requests are trying to use the same `resty.websocket` instance. You should always initiate `resty.websocket` objects in function local variables or in the `ngx.ctx` table. These places all have their own data copies for each request. [Back to TOC](#table-of-contents) Installation ============ It is recommended to use the latest [OpenResty bundle](http://openresty.org) directly where this library is bundled and enabled by default. At least OpenResty 1.4.2.9 is required. And you need to enable LuaJIT when building your OpenResty bundle by passing the `--with-luajit` option to its `./configure` script. No extra Nginx configuration is required. If you want to use this library with your own Nginx build (with ngx_lua), then you need to ensure you are using at least ngx_lua 0.9.0 (and [lua-bitop](http://bitop.luajit.org/) library if you are not using LuaJIT). Also, You need to configure the [lua_package_path](https://github.com/chaoslawful/lua-nginx-module#lua_package_path) directive to add the path of your lua-resty-websocket source tree to ngx_lua's Lua module search path, as in ```nginx # nginx.conf http { lua_package_path "/path/to/lua-resty-websocket/lib/?.lua;;"; ... } ``` and then load the library in Lua: ```lua local server = require "resty.websocket.server" ``` [Back to TOC](#table-of-contents) TODO ==== [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](http://github.com/agentzh/lua-resty-websocket/issues), 1. or posting to the [OpenResty community](http://wiki.nginx.org/HttpLuaModule#Community). [Back to TOC](#table-of-contents) Author ====== Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2013-2017, by Yichun Zhang (agentzh) , OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * Blog post [WebSockets with OpenResty](https://medium.com/p/1778601c9e05) by Aapo Talvensaari. * the ngx_lua module: http://wiki.nginx.org/HttpLuaModule * the websocket protocol: http://tools.ietf.org/html/rfc6455 * the [lua-resty-upload](https://github.com/agentzh/lua-resty-upload) library * the [lua-resty-redis](https://github.com/agentzh/lua-resty-redis) library * the [lua-resty-memcached](https://github.com/agentzh/lua-resty-memcached) library * the [lua-resty-mysql](https://github.com/agentzh/lua-resty-mysql) library [Back to TOC](#table-of-contents) openresty-lua-resty-websocket-5400587/dist.ini000066400000000000000000000004311475261236100213200ustar00rootroot00000000000000name=lua-resty-websocket abstract=Lua WebSocket implementation for the ngx_lua module author=Yichun "agentzh" Zhang (agentzh) is_original=yes license=2bsd lib_dir=lib doc_dir=lib repo_link=https://github.com/openresty/lua-resty-websocket main_module=lib/resty/websocket/client.lua openresty-lua-resty-websocket-5400587/lib/000077500000000000000000000000001475261236100204245ustar00rootroot00000000000000openresty-lua-resty-websocket-5400587/lib/resty/000077500000000000000000000000001475261236100215725ustar00rootroot00000000000000openresty-lua-resty-websocket-5400587/lib/resty/websocket/000077500000000000000000000000001475261236100235605ustar00rootroot00000000000000openresty-lua-resty-websocket-5400587/lib/resty/websocket/client.lua000066400000000000000000000243061475261236100255460ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) -- FIXME: this library is very rough and is currently just for testing -- the websocket client. local wbproto = require "resty.websocket.protocol" local bit = require "bit" local _recv_frame = wbproto.recv_frame local _send_frame = wbproto.send_frame local new_tab = wbproto.new_tab local tcp = ngx.socket.tcp local re_match = ngx.re.match local re_find = ngx.re.find local encode_base64 = ngx.encode_base64 local concat = table.concat local char = string.char local str_find = string.find local rand = math.random local rshift = bit.rshift local band = bit.band local setmetatable = setmetatable local type = type local debug = ngx.config.debug local ngx_log = ngx.log local ngx_DEBUG = ngx.DEBUG local assert = assert local ssl_support = true if not ngx.config or not ngx.config.ngx_lua_version or ngx.config.ngx_lua_version < 9011 then ssl_support = false end local _M = new_tab(0, 13) _M._VERSION = '0.13' local mt = { __index = _M } function _M.new(self, opts) local sock, err = tcp() if not sock then return nil, err end local max_payload_len, send_unmasked, timeout local max_recv_len, max_send_len if opts then max_payload_len = opts.max_payload_len max_recv_len = opts.max_recv_len max_send_len = opts.max_send_len send_unmasked = opts.send_unmasked timeout = opts.timeout if timeout then sock:settimeout(timeout) end end max_payload_len = max_payload_len or 65535 max_recv_len = max_recv_len or max_payload_len max_send_len = max_send_len or max_payload_len return setmetatable({ sock = sock, max_recv_len = max_recv_len, max_send_len = max_send_len, send_unmasked = send_unmasked, }, mt) end function _M.connect(self, uri, opts) local sock = self.sock if not sock then return nil, "not initialized" end local is_unix = false local m, err if re_find(uri, "unix:") then is_unix = true m, err = re_match(uri, [[^(wss?)://(unix:[^:]+):()(.*)]], "jo") else m, err = re_match(uri, [[^(wss?)://([^:/]+)(?::(\d+))?(.*)]], "jo") end if not m then if err then return nil, "failed to match the uri: " .. err end return nil, "bad websocket uri" end local scheme = m[1] local addr = m[2] local port = m[3] local path = m[4] -- ngx.say("host: ", host) -- ngx.say("port: ", port) local ssl = scheme == "wss" if ssl and not ssl_support then return nil, "ngx_lua 0.9.11+ required for SSL sockets" end if not port then port = ssl and 443 or 80 end if path == "" then path = "/" end local ssl_verify, server_name, headers, proto_header, origin_header local sock_opts = {} local client_cert, client_priv_key local header_host local key if opts then local protos = opts.protocols if protos then if type(protos) == "table" then proto_header = "\r\nSec-WebSocket-Protocol: " .. concat(protos, ",") else proto_header = "\r\nSec-WebSocket-Protocol: " .. protos end end local origin = opts.origin if origin then origin_header = "\r\nOrigin: " .. origin end if opts.pool then sock_opts.pool = opts.pool end --pool_size specify the size of the connection pool. If omitted and no backlog option was provided, no pool will be created. if opts.pool_size then sock_opts.pool_size = opts.pool_size end if opts.backlog then sock_opts.backlog = opts.backlog end client_cert = opts.client_cert client_priv_key = opts.client_priv_key if client_cert then assert(client_priv_key, "client_priv_key must be provided with client_cert") end ssl_verify = opts.ssl_verify server_name = opts.server_name if server_name ~= nil and type(server_name) ~= "string" then return nil, "SSL server_name must be a string" end if opts.headers then headers = opts.headers if type(headers) ~= "table" then return nil, "custom headers must be a table" end end header_host = opts.host if header_host ~= nil and type(header_host) ~= "string" then return nil, "custom host header must be a string" end key = opts.key if key ~= nil and type(key) ~= "string" then return nil, "custom Sec-WebSocket-Key must be a string" end end local ok, err if is_unix then ok, err = sock:connect(addr, sock_opts) else ok, err = sock:connect(addr, port, sock_opts) end if not ok then return nil, "failed to connect: " .. err end -- check for connections from pool: local reused_count, err = sock:getreusedtimes() if not reused_count then return nil, "failed to get reused times: " .. tostring(err) end if reused_count > 0 then -- being a reused connection (must have done handshake) return 1, nil, "connection reused" end if ssl then if client_cert then ok, err = sock:setclientcert(client_cert, client_priv_key) if not ok then return nil, "failed to set TLS client certificate: " .. err end end server_name = server_name or header_host or addr ok, err = sock:sslhandshake(false, server_name, ssl_verify) if not ok then return nil, "ssl handshake failed: " .. err end end local custom_headers if headers then custom_headers = concat(headers, "\r\n") custom_headers = "\r\n" .. custom_headers end -- do the websocket handshake: if not key then local bytes = char(rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1, rand(256) - 1) key = encode_base64(bytes) end local host_header = header_host or (is_unix and "unix_sock" or addr .. ":" .. port) local req = "GET " .. path .. " HTTP/1.1\r\nUpgrade: websocket\r\nHost: " .. host_header .. "\r\nSec-WebSocket-Key: " .. key .. (proto_header or "") .. "\r\nSec-WebSocket-Version: 13" .. (origin_header or "") .. "\r\nConnection: Upgrade" .. (custom_headers or "") .. "\r\n\r\n" local bytes, err = sock:send(req) if not bytes then return nil, "failed to send the handshake request: " .. err end local header_reader = sock:receiveuntil("\r\n\r\n") -- FIXME: check for too big response headers local header, err, partial = header_reader() if not header then return nil, "failed to receive response header: " .. err end -- error("header: " .. header) -- FIXME: verify the response headers m, err = re_match(header, [[^\s*HTTP/1\.1\s+]], "jo") if not m then return nil, "bad HTTP response status line: " .. header end return 1, nil, header end function _M.set_timeout(self, time) local sock = self.sock if not sock then return nil, nil, "not initialized yet" end return sock:settimeout(time) end function _M.recv_frame(self) if self.fatal then return nil, nil, "fatal error already happened" end local sock = self.sock if not sock then return nil, nil, "not initialized yet" end local data, typ, err = _recv_frame(sock, self.max_recv_len, false) if not data and not str_find(err, ": timeout", 1, true) then self.fatal = true end return data, typ, err end local function send_frame(self, fin, opcode, payload) if self.fatal then return nil, "fatal error already happened" end if self.closed then return nil, "already closed" end local sock = self.sock if not sock then return nil, "not initialized yet" end local bytes, err = _send_frame(sock, fin, opcode, payload, self.max_send_len, not self.send_unmasked) if not bytes then self.fatal = true end return bytes, err end _M.send_frame = send_frame function _M.send_text(self, data) return send_frame(self, true, 0x1, data) end function _M.send_binary(self, data) return send_frame(self, true, 0x2, data) end local function send_close(self, code, msg) local payload if code then if type(code) ~= "number" or code > 0x7fff then return nil, "bad status code" end payload = char(band(rshift(code, 8), 0xff), band(code, 0xff)) .. (msg or "") end if debug then ngx_log(ngx_DEBUG, "sending the close frame") end local bytes, err = send_frame(self, true, 0x8, payload) if not bytes then self.fatal = true end self.closed = true return bytes, err end _M.send_close = send_close function _M.send_ping(self, data) return send_frame(self, true, 0x9, data) end function _M.send_pong(self, data) return send_frame(self, true, 0xa, data) end function _M.close(self) if self.fatal then return nil, "fatal error already happened" end local sock = self.sock if not sock then return nil, "not initialized" end if not self.closed then local bytes, err = send_close(self) if not bytes then return nil, "failed to send close frame: " .. err end end return sock:close() end function _M.set_keepalive(self, ...) local sock = self.sock if not sock then return nil, "not initialized" end return sock:setkeepalive(...) end return _M openresty-lua-resty-websocket-5400587/lib/resty/websocket/protocol.lua000066400000000000000000000214241475261236100261270ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local bit = require "bit" local ffi = require "ffi" local byte = string.byte local char = string.char local sub = string.sub local band = bit.band local bor = bit.bor local bxor = bit.bxor local lshift = bit.lshift local rshift = bit.rshift --local tohex = bit.tohex local tostring = tostring local concat = table.concat local rand = math.random local type = type local debug = ngx.config.debug local ngx_log = ngx.log local ngx_DEBUG = ngx.DEBUG local ffi_new = ffi.new local ffi_string = ffi.string local ok, new_tab = pcall(require, "table.new") if not ok then new_tab = function (narr, nrec) return {} end end local _M = new_tab(0, 5) _M.new_tab = new_tab _M._VERSION = '0.13' local types = { [0x0] = "continuation", [0x1] = "text", [0x2] = "binary", [0x8] = "close", [0x9] = "ping", [0xa] = "pong", } local str_buf_size = 4096 local str_buf local c_buf_type = ffi.typeof("char[?]") local function get_string_buf(size) if size > str_buf_size then return ffi_new(c_buf_type, size) end if not str_buf then str_buf = ffi_new(c_buf_type, str_buf_size) end return str_buf end function _M.recv_frame(sock, max_payload_len, force_masking) local data, err = sock:receive(2) if not data then return nil, nil, "failed to receive the first 2 bytes: " .. err end local fst, snd = byte(data, 1, 2) local fin = band(fst, 0x80) ~= 0 -- print("fin: ", fin) if band(fst, 0x70) ~= 0 then return nil, nil, "bad RSV1, RSV2, or RSV3 bits" end local opcode = band(fst, 0x0f) -- print("opcode: ", tohex(opcode)) if opcode >= 0x3 and opcode <= 0x7 then return nil, nil, "reserved non-control frames" end if opcode >= 0xb and opcode <= 0xf then return nil, nil, "reserved control frames" end local mask = band(snd, 0x80) ~= 0 if debug then ngx_log(ngx_DEBUG, "recv_frame: mask bit: ", mask and 1 or 0) end if force_masking and not mask then return nil, nil, "frame unmasked" end local payload_len = band(snd, 0x7f) -- print("payload len: ", payload_len) if payload_len == 126 then local data, err = sock:receive(2) if not data then return nil, nil, "failed to receive the 2 byte payload length: " .. (err or "unknown") end payload_len = bor(lshift(byte(data, 1), 8), byte(data, 2)) elseif payload_len == 127 then local data, err = sock:receive(8) if not data then return nil, nil, "failed to receive the 8 byte payload length: " .. (err or "unknown") end if byte(data, 1) ~= 0 or byte(data, 2) ~= 0 or byte(data, 3) ~= 0 or byte(data, 4) ~= 0 then return nil, nil, "payload len too large" end local fifth = byte(data, 5) if band(fifth, 0x80) ~= 0 then return nil, nil, "payload len too large" end payload_len = bor(lshift(fifth, 24), lshift(byte(data, 6), 16), lshift(byte(data, 7), 8), byte(data, 8)) end if band(opcode, 0x8) ~= 0 then -- being a control frame if payload_len > 125 then return nil, nil, "too long payload for control frame" end if not fin then return nil, nil, "fragmented control frame" end end -- print("payload len: ", payload_len, ", max payload len: ", -- max_payload_len) if payload_len > max_payload_len then return nil, nil, "exceeding max payload len" end local rest if mask then rest = payload_len + 4 else rest = payload_len end -- print("rest: ", rest) local data if rest > 0 then data, err = sock:receive(rest) if not data then return nil, nil, "failed to read masking-len and payload: " .. (err or "unknown") end else data = "" end -- print("received rest") if opcode == 0x8 then -- being a close frame if payload_len > 0 then if payload_len < 2 then return nil, nil, "close frame with a body must carry a 2-byte" .. " status code" end local msg, code if mask then local fst = bxor(byte(data, 4 + 1), byte(data, 1)) local snd = bxor(byte(data, 4 + 2), byte(data, 2)) code = bor(lshift(fst, 8), snd) if payload_len > 2 then -- TODO string.buffer optimizations local bytes = get_string_buf(payload_len - 2) for i = 3, payload_len do bytes[i - 3] = bxor(byte(data, 4 + i), byte(data, (i - 1) % 4 + 1)) end msg = ffi_string(bytes, payload_len - 2) else msg = "" end else local fst = byte(data, 1) local snd = byte(data, 2) code = bor(lshift(fst, 8), snd) -- print("parsing unmasked close frame payload: ", payload_len) if payload_len > 2 then msg = sub(data, 3) else msg = "" end end return msg, "close", code end return "", "close", nil end local msg if mask then -- TODO string.buffer optimizations local bytes = get_string_buf(payload_len) for i = 1, payload_len do bytes[i - 1] = bxor(byte(data, 4 + i), byte(data, (i - 1) % 4 + 1)) end msg = ffi_string(bytes, payload_len) else msg = data end return msg, types[opcode], not fin and "again" or nil end local function build_frame(fin, opcode, payload_len, payload, masking) -- XXX optimize this when we have string.buffer in LuaJIT 2.1 local fst if fin then fst = bor(0x80, opcode) else fst = opcode end local snd, extra_len_bytes if payload_len <= 125 then snd = payload_len extra_len_bytes = "" elseif payload_len <= 65535 then snd = 126 extra_len_bytes = char(band(rshift(payload_len, 8), 0xff), band(payload_len, 0xff)) else if band(payload_len, 0x7fffffff) < payload_len then return nil, "payload too big" end snd = 127 -- XXX we only support 31-bit length here extra_len_bytes = char(0, 0, 0, 0, band(rshift(payload_len, 24), 0xff), band(rshift(payload_len, 16), 0xff), band(rshift(payload_len, 8), 0xff), band(payload_len, 0xff)) end local masking_key if masking then -- set the mask bit snd = bor(snd, 0x80) local key = rand(0xffffffff) masking_key = char(band(rshift(key, 24), 0xff), band(rshift(key, 16), 0xff), band(rshift(key, 8), 0xff), band(key, 0xff)) -- TODO string.buffer optimizations local bytes = get_string_buf(payload_len) for i = 1, payload_len do bytes[i - 1] = bxor(byte(payload, i), byte(masking_key, (i - 1) % 4 + 1)) end payload = ffi_string(bytes, payload_len) else masking_key = "" end return char(fst, snd) .. extra_len_bytes .. masking_key .. payload end _M.build_frame = build_frame function _M.send_frame(sock, fin, opcode, payload, max_payload_len, masking) -- ngx.log(ngx.WARN, ngx.var.uri, ": masking: ", masking) if not payload then payload = "" elseif type(payload) ~= "string" then payload = tostring(payload) end local payload_len = #payload if payload_len > max_payload_len then return nil, "payload too big" end if band(opcode, 0x8) ~= 0 then -- being a control frame if payload_len > 125 then return nil, "too much payload for control frame" end if not fin then return nil, "fragmented control frame" end end local frame, err = build_frame(fin, opcode, payload_len, payload, masking) if not frame then return nil, "failed to build frame: " .. err end local bytes, err = sock:send(frame) if not bytes then return nil, "failed to send frame: " .. err end return bytes end return _M openresty-lua-resty-websocket-5400587/lib/resty/websocket/server.lua000066400000000000000000000124451475261236100255770ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local bit = require "bit" local wbproto = require "resty.websocket.protocol" local new_tab = wbproto.new_tab local _recv_frame = wbproto.recv_frame local _send_frame = wbproto.send_frame local ngx = ngx local http_ver = ngx.req.http_version local req_sock = ngx.req.socket local ngx_header = ngx.header local req_headers = ngx.req.get_headers local str_lower = string.lower local char = string.char local str_find = string.find local sha1_bin = ngx.sha1_bin local base64 = ngx.encode_base64 local read_body = ngx.req.read_body local ngx_send_headers = ngx.send_headers local ngx_flush = ngx.flush local band = bit.band local rshift = bit.rshift local type = type local setmetatable = setmetatable local tostring = tostring -- local print = print local _M = new_tab(0, 10) _M._VERSION = '0.13' local mt = { __index = _M } function _M.new(self, opts) if ngx.headers_sent then return nil, "response header already sent" end read_body() if http_ver() ~= 1.1 then return nil, "bad http version" end local headers = req_headers() local val = headers.upgrade if type(val) == "table" then val = val[1] end if not val or str_lower(val) ~= "websocket" then return nil, "bad \"upgrade\" request header: " .. tostring(val) end val = headers.connection if type(val) == "table" then val = val[1] end if not val or not str_find(str_lower(val), "upgrade", 1, true) then return nil, "bad \"connection\" request header" end local key = headers["sec-websocket-key"] if type(key) == "table" then key = key[1] end if not key then return nil, "bad \"sec-websocket-key\" request header" end local ver = headers["sec-websocket-version"] if type(ver) == "table" then ver = ver[1] end if not ver or ver ~= "13" then return nil, "bad \"sec-websocket-version\" request header" end local protocols = headers["sec-websocket-protocol"] if type(protocols) == "table" then protocols = protocols[1] end if protocols then ngx_header["Sec-WebSocket-Protocol"] = protocols end ngx_header["Upgrade"] = "websocket" local sha1 = sha1_bin(key .. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11") ngx_header["Sec-WebSocket-Accept"] = base64(sha1) ngx_header["Content-Type"] = nil ngx.status = 101 local ok, err = ngx_send_headers() if not ok then return nil, "failed to send response header: " .. (err or "unknown") end ok, err = ngx_flush(true) if not ok then return nil, "failed to flush response header: " .. (err or "unknown") end local sock sock, err = req_sock(true) if not sock then return nil, err end local max_payload_len, send_masked, timeout local max_recv_len, max_send_len if opts then max_payload_len = opts.max_payload_len max_recv_len = opts.max_recv_len max_send_len = opts.max_send_len send_masked = opts.send_masked timeout = opts.timeout if timeout then sock:settimeout(timeout) end end max_payload_len = max_payload_len or 65535 max_recv_len = max_recv_len or max_payload_len max_send_len = max_send_len or max_payload_len return setmetatable({ sock = sock, max_recv_len = max_recv_len, max_send_len = max_send_len, send_masked = send_masked, }, mt) end function _M.set_timeout(self, time) local sock = self.sock if not sock then return nil, nil, "not initialized yet" end return sock:settimeout(time) end function _M.recv_frame(self) if self.fatal then return nil, nil, "fatal error already happened" end local sock = self.sock if not sock then return nil, nil, "not initialized yet" end local data, typ, err = _recv_frame(sock, self.max_recv_len, true) if not data and not str_find(err, ": timeout", 1, true) then self.fatal = true end return data, typ, err end local function send_frame(self, fin, opcode, payload) if self.fatal then return nil, "fatal error already happened" end local sock = self.sock if not sock then return nil, "not initialized yet" end local bytes, err = _send_frame(sock, fin, opcode, payload, self.max_send_len, self.send_masked) if not bytes then self.fatal = true end return bytes, err end _M.send_frame = send_frame function _M.send_continue(self, data) return send_frame(self, true, 0x0, data) end function _M.send_text(self, data) return send_frame(self, true, 0x1, data) end function _M.send_binary(self, data) return send_frame(self, true, 0x2, data) end function _M.send_close(self, code, msg) local payload if code then if type(code) ~= "number" or code > 0x7fff then return nil, "bad status code" end payload = char(band(rshift(code, 8), 0xff), band(code, 0xff)) .. (msg or "") end return send_frame(self, true, 0x8, payload) end function _M.send_ping(self, data) return send_frame(self, true, 0x9, data) end function _M.send_pong(self, data) return send_frame(self, true, 0xa, data) end return _M openresty-lua-resty-websocket-5400587/t/000077500000000000000000000000001475261236100201215ustar00rootroot00000000000000openresty-lua-resty-websocket-5400587/t/cert/000077500000000000000000000000001475261236100210565ustar00rootroot00000000000000openresty-lua-resty-websocket-5400587/t/cert/mtls_ca.crt000066400000000000000000000022401475261236100232100ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDPDCCAiQCE02SO/h/om49Gjo0vAbL7/G0E5cwDQYJKoZIhvcNAQELBQAwWjEL MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAoMCU9wZW5S ZXN0eTEiMCAGA1UEAwwZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAgFw0yMjAz MjIxMTUxNTJaGA8yMTIyMDIyNjExNTE1MlowWjELMAkGA1UEBhMCQVUxEzARBgNV BAgMClNvbWUtU3RhdGUxEjAQBgNVBAoMCU9wZW5SZXN0eTEiMCAGA1UEAwwZT3Bl blJlc3R5IFRlc3RpbmcgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKaitHvQzQf1/pqD9ybzu2c2x6cOfAer4mRBrVJb7ib3UJYz9TEOG9OH NbfEvTzv7svgW/s2HB/f3HLP9DYKRQe6aTuTS7OrxQqO8qE5aXNeG+KmhJANP0tD 6LsnubtnvKwIh+SDArEjjz5ZIyu/HWgh9Aajb95WCdvwThassJpiMgASukn41zWi ugqjv9EUM+mn73Klv9gggPQAJzjidqYABzU6NqUKZwPHWLut4fbLt66P335bZ2tI 529mrRnwRDbbhZ6AuQU3TCqUYeLCmK5Cxiw1zHOsXOr7BGY5UvNa0n6t6RfAtETm XIijMtNhOuCoqpczVe7jwKbAjcOQfa0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA GS96499Wn8Pyo5FOW3Z+4r5QQSr9f3g+gNY/5yQRdhs4NS3Seoe9fSTyyqaf0j0/ ctYWM08PkC5NIrtjBbpyT1TZDiCu6MbyTMjkpkfXwhLzNrVAEvgafdKwGe22eNeg CNCb4HglZS8sBPIFf39h2MPwXPAxpnSWUmszu8tul7wNr15ho52TGdOkL7u2GZVX 5tYGr+lK7gatOSAtRKsoxmPrIYe0ny3YGkpLtnzbF6Ejel+eopYi/vQApHsOTy0D ZV2PZ9Bn4YcrY1LZRRJqzCuXSfX5m0EUTIwpDMx+bv3iEeb5ItyLk5hRzYkRX81X vZ6a4jis7U92TLmcyyZYhg== -----END CERTIFICATE----- openresty-lua-resty-websocket-5400587/t/cert/mtls_ca.key000066400000000000000000000032501475261236100232120ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmorR70M0H9f6a g/cm87tnNsenDnwHq+JkQa1SW+4m91CWM/UxDhvThzW3xL087+7L4Fv7Nhwf39xy z/Q2CkUHumk7k0uzq8UKjvKhOWlzXhvipoSQDT9LQ+i7J7m7Z7ysCIfkgwKxI48+ WSMrvx1oIfQGo2/eVgnb8E4WrLCaYjIAErpJ+Nc1oroKo7/RFDPpp+9ypb/YIID0 ACc44namAAc1OjalCmcDx1i7reH2y7euj99+W2drSOdvZq0Z8EQ224WegLkFN0wq lGHiwpiuQsYsNcxzrFzq+wRmOVLzWtJ+rekXwLRE5lyIozLTYTrgqKqXM1Xu48Cm wI3DkH2tAgMBAAECggEAGLsUGz4pd9GACHGmeC77NL3SEs6ZBNBzSJrgvNTs+vaA jNJIRRAJfDLYe54k0crwP2zcaeOld+uS/a00WuLaTOPTI2bgeNl45HDDvL7XEiq4 68H38aMtrh91hnVGYPRr8YJQnM7+0shqxX+YMzFpjV9gpq2R+Eb/rpczF7Vofnjw A/MHyBOT8XIb2E4YiAjN7T3rPnDVNp27pZRIp02P3ZI4F7IQSLhEzY54eFQe23+7 cRjw8oFpHxGn4fGLISUri9z38U32Q7HCC8PvTy2zekx3Ifdrq0S/I7mAqXM+XeHZ o/fdJxiwvAPnUufFR79lX6zvUo2bKtkkJniDUpkMtwKBgQDXMbN96BF2IcDIsHPl fGnYA+e6OTF++cDt4Ge64oL8FaGY6/+aJ3X9NvPMNhf3WRqTomNkuGiHjSEkTfR/ BgQ3Z7x2v055+dAdLPUh/+flEcv5aPqZqBzYYNrhUC8jjte2zt5VN4SmlL6wCDWt A5UPnMGg5uExBScAIPu/8quCHwKBgQDGO8uq5YvWmFy3m9tD4g9cxyh2EStovptQ S3zH/nWBCP2Rx9YixFbZvjYujVWcuCC9D/5CwLpcyEa3NIRF4RByAgzB/AGABi2Q JlpAByYrbqtFMN17qBwpBrTwdgs+JD8cN8rPgSviZlL8xOIdX8Mw1HuCFtasBvUW 95Wrqb8+swKBgQCTaxjrR++uXbETys2aiIB52zMD/+pIchAY5YIqJMJWrvrlJ8cS c7YAoYSigOwqJoBuYvB0L2Bse+IYXM8Btb1tt0MElknMhbZsRkAn6oeSBX8WfTQv z1rzYGaRs7yXP2PHeDAXcNEOzRdUwEsFG08iQuDiuUfLrRvqmq3b8QJNQQKBgHaJ iRdPHhibkU3F6A6mnhMXkG1RhQikedFA4oPg+DjJvH8w5S5zA5A++r1JjHkjbYhA iQU3o/kZVZf10mbK13+lFCXnYKpCh3pcRLlmzP9JtSaxuq9X7kbmGMp1e/GT0R05 i5AbqLdAAr3dqWxxOBH57UT0DThfDK3ILPqyjYabAoGAXgtdrmgFOfywNRuq0Qox Eh+EYY4SnrZUFUFraVV7zZsRlJXTE8kxBGh73j0sX409Wbmy1CEoFw91f9FBIZzJ CjaF4Xod77FVnanL+rOUMHEdaYo2LzATRFZJzB/3D60hkHJjP3fCvY+Xln7Lt35B HDQslqp0wC9aeznXl+eMQYY= -----END PRIVATE KEY----- openresty-lua-resty-websocket-5400587/t/cert/mtls_client.crt000066400000000000000000000021531475261236100241060ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDFzCCAf8CFElxMXCkerhj2Kjjh+Hm3cucOlILMA0GCSqGSIb3DQEBCwUAMFox CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlPcGVu UmVzdHkxIjAgBgNVBAMMGU9wZW5SZXN0eSBUZXN0aW5nIFJvb3QgQ0EwHhcNMjIw MzIyMTIwMjU5WhcNMzIwMzE5MTIwMjU5WjA2MQswCQYDVQQGEwJBVTETMBEGA1UE CAwKU29tZS1TdGF0ZTESMBAGA1UECgwJT3BlblJlc3R5MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAyqq9ZO3Zx3nVly5ZHao5HecjhafNdHIM735y5sim WINjpqBr4b0hwdrvUBfNLVpf5qLXf8NDH9Rb7gS9/gs+bmVrqDVKsvYjBpbvA/v1 YdAk9PlmITxSRaYQyIu0EQAw5nZq9FMiAvGynEYKXir4vSqou4Av7FgAOBQQE3Mm G0XjAgFbTw2dQRH0M8f5a7Tu/BdfEkNRQb7n++m7JZoTIBfESUkhaN0DR33JSqdh ysrvH3KZq5DkVsX131kM6Y3lfWARdpFNANo0r3FSB31F46HttnjfNR5+GurA2wOE ymb7cDGpuWonjhT9ohJtN2fWDUTIf4LRuLYLjzmq6O5SnQIDAQABMA0GCSqGSIb3 DQEBCwUAA4IBAQAdEMkoOA1bovMjzp3HpKQcygpalSa+Ipyqe5UJy/UsRaqupxcq bDjfHkqcjcqtuDnxKMksxFFPPPcoXEwBzTcQExfPchqRkX9Fa+SRsLri5kLVGtBm DZTXqvbH51MQKDTs2CfKtZQn8WxzU2pQyd4ae3Qwc1S/I+/5HsX0xmv6BwMXzeqj VjO4vk6wnbgKMqMUEAsHjcWqmc6yBBmh2EN2X1wMfpuH8iJQWAv4QBPXPUGnV2Jh RoPDko/Fyx4yLv3T7BiHDJ2Sf0xtKtxP6eKMo8IGeGod0cueSRQ7w7hFSNd7+4SW 6QOdJ347xcyMyAwpCnqsmSxspLkBtfYOnvn8 -----END CERTIFICATE----- openresty-lua-resty-websocket-5400587/t/cert/mtls_client.key000066400000000000000000000032501475261236100241050ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKqr1k7dnHedWX Llkdqjkd5yOFp810cgzvfnLmyKZYg2OmoGvhvSHB2u9QF80tWl/motd/w0Mf1Fvu BL3+Cz5uZWuoNUqy9iMGlu8D+/Vh0CT0+WYhPFJFphDIi7QRADDmdmr0UyIC8bKc RgpeKvi9Kqi7gC/sWAA4FBATcyYbReMCAVtPDZ1BEfQzx/lrtO78F18SQ1FBvuf7 6bslmhMgF8RJSSFo3QNHfclKp2HKyu8fcpmrkORWxfXfWQzpjeV9YBF2kU0A2jSv cVIHfUXjoe22eN81Hn4a6sDbA4TKZvtwMam5aieOFP2iEm03Z9YNRMh/gtG4tguP Oaro7lKdAgMBAAECggEAKKMlyNgcg+/9EQxdGCKqw0E2kTU9cCzyRQ9w0K/JExR9 Zcri9ueqnildNQ0gughWFHPwjBDGI9q7+DUBN7Bfe1lgxeCxssLB8S9Qi9b4s/09 e9WKUf27bXXIBb5lg8crBvsVpRoKRtbZ/pXYvFsXdy7XmIkyksxudtAnDQ9Yw7zb R3tSeJScx267XObPunep5kvm27iCv2BQCGhRppIoZeh6VxEJIKKsyGoG12XrFyQZ DTQ3Eh3T9JwolAZu3fyV5l1QxSlCrg0uIchNFODmN9mqQwjjsYoz4nnv17r/tmJw nuz56M3P638IXTTEwDkr5AqylT9yUT50V2xIz5lGLQKBgQDbS+teT2T/Zi2Bd6XE q4WzXaC1VLzhSaGGceZjPGtGJLV7n4qCEJ2y1lN43L456AW5Ef8hIWwM9lE6UbPL makfEccztjZRk/8G93IcEX0vQZyxBlLgIkCb9sCZdhqQqwX4tfe/m9GhPXMT6lD0 TLD/7fCyMSgt9LpEN1rCb9XUrwKBgQDslkz28STIFslapN6xK6dTgOUtAsDkCg48 fd6Z4C+yi4HCpH81PPBUfgvDUfDSYetU7I/ZboWVJvwaPzb5pxnw489uDrUauaIx a71jGE6JXIixWKMC5zE7/nPxFmyPBzM175ezBw/K9cYhgbt5F6ORRbbOA1oBW767 tyjfeZ64cwKBgQC8F/4lwkuKlIVrishwS/49vozde3UWdyVIP+GwNF5+p3XSNyGC NeZNQnAONqgi2tQtzTXboOMgqxU4xGNGuuHIeGM4A43LovkXbJ4/XPDW25weaqIj BL4OCDNibV6Tv1072jhJ7Mh9WEugRVZydGVM3zWYYXlpEYPChwgdxfbOmQKBgBjr b+nm1n/43nacvRQeS/6gqgMGsjiS0pMOkv7UPVHqHd3Zo8iAxbOwnx6Qp/QQ+k+0 pyY43Psr4wwEso6zSik0ZanrBKpu+SWJeqZQbh1L0N4VPv5USbxO/flb6k1abct1 lB34VXKEVr06w/tqQQFRPYMPmVBhUILHNRfs4In/AoGAWRYRN1ktIQvdrWl9arNG J1a2MY3Ek1RTpBRx5lRg5JsjCgnyDQB6LtXgmir3n3c1dinA6Ct2dyg++K4N5ntn 2PEa6MXIWjvRvbcaLnS+21iGch4FWS/Xwyd7vj+4nU5VXKPeLjagM5uCm1PTOK3f zAKenQxYOMxVdosUPNB/MMI= -----END PRIVATE KEY----- openresty-lua-resty-websocket-5400587/t/cert/mtls_server.crt000066400000000000000000000022071475261236100241360ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDLDCCAhQCFACm5o1DAUE5rcxAm4J0zmlxjt0CMA0GCSqGSIb3DQEBCwUAMFox CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlPcGVu UmVzdHkxIjAgBgNVBAMMGU9wZW5SZXN0eSBUZXN0aW5nIFJvb3QgQ0EwIBcNMjIw MzIyMTIwMTMzWhgPMjEyMjAyMjYxMjAxMzNaMEkxCzAJBgNVBAYTAkFVMRMwEQYD VQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRl c3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuj3XwuffQXHa 9+BNlKuYC8itkl7ydQEe3JDm0/49twXSMO9/U0/wBaHLsLo4HS95HZ9Ed/jXzAph eJxn3MZ5spbDKJzqv0kqzLrhEtOW0GNLVoqnjC4Z7My/punI5v2wvqULgHmFgxAT oa0plOfAEZPpjIjwA6ottZmHYNMsT5fC1E3wq4hqDFOgu4INAt96VlOaBKF27XHt //omwpaueubfxmDwJ8Mh6AWxj0tdxNWwuxGURsBFarLPRaeIkTrCu7vMEPWLuSpC gBDmcHsOXEvpX0w1EExcawzd40xJ3hoCvdUaH9Jrz+f2DCZNKJgCt7svUvgygt4v gLuExRxYVwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCRqRbPStilYE3CVff9NEGR j+j0XV0xQoOEDHMgoemzR+MMysnlUSA0d+5LcHIVq9Iz8WvsIX/QlCvKTlwJWiF1 u0ZHDqgyfk5aNUTH1Hi2mMNg/0ssZcLmnHHYxBM65tBp1iNsV54isRzjko5tRoBZ e9x2/r/+8Pm9hk6nnPkTiPxeMkkKQAMk5mremGT7jFd3xO5sDkdZL7Ga8Kt70s1+ XROKySFEC+ngvP5YNWZ/zI43lUS0E4wo6DIKrHkQkv7noq4ewoiuuxoB1fmKXu+c WcxJaAF2O5pV0Y94KRTG+bT3afW7RMHnfkYf4VENMKABxZXgmmg12g3mtYei6rdR -----END CERTIFICATE----- openresty-lua-resty-websocket-5400587/t/cert/mtls_server.key000066400000000000000000000032501475261236100241350ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6PdfC599Bcdr3 4E2Uq5gLyK2SXvJ1AR7ckObT/j23BdIw739TT/AFocuwujgdL3kdn0R3+NfMCmF4 nGfcxnmylsMonOq/SSrMuuES05bQY0tWiqeMLhnszL+m6cjm/bC+pQuAeYWDEBOh rSmU58ARk+mMiPADqi21mYdg0yxPl8LUTfCriGoMU6C7gg0C33pWU5oEoXbtce3/ +ibClq565t/GYPAnwyHoBbGPS13E1bC7EZRGwEVqss9Fp4iROsK7u8wQ9Yu5KkKA EOZwew5cS+lfTDUQTFxrDN3jTEneGgK91Rof0mvP5/YMJk0omAK3uy9S+DKC3i+A u4TFHFhXAgMBAAECggEAE+5JWFDjKghKtCs7cjUY3O35cUga712S1WzmXvp+1UbY syb2O866s4eYmk2bcrghYIOqWqJ1SZ80xikKzmwpGu0abo64aockfuti6dZd9egi aF0HSC+o05gnzG+JcfrlPsm/3NxkZt3CFBPJdueEPP1UyZbgBKxiHuSSwdBnlg7L Zu64iXqO+juz9GppkwuakJa/3e6mk0el5B6JY+Gk8b0sPrd9z7FrXyq7DffaQ2ON 18I+r/dDyxVPV+0tAU+64YFtWjKzoIGhrPenOdk7s+DPiIuXnEuun65Q/w/hVWKy Wm64lstNoxU4RShxYGV3MznKgJ1XJyT9YzwqjqW20QKBgQDTa8lVIomHxSIlfMH+ lLRsoFoYIBYUwjcEy9jxh2llJHTPX0CKphpH/ByqwzYn+iVHrCfxYwSkWnN/KsGg Ix7b+BemhbRIUukjOU8QI5/p5LgrmmC1orpZ54o8cVl9K77I/hBhGhUZzHuzTLH9 ViPUhDrARNtXUKBV3Y+TmfhtpwKBgQDhgudculLDzq20sYOqb/NB+SlcowZDkLaN TXIhYKmGK8DaJeiojVmIOqOl8+P/j4cQg3m54KZ8T/4bQt2ynBwmYH4+2lUbpGf9 N6I9CEWmjX7ZARZYI4RvM1aDPrSbC6xb0W6nC4wQkjhck6ngNTHkHYdE+Q6vHy7P gAmVfBb10QKBgQCe8ATnD5O8kaJd9DASptAMaW/Rey2eZXLfFC//QwEknAeEbeMj WEOhohIa/a4U16R3ASD2Aq5Wr/jrvMTbEgv86cE92n3xcQL7C/Y399AcEWmyvde+ NJtLQxlU3xGbW+uNRhIiLW13e5Xy8NFN1hgRh2ZzbFBIj8A5TNrG55UvOQKBgQCM rI4K6CgNAXaWi02pGmDSvM0yfne/2hwmlTMm4xedHNoWuyMhUduSAZJoSXXmy+/j O0DJ1PvF/Fh1RQbrDjr5LaRTLPt+XNaJvRS1od1hAk8oq2b24GESxSGoiYs8VNHW DRVLmwZqp+wExBBqToSq2kixm/OvBnK6+hIAcAIaoQKBgG0kwGYFumhYNOO7qVjL AnfXbml94n7QGc8hWNs3aq6wKH0Oc3mSzMlsClnV0bVUnyF5fxTDwtZ4g1hRio4A +h321+H+7SxqrK/P5S9bhhyPMM0wByRU/Wa6pRQ6+NvFFY0fU3faVd3j2rcBEm41 6H6KpGxP868KXvVcot92emgZ -----END PRIVATE KEY----- openresty-lua-resty-websocket-5400587/t/cert/test.crt000066400000000000000000000017311475261236100225510ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICqTCCAhICCQClDm1WkreW4jANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMC VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x EjAQBgNVBAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQD DAh0ZXN0LmNvbTEgMB4GCSqGSIb3DQEJARYRYWdlbnR6aEBnbWFpbC5jb20wIBcN MTQwNzIxMDMyMzQ3WhgPMjE1MTA2MTMwMzIzNDdaMIGXMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAG A1UECgwJT3BlblJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRl c3QuY29tMSAwHgYJKoZIhvcNAQkBFhFhZ2VudHpoQGdtYWlsLmNvbTCBnzANBgkq hkiG9w0BAQEFAAOBjQAwgYkCgYEA6P18zUvtmaKQK2xePy8ZbFwSyTLw+jW6t9eZ aiTec8X3ibN9WemrxHzkTRikxP3cAQoITRuZiQvF4Q7DO6wMkz/b0zwfgX5uedGq 047AJP6n/mwlDOjGSNomBLoXQzo7tVe60ikEm3ZyDUqnJPJMt3hImO5XSop4MPMu Za9WhFcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQA4OBb9bOyWB1//93nSXX1mdENZ IQeyTK0Dd6My76lnZxnZ4hTWrvvd0b17KLDU6JnS2N5ee3ATVkojPidRLWLIhnh5 0eXrcKalbO2Ce6nShoFvQCQKXN2Txmq2vO/Mud2bHAWwJALg+qi1Iih/gVYB9sct FLg8zFOzRlYiU+6Mmw== -----END CERTIFICATE----- openresty-lua-resty-websocket-5400587/t/cert/test.key000066400000000000000000000015731475261236100225550ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDo/XzNS+2ZopArbF4/LxlsXBLJMvD6Nbq315lqJN5zxfeJs31Z 6avEfORNGKTE/dwBCghNG5mJC8XhDsM7rAyTP9vTPB+Bfm550arTjsAk/qf+bCUM 6MZI2iYEuhdDOju1V7rSKQSbdnINSqck8ky3eEiY7ldKingw8y5lr1aEVwIDAQAB AoGBANgB66sKMga2SKN5nQdHS3LDCkevCutu1OWM5ZcbB4Kej5kC57xsf+tzPtab emeIVGhCPOAALqB4YcT+QtMX967oM1MjcFbtH7si5oq6UYyp3i0G9Si6jIoVHz3+ 8yOUaqwKbK+bRX8VS0YsHZmBsPK5ryN50iUwsU08nemoA94BAkEA9GS9Q5OPeFkM tFxsIQ1f2FSsZAuN/1cpZgJqY+YaAN7MSPGTWyfd7nWG/Zgk3GO9/2ihh4gww+7B To09GkmW4QJBAPQOHC2V+t2TA98+6Lj6+TYwcGEkhOENfVpH25mQ+kXgF/1Bd6rA nosT1bdAY+SnmWXbSw6Kv5C20Em+bEX8WjcCQCSRRjhsRdVODbaW9Z7kb2jhEoJN sEt6cTlQNzcHYPCsZYisjM3g4zYg47fiIfHQAsfKkhDDcfh/KvFj9LaQOEECQQCH eBWYEDpSJ7rsfqT7mQQgWj7nDThdG/nK1TxGP71McBmg0Gg2dfkLRhVJRQqt74Is kc9V4Rp4n6F6baL4Lh19AkEA6pZZer0kg3Kv9hjhaITIKUYdfIp9vYnDRWbQlBmR atV8V9u9q2ETZvqfHpN+9Lu6NYR4yXIEIRf1bnIZ/mr9eQ== -----END RSA PRIVATE KEY----- openresty-lua-resty-websocket-5400587/t/count.t000066400000000000000000000033511475261236100214400ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et: use Test::Nginx::Socket::Lua; use Cwd qw(cwd); use Protocol::WebSocket::Frame; repeat_each(2); plan tests => repeat_each() * (blocks() * 3); my $pwd = cwd(); our $HttpConfig = qq{ lua_package_path "$pwd/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_REDIS_PORT} ||= 6379; no_long_string(); #no_diff(); run_tests(); __DATA__ === TEST 1: module size of resty.websocket.protocol --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local proto = require "resty.websocket.protocol" n = 0 for _, _ in pairs(proto) do n = n + 1 end ngx.say("size: ", n) '; } --- request GET /t --- response_body size: 5 --- no_error_log [error] === TEST 2: module size of resty.websocket.client --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local client = require "resty.websocket.client" n = 0 for _, _ in pairs(client) do n = n + 1 end ngx.say("size: ", n) '; } --- request GET /t --- response_body size: 13 --- no_error_log [error] === TEST 3: module size of resty.websocket.server --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local server = require "resty.websocket.server" n = 0 for _, _ in pairs(server) do n = n + 1 end ngx.say("size: ", n) '; } --- request GET /t --- response_body size: 11 --- no_error_log [error] openresty-lua-resty-websocket-5400587/t/cs.t000066400000000000000000002224461475261236100207250ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et: use Test::Nginx::Socket::Lua; use Cwd qw(cwd); use Protocol::WebSocket::Frame; repeat_each(2); plan tests => repeat_each() * (blocks() * 4 + 1); my $pwd = cwd(); our $HttpConfig = qq{ lua_package_path "$pwd/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_REDIS_PORT} ||= 6379; check_accum_error_log(); no_long_string(); #no_diff(); sub read_file { my $infile = shift; open my $in, $infile or die "cannot open $infile for reading: $!"; my $cert = do { local $/; <$in> }; close $in; $cert; } run_tests(); __DATA__ === TEST 1: text frame --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end ngx.say("1: received: ", data, " (", typ, ")") local bytes, err = wb:send_text("copy: " .. data) if not bytes then ngx.say("failed to send frame: ", err) return end data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("2: received: ", data, " (", typ, ")") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local bytes, err = wb:send_text("你好, WebSocket!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end '; } --- request GET /c --- response_body 1: received: 你好, WebSocket! (text) 2: received: copy: 你好, WebSocket! (text) --- no_error_log [error] [warn] --- error_log recv_frame: mask bit: 0 recv_frame: mask bit: 1 === TEST 2: binary frame --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end ngx.say("1: received: ", data, " (", typ, ")") local bytes, err = wb:send_binary("copy: " .. data) if not bytes then ngx.say("failed to send frame: ", err) return end data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("2: received: ", data, " (", typ, ")") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local bytes, err = wb:send_binary("你好, WebSocket!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! bytes, err = wb:send_binary(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end '; } --- request GET /c --- response_body 1: received: 你好, WebSocket! (binary) 2: received: copy: 你好, WebSocket! (binary) --- no_error_log [error] [warn] === TEST 3: close frame (without msg body) --- http_config eval: $::HttpConfig --- config lingering_close always; location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local bytes, err = wb:send_close() if not bytes then ngx.say("failed to send frame: ", err) return end wb:recv_frame() -- receive the close frame '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_close() if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) wb:send_close() '; } --- request GET /c --- response_body received close: : nil --- error_log received: close: : nil --- no_error_log [error] === TEST 4: close frame (with msg body) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local bytes, err = wb:send_close(1000, "server, let\'s close!") if not bytes then ngx.say("failed to send frame: ", err) return end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_close(1001, "client, let\'s close!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) '; } --- request GET /c --- response_body received close: client, let's close!: 1001 --- error_log received: close: server, let's close!: 1000 --- no_error_log [error] === TEST 5: ping frame (without msg body) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local bytes, err = wb:send_ping() if not bytes then ngx.say("failed to send frame: ", err) return end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_ping() if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) '; } --- request GET /c --- response_body received ping: : nil --- error_log received: ping: : nil --- no_error_log [error] === TEST 6: ping frame (with msg body) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local bytes, err = wb:send_ping("hey, server?") if not bytes then ngx.say("failed to send frame: ", err) return end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_ping("hey, client?") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) '; } --- request GET /c --- response_body received ping: hey, client?: nil --- error_log received: ping: hey, server?: nil --- no_error_log [error] === TEST 7: pong frame (without msg body) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local bytes, err = wb:send_pong() if not bytes then ngx.say("failed to send frame: ", err) return end wb:recv_frame() -- receive the close frame '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_pong() if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) wb:send_close() '; } --- request GET /c --- response_body received pong: : nil --- error_log received: pong: : nil --- no_error_log [error] === TEST 8: pong frame (with msg body) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local bytes, err = wb:send_pong("halo, server!") if not bytes then ngx.say("failed to send frame: ", err) return end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_pong("halo, client!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) '; } --- request GET /c --- response_body received pong: halo, client!: nil --- error_log received: pong: halo, server!: nil --- no_error_log [error] === TEST 9: client recv timeout (set_timeout) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end wb:set_timeout(1) local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) else ngx.say("1: received: ", data, " (", typ, ")") end wb:set_timeout(1000) data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) else ngx.say("2: received: ", data, " (", typ, ")") end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.sleep(0.2) local bytes, err = wb:send_text("你好, WebSocket!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end '; } --- request GET /c --- response_body failed to receive 1st frame: failed to receive the first 2 bytes: timeout 2: received: 你好, WebSocket! (text) --- error_log lua tcp socket read timed out --- no_error_log [warn] === TEST 10: client recv timeout (timeout option) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new{ timeout = 100 } local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) else ngx.say("1: received: ", data, " (", typ, ")") end wb:set_timeout(1000) data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) else ngx.say("2: received: ", data, " (", typ, ")") end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.sleep(0.2) local bytes, err = wb:send_text("你好, WebSocket!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end '; } --- request GET /c --- response_body failed to receive 1st frame: failed to receive the first 2 bytes: timeout 2: received: 你好, WebSocket! (text) --- error_log lua tcp socket read timed out --- no_error_log [warn] === TEST 11: server recv timeout (set_timeout) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end ngx.sleep(0.2) local bytes, err = wb:send_text("你好, WebSocket!") if not bytes then ngx.say("failed to send the 1st text: ", err) return ngx.exit(444) end ngx.say("ok") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end wb:set_timeout(1) local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive 1st frame: ", err) else ngx.log(ngx.WARN, "1: received: ", data, " (", typ, ")") end wb:set_timeout(1000) data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive 2nd frame: ", err) else ngx.log(ngx.WARN, "2: received: ", data, " (", typ, ")") end '; } --- request GET /c --- response_body ok --- error_log failed to receive 1st frame: failed to receive the first 2 bytes: timeout 2: received: 你好, WebSocket! (text) lua tcp socket read timed out === TEST 12: server recv timeout (in constructor) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end ngx.sleep(0.2) local bytes, err = wb:send_text("你好, WebSocket!") if not bytes then ngx.say("failed to send the 1st text: ", err) return ngx.exit(444) end ngx.say("ok") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new{ timeout = 1 } 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 ngx.log(ngx.ERR, "failed to receive 1st frame: ", err) else ngx.log(ngx.WARN, "1: received: ", data, " (", typ, ")") end wb:set_timeout(1000) data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive 2nd frame: ", err) else ngx.log(ngx.WARN, "2: received: ", data, " (", typ, ")") end '; } --- request GET /c --- response_body ok --- error_log failed to receive 1st frame: failed to receive the first 2 bytes: timeout 2: received: 你好, WebSocket! (text) lua tcp socket read timed out --- timeout: 6 === TEST 13: reused upstream websocket connections (set_keepalive) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local connect_opts = { -- choose a unique keepalive pool name to ensure our first -- connection is not reused pool = ngx.var.request_id, } for i = 1, 3 do local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err, res = wb:connect(uri, connect_opts) if not ok then ngx.say("failed to connect: " .. err) return end if res == "connection reused" then ngx.say(res) else ngx.say("new connection") end local data = "hello " .. i local bytes, err = wb:send_text(data) if not bytes then ngx.say("failed to send frame: ", err) return end local typ data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("received: ", data, " (", typ, ")") local ok, err = wb:set_keepalive() if not ok then ngx.say("failed to recycle conn: ", err) return end end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end while true do local data, typ, err = wb:recv_frame() if not data then -- ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end end '; } --- request GET /c --- response_body new connection received: hello 1 (text) connection reused received: hello 2 (text) connection reused received: hello 3 (text) --- no_error_log [error] [warn] --- error_log recv_frame: mask bit: 0 recv_frame: mask bit: 1 === TEST 14: pool option --- http_config eval: $::HttpConfig --- config lua_socket_log_errors off; location = /c2 { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s2" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri, { pool = "my_conn_pool" }) if not ok then ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end end local data, typ, err = wb:send_text("hello websocket") if not data then ngx.say("failed to receive 2nd frame: ", err) return end data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("received: ", data, " (", typ, ")") local ok, err = wb:set_keepalive() if not ok then ngx.say("failed to set keepalive: ", err) return end '; } location = /s2 { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end while true do local data, err = wb:recv_frame() if not data then -- ngx.log(ngx.ERR, "failed to recv text: ", err) return ngx.exit(444) end local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end end '; } --- request GET /c2 --- response_body received: hello websocket (text) --- stap F(ngx_http_lua_socket_tcp_setkeepalive) { println("socket tcp set keepalive") } --- stap_out socket tcp set keepalive --- error_log lua tcp socket keepalive create connection pool for key "my_conn_pool" --- no_error_log [error] [warn] === TEST 15: text frame (send masked frames on the server side) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end ngx.say("1: received: ", data, " (", typ, ")") local bytes, err = wb:send_text("copy: " .. data) if not bytes then ngx.say("failed to send frame: ", err) return end data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("2: received: ", data, " (", typ, ")") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new{ send_masked = true } if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local bytes, err = wb:send_text("你好, WebSocket!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end ngx.sleep(0.001) -- lingering close '; } --- request GET /c --- response_body 1: received: 你好, WebSocket! (text) 2: received: copy: 你好, WebSocket! (text) --- no_error_log [error] [warn] recv_frame: mask bit: 0 --- error_log recv_frame: mask bit: 1 --- timeout: 6 === TEST 16: text frame (send unmasked frames on the client side) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new{ send_unmasked = true } local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end ngx.say("1: received: ", data, " (", typ, ")") local bytes, err = wb:send_text("copy: " .. data) if not bytes then ngx.say("failed to send frame: ", err) return end data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("2: received: ", data, " (", typ, ")") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local bytes, err = wb:send_text("你好, WebSocket!") if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end ngx.sleep(0.001) -- lingering close '; } --- request GET /c --- response_body_like eval qr/^1: received: 你好, WebSocket! \(text\) (?:failed to receive 2nd frame: failed to receive the first 2 bytes: (?:closed|connection reset by peer) |failed to send frame: failed to send frame: broken pipe)$/ --- no_error_log [warn] --- error_log recv_frame: mask bit: 0 failed to receive a frame: frame unmasked === TEST 17: close frame (without msg body) + close() --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local bytes, err = wb:send_close() if not bytes then ngx.say("failed to send frame: ", err) return end local ok, err = wb:close() if not ok then ngx.say("failed to close: ", err) return end ngx.say("successfully closed the TCP connection") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_close() if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) '; } --- request GET /c --- response_body received close: : nil successfully closed the TCP connection --- error_log received: close: : nil sending the close frame --- no_error_log [error] === TEST 18: directly calling close() without sending the close frame ourselves --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end -- print("c: receiving frame") local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 1st frame: ", err) return end -- print("c: received frame") ngx.say("received ", typ, ": ", data, ": ", err) local ok, err = wb:close() if not ok then ngx.say("failed to close: ", err) return end ngx.say("successfully closed the TCP connection") '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end -- print("s: sending close") local bytes, err = wb:send_close() if not bytes then ngx.log(ngx.ERR, "failed to send the 1st text: ", err) return ngx.exit(444) end -- print("s: sent close") local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, "received: ", typ, ": ", data, ": ", err) '; } --- request GET /c --- response_body received close: : nil successfully closed the TCP connection --- error_log received: close: : nil sending the close frame --- no_error_log [error] === TEST 19: client handshake (scalar protocols) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" math.randomseed(0) local wb, err = client:new() local uri = "ws://127.0.0.1:7986/" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri, { protocols = "json" }) if not ok then ngx.say("failed to connect: " .. err) return end '; } --- request GET /c --- tcp_listen: 7986 --- tcp_query eval "GET / HTTP/1.1\r Upgrade: websocket\r Host: 127.0.0.1:7986\r Sec-WebSocket-Key: y7KXwBSpVrxtkR0O+bQt+Q==\r Sec-WebSocket-Protocol: json\r Sec-WebSocket-Version: 13\r Connection: Upgrade\r \r " --- tcp_reply: blah --- response_body failed to connect: failed to receive response header: closed --- no_error_log [error] [warn] === TEST 20: client handshake (table protocols) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" math.randomseed(0) local wb, err = client:new() local uri = "ws://127.0.0.1:7986/" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri, { protocols = {"xml", "json"} }) if not ok then ngx.say("failed to connect: " .. err) return end '; } --- request GET /c --- tcp_listen: 7986 --- tcp_query eval "GET / HTTP/1.1\r Upgrade: websocket\r Host: 127.0.0.1:7986\r Sec-WebSocket-Key: y7KXwBSpVrxtkR0O+bQt+Q==\r Sec-WebSocket-Protocol: xml,json\r Sec-WebSocket-Version: 13\r Connection: Upgrade\r \r " --- tcp_reply: blah --- response_body failed to connect: failed to receive response header: closed --- no_error_log [error] [warn] === TEST 21: client handshake (origin) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua ' local client = require "resty.websocket.client" math.randomseed(0) local wb, err = client:new() local uri = "ws://127.0.0.1:7986/" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri, { origin = "test.com" }) if not ok then ngx.say("failed to connect: " .. err) return end '; } --- request GET /c --- tcp_listen: 7986 --- tcp_query eval "GET / HTTP/1.1\r Upgrade: websocket\r Host: 127.0.0.1:7986\r Sec-WebSocket-Key: y7KXwBSpVrxtkR0O+bQt+Q==\r Sec-WebSocket-Version: 13\r Origin: test.com\r Connection: Upgrade\r \r " --- tcp_reply: blah --- response_body failed to connect: failed to receive response header: closed --- no_error_log [error] [warn] === TEST 22: SSL with keepalive --- no_check_leak --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() for i = 1, 3 do local uri = "wss://127.0.0.1:12345/s" local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data = "hello " .. i local bytes, err = wb:send_text(data) if not bytes then ngx.say("failed to send frame: ", err) return end local typ data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("received: ", data, " (", typ, ")") local ok, err = wb:set_keepalive() if not ok then ngx.say("failed to recycle conn: ", err) return end end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end while true do local data, typ, err = wb:recv_frame() if not data then -- ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end end '; } --- request GET /c --- response_body received: hello 1 (text) received: hello 2 (text) received: hello 3 (text) --- no_error_log [error] [warn] --- timeout: 10 === TEST 23: SSL without keepalive --- no_check_leak --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://127.0.0.1:12345/s" local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data = "hello" local bytes, err = wb:send_text(data) if not bytes then ngx.say("failed to send frame: ", err) return end local typ data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("received: ", data, " (", typ, ")") local ok, err = wb:close() if not ok then ngx.say("failed to close conn: ", err) return end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() 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 -- ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end '; } --- request GET /c --- response_body received: hello (text) --- no_error_log [error] [warn] --- timeout: 10 === TEST 24: SSL with ssl_verify --- no_check_leak --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; resolver 127.0.0.1:1953 ipv6=off; resolver_timeout 1s; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 1; location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://test.com:12345/s" local ok, err = wb:connect(uri, {ssl_verify = true}) if not ok then ngx.say("failed to connect: " .. err) return end local data = "hello" local bytes, err = wb:send_text(data) if not bytes then ngx.say("failed to send frame: ", err) return end local typ data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("received: ", data, " (", typ, ")") local ok, err = wb:close() if not ok then ngx.say("failed to close conn: ", err) return end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() 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 -- ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end '; } --- udp_listen: 1953 --- udp_reply eval sub { # Get DNS request ID from passed UDP datagram my $dns_id = unpack("n", shift); # Set name and encode it my $name = "test.com"; $name =~ s/([^.]+)\.?/chr(length($1)) . $1/ge; $name .= "\0"; my $s = ''; $s .= pack("n", $dns_id); # DNS response flags, hardcoded my $flags = (1 << 15) + (0 << 11) + (0 << 10) + (0 << 9) + (1 << 8) + (1 << 7) + 0; $flags = pack("n", $flags); $s .= $flags; $s .= pack("nnnn", 1, 1, 0, 0); $s .= $name; $s .= pack("nn", 1, 1); # Set response address and pack it my @addr = split /\./, "127.0.0.1"; my $data = pack("CCCC", @addr); $s .= $name. pack("nnNn", 1, 1, 1, 4) . $data; return $s; } --- request GET /c --- response_body received: hello (text) --- no_error_log [error] [warn] --- timeout: 10 === TEST 25: SSL with ssl_verify (handshake failed) --- no_check_leak --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; resolver 127.0.0.1:1953 ipv6=off; resolver_timeout 1s; location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://test.com:12345/s" local ok, err = wb:connect(uri, {ssl_verify = true}) if not ok then ngx.say("failed to connect: " .. err) return end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end '; } --- udp_listen: 1953 --- udp_reply eval sub { # Get DNS request ID from passed UDP datagram my $dns_id = unpack("n", shift); # Set name and encode it my $name = "test.com"; $name =~ s/([^.]+)\.?/chr(length($1)) . $1/ge; $name .= "\0"; my $s = ''; $s .= pack("n", $dns_id); # DNS response flags, hardcoded my $flags = (1 << 15) + (0 << 11) + (0 << 10) + (0 << 9) + (1 << 8) + (1 << 7) + 0; $flags = pack("n", $flags); $s .= $flags; $s .= pack("nnnn", 1, 1, 0, 0); $s .= $name; $s .= pack("nn", 1, 1); # Set response address and pack it my @addr = split /\./, "127.0.0.1"; my $data = pack("CCCC", @addr); $s .= $name. pack("nnNn", 1, 1, 1, 4) . $data; return $s; } --- request GET /c --- error_log lua ssl certificate verify error: (18: self signed certificate) --- timeout: 10 === TEST 26: SSL without ssl_verify --- no_check_leak --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /c { content_by_lua ' local client = require "resty.websocket.client" local wb, err = client:new() for i = 1, 3 do local uri = "wss://127.0.0.1:12345/s" local ok, err = wb:connect(uri, {ssl_verify = false}) if not ok then ngx.say("failed to connect: " .. err) return end local data = "hello " .. i local bytes, err = wb:send_text(data) if not bytes then ngx.say("failed to send frame: ", err) return end local typ data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("received: ", data, " (", typ, ")") local ok, err = wb:set_keepalive() if not ok then ngx.say("failed to close conn: ", err) return end end '; } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end while true do local data, typ, err = wb:recv_frame() if not data then -- ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end end '; } --- request GET /c --- response_body received: hello 1 (text) received: hello 2 (text) received: hello 3 (text) --- no_error_log [error] [warn] --- timeout: 10 === TEST 27: handhake with custom headers --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local headers = { "a-header: a header value", "another-header: another header value", "yet-another-header: yet another header value" } local ok, err = wb:connect(uri, {headers = headers}) if not ok then ngx.say("failed to connect: " .. err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end for k, v in pairs(ngx.req.get_headers()) do print(string.format("%s = %s", k, v)) end } } --- request GET /c --- error_log a-header = a header value another-header = another header value yet-another-header = yet another header value === TEST 28: send invalid close status code --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive: ", err) return end ngx.say("received ", typ, ": ", data, ": ", err) } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local bytes, err = wb:send_close(0xf000, "client, let\'s close!") if not bytes then ngx.log(ngx.ERR, "failed to send close: ", err) return ngx.exit(444) end } } --- request GET /c --- response_body failed to receive: failed to receive the first 2 bytes: closed --- error_log failed to send close: bad status code === TEST 29: mutual TLS with client certs --- no_check_leak --- http_config eval: $::HttpConfig --- config listen $TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate ../../cert/mtls_server.crt; ssl_certificate_key ../../cert/mtls_server.key; ssl_client_certificate ../../cert/mtls_ca.crt; ssl_verify_client on; server_tokens off; resolver 127.0.0.1:1953 ipv6=off; resolver_timeout 1s; lua_ssl_trusted_certificate ../../cert/mtls_ca.crt; lua_ssl_verify_depth 2; location = /c { content_by_lua_block { local ssl = require "ngx.ssl" local f = assert(io.open('t/cert/mtls_client.crt')) local cert_data = f:read("*a") f:close() f = assert(io.open('t/cert/mtls_client.key')) local key_data = f:read("*a") f:close() local chain = assert(ssl.parse_pem_cert(cert_data)) local priv = assert(ssl.parse_pem_priv_key(key_data)) local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://test.com:$TEST_NGINX_RAND_PORT_1/s" local ok, err = wb:connect(uri, {ssl_verify = true, client_cert = chain, client_priv_key = priv}) if not ok then ngx.say("failed to connect: " .. err) return end local data = "hello" local bytes, err = wb:send_text(data) if not bytes then ngx.say("failed to send frame: ", err) return end local typ data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive 2nd frame: ", err) return end ngx.say("received: ", data, " (", typ, ")") local ok, err = wb:close() if not ok then ngx.say("failed to close conn: ", err) return end } } location = /s { content_by_lua ' local server = require "resty.websocket.server" local wb, err = server:new() 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 -- ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end -- send it back! local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send the 2nd text: ", err) return ngx.exit(444) end '; } --- udp_listen: 1953 --- udp_reply eval sub { # Get DNS request ID from passed UDP datagram my $dns_id = unpack("n", shift); # Set name and encode it my $name = "test.com"; $name =~ s/([^.]+)\.?/chr(length($1)) . $1/ge; $name .= "\0"; my $s = ''; $s .= pack("n", $dns_id); # DNS response flags, hardcoded my $flags = (1 << 15) + (0 << 11) + (0 << 10) + (0 << 9) + (1 << 8) + (1 << 7) + 0; $flags = pack("n", $flags); $s .= $flags; $s .= pack("nnnn", 1, 1, 0, 0); $s .= $name; $s .= pack("nn", 1, 1); # Set response address and pack it my @addr = split /\./, "127.0.0.1"; my $data = pack("CCCC", @addr); $s .= $name. pack("nnNn", 1, 1, 1, 4) . $data; return $s; } --- request GET /c --- response_body received: hello (text) --- no_error_log [error] [warn] --- timeout: 10 === TEST 30: handshake with default host header --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "host: <", ngx.var.http_host, ">") } } --- request GET /c --- error_log eval qr/host: <127.0.0.1:\d+>/ === TEST 31: handshake with custom host header (without port number) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local ok, err = wb:connect(uri, { host = "client.test" }) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "host: <", ngx.var.http_host, ">") } } --- request GET /c --- error_log host: === TEST 32: handshake with custom host header (with port number) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local ok, err = wb:connect(uri, { host = "client.test:8080" }) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "host: <", ngx.var.http_host, ">") } } --- request GET /c --- error_log host: === TEST 33: SNI derived from custom host header (without port number) --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://127.0.0.1:12345/s" local opts = { host = "test.com", ssl_verify = false, } local ok, err = wb:connect(uri, opts) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "host: <", ngx.var.http_host, ">") ngx.log(ngx.INFO, "SSL server name: <", ngx.var.ssl_server_name, ">") } } --- request GET /c --- error_log host: SSL server name: === TEST 34: SNI derived from custom host header (with port number) --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://127.0.0.1:12345/s" local opts = { host = "test.com:8443", ssl_verify = false, } local ok, err = wb:connect(uri, opts) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "host: <", ngx.var.http_host, ">") ngx.log(ngx.INFO, "SSL server name: <", ngx.var.ssl_server_name, ">") } } --- request GET /c --- error_log host: SSL server name: === TEST 35: custom SNI --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com client.test; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://127.0.0.1:12345/s" local opts = { server_name = "test.com", ssl_verify = false, } local ok, err = wb:connect(uri, opts) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "host: <", ngx.var.http_host, ">") ngx.log(ngx.INFO, "SSL server name: <", ngx.var.ssl_server_name, ">") } } --- request GET /c --- error_log eval [ qr/host: <127.0.0.1:\d+>/, "SSL server name: ", ] === TEST 36: custom SNI and host --- http_config eval: $::HttpConfig --- config listen 12345 ssl; server_name test.com client.test; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "wss://127.0.0.1:12345/s" local opts = { host = "client.test", server_name = "test.com", ssl_verify = false, } local ok, err = wb:connect(uri, opts) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "host: <", ngx.var.http_host, ">") ngx.log(ngx.INFO, "SSL server name: <", ngx.var.ssl_server_name, ">") } } --- request GET /c --- error_log host: SSL server name: === TEST 37: overriding the Sec-WebSocket-Key header --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local opts = { key = "y7KXwBSpVrxtkR0O+bQt+Q==", } local ok, err = wb:connect(uri, opts) if not ok then ngx.say("failed to connect: ", err) return end } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "key: ", ngx.var.http_sec_websocket_key) } } --- request GET /c --- error_log key: y7KXwBSpVrxtkR0O+bQt+Q== === TEST 38: server handshake response string --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local ok, err, res = wb:connect(uri) if not ok then ngx.say("failed to connect: ", err) return end if not res then ngx.say("no response string") return end ngx.say(res) } } location = /s { content_by_lua_block { ngx.header["X-My-Custom-Header"] = "test" local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end } } --- request GET /c --- response_body_like ^HTTP\/1\.1 101 Switching Protocols.*X-My-Custom-Header: test.* --- no_error_log [error] [warn] === TEST 39: server handshake response string (reused connection) --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" local connect_opts = { -- choose a unique keepalive pool name to ensure our first -- connection is not reused pool = ngx.var.request_id, } local ok, err, res = wb:connect(uri, connect_opts) if not ok then ngx.say("failed to connect: ", err) return end if not res then ngx.say("no response string") return end if not res:match("^HTTP/1%.1 101 Switching Protocols\r\n") then ngx.say("invalid response string") return end ok, err = wb:send_text("first connection") if not ok then ngx.say("failed to send message: ", err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive message: ", err) return end ngx.say("received ", typ, " frame: ", data) ok, err = wb:set_keepalive() if not ok then ngx.say("failed to enable keepalive: ", err) return end wb = client:new() ok, err, res = wb:connect(uri, connect_opts) if not ok then ngx.say("second connect failed: ", err) return end if res ~= "connection reused" then ngx.say("expected 'connection reused' response string") return end ok, err = wb:send_text("reused connection") if not ok then ngx.say("failed to send message: ", err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive message: ", err) return end ngx.say("received ", typ, " frame: ", data) } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end while true do local data, typ, err = wb:recv_frame() if not data then return ngx.exit(444) end -- send it back! local bytes, err = wb:send_text(data) if not bytes then ngx.log(ngx.ERR, "failed to send text frame: ", err) return ngx.exit(444) end end } } --- request GET /c --- response_body received text frame: first connection received text frame: reused connection --- no_error_log [error] [warn] openresty-lua-resty-websocket-5400587/t/limits.t000066400000000000000000000270061475261236100216140ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et: use Test::Nginx::Socket::Lua; use Cwd qw(cwd); use Protocol::WebSocket::Frame; repeat_each(2); plan tests => repeat_each() * (blocks() * 7); my $pwd = cwd(); our $HttpConfig = qq{ lua_package_path "$pwd/lib/?.lua;;"; lua_package_cpath "/usr/local/openresty-debug/lualib/?.so;/usr/local/openresty/lualib/?.so;;"; }; check_accum_error_log(); no_long_string(); run_tests(); __DATA__ === TEST 1: client max_send_len --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new({ max_send_len = 200, }) local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local frame = string.rep("1", 200) local sent, err = wb:send_text(frame) if not sent then ngx.say("failed to send 1st frame: ", err) return end ngx.say("1: sent a frame of len ", #frame) local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive frame: ", err) return end ngx.say("2: received ", typ, " frame of len ", #data) frame = string.rep("1", 201) sent, err = wb:send_text(frame) if sent then ngx.say("expected sending 2nd frame to fail") return end ngx.say("3: failed sending a frame of len ", #frame, ": ", err) } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() 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 ngx.log(ngx.ERR, "failed receiving frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "1: received ", typ, " frame of len ", #data) local sent, err = wb:send_text(data) if not sent then ngx.log(ngx.ERR, "failed sending frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "2: sent ", typ, " frame of len ", #data) } } --- request GET /c --- response_body 1: sent a frame of len 200 2: received text frame of len 200 3: failed sending a frame of len 201: payload too big --- no_error_log [error] [warn] --- error_log 1: received text frame of len 200 2: sent text frame of len 200 === TEST 2: client max_recv_len --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new({ max_recv_len = 200, }) local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local frame = string.rep("1", 200) local sent, err = wb:send_text(frame) if not sent then ngx.say("failed to send 1st frame: ", err) return end ngx.say("1: sent a frame of len ", #frame) local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive frame: ", err) return end ngx.say("2: received ", typ, " frame of len ", #data) frame = string.rep("1", 201) sent, err = wb:send_text(frame) if not sent then ngx.say("failed to send 2nd frame: ", err) return end ngx.say("3: sent a frame of len ", #frame) local data, typ, err = wb:recv_frame() if data then ngx.say("expected receiving 2nd frame to fail") return elseif err ~= "exceeding max payload len" then ngx.say("unexpected error from recv_frame: ", err) return end ngx.say("4: failed receiving frame: ", err) } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new() 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 ngx.log(ngx.ERR, "failed receiving frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "1: received ", typ, " frame of len ", #data) local sent, err = wb:send_text(data) if not sent then ngx.log(ngx.ERR, "failed receiving frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "2: sent frame of len ", #data) data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed receiving frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "3: received ", typ, " frame of len ", #data) sent, err = wb:send_text(data) if not sent then ngx.log(ngx.ERR, "failed receiving frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "4: sent frame of len ", #data) } } --- request GET /c --- response_body 1: sent a frame of len 200 2: received text frame of len 200 3: sent a frame of len 201 4: failed receiving frame: exceeding max payload len --- no_error_log [error] [warn] --- error_log 1: received text frame of len 200 2: sent frame of len 200 3: received text frame of len 201 4: sent frame of len 201 === TEST 3: server max_send_len --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive frame: ", err) return end ngx.say("1: received ", typ, " frame of len ", #data) local frame = string.rep("1", 300) local sent, err = wb:send_text(frame) if not sent then ngx.say("failed sending frame: ", err) return end ngx.say("2: sent a text frame of len ", #frame) --wb:recv_frame() } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new({ max_send_len = 200, }) if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local frame = string.rep("1", 200) local sent, err = wb:send_text(frame) if not sent then ngx.log(ngx.ERR, "failed sending 1st frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "1: sent frame of len ", #frame) local data, typ, err = wb:recv_frame() if not data then ngx.log(ngx.ERR, "failed receiving frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "2: received ", typ, " frame of len ", #data) sent, err = wb:send_text(data) if sent then ngx.log(ngx.ERR, "expected sending 2nd frame to fail") return ngx.exit(444) end ngx.log(ngx.INFO, "3: failed sending frame of len ", #data, ": ", err) } } --- request GET /c --- response_body 1: received text frame of len 200 2: sent a text frame of len 300 --- no_error_log [error] [warn] --- error_log 1: sent frame of len 200 2: received text frame of len 300 3: failed sending frame of len 300: payload too big === TEST 4: server max_recv_len --- http_config eval: $::HttpConfig --- config location = /c { content_by_lua_block { local client = require "resty.websocket.client" local wb, err = client:new() local uri = "ws://127.0.0.1:" .. ngx.var.server_port .. "/s" -- ngx.say("uri: ", uri) local ok, err = wb:connect(uri) if not ok then ngx.say("failed to connect: " .. err) return end local frame = string.rep("1", 200) local sent, err = wb:send_text(frame) if not sent then ngx.say("failed sending frame: ", err) return end ngx.say("1: sent text frame of len ", #frame) local data, typ, err = wb:recv_frame() if not data then ngx.say("failed to receive frame: ", err) return end ngx.say("2: received ", typ, " frame of len ", #data) frame = string.rep("1", 300) sent, err = wb:send_text(frame) if not sent then ngx.say("failed sending frame: ", err) return end ngx.say("3: sent text frame of len ", #frame) } } location = /s { content_by_lua_block { local server = require "resty.websocket.server" local wb, err = server:new({ max_recv_len = 200, }) 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 ngx.log(ngx.ERR, "failed receiving frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "1: received ", typ, " frame of len ", #data) local sent, err = wb:send_text(data .. data) if not sent then ngx.log(ngx.ERR, "failed sending frame: ", err) return ngx.exit(444) end ngx.log(ngx.INFO, "2: sent ", typ, " frame of len ", #data * 2) local data, typ, err = wb:recv_frame() if data then ngx.log(ngx.ERR, "expected recv to fail") return ngx.exit(444) end ngx.log(ngx.INFO, "3: failed receiving frame: ", err) } } --- request GET /c --- response_body 1: sent text frame of len 200 2: received text frame of len 400 3: sent text frame of len 300 --- no_error_log [error] [warn] --- error_log 1: received text frame of len 200 2: sent text frame of len 400 3: failed receiving frame: exceeding max payload len openresty-lua-resty-websocket-5400587/t/sanity.t000066400000000000000000000651401475261236100216230ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et: use Test::Nginx::Socket::Lua; use Cwd qw(cwd); use Protocol::WebSocket::Frame; repeat_each(2); plan tests => repeat_each() * 162; my $pwd = cwd(); our $HttpConfig = qq{ lua_package_path "$pwd/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_REDIS_PORT} ||= 6379; no_long_string(); #no_diff(); run_tests(); __DATA__ === TEST 1: simple handshake --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' collectgarbage() local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r Origin: http://example.com\r \r " --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat !Content-Type --- raw_response_headers_like: ^HTTP/1.1 101 Switching Protocols\r\n --- response_body --- no_error_log [error] --- error_code: 101 === TEST 2: simple text data frame (3 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => 'foo', type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log text msg received: foo: nil, --- no_error_log [error] --- error_code: 101 === TEST 3: simple text data frame (0 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => '', type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log text msg received: , --- no_error_log [error] --- error_code: 101 === TEST 4: simple text data frame (125 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "a" x 124 . "b", type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log eval "text msg received: " . ("a" x 124) . "b,", --- no_error_log [error] --- error_code: 101 === TEST 5: simple text data frame (126 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "a" x 125 . "b", type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log eval "text msg received: " . ("a" x 125) . "b,", --- no_error_log [error] --- error_code: 101 === TEST 6: simple text data frame (127 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "a" x 126 . "b", type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log eval "text msg received: " . ("a" x 126) . "b,", --- no_error_log [error] --- error_code: 101 === TEST 7: simple text data frame (65535 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end local m, err = ngx.re.match(msg, "^a{65534}b$", "jo") if m then ngx.log(ngx.WARN, typ, " msg received is expected") else ngx.log(ngx.WARN, typ, " msg received is NOT expected") end '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "a" x 65534 . "b", type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log text msg received is expected, --- no_error_log [error] --- error_code: 101 --- no_check_leak === TEST 8: simple text data frame (65536 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new{ max_payload_len = 65536 } if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end local m, err = ngx.re.match(msg, "^a{65535}b$", "jo") if m then ngx.log(ngx.WARN, typ, " msg received is expected") else ngx.log(ngx.WARN, typ, " msg received is NOT expected") end '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "a" x 65535 . "b", type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log text msg received is expected, --- no_error_log [error] --- error_code: 101 --- no_check_leak === TEST 9: simple text data frame (1 Mbytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new{ max_payload_len = 1048576 + 1 } if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return end local m, err = ngx.re.match(msg, "^a+b$", "jo") if m and #msg == 1048576 + 1 then ngx.log(ngx.WARN, typ, " msg received is expected") else if err then ngx.log(ngx.ERR, "failed to match regex: ", err) return end ngx.log(ngx.WARN, typ, " msg received is NOT expected") end '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(max_payload_size => 1048576 + 1, buffer => "a" x 1048576 . "b", type => 'text', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log text msg received is expected, --- no_error_log [error] --- error_code: 101 --- no_check_leak === TEST 10: simple binary data frame (3 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => 'foo', type => 'binary', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log binary msg received: foo, --- no_error_log [error] --- error_code: 101 === TEST 11: close frame (status code + non-empty msg) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => pack("n", 1000) . 'yes, closed', type => 'close', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log close msg received: yes, closed: 1000, --- no_error_log [error] --- error_code: 101 === TEST 12: close frame (just status code) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => pack("n", 1002), type => 'close', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log close msg received: : 1002, --- no_error_log [error] --- error_code: 101 === TEST 13: close frame (no payload at all) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "", type => 'close', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log close msg received: : nil, --- no_error_log [error] --- error_code: 101 === TEST 14: ping frame (no payload at all) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "", type => 'ping', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log ping msg received: : nil, --- no_error_log [error] --- error_code: 101 === TEST 15: ping frame (with payload) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "are you there? 你好", type => 'ping', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log ping msg received: are you there? 你好: nil, --- no_error_log [error] --- error_code: 101 === TEST 16: pong frame (with payload) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "are you there? 你好", type => 'pong', masked => 1)->to_bytes(); --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log pong msg received: are you there? 你好: nil, --- no_error_log [error] --- error_code: 101 === TEST 17: exceeding the default 65535 max frame len limit (65536 bytes) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end local m, err = ngx.re.match(msg, "^a{65535}b$", "jo") if m then ngx.log(ngx.WARN, typ, " msg received is expected") else ngx.log(ngx.WARN, typ, " msg received is NOT expected") end '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r " . Protocol::WebSocket::Frame->new(buffer => "a" x 65535 . "b", type => 'text', masked => 1)->to_bytes(); --- ignore_response --- error_log failed to read msg: exceeding max payload len --- no_error_log text msg received is expected, === TEST 18: simple text data frame (3 bytes, fragmented, first frame) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval my $frame = Protocol::WebSocket::Frame->new(buffer => 'foo', type => 'text', masked => 1)->to_bytes(); $frame =~ s/./chr(ord($&) & 0x7f)/e; # clear the FIN bit "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r $frame"; --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log text msg received: foo: again, --- no_error_log [error] --- error_code: 101 === TEST 19: simple text data frame (3 bytes, fragmented, last frame) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval my $frame = Protocol::WebSocket::Frame->new(buffer => 'foo', type => 'text', masked => 1)->to_bytes(); $frame =~ s/./chr(ord($&) & 0xf0)/e; # clear the opcode "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r $frame"; --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log continuation msg received: foo: nil, --- no_error_log [error] --- error_code: 101 === TEST 20: simple text data frame (3 bytes, fragmented, middle frame) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end local msg, typ, err = wb:recv_frame() if not msg then ngx.log(ngx.ERR, "failed to read msg: ", err) return ngx.exit(444) end ngx.log(ngx.WARN, typ, " msg received: ", msg, ": ", err) '; } --- raw_request eval my $frame = Protocol::WebSocket::Frame->new(buffer => 'foo', type => 'text', masked => 1)->to_bytes(); $frame =~ s/./chr(ord($&) & 0x70)/e; # clear the opcode "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: Upgrade\r Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r \r $frame"; --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat --- response_body --- error_log continuation msg received: foo: again, --- no_error_log [error] --- error_code: 101 === TEST 21: Firefox 22.0 handshake --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua ' local websocket = require "resty.websocket.server" local wb, err = websocket:new() if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end '; } --- raw_request eval "GET /t HTTP/1.1\r Host: server.example.com\r Upgrade: websocket\r Connection: keep-alive, Upgrade\r Cache-Control: no-cache\r Pragma: no-cache\r Sec-WebSocket-Key: 05EiFj8mhoZ5F/oFE3Tyeg==\r Sec-WebSocket-Protocol: chat\r Sec-WebSocket-Version: 13\r Origin: null\r \r " --- response_headers Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: tBNO4O+F4DrQyajB62pvtRNU8LM= Sec-WebSocket-Protocol: chat --- response_body --- no_error_log [error] --- error_code: 101 openresty-lua-resty-websocket-5400587/valgrind.suppress000066400000000000000000000165031475261236100232770ustar00rootroot00000000000000{ Memcheck:Param write(buf) fun:__write_nocancel fun:ngx_log_error_core fun:ngx_resolver_read_response } { Memcheck:Cond fun:ngx_sprintf_num fun:ngx_vslprintf fun:ngx_log_error_core fun:ngx_resolver_read_response fun:ngx_epoll_process_events fun:ngx_process_events_and_timers fun:ngx_single_process_cycle fun:main } { Memcheck:Addr1 fun:ngx_vslprintf fun:ngx_snprintf fun:ngx_sock_ntop fun:ngx_event_accept } { Memcheck:Param write(buf) fun:__write_nocancel fun:ngx_log_error_core fun:ngx_resolver_read_response fun:ngx_event_process_posted fun:ngx_process_events_and_timers fun:ngx_single_process_cycle fun:main } { Memcheck:Cond fun:ngx_sprintf_num fun:ngx_vslprintf fun:ngx_log_error_core fun:ngx_resolver_read_response fun:ngx_event_process_posted fun:ngx_process_events_and_timers fun:ngx_single_process_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc obj:* } { exp-sgcheck:SorG fun:ngx_http_lua_ndk_set_var_get } { exp-sgcheck:SorG fun:ngx_http_variables_init_vars fun:ngx_http_block } { exp-sgcheck:SorG fun:ngx_conf_parse } { exp-sgcheck:SorG fun:ngx_vslprintf fun:ngx_log_error_core } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_calloc fun:ngx_event_process_init } { Memcheck:Param epoll_ctl(event) fun:epoll_ctl } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_event_process_init } { Memcheck:Cond fun:ngx_conf_flush_files fun:ngx_single_process_cycle } { Memcheck:Cond fun:memcpy fun:ngx_vslprintf fun:ngx_log_error_core fun:ngx_http_charset_header_filter } { Memcheck:Param socketcall.setsockopt(optval) fun:setsockopt fun:drizzle_state_connect } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_pool_cleanup_add } { Memcheck:Cond fun:ngx_conf_flush_files fun:ngx_single_process_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_array_push fun:ngx_http_get_variable_index fun:ngx_http_memc_add_variable fun:ngx_http_memc_init fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_event_process_init fun:ngx_single_process_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_crc32_table_init fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_event_process_init fun:ngx_worker_process_init fun:ngx_worker_process_cycle fun:ngx_spawn_process fun:ngx_start_worker_processes fun:ngx_master_process_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_pcalloc fun:ngx_hash_init fun:ngx_http_variables_init_vars fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_pcalloc fun:ngx_http_upstream_drizzle_create_srv_conf fun:ngx_http_upstream fun:ngx_conf_parse fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_pcalloc fun:ngx_hash_keys_array_init fun:ngx_http_variables_add_core_vars fun:ngx_http_core_preconfiguration fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_array_push fun:ngx_hash_add_key fun:ngx_http_add_variable fun:ngx_http_echo_add_variables fun:ngx_http_echo_handler_init fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_pcalloc fun:ngx_http_upstream_drizzle_create_srv_conf fun:ngx_http_core_server fun:ngx_conf_parse fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_pcalloc fun:ngx_http_upstream_drizzle_create_srv_conf fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_array_push fun:ngx_hash_add_key fun:ngx_http_variables_add_core_vars fun:ngx_http_core_preconfiguration fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_pcalloc fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_hash_init fun:ngx_http_upstream_init_main_conf fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_pcalloc fun:ngx_http_drizzle_keepalive_init fun:ngx_http_upstream_drizzle_init fun:ngx_http_upstream_init_main_conf fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large fun:ngx_palloc fun:ngx_hash_init fun:ngx_http_variables_init_vars fun:ngx_http_block fun:ngx_conf_parse fun:ngx_init_cycle fun:main } { Memcheck:Cond fun:index fun:expand_dynamic_string_token fun:_dl_map_object fun:map_doit fun:_dl_catch_error fun:do_preload fun:dl_main fun:_dl_sysdep_start fun:_dl_start } { Memcheck:Cond obj:* } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:ngx_alloc fun:ngx_set_environment fun:ngx_single_process_cycle } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:ngx_alloc fun:ngx_set_environment fun:ngx_worker_process_init fun:ngx_worker_process_cycle }