Commit 7d5694cf authored by Alessandro Ghedini's avatar Alessandro Ghedini

Imported Upstream version 0.018

parent ce0b9ab8
Release notes for HTTP-Tiny
0.018 2012-04-18 09:39:50 America/New_York
- Add verify_SSL option to do more secure SSL operations, incl.
attempting to validate against a CA bundle (Mozilla::CA
recommended, but will attempt to find some OS bundles). Also
add SSL_opts, which passes through IO::Socket::SSL's SSL_*
options to control SSL verification. (GH #6, #9) [Mike Doherty]
[ADDED]
- Reponse hashref includes final URL (including any redirections)
[Lukas Eklund]
0.017 2012-02-22 21:57:37 EST5EDT
[DOCUMENTATION]
......
......@@ -32,6 +32,7 @@ t/130_redirect.t
t/140_proxy.t
t/150_post_form.t
t/200_live.t
t/210_live_ssl.t
t/Util.pm
t/cases/delete-01.txt
t/cases/form-01.txt
......
......@@ -2,10 +2,11 @@
"abstract" : "A small, simple, correct HTTP/1.1 client",
"author" : [
"Christian Hansen <chansen@cpan.org>",
"David Golden <dagolden@cpan.org>"
"David Golden <dagolden@cpan.org>",
"Mike Doherty <doherty@cpan.org>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 4.300009, CPAN::Meta::Converter version 2.120351",
"generated_by" : "Dist::Zilla version 4.300009, CPAN::Meta::Converter version 2.120630",
"license" : [
"perl_5"
],
......@@ -40,6 +41,10 @@
"perl" : "5.006",
"strict" : "0",
"warnings" : "0"
},
"suggests" : {
"IO::Socket::SSL" : "0",
"Mozilla::CA" : "0"
}
},
"test" : {
......@@ -61,7 +66,7 @@
"provides" : {
"HTTP::Tiny" : {
"file" : "lib/HTTP/Tiny.pm",
"version" : "0.017"
"version" : "0.018"
}
},
"release_status" : "stable",
......@@ -77,6 +82,6 @@
"web" : "https://github.com/dagolden/p5-http-tiny"
}
},
"version" : "0.017"
"version" : "0.018"
}
......@@ -3,6 +3,7 @@ abstract: 'A small, simple, correct HTTP/1.1 client'
author:
- 'Christian Hansen <chansen@cpan.org>'
- 'David Golden <dagolden@cpan.org>'
- 'Mike Doherty <doherty@cpan.org>'
build_requires:
Data::Dumper: 0
Exporter: 0
......@@ -18,7 +19,7 @@ build_requires:
configure_requires:
ExtUtils::MakeMaker: 6.30
dynamic_config: 0
generated_by: 'Dist::Zilla version 4.300009, CPAN::Meta::Converter version 2.120351'
generated_by: 'Dist::Zilla version 4.300009, CPAN::Meta::Converter version 2.120630'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
......@@ -35,7 +36,7 @@ no_index:
provides:
HTTP::Tiny:
file: lib/HTTP/Tiny.pm
version: 0.017
version: 0.018
requires:
Carp: 0
IO::Socket: 0
......@@ -48,4 +49,4 @@ resources:
bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=HTTP-Tiny
homepage: https://github.com/dagolden/p5-http-tiny
repository: https://github.com/dagolden/p5-http-tiny.git
version: 0.017
version: 0.018
......@@ -10,7 +10,7 @@ use ExtUtils::MakeMaker 6.30;
my %WriteMakefileArgs = (
"ABSTRACT" => "A small, simple, correct HTTP/1.1 client",
"AUTHOR" => "Christian Hansen <chansen\@cpan.org>, David Golden <dagolden\@cpan.org>",
"AUTHOR" => "Christian Hansen <chansen\@cpan.org>, David Golden <dagolden\@cpan.org>, Mike Doherty <doherty\@cpan.org>",
"BUILD_REQUIRES" => {
"Data::Dumper" => 0,
"Exporter" => 0,
......@@ -39,7 +39,7 @@ my %WriteMakefileArgs = (
"strict" => 0,
"warnings" => 0
},
"VERSION" => "0.017",
"VERSION" => "0.018",
"test" => {
"TESTS" => "t/*.t"
}
......
......@@ -2,7 +2,7 @@ NAME
HTTP::Tiny - A small, simple, correct HTTP/1.1 client
VERSION
version 0.017
version 0.018
SYNOPSIS
use HTTP::Tiny;
......@@ -61,10 +61,22 @@ METHODS
Request timeout in seconds (default is 60)
* "verify_SSL"
A boolean that indicates whether to validate the SSL certificate of
an "https" connection (default is false)
* "SSL_options"
A hashref of "SSL_*" options to pass through to IO::Socket::SSL
Exceptions from "max_size", "timeout" or other errors will result in a
pseudo-HTTP status code of 599 and a reason of "Internal Exception". The
content field in the response will contain the text of the exception.
See "SSL SUPPORT" for more on the "verify_SSL" and "SSL_options"
attributes.
get|head|put|post|delete
$response = $http->get($url);
$response = $http->get($url, \%options);
......@@ -126,25 +138,25 @@ METHODS
Valid options are:
* headers
* "headers"
A hashref containing headers to include with the request. If the
value for a header is an array reference, the header will be output
multiple times with each value in the array. These headers
over-write any default headers.
* content
* "content"
A scalar to include as the body of the request OR a code reference
that will be called iteratively to produce the body of the response
that will be called iteratively to produce the body of the request
* trailer_callback
* "trailer_callback"
A code reference that will be called if it exists to provide a
hashref of trailing headers (only used with chunked
transfer-encoding)
* data_callback
* "data_callback"
A code reference that will be called for each chunks of the response
body received.
......@@ -163,25 +175,31 @@ METHODS
The "request" method returns a hashref containing the response. The
hashref will have the following keys:
* success
* "success"
Boolean indicating whether the operation returned a 2XX status code
* status
* "url"
URL that provided the response. This is the URL of the request
unless there were redirections, in which case it is the last URL
queried in a redirection chain
* "status"
The HTTP status code of the response
* reason
* "reason"
The response phrase returned by the server
* content
* "content"
The body of the response. If the response does not have any content
or if a data callback is provided to consume the response body, this
will be the empty string
* headers
* "headers"
A hashref of header fields. All header field names will be
normalized to be lower case. If a header is repeated, the value will
......@@ -203,6 +221,72 @@ METHODS
the values of the array reference. The key/value pairs in the resulting
string will be sorted by key and value.
SSL SUPPORT
Direct "https" connections are supported only if IO::Socket::SSL is
installed. An exception will be thrown if IO::Socket::SSL is not
installed or if the SSL encryption fails. There is no support for
"https" connections via proxy.
SSL provides two distinct capabilities:
* Encrypted communication channel
* Verification of server identity
By default, HTTP::Tiny does not verify server identity.
Server identity verification is controversial and potentially tricky
because it depends on a (usually paid) third-party Certificate Authority
(CA) trust model to validate a certificate as legitimate. This
discriminates against servers with self-signed certificates or
certificates signed by free, community-driven CA's such as CAcert.org
<http://cacert.org>.
By default, HTTP::Tiny does not make any assumptions about your trust
model, threat level or risk tolerance. It just aims to give you an
encrypted channel when you need one.
Setting the "verify_SSL" attribute to a true value will make HTTP::Tiny
verify that an SSL connection has a valid SSL certificate corresponding
to the host name of the connection and that the SSL certificate has been
verified by a CA. Assuming you trust the CA, this will protect against a
man-in-the-middle attack
<http://en.wikipedia.org/wiki/Man-in-the-middle_attack>. If you are
concerned about security, you should enable this option.
Certificate verification requires a file containing trusted CA
certificates. If the Mozilla::CA module is installed, HTTP::Tiny will
use the CA file included with it as a source of trusted CA's. (This
means you trust Mozilla, the author of Mozilla::CA, the CPAN mirror
where you got Mozilla::CA, the toolchain used to install it, and your
operating system security, right?)
If that module is not available, then HTTP::Tiny will search several
system-specific default locations for a CA certificate file:
* /etc/ssl/certs/ca-certificates.crt
* /etc/pki/tls/certs/ca-bundle.crt
* /etc/ssl/ca-bundle.pem
An exception will be raised if "verify_SSL" is true and no CA
certificate file is available.
If you desire complete control over SSL connections, the "SSL_options"
attribute lets you provide a hash reference that will be passed through
to "IO::Socket::SSL::start_SSL()", overriding any options set by
HTTP::Tiny. For example, to provide your own trusted CA file:
SSL_options => {
SSL_ca_file => $file_path,
}
The "SSL_options" attribute could also be used for such things as
providing a client certificate for authentication to a server or
controlling the choice of cipher used for the SSL connection. See
IO::Socket::SSL documentation for details.
LIMITATIONS
HTTP::Tiny is *conditionally compliant* with the HTTP/1.1 specification
<http://www.w3.org/Protocols/rfc2616/rfc2616.html>. It attempts to meet
......@@ -228,11 +312,6 @@ LIMITATIONS
* Persistent connections are not supported. The "Connection" header
will always be set to "close".
* Direct "https" connections are supported only if IO::Socket::SSL is
installed. There is no support for "https" connections via proxy.
Any SSL certificate that matches the host is accepted -- SSL
certificates are not verified against certificate authorities.
* Cookies are not directly supported. Users that set a "Cookie" header
should also set "max_redirect" to zero to ensure cookies are not
inappropriately re-transmitted.
......@@ -254,6 +333,10 @@ LIMITATIONS
SEE ALSO
* LWP::UserAgent
* IO::Socket::SSL
* Mozilla::CA
SUPPORT
Bugs / Feature Requests
Please report any bugs or feature requests through the issue tracker at
......@@ -273,6 +356,8 @@ AUTHORS
* David Golden <dagolden@cpan.org>
* Mike Doherty <doherty@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2012 by Christian Hansen.
......
name = HTTP-Tiny
author = Christian Hansen <chansen@cpan.org>
author = David Golden <dagolden@cpan.org>
author = Mike Doherty <doherty@cpan.org>
license = Perl_5
copyright_holder = Christian Hansen
......@@ -10,7 +11,14 @@ stopwords = SSL
stopwords = chunked
stopwords = redirections
stopwords = timestamp
stopwords = CA's
stopwords = CAcert
[RemovePrereqs]
remove = Errno
remove = IO::Socket::SSL
remove = Mozilla::CA
[Prereqs/Suggests]
IO::Socket::SSL = 0
Mozilla::CA = 0
This diff is collapsed.
......@@ -6,7 +6,9 @@ use warnings;
use Test::More tests => 2;
use HTTP::Tiny;
my @accessors = qw(agent default_headers max_redirect max_size proxy timeout);
my @accessors = qw(
agent default_headers max_redirect max_size proxy timeout SSL_options verify_SSL
);
my @methods = qw(
new get head put post delete post_form request mirror www_form_urlencode
);
......@@ -25,4 +27,3 @@ my @extra =
ok( ! scalar @extra, "No unexpected subroutines defined" )
or diag "Found: @extra";
......@@ -75,6 +75,8 @@ for my $file ( dir_list("t/cases", qr/^get/ ) ) {
ok( ! $response->{success}, "$label success flag false" );
}
is ( $response->{url}, $url, "$label response URL" );
if (defined $case->{expected_headers}) {
my %expected = hashify( $case->{expected_headers} );
is_deeply($response->{headers}, \%expected, "$label expected headers");
......@@ -93,6 +95,8 @@ for my $file ( dir_list("t/cases", qr/^get/ ) ) {
}
;
if ( $options{data_callback} ) {
$check_expected->( $main::data, "$label cb got content" );
is ( $response->{content}, '', "$label resp content empty" );
......
......@@ -65,6 +65,11 @@ for my $file ( dir_list("t/cases", qr/^redirect/ ) ) {
? join("$CRLF", @{$case->{expected}}) : '';
is ( $response->{content}, $exp_content, "$label content" );
if ( $case->{expected_url} ) {
is ( $response->{url}, $case->{expected_url}[0], "$label response URL" );
}
}
done_testing;
#!perl
use strict;
use warnings;
use Test::More 0.88;
use IO::Socket::INET;
BEGIN {
eval 'use IO::Socket::SSL; 1';
plan skip_all => 'IO::Socket::SSL required for SSL tests' if $@;
# $IO::Socket::SSL::DEBUG = 3;
eval 'use Mozilla::CA; 1';
plan skip_all => 'Mozilla::CA required for SSL tests' if $@;
}
use HTTP::Tiny;
plan skip_all => 'Only run for $ENV{AUTOMATED_TESTING}'
unless $ENV{AUTOMATED_TESTING};
my $data = {
'https://www.google.ca/' => {
host => 'www.google.ca',
pass => { SSL_verifycn_scheme => 'http', SSL_verifycn_name => 'www.google.ca', SSL_verify_mode => 0x01, SSL_ca_file => Mozilla::CA::SSL_ca_file() },
fail => { SSL_verify_callback => sub { 0 }, SSL_verify_mode => 0x01 },
default_should_yield => '1',
},
'https://twitter.com/' => {
host => 'twitter.com',
pass => { SSL_verifycn_scheme => 'http', SSL_verifycn_name => 'twitter.com', SSL_verify_mode => 0x01, SSL_ca_file => Mozilla::CA::SSL_ca_file() },
fail => { SSL_verify_callback => sub { 0 }, SSL_verify_mode => 0x01 },
default_should_yield => '1',
},
'https://github.com/' => {
host => 'github.com',
pass => { SSL_verifycn_scheme => 'http', SSL_verifycn_name => 'github.com', SSL_verify_mode => 0x01, SSL_ca_file => Mozilla::CA::SSL_ca_file() },
fail => { SSL_verify_callback => sub { 0 }, SSL_verify_mode => 0x01 },
default_should_yield => '1',
},
'https://spinrite.com/' => {
host => 'spinrite.com',
pass => { SSL_verifycn_scheme => 'none', SSL_verifycn_name => 'spinrite.com', SSL_verify_mode => 0x00 },
fail => { SSL_verifycn_scheme => 'http', SSL_verifycn_name => 'spinrite.com', SSL_verify_mode => 0x01, SSL_ca_file => Mozilla::CA::SSL_ca_file() },
default_should_yield => '',
}
};
plan tests => scalar keys %$data;
while (my ($url, $data) = each %$data) {
subtest $url => sub {
plan 'skip_all' => 'Internet connection timed out'
unless IO::Socket::INET->new(
PeerHost => $data->{host},
PeerPort => 443,
Proto => 'tcp',
Timeout => 10,
);
# the default verification
my $response = HTTP::Tiny->new(verify_ssl => 1)->get($url);
is $response->{success}, $data->{default_should_yield}, "Request to $url passed/failed using default as expected"
or do { delete $response->{content}; diag explain [IO::Socket::SSL::errstr(), $response] };
# force validation to succeed
my $pass = HTTP::Tiny->new( SSL_options => $data->{pass} )->get($url);
isnt $pass->{status}, '599', "Request to $url completed (forced pass)"
or do { delete $pass->{content}; diag explain $pass };
ok $pass->{content}, 'Got some content';
# force validation to fail
my $fail = HTTP::Tiny->new( SSL_options => $data->{fail} )->get($url);
is $fail->{status}, '599', "Request to $url failed (forced fail)"
or do { delete $fail->{content}; diag explain [IO::Socket::SSL::errstr(), $fail] };
ok $fail->{content}, 'Got some content';
};
}
......@@ -2,6 +2,8 @@ url
http://example.com/index.html
expected
abcdefghijklmnopqrstuvwxyz1234567890abcdef
expected_url
http://example.com/index2.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -4,6 +4,8 @@ url
http://example.com/index.html
expected
<a href="http://example.com/index2.html">redirect</a>
expected_url
http://example.com/index.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -4,6 +4,8 @@ url
http://example.com/index.html
expected
<a href="http://example.com/index3.html">redirect</a>
expected_url
http://example.com/index2.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -4,6 +4,8 @@ url
http://example.com/index.html
expected
abcdefghijklmnopqrstuvwxyz1234567890abcdef
expected_url
http://example.com/index3.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -2,6 +2,8 @@ url
http://example.com/index.html
expected
abcdefghijklmnopqrstuvwxyz1234567890abcdef
expected_url
http://example.com/index3.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -2,6 +2,8 @@ url
http://example.com/index.html
expected
abcdefghijklmnopqrstuvwxyz1234567890abcdef
expected_url
http://example.com/index2.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -2,6 +2,8 @@ url
http://example.com/index.html
expected
abcdefghijklmnopqrstuvwxyz1234567890abcdef
expected_url
http://example.com/index2.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -2,6 +2,8 @@ url
http://example.com/index.html
expected
<a href="http://example.com/index2.html">redirect</a>
expected_url
http://example.com/index.html
----------
GET /index.html HTTP/1.1
Host: example.com
......
......@@ -4,6 +4,8 @@ method
POST
expected
abcdefghijklmnopqrstuvwxyz1234567890abcdef
expected_url
http://example.com/index2.html
----------
POST /index.html HTTP/1.1
Host: example.com
......
#!perl
# This test is generated by Dist::Zilla::Plugin::Test::PodSpelling
use strict;
use warnings;
use Test::More;
eval "use Pod::Wordlist::hanekomu";
plan skip_all => "Pod::Wordlist::hanekomu required for testing POD spelling"
if $@;
eval "use Test::Spelling 0.12";
plan skip_all => "Test::Spelling 0.12 required for testing POD spelling"
if $@;
use Test::Requires {
'Test::Spelling' => 0.12,
'Pod::Wordlist::hanekomu' => 0,
};
add_stopwords(<DATA>);
......@@ -20,8 +16,14 @@ SSL
chunked
redirections
timestamp
CA's
CAcert
Christian
Hansen
David
Golden
Mike
Doherty
lib
HTTP
Tiny
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment