Help language development. Donate to The Perl Foundation
Cookie::Jar - A minimalist HTTP cookie jar
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');
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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
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.
Shipped as part of Cro::HTTP and is used by that client. The client cannot be configured to use another cookie jar.
Shipped as part of HTTP::UserAgent and is used by that client. The client cannot be configured to use another cookie jar.
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.
José Joaquín Atria [email protected]
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 2022 José Joaquín Atria
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.