summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/WebService/Server/JSONRPC.pm69
-rw-r--r--template/en/default/global/user-error.html.tmpl5
2 files changed, 70 insertions, 4 deletions
diff --git a/Bugzilla/WebService/Server/JSONRPC.pm b/Bugzilla/WebService/Server/JSONRPC.pm
index ae479ff5e..5ab5e4a7b 100644
--- a/Bugzilla/WebService/Server/JSONRPC.pm
+++ b/Bugzilla/WebService/Server/JSONRPC.pm
@@ -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
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index d866f301d..698eed8fb 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -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.