tcpsock:receiveuntil
--------------------
**语法:** *iterator = tcpsock:receiveuntil(pattern, options?)*
**环境:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.**
该方法返回一个迭代的 Lua 函数,该函数可以被调用读取数据流直到指定的规则或有错误发生。
这里有个例子,使用这个方法读取边界序列为 `--abcedhb` 数据流:
```lua
local reader = sock:receiveuntil("\r\n--abcedhb")
local data, err, partial = reader()
if not data then
ngx.say("failed to read the data stream: ", err)
end
ngx.say("read the data stream: ", data)
```
当不使用任何参数调用时,迭代函数返回的接收数据是指定规则 *之前* 的输入数据流。所以对于上面的例子,如果输入数据流是 `'hello, world! -agentzh\r\n--abcedhb blah blah'` ,然后将返回字符串 `'hello, world! -agentzh'` 。
错误的情况下,迭代函数将返回 `nil` 、错误描述信息以及已经读取到的部分数据内容。
迭代函数可以被多次调用,并且可以安全的与其他 cosocket 方法或其他迭代函数混合调用。
当这个迭代函数使用 `size` 参数时的行为有点不同(比如,真正的迭代)。就是说,每次调用它将读取 `size` 大小的数据,最后一次调用(无论找到边界规则或遇到错误)将返回 `nil` 。该迭代函数的最后一次成功调用, `err` 的返回值也将是 `nil` 。在最后一次成功调用(返回数据 `nil`,错误信息 `nil`)之后,该迭代函数将会被重置。细看下面的例子:
```lua
local reader = sock:receiveuntil("\r\n--abcedhb")
while true do
local data, err, partial = reader(4)
if not data then
if err then
ngx.say("failed to read the data stream: ", err)
break
end
ngx.say("read done")
break
end
ngx.say("read chunk: [", data, "]")
end
```
对于输入数据是 `'hello, world! -agentzh\r\n--abcedhb blah blah'` ,使用上面的示例代码我们将得到下面输出:
read chunk: [hell]
read chunk: [o, w]
read chunk: [orld]
read chunk: [! -a]
read chunk: [gent]
read chunk: [zh]
read done
注意,当边界规则对数据流解析有歧义时,实际返回数据长度 *可能* 会略大于 `size` 参数指定的大小限制。在数据流的边界,返回的字符数据长度同样也可能小于 `size` 参数限制。
迭代函数的读操作超时控制,是由 [lua_socket_read_timeout](#lua_socket_read_timeout) 指令配置和 [settimeout](#tcpsocksettimeout) 方法设置的。而后者有更高的优先级,例如:
```lua
local readline = sock:receiveuntil("\r\n")
sock:settimeout(1000) -- one second timeout
line, err, partial = readline()
if not line then
ngx.say("failed to read a line: ", err)
return
end
ngx.say("successfully read a line: ", line)
```
在调用迭代函数(注意 `receiveuntil` 调用在这里是不相干的) *之前* 调用 [settimeout](#tcpsocksettimeout) 方法是非常重要的。
从 `v0.5.1` 版本开始,该方法接收一个可选的 `options` 表参数来控制一些行为。支持下面这些选项:
* `inclusive`
`inclusive` 用一个布尔值来控制返回数据串是否包含规则字符串,默认是 `false`。例如:
```lua
local reader = tcpsock:receiveuntil("_END_", { inclusive = true })
local data = reader()
ngx.say(data)
```
然后对于数据数据流 `"hello world _END_ blah blah blah"` ,根据上面的示例代码将得到 `hello world _END_` 的输出,包含规则字符串 `_END_` 自身。
自从 `v0.8.8` 版本,当出现读取超时错误时,该方法不再自动关闭当前连接。对于其他连接错误,该方法总是会自动关闭连接。
该特性是在 `v0.5.0rc1` 版本首次引入的。
[返回目录](#nginx-api-for-lua)
> English source:
tcpsock:receiveuntil
--------------------
**syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)*
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.**
This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs.
Here is an example for using this method to read a data stream with the boundary sequence `--abcedhb`:
```lua
local reader = sock:receiveuntil("\r\n--abcedhb")
local data, err, partial = reader()
if not data then
ngx.say("failed to read the data stream: ", err)
end
ngx.say("read the data stream: ", data)
```
When called without any argument, the iterator function returns the received data right *before* the specified pattern string in the incoming data stream. So for the example above, if the incoming data stream is `'hello, world! -agentzh\r\n--abcedhb blah blah'`, then the string `'hello, world! -agentzh'` will be returned.
In case of error, the iterator function will return `nil` along with a string describing the error and the partial data bytes that have been read so far.
The iterator function can be called multiple times and can be mixed safely with other cosocket method calls or other iterator function calls.
The iterator function behaves differently (i.e., like a real iterator) when it is called with a `size` argument. That is, it will read that `size` of data on each invocation and will return `nil` at the last invocation (either sees the boundary pattern or meets an error). For the last successful invocation of the iterator function, the `err` return value will be `nil` too. The iterator function will be reset after the last successful invocation that returns `nil` data and `nil` error. Consider the following example:
```lua
local reader = sock:receiveuntil("\r\n--abcedhb")
while true do
local data, err, partial = reader(4)
if not data then
if err then
ngx.say("failed to read the data stream: ", err)
break
end
ngx.say("read done")
break
end
ngx.say("read chunk: [", data, "]")
end
```
Then for the incoming data stream `'hello, world! -agentzh\r\n--abcedhb blah blah'`, we shall get the following output from the sample code above:
read chunk: [hell]
read chunk: [o, w]
read chunk: [orld]
read chunk: [! -a]
read chunk: [gent]
read chunk: [zh]
read done
Note that, the actual data returned *might* be a little longer than the size limit specified by the `size` argument when the boundary pattern has ambiguity for streaming parsing. Near the boundary of the data stream, the data string actually returned could also be shorter than the size limit.
Timeout for the iterator function's reading operation is controlled by the [lua_socket_read_timeout](#lua_socket_read_timeout) config directive and the [settimeout](#tcpsocksettimeout) method. And the latter takes priority. For example:
```lua
local readline = sock:receiveuntil("\r\n")
sock:settimeout(1000) -- one second timeout
line, err, partial = readline()
if not line then
ngx.say("failed to read a line: ", err)
return
end
ngx.say("successfully read a line: ", line)
```
It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling the iterator function (note that the `receiveuntil` call is irrelevant here).
As from the `v0.5.1` release, this method also takes an optional `options` table argument to control the behavior. The following options are supported:
* `inclusive`
The `inclusive` takes a boolean value to control whether to include the pattern string in the returned data string. Default to `false`. For example,
```lua
local reader = tcpsock:receiveuntil("_END_", { inclusive = true })
local data = reader()
ngx.say(data)
```
Then for the input data stream `"hello world _END_ blah blah blah"`, then the example above will output `hello world _END_`, including the pattern string `_END_` itself.
Since the `v0.8.8` release, this method no longer automatically closes the current connection when the read timeout error happens. For other connection errors, this method always automatically closes the connection.
This method was first introduced in the `v0.5.0rc1` release.
[Back to TOC](#nginx-api-for-lua)
- Name yuansheng-8.4 WenMing(√)
- Status yuansheng-8.6 WenMing(√)
- Version
- Synopsis yuansheng-8.6 WenMing(√)
- Description yuansheng-8.16 WenMing(√)
- Typical Uses yuansheng-8.16 WenMing(√)
- Nginx Compatibility yuansheng-8.17 WenMing(√)
- Installation yuansheng-8.17 WenMing(√)
- C Macro Configurations yuansheng-8.17 WenMing(√)
- Installation on Ubuntu 11.10 yuansheng-8.18
- Community
- English Mailing List
- Chinese Mailing List
- Code Repository yuansheng-8.20 WenMing(√)
- Bugs and Patches yuansheng-8.20 WenMing(√)
- Lua/LuaJIT bytecode support yuansheng-8.31
- System Environment Variable Support yuansheng-9.1
- HTTP 1.0 support lance-2015.8.13
- Statically Linking Pure Lua Modules yuansheng-9.1
- Nginx Worker内的数据共享 lance-2015.8.5
- Known Issues
- TCP socket connect operation issues yuansheng-9.2
- Lua Coroutine Yielding/Resuming yuansheng-9.2
- Lua Variable Scope yuansheng-9.2
- Locations Configured by Subrequest Directives of Other Modules lance-2015.8.12
- Cosockets Not Available Everywhere yuansheng-9.2
- 特别转义序列 lance-2015.8.5
- Mixing with SSI Not Supported yuansheng-9.2
- SPDY Mode Not Fully Supported yuansheng-9.2
- Missing data on short circuited requests yuansheng-9.2
- TODO yuansheng-9.3
- Changes yuansheng-9.3 WenMing(√)
- Test Suite yuansheng-9.3
- Copyright and License yuansheng-9.3
- See Also yuansheng-9.3
- Directives yuansheng-9.3
- Nginx API for Lua yuansheng-9.3
- Obsolete Sections yuansheng-9.3
- lua_use_default_type hambut 2015.8.5
- lua_code_cache hambut 2015.8.5
- lua_regex_cache_max_entries yuansheng-9.3
- lua_regex_match_limit yuansheng-9.3
- lua_package_path yuansheng-9.4
- lua_package_cpath yuansheng-9.4
- init_by_lua yuansheng-9.4
- init_by_lua_file yuansheng-9.4
- init_worker_by_lua yuansheng-9.6
- init_worker_by_lua_file yuansheng-9.6
- set_by_lua yuansheng-9.6
- set_by_lua_file yuansheng-9.6
- content_by_lua dengshiyong 2015.8.12 WenMing(√)
- content_by_lua_file yuansheng-9.19
- rewrite_by_lua yuansheng-9.19
- rewrite_by_lua_file yuansheng-9.19
- access_by_lua yuansheng-9.27
- access_by_lua_file yuansheng-9.28
- header_filter_by_lua liujinxuan 2015.9.1
- header_filter_by_lua_file yuansheng-9.28
- body_filter_by_lua yuansheng-9.28
- body_filter_by_lua_file yuansheng-9.28
- log_by_lua yuansheng-9.28
- log_by_lua_file yuansheng-9.28
- lua_need_request_body yuansheng-9.28
- lua_shared_dict lance-2015.8.20
- lua_socket_connect_timeout yuansheng-9.28
- lua_socket_send_timeout yuansheng-9.28
- lua_socket_send_lowat yuansheng-9.28
- lua_socket_read_timeout yuansheng-9.28
- lua_socket_buffer_size yuansheng-9.28
- lua_socket_pool_size yuansheng-9.28
- lua_socket_keepalive_timeout yuansheng-9.28
- lua_socket_log_errors yuansheng-9.28
- lua_ssl_ciphers yuansheng-9.29
- lua_ssl_crl yuansheng-9.29
- lua_ssl_protocols yuansheng-9.29
- lua_ssl_trusted_certificate yuansheng-9.29
- lua_ssl_verify_depth yuansheng-9.29
- lua_http10_buffering yuansheng-9.29
- rewrite_by_lua_no_postpone yuansheng-9.29
- lua_transform_underscores_in_response_headers yuansheng-9.29
- lua_check_client_abort yuansheng-9.29
- lua_max_pending_timers yuansheng-9.29
- lua_max_running_timers yuansheng-9.29
- ngx.arg lance-2015.8.19
- ngx.var.VARIABLE lance-2015.8.19
- Core constants lance-2015.8.14 WenMing(√)
- HTTP method constants lance-2015.8.13
- HTTP status constants lance-2015.8.13
- Nginx log level constants lance-2015.8.13
- print lance-2015.8.14
- ngx.ctx lance-2015.8.14
- ngx.location.capture lance-2015.8.11
- ngx.location.capture_multi lance-2015.8.11
- ngx.status lance-2015.8.18 yuansheng(√)
- ngx.header.HEADER lance-2015.9.6 yuansheng(√)
- ngx.resp.get_headers lance-2015.9.7 yuansheng(√)
- ngx.req.start_time lance-2015.9.9 yuansheng(√)
- ngx.req.http_version lance-2015.9.9 yuansheng(√)
- ngx.req.raw_header lance-2015.9.9 yuansheng(√)
- ngx.req.get_method lance-2015.9.9 yuansheng(√)
- ngx.req.set_method lance-2015.9.9 yuansheng(√)
- ngx.req.set_uri lance-2015.9.9
- ngx.req.set_uri_args lance-2015.9.10
- ngx.req.get_uri_args lance-2015.9.10
- ngx.req.get_post_args lance-2015.9.10
- ngx.req.get_headers lance-2015.9.11
- ngx.req.set_header lance-2015.9.14
- ngx.req.clear_header lance-2015.9.14
- ngx.req.read_body lance-2015.9.16
- ngx.req.discard_body lance-2015.9.24
- ngx.req.get_body_data lance-2015.9.24
- ngx.req.get_body_file lance-2015.9.28
- ngx.req.set_body_data lance-2015.9.28
- ngx.req.set_body_file lance-2015.9.28
- ngx.req.init_body lance-2015.9.28
- ngx.req.append_body lance-2015.9.28
- ngx.req.finish_body lance-2015.9.28
- ngx.req.socket yuansheng-10.12
- ngx.exec yuansheng-10.12
- ngx.redirect yuansheng-10.12
- ngx.send_headers yuansheng-10.12
- ngx.headers_sent yuansheng-10.12
- ngx.print lance-2015.8.7
- ngx.say lance-2015.8.7
- ngx.log lance-2015.8.13
- ngx.flush lance-2015.8.13
- ngx.exit lance-2015.8.13
- ngx.eof lance-2015.8.18
- ngx.sleep lance-2015.8.18
- ngx.escape_uri lance-2015.8.18
- ngx.unescape_uri lance-2015.8.18
- ngx.encode_args lance-2015.8.18
- ngx.decode_args lance-2015.8.18
- ngx.encode_base64 hambut-2015.9.9
- ngx.decode_base64 hambut-2015.9.9
- ngx.crc32_short hambut-2015.9.9
- ngx.crc32_long hambut-2015.9.9
- ngx.hmac_sha1 hambut-2015.9.9
- ngx.md5 hambut-2015.9.9
- ngx.md5_bin hambut-2015.9.9
- ngx.sha1_bin hambut-2015.9.9
- ngx.quote_sql_str hambut-2015.9.9
- ngx.today bells-2015.8.8
- ngx.time bells-2015.8.22
- ngx.now bells-2015.8.22
- ngx.update_time bells-2015.8.16
- ngx.localtime bells-2015.8.22
- ngx.utctime bells-2015.8.22
- ngx.cookie_time yuansheng-10.12
- ngx.http_time yuansheng-10.10
- ngx.parse_http_time yuansheng-10.10
- ngx.is_subrequest yuansheng-10.8
- ngx.re.match lance-2015.8.6
- ngx.re.find lance-2015.8.6
- ngx.re.gmatch lance-2015.8.6
- ngx.re.sub lance-2015.8.6
- ngx.re.gsub lance-2015.8.6
- ngx.shared.DICT lance-2015.8.10
- ngx.shared.DICT.get lance-2015.8.10
- ngx.shared.DICT.get_stale lance-2015.8.10
- ngx.shared.DICT.set lance-2015.8.10
- ngx.shared.DICT.safe_set lance-2015.8.10
- ngx.shared.DICT.add lance-2015.8.10
- ngx.shared.DICT.safe_add lance-2015.8.10
- ngx.shared.DICT.replace lance-2015.8.10
- ngx.shared.DICT.delete lance-2015.8.10
- ngx.shared.DICT.incr lance-2015.8.10
- ngx.shared.DICT.flush_all lance-2015.8.10
- ngx.shared.DICT.flush_expired lance-2015.8.10
- ngx.shared.DICT.get_keys lance-2015.8.10
- ngx.socket.udp yuansheng-10.8
- udpsock:setpeername yuansheng-10.8
- udpsock:send yuansheng-10.8
- udpsock:receive yuansheng-10.8
- udpsock:close yuansheng-10.8
- udpsock:settimeout yuansheng-10.8
- ngx.socket.tcp yuansheng-10.7
- tcpsock:connect yuansheng-10.7
- tcpsock:sslhandshake yuansheng-10.7
- tcpsock:send yuansheng-10.7
- tcpsock:receive yuansheng-10.5
- tcpsock:receiveuntil yuansheng-10.5
- tcpsock:close yuansheng-10.5
- tcpsock:settimeout yuansheng-10.5
- tcpsock:setoption yuansheng-10.5
- tcpsock:setkeepalive yuansheng-10.5
- tcpsock:getreusedtimes yuansheng-10.5
- ngx.socket.connect yuansheng-10.4
- ngx.get_phase yuansheng-10.2
- ngx.thread.spawn yuansheng-10.2
- ngx.thread.wait yuansheng-10.4
- ngx.thread.kill yuansheng-10.4
- ngx.on_abort yuansheng-10.2
- ngx.timer.at yuansheng-10.1
- ngx.config.debug yuansheng-9.30
- ngx.config.prefix yuansheng-9.30
- ngx.config.nginx_version yuansheng-9.30
- ngx.config.nginx_configure yuansheng-9.30
- ngx.config.ngx_lua_version yuansheng-9.30
- ngx.worker.exiting yuansheng-9.30
- ngx.worker.pid yuansheng-9.30
- ndk.set_var.DIRECTIVE yuansheng-9.30
- coroutine.create yuansheng-9.30
- coroutine.resume yuansheng-9.30
- coroutine.yield yuansheng-9.30
- coroutine.wrap yuansheng-9.30
- coroutine.running yuansheng-9.30
- coroutine.status yuansheng-9.30