Skip to content

Instantly share code, notes, and snippets.

@vti
Created September 11, 2011 07:37
Show Gist options
  • Save vti/1209294 to your computer and use it in GitHub Desktop.
Save vti/1209294 to your computer and use it in GitHub Desktop.
diff --git a/lib/MetaCPAN/Role/JSONP.pm b/lib/MetaCPAN/Role/JSONP.pm
new file mode 100644
index 0000000..7dfcb37
--- /dev/null
+++ b/lib/MetaCPAN/Role/JSONP.pm
@@ -0,0 +1,42 @@
+package MetaCPAN::Role::JSONP;
+use Moose::Role;
+use Encode;
+
+before _BEGIN => sub {
+ my $self = shift;
+ my ($c) = @_;
+
+ my $jsonp = $c->req->param('callback');
+ if ($jsonp && $jsonp =~ m/^[\w\.\[\]]+$/) {
+
+ # We remove callback param so it doesn't go any further.
+ # ElasticSearch for example supports JSONP calls too
+ $c->req->param('callback', undef);
+
+ # Made it private, but maybe there is a
+ # better way to hide stash parameter
+ $c->stash->{_jsonp} = $jsonp;
+ }
+};
+
+after _END => sub {
+ my $self = shift;
+ my ($c) = @_;
+
+ if (my $jsonp = delete $c->stash->{_jsonp}) {
+ $c->res->content_type('text/javascript; charset=utf-8');
+
+ my $body = $c->res->output();
+ $body = "$jsonp($body);";
+
+ # This is needed for the correct JSONP response
+ # because we have JSON already in bytes
+ $body = decode('UTF-8', $body);
+
+ $c->res->output($body);
+ }
+
+ return 1;
+};
+
+1;
diff --git a/lib/MetaCPAN/Server/Controller/Author.pm b/lib/MetaCPAN/Server/Controller/Author.pm
index 1d9bd27..1bf1b12 100644
--- a/lib/MetaCPAN/Server/Controller/Author.pm
+++ b/lib/MetaCPAN/Server/Controller/Author.pm
@@ -1,6 +1,7 @@
package MetaCPAN::Server::Controller::Author;
use Moose;
BEGIN { extends 'MetaCPAN::Server::Controller' }
+with 'MetaCPAN::Role::JSONP';
sub index : Chained('/') : PathPart('author') : CaptureArgs(0) {
}
diff --git a/t/server/controller/author.t b/t/server/controller/author.t
index 18acdf5..a71b513 100644
--- a/t/server/controller/author.t
+++ b/t/server/controller/author.t
@@ -26,7 +26,14 @@ test_psgi app, sub {
if ( $k eq '/author/_mapping' );
}
- ok( my $res = $cb->(
+ my $res = $cb->( GET '/author/MO?callback=jsonp'), "GET jsonp";
+ is( $res->header('content-type'),
+ 'text/javascript; charset=utf-8',
+ 'Content-type'
+ );
+ like( $res->content, qr/^jsonp\(.*\);$/ms );
+
+ ok( $res = $cb->(
POST '/author/_search',
#'Content-type' => 'application/json',
Content => '{"query":{"match_all":{}},"size":0}'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment