Skip to content

Instantly share code, notes, and snippets.

@vti
Created September 1, 2011 18:37
Show Gist options
  • Save vti/1186895 to your computer and use it in GitHub Desktop.
Save vti/1186895 to your computer and use it in GitHub Desktop.
metacpan jsonp
diff --git a/lib/MetaCPAN/Server.pm b/lib/MetaCPAN/Server.pm
index 75f687d..2f0d103 100755
--- a/lib/MetaCPAN/Server.pm
+++ b/lib/MetaCPAN/Server.pm
@@ -1,9 +1,10 @@
package MetaCPAN::Server;
+use lib 'lib';
use Moose;
extends 'Catalyst';
use CatalystX::RoleApplicator;
-use Plack::Middleware::ReverseProxy;
+use Plack::Builder;
use FindBin;
use lib "$FindBin::RealBin/../";
@@ -72,8 +73,11 @@ __PACKAGE__->setup(
__PACKAGE__->setup_engine('PSGI');
__PACKAGE__->meta->make_immutable( replace_constructor => 1 );
-Plack::Middleware::ReverseProxy->wrap(
- sub {
- __PACKAGE__->run(@_);
- }
-);
+builder {
+ enable 'ReverseProxy';
+
+ enable_if { $_[0]->{PATH_INFO} =~ m!^/(?:author|OTHER ALLOWED PATHS GO HERE)(?:/|$)! }
+ 'JSONP::ElasticSearch';
+
+ sub { __PACKAGE__->run(@_) };
+}
diff --git a/lib/Plack/Middleware/JSONP/ElasticSearch.pm b/lib/Plack/Middleware/JSONP/ElasticSearch.pm
new file mode 100644
index 0000000..5e9b100
--- /dev/null
+++ b/lib/Plack/Middleware/JSONP/ElasticSearch.pm
@@ -0,0 +1,43 @@
+package Plack::Middleware::JSONP::ElasticSearch;
+use strict;
+use parent qw(Plack::Middleware::JSONP);
+use Plack::Util;
+use URI::Escape ();
+
+sub call {
+ my ($self, $env) = @_;
+
+ my $callback_key = $self->callback_key;
+
+ # We cut off jsonp callback parameter because we don't want
+ # it to get to ElasticSearch (otherwise we get already wrapped
+ # JSONP response that metacpan tries to parse as JSON)
+ my $callback;
+ if ($env->{QUERY_STRING} =~ s/(?:^|&)$callback_key=([^&]+)//) {
+ $callback = URI::Escape::uri_unescape($1);
+ $callback = undef unless $callback =~ /^[\w\.\[\]]+$/;
+ }
+
+ my $res = $self->app->($env);
+ return $res unless defined $callback;
+
+ $self->response_cb(
+ $res,
+ sub {
+ my $res = shift;
+ if (defined $res->[2]) {
+ my $h = Plack::Util::headers($res->[1]);
+ if ($h->get('Content-Type') =~ m!/(?:json|javascript)!) {
+ my $body;
+ Plack::Util::foreach($res->[2], sub { $body .= $_[0] });
+ my $jsonp = "$callback($body)";
+ $res->[2] = [$jsonp];
+ $h->set('Content-Length', length $jsonp);
+ $h->set('Content-Type', 'text/javascript');
+ }
+ }
+ }
+ );
+}
+
+1;
diff --git a/t/plack/middleware/jsonp-elastic-search.t b/t/plack/middleware/jsonp-elastic-search.t
new file mode 100644
index 0000000..c3671a1
--- /dev/null
+++ b/t/plack/middleware/jsonp-elastic-search.t
@@ -0,0 +1,33 @@
+use strict;
+use Test::More;
+use Plack::Test;
+use Plack::Builder;
+
+my @json = ('{"foo":', '"bar"}');
+my $json = join '', @json;
+
+my $app = sub {
+ is($_[0]->{QUERY_STRING}, '');
+
+ return [200, ['Content-Type' => 'application/json'], [@json]];
+};
+$app = builder {
+ enable "Plack::Middleware::JSONP::ElasticSearch";
+ $app;
+};
+
+test_psgi
+ app => $app,
+ client => sub {
+ my $cb = shift;
+
+ my $res = $cb->(HTTP::Request->new(GET => 'http://localhost/'));
+ is $res->content_type, 'application/json';
+ is $res->content, $json;
+
+ $res = $cb->(HTTP::Request->new(GET => 'http://localhost/?callback=foo'));
+ is $res->content_type, 'text/javascript';
+ is $res->content, "foo($json)";
+ };
+
+done_testing;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment