#!/usr/local/bin/perl
BEGIN
{
use
vars
qw( $DEBUG $CRLF )
;
our
$CRLF
=
"\015\012"
;
our
$DEBUG
=
exists
(
$ENV
{AUTHOR_TESTING} ) ?
$ENV
{AUTHOR_TESTING} : 0;
};
BEGIN
{
use
ok(
'HTTP::Promise::Message'
);
};
my
(
$m
,
$m2
,
@parts
,
$parts
,
$io_layer
,
$body
,
$rv
,
$decoded_content
);
$m
= HTTP::Promise::Message->new;
isa_ok(
$m
=> [
'HTTP::Promise::Message'
] );
can_ok(
$m
=>
'add_content'
);
can_ok(
$m
=>
'add_content_utf8'
);
can_ok(
$m
=>
'add_part'
);
can_ok(
$m
=>
'as_string'
);
can_ok(
$m
=>
'boundary'
);
can_ok(
$m
=>
'can'
);
can_ok(
$m
=>
'clear'
);
can_ok(
$m
=>
'clone'
);
can_ok(
$m
=>
'content'
);
can_ok(
$m
=>
'content_charset'
);
can_ok(
$m
=>
'content_ref'
);
can_ok(
$m
=>
'decodable'
);
can_ok(
$m
=>
'decode'
);
can_ok(
$m
=>
'decode_content'
);
can_ok(
$m
=>
'decoded_content'
);
can_ok(
$m
=>
'decoded_content_utf8'
);
can_ok(
$m
=>
'dump'
);
can_ok(
$m
=>
'encode'
);
can_ok(
$m
=>
'entity'
);
can_ok(
$m
=>
'header'
);
can_ok(
$m
=>
'headers'
);
can_ok(
$m
=>
'headers_as_string'
);
can_ok(
$m
=>
'is_encoding_supported'
);
can_ok(
$m
=>
'make_boundary'
);
can_ok(
$m
=>
'parse'
);
can_ok(
$m
=>
'parts'
);
can_ok(
$m
=>
'protocol'
);
can_ok(
$m
=>
'start_line'
);
can_ok(
$m
=>
'version'
);
is(
ref
(
$m
->headers ),
'HTTP::Promise::Headers'
);
is(
$m
->as_string,
$CRLF
,
'empty headers and no content'
);
is(
$m
->headers->as_string,
''
,
'headers->as_string'
);
is(
$m
->headers_as_string,
''
,
'headers_as_string'
);
is(
$m
->content,
''
,
'no content'
);
$m
->header(
'Foo'
, 1 );
is(
$m
->as_string,
"Foo: 1${CRLF}${CRLF}"
);
$m2
= HTTP::Promise::Message->new(
$m
->headers, {
debug
=>
$DEBUG
} ) ||
bail_out(
"Failed to instantiate a HTTP::Promise::Message object: "
. HTTP::Promise::Message->error );
$m2
->header(
bar
=> 2 );
is(
$m
->as_string,
"Foo: 1${CRLF}${CRLF}"
);
is(
$m2
->as_string,
"Bar: 2${CRLF}Foo: 1${CRLF}${CRLF}"
);
is(
$m2
->
dump
,
"Bar: 2${CRLF}Foo: 1${CRLF}\n(no content)\n"
);
is(
$m2
->
dump
(
no_content
=>
''
),
"Bar: 2${CRLF}Foo: 1${CRLF}\n\n"
);
is(
$m2
->
dump
(
no_content
=>
'-'
),
"Bar: 2${CRLF}Foo: 1${CRLF}\n-\n"
);
$body
=
$m2
->content(
'0'
);
diag(
"Error setting content: "
,
$m2
->error )
if
(
$DEBUG
&& !
defined
(
$body
) );
is(
$m2
->content,
'0'
,
'checking content is 0'
);
is(
$m2
->
dump
(
no_content
=>
'-'
),
"Bar: 2${CRLF}Foo: 1${CRLF}\n0\n"
);
is(
$m2
->
dump
(
no_content
=>
'0'
),
"Bar: 2${CRLF}Foo: 1${CRLF}\n\\x30\n"
);
$m2
= HTTP::Promise::Message->new(
$m
->headers,
'foo'
, {
debug
=>
$DEBUG
} );
is(
$m2
->as_string,
"Foo: 1${CRLF}${CRLF}foo"
,
'1 header and content foo'
);
is(
$m2
->as_string(
"<<\n"
),
"Foo: 1<<\n<<\nfoo"
,
'using <<\n as eol'
);
$m2
= HTTP::Promise::Message->new(
$m
->headers,
"foo\n"
, {
debug
=>
$DEBUG
} );
is(
$m2
->as_string,
"Foo: 1${CRLF}${CRLF}foo\n"
,
'1 header and content foo\n'
);
$m
= HTTP::Promise::Message->new( [
a
=> 1,
b
=> 2 ],
'abc'
, {
debug
=>
$DEBUG
} );
is(
$m
->as_string,
"A: 1${CRLF}B: 2${CRLF}${CRLF}abc"
,
'lower case content get proper casing'
);
$m
= HTTP::Promise::Message->parse(
''
,
debug
=>
$DEBUG
);
diag(
"Error parsing: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$m
) );
isa_ok(
$m
=> [
'HTTP::Promise::Message'
] );
is(
$m
->as_string,
"${CRLF}"
,
'no content'
);
$m
= HTTP::Promise::Message->parse(
"\n"
,
debug
=>
$DEBUG
);
is(
$m
,
undef
,
'bad request cannot be parsed: only 1 new line'
);
$m
= HTTP::Promise::Message->parse(
"\n\n"
,
debug
=>
$DEBUG
);
is(
$m
,
undef
,
'bad request cannot be parsed: only 2 new lines'
);
is( HTTP::Promise::Message->error->code, 400,
'bad request error code'
);
$m
= HTTP::Promise::Message->parse(
'foo'
,
debug
=>
$DEBUG
);
is(
$m
,
undef
,
'bad request cannot be parsed: no header'
);
$m
= HTTP::Promise::Message->parse(
"foo: 1\n\n"
,
debug
=>
$DEBUG
);
diag(
"Error parsing: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$m
) );
is(
$m
->as_string,
"Foo: 1${CRLF}${CRLF}"
);
$m
= HTTP::Promise::Message->parse(
"foo_bar: 1\n"
,
debug
=>
$DEBUG
);
diag(
"Error parsing: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$m
) );
is(
$m
,
undef
,
'bad request cannot be parsed: missing 2 crlf to separate headers'
);
$m
= HTTP::Promise::Message->parse(
"foo: 1\nfoo"
,
debug
=>
$DEBUG
);
diag(
"Error parsing: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$m
) );
is(
$m
,
undef
,
'bad request cannot be parsed: missing 2 crlf to separate headers'
);
$m
= HTTP::Promise::Message->parse(
<<EOT, debug => $DEBUG );
Foo: 1 2 3 4
bar: 1
Baz: 1
foobarbaz
EOT
diag(
"Error parsing: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$m
) );
is(
$m
->as_string,
join
(
$CRLF
,
split
( /\n/,
<<EOT, -1 ) ) . "foobarbaz\n", 'order of headers' );
Bar: 1
Baz: 1
Foo: 1 2 3 4
EOT
$m
= HTTP::Promise::Message->parse(
<<EOT, debug => $DEBUG );
Date: Fri, 18 Feb 2005 18:33:46 GMT
Connection: close
Content-Type: text/plain
foo:bar
second line
EOT
is(
$m
->content,
<<EOT, 'body only' );
foo:bar
second line
EOT
$m
->content(
''
);
is(
$m
->as_string,
join
(
$CRLF
,
split
( /\n/,
<<EOT, -1 ) ), 'headers only' );
Connection: close
Date: Fri, 18 Feb 2005 18:33:46 GMT
Content-Type: text/plain
EOT
$m
= HTTP::Promise::Message->parse(
" abc\nfoo: 1\n"
,
debug
=>
$DEBUG
);
is(
$m
,
undef
,
'bad request cannot be parsed: missing headers'
);
$m
= HTTP::Promise::Message->parse(
" foo : 1\n"
,
debug
=>
$DEBUG
);
is(
$m
,
undef
,
'bad request cannot be parsed: space at start is not allowed -> missing headers'
);
$m
= HTTP::Promise::Message->parse(
"\nfoo: bar\n"
,
debug
=>
$DEBUG
);
is(
$m
,
undef
,
'bad request cannot be parsed: crlf at start is not allowed -> missing headers'
);
$m
= HTTP::Promise::Message->new( [
a
=> 1,
b
=> 2 ],
'abc'
, {
debug
=>
$DEBUG
} );
is(
$m
->content,
'abc'
);
$m
->content(
"foo\n"
);
is(
$m
->content,
"foo\n"
);
$m
->add_content(
'bar'
);
is(
$m
->content,
"foo\nbar"
);
$m
->add_content( \
"\n"
);
is(
$m
->content,
"foo\nbar\n"
);
is( Scalar::Util::reftype(
$m
->content_ref ),
'SCALAR'
,
'returning content as scalar reference'
);
is( ${
$m
->content_ref},
"foo\nbar\n"
,
'content reference'
);
$m
->entity->body->replace(
qr/[ao]/
,
'i'
);
is(
$m
->content,
"fii\nbir\n"
,
'body->replace'
);
$m
->clear;
is(
$m
->headers->header_field_names, 0 );
is(
$m
->content,
''
);
is(
$m
->parts->first,
undef
,
'no part'
);
my
$p1
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
diag(
"Error setting part #1 object: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$p1
) );
my
$p2
= HTTP::Promise::Message->new( [
a
=> 1],
'foo'
, {
debug
=>
$DEBUG
} );
diag(
"Error setting part #2 object: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$p2
) );
my
$p3
= HTTP::Promise::Message->new(
undef
,
"bar\n"
, {
debug
=>
$DEBUG
} );
diag(
"Error setting part #3 object: "
, HTTP::Promise::Message->error )
if
(
$DEBUG
&& !
defined
(
$p3
) );
isa_ok(
$p1
=> [
'HTTP::Promise::Message'
],
'part #1 is a HTTP::Promise::Message object'
);
isa_ok(
$p2
=> [
'HTTP::Promise::Message'
],
'part #2 is a HTTP::Promise::Message object'
);
isa_ok(
$p3
=> [
'HTTP::Promise::Message'
],
'part #3 is a HTTP::Promise::Message object'
);
$parts
=
$m
->parts(
$p1
,
$p2
,
$p3
);
diag(
"Setting parts resulted in an error: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$parts
) );
isa_ok(
$parts
=> [
'Module::Generic::Array'
] );
isa_ok(
$parts
->
first
=> [
'HTTP::Promise::Entity'
] );
diag(
"Is first part ("
,
$parts
->first,
") same as part #1 ("
,
$p1
->entity,
") ?"
)
if
(
$DEBUG
);
is( Scalar::Util::refaddr(
$parts
->first ), Scalar::Util::refaddr(
$p1
->entity ) );
is(
$m
->parts->first->as_string,
"${CRLF}"
,
'parts as string'
);
my
$str
=
$m
->as_string;
my
$boundary
=
$m
->boundary;
$str
=~ s/\r/<CR>/g;
is(
$str
,
<<EOT );
Content-Type: multipart/mixed; boundary=${boundary}<CR>
<CR>
--${boundary}<CR>
<CR>
<CR>
--${boundary}<CR>
A: 1<CR>
<CR>
foo<CR>
--${boundary}<CR>
<CR>
bar
<CR>
--${boundary}--<CR>
EOT
$m2
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
$m2
->parts(
$m
);
diag(
"Encapsulated object ($m) boundary is '"
,
$m
->boundary,
"'"
)
if
(
$DEBUG
);
$str
=
$m2
->as_string;
diag(
"Top object ($m2) boundary is '"
,
$m2
->boundary,
"'"
)
if
(
$DEBUG
);
$str
=~ s/\r/<CR>/g;
ok(
$str
=~ /boundary=(\S+)/ );
my
$boundary2
=
$m2
->boundary;
is(
$str
,
<<EOT );
Content-Type: multipart/mixed; boundary=${boundary2}<CR>
<CR>
--${boundary2}<CR>
Content-Type: multipart/mixed; boundary=${boundary}<CR>
<CR>
--${boundary}<CR>
<CR>
<CR>
--${boundary}<CR>
A: 1<CR>
<CR>
foo<CR>
--${boundary}<CR>
<CR>
bar
<CR>
--${boundary}--<CR>
<CR>
--${boundary2}--<CR>
EOT
$parts
=
$m2
->parts;
is(
$parts
->
length
, 1 );
$parts
=
$parts
->first->parts;
is(
$parts
->
length
, 3 );
is(
$parts
->[1]->header(
'A'
), 1 );
$m2
->parts( [ HTTP::Promise::Message->new ] );
$parts
=
$m2
->parts;
is(
$parts
->
length
, 1 );
$m2
->parts( [] );
$parts
=
$m2
->parts;
is(
$parts
->
length
, 0 );
$m
->clear;
$m2
->clear;
$m
= HTTP::Promise::Message->new( [
content_type
=>
"message/http; boundary=aaa"
, ],
<<EOT, { debug => $DEBUG } );
GET / HTTP/1.1
Host: www.example.com:8008
EOT
diag(
"HTTP message is:\n"
,
$m
->as_string )
if
(
$DEBUG
);
$parts
=
$m
->parts;
is(
$parts
->
length
, 1,
'number of parts'
);
$m2
=
$parts
->[0];
isa_ok(
$m2
=> [
'HTTP::Promise::Entity'
],
'part is an entity object'
);
SKIP:
{
skip(
'No part object defined'
, 6 )
unless
(
defined
(
$m2
) );
my
$msg
=
$m2
->http_message;
isa_ok(
$msg
=> [
'HTTP::Promise::Request'
],
'http message is an HTTP::Promise::Request object'
);
is(
$msg
->method,
'GET'
,
'method is GET'
);
is(
$msg
->uri,
'/'
,
'uri is /'
);
is(
$msg
->protocol,
'HTTP/1.1'
,
'protocol is HTTP/1.1'
);
is(
$msg
->header(
'Host'
),
'www.example.com:8008'
);
is(
$msg
->content,
''
,
'no content'
);
};
diag(
"Changing content to HTTP/1.0 200 OK\\nContent-Type: text/plain\\n\\nHello\\n"
)
if
(
$DEBUG
);
$m
->content(
<<EOT );
HTTP/1.0 200 OK
Content-Type: text/plain
Hello
EOT
diag(
"Entity is:\n"
,
$m
->as_string )
if
(
$DEBUG
);
diag(
"Check 1. There are "
,
$m
->parts->
length
,
" parts found."
)
if
(
$DEBUG
);
$m2
=
$m
->parts->[0];
isa_ok(
$m2
=> [
'HTTP::Promise::Entity'
],
'part is an entity object'
);
SKIP:
{
skip(
'No part object defined'
, 6 )
unless
(
defined
(
$m2
) );
my
$msg
=
$m2
->http_message;
diag(
"Part as string is: '"
,
$msg
->as_string,
"'"
)
if
(
$DEBUG
);
is(
$msg
->protocol,
'HTTP/1.0'
,
'protocol is HTTP/1.0'
);
is(
$msg
->code,
'200'
,
'code is 200'
);
is(
$msg
->status,
'OK'
,
'status is OK'
);
is(
$msg
->content_type,
'text/plain'
,
'mime-type is text/plain'
);
is(
$msg
->content,
"Hello\n"
,
'content is Hello\n'
);
};
diag(
"Check 2. There are "
,
$m
->parts->
length
,
" parts found."
)
if
(
$DEBUG
);
diag(
"HTTP message is:\n"
,
$m
->as_string )
if
(
$DEBUG
);
$parts
=
$m
->parts( HTTP::Promise::Message->new, HTTP::Promise::Message->new );
diag(
"Error message is: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$parts
) );
ok( !
defined
(
$parts
) &&
$m
->error->message,
'only 1 part possible for message/http'
);
$m
->entity->debug(
$DEBUG
);
diag(
"Calliing \$m->add_part"
)
if
(
$DEBUG
);
$rv
=
$m
->add_part( HTTP::Promise::Message->new( [
a
=> [1..3] ],
'a'
) );
diag(
"is \$rv from add_part an HTTP::Promise::Message object ?"
)
if
(
$DEBUG
);
isa_ok(
$rv
=> [
'HTTP::Promise::Message'
],
'add_part returns the message object'
);
diag(
"Error adding part: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$rv
) );
is(
$m
->parts->
length
, 2,
'number of parts'
);
$boundary
=
$m
->boundary;
$str
=
$m
->as_string;
$str
=~ s/\r/<CR>/g;
is(
$str
,
<<EOT, 'message as string ater adding part' );
Content-Type: multipart/form-data; boundary=${boundary}<CR>
<CR>
--${boundary}<CR>
Content-Type: message/http; boundary=aaa<CR>
Content-Disposition: form-data; name="part1"<CR>
<CR>
HTTP/1.0 200 OK<CR>
Content-Type: text/plain<CR>
<CR>
Hello
<CR>
--${boundary}<CR>
A: 1<CR>
A: 2<CR>
A: 3<CR>
Content-Disposition: form-data; name="part2"<CR>
<CR>
a<CR>
--${boundary}--<CR>
EOT
$m
->content_type(
'multipart/mixed'
);
$m
->add_part( HTTP::Promise::Message->new( [
b
=> [1..3] ],
'b'
) );
$boundary
=
$m
->boundary;
$str
=
$m
->as_string;
$str
=~ s/\r/<CR>/g;
is(
$str
,
<<EOT, 'adding part in an explicit multipart/mixed structure' );
Content-Type: multipart/mixed; boundary=${boundary}<CR>
<CR>
--${boundary}<CR>
Content-Type: message/http; boundary=aaa<CR>
<CR>
HTTP/1.0 200 OK<CR>
Content-Type: text/plain<CR>
<CR>
Hello
<CR>
--${boundary}<CR>
A: 1<CR>
A: 2<CR>
A: 3<CR>
<CR>
a<CR>
--${boundary}<CR>
B: 1<CR>
B: 2<CR>
B: 3<CR>
<CR>
b<CR>
--${boundary}--<CR>
EOT
$m
= HTTP::Promise::Message->new({
debug
=>
$DEBUG
});
$m
->add_part( HTTP::Promise::Message->new( [
a
=> [1..3] ],
'a'
) );
$boundary
=
$m
->boundary;
is(
$m
->header(
'Content-Type'
),
"multipart/form-data; boundary=${boundary}"
);
$str
=
$m
->as_string;
$str
=~ s/\r/<CR>/g;
is(
$str
,
<<EOT, 'default form-data upon adding part' );
Content-Type: multipart/form-data; boundary=${boundary}<CR>
<CR>
--${boundary}<CR>
A: 1<CR>
A: 2<CR>
A: 3<CR>
Content-Disposition: form-data; name="part1"<CR>
<CR>
a<CR>
--${boundary}--<CR>
EOT
$m
= HTTP::Promise::Message->new( [
'Content-Type'
=>
'multipart/mixed'
], {
debug
=>
$DEBUG
} );
$m
->add_part( HTTP::Promise::Message->new( [],
'foo and a lot more content'
, {
debug
=>
$DEBUG
} ) );
$boundary
=
$m
->boundary;
is(
$m
->header(
'Content-Type'
),
"multipart/mixed; boundary=${boundary}"
);
$parts
=
$m
->parts;
is(
$parts
->[0]->body->as_string,
'foo and a lot more content'
);
like(
$parts
->[0]->
dump
(
maxlength
=> 4 ),
qr/foo \.\.\./
,
'dump max 4 bytes'
);
like(
$parts
->[0]->
dump
(
maxlength
=> 0 ),
qr/foo and a lot/
,
'dump no limit'
);
$rv
=
$m
->encode;
ok( !
defined
(
$rv
) &&
$m
->error->message =~ /Cannot encode multipart/ );
$m
->content_type(
'message/http'
);
$rv
=
$m
->encode;
ok( !
defined
(
$rv
) &&
$m
->error->message =~ /Cannot encode message/ );
$m
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
my
$foo
=
'foo'
;
my
$ref
=
$m
->content_ref( \
$foo
);
is(
$m
->content,
'foo'
,
'content_ref'
);
my
$foo2
=
$m
->content(
'bar'
);
isa_ok(
$foo2
=> [
'HTTP::Promise::Body::Scalar'
] );
is(
$foo2
->as_string,
'bar'
);
is(
$m
->content,
'bar'
);
my
$content_ref
=
$m
->content_ref;
SKIP:
{
skip(
'content_ref not set.'
, 2 )
if
( !
ref
(
$content_ref
) );
is( Scalar::Util::reftype(
$content_ref
),
'SCALAR'
,
'value returned by content_ref is a scalar object'
);
is(
$$content_ref
,
'bar'
);
};
$m
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
$m
->content(
'fo=6F'
);
$m
->entity->is_encoded(1);
my
$decoded
=
$m
->decoded_content;
diag(
"Error decoding: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$decoded
) );
is(
$decoded
,
'fo=6F'
,
'content enchanged without Content-Encoding set'
);
$m
->header(
'Content-Encoding'
,
'quoted-printable'
);
is(
$m
->decoded_content,
'foo'
);
for
my
$encoding
(
qw/gzip x-gzip/
)
{
$m
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
$m
->header(
'Content-Encoding'
,
"$encoding, base64"
);
$m
->entity->is_encoded(1);
$m
->content_type(
'text/plain; charset=UTF-8'
);
$m
->content(
"H4sICFWAq0ECA3h4eAB7v3u/R6ZCSUZqUarCoxm7uAAZKHXiEAAAAA==\n"
);
my
$decoded_content
=
$m
->decoded_content(
binmode
=>
'utf8'
,
replace
=> 0 );
diag(
"Is content in decoded utf8? "
, ( utf8::is_utf8(
$decoded_content
) ?
'yes'
:
'no'
) )
if
(
$DEBUG
);
ok(
defined
(
$decoded_content
),
'content was decoded'
);
is(
$decoded_content
,
"\x{FEFF}Hi there \x{263A}\n"
,
'decoded utf-8 content'
);
is(
$m
->content->
scalar
,
"H4sICFWAq0ECA3h4eAB7v3u/R6ZCSUZqUarCoxm7uAAZKHXiEAAAAA==\n"
,
'original content unchanged'
);
$m2
=
$m
->clone;
isa_ok(
$m2
=> [
'HTTP::Promise::Message'
] );
diag(
"Error cloning HTTP::Promise::Message object: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$m2
) );
SKIP:
{
skip(
'clone did not return an HTTP::Promise::Message object.'
, 3 )
if
( !
defined
(
$m2
) );
ok(
$m2
->entity->is_encoded,
'entity body is encoded'
);
ok(
$m2
->decode,
'decoded entity body'
);
ok( !
$m2
->entity->is_encoded,
'entity body is not encoded'
);
like(
$m2
->content,
qr/Hi there/
,
'content check after decoding'
);
};
diag(
"List of supported encodings: '"
,
$m
->decodable->
join
(
"', '"
)->
scalar
,
"'"
)
if
(
$DEBUG
);
ok(
$m
->is_encoding_supported(
$encoding
),
"$encoding is supported"
);
$decoded_content
=
$m
->decoded_content(
binmode
=>
'utf8'
);
diag(
"Error decoding content: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$decoded_content
) );
ok(
defined
(
$decoded_content
),
'decoded content defined'
);
is(
$decoded_content
,
"\x{FEFF}Hi there \x{263A}\n"
,
'decoded content check'
);
my
$m2
= HTTP::Promise::Message->new([
'Content-Type'
=>
'text/plain'
,
],
"Hi there\n"
,
{
debug
=>
$DEBUG
},
);
$rv
=
$m2
->encode(
$encoding
,
update_header
=> 1 );
diag(
"Error encoding: "
,
$m2
->error )
if
(
$DEBUG
&& !
defined
(
$rv
) );
ok(
$rv
,
"encoding content using $encoding"
);
is(
$m2
->header(
'Content-Encoding'
),
$encoding
,
"Content-Encoding is $encoding"
);
is(
$m2
->headers->content_encoding,
$encoding
,
"content_encoding returns $encoding"
);
unlike(
$m2
->content->
scalar
,
qr/Hi there/
);
diag(
"Decoding content."
)
if
(
$DEBUG
);
$decoded_content
=
$m2
->decoded_content(
binmode
=>
'utf8'
,
replace
=> 0 );
diag(
"Error decoding content: "
,
$m2
->error )
if
(
$DEBUG
&& !
defined
(
$decoded_content
) );
is(
$decoded_content
,
"Hi there\n"
,
'decoded content check'
);
ok(
$m2
->decode,
'decode content'
);
is(
$m2
->content,
"Hi there\n"
,
'decoded content check'
);
}
$m
->remove_header(
'Content-Encoding'
);
$m
->content(
"a\x{FF}"
);
$m
->entity->debug(
$DEBUG
);
diag(
"Content-Type is '"
,
$m
->headers->content_type,
"'"
)
if
(
$DEBUG
);
$io_layer
=
$m
->entity->io_encoding;
is(
$io_layer
,
'utf-8'
,
'io encoding'
);
$decoded_content
=
$m
->decoded_content(
replace
=> 0 );
diag(
"Is \$decoded_content in perl utf8? "
, ( utf8::is_utf8(
$$decoded_content
) ?
'yes'
:
'no'
) )
if
(
$DEBUG
);
if
(
$DEBUG
)
{
my
$utf8_data
=
$$decoded_content
;
$utf8_data
=~ s/([\N{U+0080}-\N{U+FFFF}\n])/
sprintf
(
'\\x{%X}'
,
ord
($1))/eg;
diag(
"utf string returned: '$utf8_data'"
);
}
is(
"$decoded_content"
,
"a\x{FFFD}"
,
'guessed utf8 content check'
);
$io_layer
=
$m
->entity->io_encoding(
charset_strict
=> 1 );
is(
$io_layer
,
undef
,
'strict io encoding returns undef'
);
is(
$m
->decoded_content(
charset_strict
=> 1 )->
scalar
,
"a\x{FF}"
,
'decoded_content returns body content unaltered'
);
$m
->header(
'Content-Encoding'
,
'foobar'
);
$m
->entity->is_encoded(1);
$decoded_content
=
$m
->decoded_content;
is( (
defined
(
$decoded_content
) ?
"$decoded_content"
:
''
),
''
,
'failed decoding content'
);
like(
$m
->error->message,
qr/^Decoding provided "foobar" is unsupported/
,
'error->message for unsupported encoding'
);
my
$err
= 0;
eval
{
$m
->decoded_content(
raise_error
=> 1 );
$err
++;
};
diag(
"\$@ is '$@'"
);
like( $@->message,
qr/Decoding provided "foobar" is unsupported/
,
'$@->message for unsupported encoding'
);
is(
$err
, 0 );
$rv
= HTTP::Promise::Message->new( [],
"\x{263A}"
, {
debug
=>
$DEBUG
} );
ok( !
defined
(
$rv
) );
like( HTTP::Promise::Message->error->message,
qr/bytes/
);
$m
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
$rv
=
$m
->add_content(
"\x{263A}"
);
ok( !
defined
(
$rv
) );
like(
$m
->error->message,
qr/bytes/
);
$rv
=
$m
->content(
"\x{263A}"
);
ok( !
defined
(
$rv
) );
like(
$m
->error->message,
qr/bytes/
);
{
$m
= HTTP::Promise::Message->new( [
'Content-Type'
,
'text/plain; charset=UTF-8'
], {
debug
=>
$DEBUG
} );
my
$body
=
$m
->add_content_utf8(
"\x{263A}"
);
isa_ok(
$body
=> [
'HTTP::Promise::Body'
] );
diag(
"An error occurred adding utf8 content: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$body
) );
$body
=
$m
->add_content_utf8(
"-\xC5"
);
diag(
"An error occurred adding utf8 content: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$body
) );
isa_ok(
$body
=> [
'HTTP::Promise::Body'
] );
my
$content
=
$m
->content;
is(
"$content"
,
"\xE2\x98\xBA-\xC3\x85"
,
'resulting utf8 content added'
);
is(
$m
->decoded_content(
binmode
=>
'utf-8'
),
"\x{263A}-\x{00C5}"
,
'resulting decoded utf8 content added'
);
}
$m
= HTTP::Promise::Message->new([
'Content-Type'
=>
'text/plain'
,
],
'Hello world!'
,
{
debug
=>
$DEBUG
},
);
$m
->content_length(
$m
->content->
length
);
$m
->encode(
'deflate'
,
update_header
=> 1 );
$m
->
dump
(
prefix
=>
'# '
);
is(
$m
->
dump
(
prefix
=>
'| '
),
join
(
"| \n"
,
<<EOT1, <<'EOT2' ), 'dump with prefix' );
| Content-Encoding: deflate\r
| Content-Type: text/plain\r
EOT1
| x\x9C\xF3H\xCD\xC9\xC9W(\xCF/\xCAIQ\4\0\35\t\4^
EOT2
for
my
$encoding
(
qw/identity none/
)
{
my
$m2
=
$m
->clone;
$m2
->encode(
'base64'
,
$encoding
);
is(
$m2
->as_string,
join
(
$CRLF
,
split
( /\n/,
<<"EOT", -1 ) ) . "eJzzSM3JyVcozy/KSVEEAB0JBF4=" );
Content-Encoding: deflate, base64, $encoding
Content-Type: text/plain
EOT
is(
$m2
->decoded_content,
'Hello world!'
);
}
$m
= HTTP::Promise::Message->new([
'Content-Type'
=>
'text/plain'
,
'Content-Encoding'
=>
'deflate, base64'
,
],
'80jNyclXCM8vyklRBAA='
,
{
debug
=>
$DEBUG
}
);
$m
->entity->is_encoded(1);
$m
->debug(
$DEBUG
)
if
(
$DEBUG
);
$decoded_content
=
$m
->decoded_content;
diag(
"Error decoding content: "
,
$m
->error )
if
(
$DEBUG
&& !
defined
(
$decoded_content
) );
is(
$decoded_content
,
'Hello World!'
,
'decoded content from base64 and deflate'
);
ok( !
$m
->header(
'Client-Warning'
) );
if
( HTTP::Promise::Stream->load(
'bzip2'
) )
{
for
my
$encoding
(
qw( x-bzip2 bzip2 )
)
{
my
$m
= HTTP::Promise::Message->new([
'Content-Type'
=>
'text/plain'
,
'Content-Encoding'
=>
"$encoding, base64"
,
],
"QlpoOTFBWSZTWcvLx0QAAAHVgAAQYAAAQAYEkIAgADEAMCBoYlnQeSEMvxdyRThQkMvLx0Q=\n"
,
{
debug
=>
$DEBUG
},
);
isa_ok(
$m
=> [
'HTTP::Promise::Message'
],
"object created with encodings $encoding, base64"
);
SKIP:
{
skip(
'Cannot create HTTP::Promise::Message object'
, 3 );
is(
$m
->decoded_content(
replace
=> 0 ),
"Hello world!\n"
,
'decoded content'
);
ok(
$m
->decode,
'decode'
);
is(
$m
->content,
"Hello world!\n"
,
'content after decode()'
);
};
$m
= HTTP::Promise::Message->new([
'Content-Type'
=>
'text/plain'
,
],
'Hello world!'
,
{
debug
=>
$DEBUG
},
);
isa_ok(
$m
=> [
'HTTP::Promise::Message'
],
"object created with plain content"
);
SKIP:
{
skip(
'Cannot create HTTP::Promise::Message object'
, 6 );
ok(
$m
->encode(
$encoding
),
"encode( $encoding )"
);
is(
$m
->header(
'Content-Encoding'
),
$encoding
,
'Content-Encoding header added'
);
like(
$m
->content,
qr/^BZh.*\0/
,
"encoded content with $encoding"
);
is(
$m
->decoded_content(
replace
=> 0 ),
'Hello world!'
,
'decoded_content'
);
ok(
$m
->decode,
'decode'
);
is(
$m
->content,
'Hello world!'
,
'content after decode()'
);
};
}
}
else
{
skip(
'Need IO::Compress::Bzip2 and IO::Uncompress::Bunzip2'
, 18 );
}
$m
= HTTP::Promise::Message->new(
[
'Content-Type'
,
'application/xml'
],
"\xFF\xFE<\0?\0x\0m\0l\0 \0v\0e\0r\0s\0i\0o\0n\0=\0\"\x001\0.\x000\0\"\0 \0e\0n\0c\0o\0d\0i\0n\0g\0=\0\"\0U\0T\0F\0-\x001\x006\0l\0e\0\"\0?\0>\0\n\0<\0r\0o\0o\0t\0>\0\xC9\0r\0i\0c\0<\0/\0r\0o\0o\0t\0>\0\n\0"
,
{
debug
=>
$DEBUG
}
);
is(
$m
->decoded_content,
qq{<?xml version="1.0"?>\n<root>\xC9ric</root>\n}
,
'UTF-16le decoded content'
);
$m
->DESTROY;
is(
$m
->decoded_content,
qq{<?xml version="1.0"?>\n<root>\xC9ric</root>\n}
,
'UTF-16le decoded content after DESTROY'
);
$m
= HTTP::Promise::Message->new([
'Content-Type'
=>
'text/plain'
,
],
"Hello World!\n"
,
{
debug
=>
$DEBUG
}
);
is(
$m
->content,
"Hello World!\n"
,
'content'
);
ok(
$m
->encode(),
'encode'
);
is(
$m
->content,
"Hello World!\n"
,
'content unchanged with no encoding'
);
is(
$m
->encode(
'not-an-encoding'
),
undef
,
'encode fail with bad encoding'
);
is(
$m
->content,
"Hello World!\n"
,
'content unchanged with bad encoding'
);
for
my
$encoding
(
qw( compress x-compress )
)
{
$m
= HTTP::Promise::Message->new([
'Content-Type'
=>
'text/plain'
,
'Content-Encoding'
=>
$encoding
,
],
'foo'
,
{
debug
=>
$DEBUG
},
);
isa_ok(
$m
=> [
'HTTP::Promise::Message'
],
"object created with encoding $encoding, but plain content"
);
SKIP:
{
skip(
'Cannot create HTTP::Promise::Message object'
, 1 );
eval
{
$m
->decoded_content(
raise_error
=> 1 ); };
like( $@,
qr/Cannot uncompress content/
,
"cannot uncompress uncompressed content"
);
};
}
$m
= HTTP::Promise::Message->new(
'bad-header'
);
ok( !
defined
(
$m
),
'failed to create object with bad header'
);
like( HTTP::Promise::Message->error->message,
qr/Bad header argument/
,
'bad header error message'
);
$m
= HTTP::Promise::Message->new( [
'Content-Encoding'
=>
'foo'
],
'Hello world'
, {
debug
=>
$DEBUG
} );
isa_ok(
$m
=> [
'HTTP::Promise::Message'
],
"object created with bad encoding foo"
);
is(
$m
->decode,
undef
,
'decode with encoding foo failed'
);
$m
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
isa_ok(
$m
=> [
'HTTP::Promise::Message'
],
"dummy object created"
);
ok(
$m
->decode,
'decode'
);
$body
=
$m
->content(
undef
);
isa_ok(
$body
=> [
'HTTP::Promise::Body'
],
'content is reset and an HTTP::Promise::Body is returned'
);
ok(
$m
->entity->body->is_empty,
'body is empty'
);
$rv
=
$m
->content( [] );
ok( !
defined
(
$rv
),
'content() failed when provided with an array'
);
like(
$m
->error->message,
qr/I was expecting a string or a scalar reference, but instead got/
,
'content() error message'
);
$m
= HTTP::Promise::Message->new( [
'Content-Type'
=>
'text/plain'
,],
"\xEF\xBB\xBFaa/"
, {
debug
=>
$DEBUG
} );
isa_ok(
$m
=> [
'HTTP::Promise::Message'
],
"object created with utf-8 content to be guessed."
);
is(
$m
->content_charset,
'UTF-8'
,
'content_charset correctly guessed utf-8'
);
diag(
'changing content to UTF-32LE data'
)
if
(
$DEBUG
);
$m
->content(
"\xFF\xFE\x00\x00aa/"
);
is(
$m
->content_charset,
"UTF-32LE"
,
'content_charset correctly guessed UTF-32LE'
);
diag(
'changing content to UTF-32BE data'
)
if
(
$DEBUG
);
$m
->content(
"\x00\x00\xFE\xFFaa/"
);
is(
$m
->content_charset,
"UTF-32BE"
,
'content_charset correctly guessed UTF-32BE'
);
diag(
'changing content to UTF-16LE data'
)
if
(
$DEBUG
);
$m
->content(
"\xFF\xFEaa/"
);
is(
$m
->content_charset,
"UTF-16LE"
,
'content_charset correctly guessed UTF-16LE'
);
diag(
'changing content to UTF-16BE data'
)
if
(
$DEBUG
);
$m
->content(
"\xFE\xFFaa/"
);
is(
$m
->content_charset,
"UTF-16BE"
,
'content_charset correctly guessed UTF-16BE'
);
{
$m
= HTTP::Promise::Message->new( {
debug
=>
$DEBUG
} );
local
$@ =
'pre-existing error'
;
$m
->decodable;
is( $@,
'pre-existing error'
,
'decodable() does not overwrite $@'
);
}
$m
= HTTP::Promise::Message->new([
'User-Agent'
=>
'Mozilla/5.0'
,
{
debug
=>
$DEBUG
}
]);
ok(
$m
->can(
'content'
),
'can content()'
);
my
$method
=
$m
->can(
'user_agent'
);
is(
ref
(
$method
),
'CODE'
,
'can user_agent from HTTP::Promise::Headers'
);
is( HTTP::Promise::Message->can(
'user_agent'
),
$method
,
'user_agent code reference'
);
is(
$m
->
$method
,
'Mozilla/5.0'
,
'user_agent value retrieved'
);
ok( HTTP::Promise::Message->can(
'content'
),
'content() as a class function'
);
$method
= HTTP::Promise::Message->can(
'referrer'
);
is(
ref
(
$method
),
'CODE'
,
'referrer code reference'
);
is(
$m
->can(
'referrer'
),
$method
,
'can referrer'
);
eval
{
$m
->unknown_method; };
like( $@,
qr/Method unknown_method\(\) is not defined in class HTTP::Promise::Message/
,
'trapping $m->unknown_method'
);
is(
$m
->can(
'unknown_method'
),
undef
,
'can not unknown_method using object'
);
eval
{ HTTP::Promise::Message->unknown_method; };
like( $@,
qr/Method unknown_method\(\) is not defined in class HTTP::Promise::Message/
,
'trapping HTTP::Promise::Message->unknown_method'
);
is( HTTP::Promise::Message->can(
'unknown_method'
),
undef
,
'can not unknown_method as class function'
);
eval
{
my
$empty
=
''
;
$m
->
$empty
; };
like( $@,
qr/Method \(\) is not defined in class HTTP::Promise::Message/
,
'cannot call null method'
);
done_testing();