pax_global_header00006660000000000000000000000064130071740470014515gustar00rootroot0000000000000052 comment=cc59f2f3e4383477a7c415aa2ceb7af7e03d487d lua-resty-websocket-0.06/000077500000000000000000000000001300717404700153535ustar00rootroot00000000000000lua-resty-websocket-0.06/.gitattributes000066400000000000000000000000331300717404700202420ustar00rootroot00000000000000*.t linguist-language=Text lua-resty-websocket-0.06/.gitignore000066400000000000000000000000771300717404700173470ustar00rootroot00000000000000*.swp *.swo *~ go t/servroot/ reindex *.t_ tags a.patch *.html lua-resty-websocket-0.06/.travis.yml000066400000000000000000000054371300717404700174750ustar00rootroot00000000000000sudo: required dist: trusty os: linux language: c compiler: - gcc - clang 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.0.2h - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH - TEST_NGINX_SLEEP=0.006 matrix: - NGINX_VERSION=1.9.15 - NGINX_VERSION=1.11.2 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/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 - ngx-build $NGINX_VERSION --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 -r t lua-resty-websocket-0.06/Makefile000066400000000000000000000007021300717404700170120ustar00rootroot00000000000000OPENRESTY_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 lua-resty-websocket-0.06/README.markdown000066400000000000000000000517001300717404700200570ustar00rootroot00000000000000Name ==== 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) * [recv_frame](#recv_frame) * [build_frame](#build_frame) * [send_frame](#send_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 ngx.log(ngx.ERR, "failed to receive a frame: ", err) return ngx.exit(444) end if typ == "close" then -- 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 local code = err 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. * `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 = 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. * `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 = wb:connect("ws://:/")` `syntax: ok, err = wb:connect("wss://:/")` `syntax: ok, err = wb:connect("ws://:/", options)` `syntax: ok, err = 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. 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 `:`. * `ssl_verify` Specifies whether to perform SSL certificate verfication during the SSL handshake if the `wss://` scheme is used. 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) #### 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) #### build_frame `syntax: frame = protocol.build_frame(fin, opcode, payload_len, payload, masking)` Builds a raw WebSocket frame. [Back to TOC](#table-of-contents) #### 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 (章亦春) , CloudFlare Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2013-2016, by Yichun Zhang (agentzh) , CloudFlare 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) lua-resty-websocket-0.06/dist.ini000066400000000000000000000004311300717404700170150ustar00rootroot00000000000000name=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 lua-resty-websocket-0.06/lib/000077500000000000000000000000001300717404700161215ustar00rootroot00000000000000lua-resty-websocket-0.06/lib/resty/000077500000000000000000000000001300717404700172675ustar00rootroot00000000000000lua-resty-websocket-0.06/lib/resty/websocket/000077500000000000000000000000001300717404700212555ustar00rootroot00000000000000lua-resty-websocket-0.06/lib/resty/websocket/client.lua000066400000000000000000000173641300717404700232510ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) -- FIXME: this library is very rough and is currently just for testing -- the websocket server. 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 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 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.06' 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 if opts then max_payload_len = opts.max_payload_len send_unmasked = opts.send_unmasked timeout = opts.timeout if timeout then sock:settimeout(timeout) end end return setmetatable({ sock = sock, max_payload_len = max_payload_len or 65535, 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 m, err = re_match(uri, [[^(wss?)://([^:/]+)(?::(\d+))?(.*)]], "jo") 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 host = m[2] local port = m[3] local path = m[4] -- ngx.say("host: ", host) -- ngx.say("port: ", port) if not port then port = 80 end if path == "" then path = "/" end local ssl_verify, proto_header, origin_header, sock_opts = false 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 local pool = opts.pool if pool then sock_opts = { pool = pool } end if opts.ssl_verify then if not ssl_support then return nil, "ngx_lua 0.9.11+ required for SSL sockets" end ssl_verify = true end end local ok, err if sock_opts then ok, err = sock:connect(host, port, sock_opts) else ok, err = sock:connect(host, port) end if not ok then return nil, "failed to connect: " .. err end if scheme == "wss" then if not ssl_support then return nil, "ngx_lua 0.9.11+ required for SSL sockets" end ok, err = sock:sslhandshake(false, host, ssl_verify) if not ok then return nil, "ssl handshake failed: " .. err end end -- check for connections from pool: local count,err = sock:getreusedtimes() if not count then return nil, "failed to get reused times: " .. err end if count > 0 then -- being a reused connection (must have done handshake) return 1 end -- do the websocket handshake: 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) local key = encode_base64(bytes) local req = "GET " .. path .. " HTTP/1.1\r\nUpgrade: websocket\r\nHost: " .. host .. ":" .. port .. "\r\nSec-WebSocket-Key: " .. key .. (proto_header or "") .. "\r\nSec-WebSocket-Version: 13" .. (origin_header or "") .. "\r\nConnection: Upgrade\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 -- 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 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_payload_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_payload_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 lua-resty-websocket-0.06/lib/resty/websocket/protocol.lua000066400000000000000000000207141300717404700236250ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local bit = require "bit" 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 str_char = string.char local rand = math.random local type = type local debug = ngx.config.debug local ngx_log = ngx.log local ngx_DEBUG = ngx.DEBUG 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.06' local types = { [0x0] = "continuation", [0x1] = "text", [0x2] = "binary", [0x8] = "close", [0x9] = "ping", [0xa] = "pong", } 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 = new_tab(payload_len - 2, 0) for i = 3, payload_len do bytes[i - 2] = str_char(bxor(byte(data, 4 + i), byte(data, (i - 1) % 4 + 1))) end msg = concat(bytes) 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 = new_tab(payload_len, 0) for i = 1, payload_len do bytes[i] = str_char(bxor(byte(data, 4 + i), byte(data, (i - 1) % 4 + 1))) end msg = concat(bytes) 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 = new_tab(payload_len, 0) for i = 1, payload_len do bytes[i] = str_char(bxor(byte(payload, i), byte(masking_key, (i - 1) % 4 + 1))) end payload = concat(bytes) 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 lua-resty-websocket-0.06/lib/resty/websocket/server.lua000066400000000000000000000114211300717404700232650ustar00rootroot00000000000000-- 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 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 ngx = ngx local read_body = ngx.req.read_body local band = bit.band local rshift = bit.rshift local type = type local setmetatable = setmetatable -- local print = print local _M = new_tab(0, 10) _M._VERSION = '0.06' 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" 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 "unknonw") 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 if opts then max_payload_len = opts.max_payload_len send_masked = opts.send_masked timeout = opts.timeout if timeout then sock:settimeout(timeout) end end return setmetatable({ sock = sock, max_payload_len = max_payload_len or 65535, 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_payload_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_payload_len, self.send_masked) 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 function _M.send_close(self, code, msg) local payload if code then if type(code) ~= "number" or code > 0x7fff then 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 lua-resty-websocket-0.06/t/000077500000000000000000000000001300717404700156165ustar00rootroot00000000000000lua-resty-websocket-0.06/t/cert/000077500000000000000000000000001300717404700165535ustar00rootroot00000000000000lua-resty-websocket-0.06/t/cert/test.crt000066400000000000000000000017311300717404700202460ustar00rootroot00000000000000-----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----- lua-resty-websocket-0.06/t/cert/test.key000066400000000000000000000015731300717404700202520ustar00rootroot00000000000000-----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----- lua-resty-websocket-0.06/t/count.t000066400000000000000000000033521300717404700171360ustar00rootroot00000000000000# 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: 10 --- no_error_log [error] lua-resty-websocket-0.06/t/cs.t000066400000000000000000001515411300717404700164170ustar00rootroot00000000000000# 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 + 14); 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(); 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() for i = 1, 3 do 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 = "hello " .. i local bytes, err = wb:send_text(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("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! 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] --- 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 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 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! 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 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! 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 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! 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 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! 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 lua-resty-websocket-0.06/t/sanity.t000066400000000000000000000650531300717404700173230ustar00rootroot00000000000000# 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 === 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 === 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 === 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 lua-resty-websocket-0.06/valgrind.suppress000066400000000000000000000206631300717404700207760ustar00rootroot00000000000000{ 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:Leak fun:malloc fun:ngx_alloc fun:ngx_malloc fun:ngx_pcalloc } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:(below main) } { 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:Leak fun:memalign fun:posix_memalign fun:ngx_memalign fun:ngx_pcalloc } { Memcheck:Param socketcall.setsockopt(optval) fun:setsockopt fun:drizzle_state_connect } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc_large } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_pool_cleanup_add } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_pnalloc } { Memcheck:Cond fun:ngx_conf_flush_files fun:ngx_single_process_cycle fun:main } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_palloc } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_pcalloc } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_malloc fun:ngx_palloc_large } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_create_pool } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_malloc fun:ngx_palloc } { Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_malloc fun:ngx_pnalloc } { 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:Leak fun:memalign fun:posix_memalign fun:ngx_memalign fun:ngx_create_pool } { Memcheck:Leak fun:memalign fun:posix_memalign fun:ngx_memalign fun:ngx_palloc_block fun:ngx_palloc } { 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 }