HTTP-Cookies-6.12 000755 001750 001751 0 15231271120 12633 5 ustar 00olaf olaf 000000 000000 LICENSE 100644 001750 001751 46270 15231271120 13752 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 This software is copyright (c) 2002 by Gisle Aas.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
Terms of the Perl programming language system itself
a) the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any
later version, or
b) the "Artistic License"
--- The GNU General Public License, Version 1, February 1989 ---
This software is Copyright (c) 2002 by Gisle Aas.
This is free software, licensed under:
The GNU General Public License, Version 1, February 1989
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must tell them their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work based
on the Program" means either the Program or any work containing the
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program or any portion of
it, and copy and distribute such modifications under the terms of Paragraph
1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating that
you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish, that
in whole or in part contains the Program or any part thereof, either
with or without modifications, to be licensed at no charge to all
third parties under the terms of this General Public License (except
that you may choose to grant warranty protection to some or all
third parties, at your option).
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a fee for the physical act of transferring a
copy, and you may at your option offer warranty protection in
exchange for a fee.
Mere aggregation of another independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the Program (or a portion or derivative of
it, under Paragraph 2) in object code or executable form under the terms of
Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal charge
for the cost of distribution) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
Source code for a work means the preferred form of the work for making
modifications to it. For an executable file, complete source code means
all the source code for all modules it contains; but, as a special
exception, it need not include source code for modules which are standard
libraries that accompany the operating system on which the executable
file runs, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License. However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.
5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.
7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of the license which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
the license, you may choose any version ever published by the Free Software
Foundation.
8. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
Copyright (C) 19yy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
program `Gnomovision' (a program to direct compilers to make passes
at assemblers) written by James Hacker.
, 1 April 1989
Moe Ghoul, President of Vice
That's all there is to it!
--- The Perl Artistic License 1.0 ---
This software is Copyright (c) 2002 by Gisle Aas.
This is free software, licensed under:
The Perl Artistic License 1.0
The "Artistic License"
Preamble
The intent of this document is to state the conditions under which a
Package may be copied, such that the Copyright Holder maintains some
semblance of artistic control over the development of the package,
while giving the users of the package the right to use and distribute
the Package in a more-or-less customary fashion, plus the right to make
reasonable modifications.
Definitions:
"Package" refers to the collection of files distributed by the
Copyright Holder, and derivatives of that collection of files
created through textual modification.
"Standard Version" refers to such a Package if it has not been
modified, or has been modified in accordance with the wishes
of the Copyright Holder as specified below.
"Copyright Holder" is whoever is named in the copyright or
copyrights for the package.
"You" is you, if you're thinking about copying or distributing
this Package.
"Reasonable copying fee" is whatever you can justify on the
basis of media cost, duplication charges, time of people involved,
and so on. (You will not be required to justify it to the
Copyright Holder, but only to the computing community at large
as a market that must bear the fee.)
"Freely Available" means that no fee is charged for the item
itself, though there may be fees involved in handling the item.
It also means that recipients of the item may redistribute it
under the same conditions they received it.
1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated disclaimers.
2. You may apply bug fixes, portability fixes and other modifications
derived from the Public Domain or from the Copyright Holder. A Package
modified in such a way shall still be considered the Standard Version.
3. You may otherwise modify your copy of this Package in any way, provided
that you insert a prominent notice in each changed file stating how and
when you changed that file, and provided that you do at least ONE of the
following:
a) place your modifications in the Public Domain or otherwise make them
Freely Available, such as by posting said modifications to Usenet or
an equivalent medium, or placing the modifications on a major archive
site such as uunet.uu.net, or by allowing the Copyright Holder to include
your modifications in the Standard Version of the Package.
b) use the modified Package only within your corporation or organization.
c) rename any non-standard executables so the names do not conflict
with standard executables, which must also be provided, and provide
a separate manual page for each non-standard executable that clearly
documents how it differs from the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the following:
a) distribute a Standard Version of the executables and library files,
together with instructions (in the manual page or equivalent) on where
to get the Standard Version.
b) accompany the distribution with the machine-readable source of
the Package with your modifications.
c) give non-standard executables non-standard names, and clearly
document the differences in manual pages (or equivalent), together
with instructions on where to get the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of this
Package. You may charge any fee you choose for support of this
Package. You may not charge a fee for this Package itself. However,
you may distribute this Package in aggregate with other (possibly
commercial) programs as part of a larger (possibly commercial) software
distribution provided that you do not advertise this Package as a
product of your own. You may embed this Package's interpreter within
an executable of yours (by linking); this shall be construed as a mere
form of aggregation, provided that the complete Standard Version of the
interpreter is so embedded.
6. The scripts and library files supplied as input to or produced as
output from the programs of this Package do not automatically fall
under the copyright of this Package, but belong to whoever generated
them, and may be sold commercially, and may be aggregated with this
Package. If such scripts or library files are aggregated with this
Package via the so-called "undump" or "unexec" methods of producing a
binary executable image, then distribution of such an image shall
neither be construed as a distribution of this Package nor shall it
fall under the restrictions of Paragraphs 3 and 4, provided that you do
not represent such an executable image as a Standard Version of this
Package.
7. C subroutines (or comparably compiled subroutines in other
languages) supplied by you and linked into this Package in order to
emulate subroutines and variables of the language defined by this
Package shall not be considered part of this Package, but are the
equivalent of input as in Paragraph 6, provided these subroutines do
not change the language in any way that would cause it to fail the
regression tests for the language.
8. Aggregation of this Package with a commercial distribution is always
permitted provided that the use of this Package is embedded; that is,
when no overt attempt is made to make this Package's interfaces visible
to the end user of the commercial distribution. Such use shall not be
construed as a distribution of this Package.
9. The name of the Copyright Holder may not be used to endorse or promote
products derived from this software without specific prior written permission.
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End
INSTALL 100644 001750 001751 4553 15231271120 13754 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 This is the Perl distribution HTTP-Cookies.
Installing HTTP-Cookies is straightforward.
## Installation with cpanm
If you have cpanm, you only need one line:
% cpanm HTTP::Cookies
If it does not have permission to install modules to the current perl, cpanm
will automatically set up and install to a local::lib in your home directory.
See the local::lib documentation (https://metacpan.org/pod/local::lib) for
details on enabling it in your environment.
## Installing with the CPAN shell
Alternatively, if your CPAN shell is set up, you should just be able to do:
% cpan HTTP::Cookies
## Manual installation
As a last resort, you can manually install it. If you have not already
downloaded the release tarball, you can find the download link on the module's
MetaCPAN page: https://metacpan.org/pod/HTTP::Cookies
Untar the tarball, install configure prerequisites (see below), then build it:
% perl Makefile.PL
% make && make test
Then install it:
% make install
On Windows platforms, you should use `dmake` or `nmake`, instead of `make`.
If your perl is system-managed, you can create a local::lib in your home
directory to install modules to. For details, see the local::lib documentation:
https://metacpan.org/pod/local::lib
The prerequisites of this distribution will also have to be installed manually. The
prerequisites are listed in one of the files: `MYMETA.yml` or `MYMETA.json` generated
by running the manual build process described above.
## Configure Prerequisites
This distribution requires other modules to be installed before this
distribution's installer can be run. They can be found under the
"configure_requires" key of META.yml or the
"{prereqs}{configure}{requires}" key of META.json.
## Other Prerequisites
This distribution may require additional modules to be installed after running
Makefile.PL.
Look for prerequisites in the following phases:
* to run make, PHASE = build
* to use the module code itself, PHASE = runtime
* to run tests, PHASE = test
They can all be found in the "PHASE_requires" key of MYMETA.yml or the
"{prereqs}{PHASE}{requires}" key of MYMETA.json.
## Documentation
HTTP-Cookies documentation is available as POD.
You can run `perldoc` from a shell to read the documentation:
% perldoc HTTP::Cookies
For more information on installing Perl modules via CPAN, please see:
https://www.cpan.org/modules/INSTALL.html
Changes 100644 001750 001751 5351 15231271120 14213 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 Revision history for HTTP-Cookies. The HTTP::Cookies module used to be bundled
with the libwww-perl distribution.
6.12 2026-07-26 02:34:52Z
- Honour Max-Age when extracting cookies; it had been silently ignored
since 6.10, so Max-Age=0 no longer deleted a cookie and a Max-Age
lifetime was never applied (GH#69) (reported by Robert Mueller)
- When both Max-Age and Expires are present, let Max-Age take precedence
regardless of order, and let a repeated attribute's last value win, per
RFC 6265 5.3 (GH#69)
6.11 2023-12-07 16:36:52Z
- Replace "Test" with "Test::More" (GH#70) (James Raspass)
6.10 2021-01-04 22:03:43Z
- Do not set discard if max-age is set (GH#61) (robnagler, simbabque)
- Add tests for #61 - do not set discard if max-age is set (GH#65) (Julien Fiegehenn)
6.09 2020-11-19 22:20:47Z
- Allow HttpOnly cookies to be loaded by HTTP::Cookies::Netscape (GH#63)
(Charlie Hothersall-Thomas)
6.08 2019-12-02 15:58:32Z
- allow different "ignore_discard" value at save() time (GH#2) (Alex Peters)
6.07 2019-11-15 18:11:42Z
- Fix t/issue32.t on old perl versions (GH#59) (Bernhard M. Wiedemann)
6.06 2019-11-12 14:28:31Z
- Make test pass in 2025 (GH#56) (Bernhard M. Wiedemann)
6.05 2019-10-24 02:21:51Z
- Fix GH#32 by checking for " as well as ; when splitting. (GH#49) (colinnewell)
- Fix GH#48 update documentation about $version (GH#55) (Dave Menninger)
- Fix broken README badge (GH#54) (Alex Peters)
- Whenever possible, use an absolute four digit year for Time::Local (GH#52) (Olaf Alders)
- Add test case for Issue #26 (GH#45) (George-NG)
- Long numbers (GH#47) (pludlamCVL)
- Cookies.pm: die if close on $fh in ->save fails (GH#46) (MCRayRay)
- Replace "use vars" with "our" (GH#43) (James Raspass)
- Fixed minor typo in the pod for HTTP::Cookies. (GH#39) (Mohammad S Anwar)
6.04 2017-08-03 15:05:22Z
- Fix package version numbers
6.03 2017-04-03 11:35:35-04:00 America/Toronto
- No changes since TRIAL release 6.02
6.02 2017-01-12 18:02:49-05:00 America/Toronto (TRIAL RELEASE)
- Document the lack of Public Suffix https://publicsuffix.org/ support
- Add TODO tests for lack of Public Suffix support
- Improve "maxage" documentation
- Update the GitHub repository location
- Use GitHub Issues instead of RT
- Stop using bareword filehandles
- Various internal distribution management and testing changes
- Add get_cookies() method
6.01 2012-02-15
- Restore 5.8.1 compatiblity.
6.00 2011-02-27
- Initial release of HTTP-Cookies as a separate distribution. There are no
code changes besides incrementing the version number since
libwww-perl-5.837.
cpanfile 100644 001750 001751 2176 15231271120 14426 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 # This file is generated by Dist::Zilla::Plugin::CPANFile v6.037
# Do not edit this file directly. To change prereqs, edit the `dist.ini` file.
requires "Carp" => "0";
requires "HTTP::Date" => "6";
requires "HTTP::Headers::Util" => "6";
requires "HTTP::Request" => "0";
requires "locale" => "0";
requires "perl" => "5.008001";
requires "strict" => "0";
on 'test' => sub {
requires "ExtUtils::MakeMaker" => "0";
requires "File::Spec" => "0";
requires "HTTP::Response" => "0";
requires "Test::More" => "0.96";
requires "URI" => "0";
requires "warnings" => "0";
};
on 'test' => sub {
recommends "CPAN::Meta" => "2.120900";
};
on 'configure' => sub {
requires "ExtUtils::MakeMaker" => "0";
};
on 'develop' => sub {
requires "App::perlvars" => "0";
requires "Pod::Coverage::TrustPod" => "0";
requires "Test::CPAN::Changes" => "0.19";
requires "Test::EOL" => "0";
requires "Test::Mojibake" => "0";
requires "Test::More" => "0.96";
requires "Test::Pod" => "1.41";
requires "Test::Pod::Coverage" => "1.08";
requires "Test::Portability::Files" => "0";
requires "Test::Version" => "1";
requires "warnings" => "0";
};
META.yml 100644 001750 001751 45552 15231271120 14220 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 ---
abstract: 'HTTP cookie jars'
author:
- 'Gisle Aas '
build_requires:
ExtUtils::MakeMaker: '0'
File::Spec: '0'
HTTP::Response: '0'
Test::More: '0.96'
URI: '0'
warnings: '0'
configure_requires:
ExtUtils::MakeMaker: '0'
dynamic_config: 1
generated_by: 'Dist::Zilla version 6.037, CPAN::Meta::Converter version 2.150013'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: HTTP-Cookies
no_index:
directory:
- examples
- t
- xt
requires:
Carp: '0'
HTTP::Date: '6'
HTTP::Headers::Util: '6'
HTTP::Request: '0'
locale: '0'
perl: '5.008001'
strict: '0'
resources:
bugtracker: https://github.com/libwww-perl/HTTP-Cookies/issues
homepage: https://github.com/libwww-perl/HTTP-Cookies
repository: https://github.com/libwww-perl/HTTP-Cookies.git
version: '6.12'
x_Dist_Zilla:
perl:
version: '5.042002'
plugins:
-
class: Dist::Zilla::Plugin::Encoding
name: Encoding
version: '6.037'
-
class: Dist::Zilla::Plugin::OSPrereqs
config:
Dist::Zilla::Plugin::OSPrereqs:
os: MSWin32
name: MSWin32
version: '0.011'
-
class: Dist::Zilla::Plugin::AutoPrereqs
name: AutoPrereqs
version: '6.037'
-
class: Dist::Zilla::Plugin::Prereqs
config:
Dist::Zilla::Plugin::Prereqs:
phase: runtime
type: requires
name: Prereqs
version: '6.037'
-
class: Dist::Zilla::Plugin::PromptIfStale
config:
Dist::Zilla::Plugin::PromptIfStale:
check_all_plugins: 0
check_all_prereqs: 0
modules:
- Dist::Zilla::PluginBundle::Author::OALDERS
phase: build
run_under_travis: 0
skip: []
name: '@Author::OALDERS/stale modules, build'
version: '0.060'
-
class: Dist::Zilla::Plugin::PromptIfStale
config:
Dist::Zilla::Plugin::PromptIfStale:
check_all_plugins: 1
check_all_prereqs: 1
modules: []
phase: release
run_under_travis: 0
skip: []
name: '@Author::OALDERS/stale modules, release'
version: '0.060'
-
class: Dist::Zilla::Plugin::CheckChangesHasContent
name: '@Author::OALDERS/CheckChangesHasContent'
version: '0.011'
-
class: Dist::Zilla::Plugin::MakeMaker
config:
Dist::Zilla::Role::TestRunner:
default_jobs: '8'
name: '@Author::OALDERS/MakeMaker'
version: '6.037'
-
class: Dist::Zilla::Plugin::CPANFile
name: '@Author::OALDERS/CPANFile'
version: '6.037'
-
class: Dist::Zilla::Plugin::ContributorsFile
name: '@Author::OALDERS/ContributorsFile'
version: 0.4.0
-
class: Dist::Zilla::Plugin::MetaJSON
name: '@Author::OALDERS/MetaJSON'
version: '6.037'
-
class: Dist::Zilla::Plugin::MetaYAML
name: '@Author::OALDERS/MetaYAML'
version: '6.037'
-
class: Dist::Zilla::Plugin::Manifest
name: '@Author::OALDERS/Manifest'
version: '6.037'
-
class: Dist::Zilla::Plugin::MetaNoIndex
name: '@Author::OALDERS/MetaNoIndex'
version: '6.037'
-
class: Dist::Zilla::Plugin::MetaConfig
name: '@Author::OALDERS/MetaConfig'
version: '6.037'
-
class: Dist::Zilla::Plugin::MetaResources
name: '@Author::OALDERS/MetaResources'
version: '6.037'
-
class: Dist::Zilla::Plugin::License
name: '@Author::OALDERS/License'
version: '6.037'
-
class: Dist::Zilla::Plugin::InstallGuide
config:
Dist::Zilla::Role::ModuleMetadata:
Module::Metadata: '1.000038'
version: '0.006'
name: '@Author::OALDERS/InstallGuide'
version: '1.200014'
-
class: Dist::Zilla::Plugin::ExecDir
name: '@Author::OALDERS/ExecDir'
version: '6.037'
-
class: Dist::Zilla::Plugin::MojibakeTests
name: '@Author::OALDERS/MojibakeTests'
version: '0.8'
-
class: Dist::Zilla::Plugin::PodSyntaxTests
name: '@Author::OALDERS/PodSyntaxTests'
version: '6.037'
-
class: Dist::Zilla::Plugin::Test::CPAN::Changes
config:
Dist::Zilla::Plugin::Test::CPAN::Changes:
changelog: Changes
filename: xt/release/cpan-changes.t
name: '@Author::OALDERS/Test::CPAN::Changes'
version: '0.013'
-
class: Dist::Zilla::Plugin::Test::EOL
config:
Dist::Zilla::Plugin::Test::EOL:
filename: xt/author/eol.t
finder:
- ':ExecFiles'
- ':InstallModules'
- ':TestFiles'
trailing_whitespace: 1
name: '@Author::OALDERS/Test::EOL'
version: '0.19'
-
class: Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable
name: '@Author::OALDERS/Test::Pod::Coverage::Configurable'
version: '0.07'
-
class: Dist::Zilla::Plugin::Test::Portability
config:
Dist::Zilla::Plugin::Test::Portability:
options: ''
name: '@Author::OALDERS/Test::Portability'
version: '2.001003'
-
class: Dist::Zilla::Plugin::TestRelease
name: '@Author::OALDERS/TestRelease'
version: '6.037'
-
class: Dist::Zilla::Plugin::Test::ReportPrereqs
name: '@Author::OALDERS/Test::ReportPrereqs'
version: '0.029'
-
class: Dist::Zilla::Plugin::Test::Version
name: '@Author::OALDERS/Test::Version'
version: '1.09'
-
class: Dist::Zilla::Plugin::RunExtraTests
config:
Dist::Zilla::Role::TestRunner:
default_jobs: '8'
name: '@Author::OALDERS/RunExtraTests'
version: '0.029'
-
class: Dist::Zilla::Plugin::PodWeaver
config:
Dist::Zilla::Plugin::PodWeaver:
finder:
- ':InstallModules'
- ':PerlExecFiles'
plugins:
-
class: Pod::Weaver::Plugin::EnsurePod5
name: '@CorePrep/EnsurePod5'
version: '4.020'
-
class: Pod::Weaver::Plugin::H1Nester
name: '@CorePrep/H1Nester'
version: '4.020'
-
class: Pod::Weaver::Plugin::SingleEncoding
name: '@Default/SingleEncoding'
version: '4.020'
-
class: Pod::Weaver::Section::Name
name: '@Default/Name'
version: '4.020'
-
class: Pod::Weaver::Section::Version
name: '@Default/Version'
version: '4.020'
-
class: Pod::Weaver::Section::Region
name: '@Default/prelude'
version: '4.020'
-
class: Pod::Weaver::Section::Generic
name: SYNOPSIS
version: '4.020'
-
class: Pod::Weaver::Section::Generic
name: DESCRIPTION
version: '4.020'
-
class: Pod::Weaver::Section::Generic
name: OVERVIEW
version: '4.020'
-
class: Pod::Weaver::Section::Collect
name: ATTRIBUTES
version: '4.020'
-
class: Pod::Weaver::Section::Collect
name: METHODS
version: '4.020'
-
class: Pod::Weaver::Section::Collect
name: FUNCTIONS
version: '4.020'
-
class: Pod::Weaver::Section::Leftovers
name: '@Default/Leftovers'
version: '4.020'
-
class: Pod::Weaver::Section::Region
name: '@Default/postlude'
version: '4.020'
-
class: Pod::Weaver::Section::Authors
name: '@Default/Authors'
version: '4.020'
-
class: Pod::Weaver::Section::Legal
name: '@Default/Legal'
version: '4.020'
name: '@Author::OALDERS/PodWeaver'
version: '4.010'
-
class: Dist::Zilla::Plugin::PruneCruft
name: '@Author::OALDERS/PruneCruft'
version: '6.037'
-
class: Dist::Zilla::Plugin::CopyFilesFromBuild
name: '@Author::OALDERS/CopyFilesFromBuild'
version: '0.170880'
-
class: Dist::Zilla::Plugin::GithubMeta
name: '@Author::OALDERS/GithubMeta'
version: '0.58'
-
class: Dist::Zilla::Plugin::Git::GatherDir
config:
Dist::Zilla::Plugin::GatherDir:
exclude_filename:
- Install
- LICENSE
- META.json
- Makefile.PL
- README.md
- cpanfile
exclude_match: []
include_dotfiles: 0
prefix: ''
prune_directory: []
root: .
Dist::Zilla::Plugin::Git::GatherDir:
include_untracked: 0
name: '@Author::OALDERS/Git::GatherDir'
version: '2.052'
-
class: Dist::Zilla::Plugin::CopyFilesFromRelease
config:
Dist::Zilla::Plugin::CopyFilesFromRelease:
filename:
- Install
match: []
name: '@Author::OALDERS/CopyFilesFromRelease'
version: '0.007'
-
class: Dist::Zilla::Plugin::Git::Check
config:
Dist::Zilla::Plugin::Git::Check:
untracked_files: die
Dist::Zilla::Role::Git::DirtyFiles:
allow_dirty:
- Changes
- Install
- LICENSE
- META.json
- Makefile.PL
- README.md
- cpanfile
- dist.ini
allow_dirty_match: []
changelog: Changes
Dist::Zilla::Role::Git::Repo:
git_version: 2.43.0
repo_root: .
name: '@Author::OALDERS/Git::Check'
version: '2.052'
-
class: Dist::Zilla::Plugin::Git::Contributors
config:
Dist::Zilla::Plugin::Git::Contributors:
git_version: 2.43.0
include_authors: 0
include_releaser: 1
order_by: name
paths: []
name: '@Author::OALDERS/Git::Contributors'
version: '0.039'
-
class: Dist::Zilla::Plugin::ReadmeAnyFromPod
config:
Dist::Zilla::Role::FileWatcher:
version: '0.006'
name: '@Author::OALDERS/ReadmeMdInBuild'
version: '0.163250'
-
class: Dist::Zilla::Plugin::StaticInstall
config:
Dist::Zilla::Plugin::StaticInstall:
dry_run: 0
mode: off
name: '@Author::OALDERS/StaticInstall'
version: '0.012'
-
class: Dist::Zilla::Plugin::ShareDir
name: '@Author::OALDERS/ShareDir'
version: '6.037'
-
class: Dist::Zilla::Plugin::CheckIssues
name: '@Author::OALDERS/CheckIssues'
version: '0.011'
-
class: Dist::Zilla::Plugin::ConfirmRelease
name: '@Author::OALDERS/ConfirmRelease'
version: '6.037'
-
class: Dist::Zilla::Plugin::UploadToCPAN
name: '@Author::OALDERS/UploadToCPAN'
version: '6.037'
-
class: Dist::Zilla::Plugin::RewriteVersion::Transitional
config:
Dist::Zilla::Plugin::RewriteVersion:
add_tarball_name: 0
finders:
- ':ExecFiles'
- ':InstallModules'
global: 0
skip_version_provider: 0
Dist::Zilla::Plugin::RewriteVersion::Transitional: {}
name: '@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional'
version: '0.009'
-
class: Dist::Zilla::Plugin::MetaProvides::Update
name: '@Author::OALDERS/@Git::VersionManager/MetaProvides::Update'
version: '0.007'
-
class: Dist::Zilla::Plugin::CopyFilesFromRelease
config:
Dist::Zilla::Plugin::CopyFilesFromRelease:
filename:
- Changes
match: []
name: '@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease'
version: '0.007'
-
class: Dist::Zilla::Plugin::Git::Commit
config:
Dist::Zilla::Plugin::Git::Commit:
add_files_in: []
commit_msg: v%V%n%n%c
signoff: 0
Dist::Zilla::Role::Git::DirtyFiles:
allow_dirty:
- Changes
- Install
- LICENSE
- META.json
- Makefile.PL
- README.md
- cpanfile
- dist.ini
allow_dirty_match: []
changelog: Changes
Dist::Zilla::Role::Git::Repo:
git_version: 2.43.0
repo_root: .
Dist::Zilla::Role::Git::StringFormatter:
time_zone: local
name: '@Author::OALDERS/@Git::VersionManager/release snapshot'
version: '2.052'
-
class: Dist::Zilla::Plugin::Git::Tag
config:
Dist::Zilla::Plugin::Git::Tag:
branch: ~
changelog: Changes
signed: 0
tag: v6.12
tag_format: v%V
tag_message: v%V
Dist::Zilla::Role::Git::Repo:
git_version: 2.43.0
repo_root: .
Dist::Zilla::Role::Git::StringFormatter:
time_zone: local
name: '@Author::OALDERS/@Git::VersionManager/Git::Tag'
version: '2.052'
-
class: Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional
config:
Dist::Zilla::Plugin::BumpVersionAfterRelease:
finders:
- ':ExecFiles'
- ':InstallModules'
global: 0
munge_makefile_pl: 1
Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional: {}
name: '@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional'
version: '0.009'
-
class: Dist::Zilla::Plugin::NextRelease
name: '@Author::OALDERS/@Git::VersionManager/NextRelease'
version: '6.037'
-
class: Dist::Zilla::Plugin::Git::Commit
config:
Dist::Zilla::Plugin::Git::Commit:
add_files_in: []
commit_msg: 'increment $VERSION after %v release'
signoff: 0
Dist::Zilla::Role::Git::DirtyFiles:
allow_dirty:
- Build.PL
- Changes
- Makefile.PL
allow_dirty_match:
- (?^:^lib/.*\.pm$)
changelog: Changes
Dist::Zilla::Role::Git::Repo:
git_version: 2.43.0
repo_root: .
Dist::Zilla::Role::Git::StringFormatter:
time_zone: local
name: '@Author::OALDERS/@Git::VersionManager/post-release commit'
version: '2.052'
-
class: Dist::Zilla::Plugin::Git::Push
config:
Dist::Zilla::Plugin::Git::Push:
push_to:
- origin
remotes_must_exist: 1
Dist::Zilla::Role::Git::Repo:
git_version: 2.43.0
repo_root: .
name: '@Author::OALDERS/Git::Push'
version: '2.052'
-
class: Dist::Zilla::Plugin::BumpVersionAfterRelease
config:
Dist::Zilla::Plugin::BumpVersionAfterRelease:
finders:
- ':ExecFiles'
- ':InstallModules'
global: 0
munge_makefile_pl: 1
name: BumpVersionAfterRelease
version: '0.018'
-
class: Dist::Zilla::Plugin::Prereqs
config:
Dist::Zilla::Plugin::Prereqs:
phase: develop
type: requires
name: DevelopRequires
version: '6.037'
-
class: Dist::Zilla::Plugin::PruneFiles
name: PruneFiles
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':InstallModules'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':IncModules'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':TestFiles'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':ExtraTestFiles'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':ExecFiles'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':PerlExecFiles'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':ShareFiles'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':MainModule'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':AllFiles'
version: '6.037'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':NoFiles'
version: '6.037'
zilla:
class: Dist::Zilla::Dist::Builder
config:
is_trial: 0
version: '6.037'
x_contributors:
- 'Adam Kennedy '
- 'Adam Sjogren '
- 'Alexey Tourbin '
- 'Alex Kapranoff '
- 'Alex Peters '
- 'amire80 '
- 'Andreas J. Koenig '
- 'Bernhard M. Wiedemann '
- 'Bill Mann '
- 'Bron Gondwana '
- 'Charlie Hothersall-Thomas '
- 'Chase Whitener '
- 'Colin Newell '
- 'Daniel Hedlund '
- 'Dave Menninger '
- 'David E. Wheeler '
- 'DAVIDRW '
- 'dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>'
- 'Father Chrysostomos '
- 'FWILES '
- 'Gavin Peters '
- 'George Grozdev '
- 'Graeme Thompson '
- 'Hans-H. Froehlich '
- 'Ian Kilgore '
- 'Jacob J '
- 'James McCoy '
- 'James Raspass '
- 'jefflee '
- 'john9art '
- 'Julien Fiegehenn '
- 'Mark Raymond '
- 'Mark Stosberg '
- 'Michal Josef Špaček '
- 'Mike Schilli '
- 'Mohammad S Anwar '
- 'murphy '
- 'Olaf Alders '
- 'Ondrej Hanak '
- 'Perlover '
- 'Peter Rabbitson '
- 'Philip J. Ludlam '
- 'phrstbrn '
- 'Robert Stone '
- 'robnagler '
- 'Rolf Grossmann '
- 'ruff '
- 'sasao '
- 'Sean M. Burke '
- 'Slaven Rezic '
- 'Spiros Denaxas '
- 'Steve Hay '
- 'Todd Lipcon '
- 'Tom Hukins '
- 'Tony Finch '
- 'Toru Yamaguchi '
- 'Ville Skyttä '
- 'Yuri Karaban '
- 'Zefram '
x_generated_by_perl: v5.42.2
x_serialization_backend: 'YAML::Tiny version 1.76'
x_spdx_expression: 'Artistic-1.0-Perl OR GPL-1.0-or-later'
x_static_install: 0
MANIFEST 100644 001750 001751 1166 15231271120 14051 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 # This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.037
CONTRIBUTORS
Changes
INSTALL
LICENSE
MANIFEST
META.json
META.yml
Makefile.PL
README.md
cpanfile
dist.ini
lib/HTTP/Cookies.pm
lib/HTTP/Cookies/Microsoft.pm
lib/HTTP/Cookies/Netscape.pm
perlcriticrc
perlimports.toml
t/00-report-prereqs.dd
t/00-report-prereqs.t
t/10-original_spec.t
t/11-rfc_2965.t
t/cookies.t
t/data/netscape-httponly.txt
t/issue26.t
t/issue32.t
t/issue69.t
t/publicsuffix.t
xt/author/eol.t
xt/author/mojibake.t
xt/author/pod-coverage.t
xt/author/pod-syntax.t
xt/author/portability.t
xt/author/test-version.t
xt/release/cpan-changes.t
dist.ini 100644 001750 001751 1725 15231271120 14365 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 name = HTTP-Cookies
author = Gisle Aas
license = Perl_5
main_module = lib/HTTP/Cookies.pm
copyright_holder = Gisle Aas
copyright_year = 2002
[Encoding]
encoding = ISO-8859-1
filename = t/cookies.t
[OSPrereqs / MSWin32]
Win32 = 0
[AutoPrereqs]
skip = ^Win32
[Prereqs]
HTTP::Date = 6
HTTP::Headers::Util = 6
perl = 5.008001
[@Author::OALDERS]
-remove = AutoPrereqs
-remove = MinimumPerl
-remove = OALDERS::TidyAll
-remove = PkgVersion
-remove = PodCoverageTests
-remove = Prereqs
-remove = Test::Perl::Critic
-remove = Test::PodSpelling
-remove = Test::TidyAll
-remove = Test::Synopsis
StaticInstall.mode = off
StaticInstall.dry_run = 0
Test::Pod::Coverage::Configurable.skip = HTTP::Cookies::Microsoft
Test::Pod::Coverage::Configurable.trustme = HTTP::Cookies => qr/set_cookie_ok/
[BumpVersionAfterRelease]
[Prereqs / DevelopRequires]
App::perlvars = 0
[PruneFiles]
filename = precious.toml
filename = .perltidyrc
filename = scripts/pre-commit
META.json 100644 001750 001751 70511 15231271120 14361 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 {
"abstract" : "HTTP cookie jars",
"author" : [
"Gisle Aas "
],
"dynamic_config" : 1,
"generated_by" : "Dist::Zilla version 6.037, CPAN::Meta::Converter version 2.150013",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "HTTP-Cookies",
"no_index" : {
"directory" : [
"examples",
"t",
"xt"
]
},
"prereqs" : {
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"develop" : {
"requires" : {
"App::perlvars" : "0",
"Pod::Coverage::TrustPod" : "0",
"Test::CPAN::Changes" : "0.19",
"Test::EOL" : "0",
"Test::Mojibake" : "0",
"Test::More" : "0.96",
"Test::Pod" : "1.41",
"Test::Pod::Coverage" : "1.08",
"Test::Portability::Files" : "0",
"Test::Version" : "1",
"warnings" : "0"
}
},
"runtime" : {
"requires" : {
"Carp" : "0",
"HTTP::Date" : "6",
"HTTP::Headers::Util" : "6",
"HTTP::Request" : "0",
"locale" : "0",
"perl" : "5.008001",
"strict" : "0"
}
},
"test" : {
"recommends" : {
"CPAN::Meta" : "2.120900"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Spec" : "0",
"HTTP::Response" : "0",
"Test::More" : "0.96",
"URI" : "0",
"warnings" : "0"
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/libwww-perl/HTTP-Cookies/issues"
},
"homepage" : "https://github.com/libwww-perl/HTTP-Cookies",
"repository" : {
"type" : "git",
"url" : "https://github.com/libwww-perl/HTTP-Cookies.git",
"web" : "https://github.com/libwww-perl/HTTP-Cookies"
}
},
"version" : "6.12",
"x_Dist_Zilla" : {
"perl" : {
"version" : "5.042002"
},
"plugins" : [
{
"class" : "Dist::Zilla::Plugin::Encoding",
"name" : "Encoding",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::OSPrereqs",
"config" : {
"Dist::Zilla::Plugin::OSPrereqs" : {
"os" : "MSWin32"
}
},
"name" : "MSWin32",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::AutoPrereqs",
"name" : "AutoPrereqs",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "runtime",
"type" : "requires"
}
},
"name" : "Prereqs",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 0,
"check_all_prereqs" : 0,
"modules" : [
"Dist::Zilla::PluginBundle::Author::OALDERS"
],
"phase" : "build",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::OALDERS/stale modules, build",
"version" : "0.060"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 1,
"check_all_prereqs" : 1,
"modules" : [],
"phase" : "release",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::OALDERS/stale modules, release",
"version" : "0.060"
},
{
"class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
"name" : "@Author::OALDERS/CheckChangesHasContent",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::MakeMaker",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8"
}
},
"name" : "@Author::OALDERS/MakeMaker",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::CPANFile",
"name" : "@Author::OALDERS/CPANFile",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::ContributorsFile",
"name" : "@Author::OALDERS/ContributorsFile",
"version" : "0.4.0"
},
{
"class" : "Dist::Zilla::Plugin::MetaJSON",
"name" : "@Author::OALDERS/MetaJSON",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::MetaYAML",
"name" : "@Author::OALDERS/MetaYAML",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::Manifest",
"name" : "@Author::OALDERS/Manifest",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::MetaNoIndex",
"name" : "@Author::OALDERS/MetaNoIndex",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::MetaConfig",
"name" : "@Author::OALDERS/MetaConfig",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::MetaResources",
"name" : "@Author::OALDERS/MetaResources",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::License",
"name" : "@Author::OALDERS/License",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::InstallGuide",
"config" : {
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000038",
"version" : "0.006"
}
},
"name" : "@Author::OALDERS/InstallGuide",
"version" : "1.200014"
},
{
"class" : "Dist::Zilla::Plugin::ExecDir",
"name" : "@Author::OALDERS/ExecDir",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::MojibakeTests",
"name" : "@Author::OALDERS/MojibakeTests",
"version" : "0.8"
},
{
"class" : "Dist::Zilla::Plugin::PodSyntaxTests",
"name" : "@Author::OALDERS/PodSyntaxTests",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
"config" : {
"Dist::Zilla::Plugin::Test::CPAN::Changes" : {
"changelog" : "Changes",
"filename" : "xt/release/cpan-changes.t"
}
},
"name" : "@Author::OALDERS/Test::CPAN::Changes",
"version" : "0.013"
},
{
"class" : "Dist::Zilla::Plugin::Test::EOL",
"config" : {
"Dist::Zilla::Plugin::Test::EOL" : {
"filename" : "xt/author/eol.t",
"finder" : [
":ExecFiles",
":InstallModules",
":TestFiles"
],
"trailing_whitespace" : 1
}
},
"name" : "@Author::OALDERS/Test::EOL",
"version" : "0.19"
},
{
"class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
"name" : "@Author::OALDERS/Test::Pod::Coverage::Configurable",
"version" : "0.07"
},
{
"class" : "Dist::Zilla::Plugin::Test::Portability",
"config" : {
"Dist::Zilla::Plugin::Test::Portability" : {
"options" : ""
}
},
"name" : "@Author::OALDERS/Test::Portability",
"version" : "2.001003"
},
{
"class" : "Dist::Zilla::Plugin::TestRelease",
"name" : "@Author::OALDERS/TestRelease",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
"name" : "@Author::OALDERS/Test::ReportPrereqs",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::Test::Version",
"name" : "@Author::OALDERS/Test::Version",
"version" : "1.09"
},
{
"class" : "Dist::Zilla::Plugin::RunExtraTests",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8"
}
},
"name" : "@Author::OALDERS/RunExtraTests",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::PodWeaver",
"config" : {
"Dist::Zilla::Plugin::PodWeaver" : {
"finder" : [
":InstallModules",
":PerlExecFiles"
],
"plugins" : [
{
"class" : "Pod::Weaver::Plugin::EnsurePod5",
"name" : "@CorePrep/EnsurePod5",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Plugin::H1Nester",
"name" : "@CorePrep/H1Nester",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Plugin::SingleEncoding",
"name" : "@Default/SingleEncoding",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Name",
"name" : "@Default/Name",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Version",
"name" : "@Default/Version",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Default/prelude",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "SYNOPSIS",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "DESCRIPTION",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "OVERVIEW",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "ATTRIBUTES",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "METHODS",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "FUNCTIONS",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Leftovers",
"name" : "@Default/Leftovers",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Default/postlude",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Authors",
"name" : "@Default/Authors",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Legal",
"name" : "@Default/Legal",
"version" : "4.020"
}
]
}
},
"name" : "@Author::OALDERS/PodWeaver",
"version" : "4.010"
},
{
"class" : "Dist::Zilla::Plugin::PruneCruft",
"name" : "@Author::OALDERS/PruneCruft",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
"name" : "@Author::OALDERS/CopyFilesFromBuild",
"version" : "0.170880"
},
{
"class" : "Dist::Zilla::Plugin::GithubMeta",
"name" : "@Author::OALDERS/GithubMeta",
"version" : "0.58"
},
{
"class" : "Dist::Zilla::Plugin::Git::GatherDir",
"config" : {
"Dist::Zilla::Plugin::GatherDir" : {
"exclude_filename" : [
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile"
],
"exclude_match" : [],
"include_dotfiles" : 0,
"prefix" : "",
"prune_directory" : [],
"root" : "."
},
"Dist::Zilla::Plugin::Git::GatherDir" : {
"include_untracked" : 0
}
},
"name" : "@Author::OALDERS/Git::GatherDir",
"version" : "2.052"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Install"
],
"match" : []
}
},
"name" : "@Author::OALDERS/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
"config" : {
"Dist::Zilla::Plugin::Git::Check" : {
"untracked_files" : "die"
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Changes",
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile",
"dist.ini"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
}
},
"name" : "@Author::OALDERS/Git::Check",
"version" : "2.052"
},
{
"class" : "Dist::Zilla::Plugin::Git::Contributors",
"config" : {
"Dist::Zilla::Plugin::Git::Contributors" : {
"git_version" : "2.43.0",
"include_authors" : 0,
"include_releaser" : 1,
"order_by" : "name",
"paths" : []
}
},
"name" : "@Author::OALDERS/Git::Contributors",
"version" : "0.039"
},
{
"class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
"config" : {
"Dist::Zilla::Role::FileWatcher" : {
"version" : "0.006"
}
},
"name" : "@Author::OALDERS/ReadmeMdInBuild",
"version" : "0.163250"
},
{
"class" : "Dist::Zilla::Plugin::StaticInstall",
"config" : {
"Dist::Zilla::Plugin::StaticInstall" : {
"dry_run" : 0,
"mode" : "off"
}
},
"name" : "@Author::OALDERS/StaticInstall",
"version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::ShareDir",
"name" : "@Author::OALDERS/ShareDir",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::CheckIssues",
"name" : "@Author::OALDERS/CheckIssues",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::ConfirmRelease",
"name" : "@Author::OALDERS/ConfirmRelease",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::UploadToCPAN",
"name" : "@Author::OALDERS/UploadToCPAN",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
"config" : {
"Dist::Zilla::Plugin::RewriteVersion" : {
"add_tarball_name" : 0,
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"skip_version_provider" : 0
},
"Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
},
"name" : "@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Update",
"name" : "@Author::OALDERS/@Git::VersionManager/MetaProvides::Update",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Changes"
],
"match" : []
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "v%V%n%n%c",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Changes",
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile",
"dist.ini"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/release snapshot",
"version" : "2.052"
},
{
"class" : "Dist::Zilla::Plugin::Git::Tag",
"config" : {
"Dist::Zilla::Plugin::Git::Tag" : {
"branch" : null,
"changelog" : "Changes",
"signed" : 0,
"tag" : "v6.12",
"tag_format" : "v%V",
"tag_message" : "v%V"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/Git::Tag",
"version" : "2.052"
},
{
"class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
"config" : {
"Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"munge_makefile_pl" : 1
},
"Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
},
"name" : "@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::NextRelease",
"name" : "@Author::OALDERS/@Git::VersionManager/NextRelease",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "increment $VERSION after %v release",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Build.PL",
"Changes",
"Makefile.PL"
],
"allow_dirty_match" : [
"(?^:^lib/.*\\.pm$)"
],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/post-release commit",
"version" : "2.052"
},
{
"class" : "Dist::Zilla::Plugin::Git::Push",
"config" : {
"Dist::Zilla::Plugin::Git::Push" : {
"push_to" : [
"origin"
],
"remotes_must_exist" : 1
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
}
},
"name" : "@Author::OALDERS/Git::Push",
"version" : "2.052"
},
{
"class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease",
"config" : {
"Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"munge_makefile_pl" : 1
}
},
"name" : "BumpVersionAfterRelease",
"version" : "0.018"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "develop",
"type" : "requires"
}
},
"name" : "DevelopRequires",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::PruneFiles",
"name" : "PruneFiles",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":IncModules",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":TestFiles",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExtraTestFiles",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExecFiles",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":PerlExecFiles",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ShareFiles",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":MainModule",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":AllFiles",
"version" : "6.037"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":NoFiles",
"version" : "6.037"
}
],
"zilla" : {
"class" : "Dist::Zilla::Dist::Builder",
"config" : {
"is_trial" : 0
},
"version" : "6.037"
}
},
"x_contributors" : [
"Adam Kennedy ",
"Adam Sjogren ",
"Alexey Tourbin ",
"Alex Kapranoff ",
"Alex Peters ",
"amire80 ",
"Andreas J. Koenig ",
"Bernhard M. Wiedemann ",
"Bill Mann ",
"Bron Gondwana ",
"Charlie Hothersall-Thomas ",
"Chase Whitener ",
"Colin Newell ",
"Daniel Hedlund ",
"Dave Menninger ",
"David E. Wheeler ",
"DAVIDRW ",
"dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"Father Chrysostomos ",
"FWILES ",
"Gavin Peters ",
"George Grozdev ",
"Graeme Thompson ",
"Hans-H. Froehlich ",
"Ian Kilgore ",
"Jacob J ",
"James McCoy ",
"James Raspass ",
"jefflee ",
"john9art ",
"Julien Fiegehenn ",
"Mark Raymond ",
"Mark Stosberg ",
"Michal Josef \u0160pa\u010dek ",
"Mike Schilli ",
"Mohammad S Anwar ",
"murphy ",
"Olaf Alders ",
"Ondrej Hanak ",
"Perlover ",
"Peter Rabbitson ",
"Philip J. Ludlam ",
"phrstbrn ",
"Robert Stone ",
"robnagler ",
"Rolf Grossmann ",
"ruff ",
"sasao ",
"Sean M. Burke ",
"Slaven Rezic ",
"Spiros Denaxas ",
"Steve Hay ",
"Todd Lipcon ",
"Tom Hukins ",
"Tony Finch ",
"Toru Yamaguchi ",
"Ville Skytt\u00e4 ",
"Yuri Karaban ",
"Zefram "
],
"x_generated_by_perl" : "v5.42.2",
"x_serialization_backend" : "Cpanel::JSON::XS version 4.40",
"x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
"x_static_install" : 0
}
README.md 100644 001750 001751 16654 15231271120 14227 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 # NAME
HTTP::Cookies - HTTP cookie jars
# VERSION
version 6.12
# SYNOPSIS
use HTTP::Cookies;
$cookie_jar = HTTP::Cookies->new(
file => "$ENV{'HOME'}/lwp_cookies.dat",
autosave => 1,
);
use LWP;
my $browser = LWP::UserAgent->new;
$browser->cookie_jar($cookie_jar);
Or for an empty and temporary cookie jar:
use LWP;
my $browser = LWP::UserAgent->new;
$browser->cookie_jar( {} );
# DESCRIPTION
This class is for objects that represent a "cookie jar" -- that is, a
database of all the HTTP cookies that a given LWP::UserAgent object
knows about.
Cookies are a general mechanism which server side connections can use
to both store and retrieve information on the client side of the
connection. For more information about cookies refer to
[Cookie Spec](http://curl.haxx.se/rfc/cookie_spec.html) and
[Cookie Central](http://www.cookiecentral.com). This module also implements the
new style cookies described in [RFC 2965](https://tools.ietf.org/html/rfc2965).
The two variants of cookies are supposed to be able to coexist happily.
Instances of the class _HTTP::Cookies_ are able to store a collection
of Set-Cookie2: and Set-Cookie: headers and are able to use this
information to initialize Cookie-headers in _HTTP::Request_ objects.
The state of a _HTTP::Cookies_ object can be saved in and restored from
files.
# LIMITATIONS
This module does not support [Public Suffix](https://publicsuffix.org/) encouraged by a more recent standard, [RFC
6265](https://tools.ietf.org/html/rfc6265).
This module's shortcomings mean that a malicious Web site can set
cookies to track your user agent across all sites under a top level
domain. See `t/publicsuffix.t` in this module's distribution for
details.
[HTTP::CookieJar::LWP](https://metacpan.org/pod/HTTP%3A%3ACookieJar%3A%3ALWP) supports Public Suffix, but only provides a
limited subset of this module's functionality and [does not
support](https://metacpan.org/pod/HTTP%3A%3ACookieJar#LIMITATIONS-AND-CAVEATS) standards older than
_RFC 6265_.
# METHODS
The following methods are provided:
- $cookie\_jar = HTTP::Cookies->new
The constructor takes hash style parameters. The following
parameters are recognized:
file: name of the file to restore cookies from and save cookies to
autosave: save during destruction (bool)
ignore_discard: save even cookies that are requested to be discarded (bool)
hide_cookie2: do not add Cookie2 header to requests
Future parameters might include (not yet implemented):
max_cookies 300
max_cookies_per_domain 20
max_cookie_size 4096
no_cookies list of domain names that we never return cookies to
- $cookie\_jar->get\_cookies( $url\_or\_domain )
- $cookie\_jar->get\_cookies( $url\_or\_domain, $cookie\_key,... )
Returns a reference to a hash of the cookies that apply to the given URL. If a
domainname is given as argument, then a prefix of "https://" is assumed.
If one or more $cookie\_key parameters are provided return the given values,
or `undef` if the cookie isn't available.
- $cookie\_jar->add\_cookie\_header( $request )
The add\_cookie\_header() method will set the appropriate Cookie:-header
for the _HTTP::Request_ object given as argument. The $request must
have a valid url attribute before this method is called.
- $cookie\_jar->extract\_cookies( $response )
The extract\_cookies() method will look for Set-Cookie: and
Set-Cookie2: headers in the _HTTP::Response_ object passed as
argument. Any of these headers that are found are used to update
the state of the $cookie\_jar.
- $cookie\_jar->set\_cookie( $version, $key, $val, $path, $domain, $port, $path\_spec, $secure, $maxage, $discard, \\%rest )
The set\_cookie() method updates the state of the $cookie\_jar. The
$key, $val, $domain, $port and $path arguments are strings. The
$path\_spec, $secure, $discard arguments are boolean values. The $maxage
value is a number indicating number of seconds that this cookie will
live. A value of $maxage <= 0 will delete this cookie. The $version argument
sets the version of the cookie; the default value is 0 ( original Netscape
spec ). Setting $version to another value indicates the RFC to which the
cookie conforms (e.g. version 1 for RFC 2109). %rest defines various other
attributes like "Comment" and "CommentURL".
- $cookie\_jar->save
- $cookie\_jar->save( $file )
- $cookie\_jar->save( file => $file, ignore\_discard => $ignore\_discard )
This method saves the state of the $cookie\_jar to a file.
The state can then be restored later using the load() method. If a
filename is not specified we will use the name specified during
construction. If the $ignore\_discard value is true (or not specified,
but attribute _ignore\_discard_ was set at cookie jar construction),
then we will even save cookies that are marked to be discarded.
The default is to save a sequence of "Set-Cookie3" lines.
"Set-Cookie3" is a proprietary LWP format, not known to be compatible
with any browser. The _HTTP::Cookies::Netscape_ sub-class can
be used to save in a format compatible with Netscape.
- $cookie\_jar->load
- $cookie\_jar->load( $file )
This method reads the cookies from the file and adds them to the
$cookie\_jar. The file must be in the format written by the save()
method.
- $cookie\_jar->revert
This method empties the $cookie\_jar and re-loads the $cookie\_jar
from the last save file.
- $cookie\_jar->clear
- $cookie\_jar->clear( $domain )
- $cookie\_jar->clear( $domain, $path )
- $cookie\_jar->clear( $domain, $path, $key )
Invoking this method without arguments will empty the whole
$cookie\_jar. If given a single argument only cookies belonging to
that domain will be removed. If given two arguments, cookies
belonging to the specified path within that domain are removed. If
given three arguments, then the cookie with the specified key, path
and domain is removed.
- $cookie\_jar->clear\_temporary\_cookies
Discard all temporary cookies. Scans for all cookies in the jar
with either no expire field or a true `discard` flag. To be
called when the user agent shuts down according to RFC 2965.
- $cookie\_jar->scan( \\&callback )
The argument is a subroutine that will be invoked for each cookie
stored in the $cookie\_jar. The subroutine will be invoked with
the following arguments:
0 version
1 key
2 val
3 path
4 domain
5 port
6 path_spec
7 secure
8 expires
9 discard
10 hash
- $cookie\_jar->as\_string
- $cookie\_jar->as\_string( $skip\_discardables )
The as\_string() method will return the state of the $cookie\_jar
represented as a sequence of "Set-Cookie3" header lines separated by
"\\n". If $skip\_discardables is TRUE, it will not return lines for
cookies with the _Discard_ attribute.
# SEE ALSO
[HTTP::Cookies::Netscape](https://metacpan.org/pod/HTTP%3A%3ACookies%3A%3ANetscape), [HTTP::Cookies::Microsoft](https://metacpan.org/pod/HTTP%3A%3ACookies%3A%3AMicrosoft)
# AUTHOR
Gisle Aas
# COPYRIGHT AND LICENSE
This software is copyright (c) 2002 by Gisle Aas.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
Makefile.PL 100644 001750 001751 3055 15231271120 14671 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 # This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.037
use strict;
use warnings;
use 5.008001;
use ExtUtils::MakeMaker;
my %WriteMakefileArgs = (
"ABSTRACT" => "HTTP cookie jars",
"AUTHOR" => "Gisle Aas ",
"CONFIGURE_REQUIRES" => {
"ExtUtils::MakeMaker" => 0
},
"DISTNAME" => "HTTP-Cookies",
"LICENSE" => "perl",
"MIN_PERL_VERSION" => "5.008001",
"NAME" => "HTTP::Cookies",
"PREREQ_PM" => {
"Carp" => 0,
"HTTP::Date" => 6,
"HTTP::Headers::Util" => 6,
"HTTP::Request" => 0,
"locale" => 0,
"strict" => 0
},
"TEST_REQUIRES" => {
"ExtUtils::MakeMaker" => 0,
"File::Spec" => 0,
"HTTP::Response" => 0,
"Test::More" => "0.96",
"URI" => 0,
"warnings" => 0
},
"VERSION" => "6.12",
"test" => {
"TESTS" => "t/*.t"
}
);
my %FallbackPrereqs = (
"Carp" => 0,
"ExtUtils::MakeMaker" => 0,
"File::Spec" => 0,
"HTTP::Date" => 6,
"HTTP::Headers::Util" => 6,
"HTTP::Request" => 0,
"HTTP::Response" => 0,
"Test::More" => "0.96",
"URI" => 0,
"locale" => 0,
"strict" => 0,
"warnings" => 0
);
unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
delete $WriteMakefileArgs{TEST_REQUIRES};
delete $WriteMakefileArgs{BUILD_REQUIRES};
$WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
}
delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
unless eval { ExtUtils::MakeMaker->VERSION(6.52) };
if ( $^O eq 'MSWin32' ) {
$WriteMakefileArgs{PREREQ_PM}{'Win32'} = $FallbackPrereqs{'Win32'} = '0';
}
WriteMakefile(%WriteMakefileArgs);
t 000755 001750 001751 0 15231271120 13017 5 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 cookies.t 100644 001750 001751 63245 15231271120 15032 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t #!perl -w
use HTTP::Cookies ();
use HTTP::Request ();
use HTTP::Response ();
use URI ();
use Test::More tests => 79;
#-------------------------------------------------------------------
# First we check that it works for the original example at
# http://curl.haxx.se/rfc/cookie_spec.html
# Client requests a document, and receives in the response:
#
# Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
#
# When client requests a URL in path "/" on this server, it sends:
#
# Cookie: CUSTOMER=WILE_E_COYOTE
#
# Client requests a document, and receives in the response:
#
# Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
#
# When client requests a URL in path "/" on this server, it sends:
#
# Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
#
# Client receives:
#
# Set-Cookie: SHIPPING=FEDEX; path=/fo
#
# When client requests a URL in path "/" on this server, it sends:
#
# Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
#
# When client requests a URL in path "/foo" on this server, it sends:
#
# Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
#
# The last Cookie is buggy, because both specifications says that the
# most specific cookie must be sent first. SHIPPING=FEDEX is the
# most specific and should thus be first.
my $year_plus_one = (localtime)[5] + 1900 + 1;
$c = HTTP::Cookies->new;
$req = HTTP::Request->new( GET => "http://1.1.1.1/" );
$req->header( "Host", "www.acme.com:80" );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->header( "Set-Cookie" =>
"CUSTOMER=WILE_E_COYOTE; path=/ ; expires=Wednesday, 09-Nov-$year_plus_one 23:12:40 GMT"
);
#print $res->as_string;
$c->extract_cookies($res);
$req = HTTP::Request->new( GET => "http://www.acme.com/" );
$c->add_cookie_header($req);
is( $req->header("Cookie"), "CUSTOMER=WILE_E_COYOTE" );
is( $req->header("Cookie2"), "\$Version=\"1\"" );
$res->request($req);
$res->header( "Set-Cookie" => "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/" );
$c->extract_cookies($res);
$req = HTTP::Request->new( GET => "http://www.acme.com/foo/bar" );
$c->add_cookie_header($req);
$h = $req->header("Cookie");
like( $h, qr/PART_NUMBER=ROCKET_LAUNCHER_0001/ );
like( $h, qr/CUSTOMER=WILE_E_COYOTE/ );
$res->request($req);
$res->header( "Set-Cookie", "SHIPPING=FEDEX; path=/foo" );
$c->extract_cookies($res);
$req = HTTP::Request->new( GET => "http://www.acme.com/" );
$c->add_cookie_header($req);
$h = $req->header("Cookie");
like( $h, qr/PART_NUMBER=ROCKET_LAUNCHER_0001/ );
like( $h, qr/CUSTOMER=WILE_E_COYOTE/ );
unlike( $h, qr/SHIPPING=FEDEX/ );
$req = HTTP::Request->new( GET => "http://www.acme.com/foo/" );
$c->add_cookie_header($req);
$h = $req->header("Cookie");
like( $h, qr/PART_NUMBER=ROCKET_LAUNCHER_0001/ );
like( $h, qr/CUSTOMER=WILE_E_COYOTE/ );
like( $h, qr/^SHIPPING=FEDEX;/ );
print $c->as_string;
# Second Example transaction sequence:
#
# Assume all mappings from above have been cleared.
#
# Client receives:
#
# Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
#
# When client requests a URL in path "/" on this server, it sends:
#
# Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
#
# Client receives:
#
# Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
#
# When client requests a URL in path "/ammo" on this server, it sends:
#
# Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
#
# NOTE: There are two name/value pairs named "PART_NUMBER" due to
# the inheritance of the "/" mapping in addition to the "/ammo" mapping.
$c = HTTP::Cookies->new; # clear it
$req = HTTP::Request->new( GET => "http://www.acme.com/" );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->header( "Set-Cookie", "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/" );
$c->extract_cookies($res);
$req = HTTP::Request->new( GET => "http://www.acme.com/" );
$c->add_cookie_header($req);
is( $req->header("Cookie"), "PART_NUMBER=ROCKET_LAUNCHER_0001" );
$res->request($req);
$res->header( "Set-Cookie", "PART_NUMBER=RIDING_ROCKET_0023; path=/ammo" );
$c->extract_cookies($res);
$req = HTTP::Request->new( GET => "http://www.acme.com/ammo" );
$c->add_cookie_header($req);
like(
$req->header("Cookie"),
qr/^PART_NUMBER=RIDING_ROCKET_0023;\s*PART_NUMBER=ROCKET_LAUNCHER_0001/
);
print $c->as_string;
undef($c);
#-------------------------------------------------------------------
# When there are no "Set-Cookie" header, then even responses
# without any request URLs connected should be allowed.
$c = HTTP::Cookies->new;
$c->extract_cookies( HTTP::Response->new( "200", "OK" ) );
is( count_cookies($c), 0 );
#-------------------------------------------------------------------
# Then we test with the examples from RFC 2965.
#
# 5. EXAMPLES
$c = HTTP::Cookies->new;
#
# 5.1 Example 1
#
# Most detail of request and response headers has been omitted. Assume
# the user agent has no stored cookies.
#
# 1. User Agent -> Server
#
# POST /acme/login HTTP/1.1
# [form data]
#
# User identifies self via a form.
#
# 2. Server -> User Agent
#
# HTTP/1.1 200 OK
# Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
#
# Cookie reflects user's identity.
$cookie = interact(
$c, 'http://www.acme.com/acme/login',
'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"'
);
ok( !$cookie );
#
# 3. User Agent -> Server
#
# POST /acme/pickitem HTTP/1.1
# Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
# [form data]
#
# User selects an item for ``shopping basket.''
#
# 4. Server -> User Agent
#
# HTTP/1.1 200 OK
# Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
# Path="/acme"
#
# Shopping basket contains an item.
$cookie = interact(
$c, 'http://www.acme.com/acme/pickitem',
'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"'
);
like(
$cookie,
qr(^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$)
);
#
# 5. User Agent -> Server
#
# POST /acme/shipping HTTP/1.1
# Cookie: $Version="1";
# Customer="WILE_E_COYOTE"; $Path="/acme";
# Part_Number="Rocket_Launcher_0001"; $Path="/acme"
# [form data]
#
# User selects shipping method from form.
#
# 6. Server -> User Agent
#
# HTTP/1.1 200 OK
# Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
#
# New cookie reflects shipping method.
$cookie = interact(
$c, "http://www.acme.com/acme/shipping",
'Shipping="FedEx"; Version="1"; Path="/acme"'
);
like( $cookie, qr/^\$Version="?1"?;/ );
like( $cookie, qr/Part_Number="?Rocket_Launcher_0001"?;\s*\$Path="\/acme"/ );
like( $cookie, qr/Customer="?WILE_E_COYOTE"?;\s*\$Path="\/acme"/ );
#
# 7. User Agent -> Server
#
# POST /acme/process HTTP/1.1
# Cookie: $Version="1";
# Customer="WILE_E_COYOTE"; $Path="/acme";
# Part_Number="Rocket_Launcher_0001"; $Path="/acme";
# Shipping="FedEx"; $Path="/acme"
# [form data]
#
# User chooses to process order.
#
# 8. Server -> User Agent
#
# HTTP/1.1 200 OK
#
# Transaction is complete.
$cookie = interact( $c, "http://www.acme.com/acme/process" );
print "FINAL COOKIE: $cookie\n";
like( $cookie, qr/Shipping="?FedEx"?;\s*\$Path="\/acme"/ );
like( $cookie, qr/WILE_E_COYOTE/ );
#
# The user agent makes a series of requests on the origin server, after
# each of which it receives a new cookie. All the cookies have the same
# Path attribute and (default) domain. Because the request URLs all have
# /acme as a prefix, and that matches the Path attribute, each request
# contains all the cookies received so far.
print $c->as_string;
# 5.2 Example 2
#
# This example illustrates the effect of the Path attribute. All detail
# of request and response headers has been omitted. Assume the user agent
# has no stored cookies.
$c = HTTP::Cookies->new;
# Imagine the user agent has received, in response to earlier requests,
# the response headers
#
# Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
# Path="/acme"
#
# and
#
# Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
# Path="/acme/ammo"
interact(
$c, "http://www.acme.com/acme/ammo/specific",
'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"',
'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"'
);
# A subsequent request by the user agent to the (same) server for URLs of
# the form /acme/ammo/... would include the following request header:
#
# Cookie: $Version="1";
# Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
# Part_Number="Rocket_Launcher_0001"; $Path="/acme"
#
# Note that the NAME=VALUE pair for the cookie with the more specific Path
# attribute, /acme/ammo, comes before the one with the less specific Path
# attribute, /acme. Further note that the same cookie name appears more
# than once.
$cookie = interact( $c, "http://www.acme.com/acme/ammo/..." );
like( $cookie, qr/Riding_Rocket_0023.*Rocket_Launcher_0001/ );
# A subsequent request by the user agent to the (same) server for a URL of
# the form /acme/parts/ would include the following request header:
#
# Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
#
# Here, the second cookie's Path attribute /acme/ammo is not a prefix of
# the request URL, /acme/parts/, so the cookie does not get forwarded to
# the server.
$cookie = interact( $c, "http://www.acme.com/acme/parts/" );
like( $cookie, qr/Rocket_Launcher_0001/ );
unlike( $cookie, qr/Riding_Rocket_0023/ );
print $c->as_string;
#-----------------------------------------------------------------------
# Test rejection of Set-Cookie2 responses based on domain, path or port
$c = HTTP::Cookies->new;
# illegal domain (no embedded dots)
$cookie = interact( $c, "http://www.acme.com", 'foo=bar; domain=".com"' );
is( count_cookies($c), 0 );
# legal domain
$cookie = interact( $c, "http://www.acme.com", 'foo=bar; domain="acme.com"' );
is( count_cookies($c), 1 );
# illegal domain (host prefix "www.a" contains a dot)
$cookie
= interact( $c, "http://www.a.acme.com", 'foo=bar; domain="acme.com"' );
is( count_cookies($c), 1 );
# legal domain
$cookie = interact(
$c, "http://www.a.acme.com",
'foo=bar; domain=".a.acme.com"'
);
is( count_cookies($c), 2 );
# can't use a IP-address as domain
$cookie = interact(
$c, "http://125.125.125.125",
'foo=bar; domain="125.125.125"'
);
is( count_cookies($c), 2 );
# illegal path (must be prefix of request path)
$cookie = interact(
$c, "http://www.sol.no",
'foo=bar; domain=".sol.no"; path="/foo"'
);
is( count_cookies($c), 2 );
# legal path
$cookie = interact(
$c, "http://www.sol.no/foo/bar",
'foo=bar; domain=".sol.no"; path="/foo"'
);
is( count_cookies($c), 3 );
# illegal port (request-port not in list)
$cookie = interact(
$c, "http://www.sol.no",
'foo=bar; domain=".sol.no"; port="90,100"'
);
is( count_cookies($c), 3 );
# legal port
$cookie = interact(
$c, "http://www.sol.no",
'foo=bar; domain=".sol.no"; port="90,100, 80,8080"; max-age=100; Comment = "Just kidding! (\"|\\\\) "'
);
is( count_cookies($c), 4 );
# port attribute without any value (current port)
$cookie = interact(
$c, "http://www.sol.no",
'foo9=bar; domain=".sol.no"; port; max-age=100;'
);
is( count_cookies($c), 5 );
# encoded path
$cookie = interact( $c, "http://www.sol.no/foo/", 'foo8=bar; path="/%66oo"' );
is( count_cookies($c), 6 );
my $file = "lwp-cookies-$$.txt";
$c->save($file);
$old = $c->as_string;
undef($c);
$c = HTTP::Cookies->new;
$c->load($file);
unlink($file) || warn "Can't unlink $file: $!";
is( $old, $c->as_string );
undef($c);
#
# Try some URL encodings of the PATHs
#
$c = HTTP::Cookies->new;
interact(
$c, "http://www.acme.com/foo%2f%25/%40%40%0Anew%E5/%E5",
'foo = bar; version = 1'
);
print $c->as_string;
$cookie = interact(
$c, "http://www.acme.com/foo%2f%25/@@%0anew/",
"bar=baz; path=\"/foo/\"; version=1"
);
like( $cookie, qr/foo=bar/ );
like( $cookie, qr/^\$version=\"?1\"?/i );
$cookie = interact( $c, "http://www.acme.com/foo/%25/@@%0anew/" );
ok( !$cookie );
undef($c);
#
# Try to use the Netscape cookie file format for saving
#
$file = "cookies-$$.txt";
$c = HTTP::Cookies::Netscape->new( file => $file );
interact( $c, "http://www.acme.com/", "foo1=bar; max-age=100" );
interact(
$c, "http://www.acme.com/",
"foo2=bar; port=\"80\"; max-age=100; Discard; Version=1"
);
interact( $c, "http://www.acme.com/", "foo3=bar; secure; Version=1" );
$c->save;
undef($c);
$c = HTTP::Cookies::Netscape->new( file => $file );
is( count_cookies($c), 1 ); # 2 of them discarded on save
like( $c->as_string, qr/foo1=bar/ );
undef($c);
unlink($file);
# Expect a HttpOnly cookie to be loaded, rather than treated as a comment
$c = HTTP::Cookies::Netscape->new( file => 't/data/netscape-httponly.txt' );
is( count_cookies($c), 4 );
undef($c);
#
# Some additional Netscape cookies test
#
$c = HTTP::Cookies->new;
$req = HTTP::Request->new( POST => "http://foo.bar.acme.com/foo" );
# Netscape allows a host part that contains dots
$res = HTTP::Response->new( 200, "OK" );
$res->header( set_cookie => 'Customer=WILE_E_COYOTE; domain=.acme.com' );
$res->request($req);
$c->extract_cookies($res);
# and that the domain is the same as the host without adding a leading
# dot to the domain. Should not quote even if strange chars are used
# in the cookie value.
$res = HTTP::Response->new( 200, "OK" );
$res->header( set_cookie => 'PART_NUMBER=3,4; domain=foo.bar.acme.com' );
$res->request($req);
$c->extract_cookies($res);
print $c->as_string;
$req = HTTP::Request->new( POST => URI->new("http://foo.bar.acme.com/foo") );
$c->add_cookie_header($req);
#print $req->as_string;
like( $req->header("Cookie"), qr/PART_NUMBER=3,4/ );
like( $req->header("Cookie"), qr/Customer=WILE_E_COYOTE/ );
# Test handling of local intranet hostnames without a dot
$c->clear;
print "---\n";
interact( $c, "http://example/", "foo1=bar; PORT; Discard;" );
$_ = interact( $c, "http://example/", 'foo2=bar; domain=".local"' );
like( $_, qr/foo1=bar/ );
$_ = interact( $c, "http://example/", 'foo3=bar' );
$_ = interact( $c, "http://example/" );
print "Cookie: $_\n";
like( $_, qr/foo2=bar/ );
is( count_cookies($c), 3 );
print $c->as_string;
# Test for empty path
# Broken web-server ORION/1.3.38 returns to the client response like
#
# Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=
#
# e.g. with Path set to nothing.
# In this case routine extract_cookies() must set cookie to / (root)
print "---\n";
print "Test for empty path...\n";
$c = HTTP::Cookies->new; # clear it
$req = HTTP::Request->new( GET => "http://www.ants.com/" );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->header( "Set-Cookie" => "JSESSIONID=ABCDERANDOM123; Path=" );
print $res->as_string;
$c->extract_cookies($res);
#print $c->as_string;
$req = HTTP::Request->new( GET => "http://www.ants.com/" );
$c->add_cookie_header($req);
#print $req->as_string;
is( $req->header("Cookie"), "JSESSIONID=ABCDERANDOM123" );
is( $req->header("Cookie2"), "\$Version=\"1\"" );
# missing path in the request URI
$req = HTTP::Request->new( GET => URI->new("http://www.ants.com:8080") );
$c->add_cookie_header($req);
#print $req->as_string;
is( $req->header("Cookie"), "JSESSIONID=ABCDERANDOM123" );
is( $req->header("Cookie2"), "\$Version=\"1\"" );
# test mixing of Set-Cookie and Set-Cookie2 headers.
# Example from http://www.trip.com/trs/trip/flighttracker/flight_tracker_home.xsl
# which gives up these headers:
#
# HTTP/1.1 200 OK
# Connection: close
# Date: Fri, 20 Jul 2001 19:54:58 GMT
# Server: Apache/1.3.19 (Unix) ApacheJServ/1.1.2
# Content-Type: text/html
# Content-Type: text/html; charset=iso-8859-1
# Link: ; rel="stylesheet"; type="text/css"
# Servlet-Engine: Tomcat Web Server/3.2.1 (JSP 1.1; Servlet 2.2; Java 1.3.0; SunOS 5.8 sparc; java.vendor=Sun Microsystems Inc.)
# Set-Cookie: trip.appServer=1111-0000-x-024;Domain=.trip.com;Path=/
# Set-Cookie: JSESSIONID=fkumjm7nt1.JS24;Path=/trs
# Set-Cookie2: JSESSIONID=fkumjm7nt1.JS24;Version=1;Discard;Path="/trs"
# Title: TRIP.com Travel - FlightTRACKER
# X-Meta-Description: Trip.com privacy policy
# X-Meta-Keywords: privacy policy
$req = HTTP::Request->new(
'GET',
'http://www.trip.com/trs/trip/flighttracker/flight_tracker_home.xsl'
);
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->push_header( "Set-Cookie" =>
qq(trip.appServer=1111-0000-x-024;Domain=.trip.com;Path=/) );
$res->push_header( "Set-Cookie" => qq(JSESSIONID=fkumjm7nt1.JS24;Path=/trs) );
$res->push_header( "Set-Cookie2" =>
qq(JSESSIONID=fkumjm7nt1.JS24;Version=1;Discard;Path="/trs") );
#print $res->as_string;
$c = HTTP::Cookies->new; # clear it
$c->extract_cookies($res);
print $c->as_string;
is( $c->as_string, <<'EOT' );
Set-Cookie3: trip.appServer=1111-0000-x-024; path="/"; domain=.trip.com; path_spec; discard; version=0
Set-Cookie3: JSESSIONID=fkumjm7nt1.JS24; path="/trs"; domain=www.trip.com; path_spec; discard; version=1
EOT
#-------------------------------------------------------------------
# Test if temporary cookies are deleted properly with
# $jar->clear_temporary_cookies()
$req = HTTP::Request->new( 'GET', 'http://www.perlmeister.com/scripts' );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
# Set session/perm cookies and mark their values as "session" vs. "perm"
# to recognize them later
$res->push_header( "Set-Cookie" => qq(s1=session;Path=/scripts) );
$res->push_header( "Set-Cookie" =>
qq(p1=perm; Domain=.perlmeister.com;Path=/;expires=Fri, 02-Feb-$year_plus_one 23:24:20 GMT)
);
$res->push_header( "Set-Cookie" =>
qq(p2=perm;Path=/;expires=Fri, 02-Feb-$year_plus_one 23:24:20 GMT) );
$res->push_header(
"Set-Cookie" => qq(s2=session;Path=/scripts;Domain=.perlmeister.com) );
$res->push_header(
"Set-Cookie2" => qq(s3=session;Version=1;Discard;Path="/") );
$c = HTTP::Cookies->new; # clear jar
$c->extract_cookies($res);
# How many session/permanent cookies do we have?
my %counter = ( "session_after" => 0 );
$c->scan( sub { $counter{"${_[2]}_before"}++ } );
$c->clear_temporary_cookies();
# How many now?
$c->scan( sub { $counter{"${_[2]}_after"}++ } );
is( $counter{"perm_after"}, $counter{"perm_before"} )
; # a permanent cookie got lost accidently
is( $counter{"session_after"}, 0 ); # a session cookie hasn't been cleared
is( $counter{"session_before"}, 3 )
; # we didn't have session cookies in the first place
#print $c->as_string;
# Test handling of 'secure ' attribute for classic cookies
$c = HTTP::Cookies->new;
$req = HTTP::Request->new( GET => "https://1.1.1.1/" );
$req->header( "Host", "www.acme.com:80" );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->header( "Set-Cookie" => "CUSTOMER=WILE_E_COYOTE ; secure ; path=/" );
#print $res->as_string;
$c->extract_cookies($res);
$req = HTTP::Request->new( GET => "http://www.acme.com/" );
$c->add_cookie_header($req);
ok( !$req->header("Cookie") );
$req->uri->scheme("https");
$c->add_cookie_header($req);
is( $req->header("Cookie"), "CUSTOMER=WILE_E_COYOTE" );
#print $req->as_string;
#print $c->as_string;
$req = HTTP::Request->new( GET => "ftp://ftp.activestate.com/" );
$c->add_cookie_header($req);
ok( !$req->header("Cookie") );
$req = HTTP::Request->new( GET => "file:/etc/motd" );
$c->add_cookie_header($req);
ok( !$req->header("Cookie") );
$req = HTTP::Request->new( GET => "mailto:gisle\@aas.no" );
$c->add_cookie_header($req);
ok( !$req->header("Cookie") );
# Test cookie called 'expires'
$c = HTTP::Cookies->new;
$req = HTTP::Request->new( "GET" => "http://example.com" );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->header( "Set-Cookie" => "Expires=10101" );
$c->extract_cookies($res);
#print $c->as_string;
is( $c->as_string, <<'EOT' );
Set-Cookie3: Expires=10101; path="/"; domain=example.com; discard; version=0
EOT
# Test empty cookie header [RT#29401]
$c = HTTP::Cookies->new;
$res->header( "Set-Cookie" => [ "CUSTOMER=WILE_E_COYOTE; path=/;", "" ] );
#print $res->as_string;
$c->extract_cookies($res);
#print $c->as_string;
is( $c->as_string, <<'EOT' );
Set-Cookie3: CUSTOMER=WILE_E_COYOTE; path="/"; domain=example.com; path_spec; discard; version=0
EOT
# Test empty cookie part [RT#38480]
$c = HTTP::Cookies->new;
$res->header( "Set-Cookie" => "CUSTOMER=WILE_E_COYOTE;;path=/;" );
#print $res->as_string;
$c->extract_cookies($res);
#print $c->as_string;
is( $c->as_string, <<'EOT' );
Set-Cookie3: CUSTOMER=WILE_E_COYOTE; path="/"; domain=example.com; path_spec; discard; version=0
EOT
# Test Set-Cookie with version set
$c = HTTP::Cookies->new;
$res->header( "Set-Cookie" => "foo=\"bar\";version=1" );
#print $res->as_string;
$c->extract_cookies($res);
#print $c->as_string;
$req = HTTP::Request->new( GET => "http://www.example.com/foo" );
$c->add_cookie_header($req);
#print $req->as_string;
is( $req->header("Cookie"), "foo=bar" );
# Test cookies that expire far into the future [RT#50147]
$c = HTTP::Cookies->new;
$res->header(
"Set-Cookie",
"PREF=ID=cee18f7c4e977184:TM=1254583090:LM=1254583090:S=Pdb0-hy9PxrNj4LL; expires=Mon, 03-Oct-2211 15:18:10 GMT; path=/; domain=.example.com"
);
$res->push_header(
"Set-Cookie",
"expired1=1; expires=Mon, 03-Oct-2001 15:18:10 GMT; path=/; domain=.example.com"
);
$res->push_header(
"Set-Cookie",
"expired2=1; expires=Fri Jan 1 00:00:00 GMT 1970; path=/; domain=.example.com"
);
$res->push_header(
"Set-Cookie",
"expired3=1; expires=Fri Jan 1 00:00:01 GMT 1970; path=/; domain=.example.com"
);
$res->push_header(
"Set-Cookie",
"expired4=1; expires=Thu Dec 31 23:59:59 GMT 1969; path=/; domain=.example.com"
);
$res->push_header(
"Set-Cookie",
"expired5=1; expires=Fri Feb 2 00:00:00 GMT 1950; path=/; domain=.example.com"
);
$c->extract_cookies($res);
#print $res->as_string;
#print "---\n";
#print $c->as_string;
$req = HTTP::Request->new( GET => "http://www.example.com/foo" );
$c->add_cookie_header($req);
#print $req->as_string;
is(
$req->header("Cookie"),
"PREF=ID=cee18f7c4e977184:TM=1254583090:LM=1254583090:S=Pdb0-hy9PxrNj4LL"
);
$c->clear_temporary_cookies;
$req = HTTP::Request->new( GET => "http://www.example.com/foo" );
$c->add_cookie_header($req);
#print $req->as_string;
is(
$req->header("Cookie"),
"PREF=ID=cee18f7c4e977184:TM=1254583090:LM=1254583090:S=Pdb0-hy9PxrNj4LL"
);
# Test merging of cookies
$c = HTTP::Cookies->new;
$res->header( "Set-Cookie", "foo=1; path=/" );
$c->extract_cookies($res);
$req = HTTP::Request->new( GET => "http://www.example.com/foo" );
$req->header( "Cookie", "x=bcd" );
$c->add_cookie_header($req);
is( $req->header("Cookie"), "x=bcd; foo=1" );
$c->add_cookie_header($req);
is( $req->header("Cookie"), "x=bcd; foo=1; foo=1" );
#print $req->as_string;
# Test get_cookies
$c = HTTP::Cookies->new;
$res->header( "Set-Cookie", "foo=42" );
$c->extract_cookies($res);
is( $c->get_cookies("example.com")->{foo}, 42 );
is( $c->get_cookies( "example.com", "foo" ), 42 );
is( $c->get_cookies( "example.com", "bar" ), undef );
is( $c->get_cookies( "http://example.com", "foo" ), 42 );
is( $c->get_cookies( "https://example.com", "foo" ), 42 );
is( $c->get_cookies( URI->new("https://example.com"), "foo" ), 42 );
is( $c->get_cookies( "foo.example.com", "foo" ), 42 );
is( $c->get_cookies( "example.org", "foo" ), undef );
my @a = $c->get_cookies( "example.com", "bar", "foo" );
is_deeply( \@a, [ undef, 42 ] );
# Test ignore_discard argument of save()
$c = HTTP::Cookies->new( ignore_discard => 0 );
interact( $c, 'http://example.com/', 'foo=bar; Discard;' );
$old = $c->as_string;
$c->save( file => $file, ignore_discard => 1 );
undef $c;
$c = HTTP::Cookies->new( ignore_discard => 0 );
$c->load($file);
unlink($file) || warn "Can't unlink $file: $!";
is( $c->as_string, $old );
$c = HTTP::Cookies::Netscape->new( ignore_discard => 0 );
$req = HTTP::Request->new( GET => "http://1.1.1.1/" );
$req->header( "Host", "www.acme.com:80" );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->header( "Set-Cookie" =>
"foo=bar; path=/; discard; expires=Wednesday, 09-Nov-$year_plus_one 23:12:40 GMT"
);
$c->extract_cookies($res);
$old = $c->as_string;
$c->save( file => $file, ignore_discard => 1 );
undef $c;
$c = HTTP::Cookies::Netscape->new( ignore_discard => 0 );
$c->load($file);
$req = HTTP::Request->new( GET => "http://www.acme.com/foo/bar" );
$c->add_cookie_header($req);
$h = $req->header("Cookie");
like( $h, qr/foo=bar/ );
unlink($file) || warn "Can't unlink $file: $!";
# max-age must produce an expiry (GH #69); the cookie should be kept rather
# than discarded. Match the expires value with a pattern, not a literal
# timestamp, so the test does not depend on the current date.
$c = HTTP::Cookies->new;
$req = HTTP::Request->new( "GET" => "http://example.com" );
$res = HTTP::Response->new( 200, "OK" );
$res->request($req);
$res->header( "Set-Cookie" => "foo=bar; max-age=1337" );
$c->extract_cookies($res);
#print $c->as_string;
like(
$c->as_string,
qr{^Set-Cookie3: foo=bar; path="/"; domain=example\.com; expires="[^"]+"; version=0\n\z},
"max-age sets an expiry and keeps the cookie"
);
#-------------------------------------------------------------------
sub interact {
my $c = shift;
my $url = shift;
my $req = HTTP::Request->new( POST => $url );
$c->add_cookie_header($req);
my $cookie = $req->header("Cookie");
my $res = HTTP::Response->new( 200, "OK" );
$res->request($req);
for (@_) { $res->push_header( "Set-Cookie2" => $_ ) }
$c->extract_cookies($res);
return $cookie;
}
sub count_cookies {
my $c = shift;
my $no = 0;
$c->scan( sub { $no++ } );
$no;
}
issue26.t 100644 001750 001751 1052 15231271120 14642 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t use strict;
use Test::More;
use HTTP::Cookies ();
use HTTP::Response ();
use HTTP::Request ();
my $CRLF = "\015\012";
my $cookie_jar = HTTP::Cookies->new();
my $request = HTTP::Request->new( GET => 'http://www.en.com/' );
my $response = HTTP::Response->parse(
"HTTP/1.1 302 Moved" . $CRLF . "Set-Cookie: expires=10101$CRLF$CRLF" );
$response->request($request);
$cookie_jar->extract_cookies($response);
is $cookie_jar->as_string(),
'Set-Cookie3: expires=10101; path="/"; domain=www.en.com; discard; version=0'
. "\n";
done_testing;
issue32.t 100644 001750 001751 2022 15231271120 14635 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t use strict;
use warnings;
use Test::More;
use HTTP::Cookies ();
use HTTP::Request ();
use HTTP::Response ();
my $nextyear = 1901 + ( gmtime() )[5];
my $req = HTTP::Request->new( GET => "http://example.com" );
my $resp = HTTP::Response->new(
200, 'OK',
[
'Set-Cookie',
q!a="b;c;\\"d"; expires=Fri, 06-Nov-!
. $nextyear
. " 08:58:34 GMT; domain=example.com; path=/"
]
);
$resp->request($req);
my $c = HTTP::Cookies->new;
$c->extract_cookies($resp);
is $c->as_string,
'Set-Cookie3: a="b;c;\"d"; path="/"; domain=example.com; path_spec; expires="'
. $nextyear
. '-11-06 08:58:34Z"; version=0' . "\n";
# test the implementation of the split function in isolation.
# should probably name the function better too.
my $simple = 'b;c;d';
is_deeply HTTP::Cookies::_split_text($simple), [qw/b c d/], "Parse $simple";
my $complex = '"b;c;\\"d";blah=32;foo="/"';
is_deeply HTTP::Cookies::_split_text($complex),
[ 'b;c;"d', 'blah=32', 'foo=/' ], "Parse $complex";
done_testing;
issue69.t 100644 001750 001751 10260 15231271120 14672 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t use strict;
use warnings;
use Test::More 0.96; # subtest
use HTTP::Cookies ();
use HTTP::Request ();
use HTTP::Response ();
# GH issue #69: the Max-Age attribute on a Set-Cookie header was parsed but
# never carried through to the stored cookie, so Max-Age was completely
# ignored -- cookies got no expiry and Max-Age=0 failed to delete them.
sub jar_with_set_cookie {
my $set_cookie = shift;
my $req = HTTP::Request->new( GET => 'http://example.com/' );
my $resp
= HTTP::Response->new( 200, 'OK', [ 'Set-Cookie', $set_cookie ] );
$resp->request($req);
my $jar = HTTP::Cookies->new;
$jar->extract_cookies($resp);
return $jar;
}
subtest 'Max-Age sets a future expiry' => sub {
my $jar = jar_with_set_cookie(
'foo=bar; domain=example.com; path=/; Max-Age=3600');
my $expires;
$jar->scan( sub { $expires = $_[8] } );
ok defined $expires, 'cookie has an expiry derived from Max-Age';
cmp_ok $expires, '>', time(), 'expiry is in the future'
if defined $expires;
};
subtest 'Max-Age=0 deletes the cookie' => sub {
my $jar = jar_with_set_cookie(
'foo=bar; domain=example.com; path=/; Max-Age=0');
my $count = 0;
$jar->scan( sub { $count++ } );
is $count, 0, 'cookie with Max-Age=0 is not stored';
};
subtest 'non-numeric Max-Age is ignored (RFC 6265 5.2.2)' => sub {
# A malformed Max-Age must be ignored, not treated as 0. Treating it as 0
# would coerce the string to 0 in set_cookie and wrongly delete the cookie.
my $jar = jar_with_set_cookie(
'foo=bar; domain=example.com; path=/; Max-Age=not-a-number');
my $count = 0;
$jar->scan( sub { $count++ } );
is $count, 1, 'cookie with a non-numeric Max-Age is still stored';
};
subtest 'an absurdly large Max-Age is capped at ~10 years' => sub {
# Without a cap, a huge value makes time() + $max_age a float, which
# serializes to garbage and silently downgrades to a session cookie.
# Mirror the expires branch, which caps far-future dates at 10 years.
my $ten_years = 10 * 365 * 24 * 60 * 60;
my $jar = jar_with_set_cookie(
'foo=bar; domain=example.com; path=/; Max-Age=' . ( '9' x 30 ) );
my $expires;
$jar->scan( sub { $expires = $_[8] } );
ok defined $expires, 'cookie is stored with an expiry';
cmp_ok $expires, '>', time(), 'expiry is in the future'
if defined $expires;
cmp_ok $expires, '<=', time() + $ten_years + 10,
'huge Max-Age is capped at ~10 years, not a float overflow'
if defined $expires;
};
subtest 'Max-Age takes precedence over Expires (RFC 6265 5.3)' => sub {
# Max-Age=0 must delete the cookie even when a far-future Expires is also
# present, regardless of the order the two attributes appear in.
for my $sc (
'foo=bar; domain=example.com; path=/; '
. 'expires=Thu, 01-Jan-2099 00:00:00 GMT; Max-Age=0',
'foo=bar; domain=example.com; path=/; '
. 'Max-Age=0; expires=Thu, 01-Jan-2099 00:00:00 GMT',
) {
my $jar = jar_with_set_cookie($sc);
my $count = 0;
$jar->scan( sub { $count++ } );
is $count, 0, "Max-Age=0 wins over Expires ($sc)";
}
};
subtest 'a finite Max-Age wins over a far-future Expires' => sub {
my $jar = jar_with_set_cookie( 'foo=bar; domain=example.com; path=/; '
. 'expires=Thu, 01-Jan-2099 00:00:00 GMT; Max-Age=100' );
my $expires;
$jar->scan( sub { $expires = $_[8] } );
ok defined $expires, 'cookie is stored with an expiry';
cmp_ok $expires, '>', time(), 'expiry is in the future'
if defined $expires;
cmp_ok $expires, '<=', time() + 200,
'the short Max-Age, not the 2099 Expires, controls the expiry'
if defined $expires;
};
subtest 'the last Max-Age wins when repeated (RFC 6265bis 5.7)' => sub {
my $jar = jar_with_set_cookie(
'foo=bar; domain=example.com; path=/; Max-Age=1; Max-Age=5000');
my $expires;
$jar->scan( sub { $expires = $_[8] } );
ok defined $expires, 'cookie is stored with an expiry';
cmp_ok $expires, '>', time() + 1000,
'the later Max-Age (5000) controls the expiry, not the earlier (1)'
if defined $expires;
};
done_testing;
CONTRIBUTORS 100644 001750 001751 2554 15231271120 14602 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12
# HTTP-COOKIES CONTRIBUTORS #
This is the (likely incomplete) list of people who have helped
make this distribution what it is, either via code contributions,
patches, bug reports, help with troubleshooting, etc. A huge
'thank you' to all of them.
* Adam Kennedy
* Adam Sjogren
* Alexey Tourbin
* Alex Kapranoff
* Alex Peters
* amire80
* Andreas J. Koenig
* Bernhard M. Wiedemann
* Bill Mann
* Bron Gondwana
* Charlie Hothersall-Thomas
* Chase Whitener
* Colin Newell
* Daniel Hedlund
* Dave Menninger
* David E. Wheeler
* DAVIDRW
* dependabot[bot]
* Father Chrysostomos
* FWILES
* Gavin Peters
* George Grozdev
* Graeme Thompson
* Hans-H. Froehlich
* Ian Kilgore
* Jacob J
* James McCoy
* James Raspass
* jefflee
* john9art
* Julien Fiegehenn
* Mark Raymond
* Mark Stosberg
* Michal Josef Špaček
* Mike Schilli
* Mohammad S Anwar
* murphy
* Olaf Alders
* Ondrej Hanak
* Perlover
* Peter Rabbitson
* Philip J. Ludlam
* phrstbrn
* Robert Stone
* robnagler
* Rolf Grossmann
* ruff
* sasao
* Sean M. Burke
* Slaven Rezic
* Spiros Denaxas
* Steve Hay
* Todd Lipcon
* Tom Hukins
* Tony Finch
* Toru Yamaguchi
* Ville Skyttä
* Yuri Karaban
* Zefram
perlcriticrc 100644 001750 001751 4405 15231271120 15327 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 severity = 3
verbose = 11
theme = core + pbp + bugs + maintenance + cosmetic + complexity + security + tests + moose
exclude = Subroutines::ProhibitCallsToUndeclaredSubs
[BuiltinFunctions::ProhibitStringySplit]
severity = 3
[CodeLayout::RequireTrailingCommas]
severity = 3
[ControlStructures::ProhibitCStyleForLoops]
severity = 3
[InputOutput::RequireCheckedSyscalls]
functions = :builtins
exclude_functions = sleep
severity = 3
[Moose::RequireCleanNamespace]
modules = Moose Moose::Role MooseX::Role::Parameterized Moose::Util::TypeConstraints
cleaners = namespace::autoclean
[NamingConventions::Capitalization]
package_exemptions = [A-Z]\w+|minFraud
file_lexical_variables = [A-Z]\w+|[^A-Z]+
global_variables = :starts_with_upper
scoped_lexical_variables = [A-Z]\w+|[^A-Z]+
severity = 3
# Given our code base, leaving this at 5 would be a huge pain
[Subroutines::ProhibitManyArgs]
max_arguments = 10
[RegularExpressions::ProhibitComplexRegexes]
max_characters = 200
[RegularExpressions::ProhibitUnusualDelimiters]
severity = 3
[Subroutines::ProhibitUnusedPrivateSubroutines]
private_name_regex = _(?!build)\w+
skip_when_using = Moo::Role Moose::Role MooseX::Role::Parameterized Role::Tiny Test::Class::Moose::Role
[TestingAndDebugging::ProhibitNoWarnings]
allow = redefine
[ValuesAndExpressions::ProhibitEmptyQuotes]
severity = 3
[ValuesAndExpressions::ProhibitInterpolationOfLiterals]
severity = 3
[ValuesAndExpressions::RequireUpperCaseHeredocTerminator]
severity = 3
[Variables::ProhibitPackageVars]
add_packages = Test::Builder
[TestingAndDebugging::RequireUseStrict]
[TestingAndDebugging::RequireUseWarnings]
[-ControlStructures::ProhibitCascadingIfElse]
[-ErrorHandling::RequireCarping]
[-InputOutput::RequireBriefOpen]
[-ValuesAndExpressions::ProhibitConstantPragma]
# No need for /xsm everywhere
[-RegularExpressions::RequireDotMatchAnything]
[-RegularExpressions::RequireExtendedFormatting]
[-RegularExpressions::RequireLineBoundaryMatching]
[-Subroutines::ProhibitExplicitReturnUndef]
# http://stackoverflow.com/questions/2275317/why-does-perlcritic-dislike-using-shift-to-populate-subroutine-variables
[-Subroutines::RequireArgUnpacking]
[-Subroutines::RequireFinalReturn]
# "use v5.14" is more readable than "use 5.014"
[-ValuesAndExpressions::ProhibitVersionStrings]
author 000755 001750 001751 0 15231271120 14511 5 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt eol.t 100644 001750 001751 1073 15231271120 15616 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt/author use strict;
use warnings;
# this test was generated with Dist::Zilla::Plugin::Test::EOL 0.19
use Test::More 0.88;
use Test::EOL;
my @files = (
'lib/HTTP/Cookies.pm',
'lib/HTTP/Cookies/Microsoft.pm',
'lib/HTTP/Cookies/Netscape.pm',
't/00-report-prereqs.dd',
't/00-report-prereqs.t',
't/10-original_spec.t',
't/11-rfc_2965.t',
't/cookies.t',
't/data/netscape-httponly.txt',
't/issue26.t',
't/issue32.t',
't/issue69.t',
't/publicsuffix.t'
);
eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files;
done_testing;
11-rfc_2965.t 100644 001750 001751 13345 15231271120 15050 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t #!perl
use strict;
use warnings;
use Test::More;
use HTTP::Cookies ();
use HTTP::Request ();
use HTTP::Response ();
use URI ();
my $jar = HTTP::Cookies->new();
plan tests => 13;
# https://www.rfc-editor.org/rfc/rfc2965.txt
# Section 4
# Example 1
{
# 1-2
# Most detail of request and response headers has been omitted. Assume
# the user agent has no stored cookies.
# 1. User Agent -> Server
# POST /acme/login HTTP/1.1
# [form data]
# User identifies self via a form.
# 2. Server -> User Agent
# HTTP/1.1 200 OK
# Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
# Cookie reflects user's identity.
my $res = HTTP::Response->new( 200, 'OK' );
$res->header( 'Set-Cookie2' =>
q{Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"} );
my $req = request_for( 'www.acme.com/acme/login', 'POST' );
# we can skip the form data as it's not necessary here
$res->request($req);
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 1,
'1.1-2: res: found the cookie'
);
# 3-4
# 3. User Agent -> Server
# POST /acme/pickitem HTTP/1.1
# Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
# [form data]
# User selects an item for "shopping basket".
# 4. Server -> User Agent
# HTTP/1.1 200 OK
# Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"
# Shopping basket contains an item.
$req = request_for( 'www.acme.com/acme/pickitem', 'POST' );
$jar->add_cookie_header($req);
my $h = $req->header("Cookie"); # checking header contents is easier
like( $h, qr/Customer="?WILE_E_COYOTE"?/, '1.3-4: req: contains header' );
$res->header( 'Set-Cookie2' =>
q{Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"}
);
$res->request($req);
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 2,
'1.3-4: res: found the cookies'
);
# 5-6
# 5. User Agent -> Server
# POST /acme/shipping HTTP/1.1
# Cookie: $Version="1";
# Customer="WILE_E_COYOTE"; $Path="/acme";
# Part_Number="Rocket_Launcher_0001"; $Path="/acme"
# [form data]
# User selects shipping method from form.
# 6. Server -> User Agent
# HTTP/1.1 200 OK
# Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
# New cookie reflects shipping method.
$req = request_for( 'www.acme.com/acme/shipping', 'POST' );
$jar->add_cookie_header($req);
$h = $req->header("Cookie"); # checking header contents is easier
like( $h, qr/Customer="?WILE_E_COYOTE"?/, '1.5-6: req: contains cust' );
like(
$h, qr/Part_Number="?Rocket_Launcher_0001"?/,
'1.5-6: req: contains part'
);
$res->header(
'Set-Cookie2' => q{Shipping="FedEx"; Version="1"; Path="/acme"} );
$res->request($req);
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 3,
'1.5-6: res: found the cookies'
);
# 7-8
# 7. User Agent -> Server
# POST /acme/process HTTP/1.1
# Cookie: $Version="1";
# Customer="WILE_E_COYOTE"; $Path="/acme";
# Part_Number="Rocket_Launcher_0001"; $Path="/acme";
# Shipping="FedEx"; $Path="/acme"
# [form data]
# User chooses to process order.
# 8. Server -> User Agent
# HTTP/1.1 200 OK
# Transaction is complete.
$req = request_for( 'www.acme.com/acme/process', 'POST' );
$jar->add_cookie_header($req);
$h = $req->header("Cookie"); # checking header contents is easier
like( $h, qr/Customer="?WILE_E_COYOTE"?/, '1.7-8: req: contains cust' );
like(
$h, qr/Part_Number="?Rocket_Launcher_0001"?/,
'1.7-8: req: contains part'
);
like( $h, qr/Shipping="?FedEx"?/, '1.7-8: req: contains shipping' );
$res = HTTP::Response->new( 200, 'OK' );
$res->request($req);
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 3,
'1.7-8: res: found the cookies'
);
}
# Example 2
#This example illustrates the effect of the Path attribute. All
# detail of request and response headers has been omitted. Assume the
# user agent has no stored cookies.
{
$jar->clear();
my $res = HTTP::Response->new( 200, 'OK' );
# requests to /acme get rocket launcher
$res->push_header( 'Set-Cookie2' =>
q{Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"}
);
# requests to /acme/ammo will get rocket launcher and rocket
$res->push_header( 'Set-Cookie2' =>
q{Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"}
);
# requests to /acme/anything_else will just get rocket launcher
my $req = request_for( 'www.acme.com/acme/', 'POST' );
$res->request($req);
$jar->extract_cookies($res);
is( count_cookies_for('www.acme.com'), 1, '2: acme: res: one cookie' );
$jar->clear();
$req = request_for( 'www.acme.com/acme/ammo', 'POST' );
$res->request($req);
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 2,
'2: acme/ammo: res: two cookies'
);
$jar->clear();
$req = request_for( 'www.acme.com/acme/parts', 'POST' );
$res->request($req);
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 1,
'2: acme/parts: res: one cookie'
);
}
sub count_cookies_for {
my $host = shift;
my $count = 0;
$jar->scan( sub { $_[4] eq $host && $count++ } );
return $count;
}
sub request_for {
my $uri = URI->new( 'http://' . shift );
my $method = shift || 'GET';
my $req = HTTP::Request->new( $method => $uri );
$req->header( Host => $uri->host_port );
return $req;
}
perlimports.toml 100644 001750 001751 2112 15231271120 16165 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12 # Valid log levels are:
# debug, info, notice, warning, error, critical, alert, emergency
# critical, alert and emergency are not currently used.
#
# Please use boolean values in this config file. Negated options (--no-*) are
# not permitted here. Explicitly set options to true or false.
#
# Some of these values deviate from the regular perlimports defaults. In
# particular, you're encouraged to leave preserve_duplicates and
# preserve_unused disabled.
cache = false # setting this to true is currently discouraged
ignore_modules = ["Test::More"]
ignore_modules_filename = ""
ignore_modules_pattern = "" # regex like "^(Foo|Foo::Bar)"
ignore_modules_pattern_filename = ""
libs = ["lib", "t/lib"]
log_filename = ""
log_level = "warn"
never_export_modules = []
never_export_modules_filename = ""
padding = true
preserve_duplicates = false
preserve_unused = false
tidy_whitespace = true
publicsuffix.t 100644 001750 001751 3570 15231271120 16054 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t #!perl
use strict;
use warnings;
use Test::More;
use HTTP::Cookies ();
use HTTP::Date ();
use HTTP::Request ();
use HTTP::Response ();
my $expiry_string = HTTP::Date::time2str( time + 86_400 );
my $jar = HTTP::Cookies->new;
{
local $TODO = 'Unexpected cookies stored';
my $res = HTTP::Response->new( 200, 'OK' );
my $req = request_for('www.exceptone.co.uk');
$res->header( 'Set-Cookie' =>
"security=fail; Domain=.co.uk; Expires=${expiry_string}" );
$res->request($req);
$jar->extract_cookies($res);
is count_cookies_for('.co.uk'), 0, 'No .co.uk cookies stored in the jar';
}
{
local $TODO = 'Unexpected cookies stored';
my $req = request_for('www.google.co.uk');
$jar->add_cookie_header($req);
is $req->header('Cookie'), undef, 'No cookies sent to www.google.co.uk';
}
{
my $req = request_for('www.google.com');
$jar->add_cookie_header($req);
is $req->header('Cookie'), undef, 'No cookies sent to www.google.com';
}
{
local $TODO = 'Unexpected cookies stored';
my $res = HTTP::Response->new( 200, 'OK' );
my $req = request_for('www.example.com');
$res->header( 'Set-Cookie' =>
"dotcom=pwned; Domain=.com; Expires=${expiry_string}" );
$res->request($req);
$jar->extract_cookies($res);
is count_cookies_for('.com'), 0, 'No .com cookies stored in the jar';
}
{
local $TODO = 'Unexpected cookies stored';
my $req = request_for('www.google.com');
$jar->add_cookie_header($req);
is $req->header('Cookie'), undef, 'No cookies sent to www.google.com';
}
sub count_cookies_for {
my $host = shift;
my $count = 0;
$jar->scan( sub { $_[4] eq $host && $count++ } );
return $count;
}
sub request_for {
my $host = shift;
my $req = HTTP::Request->new( GET => "http://${host}/" );
$req->header( Host => $host );
return $req;
}
done_testing();
HTTP 000755 001750 001751 0 15231271120 14101 5 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/lib Cookies.pm 100644 001750 001751 72200 15231271120 16214 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/lib/HTTP package HTTP::Cookies;
use strict;
use HTTP::Date qw(str2time parse_date time2str);
use HTTP::Headers::Util qw(_split_header_words join_header_words);
our $EPOCH_OFFSET;
our $VERSION = '6.12';
# Legacy: because "use "HTTP::Cookies" used be the ONLY way
# to load the class HTTP::Cookies::Netscape.
require HTTP::Cookies::Netscape;
$EPOCH_OFFSET = 0; # difference from Unix epoch
# A HTTP::Cookies object is a hash. The main attribute is the
# COOKIES 3 level hash: $self->{COOKIES}{$domain}{$path}{$key}.
sub new {
my $class = shift;
my $self = bless {
COOKIES => {},
}, $class;
my %cnf = @_;
for ( keys %cnf ) {
$self->{ lc($_) } = $cnf{$_};
}
$self->load;
$self;
}
sub add_cookie_header {
my $self = shift;
my $request = shift || return;
my $url = $request->uri;
my $scheme = $url->scheme;
unless ( $scheme =~ /^https?\z/ ) {
return;
}
my $domain = _host( $request, $url );
$domain = "$domain.local" unless $domain =~ /\./;
my $secure_request = ( $scheme eq "https" );
my $req_path = _url_path($url);
my $req_port = $url->port;
my $now = time();
_normalize_path($req_path) if $req_path =~ /%/;
my @cval; # cookie values for the "Cookie" header
my $set_ver;
my $netscape_only = 0; # An exact domain match applies to any cookie
while ( $domain =~ /\./ ) {
# Checking $domain for cookies"
my $cookies = $self->{COOKIES}{$domain};
next unless $cookies;
if ( $self->{delayload} && defined( $cookies->{'//+delayload'} ) ) {
my $cookie_data = $cookies->{'//+delayload'}{'cookie'};
delete $self->{COOKIES}{$domain};
$self->load_cookie( $cookie_data->[1] );
$cookies = $self->{COOKIES}{$domain};
next unless $cookies; # should not really happen
}
# Want to add cookies corresponding to the most specific paths
# first (i.e. longest path first)
my $path;
for $path ( sort { length($b) <=> length($a) } keys %$cookies ) {
if ( index( $req_path, $path ) != 0 ) {
next;
}
my ( $key, $array );
while ( ( $key, $array ) = each %{ $cookies->{$path} } ) {
my ( $version, $val, $port, $path_spec, $secure, $expires )
= @$array;
if ( $secure && !$secure_request ) {
next;
}
if ( $expires && $expires < $now ) {
next;
}
if ($port) {
my $found;
if ( $port =~ s/^_// ) {
# The corresponding Set-Cookie attribute was empty
$found++ if $port eq $req_port;
$port = "";
}
else {
my $p;
for $p ( split( /,/, $port ) ) {
$found++, last if $p eq $req_port;
}
}
unless ($found) {
next;
}
}
if ( $version > 0 && $netscape_only ) {
next;
}
# set version number of cookie header.
# XXX: What should it be if multiple matching
# Set-Cookie headers have different versions themselves
if ( !$set_ver++ ) {
if ( $version >= 1 ) {
push( @cval, "\$Version=$version" );
}
elsif ( !$self->{hide_cookie2} ) {
$request->header( Cookie2 => '$Version="1"' );
}
}
# do we need to quote the value
if ( $val =~ /\W/ && $version ) {
$val =~ s/([\\\"])/\\$1/g;
$val = qq("$val");
}
# and finally remember this cookie
push( @cval, "$key=$val" );
if ( $version >= 1 ) {
push( @cval, qq(\$Path="$path") ) if $path_spec;
push( @cval, qq(\$Domain="$domain") ) if $domain =~ /^\./;
if ( defined $port ) {
my $p = '$Port';
$p .= qq(="$port") if length $port;
push( @cval, $p );
}
}
}
}
}
continue {
# Try with a more general domain, alternately stripping
# leading name components and leading dots. When this
# results in a domain with no leading dot, it is for
# Netscape cookie compatibility only:
#
# a.b.c.net Any cookie
# .b.c.net Any cookie
# b.c.net Netscape cookie only
# .c.net Any cookie
if ( $domain =~ s/^\.+// ) {
$netscape_only = 1;
}
else {
$domain =~ s/[^.]*//;
$netscape_only = 0;
}
}
if (@cval) {
if ( my $old = $request->header("Cookie") ) {
unshift( @cval, $old );
}
$request->header( Cookie => join( "; ", @cval ) );
if ( my $hash = $request->{_http_cookies} ) {
%$hash = ( map split( /=/, $_, 2 ), @cval );
}
}
$request;
}
sub get_cookies {
my $self = shift;
my $url = shift;
$url = "https://$url" unless $url =~ m,^[a-zA-Z][a-zA-Z0-9.+\-]*:,;
require HTTP::Request;
my $req = HTTP::Request->new( GET => $url );
my $cookies = $req->{_http_cookies} = {};
$self->add_cookie_header($req);
if (@_) {
return map $cookies->{$_}, @_ if wantarray;
return $cookies->{ $_[0] };
}
return $cookies;
}
sub extract_cookies {
my $self = shift;
my $response = shift || return;
my @set = _split_header_words( $response->_header("Set-Cookie2") );
my @ns_set = $response->_header("Set-Cookie");
return $response unless @set || @ns_set; # quick exit
my $request = $response->request;
my $url = $request->uri;
my $req_host = _host( $request, $url );
$req_host = "$req_host.local" unless $req_host =~ /\./;
my $req_port = $url->port;
my $req_path = _url_path($url);
_normalize_path($req_path) if $req_path =~ /%/;
if (@ns_set) {
# The old Netscape cookie format for Set-Cookie
# http://curl.haxx.se/rfc/cookie_spec.html
# can for instance contain an unquoted "," in the expires
# field, so we have to use this ad-hoc parser.
my $now = time();
# Far-future Expires dates and large Max-Age values are approximated
# at ten years out, to avoid overflowing time_t (or producing a float)
# when the expiry is serialized.
my $ten_years = 10 * 365 * 24 * 60 * 60;
# Build a hash of cookies that was present in Set-Cookie2
# headers. We need to skip them if we also find them in a
# Set-Cookie header.
my %in_set2;
for (@set) {
$in_set2{ $_->[0] }++;
}
my $set;
for $set (@ns_set) {
$set =~ s/^\s+//;
my @cur;
my $param;
my $expires;
my $max_age; # Max-Age value, if seen (takes precedence)
my $expires_age; # expiry secs from now (from an Expires attr)
my $first_param = 1;
for $param ( @{ _split_text($set) } ) {
next unless length($param);
my ( $k, $v ) = split( /\s*=\s*/, $param, 2 );
if ( defined $v ) {
$v =~ s/\s+$//;
#print "$k => $v\n";
}
else {
$k =~ s/\s+$//;
#print "$k => undef";
}
if ( !$first_param && lc($k) eq "expires" ) {
# Record the value rather than applying it now: a Max-Age
# attribute, if present, takes precedence (RFC 6265 5.3), and
# a later Expires overrides an earlier one.
my $etime = str2time($v);
if ( defined $etime ) {
$expires_age = $etime - $now;
}
else {
# parse_date can deal with years outside the range of time_t,
my ( $year, $mon, $day, $hour, $min, $sec, $tz )
= parse_date($v);
if ($year) {
my $thisyear = (gmtime)[5] + 1900;
if ( $year < $thisyear ) {
$expires_age
= -1; # any negative value will do
}
elsif ( $year >= $thisyear + 10 ) {
# the date is at least 10 years into the future, just replace
# it with something approximate
$expires_age = $ten_years;
}
}
}
}
elsif ( !$first_param && lc($k) eq 'max-age' ) {
# RFC 6265 5.2.2: a non-integer Max-Age is ignored, not
# treated as 0 (which would wrongly delete the cookie).
if ( defined $v && $v =~ /\A-?[0-9]+\z/ ) {
# An absurdly large value would make time() + $max_age a
# float in set_cookie and serialize to garbage, so cap
# it at the same ten-year approximation used above.
$v = $ten_years if $v > $ten_years;
# A later Max-Age overrides an earlier one (RFC 6265bis).
$max_age = $v;
}
}
elsif ( !$first_param
&& lc($k) =~ /^(?:version|discard|ns-cookie)/ ) {
# ignore
}
else {
push( @cur, $k => $v );
}
$first_param = 0;
}
next unless @cur;
next if $in_set2{ $cur[0] };
# Apply the expiry once all params are parsed, with Max-Age taking
# precedence over Expires (RFC 6265 5.3).
my $age = defined $max_age ? $max_age : $expires_age;
if ( defined $age ) {
push( @cur, "Max-Age" => $age );
$expires++;
}
# push(@cur, "Port" => $req_port);
push( @cur, "Discard" => undef ) unless $expires;
push( @cur, "Version" => 0 );
push( @cur, "ns-cookie" => 1 );
push( @set, \@cur );
}
}
SET_COOKIE:
for my $set (@set) {
next unless @$set >= 2;
my $key = shift @$set;
my $val = shift @$set;
my %hash;
while (@$set) {
my $k = shift @$set;
my $v = shift @$set;
my $lc = lc($k);
# don't loose case distinction for unknown fields
$k = $lc if $lc =~ /^(?:discard|domain|max-age|
path|port|secure|version)$/x;
if ( $k eq "discard" || $k eq "secure" ) {
$v = 1 unless defined $v;
}
next if exists $hash{$k}; # only first value is significant
$hash{$k} = $v;
}
my %orig_hash = %hash;
my $version = delete $hash{version};
$version = 1 unless defined($version);
my $discard = delete $hash{discard};
my $secure = delete $hash{secure};
my $maxage = delete $hash{'max-age'};
my $ns_cookie = delete $hash{'ns-cookie'};
# Check domain
my $domain = delete $hash{domain};
$domain = lc($domain) if defined $domain;
if ( defined($domain)
&& $domain ne $req_host
&& $domain ne ".$req_host" ) {
if ( $domain !~ /\./ && $domain ne "local" ) {
next SET_COOKIE;
}
$domain = ".$domain" unless $domain =~ /^\./;
if ( $domain =~ /\.\d+$/ ) {
next SET_COOKIE;
}
my $len = length($domain);
unless ( substr( $req_host, -$len ) eq $domain ) {
next SET_COOKIE;
}
my $hostpre = substr( $req_host, 0, length($req_host) - $len );
if ( $hostpre =~ /\./ && !$ns_cookie ) {
next SET_COOKIE;
}
}
else {
$domain = $req_host;
}
my $path = delete $hash{path};
my $path_spec;
if ( defined $path && $path ne '' ) {
$path_spec++;
_normalize_path($path) if $path =~ /%/;
if ( !$ns_cookie
&& substr( $req_path, 0, length($path) ) ne $path ) {
next SET_COOKIE;
}
}
else {
$path = $req_path;
$path =~ s,/[^/]*$,,;
$path = "/" unless length($path);
}
my $port;
if ( exists $hash{port} ) {
$port = delete $hash{port};
if ( defined $port ) {
$port =~ s/\s+//g;
my $found;
for my $p ( split( /,/, $port ) ) {
unless ( $p =~ /^\d+$/ ) {
next SET_COOKIE;
}
$found++ if $p eq $req_port;
}
unless ($found) {
next SET_COOKIE;
}
}
else {
$port = "_$req_port";
}
}
$self->set_cookie(
$version, $key, $val, $path, $domain, $port,
$path_spec, $secure, $maxage, $discard, \%hash
) if $self->set_cookie_ok( \%orig_hash );
}
$response;
}
sub set_cookie_ok {
1;
}
sub set_cookie {
my $self = shift;
my (
$version,
$key, $val, $path, $domain, $port,
$path_spec, $secure, $maxage, $discard, $rest
) = @_;
# path and key can not be empty (key can't start with '$')
return $self
if !defined($path)
|| $path !~ m,^/,
|| !defined($key)
|| $key =~ m,^\$,;
# ensure legal port
if ( defined $port ) {
return $self unless $port =~ /^_?\d+(?:,\d+)*$/;
}
my $expires;
if ( defined $maxage ) {
if ( $maxage <= 0 ) {
delete $self->{COOKIES}{$domain}{$path}{$key};
return $self;
}
$expires = time() + $maxage;
}
$version = 0 unless defined $version;
my @array = (
$version, $val, $port,
$path_spec,
$secure, $expires, $discard
);
push( @array, {%$rest} ) if defined($rest) && %$rest;
# trim off undefined values at end
pop(@array) while !defined $array[-1];
$self->{COOKIES}{$domain}{$path}{$key} = \@array;
$self;
}
sub save {
my $self = shift;
my %args = (
file => $self->{'file'},
ignore_discard => $self->{'ignore_discard'},
@_ == 1 ? ( file => $_[0] ) : @_
);
Carp::croak('Unexpected argument to save method') if keys %args > 2;
my $file = $args{'file'} || return;
open( my $fh, '>', $file ) or die "Can't open $file: $!";
print {$fh} "#LWP-Cookies-1.0\n";
print {$fh} $self->as_string( !$args{'ignore_discard'} );
close $fh or die "Can't close $file: $!";
1;
}
sub load {
my $self = shift;
my $file = shift || $self->{'file'} || return;
local $/ = "\n"; # make sure we got standard record separator
open( my $fh, '<', $file ) or return;
# check that we have the proper header
my $magic = <$fh>;
chomp $magic;
unless ( $magic =~ /^#LWP-Cookies-\d+\.\d+/ ) {
warn "$file does not seem to contain cookies";
return;
}
# go through the file
while ( my $line = <$fh> ) {
chomp $line;
next unless $line =~ s/^Set-Cookie3:\s*//;
my $cookie;
for $cookie ( _split_header_words($line) ) {
my ( $key, $val ) = splice( @$cookie, 0, 2 );
my %hash;
while (@$cookie) {
my $k = shift @$cookie;
my $v = shift @$cookie;
$hash{$k} = $v;
}
my $version = delete $hash{version};
my $path = delete $hash{path};
my $domain = delete $hash{domain};
my $port = delete $hash{port};
my $expires = str2time( delete $hash{expires} );
my $path_spec = exists $hash{path_spec};
delete $hash{path_spec};
my $secure = exists $hash{secure};
delete $hash{secure};
my $discard = exists $hash{discard};
delete $hash{discard};
my @array = (
$version, $val, $port, $path_spec, $secure, $expires,
$discard
);
push( @array, \%hash ) if %hash;
$self->{COOKIES}{$domain}{$path}{$key} = \@array;
}
}
1;
}
sub revert {
my $self = shift;
$self->clear->load;
$self;
}
sub clear {
my $self = shift;
if ( @_ == 0 ) {
$self->{COOKIES} = {};
}
elsif ( @_ == 1 ) {
delete $self->{COOKIES}{ $_[0] };
}
elsif ( @_ == 2 ) {
delete $self->{COOKIES}{ $_[0] }{ $_[1] };
}
elsif ( @_ == 3 ) {
delete $self->{COOKIES}{ $_[0] }{ $_[1] }{ $_[2] };
}
else {
require Carp;
Carp::carp('Usage: $c->clear([domain [,path [,key]]])');
}
$self;
}
sub clear_temporary_cookies {
my ($self) = @_;
$self->scan(
sub {
if (
$_[9] or # "Discard" flag set
not $_[8]
) { # No expire field?
$_[8] = -1; # Set the expire/max_age field
$self->set_cookie(@_); # Clear the cookie
}
}
);
}
sub DESTROY {
my $self = shift;
local ( $., $@, $!, $^E, $? );
$self->save if $self->{'autosave'};
}
sub scan {
my ( $self, $cb ) = @_;
my ( $domain, $path, $key );
for $domain ( sort keys %{ $self->{COOKIES} } ) {
for $path ( sort keys %{ $self->{COOKIES}{$domain} } ) {
for $key ( sort keys %{ $self->{COOKIES}{$domain}{$path} } ) {
my (
$version, $val, $port, $path_spec,
$secure, $expires, $discard, $rest
) = @{ $self->{COOKIES}{$domain}{$path}{$key} };
$rest = {} unless defined($rest);
&$cb(
$version, $key, $val, $path, $domain, $port,
$path_spec, $secure, $expires, $discard, $rest
);
}
}
}
}
sub as_string {
my ( $self, $skip_discard ) = @_;
my @res;
$self->scan(
sub {
my (
$version, $key, $val, $path, $domain, $port,
$path_spec, $secure, $expires, $discard, $rest
) = @_;
return if $discard && $skip_discard;
my @h = ( $key, $val );
push( @h, "path", $path );
push( @h, "domain" => $domain );
push( @h, "port" => $port ) if defined $port;
push( @h, "path_spec" => undef ) if $path_spec;
push( @h, "secure" => undef ) if $secure;
push( @h, "expires" => HTTP::Date::time2isoz($expires) )
if $expires;
push( @h, "discard" => undef ) if $discard;
my $k;
for $k ( sort keys %$rest ) {
push( @h, $k, $rest->{$k} );
}
push( @h, "version" => $version );
push( @res, "Set-Cookie3: " . join_header_words( \@h ) );
}
);
join( "\n", @res, "" );
}
sub _host {
my ( $request, $url ) = @_;
if ( my $h = $request->header("Host") ) {
$h =~ s/:\d+$//; # might have a port as well
return lc($h);
}
return lc( $url->host );
}
sub _url_path {
my $url = shift;
my $path;
if ( $url->can('epath') ) {
$path = $url->epath; # URI::URL method
}
else {
$path = $url->path; # URI::_generic method
}
$path = "/" unless length $path;
$path;
}
sub _normalize_path # so that plain string compare can be used
{
my $x;
$_[0] =~ s/%([0-9a-fA-F][0-9a-fA-F])/
$x = uc($1);
$x eq "2F" || $x eq "25" ? "%$x" :
pack("C", hex($x));
/eg;
$_[0] =~ s/([\0-\x20\x7f-\xff])/sprintf("%%%02X",ord($1))/eg;
}
# deals with splitting values by ; and the fact that they could
# be in quotes which can also have escaping.
sub _split_text {
my $val = shift;
my @vals = grep { $_ ne q{} } split( /([;\\"])/, $val );
my @chunks;
# divide it up into chunks to be processed.
my $in_string = 0;
my @current_string;
for ( my $i = 0 ; $i < @vals ; $i++ ) {
my $chunk = $vals[$i];
if ($in_string) {
if ( $chunk eq q{\\} ) {
# don't care about next char probably.
# having said that, probably need to be appending to the chunks
# just dropping this.
$i++;
if ( $i < @vals ) {
push @current_string, $vals[$i];
}
}
elsif ( $chunk eq q{"} ) {
$in_string = 0;
}
else {
push @current_string, $chunk;
}
}
else {
if ( $chunk eq q{"} ) {
$in_string = 1;
}
elsif ( $chunk eq q{;} ) {
push @chunks, join( q{}, @current_string );
@current_string = ();
}
else {
push @current_string, $chunk;
}
}
}
push @chunks, join( q{}, @current_string ) if @current_string;
s/^\s+// for @chunks;
return \@chunks;
}
1;
=pod
=encoding UTF-8
=head1 NAME
HTTP::Cookies - HTTP cookie jars
=head1 VERSION
version 6.12
=head1 SYNOPSIS
use HTTP::Cookies;
$cookie_jar = HTTP::Cookies->new(
file => "$ENV{'HOME'}/lwp_cookies.dat",
autosave => 1,
);
use LWP;
my $browser = LWP::UserAgent->new;
$browser->cookie_jar($cookie_jar);
Or for an empty and temporary cookie jar:
use LWP;
my $browser = LWP::UserAgent->new;
$browser->cookie_jar( {} );
=head1 DESCRIPTION
This class is for objects that represent a "cookie jar" -- that is, a
database of all the HTTP cookies that a given LWP::UserAgent object
knows about.
Cookies are a general mechanism which server side connections can use
to both store and retrieve information on the client side of the
connection. For more information about cookies refer to
L and
L. This module also implements the
new style cookies described in L.
The two variants of cookies are supposed to be able to coexist happily.
Instances of the class I are able to store a collection
of Set-Cookie2: and Set-Cookie: headers and are able to use this
information to initialize Cookie-headers in I objects.
The state of a I object can be saved in and restored from
files.
=head1 LIMITATIONS
This module does not support L<< Public Suffix|https://publicsuffix.org/
>> encouraged by a more recent standard, L<< RFC
6265|https://tools.ietf.org/html/rfc6265 >>.
This module's shortcomings mean that a malicious Web site can set
cookies to track your user agent across all sites under a top level
domain. See F<< t/publicsuffix.t >> in this module's distribution for
details.
L<< HTTP::CookieJar::LWP >> supports Public Suffix, but only provides a
limited subset of this module's functionality and L<< does not
support|HTTP::CookieJar/LIMITATIONS-AND-CAVEATS >> standards older than
I.
=head1 METHODS
The following methods are provided:
=over 4
=item $cookie_jar = HTTP::Cookies->new
The constructor takes hash style parameters. The following
parameters are recognized:
file: name of the file to restore cookies from and save cookies to
autosave: save during destruction (bool)
ignore_discard: save even cookies that are requested to be discarded (bool)
hide_cookie2: do not add Cookie2 header to requests
Future parameters might include (not yet implemented):
max_cookies 300
max_cookies_per_domain 20
max_cookie_size 4096
no_cookies list of domain names that we never return cookies to
=item $cookie_jar->get_cookies( $url_or_domain )
=item $cookie_jar->get_cookies( $url_or_domain, $cookie_key,... )
Returns a reference to a hash of the cookies that apply to the given URL. If a
domainname is given as argument, then a prefix of "https://" is assumed.
If one or more $cookie_key parameters are provided return the given values,
or C if the cookie isn't available.
=item $cookie_jar->add_cookie_header( $request )
The add_cookie_header() method will set the appropriate Cookie:-header
for the I object given as argument. The $request must
have a valid url attribute before this method is called.
=item $cookie_jar->extract_cookies( $response )
The extract_cookies() method will look for Set-Cookie: and
Set-Cookie2: headers in the I object passed as
argument. Any of these headers that are found are used to update
the state of the $cookie_jar.
=item $cookie_jar->set_cookie( $version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard, \%rest )
The set_cookie() method updates the state of the $cookie_jar. The
$key, $val, $domain, $port and $path arguments are strings. The
$path_spec, $secure, $discard arguments are boolean values. The $maxage
value is a number indicating number of seconds that this cookie will
live. A value of $maxage <= 0 will delete this cookie. The $version argument
sets the version of the cookie; the default value is 0 ( original Netscape
spec ). Setting $version to another value indicates the RFC to which the
cookie conforms (e.g. version 1 for RFC 2109). %rest defines various other
attributes like "Comment" and "CommentURL".
=item $cookie_jar->save
=item $cookie_jar->save( $file )
=item $cookie_jar->save( file => $file, ignore_discard => $ignore_discard )
This method saves the state of the $cookie_jar to a file.
The state can then be restored later using the load() method. If a
filename is not specified we will use the name specified during
construction. If the $ignore_discard value is true (or not specified,
but attribute I was set at cookie jar construction),
then we will even save cookies that are marked to be discarded.
The default is to save a sequence of "Set-Cookie3" lines.
"Set-Cookie3" is a proprietary LWP format, not known to be compatible
with any browser. The I sub-class can
be used to save in a format compatible with Netscape.
=item $cookie_jar->load
=item $cookie_jar->load( $file )
This method reads the cookies from the file and adds them to the
$cookie_jar. The file must be in the format written by the save()
method.
=item $cookie_jar->revert
This method empties the $cookie_jar and re-loads the $cookie_jar
from the last save file.
=item $cookie_jar->clear
=item $cookie_jar->clear( $domain )
=item $cookie_jar->clear( $domain, $path )
=item $cookie_jar->clear( $domain, $path, $key )
Invoking this method without arguments will empty the whole
$cookie_jar. If given a single argument only cookies belonging to
that domain will be removed. If given two arguments, cookies
belonging to the specified path within that domain are removed. If
given three arguments, then the cookie with the specified key, path
and domain is removed.
=item $cookie_jar->clear_temporary_cookies
Discard all temporary cookies. Scans for all cookies in the jar
with either no expire field or a true C flag. To be
called when the user agent shuts down according to RFC 2965.
=item $cookie_jar->scan( \&callback )
The argument is a subroutine that will be invoked for each cookie
stored in the $cookie_jar. The subroutine will be invoked with
the following arguments:
0 version
1 key
2 val
3 path
4 domain
5 port
6 path_spec
7 secure
8 expires
9 discard
10 hash
=item $cookie_jar->as_string
=item $cookie_jar->as_string( $skip_discardables )
The as_string() method will return the state of the $cookie_jar
represented as a sequence of "Set-Cookie3" header lines separated by
"\n". If $skip_discardables is TRUE, it will not return lines for
cookies with the I attribute.
=back
=head1 SEE ALSO
L, L
=head1 AUTHOR
Gisle Aas
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2002 by Gisle Aas.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
__END__
#ABSTRACT: HTTP cookie jars
mojibake.t 100644 001750 001751 151 15231271120 16574 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt/author #!perl
use strict;
use warnings qw(all);
use Test::More;
use Test::Mojibake;
all_files_encoding_ok();
10-original_spec.t 100644 001750 001751 14726 15231271120 16432 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t #!perl
use strict;
use warnings;
use Test::More;
use HTTP::Cookies ();
use HTTP::Date ();
use HTTP::Request ();
use HTTP::Response ();
use URI ();
my $expiry_string = HTTP::Date::time2str( time + 86_400 );
my $jar = HTTP::Cookies->new();
plan tests => 20;
# https://curl.haxx.se/rfc/cookie_spec.html
# First Example transaction sequence:
{
my $res = HTTP::Response->new( 200, 'OK' );
my $req = request_for('www.acme.com');
$res->request($req);
# 1.1
# Client requests a document, and receives in the response:
# Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
$res->header( "Set-Cookie" =>
"CUSTOMER=WILE_E_COYOTE; path=/ ; expires=${expiry_string}" );
$jar->extract_cookies($res);
is( count_cookies_for('www.acme.com'), 1, '1.1: res: found the cookie' );
# 1.2
# When client requests a URL in path "/" on this server, it sends:
# Cookie: CUSTOMER=WILE_E_COYOTE
# Client requests a document, and receives in the response:
# Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
$req = request_for('www.acme.com');
$jar->add_cookie_header($req);
is(
$req->header("Cookie"), "CUSTOMER=WILE_E_COYOTE",
'1.2: req: customer'
);
is( $req->header("Cookie2"), q{$Version="1"}, '1.2: req: version' );
$res->request($req);
$res->header(
"Set-Cookie" => "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/" );
$jar->extract_cookies($res);
is( count_cookies_for('www.acme.com'), 2, '1.2: res: two cookies found' );
# 1.3
# When client requests a URL in path "/" on this server, it sends:
# Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
# Client receives:
# Set-Cookie: SHIPPING=FEDEX; path=/foo
$req = request_for('www.acme.com');
$jar->add_cookie_header($req);
my $h = $req->header("Cookie"); # checking header contents is easier
like(
$h, qr/PART_NUMBER=ROCKET_LAUNCHER_0001/,
'1.3: req: first cookie found'
);
like( $h, qr/CUSTOMER=WILE_E_COYOTE/, '1.3: req: second cookie found' );
$res->request($req);
$res->header( "Set-Cookie" => "SHIPPING=FEDEX; path=/foo" );
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 3,
'1.3: res: three cookies found'
);
# 1.4
# When client requests a URL in path "/" on this server, it sends:
# Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
$req = request_for('www.acme.com');
$jar->add_cookie_header($req);
$h = $req->header("Cookie"); # checking header contents is easier
like(
$h, qr/PART_NUMBER=ROCKET_LAUNCHER_0001/,
'1.4: req: first cookie found'
);
like( $h, qr/CUSTOMER=WILE_E_COYOTE/, '1.4: req: second cookie found' );
unlike( $h, qr/SHIPPING=FEDEX/, '1.4: req: no shipping cookie' );
$res->request($req);
$res->header( "Set-Cookie" =>
"CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001" );
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 3,
'1.4: res: three cookies found'
);
# 1.5
# When client requests a URL in path "/foo" on this server, it sends:
# Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
# The last Cookie is buggy, because both specifications says that the
# most specific cookie must be sent first. SHIPPING=FEDEX is the
# most specific and should thus be first.
$req = request_for('www.acme.com/foo');
$jar->add_cookie_header($req);
$h = $req->header("Cookie"); # checking header contents is easier
like(
$h, qr/PART_NUMBER=ROCKET_LAUNCHER_0001/,
'1.5: req: first cookie found'
);
like( $h, qr/CUSTOMER=WILE_E_COYOTE/, '1.5: req: second cookie found' );
like( $h, qr/SHIPPING=FEDEX/, '1.5: req: third cookie found' );
$res->request($req);
$res->header( "Set-Cookie" =>
"CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001" );
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 3,
'1.5: res: three cookies found'
);
}
# Second Example transaction sequence:
# Assume all mappings from above have been cleared.
{
$jar->clear();
my $res = HTTP::Response->new( 200, 'OK' );
my $req = request_for('www.acme.com');
$res->request($req);
# 2.1
# Client receives:
# Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
# When client requests a URL in path "/" on this server, it sends:
# Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
$res->header(
"Set-Cookie" => "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/" );
$jar->extract_cookies($res);
$req = request_for('www.acme.com');
$jar->add_cookie_header($req);
is(
$req->header("Cookie"), "PART_NUMBER=ROCKET_LAUNCHER_0001",
'2.1: req: cookie found'
);
$res->request($req);
$res->header(
"Set-Cookie" => "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/" );
$jar->extract_cookies($res);
is( count_cookies_for('www.acme.com'), 1, '2.1: res: one cookie found' );
# 2.2
# Client receives:
# Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
# When client requests a URL in path "/ammo" on this server, it sends:
# Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
# NOTE: There are two name/value pairs named "PART_NUMBER" due to the inheritance of the "/" mapping in addition to the "/ammo" mapping.
$res->header(
"Set-Cookie",
"PART_NUMBER=RIDING_ROCKET_0023; path=/ammo"
);
$jar->extract_cookies($res);
$req = request_for('www.acme.com/ammo');
$jar->add_cookie_header($req);
my $h = $req->header("Cookie"); # checking header contents is easier
like(
$h, qr/PART_NUMBER=ROCKET_LAUNCHER_0001/,
'2.2: req: first cookie found'
);
like(
$h, qr/PART_NUMBER=RIDING_ROCKET_0023/,
'2.2: req: second cookie found'
);
$res->request($req);
$jar->extract_cookies($res);
is(
count_cookies_for('www.acme.com'), 2,
'2.2: res: three cookies found'
);
}
sub count_cookies_for {
my $host = shift;
my $count = 0;
$jar->scan( sub { $_[4] eq $host && $count++ } );
return $count;
}
sub request_for {
my $uri = URI->new( 'http://' . shift )->canonical;
my $req = HTTP::Request->new( GET => $uri );
$req->header( Host => $uri->host_port );
return $req;
}
00-report-prereqs.t 100644 001750 001751 13601 15231271120 16574 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t #!perl
use strict;
use warnings;
# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.029
use Test::More tests => 1;
use ExtUtils::MakeMaker;
use File::Spec;
# from $version::LAX
my $lax_version_re =
qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )?
|
(?:\.[0-9]+) (?:_[0-9]+)?
) | (?:
v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )?
|
(?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)?
)
)/x;
# hide optional CPAN::Meta modules from prereq scanner
# and check if they are available
my $cpan_meta = "CPAN::Meta";
my $cpan_meta_pre = "CPAN::Meta::Prereqs";
my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic
# Verify requirements?
my $DO_VERIFY_PREREQS = 1;
sub _max {
my $max = shift;
$max = ( $_ > $max ) ? $_ : $max for @_;
return $max;
}
sub _merge_prereqs {
my ($collector, $prereqs) = @_;
# CPAN::Meta::Prereqs object
if (ref $collector eq $cpan_meta_pre) {
return $collector->with_merged_prereqs(
CPAN::Meta::Prereqs->new( $prereqs )
);
}
# Raw hashrefs
for my $phase ( keys %$prereqs ) {
for my $type ( keys %{ $prereqs->{$phase} } ) {
for my $module ( keys %{ $prereqs->{$phase}{$type} } ) {
$collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module};
}
}
}
return $collector;
}
my @include = qw(
);
my @exclude = qw(
);
# Add static prereqs to the included modules list
my $static_prereqs = do './t/00-report-prereqs.dd';
# Merge all prereqs (either with ::Prereqs or a hashref)
my $full_prereqs = _merge_prereqs(
( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ),
$static_prereqs
);
# Add dynamic prereqs to the included modules list (if we can)
my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml';
my $cpan_meta_error;
if ( $source && $HAS_CPAN_META
&& (my $meta = eval { CPAN::Meta->load_file($source) } )
) {
$full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs);
}
else {
$cpan_meta_error = $@; # capture error from CPAN::Meta->load_file($source)
$source = 'static metadata';
}
my @full_reports;
my @dep_errors;
my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs;
# Add static includes into a fake section
for my $mod (@include) {
$req_hash->{other}{modules}{$mod} = 0;
}
for my $phase ( qw(configure build test runtime develop other) ) {
next unless $req_hash->{$phase};
next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING});
for my $type ( qw(requires recommends suggests conflicts modules) ) {
next unless $req_hash->{$phase}{$type};
my $title = ucfirst($phase).' '.ucfirst($type);
my @reports = [qw/Module Want Have/];
for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) {
next if grep { $_ eq $mod } @exclude;
my $want = $req_hash->{$phase}{$type}{$mod};
$want = "undef" unless defined $want;
$want = "any" if !$want && $want == 0;
if ($mod eq 'perl') {
push @reports, ['perl', $want, $]];
next;
}
my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required";
my $file = $mod;
$file =~ s{::}{/}g;
$file .= ".pm";
my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC;
if ($prefix) {
my $have = MM->parse_version( File::Spec->catfile($prefix, $file) );
$have = "undef" unless defined $have;
push @reports, [$mod, $want, $have];
if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) {
if ( $have !~ /\A$lax_version_re\z/ ) {
push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)";
}
elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) {
push @dep_errors, "$mod version '$have' is not in required range '$want'";
}
}
}
else {
push @reports, [$mod, $want, "missing"];
if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) {
push @dep_errors, "$mod is not installed ($req_string)";
}
}
}
if ( @reports ) {
push @full_reports, "=== $title ===\n\n";
my $ml = _max( map { length $_->[0] } @reports );
my $wl = _max( map { length $_->[1] } @reports );
my $hl = _max( map { length $_->[2] } @reports );
if ($type eq 'modules') {
splice @reports, 1, 0, ["-" x $ml, "", "-" x $hl];
push @full_reports, map { sprintf(" %*s %*s\n", -$ml, $_->[0], $hl, $_->[2]) } @reports;
}
else {
splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl];
push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports;
}
push @full_reports, "\n";
}
}
}
if ( @full_reports ) {
diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports;
}
if ( $cpan_meta_error || @dep_errors ) {
diag "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n";
}
if ( $cpan_meta_error ) {
my ($orig_source) = grep { -f } 'MYMETA.json', 'MYMETA.yml';
diag "\nCPAN::Meta->load_file('$orig_source') failed with: $cpan_meta_error\n";
}
if ( @dep_errors ) {
diag join("\n",
"\nThe following REQUIRED prerequisites were not satisfied:\n",
@dep_errors,
"\n"
);
}
pass('Reported prereqs');
# vim: ts=4 sts=4 sw=4 et:
pod-syntax.t 100644 001750 001751 251 15231271120 17122 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt/author #!perl
# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests
use strict; use warnings;
use Test::More;
use Test::Pod 1.41;
all_pod_files_ok();
00-report-prereqs.dd 100644 001750 001751 4206 15231271120 16701 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t do { my $x = {
'configure' => {
'requires' => {
'ExtUtils::MakeMaker' => '0'
}
},
'develop' => {
'requires' => {
'App::perlvars' => '0',
'Pod::Coverage::TrustPod' => '0',
'Test::CPAN::Changes' => '0.19',
'Test::EOL' => '0',
'Test::Mojibake' => '0',
'Test::More' => '0.96',
'Test::Pod' => '1.41',
'Test::Pod::Coverage' => '1.08',
'Test::Portability::Files' => '0',
'Test::Version' => '1',
'warnings' => '0'
}
},
'runtime' => {
'requires' => {
'Carp' => '0',
'HTTP::Date' => '6',
'HTTP::Headers::Util' => '6',
'HTTP::Request' => '0',
'locale' => '0',
'perl' => '5.008001',
'strict' => '0'
}
},
'test' => {
'recommends' => {
'CPAN::Meta' => '2.120900'
},
'requires' => {
'ExtUtils::MakeMaker' => '0',
'File::Spec' => '0',
'HTTP::Response' => '0',
'Test::More' => '0.96',
'URI' => '0',
'warnings' => '0'
}
}
};
$x;
} portability.t 100644 001750 001751 130 15231271120 17352 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt/author use strict;
use warnings;
use Test::More;
use Test::Portability::Files;
run_tests();
pod-coverage.t 100644 001750 001751 2154 15231271120 17413 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt/author #!perl
# This file was automatically generated by Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable 0.07.
use Test::Pod::Coverage 1.08;
use Test::More 0.88;
BEGIN {
if ( $] <= 5.008008 ) {
plan skip_all => 'These tests require Pod::Coverage::TrustPod, which only works with Perl 5.8.9+';
}
}
use Pod::Coverage::TrustPod;
my %skip = map { $_ => 1 } qw( HTTP::Cookies::Microsoft );
my @modules;
for my $module ( all_modules() ) {
next if $skip{$module};
push @modules, $module;
}
plan skip_all => 'All the modules we found were excluded from POD coverage test.'
unless @modules;
plan tests => scalar @modules;
my %trustme = (
'HTTP::Cookies' => [
qr/set_cookie_ok/
]
);
my @also_private;
for my $module ( sort @modules ) {
pod_coverage_ok(
$module,
{
coverage_class => 'Pod::Coverage::TrustPod',
also_private => \@also_private,
trustme => $trustme{$module} || [],
},
"pod coverage for $module"
);
}
done_testing();
test-version.t 100644 001750 001751 637 15231271120 17466 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt/author use strict;
use warnings;
use Test::More;
# generated by Dist::Zilla::Plugin::Test::Version 1.09
use Test::Version;
my @imports = qw( version_all_ok );
my $params = {
is_strict => 0,
has_version => 1,
multiple => 0,
};
push @imports, $params
if version->parse( $Test::Version::VERSION ) >= version->parse('1.002');
Test::Version->import(@imports);
version_all_ok;
done_testing;
release 000755 001750 001751 0 15231271120 14627 5 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt cpan-changes.t 100644 001750 001751 344 15231271120 17464 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/xt/release use strict;
use warnings;
# this test was generated with Dist::Zilla::Plugin::Test::CPAN::Changes 0.013
use Test::More 0.96 tests => 1;
use Test::CPAN::Changes;
subtest 'changes_ok' => sub {
changes_file_ok('Changes');
};
Cookies 000755 001750 001751 0 15231271120 15475 5 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/lib/HTTP Netscape.pm 100644 001750 001751 7116 15231271120 17742 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/lib/HTTP/Cookies package HTTP::Cookies::Netscape;
use strict;
our $VERSION = '6.12';
require HTTP::Cookies;
our @ISA = qw(HTTP::Cookies);
sub load {
my ( $self, $file ) = @_;
$file ||= $self->{'file'} || return;
local $/ = "\n"; # make sure we got standard record separator
open( my $fh, '<', $file ) || return;
my $magic = <$fh>;
chomp $magic;
unless ( $magic =~ /^#(?: Netscape)? HTTP Cookie File/ ) {
warn "$file does not look like a netscape cookies file";
return;
}
my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
while ( my $line = <$fh> ) {
chomp($line);
$line =~ s/\s*\#HttpOnly_//;
next if $line =~ /^\s*\#/;
next if $line =~ /^\s*$/;
$line =~ tr/\n\r//d;
my ( $domain, $bool1, $path, $secure, $expires, $key, $val )
= split( /\t/, $line );
$secure = ( $secure eq "TRUE" );
$self->set_cookie(
undef, $key, $val, $path, $domain, undef, 0,
$secure, $expires - $now, 0
);
}
1;
}
sub save {
my $self = shift;
my %args = (
file => $self->{'file'},
ignore_discard => $self->{'ignore_discard'},
@_ == 1 ? ( file => $_[0] ) : @_
);
Carp::croak('Unexpected argument to save method') if keys %args > 2;
my $file = $args{'file'} || return;
open( my $fh, '>', $file ) || return;
# Use old, now broken link to the old cookie spec just in case something
# else (not us!) requires the comment block exactly this way.
print {$fh} <scan(
sub {
my (
$version, $key, $val, $path, $domain, $port, $path_spec,
$secure, $expires, $discard, $rest
) = @_;
return if $discard && !$args{'ignore_discard'};
$expires = $expires ? $expires - $HTTP::Cookies::EPOCH_OFFSET : 0;
return if $now > $expires;
$secure = $secure ? "TRUE" : "FALSE";
my $bool = $domain =~ /^\./ ? "TRUE" : "FALSE";
print {$fh} join(
"\t", $domain, $bool, $path, $secure, $expires, $key,
$val
),
"\n";
}
);
1;
}
1;
=pod
=encoding UTF-8
=head1 NAME
HTTP::Cookies::Netscape - Access to Netscape cookies files
=head1 VERSION
version 6.12
=head1 SYNOPSIS
use LWP;
use HTTP::Cookies::Netscape;
$cookie_jar = HTTP::Cookies::Netscape->new(
file => "c:/program files/netscape/users/ZombieCharity/cookies.txt",
);
my $browser = LWP::UserAgent->new;
$browser->cookie_jar( $cookie_jar );
=head1 DESCRIPTION
This is a subclass of C that reads (and optionally
writes) Netscape/Mozilla cookie files.
See the documentation for L.
=head1 CAVEATS
Please note that the Netscape/Mozilla cookie file format can't store
all the information available in the Set-Cookie2 headers, so you will
probably lose some information if you save in this format.
At time of writing, this module seems to work fine with Mozilla
Phoenix/Firebird.
=head1 SEE ALSO
L
=head1 AUTHOR
Gisle Aas
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2002 by Gisle Aas.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
__END__
#ABSTRACT: Access to Netscape cookies files
data 000755 001750 001751 0 15231271120 13730 5 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t netscape-httponly.txt 100644 001750 001751 1174 15231271120 20315 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/t/data # Netscape HTTP Cookie File
# http://www.netscape.com/newsref/std/cookie_spec.html
# This is a generated file! Do not edit.
# Should be loaded as normal
www.acme.com FALSE / FALSE 21474836470 foo1 bar
# Should be loaded with hostname www.acme.com
#HttpOnly_www.acme.com FALSE / FALSE 21474836470 foo2 bar
#HttpOnly_www.acme.com FALSE / FALSE 21474836470 foo3 bar
#HttpOnly_www.acme.com FALSE / FALSE 21474836470 foo4 bar
# Should not be loaded (double prefix)
#HttpOnly_#HttpOnly_www.acme.com FALSE / FALSE 21474836470 foo5 bar
# Should not be loaded (case-sensitivity)
#Httponly_www.acme.com FALSE / FALSE 21474836470 foo6 bar
Microsoft.pm 100644 001750 001751 23075 15231271120 20167 0 ustar 00olaf olaf 000000 000000 HTTP-Cookies-6.12/lib/HTTP/Cookies package HTTP::Cookies::Microsoft;
use strict;
our $VERSION = '6.12';
require HTTP::Cookies;
our @ISA = qw(HTTP::Cookies);
sub load_cookies_from_file {
my ($file) = @_;
my @cookies;
open( my $fh, '<', $file ) || return;
while ( my $key = <$fh> ) {
chomp $key;
my ( $value, $domain_path, $flags, $lo_expire, $hi_expire );
my ( $lo_create, $hi_create, $sep );
chomp( $value = <$fh> );
chomp( $domain_path = <$fh> );
chomp( $flags = <$fh> ); # 0x0001 bit is for secure
chomp( $lo_expire = <$fh> );
chomp( $hi_expire = <$fh> );
chomp( $lo_create = <$fh> );
chomp( $hi_create = <$fh> );
chomp( $sep = <$fh> );
if ( !defined($key)
|| !defined($value)
|| !defined($domain_path)
|| !defined($flags)
|| !defined($hi_expire)
|| !defined($lo_expire)
|| !defined($hi_create)
|| !defined($lo_create)
|| !defined($sep)
|| ( $sep ne '*' ) ) {
last;
}
if ( $domain_path =~ /^([^\/]+)(\/.*)$/ ) {
my $domain = $1;
my $path = $2;
push @cookies, {
KEY => $key, VALUE => $value, DOMAIN => $domain,
PATH => $path, FLAGS => $flags, HIXP => $hi_expire,
LOXP => $lo_expire, HICREATE => $hi_create,
LOCREATE => $lo_create
};
}
}
return \@cookies;
}
sub get_user_name {
use Win32;
use locale;
my $user = lc( Win32::LoginName() );
return $user;
}
# MSIE stores create and expire times as Win32 FILETIME,
# which is 64 bits of 100 nanosecond intervals since Jan 01 1601
#
# But Cookies code expects time in 32-bit value expressed
# in seconds since Jan 01 1970
#
sub epoch_time_offset_from_win32_filetime {
my ( $high, $low ) = @_;
#--------------------------------------------------------
# USEFUL CONSTANT
#--------------------------------------------------------
# 0x019db1de 0xd53e8000 is 1970 Jan 01 00:00:00 in Win32 FILETIME
#
# 100 nanosecond intervals == 0.1 microsecond intervals
my $filetime_low32_1970 = 0xd53e8000;
my $filetime_high32_1970 = 0x019db1de;
#------------------------------------
# ALGORITHM
#------------------------------------
# To go from 100 nanosecond intervals to seconds since 00:00 Jan 01 1970:
#
# 1. Adjust 100 nanosecond intervals to Jan 01 1970 base
# 2. Divide by 10 to get to microseconds (1/millionth second)
# 3. Divide by 1000000 (10 ^ 6) to get to seconds
#
# We can combine Step 2 & 3 into one divide.
#
# After much trial and error, I came up with the following code which
# avoids using Math::BigInt or floating pt, but still gives correct answers
# If the filetime is before the epoch, return 0
if (
( $high < $filetime_high32_1970 )
|| ( ( $high == $filetime_high32_1970 )
&& ( $low < $filetime_low32_1970 ) )
) {
return 0;
}
# Can't multiply by 0x100000000, (1 << 32),
# without Perl issuing an integer overflow warning
#
# So use two multiplies by 0x10000 instead of one multiply by 0x100000000
#
# The result is the same.
#
my $date1970 = ( ( $filetime_high32_1970 * 0x10000 ) * 0x10000 )
+ $filetime_low32_1970;
my $time = ( ( $high * 0x10000 ) * 0x10000 ) + $low;
$time -= $date1970;
$time /= 10000000;
return $time;
}
sub load_cookie {
my ( $self, $file ) = @_;
my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
my $cookie_data;
if ( -f $file ) {
# open the cookie file and get the data
$cookie_data = load_cookies_from_file($file);
foreach my $cookie ( @{$cookie_data} ) {
my $secure = ( $cookie->{FLAGS} & 1 ) != 0;
my $expires = epoch_time_offset_from_win32_filetime(
$cookie->{HIXP},
$cookie->{LOXP}
);
$self->set_cookie(
undef, $cookie->{KEY}, $cookie->{VALUE},
$cookie->{PATH}, $cookie->{DOMAIN}, undef,
0, $secure, $expires - $now, 0
);
}
}
}
sub load {
my ( $self, $cookie_index ) = @_;
my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
my $cookie_dir = '';
my $delay_load
= ( defined( $self->{'delayload'} ) && $self->{'delayload'} );
my $user_name = get_user_name();
my $data;
$cookie_index ||= $self->{'file'} || return;
if ( $cookie_index =~ /[\\\/][^\\\/]+$/ ) {
$cookie_dir = $` . "\\";
}
open( my $fh, '<:raw', $cookie_index ) || return;
if ( 256 != read( $fh, $data, 256 ) ) {
warn "$cookie_index file is not large enough";
return;
}
# Cookies' index.dat file starts with 32 bytes of signature
# followed by an offset to the first record, stored as a little-endian DWORD
my ( $sig, $size ) = unpack( 'a32 V', $data );
# check that sig is valid (only tested in IE6.0)
if ( ( $sig !~ /^Client UrlCache MMF Ver 5\.2/ ) || ( 0x4000 != $size ) )
{
warn "$cookie_index ['$sig' $size] does not seem to contain cookies";
return;
}
# move the file ptr to start of the first record
if ( 0 == seek( $fh, $size, 0 ) ) {
return;
}
# Cookies are usually stored in 'URL ' records in two contiguous 0x80 byte sectors (256 bytes)
# so read in two 0x80 byte sectors and adjust if not a Cookie.
while ( 256 == read( $fh, $data, 256 ) ) {
# each record starts with a 4-byte signature
# and a count (little-endian DWORD) of 0x80 byte sectors for the record
( $sig, $size ) = unpack( 'a4 V', $data );
# Cookies are found in 'URL ' records
if ( 'URL ' ne $sig ) {
# skip over uninteresting record: I've seen 'HASH' and 'LEAK' records
if ( ( $sig eq 'HASH' ) || ( $sig eq 'LEAK' ) ) {
# '-2' takes into account the two 0x80 byte sectors we've just read in
if ( ( $size > 0 ) && ( $size != 2 ) ) {
if ( 0 == seek( $fh, ( $size - 2 ) * 0x80, 1 ) ) {
# Seek failed. Something's wrong. Gonna stop.
last;
}
}
}
next;
}
#$REMOVE Need to check if URL records in Cookies' index.dat will
# ever use more than two 0x80 byte sectors
if ( $size > 2 ) {
my $more_data = ( $size - 2 ) * 0x80;
if ( $more_data != read( $fh, $data, $more_data, 256 ) ) {
last;
}
}
( my $user_name2 = $user_name ) =~ s/ /_/g;
if ( $data
=~ /Cookie:\Q$user_name\E@([\x21-\xFF]+).*?((?:\Q$user_name\E|\Q$user_name2\E)@[\x21-\xFF]+\.txt)/
) {
my $cookie_file = $cookie_dir . $2; # form full pathname
if ( !$delay_load ) {
$self->load_cookie($cookie_file);
}
else {
my $domain = $1;
# grab only the domain name, drop everything from the first dir sep on
if ( $domain =~ m{[\\/]} ) {
$domain = $`;
}
# set the delayload cookie for this domain with
# the cookie_file as cookie for later-loading info
$self->set_cookie(
undef, 'cookie', $cookie_file,
'//+delayload', $domain, undef, 0, 0, $now + 86_400, 0
);
}
}
}
1;
}
1;
=pod
=encoding UTF-8
=head1 NAME
HTTP::Cookies::Microsoft - Access to Microsoft cookies files
=head1 VERSION
version 6.12
=head1 SYNOPSIS
use LWP;
use HTTP::Cookies::Microsoft;
use Win32::TieRegistry(Delimiter => "/");
my $cookies_dir = $Registry->
{"CUser/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders/Cookies"};
$cookie_jar = HTTP::Cookies::Microsoft->new(
file => "$cookies_dir\\index.dat",
'delayload' => 1,
);
my $browser = LWP::UserAgent->new;
$browser->cookie_jar( $cookie_jar );
=head1 DESCRIPTION
This is a subclass of C which
loads Microsoft Internet Explorer 5.x and 6.x for Windows (MSIE)
cookie files.
See the documentation for L.
=head1 METHODS
The following methods are provided:
=over 4
=item $cookie_jar = HTTP::Cookies::Microsoft->new;
The constructor takes hash style parameters. In addition
to the regular HTTP::Cookies parameters, HTTP::Cookies::Microsoft
recognizes the following:
delayload: delay loading of cookie data until a request
is actually made. This results in faster
runtime unless you use most of the cookies
since only the domain's cookie data
is loaded on demand.
=back
=head1 CAVEATS
Please note that the code DOESN'T support saving to the MSIE
cookie file format.
=head1 AUTHOR
Johnny Lee
=head1 COPYRIGHT
Copyright 2002 Johnny Lee
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 AUTHOR
Gisle Aas
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2002 by Gisle Aas.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
__END__
#ABSTRACT: Access to Microsoft cookies files