Puncheur

 view release on metacpan or  search on metacpan

lib/Puncheur/Plugin/JSON.pm  view on Meta::CPAN

package Puncheur::Plugin::JSON;
use 5.010;
use strict;
use warnings;
use JSON;

our @EXPORT = qw/res_json/;

sub res_json {
    my ($self, $data) = @_;

    state $json = JSON->new->ascii(1);
    state $escape = {
        '+' => '\\u002b', # do not eval as UTF-7
        '<' => '\\u003c', # do not eval as HTML
        '>' => '\\u003e', # ditto.
    };
    my $body = $json->encode($data);
    $body =~ s!([+<>])!$escape->{$1}!g;

    my $user_agent = $self->req->user_agent || '';
    # defense from JSON hijacking
    if (
        (!$self->request->header('X-Requested-With')) &&
        $user_agent =~ /android/i                     &&
        defined $self->req->header('Cookie')          &&
        ($self->req->method||'GET') eq 'GET')
    {
        my $content = "Your request may be JSON hijacking.\nIf you are not an attacker, please add 'X-Requested-With' header to each request.";
        return $self->create_response(
            403,
            [
                'Content-Type'   => $self->html_content_type,
                'Content-Length' => length($content),
            ],
            [$content],
        );
    }

    my $encoding = $self->encoding;
    $encoding = lc $encoding->mime_name if ref $encoding;

    # add UTF-8 BOM if the client is Safari
    if ( $user_agent =~ m/Safari/ and $encoding eq 'utf-8' ) {
        $body = "\xEF\xBB\xBF" . $body;
    }

    return $self->create_response(
        200,
        [
            'Content-type'   => "application/json; charset=$encoding",
            'Content-Length' => length($body)
        ],
        [ $body ]
    );
}

1;



( run in 1.067 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )