shell bypass 403
##############################################################################
# JSONRPC version 1.1
# http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html
##############################################################################
use strict;
use JSON ();
use Carp ();
##############################################################################
package JSON::RPC::Legacy::Client;
$JSON::RPC::Legacy::Client::VERSION = '1.06';
use LWP::UserAgent;
BEGIN {
for my $method (qw/uri ua json content_type version id allow_call status_line/) {
eval qq|
sub $method {
\$_[0]->{$method} = \$_[1] if defined \$_[1];
\$_[0]->{$method};
}
|;
}
}
sub AUTOLOAD {
my $self = shift;
my $method = $JSON::RPC::Legacy::Client::AUTOLOAD;
$method =~ s/.*:://;
return if ($method eq 'DESTROY');
$method =~ s/^__(\w+)__$/$1/; # avoid to call built-in methods (ex. __VERSION__ => VERSION)
unless ( exists $self->allow_call->{ $method } ) {
Carp::croak("Can't call the method not allowed by prepare().");
}
my @params = @_;
my $obj = {
method => $method,
params => (ref $_[0] ? $_[0] : [@_]),
};
my $ret = $self->call($self->uri, $obj);
if ( $ret and $ret->is_success ) {
return $ret->result;
}
else {
Carp::croak ( $ret ? '(Procedure error) ' . $ret->error_message : $self->status_line );
}
}
sub create_json_coder {
JSON->new->allow_nonref->utf8;
}
sub new {
my $proto = shift;
my $self = bless {}, (ref $proto ? ref $proto : $proto);
my $ua = LWP::UserAgent->new(
agent => 'JSON::RPC::Legacy::Client/' . $JSON::RPC::Legacy::Client::VERSION . ' beta ',
timeout => 10,
);
$self->ua($ua);
$self->json( $proto->create_json_coder );
$self->version('1.1');
$self->content_type('application/json');
return $self;
}
sub prepare {
my ($self, $uri, $procedures) = @_;
$self->uri($uri);
$self->allow_call({ map { ($_ => 1) } @$procedures });
}
sub call {
my ($self, $uri, $obj) = @_;
my $result;
if ($uri =~ /\?/) {
$result = $self->_get($uri);
}
else {
Carp::croak "not hashref." unless (ref $obj eq 'HASH');
$result = $self->_post($uri, $obj);
}
my $service = $obj->{method} =~ /^system\./ if ( $obj );
$self->status_line($result->status_line);
return unless($result->content); # notification?
if ($service) {
return JSON::RPC::Legacy::ServiceObject->new($result, $self->json);
}
return JSON::RPC::Legacy::ReturnObject->new($result, $self->json);
}
sub _post {
my ($self, $uri, $obj) = @_;
my $json = $self->json;
$obj->{version} ||= $self->{version} || '1.1';
if ($obj->{version} eq '1.0') {
delete $obj->{version};
if (exists $obj->{id}) {
$self->id($obj->{id}) if ($obj->{id}); # if undef, it is notification.
}
else {
$obj->{id} = $self->id || ($self->id('JSON::RPC::Legacy::Client'));
}
}
else {
$obj->{id} = $self->id if (defined $self->id);
}
my $content = $json->encode($obj);
$self->ua->post(
$uri,
Content_Type => $self->{content_type},
Content => $content,
Accept => 'application/json',
);
}
sub _get {
my ($self, $uri) = @_;
$self->ua->get(
$uri,
Accept => 'application/json',
);
}
##############################################################################
package JSON::RPC::Legacy::ReturnObject;
$JSON::RPC::Legacy::ReturnObject::VERSION = $JSON::RPC::Legacy::VERSION;
BEGIN {
for my $method (qw/is_success content jsontext version/) {
eval qq|
sub $method {
\$_[0]->{$method} = \$_[1] if defined \$_[1];
\$_[0]->{$method};
}
|;
}
}
sub new {
my ($class, $obj, $json) = @_;
my $content = ( $json || JSON->new->utf8 )->decode( $obj->content );
my $self = bless {
jsontext => $obj->content,
content => $content,
}, $class;
$content->{error} ? $self->is_success(0) : $self->is_success(1);
$content->{version} ? $self->version(1.1) : $self->version(0) ;
$self;
}
sub is_error { !$_[0]->is_success; }
sub error_message {
$_[0]->version ? $_[0]->{content}->{error}->{message} : $_[0]->{content}->{error};
}
sub result {
$_[0]->{content}->{result};
}
##############################################################################
package JSON::RPC::Legacy::ServiceObject;
use base qw(JSON::RPC::Legacy::ReturnObject);
sub sdversion {
$_[0]->{content}->{sdversion} || '';
}
sub name {
$_[0]->{content}->{name} || '';
}
sub result {
$_[0]->{content}->{summary} || '';
}
1;
__END__
=pod
=head1 NAME
JSON::RPC::Legacy::Client - Perl implementation of JSON-RPC client
=head1 SYNOPSIS
use JSON::RPC::Legacy::Client;
my $client = new JSON::RPC::Legacy::Client;
my $url = 'http://www.example.com/jsonrpc/API';
my $callobj = {
method => 'sum',
params => [ 17, 25 ], # ex.) params => { a => 20, b => 10 } for JSON-RPC v1.1
};
my $res = $client->call($uri, $callobj);
if($res) {
if ($res->is_error) {
print "Error : ", $res->error_message;
}
else {
print $res->result;
}
}
else {
print $client->status_line;
}
# Easy access
$client->prepare($uri, ['sum', 'echo']);
print $client->sum(10, 23);
=head1 DESCRIPTION
This is JSON-RPC Client.
See L<http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html>.
Gets a perl object and convert to a JSON request data.
Sends the request to a server.
Gets a response returned by the server.
Converts the JSON response data to the perl object.
=head1 JSON::RPC::Legacy::Client
=head2 METHODS
=over
=item $client = JSON::RPC::Legacy::Client->new
Creates new JSON::RPC::Legacy::Client object.
=item $response = $client->call($uri, $procedure_object)
Calls to $uri with $procedure_object.
The request method is usually C<POST>.
If $uri has query string, method is C<GET>.
About 'GET' method,
see to L<http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html#GetProcedureCall>.
Return value is L</JSON::RPC::Legacy::ReturnObject>.
=item $client->prepare($uri, $arrayref_of_procedure)
Allow to call methods in contents of $arrayref_of_procedure.
Then you can call the prepared methods with an array reference or a list.
The return value is a result part of JSON::RPC::Legacy::ReturnObject.
$client->prepare($uri, ['sum', 'echo']);
$res = $client->echo('foobar'); # $res is 'foobar'.
$res = $client->sum(10, 20); # sum up
$res = $client->sum( [10, 20] ); # same as above
If you call a method which is not prepared, it will C<croak>.
Currently, B<can't call any method names as same as built-in methods>.
=item version
Sets the JSON-RPC protocol version.
1.1 by default.
=item id
Sets a request identifier.
In JSON-RPC 1.1, it is optional.
If you set C<version> 1.0 and don't set id,
the module sets 'JSON::RPC::Legacy::Client' to it.
=item ua
Setter/getter to L<LWP::UserAgent> object.
=item json
Setter/getter to the JSON coder object.
Default is L<JSON>, likes this:
$self->json( JSON->new->allow_nonref->utf8 );
$json = $self->json;
This object serializes/deserializes JSON data.
By default, returned JSON data assumes UTF-8 encoded.
=item status_line
Returns status code;
After C<call> a remote procedure, the status code is set.
=item create_json_coder
(Class method)
Returns a JSON de/encoder in C<new>.
You can override it to use your favorite JSON de/encoder.
=back
=head1 JSON::RPC::Legacy::ReturnObject
C<call> method or the methods set by C<prepared> returns this object.
(The returned JSON data is decoded by the JSON coder object which was passed
by the client object.)
=head2 METHODS
=over
=item is_success
If the call is successful, returns a true, otherwise a false.
=item is_error
If the call is not successful, returns a true, otherwise a false.
=item error_message
If the response contains an error message, returns it.
=item result
Returns the result part of a data structure returned by the called server.
=item content
Returns the whole data structure returned by the called server.
=item jsontext
Returns the row JSON data.
=item version
Returns the version of this response data.
=back
=head1 JSON::RPC::Legacy::ServiceObject
=head1 RESERVED PROCEDURE
When a client call a procedure (method) name 'system.foobar',
JSON::RPC::Legacy::Server look up MyApp::system::foobar.
L<http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html#ProcedureCall>
L<http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html#ServiceDescription>
There is JSON::RPC::Legacy::Server::system::describe for default response of 'system.describe'.
=head1 SEE ALSO
L<http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html>
L<http://json-rpc.org/wiki/specification>
=head1 AUTHOR
Makamaka Hannyaharamitu, E<lt>makamaka[at]cpan.orgE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright 2007-2008 by Makamaka Hannyaharamitu
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut