Skip to content

Commit 00ede89

Browse files
committed
Merge branch 'cookies'
2 parents 921e04d + 23af6d1 commit 00ede89

File tree

13 files changed

+1665
-7
lines changed

13 files changed

+1665
-7
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ UNRELEASED
44
- Fix incorrect timeout handling in `websocket:receive()`
55
- Add workaround to allow being required in openresty (#98)
66
- Add http.tls.old_cipher_list (#112)
7+
- Add http.cookie module (#117)
78

89

910
0.2 - 2017-05-28

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Optionally asynchronous (including DNS lookups and TLS)
66
- Supports HTTP(S) version 1.0, 1.1 and 2
77
- Functionality for both client and server
8+
- Cookie Management
89
- Websockets
910
- Compatible with Lua 5.1, 5.2, 5.3 and [LuaJIT](http://luajit.org/)
1011

@@ -34,12 +35,17 @@ This will automatically install run-time lua dependencies for you.
3435
- [basexx](https://github.com/aiq/basexx/) >= 0.2.0
3536
- [lpeg](http://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html)
3637
- [lpeg_patterns](https://github.com/daurnimator/lpeg_patterns) >= 0.5
38+
- [binaryheap.lua](https://github.com/Tieske/binaryheap.lua)
3739
- [fifo](https://github.com/daurnimator/fifo.lua)
3840

3941
To use gzip compression you need **one** of:
4042

4143
- [lzlib](https://github.com/LuaDist/lzlib) or [lua-zlib](https://github.com/brimworks/lua-zlib)
4244

45+
To check cookies against a public suffix list:
46+
47+
- [lua-psl](https://github.com/daurnimator/lua-psl)
48+
4349
If using lua < 5.3 you will need
4450

4551
- [compat-5.3](https://github.com/keplerproject/lua-compat-5.3) >= 0.3

doc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ INTERFACES = \
55
MODULES = \
66
http.bit.md \
77
http.client.md \
8+
http.cookie.md \
89
http.h1_connection.md \
910
http.h1_reason_phrases.md \
1011
http.h1_stream.md \

doc/modules/http.cookie.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
## http.cookie
2+
3+
A module for working with cookies.
4+
5+
### `bake(name, value, expiry_time, domain, path, secure_only, http_only, same_site)` <!-- --> {#http.cookie.bake}
6+
7+
Returns a string suitable for use in a `Set-Cookie` header with the passed parameters.
8+
9+
10+
### `parse_cookie(cookie)` <!-- --> {#http.cookie.parse_cookie}
11+
12+
Parses the `Cookie` header contents `cookie`.
13+
14+
Returns a table containing `name` and `value` pairs as strings.
15+
16+
17+
### `parse_cookies(req_headers)` <!-- --> {#http.cookie.parse_cookies}
18+
19+
Parses all `Cookie` headers in the [*http.headers*](#http.headers) object `req_headers`.
20+
21+
Returns a table containing `name` and `value` pairs as strings.
22+
23+
24+
### `parse_setcookie(setcookie)` <!-- --> {#http.cookie.parse_setcookie}
25+
26+
Parses the `Set-Cookie` header contents `setcookie`.
27+
28+
Returns `name`, `value` and `params` where:
29+
30+
- `name` is a string containing the cookie name
31+
- `value` is a string containing the cookie value
32+
- `params` is the a table where the keys are cookie attribute names and values are cookie attribute values
33+
34+
35+
### `new_store()` <!-- --> {#http.cookie.new_store}
36+
37+
Creates a new cookie store.
38+
39+
Cookies are unique for a tuple of domain, path and name;
40+
although multiple cookies with the same name may exist in a request due to overlapping paths or domains.
41+
42+
43+
### `store.psl` <!-- --> {#http.cookie.store.psl}
44+
45+
A [lua-psl](https://github.com/daurnimator/lua-psl) object to use for checking against the Public Suffix List.
46+
Set the field to `false` to skip checking the suffix list.
47+
48+
Defaults to the [latest](https://rockdaboot.github.io/libpsl/libpsl-Public-Suffix-List-functions.html#psl-latest) PSL on the system. If lua-psl is not installed then it will be `nil`.
49+
50+
51+
### `store.time()` <!-- --> {#http.cookie.store.time}
52+
53+
A function used by the `store` to get the current time for expiries and such.
54+
55+
Defaults to a function based on [`os.time`](https://www.lua.org/manual/5.3/manual.html#pdf-os.time).
56+
57+
58+
### `store.max_cookie_length` <!-- --> {#http.cookie.store.max_cookie_length}
59+
60+
The maximum length (in bytes) of cookies in the store; this value is also used as default maximum cookie length for `:lookup()`.
61+
Decreasing this value will only prevent new cookies from being added, it will not remove old cookies.
62+
63+
Defaults to infinity (no maximum size).
64+
65+
66+
### `store.max_cookies` <!-- --> {#http.cookie.store.max_cookies}
67+
68+
The maximum number of cookies allowed in the `store`.
69+
Decreasing this value will only prevent new cookies from being added, it will not remove old cookies.
70+
71+
Defaults to infinity (any number of cookies is allowed).
72+
73+
74+
### `store.max_cookies_per_domain` <!-- --> {#http.cookie.store.max_cookies_per_domain}
75+
76+
The maximum number of cookies allowed in the `store` per domain.
77+
Decreasing this value will only prevent new cookies from being added, it will not remove old cookies.
78+
79+
Defaults to infinity (any number of cookies is allowed).
80+
81+
82+
### `store:store(req_domain, req_path, req_is_http, req_is_secure, req_site_for_cookies, name, value, params)` <!-- --> {#http.cookie.store:store}
83+
84+
Attempts to add a cookie to the `store`.
85+
86+
- `req_domain` is the domain that the cookie was obtained from
87+
- `req_path` is the path that the cookie was obtained from
88+
- `req_is_http` is a boolean flag indicating if the cookie was obtained from a "non-HTTP" API
89+
- `req_is_secure` is a boolean flag indicating if the cookie was obtained from a "secure" protocol
90+
- `req_site_for_cookies` is a string containing the host that should be considered as the "site for cookies" (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2)), can be `nil` if unknown.
91+
- `name` is a string containing the cookie name
92+
- `value` is a string containing the cookie value
93+
- `params` is the a table where the keys are cookie attribute names and values are cookie attribute values
94+
95+
Returns a boolean indicating if a cookie was stored.
96+
97+
98+
### `store:store_from_request(req_headers, resp_headers, req_host, req_site_for_cookies)` <!-- --> {#http.cookie.store:store_from_request}
99+
100+
Attempt to store any cookies found in the response headers.
101+
102+
- `req_headers` is the [*http.headers*](#http.headers) object for the outgoing request
103+
- `resp_headers` is the [*http.headers*](#http.headers) object received in response
104+
- `req_host` is the host that your query was directed at (only used if `req_headers` is missing a `Host` header)
105+
- `req_site_for_cookies` is a string containing the host that should be considered as the "site for cookies" (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2)), can be `nil` if unknown.
106+
107+
108+
### `store:get(domain, path, name)` <!-- --> {#http.cookie.store:get}
109+
110+
Returns the cookie value for the cookie stored for the passed `domain`, `path` and `name`.
111+
112+
113+
### `store:remove(domain, path, name)` <!-- --> {#http.cookie.store:remove}
114+
115+
Deletes the cookie stored for the passed `domain`, `path` and `name`.
116+
117+
If `name` is `nil` or not passed then all cookies for the `domain` and `path` are removed.
118+
119+
If `path` is `nil` or not passed (in addition to `name`) then all cookies for the `domain` are removed.
120+
121+
122+
### `store:lookup(domain, path, is_http, is_secure, is_safe_method, site_for_cookies, is_top_level, max_cookie_length)` <!-- --> {#http.cookie.store:lookup}
123+
124+
Finds cookies visible to suitable for passing to an entity.
125+
126+
- `domain` is the domain that will be sent the cookie
127+
- `path` is the path that will be sent the cookie
128+
- `is_http` is a boolean flag indicating if the destination is a "non-HTTP" API
129+
- `is_secure` is a boolean flag indicating if the destination will be communicated with over a "secure" protocol
130+
- `is_safe_method` is a boolean flag indicating if the cookie will be sent via a safe HTTP method (See also [http.util.is_safe_method](#http.util.is_safe_method))
131+
- `site_for_cookies` is a string containing the host that should be considered as the "site for cookies" (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2)), can be `nil` if unknown.
132+
- `is_top_level` is a boolean flag indicating if this request is a "top level" request (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2))
133+
- `max_cookie_length` is the maximum cookie length to allow (See also [`store.max_cookie_length`](#http.cookie.store.max_cookie_length))
134+
135+
Returns a string suitable for use in a `Cookie` header.
136+
137+
138+
### `store:lookup_for_request(headers, host, site_for_cookies, is_top_level, max_cookie_length)` <!-- --> {#http.cookie.store:lookup_for_request}
139+
140+
Finds cookies suitable for adding to a request.
141+
142+
- `headers` is the [*http.headers*](#http.headers) object for the outgoing request
143+
- `host` is the host that your query was directed at (only used if `headers` is missing a `Host` header)
144+
- `site_for_cookies` is a string containing the host that should be considered as the "site for cookies" (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2)), can be `nil` if unknown.
145+
- `is_top_level` is a boolean flag indicating if this request is a "top level" request (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2))
146+
- `max_cookie_length` is the maximum cookie length to allow (See also [`store.max_cookie_length`](#http.cookie.store.max_cookie_length))
147+
148+
Returns a string suitable for use in a `Cookie` header.
149+
150+
151+
### `store:clean_due()` <!-- --> {#http.cookie.store:clean_due}
152+
153+
Returns the number of seconds until the next cookie in the `store` expires.
154+
155+
156+
### `store:clean()` <!-- --> {#http.cookie.store:clean}
157+
158+
Remove all expired cookies from the `store`.
159+
160+
161+
### `store:load_from_file(file)` <!-- --> {#http.cookie.store:load_from_file}
162+
163+
Loads cookie data from the file object `file` into `store`.
164+
The file should be in the Netscape Cookiejar format.
165+
Invalid lines in the file are ignored.
166+
167+
Returns `true` on success or passes along `nil, err, errno` if a `:read` call fails.
168+
169+
170+
### `store:save_to_file(file)` <!-- --> {#http.cookie.store:save_to_file}
171+
172+
Writes the cookie data from `store` into the file object `file` in the Netscape Cookiejar format.
173+
`file` is not `seek`-ed or truncated before writing.
174+
175+
Returns `true` on success or passes along `nil, err, errno` if a `:write` call fails.

doc/modules/http.request.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,28 @@ The value should be a URI or `false` to turn off proxying for the request.
6363
A [*http.headers*](#http.headers) object of headers that will be sent in the request.
6464

6565

66+
### `request.cookie_store` <!-- --> {#http.request.cookie_store}
67+
68+
The [*http.cookie.store*](#http.cookie.store) that will be used to find cookies for the request.
69+
An attempt will be made to add cookies from a response to the store.
70+
71+
Defaults to a shared store.
72+
73+
74+
### `request.is_top_level` <!-- --> {#http.request.is_top_level}
75+
76+
A boolean flag indicating if this request is a "top level" request (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2))
77+
78+
Defaults to `true`
79+
80+
81+
### `request.site_for_cookies` <!-- --> {#http.request.site_for_cookies}
82+
83+
A string containing the host that should be considered as the "site for cookies" (See [RFC 6265bis-02 Section 5.2](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02#section-5.2)), can be `nil` if unknown.
84+
85+
Defaults to `nil`.
86+
87+
6688
### `request.follow_redirects` <!-- --> {#http.request.follow_redirects}
6789

6890
Boolean indicating if `:go()` should follow redirects.

doc/modules/http.util.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ print(http_util.dict_to_query({foo = "bar"; baz = "qux"})) --> "baz=qux&foo=bar"
4545
### `resolve_relative_path(orig_path, relative_path)` <!-- --> {#http.util.resolve_relative_path}
4646

4747

48+
### `is_safe_method(method)` <!-- --> {#http.util.is_safe_method}
49+
50+
Returns a boolean indicating if the passed string `method` is a "safe" method.
51+
See [RFC 7231 section 4.2.1](https://tools.ietf.org/html/rfc7231#section-4.2.1) for more information.
52+
53+
54+
### `is_ip(str)` <!-- --> {#http.util.is_ip}
55+
56+
Returns a boolean indicating if the passed string `str` is a valid IP.
57+
58+
4859
### `scheme_to_port` <!-- --> {#http.util.scheme_to_port}
4960

5061
Map from schemes (as strings) to default ports (as integers).

http-scm-0.rockspec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ dependencies = {
2020
"basexx >= 0.2.0";
2121
"lpeg";
2222
"lpeg_patterns >= 0.5";
23+
"binaryheap >= 0.3";
2324
"fifo";
25+
-- "psl"; -- Optional
2426
}
2527

2628
build = {
@@ -29,6 +31,7 @@ build = {
2931
["http.bit"] = "http/bit.lua";
3032
["http.client"] = "http/client.lua";
3133
["http.connection_common"] = "http/connection_common.lua";
34+
["http.cookie"] = "http/cookie.lua";
3235
["http.h1_connection"] = "http/h1_connection.lua";
3336
["http.h1_reason_phrases"] = "http/h1_reason_phrases.lua";
3437
["http.h1_stream"] = "http/h1_stream.lua";

http/client.lua

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
local ca = require "cqueues.auxlib"
22
local cs = require "cqueues.socket"
33
local http_tls = require "http.tls"
4+
local http_util = require "http.util"
45
local connection_common = require "http.connection_common"
56
local onerror = connection_common.onerror
67
local new_h1_connection = require "http.h1_connection".new
@@ -9,11 +10,6 @@ local openssl_ssl = require "openssl.ssl"
910
local openssl_ctx = require "openssl.ssl.context"
1011
local openssl_verify_param = require "openssl.x509.verify_param"
1112

12-
local EOF = require "lpeg".P(-1)
13-
local IPv4address = require "lpeg_patterns.IPv4".IPv4address
14-
local IPv6addrz = require "lpeg_patterns.IPv6".IPv6addrz
15-
local IPaddress = (IPv4address + IPv6addrz) * EOF
16-
1713
-- Create a shared 'default' TLS context
1814
local default_ctx = http_tls.new_client_context()
1915

@@ -24,7 +20,7 @@ local function negotiate(s, options, timeout)
2420
if tls then
2521
local ctx = options.ctx or default_ctx
2622
local ssl = openssl_ssl.new(ctx)
27-
local ip = options.host and IPaddress:match(options.host)
23+
local ip = options.host and http_util.is_ip(options.host)
2824
if options.sendname ~= nil then
2925
if options.sendname then -- false indicates no sendname wanted
3026
ssl:setHostName(options.sendname)

0 commit comments

Comments
 (0)