Skip to content

Commit 672f6d3

Browse files
committed
Added pipeline docs and tidied formatting.
1 parent b0b8fa2 commit 672f6d3

File tree

1 file changed

+94
-128
lines changed

1 file changed

+94
-128
lines changed

README.md

Lines changed: 94 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
11
# lua-resty-http
22

3+
Lua HTTP client cosocket driver for [OpenResty](http://openresty.org/) / [ngx_lua](https://github.com/chaoslawful/lua-nginx-module).
34

4-
Lua HTTP client driver for [ngx_lua](https://github.com/chaoslawful/lua-nginx-module) based on the cosocket API. Supports HTTP 1.0 and 1.1, including chunked transfer encoding for response bodies, and provides a streaming interface to the body irrespective of transfer encoding.
5+
# Status
56

6-
## Status
7+
Ready for testing. Probably production ready in most cases, though not yet proven in the wild. Please check the issues list and let me know if you have any problems / questions.
78

8-
This is newish, but works and passes tests. Please send any design feedback or actual bugs on the issues page.
9+
# Features
10+
11+
* HTTP 1.0 and 1.1
12+
* Streaming interface to reading bodies using coroutines, for predictable memory usage in Lua land.
13+
* Alternative simple interface for singleshot requests without manual connection step.
14+
* Chunked transfer encoding.
15+
* Keepalive.
16+
* Pipelining.
17+
* Trailers.
918

1019
## Synopsis
1120

1221
```` lua
1322
lua_package_path "/path/to/lua-resty-http/lib/?.lua;;";
1423

1524
server {
25+
26+
1627
location /simpleinterface {
1728
content_by_lua '
1829

19-
-- For simple work, use the URI interface...
30+
-- For simple singleshot requests, use the URI interface.
2031
local httpc = http.new()
2132
local res, err = httpc:request_uri("http://example.com/helloworld", {
2233
method = "POST",
@@ -37,64 +48,30 @@ server {
3748
end
3849

3950
ngx.say(res.body)
51+
4052
';
4153
}
4254

43-
location /generic {
55+
56+
location /genericinterface {
4457
content_by_lua '
58+
4559
local http = require "resty.http"
4660
local httpc = http.new()
4761

48-
-- The generic form gives us more control. We must connect manually...
62+
-- The generic form gives us more control. We must connect manually.
4963
httpc:set_timeout(500)
5064
httpc:connect("127.0.0.1", 80)
5165

52-
-- And request using a path, rather than a full URI...
53-
local res, err = httpc:request{
54-
path = "/helloworld",
55-
headers = {
56-
["Host"] = "example.com",
57-
},
58-
}
59-
60-
-- Or stream the request body in
61-
local client_body_reader, err = httpc:get_client_body_reader()
62-
if not client_body_reader then
63-
if err == "chunked request bodies not supported yet" then
64-
ngx.status = 411
65-
ngx.say("411 Length Required")
66-
ngx.exit(ngx.status)
67-
end
68-
end
69-
66+
-- And request using a path, rather than a full URI.
7067
local res, err = httpc:request{
7168
path = "/helloworld",
72-
body = client_body_reader,
7369
headers = {
7470
["Host"] = "example.com",
7571
},
7672
}
77-
78-
if not res then
79-
ngx.log(ngx.ERR, err)
80-
ngx.exit(500)
81-
end
82-
83-
ngx.say(res.status)
84-
85-
for k,v in pairs(res.headers) do
86-
--
87-
end
88-
89-
-- METHOD 1.
90-
-- At this point, the body has not been read. You can read it in one go
91-
-- if you like...
92-
local body = res:read_body()
9373

94-
95-
-- METHOD 2.
96-
-- Or, stream the body using an iterator, for predictable memory usage
97-
-- in Lua land.
74+
-- Now we can use the body_reader iterator, to stream the body according to our desired chunk size.
9875
local reader = res.body_reader
9976

10077
repeat
@@ -109,62 +86,22 @@ server {
10986
end
11087
until not chunk
11188

112-
113-
-- METHOD 3.
114-
-- Or, introduce your own coroutine filter to modify the chunks as they arrive.
115-
function get_filter(reader)
116-
return coroutine.wrap(function(max_bytes)
117-
repeat
118-
local chunk, err = reader(max_bytes)
119-
if not chunk then
120-
coroutine.yield(nil, err)
121-
break
122-
end
123-
124-
-- Process data
125-
126-
coroutine.yield(chunk)
127-
until not chunk
128-
end)
129-
end
130-
131-
-- pass the body reader to your filter
132-
local reader = get_filter(res.body_reader)
133-
134-
-- then read via your filter(s) as above
135-
repeat
136-
local chunk, err = reader(8192)
137-
if err then
138-
ngx.log(ngx.ERR, err)
139-
break
140-
end
141-
142-
if chunk then
143-
ngx.print(chunk)
144-
end
145-
until not chunk
146-
147-
148-
-- If the response advertised trailers, you can merge them with the headers now
149-
res:read_trailers()
150-
15189
httpc:set_keepalive()
90+
15291
';
15392
}
15493
}
15594
````
15695

157-
## API
96+
# Connection
15897

159-
### Connection
160-
161-
#### new
98+
## new
16299

163100
`syntax: httpc = http.new()`
164101

165102
Creates the http object. In case of failures, returns `nil` and a string describing the error.
166103

167-
#### connect
104+
## connect
168105

169106
`syntax: ok, err = httpc:connect(host, port, options_table?)`
170107

@@ -179,13 +116,13 @@ An optional Lua table can be specified as the last argument to this method to sp
179116
* `pool`
180117
: Specifies a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template `<host>:<port>` or `<unix-socket-path>`.
181118

182-
#### set_timeout
119+
## set_timeout
183120

184121
`syntax: httpc:set_timeout(time)`
185122

186123
Sets the timeout (in ms) protection for subsequent operations, including the `connect` method.
187124

188-
#### set_keepalive
125+
## set_keepalive
189126

190127
`syntax: ok, err = httpc:set_keepalive(max_idle_timeout, pool_size)`
191128

@@ -197,49 +134,28 @@ Only call this method in the place you would have called the `close` method inst
197134

198135
Note that calling this instead of `close` is "safe" in that it will conditionally close depending on the type of request. Specifically, a `1.0` request without `Connection: Keep-Alive` will be closed, as will a `1.1` request with `Connection: Close`.
199136

200-
In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. In the case where the conneciton is conditionally closed as described above, returns `2` and the error string `connection must be closed`.
137+
In case of success, returns `1`. In case of errors, returns `nil, err`. In the case where the conneciton is conditionally closed as described above, returns `2` and the error string `connection must be closed`.
201138

202-
#### get_reused_times
139+
## get_reused_times
203140

204141
`syntax: times, err = httpc:get_reused_times()`
205142

206143
This method returns the (successfully) reused times for the current connection. In case of error, it returns `nil` and a string describing the error.
207144

208145
If the current connection does not come from the built-in connection pool, then this method always returns `0`, that is, the connection has never been reused (yet). If the connection comes from the connection pool, then the return value is always non-zero. So this method can also be used to determine if the current connection comes from the pool.
209146

210-
#### close
147+
## close
211148

212149
`syntax: ok, err = http:close()`
213150

214151
Closes the current connection and returns the status.
215152

216153
In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error.
217154

218-
#### get_client_body_reader
219-
220-
`syntax: reader, err = httpc:get_client_body_reader()`
221-
222-
Returns an iterator function which can be used to read the downstream request body in a chunked fashion. This iterator can be used as the value for the body field in request params.
223-
224-
```lua
225-
local req_reader = httpc:get_client_body_reader()
226-
227-
repeat
228-
local chunk, err = req_reader(8192)
229-
if err then
230-
ngx.log(ngx.ERR, err)
231-
break
232-
end
233-
234-
if chunk then
235-
-- process
236-
end
237-
until not chunk
238-
```
239155

240-
### Requesting
156+
# Requesting
241157

242-
#### request
158+
## request
243159

244160
`syntax: res, err = httpc:request(params)`
245161

@@ -251,7 +167,7 @@ The `params` table accepts the following fields:
251167
* `method` The HTTP method string.
252168
* `path` The path string.
253169
* `headers` A table of request headers.
254-
* `body` The request body as a string or an iterator function.
170+
* `body` The request body as a string, or an iterator function (see [get_client_body_reader](#get_client_body_reader)).
255171

256172
When the request is successful, `res` will contain the following fields:
257173

@@ -262,7 +178,7 @@ When the request is successful, `res` will contain the following fields:
262178
* `read_body` A method to read the entire body into a string.
263179
* `read_trailers` A method to merge any trailers underneath the headers, after reading the body.
264180

265-
##### res.body_reader
181+
## res.body_reader
266182

267183
The `body_reader` iterator can be used to stream the response body in chunk sizes of your choosing, as follows:
268184

@@ -286,21 +202,21 @@ If the reader is called with no arguments, the behaviour depends on the type of
286202

287203
Note that the size provided is actually a **maximum** size. So in the chunked transfer case, you may get chunks smaller than the size you ask, as a remainder of the actual HTTP chunks.
288204

289-
##### res:read_body
205+
## res:read_body
290206

291207
`syntax: body, err = res:read_body()`
292208

293-
Reads the body into a local string.
209+
Reads the entire body into a local string.
294210

295211

296-
##### res:read_trailers
212+
## res:read_trailers
297213

298214
`syntax: res:read_trailers()`
299215

300-
This merges any trailers headers underneath the `res.headers` table itself.
216+
This merges any trailers underneath the `res.headers` table itself. Must be called after reading the body.
301217

302218

303-
#### request_uri
219+
## request_uri
304220

305221
`syntax: res, err = httpc:request_uri(uri, params)`
306222

@@ -315,23 +231,73 @@ Additionally there is no ability to stream the response body in this mode. If th
315231
* `body` The response body as a string.
316232

317233

318-
### Utility
234+
## request_pipeline
235+
236+
`syntax: responses, err = httpc:request_pipeline(params)`
237+
238+
This method works as per the [request](#request) method above, but `params` is instead a table of param tables. Each request is sent in order, and `responses` is returned as a table of response handles. For example:
239+
240+
```lua
241+
local responses = httpc:request_pipeline{
242+
{
243+
path = "/b",
244+
},
245+
{
246+
path = "/c",
247+
},
248+
{
249+
path = "/d",
250+
}
251+
}
252+
253+
for i,r in ipairs(responses) do
254+
ngx.say(r.status)
255+
ngx.say(r:read_body())
256+
end
257+
```
258+
259+
Due to the nature of pipelining, no responses are actually read until you attempt to use the response fields (status / headers etc). And since the responses are read off in order, you must read the entire body (and any trailers if you have them), before attempting to read the next response.
260+
319261

320-
#### parse_uri
262+
# Utility
263+
264+
## parse_uri
321265

322266
`syntax: local scheme, host, port, path = unpack(httpc:parse_uri(uri))`
323267

324268
This is a convenience function allowing one to more easily use the generic interface, when the input data is a URI.
325269

326270

327-
## Author
271+
## get_client_body_reader
272+
273+
`syntax: reader, err = httpc:get_client_body_reader()`
274+
275+
Returns an iterator function which can be used to read the downstream client request body in a streaming fashion. This iterator can also be used as the value for the body field in request params, allowing one to stream the request body into a proxied upstream request.
276+
277+
```lua
278+
local req_reader = httpc:get_client_body_reader()
279+
280+
repeat
281+
local chunk, err = req_reader(8192)
282+
if err then
283+
ngx.log(ngx.ERR, err)
284+
break
285+
end
286+
287+
if chunk then
288+
-- process
289+
end
290+
until not chunk
291+
```
292+
293+
# Author
328294

329295
James Hurst <james@pintsized.co.uk>
330296

331297
Originally started life based on https://github.com/bakins/lua-resty-http-simple. Cosocket docs and implementation borrowed from the other lua-resty-* cosocket modules.
332298

333299

334-
## Licence
300+
# Licence
335301

336302
This module is licensed under the 2-clause BSD license.
337303

0 commit comments

Comments
 (0)