Skip to content

Instantly share code, notes, and snippets.

Created August 2, 2014 00:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/3bbc4c20fa1f4aaec11f to your computer and use it in GitHub Desktop.
Save anonymous/3bbc4c20fa1f4aaec11f to your computer and use it in GitHub Desktop.
diff --git a/Changes b/Changes
index 8f22ab7..aab2b53 100644
--- a/Changes
+++ b/Changes
@@ -1,5 +1,8 @@
5.24 2014-08-02
+ - Added links method to Mojo::Message.
+ - Improved split_header function in Mojo::Util to handle more formats.
+ - Fixed bug where ojo would sometimes die silently.
5.23 2014-07-31
- Improved router performance.
diff --git a/lib/Mojo/Message.pm b/lib/Mojo/Message.pm
index 0d7a4c3..fcdb36e 100644
--- a/lib/Mojo/Message.pm
+++ b/lib/Mojo/Message.pm
@@ -9,7 +9,7 @@ use Mojo::JSON 'j';
use Mojo::JSON::Pointer;
use Mojo::Parameters;
use Mojo::Upload;
-use Mojo::Util 'decode';
+use Mojo::Util qw(decode split_header);
has content => sub { Mojo::Content::Single->new };
has default_charset => 'UTF-8';
@@ -139,6 +139,18 @@ sub json {
return $pointer ? Mojo::JSON::Pointer->new($data)->get($pointer) : $data;
}
+sub links {
+ my $self = shift;
+
+ my %links;
+ for my $link (@{split_header $self->headers->link // '', '<', '>'}) {
+ my $hash = {url => (splice @$link, 0, 2)[0], @$link};
+ $links{$hash->{rel}} = $hash;
+ }
+
+ return \%links;
+}
+
sub param { shift->body_params->param(@_) }
sub parse {
@@ -578,6 +590,17 @@ sure it is not excessively large, there's a 10MB limit by d
say $msg->json->{foo}{bar}[23];
say $msg->json('/foo/bar/23');
+=head2 links
+
+ my $links = $msg->links;
+
+Extract web links from C<Link> header according to
+L<RFC 5988|http://tools.ietf.org/html/rfc5988>.
+
+ # Extract information about next page
+ say $msg->links->{next}{url};
+ say $msg->links->{next}{title};
+
=head2 param
my @names = $msg->param;
diff --git a/lib/Mojo/Util.pm b/lib/Mojo/Util.pm
index f7dccf5..2f1313b 100644
--- a/lib/Mojo/Util.pm
+++ b/lib/Mojo/Util.pm
@@ -250,7 +250,8 @@ sub slurp {
sub split_header {
my $str = shift;
- my (@tree, @token);
+ my @tree;
+ my @token = _option($str, @_);
while ($str =~ s/^[,;\s]*([^=;, ]+)\s*//) {
push @token, $1, undef;
$token[-1] = unquote($1)
@@ -260,7 +261,7 @@ sub split_header {
$str =~ s/^;\s*//;
next unless $str =~ s/^,\s*//;
push @tree, [@token];
- @token = ();
+ @token = _option($str, @_);
}
# Take care of final token
@@ -389,6 +390,10 @@ sub _encoding {
$CACHE{$_[0]} //= find_encoding($_[0]) // croak "Unknown encoding '$_[0]'";
}
+sub _option {
+ @_ > 1 && $_[0] =~ s/\Q$_[1]\E(.+?)\Q$_[2]\E// ? ($1, undef) : ();
+}
+
sub _options {
# Hash or name (one)
@@ -625,6 +630,7 @@ Read all data at once from file.
=head2 split_header
my $tree = split_header 'foo="bar baz"; test=123, yada';
+ my $tree = split_header '</foo;bar>; rel=next', '<', '>';
Split HTTP header value.
@@ -637,6 +643,12 @@ Split HTTP header value.
# "five"
split_header('one; two="three four", five=six')->[1][0];
+ # "foo;bar"
+ split_header('</foo;bar>; baz=yada')->[0][0];
+
+ # "baz"
+ split_header('</foo;bar>; baz=yada')->[0][3];
+
=head2 spurt
$bytes = spurt $bytes, '/etc/passwd';
diff --git a/lib/ojo.pm b/lib/ojo.pm
index 8fb4b28..05b5337 100644
--- a/lib/ojo.pm
+++ b/lib/ojo.pm
@@ -14,7 +14,7 @@ sub import {
# Mojolicious::Lite
my $caller = caller;
- eval "package $caller; use Mojolicious::Lite;";
+ eval "package $caller; use Mojolicious::Lite; 1" or die $@;
my $ua = $caller->app->ua;
$ua->server->app->hook(around_action => sub { local $_ = $_[1]; $_[0]->() });
diff --git a/t/mojo/response.t b/t/mojo/response.t
index 7455cc9..5967b58 100644
--- a/t/mojo/response.t
+++ b/t/mojo/response.t
@@ -416,6 +416,8 @@ is $res->headers->content_length, undef, 'right "Content-Len
$res = Mojo::Message::Response->new;
$res->parse("HTTP/1.1 500 Internal Server Error\x0d\x0a");
$res->parse("Content-Type: text/plain\x0d\x0a");
+$res->parse("Link: <http://example.com?foo=b;,ar>; rel=next\x0d\x0a");
+$res->parse(qq{Link: </>; rel=root; title="foo bar"\x0d\x0a});
$res->parse("Transfer-Encoding: chunked\x0d\x0a\x0d\x0a");
$res->parse("4\x0d\x0a");
$res->parse("abcd\x0d\x0a");
@@ -430,6 +432,14 @@ is $res->headers->content_type, 'text/plain', 'right "Con
is $res->headers->content_length, 13, 'right "Content-Length" value';
is $res->headers->transfer_encoding, undef, 'no "Transfer-Encoding" value';
is $res->body_size, 13, 'right size';
+is $res->headers->link,
+ '<http://example.com?foo=b;,ar>; rel=next, </>; rel=root; title="foo bar"',
+ 'right "Link" value';
+my $links = {
+ next => {url => 'http://example.com?foo=b;,ar', rel => 'next'},
+ root => {url => '/', rel => 'root', title => 'foo bar'}
+};
+is_deeply $res->links, $links, 'right links';
# Parse HTTP 1.1 multipart response
$res = Mojo::Message::Response->new;
diff --git a/t/mojo/util.t b/t/mojo/util.t
index 387a788..ed067d2 100644
--- a/t/mojo/util.t
+++ b/t/mojo/util.t
@@ -81,6 +81,13 @@ $tree = [
]
];
is_deeply split_header($header), $tree, 'right result';
+is_deeply split_header('', '<', '>'), [], 'right result';
+$header = q{<http://example.com/foo?bar=b,;az>; rel=next, </>; rel=root};
+$tree = [
+ ['http://example.com/foo?bar=b,;az', undef, 'rel', 'next'],
+ ['/', undef, 'rel', 'root']
+];
+is_deeply split_header($header, '<', '>'), $tree, 'right result';
# unindent
is unindent(" test\n 123\n 456\n"), "test\n 123\n456\n",
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment