NAME
Cookie::Jar - A minimalist HTTP cookie jar
SYNOPSIS
use Cookie::Jar;
my $cookies = Cookie::Jar.new;
$cookies.add: 'https://example.com', 'foo=123; Domain=example.com';
$cookies.add: 'https://example.com', 'bar=234';
say "{ .name } -> { .value }" for $cookies.get: 'GET', 'https://example.com';
# OUTPUT:
# foo -> 123
# bar -> 234
# The 'bar' cookie does not apply to this subdomain
say $cookies.header: 'GET', 'https://www.example.com';
# OUTPUT:
# foo=123
# Cookies can persist on filesystem
my $other = $jar.save('cookie.jar').load('cookie.jar');
DESCRIPTION
This is a minimal class to manage HTTP cookies. It can be used together with
a HTTP client class like HTTP::Tiny to manage cookies received in HTTP
responses and determine the cookies that apply on new requests.
Unlike other alternatives available at the time of writing, user agents
desiring to integrate with this class do not need to use a specific class
to represent the request, the response, or the cookie: all that is required
is the request URL and the headers received from the server.
The operations on this library should be thread-safe.
METHODS
Some of the methods below take a request URL parameter. In compliance with
RFC 6265, these are all canonicalised to their ASCII "punycode"
representation before processing.
Likewise, the methods in this class that return cookies (like get and
dump described below) return a read-only opaque cookie object with
the following available methods:
The Cookie Object
creation-time
A DateTime marking the moment the cookie was created. This could be before
the jar was created if the cookie was loaded from external storage with
load. This attribute is internal, and does not conflict with an
extension of the same name.
domain
Returns a Str with the cookie's domain. If the cookie did not have a domain
initially, this will be the domain the cookie was received from.
expired
Returns a Bool that will be true if the cookie is persistent and its
expiration date is in the past. It can optionally take a DateTime object to be
used instead of the current timestamp.
expires
Returns a DateTime with the cookie's expiration time. This might be a type
object if the cookie is not persistent.
host-only
Returns a Bool specifying whether the cookie should apply to domains other
than the one in its "domain" attribute. This attribute can also be called as
hostonly
.
http-only
Returns a Bool specifying whether this cookie should be included in non-HTTP
requests (this is of little use for Raku user-agents). This attribute can
also be called as httponly
.
last-access-time
Returns a DateTime specifying when the cookie was last matched for a given
URL (using the get or header methods). This attribute is
internal, and does not conflict with an extension of the same name.
name
Returns a Str with the cookie name. This attribute is internal, and does not
conflict with an extension of the same name.
path
Returns a Str with the path the cookie applies to.
persistent
Returns a Bool which will be true if the cookie has a defined expiration date.
secure
Returns a Bool specifying whether this cookie should be sent over non-secure
channels. Cookies with this attribute set to a true value will only be matched
for HTTPS requests.
value
Returns a Str with the value of the cookie. No effort is made by Cookie::Jar to
parse or otherwise decode this value. This attribute is internal, and does not
conflict with an extension of the same name.
get
Takes a key that will be matched case-insensitively to a cookie attribute.
The key can be any of the ones mentioned above, or the name of any of the
cookie's extensions. If the cookie does not have an attribute with that
name this method will return False. Otherwise, the value of the attribute
will be returned, or True if the attribute has no value. If the cookie was
set with an attribute with the same name as one of the fields described as
"internal" above (eg. 'creation-time' and 'last-access-time', etc), using
that key with this method will return the extension.
new
method new () returns Cookie::Jar
Creates a new Cookie::Jar object. The constructor takes no parameters.
To construct a Cookie::Jar with cookies that have been saved on a previous
session (with the save method), see the load method below.
add
method add (
Str:D $url,
Str:D $cookie-string,
) returns Bool
Add a new cookie to the internal storage.
This method takes a URL and a Set-Cookie
header string (received from making
a request to that URL) and adds the cookie to the jar. If the cookie is
expired, any matching cookie is deleted as described in RFC 6265 § 4.1.2.
If the PublicSuffix module is available, it will be used to validate cookie
domains and reject supercookies.
Returns True if the cookie was successfully added, or False otherwise.
dump
method dump () returns Hash
This method offers some introspection by returns a Hash representation of the
internal storage used by the jar.
The data structure store cookies indexed by nested domain, path, and cookie
name keys, as in the following example:
{
'example.com' => {
'/path' => {
'SID' => ..., # see below for details on cookie values
}
},
}
Cookies in this structure (the parts represented by the ellipsis) will be
returned as an internal read-only Cookie object. For details on this Cookie
object, see above.
get
method get (
Str:D $method,
Str:D $url,
) returns List
Takes a request method and URL and returns a (possibly empty) list of cookies
that would apply to a request made to that URL, as described in
RFC 6265 § 5.4. The order of the cookies in the list follows the same order
they would take in a Cookie
header sent with that request, as per the
document above.
The method must be one of CONNECT
, DELETE
, GET
, HEAD
, OPTIONS
,
PATCH
, POST
, PUT
, or TRACE
, and will be matched case-sensitively, as
per HTTP/1.1 specification.
Elements in the list will be internal read-only Cookie objects. For details on
this Cookie object, see above.
method header (
Str:D $method,
Str:D $url,
) returns Str
Takes a request method and URL and returns a (possibly empty) string suitable
to be used as the Cookie
header sent to a request made to that URL. The
order of the cookies in the string follows the order described in
RFC 6265 § 5.4.
The method must be one of CONNECT
, DELETE
, GET
, HEAD
, OPTIONS
,
PATCH
, POST
, PUT
, or TRACE
, and will be matched case-sensitively, as
per HTTP/1.1 specification.
This method calls get internally.
clear
multi method clear ( ) returns Cookie::Jar
multi method clear (
Str $url,
*@names,
) returns Cookie::Jar
Clear the internal storage of the jar.
When called with no arguments, all values will be deleted.
This method can alternatively be called with a URL and a possibly empty list
of cookie names. In this case cookies that would match a request made to that
URL (as per the same rules used by the get method), and possibly one
of the names provided, then those matching cookies will be deleted.
save
method save (
IO() $path,
Bool() :$netscape,
Bool() :$all,
) returns Cookie::Jar
Save the internal storage into a cookie file. This file will is suitable to be
read with the load method below. Only persistent cookies will be saved,
unless the :all
flag is set to a true value.
By default, the file will be written using an internal format used by
Cookie::Jar. If the :netscape
flag is set to a true value, the file will
instead use the Netscape HTTP Cookie File format, compatible with those
created by libcurl
.
This method returns the calling object.
load
method load (
IO() $path,
Bool() :$netscape,
) returns Cookie::Jar
Load cookies from a cookie file, like that generated with save.
If called on an existing instance, the internal storage will be cleared before
reading the input file. This method can also be called on a Cookie::Jar type
object to be used as a constructor.
In both cases, this method will return a Cookie::Jar object with the cookies
loaded from the read file.
By default, the file is assumed to use the internal Cookie::Jar format.
If the file is found to have a Netscape HTTP Cookie File header instead
(like the one generated by libcurl
), the file will be parsed as such.
Setting the :netscape
flag to a true value enforces this, such that
providing a file missing this header is an error.
LIMITATIONS
Cookie::Jar aims to be conditionally compliant with the HTTP State
Management Mechanism RFC 6265.
It aims to meet all "MUST" requirements of the specification, but only some of
the "SHOULD" requirements.
Some particular limitations of note include:
Cookie::Jar does no support features that were obsoleted by RFC 6265.
This includes the Cookie2
and Set-Cookie2
headers, .local
suffixes,
etc.
Since RFC 6265 is the only current specification of HTTP cookie
behaviour, Cookie::Jar does not support features that are not described
in it. This includes features like SameSite.
SEE ALSO
Other cookie jars
Cro::HTTP::Client::CookieJar
Shipped as part of Cro::HTTP and is used by that client. The client cannot
be configured to use another cookie jar.
HTTP::Cookies
Shipped as part of HTTP::UserAgent and is used by that client. The client
cannot be configured to use another cookie jar.
Additional Features
Cookie::Baker provides two functions, one of which, bake-cookie
, can be
used to convert a Hash into a string that can be used as a Cookie
header.
This can be used together with the add method to add a cookie from a
set of key-value pairs.
If this distribution is installed, Cookie::Jar will use it to verify cookie
domains against the list of public suffixes, as described in step 5 of
RFC 6265 § 5.3. This should help avoid supercookies.
AUTHOR
José Joaquín Atria jjatria@cpan.org
ACKNOWLEDGEMENTS
Other than the cookie jars mentioned above, the code and API in this
distribution takes inspiration from a number of similar Perl libraries.
In particular:
This module owes a debt of gratitude to their authors and those who have
contributed to them, and to their choice to make their code and work publicly
available.
COPYRIGHT AND LICENSE
Copyright 2022 José Joaquín Atria
This library is free software; you can redistribute it and/or modify it under
the Artistic License 2.0.