1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4# 5# This Source Code Form is "Incompatible With Secondary Licenses", as 6# defined by the Mozilla Public License, v. 2.0. 7 8package Bugzilla::WebService::Server; 9 10use 5.10.1; 11use strict; 12use warnings; 13 14use Bugzilla::Error; 15use Bugzilla::Util qw(datetime_from); 16 17use Scalar::Util qw(blessed); 18use Digest::MD5 qw(md5_base64); 19 20use Storable qw(freeze); 21 22sub handle_login { 23 my ($self, $class, $method, $full_method) = @_; 24 # Throw error if the supplied class does not exist or the method is private 25 ThrowCodeError('unknown_method', {method => $full_method}) if (!$class or $method =~ /^_/); 26 27 eval "require $class"; 28 ThrowCodeError('unknown_method', {method => $full_method}) if $@; 29 return if ($class->login_exempt($method) 30 and !defined Bugzilla->input_params->{Bugzilla_login}); 31 Bugzilla->login(); 32 33 Bugzilla::Hook::process( 34 'webservice_before_call', 35 { 'method' => $method, full_method => $full_method }); 36} 37 38sub datetime_format_inbound { 39 my ($self, $time) = @_; 40 41 my $converted = datetime_from($time, Bugzilla->local_timezone); 42 if (!defined $converted) { 43 ThrowUserError('illegal_date', { date => $time }); 44 } 45 $time = $converted->ymd() . ' ' . $converted->hms(); 46 return $time 47} 48 49sub datetime_format_outbound { 50 my ($self, $date) = @_; 51 52 return undef if (!defined $date or $date eq ''); 53 54 my $time = $date; 55 if (blessed($date)) { 56 # We expect this to mean we were sent a datetime object 57 $time->set_time_zone('UTC'); 58 } else { 59 # We always send our time in UTC, for consistency. 60 # passed in value is likely a string, create a datetime object 61 $time = datetime_from($date, 'UTC'); 62 } 63 return $time->iso8601(); 64} 65 66# ETag support 67sub bz_etag { 68 my ($self, $data) = @_; 69 my $cache = Bugzilla->request_cache; 70 if (defined $data) { 71 # Serialize the data if passed a reference 72 local $Storable::canonical = 1; 73 $data = freeze($data) if ref $data; 74 75 # Wide characters cause md5_base64() to die. 76 utf8::encode($data) if utf8::is_utf8($data); 77 78 # Append content_type to the end of the data 79 # string as we want the etag to be unique to 80 # the content_type. We do not need this for 81 # XMLRPC as text/xml is always returned. 82 if (blessed($self) && $self->can('content_type')) { 83 $data .= $self->content_type if $self->content_type; 84 } 85 86 $cache->{'bz_etag'} = md5_base64($data); 87 } 88 return $cache->{'bz_etag'}; 89} 90 911; 92 93=head1 NAME 94 95Bugzilla::WebService::Server - Base server class for the WebService API 96 97=head1 DESCRIPTION 98 99Bugzilla::WebService::Server is the base class for the individual WebService API 100servers such as XMLRPC, JSONRPC, and REST. You never actually create a 101Bugzilla::WebService::Server directly, you only make subclasses of it. 102 103=head1 FUNCTIONS 104 105=over 106 107=item C<bz_etag> 108 109This function is used to store an ETag value that will be used when returning 110the data by the different API server modules such as XMLRPC, or REST. The individual 111webservice methods can also set the value earlier in the process if needed such as 112before a unique update token is added. If a value is not set earlier, an etag will 113automatically be created using the returned data except in some cases when an error 114has occurred. 115 116=back 117 118=head1 SEE ALSO 119 120L<Bugzilla::WebService::Server::XMLRPC|XMLRPC>, L<Bugzilla::WebService::Server::JSONRPC|JSONRPC>, 121and L<Bugzilla::WebService::Server::REST|REST>. 122 123=head1 B<Methods in need of POD> 124 125=over 126 127=item handle_login 128 129=item datetime_format_outbound 130 131=item datetime_format_inbound 132 133=back 134