Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etersoft
bugzilla
Commits
6a10905a
Commit
6a10905a
authored
Feb 11, 2009
by
mkanat%bugzilla.org
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 475151: Refactor the XML-RPC server stuff out of Bugzilla::WebService
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat
parent
0b4ee129
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
244 additions
and
198 deletions
+244
-198
WebService.pm
Bugzilla/WebService.pm
+2
-167
Constants.pm
Bugzilla/WebService/Constants.pm
+20
-4
Server.pm
Bugzilla/WebService/Server.pm
+42
-0
XMLRPC.pm
Bugzilla/WebService/Server/XMLRPC.pm
+170
-0
xmlrpc.cgi
xmlrpc.cgi
+10
-27
No files found.
Bugzilla/WebService.pm
View file @
6a10905a
...
...
@@ -15,22 +15,13 @@
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
# This is the base class for $self in WebService method calls. For the
# actual RPC server, see Bugzilla::WebService::Server and its subclasses.
package
Bugzilla::
WebService
;
use
strict
;
use
Bugzilla::WebService::
Constants
;
use
Bugzilla::
Util
;
use
Date::
Parse
;
use
XMLRPC::
Lite
;
sub
fail_unimplemented
{
my
$this
=
shift
;
die
SOAP::
Fault
->
faultcode
(
ERROR_UNIMPLEMENTED
)
->
faultstring
(
'Service Unimplemented'
);
}
sub
datetime_format
{
my
(
$self
,
$date_string
)
=
@_
;
...
...
@@ -43,38 +34,11 @@ sub datetime_format {
return
$iso_datetime
;
}
sub
handle_login
{
my
(
$classes
,
$action
,
$uri
,
$method
)
=
@_
;
my
$class
=
$classes
->
{
$uri
};
eval
"require $class"
;
return
if
$class
->
login_exempt
(
$method
);
Bugzilla
->
login
();
# Even though we check for the need to redirect in
# Bugzilla->login() we check here again since Bugzilla->login()
# does not know what the current XMLRPC method is. Therefore
# ssl_require_redirect in Bugzilla->login() will have returned
# false if system was configured to redirect for authenticated
# sessions and the user was not yet logged in.
# So here we pass in the method name to ssl_require_redirect so
# it can then check for the extra case where the method equals
# User.login, which we would then need to redirect if not
# over a secure connection.
my
$full_method
=
$uri
.
"."
.
$method
;
Bugzilla
->
cgi
->
require_https
(
Bugzilla
->
params
->
{
'sslbase'
})
if
ssl_require_redirect
(
$full_method
);
return
;
}
# For some methods, we shouldn't call Bugzilla->login before we call them
use
constant
LOGIN_EXEMPT
=>
{
};
sub
login_exempt
{
my
(
$class
,
$method
)
=
@_
;
return
$class
->
LOGIN_EXEMPT
->
{
$method
};
}
...
...
@@ -88,135 +52,6 @@ sub type {
1
;
package
Bugzilla::WebService::XMLRPC::Transport::HTTP::
CGI
;
use
strict
;
eval
{
require
XMLRPC::Transport::
HTTP
;
};
our
@ISA
=
qw(XMLRPC::Transport::HTTP::CGI)
;
sub
initialize
{
my
$self
=
shift
;
my
%
retval
=
$self
->
SUPER::
initialize
(
@_
);
$retval
{
'serializer'
}
=
Bugzilla::WebService::XMLRPC::
Serializer
->
new
;
$retval
{
'deserializer'
}
=
Bugzilla::WebService::XMLRPC::
Deserializer
->
new
;
return
%
retval
;
}
sub
make_response
{
my
$self
=
shift
;
$self
->
SUPER::
make_response
(
@_
);
# XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
# its cookies in Bugzilla::CGI, so we need to copy them over.
foreach
(
@
{
Bugzilla
->
cgi
->
{
'Bugzilla_cookie_list'
}})
{
$self
->
response
->
headers
->
push_header
(
'Set-Cookie'
,
$_
);
}
}
1
;
# This exists to validate input parameters (which XMLRPC::Lite doesn't do)
# and also, in some cases, to more-usefully decode them.
package
Bugzilla::WebService::XMLRPC::
Deserializer
;
use
strict
;
# We can't use "use base" because XMLRPC::Serializer doesn't return
# a true value.
eval
{
require
XMLRPC::
Lite
;
};
our
@ISA
=
qw(XMLRPC::Deserializer)
;
use
Bugzilla::
Error
;
# Some method arguments need to be converted in some way, when they are input.
sub
decode_value
{
my
$self
=
shift
;
my
(
$type
)
=
@
{
$_
[
0
]
};
my
$value
=
$self
->
SUPER::
decode_value
(
@_
);
# We only validate/convert certain types here.
return
$value
if
$type
!~
/^(?:int|i4|boolean|double|dateTime\.iso8601)$/
;
# Though the XML-RPC standard doesn't allow an empty <int>,
# <double>,or <dateTime.iso8601>, we do, and we just say
# "that's undef".
if
(
grep
(
$type
eq
$_
,
qw(int double dateTime)
))
{
return
undef
if
$value
eq
''
;
}
my
$validator
=
$self
->
_validation_subs
->
{
$type
};
if
(
!
$validator
->
(
$value
))
{
ThrowUserError
(
'xmlrpc_invalid_value'
,
{
type
=>
$type
,
value
=>
$value
});
}
# We convert dateTimes to a DB-friendly date format.
if
(
$type
eq
'dateTime.iso8601'
)
{
# We leave off the $ from the end of this regex to allow for possible
# extensions to the XML-RPC date standard.
$value
=~
/^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/
;
$value
=
"$1-$2-$3 $4:$5:$6"
;
}
return
$value
;
}
sub
_validation_subs
{
my
$self
=
shift
;
return
$self
->
{
_validation_subs
}
if
$self
->
{
_validation_subs
};
# The only place that XMLRPC::Lite stores any sort of validation
# regex is in XMLRPC::Serializer. We want to re-use those regexes here.
my
$lookup
=
Bugzilla::WebService::XMLRPC::
Serializer
->
new
->
typelookup
;
# $lookup is a hash whose values are arrayrefs, and whose keys are the
# names of types. The second item of each arrayref is a subroutine
# that will do our validation for us.
my
%
validators
=
map
{
$_
=>
$lookup
->
{
$_
}
->
[
1
]
}
(
keys
%
$lookup
);
# Add a boolean validator
$validators
{
'boolean'
}
=
sub
{
$_
[
0
]
=~
/^[01]$/
};
# Some types have multiple names, or have a different name in
# XMLRPC::Serializer than their standard XML-RPC name.
$validators
{
'dateTime.iso8601'
}
=
$validators
{
'dateTime'
};
$validators
{
'i4'
}
=
$validators
{
'int'
};
$self
->
{
_validation_subs
}
=
\%
validators
;
return
\%
validators
;
}
1
;
# This package exists to fix a UTF-8 bug in SOAP::Lite.
# See http://rt.cpan.org/Public/Bug/Display.html?id=32952.
package
Bugzilla::WebService::XMLRPC::
Serializer
;
use
strict
;
# We can't use "use base" because XMLRPC::Serializer doesn't return
# a true value.
eval
{
require
XMLRPC::
Lite
;
};
our
@ISA
=
qw(XMLRPC::Serializer)
;
sub
new
{
my
$class
=
shift
;
my
$self
=
$class
->
SUPER::
new
(
@_
);
# This fixes UTF-8.
$self
->
{
'_typelookup'
}
->
{
'base64'
}
=
[
10
,
sub
{
!
utf8::
is_utf8
(
$_
[
0
])
&&
$_
[
0
]
=~
/[^\x09\x0a\x0d\x20-\x7f]/
},
'as_base64'
];
# This makes arrays work right even though we're a subclass.
# (See http://rt.cpan.org//Ticket/Display.html?id=34514)
$self
->
{
'_encodingStyle'
}
=
''
;
return
$self
;
}
sub
as_string
{
my
$self
=
shift
;
my
(
$value
)
=
@_
;
# Something weird happens with XML::Parser when we have upper-ASCII
# characters encoded as UTF-8, and this fixes it.
utf8::
encode
(
$value
)
if
utf8::
is_utf8
(
$value
)
&&
$value
=~
/^[\x00-\xff]+$/
;
return
$self
->
SUPER::
as_string
(
$value
);
}
1
;
__END__
=head1 NAME
...
...
Bugzilla/WebService/Constants.pm
View file @
6a10905a
...
...
@@ -20,13 +20,13 @@ package Bugzilla::WebService::Constants;
use
strict
;
use
base
qw(Exporter)
;
@
Bugzilla::WebService::Constants::
EXPORT
=
qw(
our
@
EXPORT
=
qw(
WS_ERROR_CODE
ERROR_UNKNOWN_FATAL
ERROR_UNKNOWN_TRANSIENT
ERROR_AUTH_NODATA
ERROR_UNIMPLEMENTED
WS_DISPATCH
)
;
# This maps the error names in global/*-error.html.tmpl to numbers.
...
...
@@ -115,7 +115,23 @@ use constant ERROR_UNKNOWN_FATAL => -32000;
use
constant
ERROR_UNKNOWN_TRANSIENT
=>
32000
;
use
constant
ERROR_AUTH_NODATA
=>
410
;
use
constant
ERROR_UNIMPLEMENTED
=>
910
;
use
constant
ERROR_GENERAL
=>
999
;
sub
WS_DISPATCH
{
# We "require" here instead of "use" above to avoid a dependency loop.
require
Bugzilla::
Hook
;
my
%
hook_dispatch
;
Bugzilla::Hook::
process
(
'webservice'
,
{
dispatch
=>
\%
hook_dispatch
});
my
$dispatch
=
{
'Bugzilla'
=>
'Bugzilla::WebService::Bugzilla'
,
'Bug'
=>
'Bugzilla::WebService::Bug'
,
'User'
=>
'Bugzilla::WebService::User'
,
'Product'
=>
'Bugzilla::WebService::Product'
,
%
hook_dispatch
};
return
$dispatch
;
};
1
;
Bugzilla/WebService/Server.pm
0 → 100644
View file @
6a10905a
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package
Bugzilla::WebService::
Server
;
use
strict
;
use
Bugzilla::
Util
qw(ssl_require_redirect)
;
sub
handle_login
{
my
(
$self
,
$class
,
$method
,
$full_method
)
=
@_
;
eval
"require $class"
;
return
if
$class
->
login_exempt
(
$method
);
Bugzilla
->
login
();
# Even though we check for the need to redirect in
# Bugzilla->login() we check here again since Bugzilla->login()
# does not know what the current XMLRPC method is. Therefore
# ssl_require_redirect in Bugzilla->login() will have returned
# false if system was configured to redirect for authenticated
# sessions and the user was not yet logged in.
# So here we pass in the method name to ssl_require_redirect so
# it can then check for the extra case where the method equals
# User.login, which we would then need to redirect if not
# over a secure connection.
Bugzilla
->
cgi
->
require_https
(
Bugzilla
->
params
->
{
'sslbase'
})
if
ssl_require_redirect
(
$full_method
);
}
1
;
Bugzilla/WebService/Server/XMLRPC.pm
0 → 100644
View file @
6a10905a
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
package
Bugzilla::WebService::Server::
XMLRPC
;
use
strict
;
use
XMLRPC::Transport::
HTTP
;
use
Bugzilla::WebService::
Server
;
our
@ISA
=
qw(XMLRPC::Transport::HTTP::CGI Bugzilla::WebService::Server)
;
use
Bugzilla::WebService::
Constants
;
sub
initialize
{
my
$self
=
shift
;
my
%
retval
=
$self
->
SUPER::
initialize
(
@_
);
$retval
{
'serializer'
}
=
Bugzilla::XMLRPC::
Serializer
->
new
;
$retval
{
'deserializer'
}
=
Bugzilla::XMLRPC::
Deserializer
->
new
;
$retval
{
'dispatch_with'
}
=
WS_DISPATCH
;
return
%
retval
;
}
sub
make_response
{
my
$self
=
shift
;
$self
->
SUPER::
make_response
(
@_
);
# XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
# its cookies in Bugzilla::CGI, so we need to copy them over.
foreach
(
@
{
Bugzilla
->
cgi
->
{
'Bugzilla_cookie_list'
}})
{
$self
->
response
->
headers
->
push_header
(
'Set-Cookie'
,
$_
);
}
}
sub
datetime_format
{
my
(
$self
,
$date_string
)
=
@_
;
my
$time
=
str2time
(
$date_string
);
my
(
$sec
,
$min
,
$hour
,
$mday
,
$mon
,
$year
)
=
localtime
$time
;
# This format string was stolen from SOAP::Utils->format_datetime,
# which doesn't work but which has almost the right format string.
my
$iso_datetime
=
sprintf
(
'%d%02d%02dT%02d:%02d:%02d'
,
$year
+
1900
,
$mon
+
1
,
$mday
,
$hour
,
$min
,
$sec
);
return
$iso_datetime
;
}
sub
handle_login
{
my
(
$self
,
$classes
,
$action
,
$uri
,
$method
)
=
@_
;
my
$class
=
$classes
->
{
$uri
};
my
$full_method
=
$uri
.
"."
.
$method
;
$self
->
SUPER::
handle_login
(
$class
,
$method
,
$full_method
);
return
;
}
1
;
# This exists to validate input parameters (which XMLRPC::Lite doesn't do)
# and also, in some cases, to more-usefully decode them.
package
Bugzilla::XMLRPC::
Deserializer
;
use
strict
;
# We can't use "use base" because XMLRPC::Serializer doesn't return
# a true value.
eval
{
require
XMLRPC::
Lite
;
};
our
@ISA
=
qw(XMLRPC::Deserializer)
;
use
Bugzilla::
Error
;
# Some method arguments need to be converted in some way, when they are input.
sub
decode_value
{
my
$self
=
shift
;
my
(
$type
)
=
@
{
$_
[
0
]
};
my
$value
=
$self
->
SUPER::
decode_value
(
@_
);
# We only validate/convert certain types here.
return
$value
if
$type
!~
/^(?:int|i4|boolean|double|dateTime\.iso8601)$/
;
# Though the XML-RPC standard doesn't allow an empty <int>,
# <double>,or <dateTime.iso8601>, we do, and we just say
# "that's undef".
if
(
grep
(
$type
eq
$_
,
qw(int double dateTime)
))
{
return
undef
if
$value
eq
''
;
}
my
$validator
=
$self
->
_validation_subs
->
{
$type
};
if
(
!
$validator
->
(
$value
))
{
ThrowUserError
(
'xmlrpc_invalid_value'
,
{
type
=>
$type
,
value
=>
$value
});
}
# We convert dateTimes to a DB-friendly date format.
if
(
$type
eq
'dateTime.iso8601'
)
{
# We leave off the $ from the end of this regex to allow for possible
# extensions to the XML-RPC date standard.
$value
=~
/^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/
;
$value
=
"$1-$2-$3 $4:$5:$6"
;
}
return
$value
;
}
sub
_validation_subs
{
my
$self
=
shift
;
return
$self
->
{
_validation_subs
}
if
$self
->
{
_validation_subs
};
# The only place that XMLRPC::Lite stores any sort of validation
# regex is in XMLRPC::Serializer. We want to re-use those regexes here.
my
$lookup
=
Bugzilla::XMLRPC::
Serializer
->
new
->
typelookup
;
# $lookup is a hash whose values are arrayrefs, and whose keys are the
# names of types. The second item of each arrayref is a subroutine
# that will do our validation for us.
my
%
validators
=
map
{
$_
=>
$lookup
->
{
$_
}
->
[
1
]
}
(
keys
%
$lookup
);
# Add a boolean validator
$validators
{
'boolean'
}
=
sub
{
$_
[
0
]
=~
/^[01]$/
};
# Some types have multiple names, or have a different name in
# XMLRPC::Serializer than their standard XML-RPC name.
$validators
{
'dateTime.iso8601'
}
=
$validators
{
'dateTime'
};
$validators
{
'i4'
}
=
$validators
{
'int'
};
$self
->
{
_validation_subs
}
=
\%
validators
;
return
\%
validators
;
}
1
;
# This package exists to fix a UTF-8 bug in SOAP::Lite.
# See http://rt.cpan.org/Public/Bug/Display.html?id=32952.
package
Bugzilla::XMLRPC::
Serializer
;
use
strict
;
# We can't use "use base" because XMLRPC::Serializer doesn't return
# a true value.
eval
{
require
XMLRPC::
Lite
;
};
our
@ISA
=
qw(XMLRPC::Serializer)
;
sub
new
{
my
$class
=
shift
;
my
$self
=
$class
->
SUPER::
new
(
@_
);
# This fixes UTF-8.
$self
->
{
'_typelookup'
}
->
{
'base64'
}
=
[
10
,
sub
{
!
utf8::
is_utf8
(
$_
[
0
])
&&
$_
[
0
]
=~
/[^\x09\x0a\x0d\x20-\x7f]/
},
'as_base64'
];
# This makes arrays work right even though we're a subclass.
# (See http://rt.cpan.org//Ticket/Display.html?id=34514)
$self
->
{
'_encodingStyle'
}
=
''
;
return
$self
;
}
sub
as_string
{
my
$self
=
shift
;
my
(
$value
)
=
@_
;
# Something weird happens with XML::Parser when we have upper-ASCII
# characters encoded as UTF-8, and this fixes it.
utf8::
encode
(
$value
)
if
utf8::
is_utf8
(
$value
)
&&
$value
=~
/^[\x00-\xff]+$/
;
return
$self
->
SUPER::
as_string
(
$value
);
}
1
;
xmlrpc.cgi
View file @
6a10905a
...
...
@@ -21,16 +21,16 @@ use lib qw(. lib);
use
Bugzilla
;
use
Bugzilla::
Constants
;
use
Bugzilla::
Error
;
use
Bugzilla::
Hook
;
use
Bugzilla::WebService::
Constants
;
# Use an eval here so that runtests.pl accepts this script even if SOAP-Lite
# is not installed.
eval
'use XMLRPC::Transport::HTTP;
use Bugzilla::WebService;'
;
eval
{
require
Bugzilla::WebService::Server::
XMLRPC
;
};
$@
&&
ThrowCodeError
(
'soap_not_installed'
);
Bugzilla
->
usage_mode
(
Bugzilla::Constants::
USAGE_MODE_WEBSERVICE
);
Bugzilla
->
usage_mode
(
USAGE_MODE_WEBSERVICE
);
# Fix the error code that SOAP::Lite uses for Perl errors.
local
$
SOAP::Constants::
FAULT_SERVER
;
$
SOAP::Constants::
FAULT_SERVER
=
ERROR_UNKNOWN_FATAL
;
# The line above is used, this one is ignored, but SOAP::Lite
...
...
@@ -38,27 +38,10 @@ $SOAP::Constants::FAULT_SERVER = ERROR_UNKNOWN_FATAL;
local
$
XMLRPC::Constants::
FAULT_SERVER
;
$
XMLRPC::Constants::
FAULT_SERVER
=
ERROR_UNKNOWN_FATAL
;
my
%
hook_dispatch
;
Bugzilla::Hook::
process
(
'webservice'
,
{
dispatch
=>
\%
hook_dispatch
});
local
@INC
=
(
bz_locations
()
->
{
extensionsdir
},
@INC
);
my
$dispatch
=
{
'Bugzilla'
=>
'Bugzilla::WebService::Bugzilla'
,
'Bug'
=>
'Bugzilla::WebService::Bug'
,
'User'
=>
'Bugzilla::WebService::User'
,
'Product'
=>
'Bugzilla::WebService::Product'
,
%
hook_dispatch
};
# The on_action sub needs to be wrapped so that we can work out which
# class to use; when the XMLRPC module calls it theres no indication
# of which dispatch class will be handling it.
# Note that using this to get code thats called before the actual routine
# is a bit of a hack; its meant to be for modifying the SOAPAction
# headers, which XMLRPC doesn't use; it relies on the XMLRPC modules
# using SOAP::Lite internally....
my
$response
=
Bugzilla::WebService::XMLRPC::Transport::HTTP::
CGI
->
dispatch_with
(
$dispatch
)
->
on_action
(
sub
{
Bugzilla::WebService::
handle_login
(
$dispatch
,
@_
)
}
)
->
handle
;
my
$server
=
new
Bugzilla::WebService::Server::
XMLRPC
;
# We use a sub for on_action because that gets us the info about what
# class is being called. Note that this is a hack--this is technically
# for setting SOAPAction, which isn't used by XML-RPC.
$server
->
on_action
(
sub
{
$server
->
handle_login
(
WS_DISPATCH
,
@_
)
})
->
handle
();
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment