Rubber-stamped by Brady Eidson.
[webbrowser.git] / BugsSite / Bugzilla / WebService.pm
blob0e429241d686c58e025b04c012ec960e012a4518
1 # -*- Mode: perl; indent-tabs-mode: nil -*-
3 # The contents of this file are subject to the Mozilla Public
4 # License Version 1.1 (the "License"); you may not use this file
5 # except in compliance with the License. You may obtain a copy of
6 # the License at http://www.mozilla.org/MPL/
8 # Software distributed under the License is distributed on an "AS
9 # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10 # implied. See the License for the specific language governing
11 # rights and limitations under the License.
13 # The Original Code is the Bugzilla Bug Tracking System.
15 # Contributor(s): Marc Schumann <wurblzap@gmail.com>
16 # Max Kanat-Alexander <mkanat@bugzilla.org>
18 package Bugzilla::WebService;
20 use strict;
21 use Bugzilla::WebService::Constants;
22 use Bugzilla::Util;
23 use Date::Parse;
25 sub fail_unimplemented {
26 my $this = shift;
28 die SOAP::Fault
29 ->faultcode(ERROR_UNIMPLEMENTED)
30 ->faultstring('Service Unimplemented');
33 sub datetime_format {
34 my ($self, $date_string) = @_;
36 my $time = str2time($date_string);
37 my ($sec, $min, $hour, $mday, $mon, $year) = localtime $time;
38 # This format string was stolen from SOAP::Utils->format_datetime,
39 # which doesn't work but which has almost the right format string.
40 my $iso_datetime = sprintf('%d%02d%02dT%02d:%02d:%02d',
41 $year + 1900, $mon + 1, $mday, $hour, $min, $sec);
42 return $iso_datetime;
45 sub handle_login {
46 my ($classes, $action, $uri, $method) = @_;
48 my $class = $classes->{$uri};
49 eval "require $class";
51 return if $class->login_exempt($method);
52 Bugzilla->login();
54 # Even though we check for the need to redirect in
55 # Bugzilla->login() we check here again since Bugzilla->login()
56 # does not know what the current XMLRPC method is. Therefore
57 # ssl_require_redirect in Bugzilla->login() will have returned
58 # false if system was configured to redirect for authenticated
59 # sessions and the user was not yet logged in.
60 # So here we pass in the method name to ssl_require_redirect so
61 # it can then check for the extra case where the method equals
62 # User.login, which we would then need to redirect if not
63 # over a secure connection.
64 my $full_method = $uri . "." . $method;
65 Bugzilla->cgi->require_https(Bugzilla->params->{'sslbase'})
66 if ssl_require_redirect($full_method);
68 return;
71 # For some methods, we shouldn't call Bugzilla->login before we call them
72 use constant LOGIN_EXEMPT => { };
74 sub login_exempt {
75 my ($class, $method) = @_;
77 return $class->LOGIN_EXEMPT->{$method};
82 package Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI;
83 use strict;
84 eval { require XMLRPC::Transport::HTTP; };
85 our @ISA = qw(XMLRPC::Transport::HTTP::CGI);
87 sub initialize {
88 my $self = shift;
89 my %retval = $self->SUPER::initialize(@_);
90 $retval{'serializer'} = Bugzilla::WebService::XMLRPC::Serializer->new;
91 return %retval;
94 sub make_response {
95 my $self = shift;
97 $self->SUPER::make_response(@_);
99 # XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
100 # its cookies in Bugzilla::CGI, so we need to copy them over.
101 foreach (@{Bugzilla->cgi->{'Bugzilla_cookie_list'}}) {
102 $self->response->headers->push_header('Set-Cookie', $_);
108 # This package exists to fix a UTF-8 bug in SOAP::Lite.
109 # See http://rt.cpan.org/Public/Bug/Display.html?id=32952.
110 package Bugzilla::WebService::XMLRPC::Serializer;
111 use strict;
112 # We can't use "use base" because XMLRPC::Serializer doesn't return
113 # a true value.
114 eval { require XMLRPC::Lite; };
115 our @ISA = qw(XMLRPC::Serializer);
117 sub new {
118 my $class = shift;
119 my $self = $class->SUPER::new(@_);
120 # This fixes UTF-8.
121 $self->{'_typelookup'}->{'base64'} =
122 [10, sub { !utf8::is_utf8($_[0]) && $_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/},
123 'as_base64'];
124 # This makes arrays work right even though we're a subclass.
125 # (See http://rt.cpan.org//Ticket/Display.html?id=34514)
126 $self->{'_encodingStyle'} = '';
127 return $self;
130 sub as_string {
131 my $self = shift;
132 my ($value) = @_;
133 # Something weird happens with XML::Parser when we have upper-ASCII
134 # characters encoded as UTF-8, and this fixes it.
135 utf8::encode($value) if utf8::is_utf8($value)
136 && $value =~ /^[\x00-\xff]+$/;
137 return $self->SUPER::as_string($value);
142 __END__
144 =head1 NAME
146 Bugzilla::WebService - The Web Service interface to Bugzilla
148 =head1 DESCRIPTION
150 This is the standard API for external programs that want to interact
151 with Bugzilla. It provides various methods in various modules.
153 Currently the only method of accessing the API is via XML-RPC. The XML-RPC
154 standard is described here: L<http://www.xmlrpc.com/spec>
156 The endpoint for Bugzilla WebServices is the C<xmlrpc.cgi> script in
157 your Bugzilla installation. For example, if your Bugzilla is at
158 C<bugzilla.yourdomain.com>, then your XML-RPC client would access the
159 API via: C<http://bugzilla.yourdomain.com/xmlrpc.cgi>
161 =head1 CALLING METHODS
163 Methods are called in the normal XML-RPC fashion. Bugzilla does not currently
164 implement any extensions to the standard method of XML-RPC method calling.
166 Methods are grouped into "packages", like C<Bug> for
167 L<Bugzilla::WebService::Bug>. So, for example,
168 L<Bugzilla::WebService::Bug/get>, is called as C<Bug.get> in XML-RPC.
170 =head1 PARAMETERS
172 In addition to the standard parameter types like C<int>, C<string>, etc.,
173 XML-RPC has two data structures, a C<< <struct> >> and an C<< <array> >>.
175 =head2 Structs
177 In Perl, we call a C<< <struct> >> a "hash" or a "hashref". You may see
178 us refer to it that way in the API documentation.
180 In example code, you will see the characters C<{> and C<}> used to represent
181 the beginning and end of structs.
183 For example, here's a struct in XML-RPC:
185 <struct>
186 <member>
187 <name>fruit</name>
188 <value><string>oranges</string></value>
189 </member>
190 <member>
191 <name>vegetable</name>
192 <value><string>lettuce</string></value>
193 </member>
194 </struct>
196 In our example code in these API docs, that would look like:
198 { fruit => 'oranges', vegetable => 'lettuce' }
200 =head2 Arrays
202 In example code, you will see the characters C<[> and C<]> used to
203 represent the beginning and end of arrays.
205 For example, here's an array in XML-RPC:
207 <array>
208 <data>
209 <value><i4>1</i4></value>
210 <value><i4>2</i4></value>
211 <value><i4>3</i4></value>
212 </data>
213 </array>
215 In our example code in these API docs, that would look like:
217 [1, 2, 3]
219 =head2 How Bugzilla WebService Methods Take Parameters
221 B<All> Bugzilla WebServices functions take their parameters in
222 a C<< <struct> >>. Another way of saying this would be: All functions
223 take a single argument, a C<< <struct> >> that contains all parameters.
224 The names of the parameters listed in the API docs for each function are
225 the C<name> element for the struct C<member>s.
227 =head1 LOGGING IN
229 You can use L<Bugzilla::WebService::User/login> to log in as a Bugzilla
230 user. This issues standard HTTP cookies that you must then use in future
231 calls, so your XML-RPC client must be capable of receiving and transmitting
232 cookies.
234 =head1 STABLE, EXPERIMENTAL, and UNSTABLE
236 Methods are marked B<STABLE> if you can expect their parameters and
237 return values not to change between versions of Bugzilla. You are
238 best off always using methods marked B<STABLE>. We may add parameters
239 and additional items to the return values, but your old code will
240 always continue to work with any new changes we make. If we ever break
241 a B<STABLE> interface, we'll post a big notice in the Release Notes,
242 and it will only happen during a major new release.
244 Methods (or parts of methods) are marked B<EXPERIMENTAL> if
245 we I<believe> they will be stable, but there's a slight chance that
246 small parts will change in the future.
248 Certain parts of a method's description may be marked as B<UNSTABLE>,
249 in which case those parts are not guaranteed to stay the same between
250 Bugzilla versions.
252 =head1 ERRORS
254 If a particular webservice call fails, it will throw a standard XML-RPC
255 error. There will be a numeric error code, and then the description
256 field will contain descriptive text of the error. Each error that Bugzilla
257 can throw has a specific code that will not change between versions of
258 Bugzilla.
260 The various errors that functions can throw are specified by the
261 documentation of those functions.
263 If your code needs to know what error Bugzilla threw, use the numeric
264 code. Don't try to parse the description, because that may change
265 from version to version of Bugzilla.
267 Note that if you display the error to the user in an HTML program, make
268 sure that you properly escape the error, as it will not be HTML-escaped.
270 =head2 Transient vs. Fatal Errors
272 If the error code is a number greater than 0, the error is considered
273 "transient," which means that it was an error made by the user, not
274 some problem with Bugzilla itself.
276 If the error code is a number less than 0, the error is "fatal," which
277 means that it's some error in Bugzilla itself that probably requires
278 administrative attention.
280 Negative numbers and positive numbers don't overlap. That is, if there's
281 an error 302, there won't be an error -302.
283 =head2 Unknown Errors
285 Sometimes a function will throw an error that doesn't have a specific
286 error code. In this case, the code will be C<-32000> if it's a "fatal"
287 error, and C<32000> if it's a "transient" error.