Apache-Session-1.94000755000000000000 013731226572 14610 5ustar00unknownunknown000000000000Apache-Session-1.94/Build.PL000444000000000000 171713730772477 16260 0ustar00unknownunknown000000000000use strict; use Module::Build; #created by eumm-migrate.pl my $build = Module::Build->new( 'dist_abstract' => 'A persistence framework for session data', 'license' => 'perl', 'build_requires' => { 'Test::More' => '0.47', 'Test::Exception' => '0.15', 'Test::Deep' => '0.082', ($ENV{TRAVIS}?('Test::Database'=>0, 'DBD::mysql'=>0, 'DBD::Pg' => 0,):()), }, 'dist_author' => 'Casey West ', 'module_name' => 'Apache::Session', 'meta_merge' => { 'keywords' => [ 'CGI', 'session', 'web' ], 'resources' => { 'repository' => 'http://github.com/chorny/Apache-Session' } }, 'requires' => { 'perl' => '5.005', 'File::Temp' => 0, 'Storable' => '0.6', 'constant' => 0, 'Digest::MD5' => 0, 'IO::File' => 0, }, 'dist_version_from' => 'lib/Apache/Session.pm', 'auto_configure_requires' => 0, ); $build->create_build_script(); Apache-Session-1.94/CHANGES000444000000000000 1767613731226335 15776 0ustar00unknownunknown000000000000In near future Apache::Session may require perl 5.6. If you use perl older than 5.6 - write to alexchorny[AT]gmail.com and tell me what version do you use, why and will you need newer versions of Apache::Session. 1.94 2020-09-19 - better error if LockDataSource is missing in Apache::Session::Lock::MySQL 1.93 2014-04-12 - even more test fixes 1.92 2014-03-08 - more test fixes 1.91 2014-01-07 by Alexandr Ciornii, Perl 26th birthday version - Add a test for RT#50896 - 99mysql.t will work more correctly in some corner cases 1.90 2013-01-27 by Alexandr Ciornii, Perl 25th birthday version - Allow specifying table for Oracle - Use Test::Database for tests 1.89 2010-09-22 by Alexandr Ciornii - require Digest::MD5 - all semaphore tests were removed - Apache::Session::Store::File::materialize should not append to $session->{serialized} - Apache::Session::Store::File will flush after writing to file 1.88 2008-12-20 by Alexandr Ciornii - Apache::Session::Generate::MD5::validate will untaint data - MIN_PERL_VERSION in Makefile.PL 1.87=1.86_03 2008-08-08 1.86_03 2008-08-03 by Alexandr Ciornii - disabled 99semaphore.t. Help needed. 1.86_02 2008-06-27 by Alexandr Ciornii - correct number of tests in 99semaphore.t 1.86_01 2008-06-20 by Alexandr Ciornii - use Carp::confess in Apache::Session::Lock::Semaphore - more info in die message in Apache::Session::Generate::MD5 (RT#36412, by Knut Arne Bjorndal) - semaphore tests check for semctl availability - Makefile.PL prints message if perl version < 5.006 1.86 2008-02-01 by Alexandr Ciornii - Default number of semaphores for *BSD is 8 in Apache::Session::Lock::Semaphore 1.85_01 2008-01-24 by Alexandr Ciornii - typos corrected (catched by Gerald Fox) - more tests and diag in 99semaphore.t - no warning "disconnect invalidates 2 active statement" in Apache::Session::Lock::MySQL by Tony Cook (RT#32148) 1.85 2007-12-20 by Alexandr Ciornii, Perl 20th birthday version - mention Catalyst::Plugin::Session, Session 1.84_01 2007-11-26 by Alexandr Ciornii (alexchorny AT gmail.com) - Added Apache::Session::Lock::Semaphore::remove to remove semaphore - 99flex.t will remove semaphore (RT#30440) - 99flex.t should work on 5.6.1 again (no chdir now) - 99flex.t will clean all temporary files (RT#30209) - pod.t included in MANIFEST - cleaner tests 1.84 2007-10-02 by Alexandr Ciornii (alexchorny AT gmail.com) - Added constant.pm to the list of prerequisites - Jeffrey W. Baker, Casey West, Alexandr Ciornii, Oliver Maul agreed to change license of all files to Perl license Alexandr Ciornii agrees to relicense to Artistic 2.0 in future if needed. - 99flex.t will be skipped on *bsd and Solaris 1.83_01 2007-08-03 by Alexandr Ciornii - better handling of Storable errors by Rick Delaney (RT#27476) 1.83=1.82_05 2007-05-25 1.82_05 2007-05-14 by Alexandr Ciornii - skipping part of 99flex.t on NetBSD 1.82_04 2007-04-27 by Alexandr Ciornii - More diagnostics in Apache::Session::Lock::Semaphore::acquire_write_lock, acquire_read_lock - Did not increment modules versions in previous versions of distribution - Apache::Session::Lock::Semaphore can work with private semaphore - 99flex.t will use private semaphore - 99dbfile.t, 99dbfilestore.t - added undef (for RT#6216) 1.82_03 2007-03-12 by Alexandr Ciornii - Apache::Session::Lock::File checks flock success (RT#6936) - Apache::Session::Lock::File will not change to shared lock if write lock is in effect and read lock is requested (RT#7072) - 99dbfile.t, 99dbfilestore.t - added untie (for RT#6216) - Apache::Session::Lock::Semaphore will check for $Config{d_semget} and cygserver 1.82_02 2007-03-11 by Alexandr Ciornii - 99semaphore.t, 99flex.t will be skipped if $Config{d_semget}==undef, patch by Slaven Rezic - Removed redundant code in 99filelock.t - Removed unnecessary skip in 99nulllock.t - Added file 'Contributing.txt' - Apache::Session - mention CGI::Session - Request in Makefile.PL 1.82_01 2007-03-10 by Alexandr Ciornii - Applied part of patch of SREZIC (Slaven Rezic), RT#3670, more diagnostics on failing file operations (Apache::Session::Lock::File, Apache::Session::Store::DB_File, Apache::Session::Store::File) - RT#1251, ModUniqueId.pm, ModUsertrack.pm - small error in Carp usage, by Slaven Rezic - 99flex.t will be skipped on perls earlier than 5.8 (RT#16539) - Requires Storable (core from 5.7.3), as it is almost useless without it 1.82 2007-02-21 by Alexandr Ciornii - Slightly faster test skip - 99semaphore.t and 99flex.t check for cygserver on Cygwin - 99flex.t skips less tests in some cases - 99flex.t checks for Digest::MD5, MIME::Base64 - Warning in doc of Apache::Session::Lock::Semaphore about cygserver - Requires File::Temp (core from 5.6.1), needed for tests and work - Changed order of use/chdir in tests (RT#16539, from Andrew Benham) 1.81_01 2007-02-12 by Alexandr Ciornii - My patch for Win32 and Cygwin (RT#18795) - More information in Makefile.PL - 99flex.t checks for Storable (RT#101) - 99semaphore.t does not die if IPC:: modules are not present 1.81 2006-05-23 - Don't unconditionally try to require packages in Apache::Session::Flex (Dave Rolsky). 1.8 2005-10-06 - Bug fix to stop death in Apache::Session::Lock::Semaphore. 1.70_01 2004-09-01 - Casey West takes the pumpkin. - Complete rewrite of test suite to use Test::* modules. - Minor documentation tweaks. --- Changes in 1.6 (2004-02-24): Fixed file age test for clean(). The previous test was never true. Applied patch to add TableName option to the DBI/MySQL store. From Corris Randall . Tests added by jwb. Applied patch from Oliver Maul for better Sybase support, without tests. Informix support from Mike Langen . Unfortunately no tests were included. Changes in 1.54 (2001-10-11): Added mod_uniqueid and mod_usertrack generators from Tatsuhiko Miyagawa Fixed validate function in Flex. Move to Digest::MD5 instead of MD5. Changes in 1.53 (2000-09-01): ? Changes in 1.52 (2000-07-23): Chris Winters added the Sybase backing store and related modules. Michael Schout fixed a commit policy bug in 1.51. Edward Lopez fixed a thinko in the POD. Peter Baker fixed a typo in the POD. Andrew Wild fixed a typo in the POD. Alan Sparks fixed a type in the POD. Jay Lawrence changed the interface so that an undefined or false variable indicates a fresh session. Previously, only undefined was considered new. Lupe Christoph noticed that there was a buffer race condition in the file store, which is now fixed. Changes in 1.51: Added the Oracle backing store. Changes in 1.50: If you are upgrading from a previous version of Apache::Session, please note these changes: The Apache::Session::DBI module is gone. It has been obsoleted by MySQL and Postgres. Please read the documentation for the module that corresponds with your database. The semaphore locker is no longer used anywhere by default. If you want to turn it on, you need to hack the modules themselves, or us Apache::Session::Flex. By default, all IDs are now 32-characters long. You can truncate them to the previous default of 16 characters by providing the IDLength argument when tieing your sessions. Note that you might also need to extend the datatype of the ID column in your database schema. All of the modules have been refreshed. I suggest reading the documentation for the ones that you plan to use. Jeffrey Apache-Session-1.94/Contributing.txt000444000000000000 66712101234351 20126 0ustar00unknownunknown000000000000If you want better support for older Perls, use CPAN::Reporter (Test::Reporter for CPANPLUS). Also you can run cpan smoking. That way module can be fixed even before you'll find that you need it. See CPAN::Reporter::Smoker. Generally, you should use Test::Reporter - it's the only way to measure popularity of distribution. Why do anything with it, if it is not used. Patches welcome. Please write tests for error you found. Apache-Session-1.94/INSTALL000444000000000000 44311254001142 15735 0ustar00unknownunknown000000000000 First, build, test, and install mod_perl and Apache. You may also need to install one or more of the following modules from CPAN: DBI, IPC::Shareable, Storable, FreezeThaw, MD5. After all of that: perl Makefile.PL make install perldoc Apache::Session Have fun, Jeffrey Apache-Session-1.94/Makefile.PL000444000000000000 455313730772506 16730 0ustar00unknownunknown000000000000use 5.005; #VERSION_FROM in Makefile.PL #Symbol.pm requires 5.002 #5.004 almost 11 years ago, earliest version supported by perlver #5.003_07 earliest version on CPAN use ExtUtils::MakeMaker; WriteMakefile1( NAME => "Apache::Session", VERSION_FROM => "lib/Apache/Session.pm", MIN_PERL_VERSION => 5.005, META_MERGE => { resources=> { repository => 'http://github.com/chorny/Apache-Session', }, keywords => ['CGI','session','web'], }, 'LICENSE' => 'perl', PREREQ_PM => { 'File::Temp' => 0, #core from 5.6.1 'Storable' => '0.6', #Will be raised later 'constant' => 0, #Available on CPAN now # 'MIME::Base64' => 0, #new versions require 5.6 # 'DB_File' => 0, #test 'Digest::MD5' => 0, #core from 5.8 'IO::File' => 0, #core }, BUILD_REQUIRES => { 'Test::More' => '0.47', #Build 'Test::Deep' => '0.082', #Build 'Test::Exception' => '0.15', #Build }, AUTHOR => 'Casey West ', ABSTRACT => 'A persistence framework for session data', 'PL_FILES' => {}, ); sub WriteMakefile1 { #Written by Alexandr Ciornii, version 0.21. Added by eumm-upgrade. my %params=@_; my $eumm_version=$ExtUtils::MakeMaker::VERSION; $eumm_version=eval $eumm_version; die "EXTRA_META is deprecated" if exists $params{EXTRA_META}; die "License not specified" if not exists $params{LICENSE}; if ($params{BUILD_REQUIRES} and $eumm_version < 6.5503) { #EUMM 6.5502 has problems with BUILD_REQUIRES $params{PREREQ_PM}={ %{$params{PREREQ_PM} || {}} , %{$params{BUILD_REQUIRES}} }; delete $params{BUILD_REQUIRES}; } delete $params{CONFIGURE_REQUIRES} if $eumm_version < 6.52; delete $params{MIN_PERL_VERSION} if $eumm_version < 6.48; delete $params{META_MERGE} if $eumm_version < 6.46; delete $params{META_ADD} if $eumm_version < 6.46; delete $params{LICENSE} if $eumm_version < 6.31; delete $params{AUTHOR} if $] < 5.005; delete $params{ABSTRACT_FROM} if $] < 5.005; delete $params{BINARY_LOCATION} if $] < 5.005; WriteMakefile(%params); } Apache-Session-1.94/MANIFEST000444000000000000 304412101235315 16060 0ustar00unknownunknown000000000000Build.PL CHANGES Contributing.txt INSTALL MANIFEST This list of files META.yml Makefile.PL README lib/Apache/Session.pm lib/Apache/Session/DB_File.pm lib/Apache/Session/File.pm lib/Apache/Session/Flex.pm lib/Apache/Session/Generate/MD5.pm lib/Apache/Session/Generate/ModUniqueId.pm lib/Apache/Session/Generate/ModUsertrack.pm lib/Apache/Session/Informix.pm lib/Apache/Session/Lock/File.pm lib/Apache/Session/Lock/MySQL.pm lib/Apache/Session/Lock/Null.pm lib/Apache/Session/Lock/Semaphore.pm lib/Apache/Session/Lock/Sybase.pm lib/Apache/Session/MySQL.pm lib/Apache/Session/MySQL/NoLock.pm lib/Apache/Session/Oracle.pm lib/Apache/Session/Postgres.pm lib/Apache/Session/Serialize/Base64.pm lib/Apache/Session/Serialize/Storable.pm lib/Apache/Session/Serialize/Sybase.pm lib/Apache/Session/Serialize/UUEncode.pm lib/Apache/Session/Store/DBI.pm lib/Apache/Session/Store/DB_File.pm lib/Apache/Session/Store/File.pm lib/Apache/Session/Store/Informix.pm lib/Apache/Session/Store/MySQL.pm lib/Apache/Session/Store/Oracle.pm lib/Apache/Session/Store/Postgres.pm lib/Apache/Session/Store/Sybase.pm lib/Apache/Session/Sybase.pm TODO b/dbi.b b/dbinew.b b/dbipop.b b/dbstore.b b/flexpop.b b/gdbm.b b/mysqllock.b b/uuevsmime.b eg/example.perl t/99base64.t t/99dbfile.t t/99dbfilestore.t t/99file.t t/99filelock.t t/99filestore.t t/99flex.t t/99md5gen.t t/99moduniqgen.t t/99mysql.t t/99mysqllock.t t/99mysqlstore.t t/99nulllock.t t/99oracle.t t/99postgres.t t/99semaphore.t t/99storable.t t/99uue.t t/pod.t META.json Apache-Session-1.94/META.json000444000000000000 1241513731226572 16411 0ustar00unknownunknown000000000000{ "abstract" : "A persistence framework for session data", "author" : [ "Casey West " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4211", "keywords" : [ "CGI", "session", "web" ], "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Apache-Session", "prereqs" : { "build" : { "requires" : { "Test::Deep" : "0.082", "Test::Exception" : "0.15", "Test::More" : "0.47" } }, "runtime" : { "requires" : { "Digest::MD5" : "0", "File::Temp" : "0", "IO::File" : "0", "Storable" : "0.6", "constant" : "0", "perl" : "5.005" } } }, "provides" : { "Apache::Session" : { "file" : "lib/Apache/Session.pm", "version" : "1.94" }, "Apache::Session::DB_File" : { "file" : "lib/Apache/Session/DB_File.pm", "version" : "1.01" }, "Apache::Session::File" : { "file" : "lib/Apache/Session/File.pm", "version" : "1.54" }, "Apache::Session::Flex" : { "file" : "lib/Apache/Session/Flex.pm", "version" : "1.01" }, "Apache::Session::Generate::MD5" : { "file" : "lib/Apache/Session/Generate/MD5.pm", "version" : "2.12" }, "Apache::Session::Generate::ModUniqueId" : { "file" : "lib/Apache/Session/Generate/ModUniqueId.pm", "version" : "0.02" }, "Apache::Session::Generate::ModUsertrack" : { "file" : "lib/Apache/Session/Generate/ModUsertrack.pm", "version" : "0.02" }, "Apache::Session::Informix" : { "file" : "lib/Apache/Session/Informix.pm", "version" : "1.01" }, "Apache::Session::Lock::File" : { "file" : "lib/Apache/Session/Lock/File.pm", "version" : "1.04" }, "Apache::Session::Lock::MySQL" : { "file" : "lib/Apache/Session/Lock/MySQL.pm", "version" : "1.01" }, "Apache::Session::Lock::Null" : { "file" : "lib/Apache/Session/Lock/Null.pm", "version" : "1.01" }, "Apache::Session::Lock::Semaphore" : { "file" : "lib/Apache/Session/Lock/Semaphore.pm", "version" : "1.04" }, "Apache::Session::Lock::Sybase" : { "file" : "lib/Apache/Session/Lock/Sybase.pm", "version" : "1.00" }, "Apache::Session::MySQL" : { "file" : "lib/Apache/Session/MySQL.pm", "version" : "1.01" }, "Apache::Session::MySQL::NoLock" : { "file" : "lib/Apache/Session/MySQL/NoLock.pm", "version" : "0.01" }, "Apache::Session::Oracle" : { "file" : "lib/Apache/Session/Oracle.pm", "version" : "1.01" }, "Apache::Session::Postgres" : { "file" : "lib/Apache/Session/Postgres.pm", "version" : "1.01" }, "Apache::Session::Serialize::Base64" : { "file" : "lib/Apache/Session/Serialize/Base64.pm", "version" : "1.01" }, "Apache::Session::Serialize::Storable" : { "file" : "lib/Apache/Session/Serialize/Storable.pm", "version" : "1.01" }, "Apache::Session::Serialize::Sybase" : { "file" : "lib/Apache/Session/Serialize/Sybase.pm", "version" : "1.00" }, "Apache::Session::Serialize::UUEncode" : { "file" : "lib/Apache/Session/Serialize/UUEncode.pm", "version" : "1.01" }, "Apache::Session::Store::DBI" : { "file" : "lib/Apache/Session/Store/DBI.pm", "version" : "1.02" }, "Apache::Session::Store::DB_File" : { "file" : "lib/Apache/Session/Store/DB_File.pm", "version" : "1.01" }, "Apache::Session::Store::File" : { "file" : "lib/Apache/Session/Store/File.pm", "version" : "1.04" }, "Apache::Session::Store::Informix" : { "file" : "lib/Apache/Session/Store/Informix.pm", "version" : "1.02" }, "Apache::Session::Store::MySQL" : { "file" : "lib/Apache/Session/Store/MySQL.pm", "version" : "1.04" }, "Apache::Session::Store::Oracle" : { "file" : "lib/Apache/Session/Store/Oracle.pm", "version" : "1.10" }, "Apache::Session::Store::Postgres" : { "file" : "lib/Apache/Session/Store/Postgres.pm", "version" : "1.03" }, "Apache::Session::Store::Sybase" : { "file" : "lib/Apache/Session/Store/Sybase.pm", "version" : "1.01" }, "Apache::Session::Sybase" : { "file" : "lib/Apache/Session/Sybase.pm", "version" : "1.00" } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "url" : "http://github.com/chorny/Apache-Session" } }, "version" : "1.94", "x_serialization_backend" : "JSON version 2.90" } Apache-Session-1.94/META.yml000444000000000000 714013731226572 16220 0ustar00unknownunknown000000000000--- abstract: A persistence framework for session data author: - 'Casey West ' build_requires: Test::Deep: 0.082 Test::Exception: 0.15 Test::More: 0.47 dynamic_config: 1 generated_by: 'Module::Build version 0.4211, CPAN::Meta::Converter version 2.150005' keywords: - CGI - session - web license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Apache-Session provides: Apache::Session: file: lib/Apache/Session.pm version: 1.94 Apache::Session::DB_File: file: lib/Apache/Session/DB_File.pm version: 1.01 Apache::Session::File: file: lib/Apache/Session/File.pm version: 1.54 Apache::Session::Flex: file: lib/Apache/Session/Flex.pm version: 1.01 Apache::Session::Generate::MD5: file: lib/Apache/Session/Generate/MD5.pm version: 2.12 Apache::Session::Generate::ModUniqueId: file: lib/Apache/Session/Generate/ModUniqueId.pm version: 0.02 Apache::Session::Generate::ModUsertrack: file: lib/Apache/Session/Generate/ModUsertrack.pm version: 0.02 Apache::Session::Informix: file: lib/Apache/Session/Informix.pm version: 1.01 Apache::Session::Lock::File: file: lib/Apache/Session/Lock/File.pm version: 1.04 Apache::Session::Lock::MySQL: file: lib/Apache/Session/Lock/MySQL.pm version: 1.01 Apache::Session::Lock::Null: file: lib/Apache/Session/Lock/Null.pm version: 1.01 Apache::Session::Lock::Semaphore: file: lib/Apache/Session/Lock/Semaphore.pm version: 1.04 Apache::Session::Lock::Sybase: file: lib/Apache/Session/Lock/Sybase.pm version: 1.00 Apache::Session::MySQL: file: lib/Apache/Session/MySQL.pm version: 1.01 Apache::Session::MySQL::NoLock: file: lib/Apache/Session/MySQL/NoLock.pm version: 0.01 Apache::Session::Oracle: file: lib/Apache/Session/Oracle.pm version: 1.01 Apache::Session::Postgres: file: lib/Apache/Session/Postgres.pm version: 1.01 Apache::Session::Serialize::Base64: file: lib/Apache/Session/Serialize/Base64.pm version: 1.01 Apache::Session::Serialize::Storable: file: lib/Apache/Session/Serialize/Storable.pm version: 1.01 Apache::Session::Serialize::Sybase: file: lib/Apache/Session/Serialize/Sybase.pm version: 1.00 Apache::Session::Serialize::UUEncode: file: lib/Apache/Session/Serialize/UUEncode.pm version: 1.01 Apache::Session::Store::DBI: file: lib/Apache/Session/Store/DBI.pm version: 1.02 Apache::Session::Store::DB_File: file: lib/Apache/Session/Store/DB_File.pm version: 1.01 Apache::Session::Store::File: file: lib/Apache/Session/Store/File.pm version: 1.04 Apache::Session::Store::Informix: file: lib/Apache/Session/Store/Informix.pm version: 1.02 Apache::Session::Store::MySQL: file: lib/Apache/Session/Store/MySQL.pm version: 1.04 Apache::Session::Store::Oracle: file: lib/Apache/Session/Store/Oracle.pm version: 1.10 Apache::Session::Store::Postgres: file: lib/Apache/Session/Store/Postgres.pm version: 1.03 Apache::Session::Store::Sybase: file: lib/Apache/Session/Store/Sybase.pm version: 1.01 Apache::Session::Sybase: file: lib/Apache/Session/Sybase.pm version: 1.00 requires: Digest::MD5: 0 File::Temp: 0 IO::File: 0 Storable: 0.6 constant: 0 perl: 5.005 resources: license: http://dev.perl.org/licenses/ repository: http://github.com/chorny/Apache-Session version: 1.94 x_serialization_backend: YAML version 1.23 Apache-Session-1.94/README000444000000000000 755412322312407 15624 0ustar00unknownunknown000000000000--------------------------------------------------------------------------- 24 February 2004 Jeffrey W. Baker --------------------------------------------------------------------------- DESCRIPTION ----------- This is Apache::Session 1.93 These modules provide persistent storage for arbitrary data, in arbitrary backing stores. The details of interacting with the backing store are abstracted to make all backing stores behave alike. The programmer simply interacts with a tied hash. COPYRIGHT AND LICENSE --------------------- Apache::Session is Copyright (c) 1998, 1999, 2000, 2001, 2004 Jeffrey William Baker . Distribute under the same terms as Perl itself. Apache::Session is Copyright (c) 2004-2006 Casey West, . Disribute under the same terms as Perl itself. Apache::Session is Copyright (c) 2007-2014 Alexandr Ciornii. Disribute under the same terms as Perl itself. PREREQUISITES ------------- Required for testing: Test::More, Test::Deep, Test::Exception, File::Temp Required for work: Storable, constant Most of Apache::Session's functions require Digest::MD5. If you wish to use the DBI backing stores, you need the latest version of DBI and the driver for your database. Currently MySQL, Postgres, and Oracle are supported. INSTALLATION ------------ Auto Use CPAN's or CPANPLUS's shell. Manual: tar -xvzf Apache-Session-1.91.tar.gz cd Apache-Session-1.91 perl Makefile.PL make make test make install Substitute "nmake"/"dmake" for "make" above if you are using Windows. EXAMPLE ------- See eg/example.perl. This program is intended to be run under mod_perl. AUTHORS ------- Jeffrey Baker is the author of Apache::Session. Tatsuhiko Miyagawa is the author of Generate::ModUniqueID and Generate::ModUsertrack Erik Rantapaa found errors in both Lock::File and Store::File Bart Schaefer notified me of a bug in Lock::File. Chris Winters contributed the Sybase code. Michael Schout fixed a commit policy bug in 1.51. Andreas J. Koenig contributed valuable CPAN advice and also Apache::Session::Tree and Apache::Session::Counted. Gerald Richter had the idea for a tied hash interface and provided the initial code for it. He also uses Apache::Session in his Embperl module and is the author of Apache::Session::Embperl Jochen Wiedmann contributed patches for bugs and improved performance. Steve Shreeve squashed a bug in 0.99.0 whereby a cleared hash or deleted key failed to set the modified bit. Peter Kaas sent quite a bit of feedback with ideas for interface improvements. Randy Harmon contributed the original storage-independent object interface with input from: Bavo De Ridder Jules Bean Lincoln Stein Scott McWhirter contributed verbose error messages for file locking. Corris Randall gave us the option to use any table name in the MySQL store. Oliver Maul updated the Sybase modules Innumerable users sent a patch for the reversed file age test in the file locking module. Mike Langen contributed Informix modules. FURTHER INFORMATION: -------------------- Apache by Apache Group comp.infosystems.www.servers.unix http://www.apache.org/ mod_perl by Doug MacEachern modperl@apache.org http://perl.apache.org/ Apache-Session-1.94/TODO000444000000000000 301411254001142 15411 0ustar00unknownunknown000000000000- Document the API Apache::Session expects you to implement for new stores, lockers, serializers, and generators. - Make interfaces more abstract so using a tied hash is not the only easily accessible option. - Review and expand test coverage as much as possible (anybody have a spare Sybase or Oracle?). - Address anything at http://rt.cpan.org/NoAuth/Bugs.html?Dist=Apache-Session - Address anything in http://cpanratings.perl.org/d/Apache-Session appropriately. - Review and apply suggestions and patches from contributors. - Form a secret cabal to get the cpanrating up to 4.5 stars. - Work with any testing monkeys that the Phalanx project brings me, http://qa.perl.org/phalanx/distros.html - Always precede a release with as many dev releases as necessary (is this getting too detailed?). - Generally treat the distribution with great care because it is widely used. Apache-Session-1.94/b000755000000000000 013731226572 15031 5ustar00unknownunknown000000000000Apache-Session-1.94/b/dbi.b000444000000000000 157511254001142 16055 0ustar00unknownunknown000000000000use Apache::Session::DBI; use DBI; use Benchmark; use vars qw($dbh $id); $dbh = DBI->connect('dbi:mysql:sessions', 'test', '', {RaiseError => 1}); sub new_session { my $s; tie %$s, 'Apache::Session::DBI', undef, {Handle => $dbh}; } sub get_id { my $s; tie %$s, 'Apache::Session::DBI', undef, {Handle => $dbh}; $id = $s->{_session_id}; } sub reopen { my $s; tie %$s, 'Apache::Session::DBI', $id, {Handle => $dbh}; } sub openread { my $s; tie %$s, 'Apache::Session::DBI', $id, {Handle => $dbh}; my $sid = $s->{_session_id}; } sub openwrite { my $s; tie %$s, 'Apache::Session::DBI', $id, {Handle => $dbh}; $s->{foo} = 'bar'; } &get_id; timethese(10000, { 'New' => \&new_session, 'Reopen' => \&reopen, 'Read Old' => \&openread, 'Write Old' => \&openwrite, }); Apache-Session-1.94/b/dbinew.b000444000000000000 31111254001142 16532 0ustar00unknownunknown000000000000use Apache::Session::File; use Benchmark; sub dotie { my $hashref; tie %$hashref, 'Apache::Session::File', undef, {Directory => '/tmp'}; } timethis(100000, \&dotie, 'Construct 100k'); Apache-Session-1.94/b/dbipop.b000444000000000000 25011254001142 16541 0ustar00unknownunknown000000000000use Apache::Session::DBI; $hashref = {}; sub foo { Apache::Session::DBI::populate($hashref); } use Benchmark; timethis(-10, \&foo, 'Construct 100K'); Apache-Session-1.94/b/dbstore.b000444000000000000 225511254001142 16755 0ustar00unknownunknown000000000000use strict; use Benchmark; use Apache::Session::Store::DB_File; use vars qw($rs $ws $n); my $dir = int(rand(10000)); mkdir $dir, 0700; chdir $dir; $ws = { args => {FileName => 'bench.dbm'}, data => {_session_id => 0}, serialized => "A"x2**10 }; $rs = { args => {FileName => 'bench.dbm'}, data => {_session_id => 0}, serialized => "A"x2**10 }; sub insert { my $store = new Apache::Session::Store::DB_File; $store->insert($ws); $ws->{data}->{_session_id}++; } sub materialize { $rs->{data}->{_session_id} = int(rand($ws->{data}->{_session_id} - 1)); my $store = new Apache::Session::Store::DB_File; $store->materialize($rs); } timethis(1000, \&insert, 'Insert First 1000'); timethis(1000, \&materialize, 'Random Access n=1000'); for (my $i = 0; $i < 9000; $i++) { &insert; } timethis(1000, \&insert, 'Insert 10000-11000'); timethis(1000, \&materialize, 'Random Access n=11000'); for (my $i = 0; $i < 89000; $i++) { &insert; } timethis(1000, \&insert, 'Insert 100000-101000'); timethis(1000, \&materialize, 'Random Access n=101000'); unlink './bench.dbm'; chdir '..'; rmdir $dir; Apache-Session-1.94/b/flexpop.b000444000000000000 42611254001142 16746 0ustar00unknownunknown000000000000use Apache::Session::Flex; use Benchmark; $hashref = { args => { Store => 'DBI', Lock => 'Semaphore', Generate => 'MD5', Serialize => 'Storable', } }; sub foo { Apache::Session::Flex::populate($hashref); } timethis(-10, \&foo, 'Construct 100K'); Apache-Session-1.94/b/gdbm.b000444000000000000 123411254001142 16220 0ustar00unknownunknown000000000000#!/usr/bin/perl -w use GDBM_File; use Benchmark; use vars qw(%hash $n); $n = 0; tie %hash, 'GDBM_File', '/tmp/foo.gdbm', &GDBM_WRCREAT, 0640; sub insert { $hash{$n} = "A"x2**10; $n++; } sub access { my $this = $hash{int(rand($n-1))}; } timethis(10000, \&insert, 'First 10000'); timethis(10000, \&access, 'Random Access n=10000'); timethis(90000, \&insert, 'Pad to 100000'); timethis(10000, \&insert, 'Insert 100000-110000'); timethis(10000, \&access, 'Random Access n=110000'); timethis(990000, \&insert, 'Pad to 1000000'); timethis(10000, \&insert, 'Insert 1000000-1001000'); timethis(10000, \&access, 'Random Access n=1001000'); Apache-Session-1.94/b/mysqllock.b000444000000000000 276411254001142 17336 0ustar00unknownunknown000000000000use Benchmark; use Apache::Session::Lock::MySQL; use vars qw($s $dbh); $s = { args => { LockDataSource => 'dbi:mysql:database=test;host=desk.eng.vivaldi', LockUsername => 'jwb', LockPassword => '' }, data => { _session_id => '' } }; $dbh = DBI->connect('dbi:mysql:database=test;host=desk.eng.vivaldi', 'jwb', '', {RaiseError => 1}); sub loop { $s->{data}->{_session_id} = int(rand(2**20)); my $l = new Apache::Session::Lock::MySQL; $l->acquire_read_lock($s); $l->acquire_write_lock($s); } timethis(1000, \&loop, 'Connect 1000 Times'); $s->{args}->{LockHandle} = $dbh; timethis(10000, \&loop, 'Connect Once, Lock 10000 Times'); `mkfifo sync`; for ($n = 10; $n <= 100; $n += 10) { $dbh->disconnect; my $is_child; for (my $i = 0; $i < $n - 1; $i++) { my $pid = fork; if (!$pid) { $is_child = 1; open (SYNC, ">sync") || die $!; last; } } if (!$is_child) { print "Sleeping 2 seconds to sync children\n"; sleep 2; open(GO, "connect('dbi:mysql:database=test;hostname=desk.eng.vivaldi', 'jwb', '', {RaiseError => 1}); $s->{args}->{LockHandle} = $dbh; timethis(-1, \&loop, "$n Children"); if ($is_child) { exit(); } for (my $i = 0; $i < $n - 1; $i++) { wait(); } close GO; } unlink "sync"; Apache-Session-1.94/b/uuevsmime.b000444000000000000 256211254001142 17333 0ustar00unknownunknown000000000000use Benchmark; use Apache::Session::Serialize::UUEncode; use Apache::Session::Serialize::Base64; use Apache::Session::Serialize::Storable; use vars qw($hash); $hash = { serialized => undef, data => { foo => 'A'x32, bar => [1,2,3,4,5,6,7,8,9,0], baz => { blah => 'A'x32, bleh => 'B'x32 } } }; sub uue { my $z = Apache::Session::Serialize::UUEncode::serialize($hash); Apache::Session::Serialize::UUEncode::unserialize($hash); } sub base64 { my $z = Apache::Session::Serialize::Base64::serialize($hash); Apache::Session::Serialize::Base64::unserialize($hash); } sub storable { my $z = Apache::Session::Serialize::Storable::serialize($hash); Apache::Session::Serialize::Storable::unserialize($hash); } timethese(-3, { Base64 => \&base64, UUE => \&uue, Storable => \&storable }); $hash->{data}->{foo} = 'A'x32000; timethese(-3, { 'Big Base64' => \&base64, 'Big UUE' => \&uue, 'Big Storable' => \&storable, }); print "Length with UUE: ". length(Apache::Session::Serialize::UUEncode::serialize($hash)) ."\n"; print "Length with Base64: ". length(Apache::Session::Serialize::Base64::serialize($hash)) ."\n"; print "Length with Storable: ". length(Apache::Session::Serialize::Storable::serialize($hash)) ."\n"; Apache-Session-1.94/eg000755000000000000 013731226572 15203 5ustar00unknownunknown000000000000Apache-Session-1.94/eg/example.perl000444000000000000 256211254001142 17642 0ustar00unknownunknown000000000000###################################################################### # # Consult the documentation before trying to run this file. # You need a /tmp directory or you need to change the Directory option! # This file also assumes PerlSendHeader Off. # ###################################################################### use strict; use Apache; use CGI; use Apache::Session::File; my $r = Apache->request(); $r->status(200); $r->content_type("text/html"); $r->send_http_header; my $session_id = $r->path_info(); $session_id =~ s/^\///; $session_id = $session_id ? $session_id : undef; my %session; my $opts = { Directory => '/tmp', LockDirectory => 'tmp', Transaction => 1 }; tie %session, 'Apache::Session::File', $session_id, $opts; my $input = CGI::param('input'); $session{name} = $input if $input; print<<__EOS__; Hello
Session ID number is: $session{_session_id}
The Session ID is embedded in the URL

Your input to the form was: $input
Your name is $session{name}

Reload this session
New session
Type in your name here:
__EOS__ Apache-Session-1.94/lib000755000000000000 013731226572 15356 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache000755000000000000 013731226572 16537 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache/Session.pm000444000000000000 4362113731226370 20677 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session # Apache persistent user sessions # Copyright(c) 1998, 1999, 2000, 2001, 2004 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################# =head1 NAME Apache::Session - A persistence framework for session data =head1 SYNOPSIS use Apache::Session::MySQL; my %session; #make a fresh session for a first-time visitor tie %session, 'Apache::Session::MySQL'; #stick some stuff in it $session{visa_number} = "1234 5678 9876 5432"; #get the session id for later use my $id = $session{_session_id}; #...time passes... #get the session data back out again during some other request my %session; tie %session, 'Apache::Session::MySQL', $id; validate($session{visa_number}); #delete a session from the object store permanently tied(%session)->delete; =head1 DESCRIPTION Apache::Session is a persistence framework which is particularly useful for tracking session data between httpd requests. Apache::Session is designed to work with Apache and mod_perl, but it should work under CGI and other web servers, and it also works outside of a web server altogether. Apache::Session consists of five components: the interface, the object store, the lock manager, the ID generator, and the serializer. The interface is defined in Session.pm, which is meant to be easily subclassed. The object store can be the filesystem, a Berkeley DB, a MySQL DB, an Oracle DB, a Postgres DB, Sybase, or Informix. Locking is done by lock files, semaphores, or the locking capabilities of the various databases. Serialization is done via Storable, and optionally ASCII-fied via MIME or pack(). ID numbers are generated via MD5. The reader is encouraged to extend these capabilities to meet his own requirements. A derived class of Apache::Session is used to tie together the three following components. The derived class inherits the interface from Apache::Session, and specifies which store and locker classes to use. Apache::Session::MySQL, for instance, uses the MySQL storage class and also the MySQL locking class. You can easily plug in your own object store or locker class. =head1 INTERFACE The interface to Apache::Session is very simple: tie a hash to the desired class and use the hash as normal. The constructor takes two optional arguments. The first argument is the desired session ID number, or undef for a new session. The second argument is a hash of options that will be passed to the object store and locker classes. =head2 tieing the session Get a new session using DBI: tie %session, 'Apache::Session::MySQL', undef, { DataSource => 'dbi:mysql:sessions' }; Restore an old session from the database: tie %session, 'Apache::Session::MySQL', $session_id, { DataSource => 'dbi:mysql:sessions' }; =head2 Storing and retrieving data to and from the session Hey, how much easier could it get? $session{first_name} = "Chuck"; $session{an_array_ref} = [ $one, $two, $three ]; $session{an_object} = Some::Class->new; =head2 Reading the session ID The session ID is the only magic entry in the session object, but anything beginning with an "_" is considered reserved for future use. my $id = $session{_session_id}; =head2 Permanently removing the session from storage tied(%session)->delete; =head1 BEHAVIOR Apache::Session tries to behave the way the author believes that you would expect. When you create a new session, Session immediately saves the session to the data store, or calls die() if it cannot. It also obtains an exclusive lock on the session object. If you retrieve an existing session, Session immediately restores the object from storage, or calls die() in case of an error. Session also obtains a non-exclusive lock on the session. As you put data into the session hash, Session squirrels it away for later use. When you untie() the session hash, or it passes out of scope, Session checks to see if anything has changed. If so, Session gains an exclusive lock and writes the session to the data store. It then releases any locks it has acquired. Note that Apache::Session does only a shallow check to see if anything has changed. If nothing changes in the top level tied hash, the data will not be updated in the backing store. You are encouraged to timestamp the session hash so that it is sure to be updated. When you call the delete() method on the session object, the object is immediately removed from the object store, if possible. When Session encounters an error, it calls die(). You will probably want to wrap your session logic in an eval block to trap these errors. =head1 LOCKING AND TRANSACTIONS By default, most Apache::Session implementations only do locking to prevent data corruption. The locking scheme does not provide transactional consistency, such as you might get from a relational database. If you desire transactional consistency, you must provide the Transaction argument with a true value when you tie the session hash. For example: tie %s, 'Apache::Session::File', $id { Directory => '/tmp/sessions', LockDirectory => '/var/lock/sessions', Transaction => 1 }; Note that the Transaction argument has no practical effect on the MySQL and Postgres implementations. The MySQL implementation only supports exclusive locking, and the Postgres implementation uses the transaction features of that database. =head1 IMPLEMENTATION The way you implement Apache::Session depends on what you are trying to accomplish. Here are some hints on which classes to use in what situations =head1 STRATEGIES Apache::Session is mainly designed to track user session between http requests. However, it can also be used for any situation where data persistence is desirable. For example, it could be used to share global data between your httpd processes. The following examples are short mod_perl programs which demonstrate some session handling basics. =head2 Sharing data between Apache processes When you share data between Apache processes, you need to decide on a session ID number ahead of time and make sure that an object with that ID number is in your object store before starting your Apache. How you accomplish that is your own business. I use the session ID "1". Here is a short program in which we use Apache::Session to store out database access information. use Apache; use Apache::Session::File; use DBI; use strict; my %global_data; eval { tie %global_data, 'Apache::Session::File', 1, {Directory => '/tmp/sessiondata'}; }; if ($@) { die "Global data is not accessible: $@"; } my $dbh = DBI->connect($global_data{datasource}, $global_data{username}, $global_data{password}) || die $DBI::errstr; undef %global_data; #program continues... As shown in this example, you should undef or untie your session hash as soon as you are done with it. This will free up any locks associated with your process. =head2 Tracking users with cookies The choice of whether to use cookies or path info to track user IDs is a rather religious topic among Apache users. This example uses cookies. The implementation of a path info system is left as an exercise for the reader. Note that Apache::Session::Generate::ModUsertrack uses Apache's mod_usertrack cookies to generate and maintain session IDs. use Apache::Session::MySQL; use Apache; use strict; #read in the cookie if this is an old session my $r = Apache->request; my $cookie = $r->header_in('Cookie'); $cookie =~ s/SESSION_ID=(\w*)/$1/; #create a session object based on the cookie we got from the browser, #or a new session if we got no cookie my %session; tie %session, 'Apache::Session::MySQL', $cookie, { DataSource => 'dbi:mysql:sessions', #these arguments are UserName => 'mySQL_user', #required when using Password => 'password', #MySQL.pm LockDataSource => 'dbi:mysql:sessions', LockUserName => 'mySQL_user', LockPassword => 'password' }; #Might be a new session, so lets give them their cookie back my $session_cookie = "SESSION_ID=$session{_session_id};"; $r->header_out("Set-Cookie" => $session_cookie); #program continues... =head1 SEE ALSO Apache::Session::MySQL, Apache::Session::Postgres, Apache::Session::File, Apache::Session::DB_File, Apache::Session::Oracle, Apache::Session::Sybase The O Reilly book "Apache Modules in Perl and C", by Doug MacEachern and Lincoln Stein, has a chapter on keeping state. CGI::Session uses OO interface to do same thing. It is better maintained, but less possibilies. Catalyst::Plugin::Session - support of sessions in Catalyst Session - OO interface to Apache::Session =head1 LICENSE Under the same terms as Perl itself. =head1 AUTHORS Alexandr Ciornii, L - current maintainer Jeffrey Baker is the author of Apache::Session. Tatsuhiko Miyagawa is the author of Generate::ModUniqueID and Generate::ModUsertrack Erik Rantapaa found errors in both Lock::File and Store::File Bart Schaefer notified me of a bug in Lock::File. Chris Winters contributed the Sybase code. Michael Schout fixed a commit policy bug in 1.51. Andreas J. Koenig contributed valuable CPAN advice and also Apache::Session::Tree and Apache::Session::Counted. Gerald Richter had the idea for a tied hash interface and provided the initial code for it. He also uses Apache::Session in his Embperl module and is the author of Apache::Session::Embperl Jochen Wiedmann contributed patches for bugs and improved performance. Steve Shreeve squashed a bug in 0.99.0 whereby a cleared hash or deleted key failed to set the modified bit. Peter Kaas sent quite a bit of feedback with ideas for interface improvements. Randy Harmon contributed the original storage-independent object interface with input from: Bavo De Ridder Jules Bean Lincoln Stein Jamie LeTaul fixed file locking on Windows. Scott McWhirter contributed verbose error messages for file locking. Corris Randall gave us the option to use any table name in the MySQL store. Oliver Maul updated the Sybase modules Innumerable users sent a patch for the reversed file age test in the file locking module. Langen Mike contributed Informix modules. =cut package Apache::Session; use strict; use vars qw($VERSION); $VERSION = '1.94'; $VERSION = eval $VERSION; #State constants # #These constants are used in a bitmask to store the #object's status. New indicates that the object #has not yet been inserted into the object store. #Modified indicates that a member value has been #changed. Deleted is set when delete() is called. #Synced indicates that an object has been materialized #from the datastore. sub NEW () {1}; sub MODIFIED () {2}; sub DELETED () {4}; sub SYNCED () {8}; #State methods # #These methods aren't used anymore for performance reasons. I'll #keep them around for reference sub is_new { $_[0]->{status} & NEW } sub is_modified { $_[0]->{status} & MODIFIED } sub is_deleted { $_[0]->{status} & DELETED } sub is_synced { $_[0]->{status} & SYNCED } sub make_new { $_[0]->{status} |= NEW } sub make_modified { $_[0]->{status} |= MODIFIED } sub make_deleted { $_[0]->{status} |= DELETED } sub make_synced { $_[0]->{status} |= SYNCED } sub make_old { $_[0]->{status} &= ($_[0]->{status} ^ NEW) } sub make_unmodified { $_[0]->{status} &= ($_[0]->{status} ^ MODIFIED) } sub make_undeleted { $_[0]->{status} &= ($_[0]->{status} ^ DELETED) } sub make_unsynced { $_[0]->{status} &= ($_[0]->{status} ^ SYNCED) } #Tie methods # #Here we are hiding our complex data persistence framework behind #a simple hash. See the perltie manpage. sub TIEHASH { my $class = shift; my $session_id = shift; my $args = shift || {}; #Set-up the data structure and make it an object #of our class my $self = { args => $args, data => { _session_id => $session_id }, serialized => undef, lock => 0, status => 0, lock_manager => undef, # These two are object refs ... object_store => undef, generate => undef, # but these three are subroutine refs serialize => undef, unserialize => undef, }; bless $self, $class; $self->populate; #If a session ID was passed in, this is an old hash. #If not, it is a fresh one. if (defined $session_id && $session_id) { #check the session ID for remote exploitation attempts #this will die() on suspicious session IDs. &{$self->{validate}}($self); if (exists $args->{Transaction} && $args->{Transaction}) { $self->acquire_write_lock; } $self->{status} &= ($self->{status} ^ NEW); $self->restore; } else { $self->{status} |= NEW; &{$self->{generate}}($self); $self->save; } return $self; } sub FETCH { my $self = shift; my $key = shift; return $self->{data}->{$key}; } sub STORE { my $self = shift; my $key = shift; my $value = shift; $self->{data}->{$key} = $value; $self->{status} |= MODIFIED; return $self->{data}->{$key}; } sub DELETE { my $self = shift; my $key = shift; $self->{status} |= MODIFIED; delete $self->{data}->{$key}; } sub CLEAR { my $self = shift; $self->{status} |= MODIFIED; $self->{data} = {}; } sub EXISTS { my $self = shift; my $key = shift; return exists $self->{data}->{$key}; } sub FIRSTKEY { my $self = shift; my $reset = keys %{$self->{data}}; return each %{$self->{data}}; } sub NEXTKEY { my $self = shift; return each %{$self->{data}}; } sub DESTROY { my $self = shift; $self->save; $self->release_all_locks; } # #Persistence methods # sub restore { my $self = shift; return if ($self->{status} & SYNCED); return if ($self->{status} & NEW); $self->acquire_read_lock; $self->{object_store}->materialize($self); &{$self->{unserialize}}($self); $self->{status} &= ($self->{status} ^ MODIFIED); $self->{status} |= SYNCED; } sub save { my $self = shift; return unless ( $self->{status} & MODIFIED || $self->{status} & NEW || $self->{status} & DELETED ); $self->acquire_write_lock; if ($self->{status} & DELETED) { $self->{object_store}->remove($self); $self->{status} |= SYNCED; $self->{status} &= ($self->{status} ^ MODIFIED); $self->{status} &= ($self->{status} ^ DELETED); return; } if ($self->{status} & MODIFIED) { &{$self->{serialize}}($self); $self->{object_store}->update($self); $self->{status} &= ($self->{status} ^ MODIFIED); $self->{status} |= SYNCED; return; } if ($self->{status} & NEW) { &{$self->{serialize}}($self); $self->{object_store}->insert($self); $self->{status} &= ($self->{status} ^ NEW); $self->{status} |= SYNCED; $self->{status} &= ($self->{status} ^ MODIFIED); return; } } sub delete { my $self = shift; return if ($self->{status} & NEW); $self->{status} |= DELETED; $self->save; } # #Locking methods # sub READ_LOCK () {1}; sub WRITE_LOCK () {2}; #These methods aren't used anymore for performance reasons. I'll keep them #around for reference. sub has_read_lock { $_[0]->{lock} & READ_LOCK } sub has_write_lock { $_[0]->{lock} & WRITE_LOCK } sub set_read_lock { $_[0]->{lock} |= READ_LOCK } sub set_write_lock { $_[0]->{lock} |= WRITE_LOCK } sub unset_read_lock { $_[0]->{lock} &= ($_[0]->{lock} ^ READ_LOCK) } sub unset_write_lock { $_[0]->{lock} &= ($_[0]->{lock} ^ WRITE_LOCK) } sub acquire_read_lock { my $self = shift; return if ($self->{lock} & READ_LOCK); $self->{lock_manager}->acquire_read_lock($self); $self->{lock} |= READ_LOCK; } sub acquire_write_lock { my $self = shift; return if ($self->{lock} & WRITE_LOCK); $self->{lock_manager}->acquire_write_lock($self); $self->{lock} |= WRITE_LOCK; } sub release_read_lock { my $self = shift; return unless ($self->{lock} & READ_LOCK); $self->{lock_manager}->release_read_lock($self); $self->{lock} &= ($self->{lock} ^ READ_LOCK); } sub release_write_lock { my $self = shift; return unless ($self->{lock} & WRITE_LOCK); $self->{lock_manager}->release_write_lock($self); $self->{lock} &= ($self->{lock} ^ WRITE_LOCK); } sub release_all_locks { my $self = shift; return unless ($self->{lock} & READ_LOCK || $self->{lock} & WRITE_LOCK); $self->{lock_manager}->release_all_locks($self); $self->{lock} &= ($self->{lock} ^ READ_LOCK); $self->{lock} &= ($self->{lock} ^ WRITE_LOCK); } 1; Apache-Session-1.94/lib/Apache/Session000755000000000000 013731226572 20162 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache/Session/DB_File.pm000444000000000000 375411437720621 22105 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::DB_File # A wrapper class # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::DB_File; use strict; use vars qw(@ISA $VERSION); $VERSION = '1.01'; @ISA = qw(Apache::Session); use Apache::Session; use Apache::Session::Lock::File; use Apache::Session::Store::DB_File; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Storable; sub populate { my $self = shift; $self->{object_store} = Apache::Session::Store::DB_File->new($self); $self->{lock_manager} = Apache::Session::Lock::File->new($self); $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Storable::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Storable::unserialize; return $self; } 1; =pod =head1 NAME Apache::Session::DB_File - An implementation of Apache::Session =head1 SYNOPSIS use Apache::Session::DB_File; tie %hash, 'Apache::Session::DB_File', $id, { FileName => 'sessions.db', LockDirectory => '/var/lock/sessions', }; =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the DB_File backing store and the File locking scheme. You must specify the filename of the database file and the directory for locking in arguments to the constructor. See the example, and the documentation for Apache::Session::Store::DB_File and Apache::Session::Lock::File. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L, L, L Apache-Session-1.94/lib/Apache/Session/File.pm000444000000000000 421211437720645 21534 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::File # Apache persistent user sessions in the filesystem # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::File; use strict; use vars qw(@ISA $VERSION); $VERSION = '1.54'; @ISA = qw(Apache::Session); use Apache::Session; use Apache::Session::Lock::File; use Apache::Session::Store::File; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Storable; sub populate { my $self = shift; $self->{object_store} = Apache::Session::Store::File->new($self); $self->{lock_manager} = Apache::Session::Lock::File->new($self); $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Storable::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Storable::unserialize; return $self; } sub DESTROY { my $self = shift; $self->save; $self->{object_store}->close; $self->release_all_locks; } 1; =pod =head1 NAME Apache::Session::File - An implementation of Apache::Session =head1 SYNOPSIS use Apache::Session::File; tie %hash, 'Apache::Session::File', $id, { Directory => '/tmp/sessions', LockDirectory => '/var/lock/sessions', }; =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the File backing store and the File locking scheme. You must specify the directory for the object store and the directory for locking in arguments to the constructor. See the example, and the documentation for Apache::Session::Store::File and Apache::Session::Lock::File. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L, L, L Apache-Session-1.94/lib/Apache/Session/Flex.pm000444000000000000 736211254001142 21541 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Flex # Apache persistent user sessions stored however you want # Copyright(c) 2000, 2001 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Flex; use strict; use vars qw(@ISA $VERSION); $VERSION = '1.01'; @ISA = qw(Apache::Session); use Apache::Session; sub populate { my $self = shift; my $store = "Apache::Session::Store::$self->{args}->{Store}"; my $lock = "Apache::Session::Lock::$self->{args}->{Lock}"; my $gen = "Apache::Session::Generate::$self->{args}->{Generate}"; my $ser = "Apache::Session::Serialize::$self->{args}->{Serialize}"; for my $class ($store, $lock) { unless ($class->can('new')) { eval "require $class" || die $@; } } unless ($gen->can('validate')) { eval "require $gen" || die $@; } unless ($ser->can('serialize')) { eval "require $ser" || die $@; } $self->{object_store} = new $store $self; $self->{lock_manager} = new $lock $self; { no strict 'refs'; $self->{generate} = \&{$gen . '::generate'}; $self->{validate} = \&{$gen . '::validate'}; $self->{serialize} = \&{$ser . '::serialize'}; $self->{unserialize} = \&{$ser . '::unserialize'}; } return $self; } 1; =pod =head1 NAME Apache::Session::Flex - Specify everything at runtime =head1 SYNOPSIS use Apache::Session::Flex; tie %hash, 'Apache::Session::Flex', $id, { Store => 'DB_File', Lock => 'Null', Generate => 'MD5', Serialize => 'Storable' }; # or tie %hash, 'Apache::Session::Flex', $id, { Store => 'Postgres', Lock => 'Null', Generate => 'MD5', Serialize => 'Base64' }; # you decide! =head1 DESCRIPTION This module is an implementation of Apache::Session. Unlike other implementations, it allows you to specify the backing store, locking scheme, ID generator, and data serializer at runtime. You do this by passing arguments in the usual Apache::Session style (see SYNOPSIS). You may use any of the modules included in this distribution, or a module of your own making. If you wish to use a module of your own making, you should make sure that it is available under the Apache::Session package namespace. =head1 USAGE You pass the modules you want to use as arguments to the constructor. The Apache::Session::Whatever part is appended for you: you should not supply it. For example, if you wanted to use MySQL as the backing store, you should give the argument C 'MySQL'>, and not C 'Apache::Session::Store::MySQL'>. There are four modules that you need to specify. Store is the backing store to use. Lock is the locking scheme. Generate is the ID generation module. Serialize is the data serialization module. There are many modules included in this distribution. For each role, they are: Store: MySQL Postgres DB_File File Lock: Null MySQL Semaphore Generate: MD5 Serialize: Storable Base64 UUEncode In addition to the arguments needed by this module, you must provide whatever arguments are expected by the backing store and lock manager that you are using. Please see the documentation for those modules. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L, L, L Apache-Session-1.94/lib/Apache/Session/Informix.pm000444000000000000 535612512453530 22451 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Informix # Apache persistent user sessions in a Informix database # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Informix; use strict; use vars qw(@ISA $VERSION); $VERSION = '1.01'; @ISA = qw(Apache::Session); use Apache::Session; use Apache::Session::Lock::Null; use Apache::Session::Store::Informix; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Base64; sub populate { my $self = shift; $self->{object_store} = Apache::Session::Store::Informix->new($self); $self->{lock_manager} = Apache::Session::Lock::Null->new($self); $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Base64::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Base64::unserialize; return $self; } 1; =pod =head1 NAME Apache::Session::Informix - An implementation of Apache::Session =head1 SYNOPSIS use Apache::Session::Informix; #if you want Apache::Session to open new DB handles: tie %hash, 'Apache::Session::Informix', $id, { DataSource => 'dbi:Informix:sessions', UserName => $db_user, Password => $db_pass, Commit => 1 }; #or, if your handles are already opened: tie %hash, 'Apache::Session::Informix', $id, { Handle => $dbh, Commit => 1 }; =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the Informix backing store and no locking. See the example, and the documentation for Apache::Session::Store::Informix for more details. =head1 USAGE The special Apache::Session argument for this module is Commit. You MUST provide the Commit argument, which instructs this module to either commit the transaction when it is finished, or to simply do nothing. This feature is provided so that this module will not have adverse interactions with your local transaction policy, nor your local database handle caching policy. The argument is mandatory in order to make you think about this problem. This module also respects the LongReadLen argument, which specifies the maximum size of the session object. If not specified, the default maximum is 8 KB. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L, L, L Apache-Session-1.94/lib/Apache/Session/MySQL.pm000444000000000000 437011254001142 21604 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::MySQL # Apache persistent user sessions in a MySQL database # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::MySQL; use strict; use vars qw(@ISA $VERSION); $VERSION = '1.01'; @ISA = qw(Apache::Session); use Apache::Session; use Apache::Session::Lock::MySQL; use Apache::Session::Store::MySQL; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Storable; sub populate { my $self = shift; $self->{object_store} = new Apache::Session::Store::MySQL $self; $self->{lock_manager} = new Apache::Session::Lock::MySQL $self; $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Storable::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Storable::unserialize; return $self; } 1; =pod =head1 NAME Apache::Session::MySQL - An implementation of Apache::Session =head1 SYNOPSIS use Apache::Session::MySQL; #if you want Apache::Session to open new DB handles: tie %hash, 'Apache::Session::MySQL', $id, { DataSource => 'dbi:mysql:sessions', UserName => $db_user, Password => $db_pass, LockDataSource => 'dbi:mysql:sessions', LockUserName => $db_user, LockPassword => $db_pass }; #or, if your handles are already opened: tie %hash, 'Apache::Session::MySQL', $id, { Handle => $dbh, LockHandle => $dbh }; =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the MySQL backing store and the MySQL locking scheme. See the example, and the documentation for Apache::Session::Store::MySQL and Apache::Session::Lock::MySQL for more details. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L, L, L Apache-Session-1.94/lib/Apache/Session/Oracle.pm000444000000000000 532211254001142 22042 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Oracle # Apache persistent user sessions in a Oracle database # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Oracle; use strict; use vars qw(@ISA $VERSION); $VERSION = '1.01'; @ISA = qw(Apache::Session); use Apache::Session; use Apache::Session::Lock::Null; use Apache::Session::Store::Oracle; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Base64; sub populate { my $self = shift; $self->{object_store} = new Apache::Session::Store::Oracle $self; $self->{lock_manager} = new Apache::Session::Lock::Null $self; $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Base64::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Base64::unserialize; return $self; } 1; =pod =head1 NAME Apache::Session::Oracle - An implementation of Apache::Session =head1 SYNOPSIS use Apache::Session::Oracle; #if you want Apache::Session to open new DB handles: tie %hash, 'Apache::Session::Oracle', $id, { DataSource => 'dbi:Oracle:sessions', UserName => $db_user, Password => $db_pass, Commit => 1 }; #or, if your handles are already opened: tie %hash, 'Apache::Session::Oracle', $id, { Handle => $dbh, Commit => 1 }; =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the Oracle backing store and no locking. See the example, and the documentation for Apache::Session::Store::Oracle for more details. =head1 USAGE The special Apache::Session argument for this module is Commit. You MUST provide the Commit argument, which instructs this module to either commit the transaction when it is finished, or to simply do nothing. This feature is provided so that this module will not have adverse interactions with your local transaction policy, nor your local database handle caching policy. The argument is mandatory in order to make you think about this problem. This module also respects the LongReadLen argument, which specifies the maximum size of the session object. If not specified, the default maximum is 8 KB. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L, L, L Apache-Session-1.94/lib/Apache/Session/Postgres.pm000444000000000000 513111254001142 22441 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Postgres # Apache persistent user sessions in a Postgres database # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Postgres; use strict; use vars qw(@ISA $VERSION); $VERSION = '1.01'; @ISA = qw(Apache::Session); use Apache::Session; use Apache::Session::Lock::Null; use Apache::Session::Store::Postgres; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Base64; sub populate { my $self = shift; $self->{object_store} = new Apache::Session::Store::Postgres $self; $self->{lock_manager} = new Apache::Session::Lock::Null $self; $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Base64::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Base64::unserialize; return $self; } 1; =pod =head1 NAME Apache::Session::Postgres - An implementation of Apache::Session =head1 SYNOPSIS use Apache::Session::Postgres; #if you want Apache::Session to open new DB handles: tie %hash, 'Apache::Session::Postgres', $id, { DataSource => 'dbi:Pg:dbname=sessions', UserName => $db_user, Password => $db_pass, Commit => 1 }; #or, if your handles are already opened: tie %hash, 'Apache::Session::Postgres', $id, { Handle => $dbh, Commit => 1 }; =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the Postgres backing store and no locking. See the example, and the documentation for Apache::Session::Store::Postgres for more details. =head1 USAGE The special Apache::Session argument for this module is Commit. You MUST provide the Commit argument, which instructs this module to either commit the transaction when it is finished, or to simply do nothing. This feature is provided so that this module will not have adverse interactions with your local transaction policy, nor your local database handle caching policy. The argument is mandatory in order to make you think about this problem. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L, L, L Apache-Session-1.94/lib/Apache/Session/Sybase.pm000444000000000000 460311254001142 22064 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Sybase # Apache persistent user sessions in a Sybase database # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Modified from Apache::Session::MySQL by Chris Winters (chris@cwinters.com) # Distribute under the Perl License # ############################################################################ package Apache::Session::Sybase; use strict; use vars qw( @ISA $VERSION ); use Apache::Session; use Apache::Session::Lock::Null; use Apache::Session::Store::Sybase; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Sybase; $VERSION = '1.00'; @ISA = qw( Apache::Session ); sub populate { my $self = shift; $self->{object_store} = new Apache::Session::Store::Sybase $self; $self->{lock_manager} = new Apache::Session::Lock::Null $self; $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Sybase::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Sybase::unserialize; return $self; } 1; =pod =head1 NAME Apache::Session::Sybase - An implementation of Apache::Session =head1 SYNOPSIS use Apache::Session::Sybase; # if you want Apache::Session to open new DB handles: tie %hash, 'Apache::Session::Sybase', $id, { DataSource => 'dbi:Sybase:database=sessions;server=SYBASE', UserName => $db_user, Password => $db_pass, Commit => 1, }; # or, if your handle is already opened: tie %hash, 'Apache::Session::Sybase', $id, { Handle => $dbh, Commit => 0, }; =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the Sybase backing store and the Null locking scheme. See the example, and the documentation for Apache::Session::Store::Sybase (also for the parameters that get passed to the backing store along with the schema necessary to save the sessions) and Apache::Session::Lock::Null for more details. =head1 AUTHOR This module was based on L which was written by Jeffrey William Baker ; it was modified by Chris Winters . =head1 SEE ALSO L =cut Apache-Session-1.94/lib/Apache/Session/Generate000755000000000000 013731226572 21714 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache/Session/Generate/MD5.pm000444000000000000 514211254001142 22754 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Generate::MD5; # Generates session identifier tokens using MD5 # Copyright(c) 2000, 2001 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Generate::MD5; use strict; use vars qw($VERSION); use Digest::MD5; $VERSION = '2.12'; sub generate { my $session = shift; my $length = 32; if (exists $session->{args}->{IDLength}) { $length = $session->{args}->{IDLength}; } $session->{data}->{_session_id} = substr(Digest::MD5::md5_hex(Digest::MD5::md5_hex(time(). {}. rand(). $$)), 0, $length); } sub validate { #This routine checks to ensure that the session ID is in the form #we expect. This must be called before we start diddling around #in the database or the disk. my $session = shift; if ($session->{data}->{_session_id} =~ /^([a-fA-F0-9]+)$/) { $session->{data}->{_session_id} = $1; } else { die "Invalid session ID: ".$session->{data}->{_session_id}; } } 1; =pod =head1 NAME Apache::Session::Generate::MD5 - Use MD5 to create random object IDs =head1 SYNOPSIS use Apache::Session::Generate::MD5; $id = Apache::Session::Generate::MD5::generate(); =head1 DESCRIPTION This module fulfills the ID generation interface of Apache::Session. The IDs are generated using a two-round MD5 of a random number, the time since the epoch, the process ID, and the address of an anonymous hash. The resultant ID number is highly entropic on Linux and other platforms that have good random number generators. You are encouraged to investigate the quality of your system's random number generator if you are using the generated ID numbers in a secure environment. This module can also examine session IDs to ensure that they are, indeed, session ID numbers and not evil attacks. The reader is encouraged to consider the effect of bogus session ID numbers in a system which uses these ID numbers to access disks and databases. This modules takes one argument in the usual Apache::Session style. The argument is IDLength, and the value, between 0 and 32, tells this module where to truncate the session ID. Without this argument, the session ID will be 32 hexadecimal characters long, equivalent to a 128-bit key. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/Generate/ModUniqueId.pm000444000000000000 254411254001142 24555 0ustar00unknownunknown000000000000package Apache::Session::Generate::ModUniqueId; use strict; use vars qw($VERSION); $VERSION = '0.02'; sub generate { my $session = shift; unless (exists $ENV{UNIQUE_ID}) { require Carp; Carp::croak('Can\'t get UNIQUE_ID env variable. Make sure mod_unique_id is enabled.'); } $session->{data}->{_session_id} = $ENV{UNIQUE_ID}; } sub validate { my $session = shift; $session->{data}->{_session_id} =~ /^[A-Za-z0-9@\-]+$/ or die "invalid session id: $session->{data}->{_session_id}."; } 1; __END__ =head1 NAME Apache::Session::Generate::ModUniqueId - mod_unique_id for session ID generation =head1 SYNOPSIS use Apache::Session::Flex; tie %session, 'Apache::Session::Flex', $id, { Store => 'MySQL', Lock => 'Null', Generate => 'ModUniqueId', Serialize => 'Storable', }; =head1 DESCRIPTION Apache::Session::Generate::ModUniqueId enables you to use unique id generated by mod_unique_id as session id for Apache::Session framework. Using mod_unique_id would ensure higher level uniquess of id. =head1 AUTHOR Tatsuhiko Miyagawa This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L, mod_unique_id =cut Apache-Session-1.94/lib/Apache/Session/Generate/ModUsertrack.pm000444000000000000 511011254001142 24765 0ustar00unknownunknown000000000000package Apache::Session::Generate::ModUsertrack; use strict; use vars qw($VERSION); $VERSION = '0.02'; use CGI::Cookie; use constant MOD_PERL => exists $ENV{MOD_PERL}; sub generate { my $session = shift; my $name = $session->{args}->{ModUsertrackCookieName} || 'Apache'; my %cookies = CGI::Cookie->fetch; if (!exists $cookies{$name} && MOD_PERL) { # no cookies, try to steal from notes require Apache; my $r = Apache->request; %cookies = CGI::Cookie->parse($r->notes('cookie')); } unless ($cookies{$name}) { # still bad luck require Carp; Carp::croak('no cookie found. Make sure mod_usertrack is enabled.'); } $session->{data}->{_session_id} = $cookies{$name}->value; } sub validate { my $session = shift; # remote_host (or remote_addr) + int $session->{data}->{_session_id} =~ /^[\d\w\.]+\.\d+$/ or die "invalid session id: $session->{data}->{_session_id}"; } 1; __END__ =head1 NAME Apache::Session::Generate::ModUsertrack - mod_usertrack for session ID generation =head1 SYNOPSIS use Apache::Session::Flex; tie %session, 'Apache::Session::Flex', $id, { Store => 'MySQL', Lock => 'Null', Generate => 'ModUsertrack', Serialize => 'Storable', ModUsertrackCookieName => 'usertrack', # optional }; =head1 DESCRIPTION Apache::Session::Generate::ModUsertrack enables you to use cookie tracked by mod_usertrack as session id for Apache::Session framework. This module fits well with long-term sessions, so better using RDBMS like MySQL for its storage. =head1 CONFIGURATION This module accepts one extra configuration option. =over 4 =item ModUsertrackCookieName Specifies cookie name used in mod_usertrack. C for default, so change this if you change it via C directive in mod_usertrack. =back =head1 LIMITATION WITHOUT MOD_PERL This module first tries to fetch named cookie, but will in vain B the HTTP request is the first one from specific client to the mod_usertrack enabled Apache web server. It is because if the request is for the first time, cookies are not yet baked on clients. If you run scripts under mod_perl, this module tries to steal (not yet baked) cookie from Apache request notes. See L for details. =head1 AUTHOR Tatsuhiko Miyagawa This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L, mod_usertrack =cut Apache-Session-1.94/lib/Apache/Session/Lock000755000000000000 013731226572 21052 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache/Session/Lock/File.pm000444000000000000 1570712456311421 22445 0ustar00unknownunknown000000000000############################################################################ # # Apache::Session::Lock::File # flock(2) locking for Apache::Session # Copyright(c) 1998, 1999, 2000, 2004 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Lock::File; use strict; use Fcntl qw(:flock); use Symbol; use vars qw($VERSION); $VERSION = '1.04'; $Apache::Session::Lock::File::LockDirectory = '/tmp'; sub new { my $class = shift; return bless { read => 0, write => 0, opened => 0, id => 0 }, $class; } sub acquire_read_lock { if ($^O eq 'MSWin32' or $^O eq 'cygwin') { #Windows cannot escalate lock, so all locks will be exclusive return &acquire_write_lock; } #Works for acquire_read_lock => acquire_write_lock => release_all_locks #This hack does not support release_read_lock #Changed by Alexandr Ciornii, 2006-06-21 my $self = shift; my $session = shift; return if $self->{read}; #does not support release_read_lock if (!$self->{opened}) { my $fh = Symbol::gensym(); my $LockDirectory = $session->{args}->{LockDirectory} || $Apache::Session::Lock::File::LockDirectory; open($fh, "+>".$LockDirectory."/Apache-Session-".$session->{data}->{_session_id}.".lock") || die "Could not open file (".$LockDirectory."/Apache-Session-".$session->{data}->{_session_id}.".lock) for writing: $!"; $self->{fh} = $fh; $self->{opened} = 1; } if (!$self->{write}) { #acquiring read lock, when write lock is in effect will clear write lock flock($self->{fh}, LOCK_SH) || die "Cannot lock: $!"; } $self->{read} = 1; } sub acquire_write_lock { my $self = shift; my $session = shift; return if $self->{write}; if (!$self->{opened}) { my $fh = Symbol::gensym(); my $LockDirectory = $session->{args}->{LockDirectory} || $Apache::Session::Lock::File::LockDirectory; open($fh, "+>".$LockDirectory."/Apache-Session-".$session->{data}->{_session_id}.".lock") || die "Could not open file (".$LockDirectory."/Apache-Session-".$session->{data}->{_session_id}.".lock) for writing: $!"; $self->{fh} = $fh; $self->{opened} = 1; } flock($self->{fh}, LOCK_EX) || die "Cannot lock: $!"; $self->{write} = 1; } sub release_read_lock { if ($^O eq 'MSWin32' or $^O eq 'cygwin') { die "release_read_lock is not supported on Win32 or Cygwin"; } my $self = shift; my $session = shift; die "No read lock to release in release_read_lock" unless $self->{read}; if (!$self->{write}) { flock($self->{fh}, LOCK_UN) || die "Cannot unlock: $!"; close $self->{fh} || die "Could no close file: $!"; $self->{opened} = 0; } $self->{read} = 0; } sub release_write_lock { my $self = shift; my $session = shift; die "No write lock acquired" unless $self->{write}; if ($self->{read}) { flock($self->{fh}, LOCK_SH) || die "Cannot lock: $!"; } else { flock($self->{fh}, LOCK_UN) || die "Cannot unlock: $!"; close $self->{fh} || die "Could not close file: $!"; $self->{opened} = 0; } $self->{write} = 0; } sub release_all_locks { my $self = shift; my $session = shift; if ($self->{opened}) { flock($self->{fh}, LOCK_UN) || die "Cannot unlock: $!"; close $self->{fh} || die "Could not close file: $!"; } $self->{opened} = 0; $self->{read} = 0; $self->{write} = 0; } sub DESTROY { my $self = shift; $self->release_all_locks; } sub clean { my $self = shift; my $dir = shift; my $time = shift; my $now = time(); opendir(DIR, $dir) || die "Could not open directory $dir: $!"; my @files = readdir(DIR); foreach my $file (@files) { if ($file =~ /^Apache-Session.*\.lock$/) { if ($now - (stat($dir.'/'.$file))[8] >= $time) { if ($^O eq 'MSWin32') { #Windows cannot unlink open file unlink($dir.'/'.$file) || next; } else { open(FH, "+>$dir/".$file) || next; flock(FH, LOCK_EX) || next; unlink($dir.'/'.$file) || next; flock(FH, LOCK_UN); close(FH); } } } } closedir(DIR); } 1; =pod =head1 NAME Apache::Session::Lock::File - Provides mutual exclusion using flock =head1 SYNOPSIS use Apache::Session::Lock::File; my $locker = Apache::Session::Lock::File->new; $locker->acquire_read_lock($ref); $locker->acquire_write_lock($ref); $locker->release_read_lock($ref); $locker->release_write_lock($ref); $locker->release_all_locks($ref); $locker->clean($dir, $age); =head1 DESCRIPTION Apache::Session::Lock::File fulfills the locking interface of Apache::Session. Mutual exclusion is achieved through the use of temporary files and the C function. =head1 CONFIGURATION The module must know where to create its temporary files. You must pass an argument in the usual Apache::Session style. The name of the argument is LockDirectory and its value is the path where you want the lockfiles created. Example: tie %s, 'Apache::Session::Blah', $id, {LockDirectory => '/var/lock/sessions'} If you do not supply this argument, temporary files will be created in /tmp. =head1 NOTES =head2 clean This module does not unlink temporary files, because it interferes with proper locking. This can cause problems on certain systems (Linux) whose file systems (ext2) do not perform well with lots of files in one directory. To prevent this you should use a script to clean out old files from your lock directory. The meaning of old is left as a policy decision for the implementor, but a method is provided for implementing that policy. You can use the C method of this module to remove files unmodified in the last $age seconds. Example: my $l = Apache::Session::Lock::File->new; $l->clean('/var/lock/sessions', 3600) #remove files older than 1 hour =head2 acquire_read_lock Will do nothing if write lock is in effect, only set readlock flag to true. =head2 release_read_lock Will do nothing if write lock is in effect, only set readlock flag to false. =head2 Win32 and Cygwin Windows cannot escalate lock, so all locks will be exclusive. release_read_lock not supported - it is not used by Apache::Session. When deleting files, they are not locked (Win32 only). =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/Lock/MySQL.pm000444000000000000 766013731225675 22526 0ustar00unknownunknown000000000000############################################################################ # # Apache::Session::Lock::MySQL # MySQL locking for Apache::Session # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Lock::MySQL; use strict; use DBI; use vars qw($VERSION); $VERSION = '1.01'; sub new { my $class = shift; return bless {lock => 0, lockid => undef, dbh => undef, mine => 0}, $class; } sub acquire_read_lock { my $self = shift; my $session = shift; return if $self->{lock}; if (!defined $self->{dbh}) { if (defined $session->{args}->{LockHandle}) { $self->{dbh} = $session->{args}->{LockHandle}; } else { if (!$session->{args}->{LockDataSource}) { die "LockDataSource not provided for Apache::Session::Lock::MySQL"; } $self->{dbh} = DBI->connect( $session->{args}->{LockDataSource}, $session->{args}->{LockUserName}, $session->{args}->{LockPassword}, { RaiseError => 1, AutoCommit => 1 } ); $self->{mine} = 1; } } local $self->{dbh}->{RaiseError} = 1; $self->{lockid} = "Apache-Session-$session->{data}->{_session_id}"; #MySQL requires a timeout on the lock operation. There is no option #to simply wait forever. So we'll wait for a hour. my $sth = $self->{dbh}->prepare_cached(q{SELECT GET_LOCK(?, 3600)}, {}, 1); $sth->execute($self->{lockid}); $sth->finish(); $self->{lock} = 1; } sub acquire_write_lock { $_[0]->acquire_read_lock($_[1]); } sub release_read_lock { my $self = shift; if ($self->{lock}) { local $self->{dbh}->{RaiseError} = 1; my $sth = $self->{dbh}->prepare_cached(q{SELECT RELEASE_LOCK(?)}, {}, 1); $sth->execute($self->{lockid}); $sth->finish(); $self->{lock} = 0; } } sub release_write_lock { $_[0]->release_read_lock; } sub release_all_locks { $_[0]->release_read_lock; } sub DESTROY { my $self = shift; $self->release_all_locks; if ($self->{mine}) { $self->{dbh}->disconnect; } } 1; =pod =head1 NAME Apache::Session::Lock::MySQL - Provides mutual exclusion using MySQL =head1 SYNOPSIS use Apache::Session::Lock::MySQL; my $locker = Apache::Session::Lock::MySQL->new(); $locker->acquire_read_lock($ref); $locker->acquire_write_lock($ref); $locker->release_read_lock($ref); $locker->release_write_lock($ref); $locker->release_all_locks($ref); =head1 DESCRIPTION Apache::Session::Lock::MySQL fulfills the locking interface of Apache::Session. Mutual exclusion is achieved through the use of MySQL's GET_LOCK and RELEASE_LOCK functions. MySQL does not support the notion of read and write locks, so this module only supports exclusive locks. When you request a shared read lock, it is instead promoted to an exclusive write lock. =head1 CONFIGURATION The module must know how to connect to your MySQL database to acquire locks. You must provide a datasource name, a user name, and a password. These options are passed in the usual Apache::Session style, and are very similar to the options for Apache::Session::Store::MySQL. Example: tie %hash, 'Apache::Session::MySQL', $id, { LockDataSource => 'dbi:mysql:database', LockUserName => 'database_user', LockPassword => 'K00l' }; Instead, you may pass in an already opened DBI handle to your database. tie %hash, 'Apache::Session::MySQL', $id, { LockHandle => $dbh }; =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/Lock/Null.pm000444000000000000 310712456311472 22455 0ustar00unknownunknown000000000000############################################################################ # # Apache::Session::Lock::Null # Pretends to provide locking for Apache::Session # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Lock::Null; use strict; use vars qw($VERSION); $VERSION = '1.01'; #This package is fake. It fulfills the API that Apache::Session #outlines but doesn't actually do anything, least of all provide #serialized access to your data store. sub new { my $class = shift; return bless {}, $class; } sub acquire_read_lock {1} sub acquire_write_lock {1} sub release_read_lock {1} sub release_write_lock {1} sub release_all_locks {1} 1; =pod =head1 NAME Apache::Session::Lock::Null - Does not actually provides mutual exclusion =head1 SYNOPSIS use Apache::Session::Lock::Null; my $locker = Apache::Session::Lock::Null->new; $locker->acquire_read_lock($ref); $locker->acquire_write_lock($ref); $locker->release_read_lock($ref); $locker->release_write_lock($ref); $locker->release_all_locks($ref); =head1 DESCRIPTION Apache::Session::Lock::Null fulfills the locking interface of Apache::Session, without actually doing any work. This is the module to use if you want maximum performance and don't actually need locking. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/Lock/Semaphore.pm000444000000000000 2045212456311506 23506 0ustar00unknownunknown000000000000############################################################################ # # Apache::Session::Lock::Semaphore # IPC Semaphore locking for Apache::Session # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Lock::Semaphore; use strict; use Config; use IPC::SysV qw(IPC_PRIVATE IPC_CREAT S_IRWXU SEM_UNDO); use IPC::Semaphore; use Carp qw/croak confess/; use vars qw($VERSION); $VERSION = '1.04'; BEGIN { if ($Config{'osname'} eq 'linux') { #More semaphores on Linux means less lock contention $Apache::Session::Lock::Semaphore::nsems = 32; } elsif ($Config{'osname'}=~/bsd/i) { $Apache::Session::Lock::Semaphore::nsems = 8; #copied from IPC::Semaphore/sem.t minus 1 } else { $Apache::Session::Lock::Semaphore::nsems = 16; } $Apache::Session::Lock::Semaphore::sem_key = 31818; } sub new { return unless $Config{d_semget}; return if $^O eq 'cygwin' && (!exists $ENV{'CYGWIN'} || $ENV{'CYGWIN'} !~ /server/i); #Modified by Alexandr Ciornii, 2007-03-12 my $class = shift; my $session = shift; my $nsems = $session->{args}->{NSems} || $Apache::Session::Lock::Semaphore::nsems; # die "You shouldn't set session argument SemaphoreKey to undef" # if exists($session->{args}->{SemaphoreKey}) && # !defined ($session->{args}->{SemaphoreKey}); my $sem_key = #exists ($session->{args}->{SemaphoreKey})? $session->{args}->{SemaphoreKey} || $Apache::Session::Lock::Semaphore::sem_key; return bless {read => 0, write => 0, sem => undef, nsems => $nsems, read_sem => undef, sem_key => $sem_key}, $class; } sub acquire_read_lock { my $self = shift; my $session = shift; return if $self->{read}; return if $self->{write}; if (!$self->{sem}) { $self->{sem} = IPC::Semaphore->new( defined($self->{sem_key})?$self->{sem_key}:IPC_PRIVATE, $self->{nsems}, IPC_CREAT | S_IRWXU) || confess("Cannot create semaphore with key $self->{sem_key}; NSEMS: $self->{nsems}: $!"); } if (!defined $self->{read_sem}) { #The number of semaphores (2^2-2^4, typically) is much less than #the potential number of session ids (2^128, typically), we need #to hash the session id to choose a semaphore. This hash routine #was stolen from Kernighan's The Practice of Programming. my $read_sem = 0; foreach my $el (split(//, $session->{data}->{_session_id})) { $read_sem = 31 * $read_sem + ord($el); } $read_sem %= ($self->{nsems}/2); $self->{read_sem} = $read_sem; } #The semaphore block is divided into two halves. The lower half #holds the read semaphores, and the upper half holds the write #semaphores. Thus we can do atomic upgrade of a read lock to a #write lock. $self->{sem}->op($self->{read_sem} + $self->{nsems}/2, 0, SEM_UNDO, $self->{read_sem}, 1, SEM_UNDO); $self->{read} = 1; } sub acquire_write_lock { my $self = shift; my $session = shift; return if($self->{write}); if (!$self->{sem}) { $self->{sem} = IPC::Semaphore->new( defined($self->{sem_key})?$self->{sem_key}:IPC_PRIVATE, $self->{nsems}, IPC_CREAT | S_IRWXU) || confess "Cannot create semaphore with key $self->{sem_key}; NSEMS: $self->{nsems}: $!"; } if (!defined $self->{read_sem}) { #The number of semaphores (2^2-2^4, typically) is much less than #the potential number of session ids (2^128, typically), we need #to hash the session id to choose a semaphore. This hash routine #was stolen from Kernighan's The Practice of Programming. my $read_sem = 0; foreach my $el (split(//, $session->{data}->{_session_id})) { $read_sem = 31 * $read_sem + ord($el); } $read_sem %= ($self->{nsems}/2); $self->{read_sem} = $read_sem; } $self->release_read_lock($session) if $self->{read}; $self->{sem}->op($self->{read_sem}, 0, SEM_UNDO, $self->{read_sem} + $self->{nsems}/2, 0, SEM_UNDO, $self->{read_sem} + $self->{nsems}/2, 1, SEM_UNDO); $self->{write} = 1; } sub release_read_lock { my $self = shift; my $session = shift; return unless $self->{read}; $self->{sem}->op($self->{read_sem}, -1, SEM_UNDO); $self->{read} = 0; } sub release_write_lock { my $self = shift; my $session = shift; return unless $self->{write}; $self->{sem}->op($self->{read_sem} + $self->{nsems}/2, -1, SEM_UNDO); $self->{write} = 0; } sub release_all_locks { my $self = shift; my $session = shift; if($self->{read}) { $self->release_read_lock($session); } if($self->{write}) { $self->release_write_lock($session); } $self->{read} = 0; $self->{write} = 0; } sub hash { my $key = shift; my $nsems = shift; my $hash = 0; } sub remove { my $self = shift; if ($self->{sem}) { $self->{sem}->remove(); } } 1; =pod =head1 NAME Apache::Session::Lock::Semaphore - Provides mutual exclusion through semaphores =head1 SYNOPSIS use Apache::Session::Lock::Semaphore; my $locker = Apache::Session::Lock::Semaphore->new; die "no semaphores" unless $locker; $locker->acquire_read_lock($ref); $locker->acquire_write_lock($ref); $locker->release_read_lock($ref); $locker->release_write_lock($ref); $locker->release_all_locks($ref); =head1 DESCRIPTION Apache::Session::Lock::semaphore fulfills the locking interface of Apache::Session. Mutual exclusion is achieved through system semaphores and the IPC::Semaphore module. =head1 CONFIGURATION The module must know how many semaphores to use, and what semaphore key to use. The number of semaphores has an impact on performance. More semaphores means less lock contention. You should use the maximum number of semaphores that your platform will allow. On stock NetBSD, OpenBSD, and Solaris systems, this is probably 16. On Linux 2.2, this is 32. This module tries to guess the number based on your operating system, but it is safer to configure it yourself. To set the number of semaphores, you need to pass an argument in the usual Apache::Session style. The name of the argument is NSems, and the value is an integer power of 2. For example: tie %s, 'Apache::Session::Blah', $id, {NSems => 16}; You may also need to configure the semaphore key that this package uses. By default, it uses key 31818. You can change this using the argument SemaphoreKey: tie %s, 'Apache::Session::Blah', $id, {NSems => 16, SemaphoreKey => 42}; =head1 PROBLEMS There are a few problems that people frequently encounter when using this package. If you get an invalid argument message, that usually means that the system is unhappy with the number of semaphores that you requested. Try decreasing the number of semaphores. The semaphore blocks that this package creates are persistent until the system is rebooted, so if you request 8 semaphores one time and 16 semaphores the next, it won't work. Use the system commands ipcs and ipcrm to inspect and remove unwanted semphore blocks. =head2 Cygwin IPC on Cygwin requires running cygserver. Without it, program will exit with "Bad System call" message. It cannot be intercepted with eval. Read /usr/share/doc/Cygwin/cygserver.README for more information. =head2 Darwin/MacOS X Darwin and MacOS X may not have semaphores, see L =head2 *BSD Error "No space left on device" means that maximum number of semaphores is reached. See L for more information. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/Lock/Sybase.pm000444000000000000 731612456313254 22777 0ustar00unknownunknown000000000000############################################################################ # # Apache::Session::Lock::Sybase # Sybase locking for Apache::Session # Copyright(c) 2003 Oliver Maul (oli@42.nu) # Distribute under the Perl License # ############################################################################ package Apache::Session::Lock::Sybase; use strict; use DBI; use vars qw($VERSION); $VERSION = '1.00'; sub new { my $class = shift; return bless {lock => 0, lockid => undef, dbh => undef, mine => 0}, $class; } sub acquire_read_lock { my $self = shift; my $session = shift; return if $self->{lock}; if (!defined $self->{dbh}) { if (defined $session->{args}->{LockHandle}) { $self->{dbh} = $session->{args}->{LockHandle}; } else { $self->{dbh} = DBI->connect( $session->{args}->{LockDataSource}, $session->{args}->{LockUserName}, $session->{args}->{LockPassword}, { RaiseError => 1, AutoCommit => 1 } ); $self->{mine} = 1; } } local $self->{dbh}->{RaiseError} = 1; $self->{lockid} = "Apache-Session-$session->{data}->{_session_id}"; my $sth = $self->{dbh}->prepare(q{sp_getapplock @Resource = '}.$self->{lockid}.q{',@LockMode='Exclusive',@LockOwner='Session',@LockTimeout = '3600000'}); $sth->execute() || die $DBI::errstr; $self->{lock} = 1; } sub acquire_write_lock { $_[0]->acquire_read_lock($_[1]); } sub release_read_lock { my $self = shift; if ($self->{lock}) { local $self->{dbh}->{RaiseError} = 1; my $sth = $self->{dbh}->prepare(q{sp_releaseapplock @Resource='}.$self->{lockid}.q{',@Lookowner='Session'}); $sth->execute() || die $DBI::errstr; $self->{lock} = 0; } } sub release_write_lock { $_[0]->release_read_lock; } sub release_all_locks { $_[0]->release_read_lock; } sub DESTROY { my $self = shift; $self->release_all_locks; if ($self->{mine}) { $self->{dbh}->disconnect; } } 1; =pod =head1 NAME Apache::Session::Lock::Sybase - Provides mutual exclusion using Sybase =head1 SYNOPSIS use Apache::Session::Lock::Sybase; my $locker = Apache::Session::Lock::Sybase->new; $locker->acquire_read_lock($ref); $locker->acquire_write_lock($ref); $locker->release_read_lock($ref); $locker->release_write_lock($ref); $locker->release_all_locks($ref); =head1 DESCRIPTION Apache::Session::Lock::Sybase fulfills the locking interface of Apache::Session. Mutual exclusion is achieved through the use of Sybase's sp_getapplock and sp_releaseapplock functions. Sybase does not support the notion of read and write locks, so this module only supports exclusive locks. When you request a shared read lock, it is instead promoted to an exclusive write lock. =head1 CONFIGURATION The module must know how to connect to your MySQL database to acquire locks. You must provide a datasource name, a user name, and a password. These options are passed in the usual Apache::Session style, and are very similar to the options for Apache::Session::Store::Sybase. Example: tie %hash, 'Apache::Session::Sybase', $id, { LockDataSource => 'dbi:sybase:database', LockUserName => 'database_user', LockPassword => 'K00l' }; Instead, you may pass in an already opened DBI handle to your database. tie %hash, 'Apache::Session::Sybase', $id, { LockHandle => $dbh }; =head1 AUTHOR This module was written by Oliver Maul . =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/MySQL000755000000000000 013731226572 21127 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache/Session/MySQL/NoLock.pm000444000000000000 502413064027744 23007 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::MySQL::NoLock # Apache persistent user sessions in a MySQL database without locking # Copyright(c) 2010 Tomas (t0m) Doran (bobtfish@bobtfish.net) # Distribute under the Perl License # ############################################################################ package Apache::Session::MySQL::NoLock; use strict; use vars qw(@ISA $VERSION); $VERSION = '0.01'; @ISA = qw(Apache::Session); use Apache::Session; use Apache::Session::Lock::Null; use Apache::Session::Store::MySQL; use Apache::Session::Generate::MD5; use Apache::Session::Serialize::Storable; sub populate { my $self = shift; $self->{object_store} = Apache::Session::Store::MySQL->new($self); $self->{lock_manager} = Apache::Session::Lock::Null->new($self); $self->{generate} = \&Apache::Session::Generate::MD5::generate; $self->{validate} = \&Apache::Session::Generate::MD5::validate; $self->{serialize} = \&Apache::Session::Serialize::Storable::serialize; $self->{unserialize} = \&Apache::Session::Serialize::Storable::unserialize; return $self; } 1; =pod =head1 NAME Apache::Session::MySQL::NoLock - An implementation of Apache::Session::MySQL without locking =head1 SYNOPSIS use Apache::Session::MySQL::NoLock; #if you want Apache::Session to open new DB handles: tie %hash, 'Apache::Session::MySQL::NoLock', $id, { DataSource => 'dbi:mysql:sessions', UserName => $db_user, Password => $db_pass, }; #or, if your handles are already opened: tie %hash, 'Apache::Session::MySQL::NoLock', $id, { Handle => $dbh, }; To configure the non-locking session store in RT (what I use this module for), put the following into your C module: Set($WebSessionClass , 'Apache::Session::MySQL::NoLock'); =head1 DESCRIPTION This module is an implementation of Apache::Session. It uses the MySQL backing store and the Null locking scheme. See the example, and the documentation for Apache::Session::Store::MySQL for more details. =head1 WARNING This module explicitly B. This can cause your session data to be overwritten or stale data to be read by subsequent requests. This B. =head1 AUTHOR This module was written by Tomas Doran . =head1 SEE ALSO L, L, L =cut Apache-Session-1.94/lib/Apache/Session/Serialize000755000000000000 013731226572 22111 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache/Session/Serialize/Base64.pm000444000000000000 342111254001142 23606 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Serialize::Base64 # Serializes session objects using Storable and MIME::Base64 # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Serialize::Base64; use strict; use vars qw($VERSION); use MIME::Base64; use Storable qw(nfreeze thaw); $VERSION = '1.01'; sub serialize { my $session = shift; $session->{serialized} = encode_base64(nfreeze($session->{data})); } sub unserialize { my $session = shift; my $data = thaw(decode_base64($session->{serialized})); die "Session could not be unserialized" unless defined $data; #Storable can return undef or die for different errors $session->{data} = $data; } 1; =pod =head1 NAME Apache::Session::Serialize::Base64 - Use Storable and MIME::Base64 to zip up persistent data =head1 SYNOPSIS use Apache::Session::Serialize::Base64; $zipped = Apache::Session::Serialize::Base64::serialize($ref); $ref = Apache::Session::Serialize::Base64::unserialize($zipped); =head1 DESCRIPTION This module fulfills the serialization interface of Apache::Session. It serializes the data in the session object by use of Storable's C and C functions, and MIME::Base64's C and C. The serialized data is ASCII text, suitable for storage in backing stores that don't handle binary data gracefully, such as Postgres. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L Apache-Session-1.94/lib/Apache/Session/Serialize/Storable.pm000444000000000000 306511254001142 24341 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Serialize::Storable # Serializes session objects using Storable # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Serialize::Storable; use strict; use vars qw($VERSION); use Storable qw(nfreeze thaw); $VERSION = '1.01'; sub serialize { my $session = shift; $session->{serialized} = nfreeze $session->{data}; } sub unserialize { my $session = shift; my $data = thaw $session->{serialized}; die "Session could not be unserialized" unless defined $data; #Storable can return undef or die for different errors $session->{data} = $data; } 1; =pod =head1 NAME Apache::Session::Serialize::Storable - Use Storable to zip up persistent data =head1 SYNOPSIS use Apache::Session::Serialize::Storable; $zipped = Apache::Session::Serialize::Storable::serialize($ref); $ref = Apache::Session::Serialize::Storable::unserialize($zipped); =head1 DESCRIPTION This module fulfills the serialization interface of Apache::Session. It serializes the data in the session object by use of Storable's C and C functions. The result is a binary object ready for storage. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L Apache-Session-1.94/lib/Apache/Session/Serialize/Sybase.pm000444000000000000 460311254001142 24013 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Serialize::Sybase # Serializes session objects using Storable and packing into Sybase format # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Modified from Apache::Session::Serialize::Storable by Chris Winters (chris@cwinters.com) # Distribute under the Perl License # ############################################################################ package Apache::Session::Serialize::Sybase; use strict; use vars qw( $VERSION ); use Apache::Session::Serialize::Storable; $VERSION = '1.00'; # Modify the storable-serialized data to work with sybase sub serialize { my $session = shift; Apache::Session::Serialize::Storable::serialize( $session ); # sets $session->{serialized} $session->{serialized} = unpack('H*', $session->{serialized} ); } # Modify the data from sybase to work with storable so it can thaw properly sub unserialize { my $session = shift; $session->{serialized} = pack('H*', $session->{serialized} ); Apache::Session::Serialize::Storable::unserialize( $session ); # sets $session->{data} } 1; =pod =head1 NAME Apache::Session::Serialize::Sybase - Use Storable to zip up persistent data and unpack/pack to put into Sybase-compatible image field =head1 SYNOPSIS use Apache::Session::Serialize::Sybase; $zipped = Apache::Session::Serialize::Sybase::serialize($ref); $ref = Apache::Session::Serialize::Sybase::unserialize($zipped); =head1 DESCRIPTION This module fulfills the serialization interface of Apache::Session by taking the data from Apache::Session::Serialize::Storable and modifying it to work with Sybase IMAGE fields. Note that you do B need to quote these values before inserting into the database, and that if you are using DBI::Sybase, you cannot use the data in a placeholder. If you use Apache::Session::Sybase as your session class, this will all get taken care of. =head1 AUTHOR Apache::Session::Serialize::Storable was written by Jeffrey William Baker ; the Sybase-specific data manipulation was written by Mark Landry for use in an earlier version of Apache::Session::DBI::Sybase and placed here by Chris Winters . =head1 SEE ALSO L, L Apache-Session-1.94/lib/Apache/Session/Serialize/UUEncode.pm000444000000000000 341511254001142 24234 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Serialize::UUEncode # Serializes session objects using Storable and pack # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Serialize::UUEncode; use strict; use vars qw($VERSION); use Storable qw(nfreeze thaw); $VERSION = '1.01'; sub serialize { my $session = shift; $session->{serialized} = pack("u", nfreeze($session->{data})); } sub unserialize { my $session = shift; my $data = thaw(unpack("u", $session->{serialized})); die "Session could not be unserialized" unless defined $data; #Storable can return undef or die for different errors $session->{data} = $data; } 1; =pod =head1 NAME Apache::Session::Serialize::UUEncode - Use Storable and C to zip up persistent data =head1 SYNOPSIS use Apache::Session::Serialize::UUEncode; $zipped = Apache::Session::Serialize::UUEncode::serialize($ref); $ref = Apache::Session::Serialize::UUEncode::unserialize($zipped); =head1 DESCRIPTION This module fulfills the serialization interface of Apache::Session. It serializes the data in the session object by use of Storable's C and C functions, and Perl's C and C. The serialized data is ASCII text, suitable for storage in backing stores that don't handle binary data gracefully, such as Postgres. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L, L Apache-Session-1.94/lib/Apache/Session/Store000755000000000000 013731226572 21256 5ustar00unknownunknown000000000000Apache-Session-1.94/lib/Apache/Session/Store/DBI.pm000444000000000000 562112277672314 22356 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::DBI # A base class for the MySQL, Postgres, and other DBI stores # Copyright(c) 2000, 2004 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::DBI; use strict; use DBI; use vars qw($VERSION); $VERSION = '1.02'; $Apache::Session::Store::DBI::TableName = "sessions"; sub new { my $class = shift; return bless { table_name => $Apache::Session::Store::DBI::TableName }, $class; } sub insert { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; if (!defined $self->{insert_sth}) { $self->{insert_sth} = $self->{dbh}->prepare_cached(qq{ INSERT INTO $self->{'table_name'} (id, a_session) VALUES (?,?)}); } $self->{insert_sth}->bind_param(1, $session->{data}->{_session_id}); $self->{insert_sth}->bind_param(2, $session->{serialized}); $self->{insert_sth}->execute; $self->{insert_sth}->finish; } sub update { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; if (!defined $self->{update_sth}) { $self->{update_sth} = $self->{dbh}->prepare_cached(qq{ UPDATE $self->{'table_name'} SET a_session = ? WHERE id = ?}); } $self->{update_sth}->bind_param(1, $session->{serialized}); $self->{update_sth}->bind_param(2, $session->{data}->{_session_id}); $self->{update_sth}->execute; $self->{update_sth}->finish; } sub materialize { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; if (!defined $self->{materialize_sth}) { $self->{materialize_sth} = $self->{dbh}->prepare_cached(qq{ SELECT a_session FROM $self->{'table_name'} WHERE id = ?}); } $self->{materialize_sth}->bind_param(1, $session->{data}->{_session_id}); $self->{materialize_sth}->execute; my $results = $self->{materialize_sth}->fetchrow_arrayref; if (!(defined $results)) { die "Object does not exist in the data store"; } $self->{materialize_sth}->finish; $session->{serialized} = $results->[0]; } sub remove { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; if (!defined $self->{remove_sth}) { $self->{remove_sth} = $self->{dbh}->prepare_cached(qq{ DELETE FROM $self->{'table_name'} WHERE id = ?}); } $self->{remove_sth}->bind_param(1, $session->{data}->{_session_id}); $self->{remove_sth}->execute; $self->{remove_sth}->finish; } 1; Apache-Session-1.94/lib/Apache/Session/Store/DB_File.pm000444000000000000 655011254001142 23161 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::DB_File # Implements session object storage via Perl's DB_File module # Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::DB_File; use strict; use vars qw($VERSION); use DB_File; $VERSION = '1.01'; sub new { my $class = shift; return bless {dbm => {}}, $class; } sub insert { my $self = shift; my $session = shift; if (!tied %{$self->{dbm}}) { my $rv = tie %{$self->{dbm}}, 'DB_File', $session->{args}->{FileName}; if (!$rv) { die "Could not open dbm file $session->{args}->{FileName}: $!"; } } if (exists $self->{dbm}->{$session->{data}->{_session_id}}) { die "Object already exists in the data store"; } $self->{dbm}->{$session->{data}->{_session_id}} = $session->{serialized}; } sub update { my $self = shift; my $session = shift; if (!tied %{$self->{dbm}}) { my $rv = tie %{$self->{dbm}}, 'DB_File', $session->{args}->{FileName}; if (!$rv) { die "Could not open dbm file $session->{args}->{FileName}: $!"; } } $self->{dbm}->{$session->{data}->{_session_id}} = $session->{serialized}; } sub materialize { my $self = shift; my $session = shift; if (!tied %{$self->{dbm}}) { my $rv = tie %{$self->{dbm}}, 'DB_File', $session->{args}->{FileName}; if (!$rv) { die "Could not open dbm file $session->{args}->{FileName}: $!"; } } $session->{serialized} = $self->{dbm}->{$session->{data}->{_session_id}}; if (!defined $session->{serialized}) { die "Object does not exist in data store"; } } sub remove { my $self = shift; my $session = shift; if (!tied %{$self->{dbm}}) { my $rv = tie %{$self->{dbm}}, 'DB_File', $session->{args}->{FileName}; if (!$rv) { die "Could not open dbm file $session->{args}->{FileName}: $!"; } } delete $self->{dbm}->{$session->{data}->{_session_id}}; } 1; =pod =head1 NAME Apache::Session::Store::DB_File - Use DB_File to store persistent objects =head1 SYNOPSIS use Apache::Session::Store::DB_File; my $store = new Apache::Session::Store::DB_File; $store->insert($ref); $store->update($ref); $store->materialize($ref); $store->remove($ref); =head1 DESCRIPTION This module fulfills the storage interface of Apache::Session. The serialized objects are stored in a Berkeley DB file using the DB_File Perl module. If DB_File works on your platform, this module should also work. =head1 OPTIONS This module requires one argument in the usual Apache::Session style. The name of the option is FileName, and the value is the full path of the database file to be used as the backing store. If the database file does not exist, it will be created. Example: tie %s, 'Apache::Session::DB_File', undef, {FileName => '/tmp/sessions'}; =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L, L Apache-Session-1.94/lib/Apache/Session/Store/File.pm000444000000000000 1126712456317423 22656 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::File # Implements session object storage via flat files # Copyright(c) 1998, 1999, 2000, 2004 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::File; use strict; use Symbol; use IO::File; use Fcntl; use vars qw($VERSION); $VERSION = '1.04'; $Apache::Session::Store::File::Directory = '/tmp'; sub new { my $class = shift; my $self; $self->{fh} = Symbol::gensym(); $self->{opened} = 0; return bless $self, $class; } sub insert { my $self = shift; my $session = shift; my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory; if (-e $directory.'/'.$session->{data}->{_session_id}) { die "Object already exists in the data store"; } my $file = $directory.'/'.$session->{data}->{_session_id}; sysopen ($self->{fh}, $file, O_RDWR|O_CREAT) || die "Could not open file $file: $!"; $self->{opened} = 1; print {$self->{fh}} $session->{serialized}; $self->{fh}->flush(); } sub update { my $self = shift; my $session = shift; my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory; if (!$self->{opened}) { my $file = $directory.'/'.$session->{data}->{_session_id}; sysopen ($self->{fh}, $file, O_RDWR|O_CREAT) || die "Could not open file $file: $!"; $self->{opened} = 1; } truncate($self->{fh}, 0) || die "Could not truncate file: $!"; seek($self->{fh}, 0, 0); print {$self->{fh}} $session->{serialized}; $self->{fh}->flush(); } sub materialize { my $self = shift; my $session = shift; my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory; my $file = $directory.'/'.$session->{data}->{_session_id}; if (-e $file) { if (!$self->{opened}) { sysopen ($self->{fh}, $file, O_RDWR|O_CREAT) || die "Could not open file $file: $!"; $self->{opened} = 1; } else { seek($self->{fh}, 0, 0) || die "Could not seek file: $!"; } $session->{serialized} = ''; my $fh = $self->{fh}; while (my $line = <$fh>) { $session->{serialized} .= $line; } } else { die "Object does not exist in the data store"; } } sub remove { my $self = shift; my $session = shift; my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory; if ($self->{opened}) { CORE::close $self->{fh}; $self->{opened} = 0; } my $file = $directory.'/'.$session->{data}->{_session_id}; if (-e $file) { unlink ($file) || die "Could not remove file $file: $!"; } else { die "Object does not exist in the data store"; } } sub close { my $self = shift; if ($self->{opened}) { CORE::close $self->{fh}; $self->{opened} = 0; } } sub DESTROY { my $self = shift; if ($self->{opened}) { CORE::close $self->{fh}; } } 1; =pod =head1 NAME Apache::Session::Store::File - Store persistent data on the filesystem =head1 SYNOPSIS use Apache::Session::Store::File; my $store = Apache::Session::Store::File->new; $store->insert($ref); $store->update($ref); $store->materialize($ref); $store->remove($ref); =head1 DESCRIPTION This module fulfills the storage interface of Apache::Session. The serialized objects are stored in files on your filesystem. =head1 OPTIONS This module requires one argument in the usual Apache::Session style. The name of the option is Directory, and the value is the full path of the directory where you wish to place the files. Example tie %s, 'Apache::Session::File', undef, {Directory => '/tmp/sessions'}; =head1 NOTES All session objects are stored in the same directory. Some filesystems, such as Linux's ext2fs, have O(n) performance where n is the number of files in a directory. Other filesystems, like Sun's UFS, and Linux's reiserfs, do not have this problem. You should consider your filesystem's performance before using this module to store many objects. =head1 AUTHOR This module was written by Jeffrey William Baker . =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/Store/Informix.pm000444000000000000 1115212101234530 23543 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::Informix # Implements session object storage via Informix # Copyright(c) 1998, 1999, 2000, 2004 Jeffrey William Baker (jwbaker@acm.org) and Mike Langen (mike.langen@tamedia.ch) # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::Informix; use strict; use DBI; use Apache::Session::Store::DBI; use vars qw(@ISA $VERSION); @ISA = qw(Apache::Session::Store::DBI); $VERSION = '1.02'; $Apache::Session::Store::Informix::DataSource = undef; $Apache::Session::Store::Informix::UserName = undef; $Apache::Session::Store::Informix::Password = undef; sub connection { my $self = shift; my $session = shift; return if (defined $self->{dbh}); if (exists $session->{args}->{Handle}) { $self->{dbh} = $session->{args}->{Handle}; $self->{commit} = $session->{args}->{Commit}; return; } my $datasource = $session->{args}->{DataSource} || $Apache::Session::Store::Informix::DataSource; my $username = $session->{args}->{UserName} || $Apache::Session::Store::Informix::UserName; my $password = $session->{args}->{Password} || $Apache::Session::Store::Informix::Password; $self->{dbh} = DBI->connect( $datasource, $username, $password, { RaiseError => 1, AutoCommit => 0 } ) || die $DBI::errstr; #If we open the connection, we close the connection $self->{disconnect} = 1; #the programmer has to tell us what commit policy to use $self->{commit} = $session->{args}->{Commit}; } sub materialize { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; local $self->{dbh}->{LongReadLen} = $session->{args}->{LongReadLen} || 8*2**10; if (!defined $self->{materialize_sth}) { $self->{materialize_sth} = $self->{dbh}->prepare_cached(qq{ SELECT a_session FROM sessions WHERE id = ? FOR UPDATE}); } $self->{materialize_sth}->bind_param(1, $session->{data}->{_session_id}); $self->{materialize_sth}->execute; my $results = $self->{materialize_sth}->fetchrow_arrayref; if (!(defined $results)) { die "Object does not exist in the data store"; } $self->{materialize_sth}->finish; $session->{serialized} = $results->[0]; } sub DESTROY { my $self = shift; if ($self->{commit}) { $self->{dbh}->commit; } if ($self->{disconnect}) { $self->{dbh}->disconnect; } } 1; =pod =head1 NAME Apache::Session::Store::Informix - Store persistent data in a Informix database =head1 SYNOPSIS use Apache::Session::Store::Informix; my $store = new Apache::Session::Store::Informix; $store->insert($ref); $store->update($ref); $store->materialize($ref); $store->remove($ref); =head1 DESCRIPTION Apache::Session::Store::Informix fulfills the storage interface of Apache::Session. Session data is stored in a Informix database. =head1 SCHEMA To use this module, you will need at least these columns in a table called 'sessions': id char(32) # or however long your session IDs are. a_session lvarchar To create this schema, you can execute this command using the sqlplus program: CREATE TABLE sessions ( id char(32) not null primary key, a_session lvarchar ); If you use some other command, ensure that there is a unique index on the table's id column. =head1 CONFIGURATION The module must know what datasource, username, and password to use when connecting to the database. These values can be set using the options hash (see Apache::Session documentation). The options are DataSource, UserName, and Password. Example: tie %hash, 'Apache::Session::Informix', $id, { DataSource => 'dbi:Informix:database', UserName => 'database_user', Password => 'K00l' }; Instead, you may pass in an already-opened DBI handle to your database. tie %hash, 'Apache::Session::Informix', $id, { Handle => $dbh }; The last option is LongReadLen, which specifies the maximum size of the session object. If not supplied, the default maximum size is 8 KB. =head1 AUTHOR This module was written by Mike Langen , based on the original for Oracle. =head1 SEE ALSO L, L Apache-Session-1.94/lib/Apache/Session/Store/MySQL.pm000444000000000000 670112262525374 22722 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::MySQL # Implements session object storage via MySQL # Copyright(c) 1998, 1999, 2000, 2004 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::MySQL; use strict; use DBI; use Apache::Session::Store::DBI; use vars qw(@ISA $VERSION); @ISA = qw(Apache::Session::Store::DBI); $VERSION = '1.04'; $Apache::Session::Store::MySQL::DataSource = undef; $Apache::Session::Store::MySQL::UserName = undef; $Apache::Session::Store::MySQL::Password = undef; sub connection { my $self = shift; my $session = shift; return if (defined $self->{dbh}); $self->{'table_name'} = $session->{args}->{TableName} || $Apache::Session::Store::DBI::TableName; if (exists $session->{args}->{Handle}) { $self->{dbh} = $session->{args}->{Handle}; return; } my $datasource = $session->{args}->{DataSource} || $Apache::Session::Store::MySQL::DataSource; my $username = $session->{args}->{UserName} || $Apache::Session::Store::MySQL::UserName; my $password = $session->{args}->{Password} || $Apache::Session::Store::MySQL::Password; $self->{dbh} = DBI->connect( $datasource, $username, $password, { RaiseError => 1, AutoCommit => 1 } ) || die $DBI::errstr; #If we open the connection, we close the connection $self->{disconnect} = 1; } sub DESTROY { my $self = shift; if ($self->{disconnect}) { $self->{dbh}->disconnect; } } 1; =pod =head1 NAME Apache::Session::Store::MySQL - Store persistent data in a MySQL database =head1 SYNOPSIS use Apache::Session::Store::MySQL; my $store = new Apache::Session::Store::MySQL; $store->insert($ref); $store->update($ref); $store->materialize($ref); $store->remove($ref); =head1 DESCRIPTION Apache::Session::Store::MySQL fulfills the storage interface of Apache::Session. Session data is stored in a MySQL database. =head1 SCHEMA To use this module, you will need at least these columns in a table called 'sessions', or another table name if you provide the TableName argument: id char(32) # or however long your session IDs are. a_session blob # or varbinary if you plan to use a big session (>64k after serialization) To create this schema, you can execute this command using the mysql program: CREATE TABLE sessions ( id char(32) not null primary key, a_session blob ); If you use some other command, ensure that there is a unique index on the table's id column. =head1 CONFIGURATION The module must know what datasource, username, and password to use when connecting to the database. These values can be set using the options hash (see Apache::Session documentation). The options are: =over 4 =item DataSource =item UserName =item Password =item TableName =item Handle =back Example: tie %hash, 'Apache::Session::MySQL', $id, { DataSource => 'dbi:mysql:database', UserName => 'database_user', Password => 'K00l', TableName => 'sessions' }; Instead, you may pass in an already-opened DBI handle to your database. tie %hash, 'Apache::Session::MySQL', $id, { Handle => $dbh }; =head1 AUTHOR This modules was written by Jeffrey William Baker =head1 SEE ALSO L Apache-Session-1.94/lib/Apache/Session/Store/Oracle.pm000444000000000000 1127512101234523 23165 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::Oracle # Implements session object storage via Oracle # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::Oracle; use strict; use DBI; use Apache::Session::Store::DBI; use vars qw(@ISA $VERSION); @ISA = qw(Apache::Session::Store::DBI); $VERSION = '1.10'; $Apache::Session::Store::Oracle::DataSource = undef; $Apache::Session::Store::Oracle::UserName = undef; $Apache::Session::Store::Oracle::Password = undef; sub connection { my $self = shift; my $session = shift; return if (defined $self->{dbh}); $self->{'table_name'} = $session->{args}->{TableName} || $Apache::Session::Store::DBI::TableName; if (exists $session->{args}->{Handle}) { $self->{dbh} = $session->{args}->{Handle}; $self->{commit} = $session->{args}->{Commit}; return; } my $datasource = $session->{args}->{DataSource} || $Apache::Session::Store::Oracle::DataSource; my $username = $session->{args}->{UserName} || $Apache::Session::Store::Oracle::UserName; my $password = $session->{args}->{Password} || $Apache::Session::Store::Oracle::Password; $self->{dbh} = DBI->connect( $datasource, $username, $password, { RaiseError => 1, AutoCommit => 0 } ) || die $DBI::errstr; #If we open the connection, we close the connection $self->{disconnect} = 1; #the programmer has to tell us what commit policy to use $self->{commit} = $session->{args}->{Commit}; } sub materialize { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; local $self->{dbh}->{LongReadLen} = $session->{args}->{LongReadLen} || 8*2**10; if (!defined $self->{materialize_sth}) { $self->{materialize_sth} = $self->{dbh}->prepare_cached(qq{ SELECT a_session FROM $self->{'table_name'} WHERE id = ? FOR UPDATE}); } $self->{materialize_sth}->bind_param(1, $session->{data}->{_session_id}); $self->{materialize_sth}->execute; my $results = $self->{materialize_sth}->fetchrow_arrayref; if (!(defined $results)) { die "Object does not exist in the data store"; } $self->{materialize_sth}->finish; $session->{serialized} = $results->[0]; } sub DESTROY { my $self = shift; if ($self->{commit}) { $self->{dbh}->commit; } if ($self->{disconnect}) { $self->{dbh}->disconnect; } } 1; =pod =head1 NAME Apache::Session::Store::Oracle - Store persistent data in a Oracle database =head1 SYNOPSIS use Apache::Session::Store::Oracle; my $store = new Apache::Session::Store::Oracle; $store->insert($ref); $store->update($ref); $store->materialize($ref); $store->remove($ref); =head1 DESCRIPTION Apache::Session::Store::Oracle fulfills the storage interface of Apache::Session. Session data is stored in a Oracle database. =head1 SCHEMA To use this module, you will need at least these columns in a table called 'sessions': id varchar2(32) # or however long your session IDs are. a_session long To create this schema, you can execute this command using the sqlplus program: CREATE TABLE sessions ( id varchar2(32) not null primary key, a_session long ); If you use some other command, ensure that there is a unique index on the table's id column. =head1 CONFIGURATION The module must know what datasource, username, and password to use when connecting to the database. These values can be set using the options hash (see Apache::Session documentation). The options are DataSource, UserName, and Password. Example: tie %hash, 'Apache::Session::Oracle', $id, { DataSource => 'dbi:Oracle:database', UserName => 'database_user', Password => 'K00l' }; Instead, you may pass in an already-opened DBI handle to your database. tie %hash, 'Apache::Session::Oracle', $id, { Handle => $dbh }; The last option is LongReadLen, which specifies the maximum size of the session object. If not supplied, the default maximum size is 8 KB. =head1 AUTHOR This modules was written by Jeffrey William Baker A fix for the commit policy was contributed by Michael Schout =head1 SEE ALSO L, L Apache-Session-1.94/lib/Apache/Session/Store/Postgres.pm000444000000000000 1127612064203706 23576 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::Postgres # Implements session object storage via Postgres # Copyright(c) 1998, 1999, 2000 Jeffrey William Baker (jwbaker@acm.org) # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::Postgres; use strict; use DBI; use Apache::Session::Store::DBI; use vars qw(@ISA $VERSION); @ISA = qw(Apache::Session::Store::DBI); $VERSION = '1.03'; $Apache::Session::Store::Postgres::DataSource = undef; $Apache::Session::Store::Postgres::UserName = undef; $Apache::Session::Store::Postgres::Password = undef; sub connection { my $self = shift; my $session = shift; return if (defined $self->{dbh}); $self->{'table_name'} = $session->{args}->{TableName} || $Apache::Session::Store::DBI::TableName; if (exists $session->{args}->{Handle}) { $self->{dbh} = $session->{args}->{Handle}; $self->{commit} = $session->{args}->{Commit}; return; } my $datasource = $session->{args}->{DataSource} || $Apache::Session::Store::Postgres::DataSource; my $username = $session->{args}->{UserName} || $Apache::Session::Store::Postgres::UserName; my $password = $session->{args}->{Password} || $Apache::Session::Store::Postgres::Password; $self->{dbh} = DBI->connect( $datasource, $username, $password, { RaiseError => 1, AutoCommit => 0 } ) || die $DBI::errstr; #If we open the connection, we close the connection $self->{disconnect} = 1; #the programmer has to tell us what commit policy to use $self->{commit} = $session->{args}->{Commit}; } sub materialize { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; if (!defined $self->{materialize_sth}) { $self->{materialize_sth} = $self->{dbh}->prepare_cached(qq{ SELECT a_session FROM $self->{'table_name'} WHERE id = ? FOR UPDATE}); } $self->{materialize_sth}->bind_param(1, $session->{data}->{_session_id}); $self->{materialize_sth}->execute; my $results = $self->{materialize_sth}->fetchrow_arrayref; if (!(defined $results)) { $self->{materialize_sth}->finish; die "Object does not exist in the data store"; } $self->{materialize_sth}->finish; $session->{serialized} = $results->[0]; } sub DESTROY { my $self = shift; if ($self->{commit}) { $self->{dbh}->commit; } if ($self->{disconnect}) { $self->{dbh}->disconnect; } } 1; =pod =head1 NAME Apache::Session::Store::Postgres - Store persistent data in a Postgres database =head1 SYNOPSIS use Apache::Session::Store::Postgres; my $store = new Apache::Session::Store::Postgres; $store->insert($ref); $store->update($ref); $store->materialize($ref); $store->remove($ref); =head1 DESCRIPTION Apache::Session::Store::Postgres fulfills the storage interface of Apache::Session. Session data is stored in a Postgres database. =head1 SCHEMA To use this module, you will need at least these columns in a table called 'sessions', or another name if you supply the TableName parameter. id char(32) # or however long your session IDs are. a_session text # This has an ~8 KB limit :( To create this schema, you can execute this command using the psql program: CREATE TABLE sessions ( id char(32) not null primary key, a_session text ); If you use some other command, ensure that there is a unique index on the table's id column. =head1 CONFIGURATION The module must know what datasource, username, and password to use when connecting to the database. These values can be set using the options hash (see Apache::Session documentation). The options are: =over 4 =item DataSource =item UserName =item Password =item Handle =item TableName =back Example: tie %hash, 'Apache::Session::Postgres', $id, { DataSource => 'dbi:Pg:dbname=database', UserName => 'database_user', Password => 'K00l' }; Instead, you may pass in an already-opened DBI handle to your database. tie %hash, 'Apache::Session::Postgres', $id, { Handle => $dbh }; =head1 AUTHOR This modules was written by Jeffrey William Baker A fix for the commit policy was contributed by Michael Schout =head1 SEE ALSO L, L Apache-Session-1.94/lib/Apache/Session/Store/Sybase.pm000444000000000000 1732511254001142 23205 0ustar00unknownunknown000000000000############################################################################# # # Apache::Session::Store::Sybase # Apache persistent user sessions in a DBI::Sybase database # # Copyright(c) 2000, 2004 Jeffrey William Baker (jwbaker@acm.org), Mark Landry (mdlandry@lincoln.midcoast.com), and Chris Winters (chris@cwinters.com) # # With modifications from earlier version of Apache::Session::DBI::Sybase # from Mark Landry (mdlandry@lincoln.midcoast.com) # # Modified to work with Apache::Session v 1.5+ by Chris Winters (chris@cwinters.com) # # Distribute under the Perl License # ############################################################################ package Apache::Session::Store::Sybase; use strict; use vars qw( @ISA $VERSION ); use Apache::Session::Store::DBI; @ISA = qw( Apache::Session::Store::DBI ); $VERSION = '1.01'; $Apache::Session::Store::Sybase::DataSource = undef; $Apache::Session::Store::Sybase::UserName = undef; $Apache::Session::Store::Sybase::Password = undef; sub connection { my $self = shift; my $session = shift; return if ( defined $self->{dbh} ); if ( exists $session->{args}->{Handle} ) { $self->{dbh} = $session->{args}->{Handle}; $self->{commit} = $session->{args}->{Commit}; } else { my $datasource = $session->{args}->{DataSource} || $Apache::Session::Store::Sybase::DataSource; my $username = $session->{args}->{UserName} || $Apache::Session::Store::Sybase::UserName; my $password = $session->{args}->{Password} || $Apache::Session::Store::Sybase::Password; $self->{dbh} = DBI->connect( $datasource, $username, $password, { RaiseError => 1, AutoCommit => 0 } ) || die $DBI::errstr; # If we open the connection, we close the connection $self->{disconnect} = 1; } # the programmer has to tell us what commit policy to use; # note that this should take effect even if the programmer # passes us a handle $self->{commit} = $session->{args}->{Commit}; # sets the variable @@textsize to the default, which # should be 32K; to test, do this from a isql/sqsh session: # # > set textsize 0 # > go # > select @@textsize # > go # # You should see something like: # : # : ----------- # : 32768 # # Note that you can also pass an argument ('textsize') for a # larger/smaller text size my $textsize = $session->{args}->{textsize} || '0'; $self->{dbh}->do( "set textsize $textsize" ); } # Both insert() and update() are modifications to # Apache::Session::Store::DBI. # Sybase cannot use placeholders for IMAGE/TEXT field types so you # must pass the data directly in the SQL rather than using bound # parameters. Naturally, this negates any usefulness of the # 'prepare_cached' method used in Apache::Session::Store::DBI, so we # use a more straightforward sequence to prepare/execute here. # Also, if you use this storage mechanism, you must also use the # serializer that puts the data structure into a format that you can # put directly into the SQL statement (e.g., '0xblahblahblah') sub insert { my $self = shift; my $session = shift; $self->connection( $session ); local $self->{dbh}->{RaiseError} = 1; my $sth = $self->{dbh}->prepare( qq{ INSERT INTO sessions (id, a_session) VALUES ( }.$self->{dbh}->quote($session->{data}->{_session_id}).qq{, }.$self->{dbh}->quote($session->{serialized}).qq{ ) } ); $sth->execute( ); } sub update { my $self = shift; my $session = shift; $self->connection( $session ); local $self->{dbh}->{RaiseError} = 1; my $sth = $self->{dbh}->prepare( qq{ UPDATE sessions SET a_session = }.$self->{dbh}->quote($session->{serialized}).qq{ WHERE id = }.$self->{dbh}->quote($session->{data}->{_session_id}) ); $sth->execute( ); } sub materialize { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; $self->{materialize_sth} = $self->{dbh}->prepare(qq{ SELECT a_session FROM sessions WHERE id = }.$self->{dbh}->quote( $session->{data}->{_session_id})); $self->{materialize_sth}->execute; my $results = $self->{materialize_sth}->fetchrow_arrayref; if (!(defined $results)) { die "Object does not exist in the data store"; } $self->{materialize_sth}->finish; $session->{serialized} = $results->[0]; } sub remove { my $self = shift; my $session = shift; $self->connection($session); local $self->{dbh}->{RaiseError} = 1; $self->{remove_sth} = $self->{dbh}->prepare_cached(qq{ DELETE FROM sessions WHERE id = }.$self->{dbh}->quote($session->{data}->{_session_id})); $self->{remove_sth}->execute; $self->{remove_sth}->finish; } sub DESTROY { my $self = shift; if ( $self->{commit} ) { $self->{dbh}->commit; } if ( $self->{disconnect} ) { $self->{dbh}->disconnect; } } 1; =pod =head1 NAME Apache::Session::Store::Sybase - Store persistent data in a Sybase database =head1 SYNOPSIS use Apache::Session::Store::Sybase; my $store = new Apache::Session::Store::MySQL; $store->insert( $ref ); $store->update( $ref ); $store->materialize( $ref ); $store->remove( $ref ); =head1 DESCRIPTION Apache::Session::Store::Sybase fulfills the storage interface of Apache::Session. Session data is stored in a Sybase database. =head1 SCHEMA To use this module, you will need at least these columns in a table called 'sessions': id CHAR(32) # or however long your session IDs are. a_session IMAGE To create this schema, you can execute this command using the isql or sqsh programs: CREATE TABLE sessions ( id CHAR(32) not null primary key, a_session TEXT ) go If you use some other command, ensure that there is a unique index on the id column of the table =head1 CONFIGURATION The module must know what datasource, username, and password to use when connecting to the database. These values can be set using the options hash (see Apache::Session documentation). The options are: =over 4 =item DataSource =item UserName =item Password =back Example: tie %hash, 'Apache::Session::Sybase', $id, { DataSource => 'dbi:Sybase:database=db;server=server', UserName => 'database_user', Password => 'K00l', Commit => 1, }; Instead, you may pass in an already-opened DBI handle to your database. tie %hash, 'Apache::Session::Sybase', $id, { Handle => $dbh }; Additional arguments you can pass to the backing store are: =over 4 =item Commit - whether we should commit any changes; if you pass in an already-open database handle that has AutoCommit set to a true value, you do not need to set this. If you let Apache::Session::Store::Sybase create your database, handle, you must set this to a true value, otherwise, your changes will not be saved =item textsize - the value we should pass to the 'set textsize ' command that sets the max size of the IMAGE field. Default is 32K (at least in Sybase ASE 11.9.2). =back =head1 AUTHOR This module was based on L which was written by Jeffrey William Baker ; it was modified by Chris Winters to work with Apache::Session 1.5+ with changes from earlier version of Apache::Session::DBI::Sybase from Mark Landry . =head1 SEE ALSO L =cut Apache-Session-1.94/t000755000000000000 013731226572 15053 5ustar00unknownunknown000000000000Apache-Session-1.94/t/99base64.t000444000000000000 155611254001142 16630 0ustar00unknownunknown000000000000use Test::More; use Test::Deep; plan skip_all => "Optional modules (MIME::Base64) not installed" unless eval { require MIME::Base64; }; plan tests => 3; my $package = 'Apache::Session::Serialize::Base64'; use_ok $package; can_ok $package, qw[serialize unserialize]; my $serialize = \&{"$package\::serialize"}; my $unserialize = \&{"$package\::unserialize"}; my $session = { serialized => undef, data => undef, }; my $simple = { foo => 1, bar => 2, baz => 'quux', quux => ['foo', 'bar'], }; $session->{data} = $simple; $serialize->($session); $session->{data} = undef; $unserialize->($session); cmp_deeply $session->{data}, $simple, "Session was deserialized correctly"; Apache-Session-1.94/t/99dbfile.t000444000000000000 241213730743333 17001 0ustar00unknownunknown000000000000use Test::More; use Test::Deep; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; plan skip_all => "Optional module (DB_File) not installed" unless eval { require DB_File; }; my $package = 'Apache::Session::DB_File'; plan tests => 8; diag "DB_File version ".DB_File->VERSION(); use_ok $package; my $origdir = getcwd; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); chdir( $tempdir ); my %session; my %tie_params = ( FileName => './text.db', LockDirectory => '.', ); tie %session, $package, undef, { %tie_params }; ok( tied(%session), "The session is tied" ); ok( exists($session{_session_id}), "Session id exists" ); ok( defined($session{_session_id}), "Session id is defined" ); my $id = $session{_session_id}; my $foo = 'bar'; my $baz = [ qw[tom dick harry] ]; $session{foo} = $foo; $session{baz} = $baz; untie %session; undef %session; tie %session, $package, $id, { %tie_params }; ok( tied(%session), "The session is tied again" ); is( $session{_session_id}, $id, "Session IDs match" ); cmp_deeply $session{foo}, $foo, "Foo matches"; cmp_deeply $session{baz}, $baz, "Baz matches"; tied(%session)->delete; untie %session; undef %session; chdir( $origdir ); Apache-Session-1.94/t/99dbfilestore.t000444000000000000 335311254001142 20043 0ustar00unknownunknown000000000000use Test::More; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; plan skip_all => "Optional module (DB_File) not installed" unless eval { require DB_File; }; my $package = 'Apache::Session::Store::DB_File'; plan tests => 13; use_ok $package; use_ok 'DB_File'; can_ok $package, qw[new insert materialize remove]; my $origdir = getcwd; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); chdir( $tempdir ); my $serial = '12345'; my $id = 'test1'; my $dbfile = 'foo.dbm'; my $session = { serialized => $serial, data => { _session_id => $id, }, args => { FileName => $dbfile, }, }; my $store = $package->new; isa_ok $store, $package; my $i_ret = $store->insert($session); is( $i_ret, $serial, "insert() returned value of serialized" ); ok( -e $dbfile, 'dbm file exists' ); undef $store; $store = $package->new; isa_ok $store, $package; $session->{serialized} = undef; lives_ok { $store->materialize($session) } 'materialize did not die'; is( $session->{serialized}, $serial, "materialized session is correct" ); my $new_serial = 'hi'; $session->{serialized} = $new_serial; my $u_ret = $store->update($session); is( $u_ret, $new_serial, "update() returned value of new serialized" ); undef $store; my %hash; tie %hash, 'DB_File', $dbfile; is( $hash{$id}, $new_serial, "dbm file updated correctly" ); $store = $package->new; isa_ok $store, $package; $store->remove($session); dies_ok { $store->materialize($session); } "Can't materialize removed session"; undef $store; untie %hash; undef %hash; chdir( $origdir ); Apache-Session-1.94/t/99file.t000444000000000000 252511254001142 16460 0ustar00unknownunknown000000000000use Test::More; use Test::Deep; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; plan skip_all => "Optional module (Fcntl) not installed" unless eval { require Fcntl; }; plan tests => 9; my $package = 'Apache::Session::File'; use_ok $package; my $origdir = getcwd; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); chdir( $tempdir ); my %session; my %tie_params = ( Directory => '.', LockDirectory => '.' ); tie %session, $package, undef, { %tie_params }; ok( tied(%session), "session is tied" ); ok( exists($session{_session_id}), "session id exists" ); ok( defined($session{_session_id}), "session id is defined" ); my $id = $session{_session_id}; my $foo = 'bar'; my $baz = [ qw[tom dick harry] ]; $session{foo} = $foo; $session{baz} = $baz; untie %session; undef %session; tie %session, $package, $id, { %tie_params }; ok( tied(%session), "The session is tied again" ); is( $session{_session_id}, $id, "Session IDs match" ); cmp_deeply $session{foo}, $foo, "Foo matches"; cmp_deeply $session{baz}, $baz, "Baz matches"; tied(%session)->delete; untie %session; undef %session; dies_ok { tie %session, $package, '../../../../../../../../foo', { %tie_params }; } "unsafe tie detected correctly"; chdir( $origdir ); Apache-Session-1.94/t/99filelock.t000444000000000000 170511254001142 17330 0ustar00unknownunknown000000000000use Test::More; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; plan skip_all => "Optional module (Fcntl) not installed" unless eval { require Fcntl; }; plan tests => 4; my $package = 'Apache::Session::Lock::File'; use_ok $package; my $origdir = getcwd; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); chdir( $tempdir ); my $lock = $package->new; my $session = { data => { _session_id => 'foo' }, args => { LockDirectory => '.' }, }; $lock->acquire_read_lock($session); ok -e './Apache-Session-foo.lock', 'lock file exists'; undef $lock; unlink('./Apache-Session-foo.lock'); $lock = $package->new; $lock->acquire_write_lock($session); ok -e './Apache-Session-foo.lock', 'lock file exists'; $lock->release_all_locks($session); $lock->clean('.', 0); ok !-e './Apache-Session-foo.lock', 'lock file does not exist'; chdir( $origdir ); Apache-Session-1.94/t/99filestore.t000444000000000000 321511254001142 17532 0ustar00unknownunknown000000000000use Test::More; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; plan skip_all => "Optional module (Fcntl) not installed" unless eval { require Fcntl; }; plan tests => 7; my $package = 'Apache::Session::Store::File'; use_ok $package; my $origdir = getcwd; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); chdir( $tempdir ); my $session = { serialized => 12345, data => { _session_id => 'test1'}, }; $Apache::Session::Store::File::Directory = '.'; $Apache::Session::Store::File::Directory = '.'; my $store = Apache::Session::Store::File->new; $store->insert($session); ok( -e "./test1", "Store file exists" ); undef $store; open (TEST, '<./test1'); my $store_contents = do { local $/; }; ok( $store_contents eq $session->{serialized} && $store_contents == 12345, "Store contents are okay" ); close TEST; $store = Apache::Session::Store::File->new; $session->{serialized} = ''; $store->materialize($session); ok( $session->{serialized} == 12345, 'restoring from file worked' ); $session->{serialized} = 'hi'; $store->update($session); undef $store; open (TEST, '<./test1'); undef $store_contents; $store_contents = do { local $/; }; ok( $store_contents eq $session->{serialized} && $store_contents eq 'hi', 'Store contents are okay' ); close TEST; undef $store; $store = Apache::Session::Store::File->new; $store->remove($session); ok( !-e "./test1", 'Session removed properly' ); dies_ok { $store->materialize($session); } "could not materialize nonexistent session"; chdir( $origdir ); Apache-Session-1.94/t/99flex.t000444000000000000 1106711432730112 16524 0ustar00unknownunknown000000000000use strict; use Test::More; #use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; use Config; #plan skip_all => "Only for perl 5.8 or later" # unless eval { # require 5.008; #perl 5.6 does not likes this test. See RT#16539. # }; #use Module::Mask;my $mask = new Module::Mask ('Storable'); plan skip_all => "Optional modules (Fcntl, Digest::MD5) not installed" unless eval { require Fcntl; require Digest::MD5; }; plan tests => 7; my $package = 'Apache::Session::Flex'; use_ok $package; #$Apache::Session::Lock::File::LockDirectory=$tempdir; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); #my $origdir = getcwd; #chdir( $tempdir ); { my $session = tie my %session, $package, undef, { Store => 'File', Lock => 'File', Generate => 'MD5', Serialize => 'Storable', Directory => $tempdir, LockDirectory => $tempdir, }; isa_ok $session->{object_store}, 'Apache::Session::Store::File'; isa_ok $session->{lock_manager}, 'Apache::Session::Lock::File'; is ref($session->{generate}), 'CODE', 'generate is CODE'; is ref($session->{serialize}), 'CODE', 'serialize is CODE'; is ref($session->{unserialize}), 'CODE', 'unserialize is CODE'; tied(%session)->delete; #untie %session; } =for cmt SKIP: { #Flex that uses IPC skip "semget not implemented",5 unless $Config{d_semget}; skip "semctl not implemented",5 unless $Config{d_semctl}; skip "Cygserver is not running",5 if $^O eq 'cygwin' && (!exists $ENV{'CYGWIN'} || $ENV{'CYGWIN'} !~ /server/i); skip "*BSD & Solaris do not like anonymous semaphores",5 if $^O =~ /bsd|solaris/i; skip "Optional modules (IPC::Semaphore, IPC::SysV, MIME::Base64, DB_File) not installed",5 unless eval { require IPC::Semaphore; require IPC::SysV; require MIME::Base64; require DB_File; }; diag( "Using IPC::Semaphore $IPC::Semaphore::VERSION, IPC::SysV $IPC::SysV::VERSION, DB_File $DB_File::VERSION" ); require Apache::Session::Lock::Semaphore; $Apache::Session::Lock::Semaphore::sem_key=undef; $Apache::Session::Lock::Semaphore::sem_key=$Apache::Session::Lock::Semaphore::sem_key; my $session = tie my %session, $package, undef, { Store => 'DB_File', Lock => 'Semaphore', Generate => 'MD5', Serialize => 'Base64', # SemaphoreKey => undef, # SemaphoreKey => 31817, }; #Apache::Session::save in TIEHASH does acquire_write_lock isa_ok $session->{object_store}, 'Apache::Session::Store::DB_File'; isa_ok $session->{lock_manager}, 'Apache::Session::Lock::Semaphore'; is ref($session->{generate}), 'CODE', 'generate is CODE'; is ref($session->{serialize}), 'CODE', 'serialize is CODE'; is ref($session->{unserialize}), 'CODE', 'unserialize is CODE'; $session->{lock_manager}->remove(); } =cut { { package Apache::Session::Store::Test; use base 'Apache::Session::Store::File'; } { package Apache::Session::Lock::Test; use base 'Apache::Session::Lock::File'; } { package Apache::Session::Generate::Test; # This wack double assignment prevents "... used only once" # warnings. *Apache::Session::Generate::Test::generate = *Apache::Session::Generate::Test::generate = \&Apache::Session::Generate::MD5::generate; *Apache::Session::Generate::Test::validate = *Apache::Session::Generate::Test::validate = \&Apache::Session::Generate::MD5::validate; } { package Apache::Session::Serialize::Test; *Apache::Session::Serialize::Test::serialize = *Apache::Session::Serialize::Test::serialize = \&Apache::Session::Serialize::Storable::serialize; *Apache::Session::Serialize::Test::unserialize = *Apache::Session::Serialize::Test::unserialize = \&Apache::Session::Serialize::Storable::unserialize; } my $session = tie my %session, $package, undef, { Store => 'Test', Lock => 'Test', Generate => 'Test', Serialize => 'Test', Directory => $tempdir, LockDirectory => $tempdir, }; isa_ok $session->{object_store}, 'Apache::Session::Store::Test'; tied(%session)->delete; $session->{lock_manager}->clean('.', 0); } #chdir( $origdir ); Apache-Session-1.94/t/99md5gen.t000444000000000000 224711254001142 16721 0ustar00unknownunknown000000000000use Test::More; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; plan skip_all => "Optional module (Digest::MD5) not installed" unless eval { require Digest::MD5; }; plan tests => 33; my $package = 'Apache::Session::Generate::MD5'; use_ok $package; #my $origdir = getcwd; #my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); #chdir( $tempdir ); my $session = {}; Apache::Session::Generate::MD5::generate($session); ok exists($session->{data}->{_session_id}), 'session id created'; ok keys(%{$session->{data}}) == 1, 'just one key in the data hashref'; like $session->{data}->{_session_id}, qr/^[0-9a-fA-F]{32}$/, 'id looks like hex'; my $old_id = $session->{data}->{_session_id}; Apache::Session::Generate::MD5::generate($session); isnt $old_id, $session->{data}->{_session_id}, 'old session id does not match new one'; for my $length (5 .. 32) { $session->{args}->{IDLength} = $length; Apache::Session::Generate::MD5::generate($session); like $session->{data}->{_session_id}, qr/^[0-9a-fA-F]{$length}$/, "id is $length chars long"; } #chdir( $origdir ); Apache-Session-1.94/t/99moduniqgen.t000444000000000000 124011254001142 17700 0ustar00unknownunknown000000000000use Test::More; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; plan tests => 4; my $package = 'Apache::Session::Generate::ModUniqueId'; use_ok $package; #my $origdir = getcwd; #my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); #chdir( $tempdir ); $ENV{UNIQUE_ID} = '12345678790abcdef'; my $session = {}; Apache::Session::Generate::ModUniqueId::generate($session); ok exists($session->{data}->{_session_id}), 'session id created'; ok keys(%{$session->{data}}) == 1, 'just one key in the data hashref'; is $session->{data}->{_session_id}, $ENV{UNIQUE_ID}, 'id matches UNIQUE_ID env param'; #chdir( $origdir ); Apache-Session-1.94/t/99mysql.t000444000000000000 1264212320750723 16742 0ustar00unknownunknown000000000000use Test::More; use Test::Deep; #plan skip_all => "Not running RDBM tests without APACHE_SESSION_MAINTAINER=1" # unless ($ENV{APACHE_SESSION_MAINTAINER} || $ENV{TRAVIS}); plan skip_all => "Optional modules (Test::Database, DBD::mysql, DBI) not installed" unless eval { require Test::Database; require DBD::mysql; require DBI; }; my $dbd_mysq_ver = DBD::mysql->VERSION(); plan skip_all => "Version $dbd_mysq_ver of DBD::mysql has serious problems on Windows" if ($^O eq 'MSWin32' && $dbd_mysq_ver >= '4.021' && $dbd_mysq_ver <= '4.023'); if ($ENV{TRAVIS}) { my $cfg = << 'EOT'; driver_dsn = dbi:mysql: username = root EOT Test::Database->load_config(\$cfg); } my @db_handles = Test::Database->handles('mysql'); plan skip_all => "No mysql handle reported by Test::Database" unless @db_handles; my $mysql = $db_handles[0]; my $dsn = $mysql->dsn(); my $uname = $mysql->username(); my $upass = $mysql->password(); diag "DBD::mysql version ".DBD::mysql->VERSION(); plan skip_all => "Test::Database handle->driver is undef. Probably it was not possible to establish connection." if !defined($mysql->driver); diag "Mysql version ".$mysql->driver->version; plan tests => 23; my $package = 'Apache::Session::MySQL'; use_ok $package; my @tables_used = qw/sessions s/; sub drop_tables { my $dbh = shift; my $dblist = join(', ', @_); my $res = $dbh->do("DROP TABLE IF EXISTS $dblist"); if (!defined $res and $dbh->errstr =~ /Cannot delete or update a parent row: a foreign key constraint/) { my $ary_ref = $dbh->selectcol_arrayref('SHOW TABLES'); $dblist = join(', ', @$ary_ref); diag "Found foreign key constraint, trying to drop all tables from DB"; $dbh->do("SET foreign_key_checks = 0"); $dbh->do("DROP TABLE IF EXISTS $dblist"); $dbh->do("SET foreign_key_checks = 1"); } } { my $dbh1 = $mysql->dbh(); drop_tables($dbh1, @tables_used); foreach my $table (@tables_used) { $dbh1->do(<<"EOT"); CREATE TABLE $table ( id char(32) not null primary key, a_session blob ); EOT } } my $session = {}; tie %{$session}, $package, undef, { DataSource => $dsn, UserName => $uname, Password => $upass, LockDataSource => $dsn, LockUserName => $uname, LockPassword => $upass, }; ok tied(%{$session}), 'session tied'; ok exists($session->{_session_id}), 'session id exists'; my $id = $session->{_session_id}; my $foo = $session->{foo} = 'bar'; my $baz = $session->{baz} = ['tom', 'dick', 'harry']; my $test_value = $session->{'test'} = 12; #test for RT#50896 untie %{$session}; undef $session; $session = {}; tie %{$session}, $package, $id, { DataSource => $dsn, UserName => $uname, Password => $upass, LockDataSource => $dsn, LockUserName => $uname, LockPassword => $upass, }; ok tied(%{$session}), 'session tied'; is $session->{_session_id}, $id, 'id retrieved matches one stored'; cmp_deeply $session->{foo}, $foo, "Foo matches"; cmp_deeply $session->{baz}, $baz, "Baz matches"; cmp_deeply $session->{test}, $test_value, "test matches"; untie %{$session}; undef $session; $session = {}; { tie %{$session}, $package, undef, { TableName => 's', DataSource => $dsn, UserName => $uname, Password => $upass, LockDataSource => $dsn, LockUserName => $uname, LockPassword => $upass, }; ok tied(%{$session}), 'session tied'; ok exists($session->{_session_id}), 'session id exists'; my $id1 = $session->{_session_id}; $session{'test'} = 13; untie %{$session}; undef $session; $session = {}; tie %{$session}, $package, $id1, { TableName => 's', DataSource => $dsn, UserName => $uname, Password => $upass, LockDataSource => $dsn, LockUserName => $uname, LockPassword => $upass, }; ok tied(%{$session}), 'session tied'; ok exists($session->{_session_id}), 'session id exists'; is($session->{_session_id}, $id1, 'session id is correct'); is($session{'test'}, 13, 'correct value retrieved'); untie %{$session}; undef $session; $session = {}; tie %{$session}, $package, $id1, { #test for RT#50896 TableName => 's', DataSource => $dsn, UserName => $uname, Password => $upass, LockDataSource => $dsn, LockUserName => $uname, LockPassword => $upass, }; ok tied(%{$session}), 'session tied'; ok exists($session->{_session_id}), 'session id exists'; is($session->{_session_id}, $id1, 'session id is correct'); is($session{'test'}, 13, 'correct value retrieved'); } untie %{$session}; undef $session; $session = {}; my $dbh = DBI->connect($dsn, $uname, $upass, {RaiseError => 1}); tie %{$session}, $package, $id, { Handle => $dbh, LockHandle => $dbh, }; ok tied(%{$session}), 'session tied'; is $session->{_session_id}, $id, 'id retrieved matches one stored'; cmp_deeply $session->{foo}, $foo, "Foo matches"; cmp_deeply $session->{baz}, $baz, "Baz matches"; cmp_deeply $session->{'test'}, $test_value, "test matches"; tied(%{$session})->delete; untie %{$session}; $dbh->disconnect; unless ($ENV{TRAVIS}) { my $dbh1 = $mysql->dbh(); drop_tables($dbh1, @tables_used); } Apache-Session-1.94/t/99mysqllock.t000444000000000000 372512322250133 17565 0ustar00unknownunknown000000000000use Test::More; #plan skip_all => "Not running RDBM tests without APACHE_SESSION_MAINTAINER=1" # unless $ENV{APACHE_SESSION_MAINTAINER}; plan skip_all => "Optional modules (Test::Database, DBD::mysql, DBI) not installed" unless eval { require Test::Database; require DBD::mysql; require DBI; }; if ($ENV{TRAVIS}) { my $cfg = << 'EOT'; driver_dsn = dbi:mysql: username = root EOT Test::Database->load_config(\$cfg); } my @db_handles = Test::Database->handles('mysql'); plan skip_all => "No mysql handle reported by Test::Database" unless @db_handles; my $mysql = $db_handles[0]; my $dsn = $mysql->dsn(); my $uname = $mysql->username(); my $upass = $mysql->password(); my $dbh = DBI->connect($dsn, $uname, $upass); plan skip_all => "Cannot connect to DB specified in Test::Database config" unless $dbh; plan tests => 4; my $package = 'Apache::Session::Lock::MySQL'; use_ok $package; my $session = { args => { LockDataSource => $dsn, LockUserName => $uname, LockPassword => $upass, }, data => { _session_id => '09876543210987654321098765432109', } }; my $lock = $package->new; my $sth = $dbh->prepare(q{SELECT GET_LOCK('Apache-Session-09876543210987654321098765432109', 0)}); my $sth2 = $dbh->prepare(q{SELECT RELEASE_LOCK('Apache-Session-09876543210987654321098765432109')}); $lock->acquire_write_lock($session); $sth->execute(); is +($sth->fetchrow_array)[0], 0, 'could not get lock'; $lock->release_write_lock($session); $sth->execute(); is +($sth->fetchrow_array)[0], 1, 'could get lock'; $sth2->execute; undef $lock; $session->{args}->{LockHandle} = $dbh; $lock = $package->new; $lock->acquire_read_lock($session); $sth->execute(); $sth->execute(); is +($sth->fetchrow_array)[0], 1, 'could get lock'; undef $lock; $sth->finish; $sth2->finish; $dbh->disconnect; Apache-Session-1.94/t/99mysqlstore.t000444000000000000 70612101215650 17745 0ustar00unknownunknown000000000000use Test::More; #plan skip_all => "Not running RDBM tests without APACHE_SESSION_MAINTAINER=1" # unless $ENV{APACHE_SESSION_MAINTAINER}; plan skip_all => "Optional modules (DBD::mysql, DBI) not installed" unless eval { require DBD::mysql; require DBI; }; plan tests => 2; my $package = 'Apache::Session::Store::MySQL'; use_ok $package; my $foo = $package->new; isa_ok $foo, $package; Apache-Session-1.94/t/99nulllock.t000444000000000000 75211254001142 17344 0ustar00unknownunknown000000000000use Test::More; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; #my $origdir = getcwd; #my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); #chdir( $tempdir ); plan tests => 4; my $package = 'Apache::Session::Lock::Null'; use_ok $package; my $session = {}; my $lock = $package->new; ok $lock->acquire_read_lock($s), 'got read'; ok $lock->acquire_write_lock($s), 'got write'; ok $lock->release_all_locks($s), 'released all'; undef $lock; #chdir( $origdir ); Apache-Session-1.94/t/99oracle.t000444000000000000 526412064175557 17037 0ustar00unknownunknown000000000000use Test::More; use Test::Deep; plan skip_all => "Not running RDBM tests without APACHE_SESSION_MAINTAINER=1" unless $ENV{APACHE_SESSION_MAINTAINER}; plan skip_all => "Optional modules (DBD::Oracle, DBI) not installed" unless eval { require DBD::Oracle; require DBI; }; plan tests => 13; my $package = 'Apache::Session::Oracle'; use_ok $package; my $session = {}; #$ENV{ORACLE_SID}='';$ENV{AS_ORACLE_USER}='test/test'; my $dsn = "dbi:Oracle:$ENV{ORACLE_SID}"; my $user = $ENV{AS_ORACLE_USER}; my $pass = $ENV{AS_ORACLE_PASS}; { my $dbh = DBI->connect($dsn, $user, $pass, {RaiseError => 1, AutoCommit => 1, PrintError=>0, }); foreach my $table (qw/sessions_perl/) { eval { $dbh->do("DROP TABLE $table", {RaiseError => 0, PrintError=>0, });}; $dbh->do(<<"EOT"); CREATE TABLE $table ( id varchar2(32) not null primary key, a_session long ) EOT } } tie %{$session}, $package, undef, { DataSource => $dsn, UserName => $user, Password => $pass, Commit => 1, TableName => 'sessions_perl', }; ok tied(%{$session}), 'session tied'; ok exists($session->{_session_id}), 'session id exists'; my $id = $session->{_session_id}; my $foo = $session->{foo} = 'bar'; my $baz = $session->{baz} = ['tom', 'dick', 'harry']; untie %{$session}; undef $session; $session = {}; tie %{$session}, $package, $id, { DataSource => $dsn, UserName => $user, Password => $pass, Commit => 1, TableName => 'sessions_perl', }; ok tied(%{$session}), 'session tied'; is $session->{_session_id}, $id, 'id retrieved matches one stored'; cmp_deeply $session->{foo}, $foo, "Foo matches"; cmp_deeply $session->{baz}, $baz, "Baz matches"; $session->{long} = 'A'x(10*2**10); untie %{$session}; undef $session; $session = {}; my $dbh = DBI->connect($dsn, $user, $pass, {RaiseError => 1, AutoCommit => 0}); tie %{$session}, $package, $id, { Handle => $dbh, Commit => 0, LongReadLen => 20*2**10, TableName => 'sessions_perl', }; ok tied(%{$session}), 'session tied'; is $session->{long}, 'A'x(10*2**10), 'long read worked'; delete $session->{long}; untie %{$session}; undef $session; $session = {}; tie %{$session}, $package, $id, { Handle => $dbh, Commit => 0, TableName => 'sessions_perl', }; ok tied(%{$session}), 'session tied'; is $session->{_session_id}, $id, 'id retrieved matches one stored'; cmp_deeply $session->{foo}, $foo, "Foo matches"; cmp_deeply $session->{baz}, $baz, "Baz matches"; tied(%{$session})->delete; untie %{$session}; $dbh->commit; $dbh->disconnect; Apache-Session-1.94/t/99postgres.t000444000000000000 510512066156146 17425 0ustar00unknownunknown000000000000 use Test::More; use Test::Deep; plan skip_all => "Not running RDBM tests without APACHE_SESSION_MAINTAINER=1" unless ($ENV{APACHE_SESSION_MAINTAINER} || $ENV{TRAVIS}); plan skip_all => "Optional modules (DBD::Pg, DBI) not installed" unless eval { require DBD::Pg; require DBI; }; plan tests => 13; my $package = 'Apache::Session::Postgres'; use_ok $package; my $session = {}; my ($dbname, $user, $pass) = ('test', 'postgres', ''); my $dsn = "dbi:Pg:database=$dbname"; { my $dbh1 = DBI->connect($dsn, $user, $pass, {RaiseError => 1, AutoCommit => 1, PrintError=>0, PrintWarn=>0,}); foreach my $table (qw/sessions s/) { eval { $dbh1->do("DROP TABLE $table", {RaiseError => 0, PrintError=>0, PrintWarn=>0,});}; $dbh1->do(<<"EOT"); CREATE TABLE $table ( id char(32) not null primary key, a_session text ) EOT } } tie %{$session}, $package, undef, { DataSource => "dbi:Pg:dbname=$dbname", UserName => $user, Password => $pass, Commit => 1 }; ok tied(%{$session}), 'session tied'; ok exists($session->{_session_id}), 'session id exists'; my $id = $session->{_session_id}; my $foo = $session->{foo} = 'bar'; my $baz = $session->{baz} = ['tom', 'dick', 'harry']; untie %{$session}; undef $session; $session = {}; tie %{$session}, $package, $id, { DataSource => "dbi:Pg:dbname=$dbname", UserName => $user, Password => $pass, Commit => 1 }; ok tied(%{$session}), 'session tied'; is $session->{_session_id}, $id, 'id retrieved matches one stored'; cmp_deeply $session->{foo}, $foo, "Foo matches"; cmp_deeply $session->{baz}, $baz, "Baz matches"; untie %{$session}; undef $session; $session = {}; tie %{$session}, $package, undef, { DataSource => "dbi:Pg:dbname=$dbname", UserName => $user, Password => $pass, Commit => 1, TableName => 's' }; ok tied(%{$session}), 'session tied'; ok exists($session->{_session_id}), 'session id exists'; untie %{$session}; undef $session; $session = {}; my $dbh = DBI->connect("dbi:Pg:dbname=$dbname", $user, $pass, {RaiseError => 1, AutoCommit => 0}); tie %{$session}, $package, $id, { Handle => $dbh, Commit => 0, }; ok tied(%{$session}), 'session tied'; is $session->{_session_id}, $id, 'id retrieved matches one stored'; cmp_deeply $session->{foo}, $foo, "Foo matches"; cmp_deeply $session->{baz}, $baz, "Baz matches"; tied(%{$session})->delete; untie %{$session}; $dbh->commit; $dbh->disconnect; Apache-Session-1.94/t/99semaphore.t000444000000000000 514211254001142 17522 0ustar00unknownunknown000000000000use strict; use Test::More; #use Test::Exception; use File::Temp qw[tempdir]; #use Cwd qw[getcwd]; use Config; BEGIN { plan skip_all => "semget not implemented" unless $Config{d_semget}; #Darwin may not have semaphores, see #http://sysnet.ucsd.edu/~bellardo/darwin/sysvsem.html plan skip_all => "semctl not implemented" unless $Config{d_semctl}; plan skip_all => "Can't tune this test. Help needed."; plan skip_all => "Optional modules (IPC::SysV, IPC::Semaphore) not installed" unless eval { require IPC::SysV; require IPC::Semaphore; }; plan skip_all => "Cygserver is not running" if $^O eq 'cygwin' && (!exists $ENV{'CYGWIN'} || $ENV{'CYGWIN'} !~ /server/i); } plan tests => 33; my $package = 'Apache::Session::Lock::Semaphore'; use_ok $package; #my $origdir = getcwd; #my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); #chdir( $tempdir ); use IPC::SysV qw(IPC_CREAT S_IRWXU SEM_UNDO); use IPC::Semaphore; diag("IPC::Semaphore version $IPC::Semaphore::VERSION"); my $semkey = int(rand(2**15-1)); my $session = { data => {_session_id => 'foo'}, args => {SemaphoreKey => $semkey} }; my $number = 1; for my $iter (2,4,6,8) { $session->{args}->{NSems} = $iter; my $locker = $package->new($session); isa_ok $locker, $package; $locker->acquire_read_lock($session); my $semnum = $locker->{read_sem}; ok(defined($semnum),'$locker->{read_sem} is defined'); my $sem = IPC::Semaphore->new($semkey, $number++, S_IRWXU); diag("NSems: $iter, error: $!") unless defined($sem); isa_ok $sem, 'IPC::Semaphore'; my @sems = $sem->getall; ok $sems[$semnum] == 1 && $sems[$semnum+$iter/2] == 0, 'the semaphores seem right'; $locker->acquire_write_lock($session); @sems = $sem->getall; ok $sems[$semnum] == 0 && $sems[$semnum+$iter/2] == 1, 'semaphores seem right again'; $locker->release_write_lock($session); @sems = $sem->getall; ok $sems[$semnum] == 0 && $sems[$semnum+$iter/2] == 0, 'the semaphores seem right x3'; $locker->acquire_write_lock($session); $locker->release_all_locks($session); @sems = $sem->getall; ok $sems[$semnum] == 0 && $sems[$semnum+$iter/2] == 0, 'the semaphores seem right x4'; $locker->acquire_read_lock($session); $locker->release_all_locks($session); @sems = $sem->getall; ok $sems[$semnum] == 0 && $sems[$semnum+$iter/2] == 0, 'the semaphores seem right x5'; $sem->remove; } #chdir( $origdir ); Apache-Session-1.94/t/99storable.t000444000000000000 166711254001142 17362 0ustar00unknownunknown000000000000use Test::More; use Test::Deep; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; #plan skip_all => "Optional module (Storable) not installed" # unless eval { # require Storable; # }; plan tests => 2; my $package = 'Apache::Session::Serialize::Storable'; use_ok $package; my $origdir = getcwd; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); chdir( $tempdir ); my $serial = \&Apache::Session::Serialize::Storable::serialize; my $unserial = \&Apache::Session::Serialize::Storable::unserialize; my $session = { serialized => undef, data => undef, }; my $simple = { foo => 1, bar => 2, baz => 'quux', quux => ['foo', 'bar'], }; $session->{data} = $simple; &$serial($session); $session->{data} = undef; &$unserial($session); cmp_deeply($simple, $session->{data}, 'session data is correct'); chdir( $origdir ); Apache-Session-1.94/t/99uue.t000444000000000000 166311254001142 16341 0ustar00unknownunknown000000000000use Test::More; use Test::Deep; use Test::Exception; use File::Temp qw[tempdir]; use Cwd qw[getcwd]; #plan skip_all => "Optional module (Storable) not installed" # unless eval { # require Storable; # }; plan tests => 2; my $package = 'Apache::Session::Serialize::UUEncode'; use_ok $package; my $origdir = getcwd; my $tempdir = tempdir( DIR => '.', CLEANUP => 1 ); chdir( $tempdir ); my $serial = \&Apache::Session::Serialize::UUEncode::serialize; my $unserial = \&Apache::Session::Serialize::UUEncode::unserialize; my $session = { serialized => undef, data => undef, }; my $simple = { foo => 1, bar => 2, baz => 'quux', quux => ['foo', 'bar'], }; $session->{data} = $simple; &$serial($session); $session->{data} = undef; &$unserial($session); cmp_deeply($simple, $session->{data}, 'session data is correct'); chdir( $origdir ); Apache-Session-1.94/t/pod.t000444000000000000 22211254001142 16111 0ustar00unknownunknown000000000000#!perl -T use Test::More; eval "use Test::Pod 1.14"; plan skip_all => "Test::Pod 1.14 required for testing POD" if $@; all_pod_files_ok();