@@ -25,12 +25,16 @@ my %args = (
name => 'Furl',
module_name => 'Furl',
- allow_pure_perl => 0,
+ allow_pureperl => 0,
script_files => [glob('script/*'), glob('bin/*')],
+ c_source => [qw()],
+ PL_files => {},
test_files => ((-d '.git' || $ENV{RELEASE_TESTING}) && -d 'xt') ? 't/ xt/' : 't/',
recursive_test_files => 1,
+
+
);
if (-d 'share') {
$args{share_dir} = 'share';
@@ -1,5 +1,14 @@
Revision history for Perl module Furl
+3.02 2014-03-18T20:52:07Z
+
+ - Added new experimental cookie_jar support.
+ (tokuhirom)
+
+3.01 2014-02-13T06:19:47Z
+
+ - Fixed documentation bug(Reported by Yappo++)
+
3.00 2013-11-13T09:39:38Z
- implement inactivity_timeout (for read / write), requested by autarch++
@@ -58,6 +58,7 @@ t/300_high/02_agent.t
t/300_high/04_http_request.t
t/300_high/05_suppress_dup_host_header.t
t/300_high/06_keep_request.t
+t/300_high/07_cookie.t
t/300_high/99_error.t
t/400_components/001_response-coding/01-file.t
t/400_components/001_response-coding/t-euc-jp.html
@@ -4,8 +4,10 @@
"Tokuhiro Matsuno <tokuhirom@gmail.com>"
],
"dynamic_config" : 0,
- "generated_by" : "Minilla/v0.4.2",
- "license" : "perl_5",
+ "generated_by" : "Minilla/v0.12.0",
+ "license" : [
+ "perl_5"
+ ],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : "2"
@@ -19,7 +21,8 @@
"share",
"eg",
"examples",
- "author"
+ "author",
+ "builder"
]
},
"prereqs" : {
@@ -35,18 +38,22 @@
"Test::CPAN::Meta" : "0",
"Test::MinimumVersion" : "0.10108",
"Test::Pod" : "1.41",
- "Test::Spellunker" : "v0.2.2"
+ "Test::Spellunker" : "v0.2.7"
},
"suggests" : {
"Child" : "0",
"Getopt::Long" : "0",
"HTTP::Lite" : "0",
+ "IO::Callback" : "0",
"LWP::UserAgent" : "0",
+ "Net::DNS::Lite" : "0",
+ "Net::IDN::Encode" : "0",
"Plack::Loader" : "0",
"Starman" : "0",
+ "Test::LeakTrace" : "0",
"Test::More" : "0",
+ "Test::Requires" : "0",
"Test::TCP" : "0",
- "Test::suggests" : "0",
"URI" : "0",
"WWW::Curl::Easy" : "4.14",
"autodie" : "0",
@@ -56,6 +63,7 @@
"runtime" : {
"recommends" : {
"Compress::Raw::Zlib" : "0",
+ "HTTP::CookieJar" : "0",
"IO::Socket::SSL" : "0",
"Net::IDN::Encode" : "0"
},
@@ -84,6 +92,7 @@
"Test::TCP" : "1.06"
},
"suggests" : {
+ "HTTP::CookieJar" : "0",
"HTTP::Proxy" : "0",
"HTTP::Server::PSGI" : "0",
"Plack" : "0",
@@ -101,14 +110,14 @@
"provides" : {
"Furl" : {
"file" : "lib/Furl.pm",
- "version" : "3.00"
+ "version" : "3.02"
},
"Furl::ConnectionCache" : {
"file" : "lib/Furl/ConnectionCache.pm"
},
"Furl::HTTP" : {
"file" : "lib/Furl/HTTP.pm",
- "version" : "3.00"
+ "version" : "3.02"
},
"Furl::Headers" : {
"file" : "lib/Furl/Headers.pm"
@@ -134,7 +143,7 @@
"web" : "https://github.com/tokuhirom/Furl"
}
},
- "version" : "3.00",
+ "version" : "3.02",
"x_contributors" : [
"Keiji, Yoshimi <walf443@gmail.com>",
"Fuji, Goro <gfuji@cpan.org>",
@@ -3,20 +3,20 @@ abstract: 'Lightning-fast URL fetcher'
author:
- 'Tokuhiro Matsuno <tokuhirom@gmail.com>'
build_requires:
- File::Temp: 0
- Test::More: 0.96
- Test::Requires: 0
- Test::TCP: 1.06
+ File::Temp: '0'
+ Test::More: '0.96'
+ Test::Requires: '0'
+ Test::TCP: '1.06'
configure_requires:
- CPAN::Meta: 0
- CPAN::Meta::Prereqs: 0
- Module::Build: 0.38
+ CPAN::Meta: '0'
+ CPAN::Meta::Prereqs: '0'
+ Module::Build: '0.38'
dynamic_config: 0
-generated_by: 'Minilla/v0.4.2, CPAN::Meta::Converter version 2.120921'
+generated_by: 'Minilla/v0.12.0, CPAN::Meta::Converter version 2.133380'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
- version: 1.4
+ version: '1.4'
name: Furl
no_index:
directory:
@@ -27,47 +27,44 @@ no_index:
- eg
- examples
- author
+ - builder
provides:
Furl:
file: lib/Furl.pm
- version: 3.00
+ version: '3.02'
Furl::ConnectionCache:
file: lib/Furl/ConnectionCache.pm
- version: 0
Furl::HTTP:
file: lib/Furl/HTTP.pm
- version: 3.00
+ version: '3.02'
Furl::Headers:
file: lib/Furl/Headers.pm
- version: 0
Furl::Request:
file: lib/Furl/Request.pm
- version: 0
Furl::Response:
file: lib/Furl/Response.pm
- version: 0
Furl::ZlibStream:
file: lib/Furl/ZlibStream.pm
- version: 0
recommends:
- Compress::Raw::Zlib: 0
- IO::Socket::SSL: 0
- Net::IDN::Encode: 0
+ Compress::Raw::Zlib: '0'
+ HTTP::CookieJar: '0'
+ IO::Socket::SSL: '0'
+ Net::IDN::Encode: '0'
requires:
- Class::Accessor::Lite: 0
- Encode: 0
- HTTP::Parser::XS: 0.11
- MIME::Base64: 0
- Mozilla::CA: 0
- Scalar::Util: 0
- Socket: 0
- Time::HiRes: 0
- perl: 5.008001
+ Class::Accessor::Lite: '0'
+ Encode: '0'
+ HTTP::Parser::XS: '0.11'
+ MIME::Base64: '0'
+ Mozilla::CA: '0'
+ Scalar::Util: '0'
+ Socket: '0'
+ Time::HiRes: '0'
+ perl: '5.008001'
resources:
bugtracker: https://github.com/tokuhirom/Furl/issues
homepage: https://github.com/tokuhirom/Furl
repository: git://github.com/tokuhirom/Furl.git
-version: 3.00
+version: '3.02'
x_contributors:
- 'Keiji, Yoshimi <walf443@gmail.com>'
- 'Fuji, Goro <gfuji@cpan.org>'
@@ -48,18 +48,23 @@ _%args_ might be:
- max\_redirects :Int = 7
- capture\_request :Bool = false
- If this parameter is true, [Furl::HTTP](http://search.cpan.org/perldoc?Furl::HTTP) captures raw request string.
+ If this parameter is true, [Furl::HTTP](https://metacpan.org/pod/Furl::HTTP) captures raw request string.
You can get it by `$res->captured_req_headers` and `$res->captured_req_content`.
- proxy :Str
- no\_proxy :Str
- headers :ArrayRef
+- cookie\_jar :Object
+
+ (EXPERIMENTAL)
+
+ An instance of HTTP::CookieJar or equivalent class that supports the add and cookie\_header methods
## Instance Methods
### `$furl->request([$request,] %args) :Furl::Response`
-Sends an HTTP request to a specified URL and returns a instance of [Furl::Response](http://search.cpan.org/perldoc?Furl::Response).
+Sends an HTTP request to a specified URL and returns a instance of [Furl::Response](https://metacpan.org/pod/Furl::Response).
_%args_ might be:
@@ -154,12 +159,12 @@ Loads proxy settings from `$ENV{HTTP_PROXY}` and `$ENV{NO_PROXY}`.
- I need more speed.
- See [Furl::HTTP](http://search.cpan.org/perldoc?Furl::HTTP), which provides the low level interface of [Furl](http://search.cpan.org/perldoc?Furl).
- It is faster than `Furl.pm` since [Furl::HTTP](http://search.cpan.org/perldoc?Furl::HTTP) does not create response objects.
+ See [Furl::HTTP](https://metacpan.org/pod/Furl::HTTP), which provides the low level interface of [Furl](https://metacpan.org/pod/Furl).
+ It is faster than `Furl.pm` since [Furl::HTTP](https://metacpan.org/pod/Furl::HTTP) does not create response objects.
- How do you use cookie\_jar?
- Furl does not directly support the cookie\_jar option available in LWP. You can use [HTTP::Cookies](http://search.cpan.org/perldoc?HTTP::Cookies), [HTTP::Request](http://search.cpan.org/perldoc?HTTP::Request), [HTTP::Response](http://search.cpan.org/perldoc?HTTP::Response) like following.
+ Furl does not directly support the cookie\_jar option available in LWP. You can use [HTTP::Cookies](https://metacpan.org/pod/HTTP::Cookies), [HTTP::Request](https://metacpan.org/pod/HTTP::Request), [HTTP::Response](https://metacpan.org/pod/HTTP::Response) like following.
my $f = Furl->new();
my $cookies = HTTP::Cookies->new();
@@ -224,6 +229,7 @@ Loads proxy settings from `$ENV{HTTP_PROXY}` and `$ENV{NO_PROXY}`.
if $received_size >= $next_update;
}
);
+
- HTTPS requests claims warnings!
When you make https requests, IO::Socket::SSL may complain about it like:
@@ -247,7 +253,7 @@ Loads proxy settings from `$ENV{HTTP_PROXY}` and `$ENV{NO_PROXY}`.
},
});
- See [IO::Socket::SSL](http://search.cpan.org/perldoc?IO::Socket::SSL) for details.
+ See [IO::Socket::SSL](https://metacpan.org/pod/IO::Socket::SSL) for details.
# AUTHOR
@@ -273,13 +279,13 @@ audreyt
# SEE ALSO
-[LWP](http://search.cpan.org/perldoc?LWP)
+[LWP](https://metacpan.org/pod/LWP)
-[IO::Socket::SSL](http://search.cpan.org/perldoc?IO::Socket::SSL)
+[IO::Socket::SSL](https://metacpan.org/pod/IO::Socket::SSL)
-[Furl::HTTP](http://search.cpan.org/perldoc?Furl::HTTP)
+[Furl::HTTP](https://metacpan.org/pod/Furl::HTTP)
-[Furl::Response](http://search.cpan.org/perldoc?Furl::Response)
+[Furl::Response](https://metacpan.org/pod/Furl::Response)
# LICENSE
@@ -16,6 +16,7 @@ suggests 'HTTP::Response'; # Furl::Response
recommends 'Net::IDN::Encode'; # for International Domain Name
recommends 'IO::Socket::SSL'; # for SSL
recommends 'Compress::Raw::Zlib'; # for Content-Encoding
+recommends 'HTTP::CookieJar';
on test => sub {
requires 'Test::More' => 0.96; # done_testing, subtest
@@ -33,6 +34,7 @@ on test => sub {
suggests 'parent';
suggests 'Plack';
suggests 'Test::Valgrind';
+ suggests 'HTTP::CookieJar';
};
on develop => sub {
@@ -43,11 +45,15 @@ on develop => sub {
suggests 'Plack::Loader';
suggests 'Starman';
suggests 'Test::More';
- suggests 'Test::suggests';
+ suggests 'Test::Requires';
suggests 'Test::TCP';
suggests 'URI';
suggests 'WWW::Curl::Easy', '4.14';
+ suggests 'IO::Callback';
suggests 'autodie';
suggests 'parent';
+ suggests 'Net::IDN::Encode';
+ suggests 'Test::LeakTrace';
+ suggests 'Net::DNS::Lite';
};
@@ -4,7 +4,7 @@ use warnings;
use base qw/Exporter/;
use 5.008001;
-our $VERSION = '3.00';
+our $VERSION = '3.02';
use Carp ();
use Furl::ConnectionCache;
@@ -564,7 +564,7 @@ sub request {
return (
$res_minor_version, $res_status, $res_msg, $res_headers, $res_content,
- $req_headers, $req_content,
+ $req_headers, $req_content, undef, undef, [$scheme, $username, $password, $host, $port, $path_query],
);
}
@@ -1297,7 +1297,7 @@ The example below sends all requests to 127.0.0.1:8080.
my $ua = Furl::HTTP->new(
get_address => sub {
my ($host, $port, $timeout) = @_;
- sockaddr_in(8080, inet_aton("127.0.0.1"));
+ pack_sockaddr_in(8080, inet_aton("127.0.0.1"));
},
);
@@ -6,7 +6,7 @@ use Furl::HTTP;
use Furl::Request;
use Furl::Response;
use Carp ();
-our $VERSION = '3.00';
+our $VERSION = '3.02';
use 5.008001;
@@ -100,6 +100,25 @@ sub request {
$args{headers} = $headers;
}
+ my $cookie_jar = ${$self}->{cookie_jar};
+
+ if ($cookie_jar) {
+ my $url;
+ if ($args{url}) {
+ $url = $args{url};
+ } else {
+ $url = join(
+ '',
+ $args{scheme},
+ '://',
+ $args{host},
+ (exists($args{port}) ? ":$args{port}" : ()),
+ exists($args{path_query}) ? $args{path_query} : '/',
+ );
+ }
+ push @{$args{headers}}, 'Cookie' => $cookie_jar->cookie_header($url);
+ }
+
my (
$res_minor_version,
$res_status,
@@ -107,10 +126,30 @@ sub request {
$res_headers,
$res_content,
$captured_req_headers,
- $captured_req_content ) = ${$self}->request(%args);
+ $captured_req_content,
+ $captured_res_headers,
+ $captured_res_content,
+ $request_info,
+ ) = ${$self}->request(%args);
my $res = Furl::Response->new($res_minor_version, $res_status, $res_msg, $res_headers, $res_content);
$res->set_request_info(\%args, $captured_req_headers, $captured_req_content);
+
+ if ($cookie_jar) {
+ my ($scheme, $username, $password, $host, $port, $path_query) = @$request_info;
+ my $req_url = join(
+ '',
+ $scheme,
+ '://',
+ (defined($username) && defined($password) ? "${username}:${password}@" : ()),
+ "$host:${port}${path_query}",
+ );
+ for my $cookie ($res->header('Set-Cookie')) {
+ # Do not use $args{url} as a url. Because the server may redirected.
+ $cookie_jar->add($req_url, $cookie);
+ }
+ }
+
return $res;
}
@@ -183,6 +222,12 @@ You can get it by C<< $res->captured_req_headers >> and C<< $res->captured_req_c
=item headers :ArrayRef
+=item cookie_jar :Object
+
+(EXPERIMENTAL)
+
+An instance of HTTP::CookieJar or equivalent class that supports the add and cookie_header methods
+
=back
=head2 Instance Methods
@@ -14,9 +14,19 @@ test_tcp(
my $furl = Furl::HTTP->new(capture_request => 1);
my @res = $furl->request( url => "http://127.0.0.1:$port/1", );
- my $content = pop @res;
- my $headers = pop @res;
- my $req = Furl::Request->parse($headers . $content);
+ my (
+ $res_minor_version,
+ $res_status,
+ $res_msg,
+ $res_headers,
+ $res_content,
+ $captured_req_headers,
+ $captured_req_content,
+ $captured_res_headers,
+ $captured_res_content,
+ $request_info,
+ ) = @res;
+ my $req = Furl::Request->parse($captured_req_headers . $captured_req_content);
is $req->method, 'GET';
is $req->uri, "http://127.0.0.1:$port/1";
@@ -0,0 +1,101 @@
+use strict;
+use warnings;
+use utf8;
+use Test::More;
+use Test::Requires 'HTTP::CookieJar', 'Plack::Request', 'Plack::Loader', 'Plack::Builder', 'Plack::Response';
+use Test::TCP;
+use Furl;
+
+subtest 'Simple case', sub {
+ test_tcp(
+ client => sub {
+ my $port = shift;
+ my $furl = Furl->new(
+ cookie_jar => HTTP::CookieJar->new()
+ );
+ my $url = "http://127.0.0.1:$port";
+
+ subtest 'first time access', sub {
+ my $res = $furl->get("${url}/");
+
+ note "Then, response should be 200 OK";
+ is $res->status, 200;
+ note "And, content should be 'OK 1'";
+ is $res->content, 'OK 1';
+ };
+
+ subtest 'Second time access', sub {
+ my $res = $furl->get("${url}/");
+
+ note "Then, response should be 200 OK";
+ is $res->status, 200;
+ note "And, content should be 'OK 2'";
+ is $res->content, 'OK 2';
+ };
+ },
+ server => \&session_server,
+ );
+};
+
+subtest '->request(host => ...) style simple interface', sub {
+ test_tcp(
+ client => sub {
+ my $port = shift;
+ my $furl = Furl->new(
+ cookie_jar => HTTP::CookieJar->new()
+ );
+
+ subtest 'first time access', sub {
+ my $res = $furl->request(
+ method => 'GET',
+ scheme => 'http',
+ host => '127.0.0.1',
+ port => $port,
+ );
+
+ note "Then, response should be 200 OK";
+ is $res->status, 200;
+ note "And, content should be 'OK 1'";
+ is $res->content, 'OK 1';
+ };
+
+ subtest 'Second time access', sub {
+ my $res = $furl->request(
+ method => 'GET',
+ scheme => 'http',
+ host => '127.0.0.1',
+ port => $port,
+ );
+
+ note "Then, response should be 200 OK";
+ is $res->status, 200;
+ note "And, content should be 'OK 2'";
+ is $res->content, 'OK 2';
+ };
+ },
+ server => \&session_server,
+ );
+};
+
+done_testing;
+
+sub session_server {
+ my $port = shift;
+ my %SESSION_STORE;
+ Plack::Loader->auto( port => $port )->run(builder {
+ enable 'ContentLength';
+
+ sub {
+ my $env = shift;
+ my $req = Plack::Request->new($env);
+ my $session_key = $req->cookies->{session_key} || rand();
+ my $cnt = ++$SESSION_STORE{$session_key};
+ note "CNT: $cnt";
+ my $res = Plack::Response->new(
+ 200, [], ["OK ${cnt}"]
+ );
+ $res->cookies->{'session_key'} = $session_key;
+ return $res->finalize;
+ };
+ });
+}