Commit 62efd548 authored by Max Kanat-Alexander's avatar Max Kanat-Alexander

Bug 550727: Add JSONP Support to the JSON-RPC WebService Interface

r=dkl, a=mkanat
parent 68af4d3c
......@@ -28,7 +28,7 @@ use Bugzilla::Error;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Util qw(taint_data);
use Bugzilla::Util qw(correct_urlbase);
use Bugzilla::Util qw(correct_urlbase trim);
#####################################
# Public JSON::RPC Method Overrides #
......@@ -58,11 +58,19 @@ sub create_json_coder {
# Override the JSON::RPC method to return our CGI object instead of theirs.
sub cgi { return Bugzilla->cgi; }
# Override the JSON::RPC method to use $cgi->header properly instead of
# just printing text directly. This fixes various problems, including
# sending Bugzilla's cookies properly.
sub response {
my ($self, $response) = @_;
# Implement JSONP.
if (my $callback = $self->_bz_callback) {
my $content = $response->content;
$response->content("$callback($content)");
}
# Use $cgi->header properly instead of just printing text directly.
# This fixes various problems, including sending Bugzilla's cookies
# properly.
my $headers = $response->headers;
my @header_args;
foreach my $name ($headers->header_field_names) {
......@@ -118,6 +126,10 @@ sub retrieve_json_from_get {
# before _handle.
$self->{_bz_request_id} = $input{id} = $id;
# _bz_callback can throw an error, so we have to set it here, after we're
# ready to throw errors.
$self->_bz_callback(scalar $cgi->param('callback'));
if (!$cgi->param('method')) {
ThrowUserError('json_rpc_get_method_required');
}
......@@ -345,11 +357,30 @@ sub _argument_type_check {
return $params;
}
##########################
# Private Custom Methods #
##########################
# _bz_method_name is stored by _find_procedure for later use.
sub _bz_method_name {
return $_[0]->{_bz_method_name};
}
sub _bz_callback {
my ($self, $value) = @_;
if (defined $value) {
$value = trim($value);
# We don't use \w because we don't want to allow Unicode here.
if ($value !~ /^[A-Za-z0-1_\.\[\]]+$/) {
ThrowUserError('json_rpc_invalid_callback', { callback => $value });
}
$self->{_bz_callback} = $value;
# JSONP needs to be parsed by a JS parser, not by a JSON parser.
$self->content_type('text/javascript');
}
return $self->{_bz_callback};
}
1;
__END__
......@@ -419,6 +450,36 @@ what version of the JSON-RPC protocol you're using, and C<id> as a URL
parameter if you want there to be a specific C<id> value in the returned
JSON-RPC response.
=head2 JSONP
When calling the JSON-RPC WebService over GET, you can use the "JSONP"
method of doing cross-domain requests, if you want to access the WebService
directly on a web page from another site. JSONP is described at
L<http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/>.
To use JSONP with Bugzilla's JSON-RPC WebService, simply specify a
C<callback> parameter to jsonrpc.cgi when using it via GET as described above.
For example, here's some HTML you could use to get the data from
C<Bugzilla.time> on a remote website, using JSONP:
<script type="text/javascript"
src="http://bugzilla.example.com/jsonrpc.cgi?method=Bugzilla.time&amp;callback=foo">
That would call the C<Bugzilla.time> method and pass its value to a function
called C<foo> as the only argument. All the other URL parameters (such as
C<params>, for passing in arguments to methods) that can be passed to
C<jsonrpc.cgi> during GET requests are also available, of course. The above
is just the simplest possible example.
The values returned when using JSONP are identical to the values returned
when not using JSONP, so you will also get error messages if there is an
error.
The C<callback> URL parameter may only contain letters, numbers, periods, and
the underscore (C<_>) character. Including any other characters will cause
Bugzilla to throw an error. (This error will be a normal JSON-RPC response,
not JSONP.)
=head1 PARAMETERS
For JSON-RPC 1.0, the very first parameter should be an object containing
......
......@@ -989,6 +989,11 @@
Error: [% err_msg FILTER html %]
Value: [% params FILTER html %]
[% ELSIF error == "json_rpc_invalid_callback" %]
You cannot use '[% callback FILTER html %]' as your 'callback' parameter.
For security reasons, only letters, numbers, and the following
characters are allowed in the 'callback' parameter: <code>[]._</code>
[% ELSIF error == "json_rpc_post_only" %]
For security reasons, you may only call the '[% method FILTER html %]'
method via HTTP POST.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment