Amon2-Plugin-Web-CpanelJSON
view release on metacpan or search on metacpan
lib/Amon2/Plugin/Web/CpanelJSON.pm view on Meta::CPAN
defence_json_hijacking_for_legacy_browser => !!0,
);
sub init {
my ($class, $c, $conf) = @_;
$conf = do {
$conf ||= {};
for my $key (qw/secure_headers json_escape_filter json/) {
if (exists $conf->{$key} && !defined $conf->{$key}) {
$conf->{$key} = undef;
}
else {
$conf->{$key} = {
%{ $DEFAULT_CONFIG{$key} },
%{ $conf->{$key} || {} },
}
}
}
+{ %DEFAULT_CONFIG, %{$conf} };
};
my $name = $conf->{name};
unless ($c->can($name)) {
my $render_json = _generate_render_json($conf);
Amon2::Util::add_method($c, $name, $render_json)
}
}
sub _generate_render_json {
my $conf = shift;
my $encoder = _generate_json_encoder($conf);
my $validator = _generate_req_validator($conf);
my $secure_headers;
if ($conf->{secure_headers}) {
$secure_headers = HTTP::SecureHeaders->new(%{ $conf->{secure_headers} });
}
return sub {
my ($c, $data, $spec, $status) = @_;
$status //= 200;
if (my $error = $validator->($c)) {
return $error;
}
my $output = $encoder->($data, $spec);
my $res = do {
my $res = $c->create_response($status);
my $encoding = $c->encoding();
$encoding = lc($encoding->mime_name) if ref $encoding;
$res->content_type("application/json; charset=$encoding");
$res->content_length(length($output));
$res->body($output);
if ($secure_headers) {
$secure_headers->apply($res->headers);
}
# X-API-Status
# (Japanese) http://web.archive.org/web/20190503111531/http://blog.yappo.jp/yappo/archives/000829.html
if (my $status_code_field = $conf->{status_code_field}) {
if (exists $data->{$status_code_field}) {
$res->header('X-API-Status' => $data->{$status_code_field})
}
}
$res
};
return $res;
}
}
sub _generate_json_encoder {
my $conf = shift;
my $json = Cpanel::JSON::XS->new;
if (my $json_args = $conf->{json}) {
for my $key (keys %{$json_args}) {
$json->$key($json_args->{$key})
}
}
my $escape_filter = $conf->{json_escape_filter} || {};
my $escape_target = '';
for my $key (keys %{$escape_filter}) {
if ($escape_filter->{$key}) {
$escape_target .= $key
}
}
return sub {
my ($data, $spec) = @_;
if (my $unbless_object = $conf->{unbless_object}) {
if (blessed($data)) {
$data = $unbless_object->($data, $spec);
}
}
my $output = $json->encode($data, $spec);
if ($escape_target && $escape_filter) {
$output =~ s!([$escape_target])!$escape_filter->{$1}!g;
}
return $output;
}
}
sub _generate_req_validator {
( run in 1.981 second using v1.01-cache-2.11-cpan-5735350b133 )