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
37ce30c4
Commit
37ce30c4
authored
Aug 09, 2013
by
Dave Lawrence
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 569177 - Add support for eTag for WebServices
r/a=glob
parent
c1a59a49
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
131 additions
and
18 deletions
+131
-18
CGI.pm
Bugzilla/CGI.pm
+3
-3
Bug.pm
Bugzilla/WebService/Bug.pm
+12
-5
Server.pm
Bugzilla/WebService/Server.pm
+59
-1
JSONRPC.pm
Bugzilla/WebService/Server/JSONRPC.pm
+24
-5
REST.pm
Bugzilla/WebService/Server/REST.pm
+4
-0
XMLRPC.pm
Bugzilla/WebService/Server/XMLRPC.pm
+24
-3
config.cgi
config.cgi
+5
-1
No files found.
Bugzilla/CGI.pm
View file @
37ce30c4
...
@@ -236,11 +236,11 @@ sub check_etag {
...
@@ -236,11 +236,11 @@ sub check_etag {
$possible_etag
=~
s/^\"//g
;
$possible_etag
=~
s/^\"//g
;
$possible_etag
=~
s/\"$//g
;
$possible_etag
=~
s/\"$//g
;
if
(
$possible_etag
eq
$valid_etag
or
$possible_etag
eq
'*'
)
{
if
(
$possible_etag
eq
$valid_etag
or
$possible_etag
eq
'*'
)
{
print
$self
->
header
(
-
ETag
=>
$possible_etag
,
return
1
;
-
status
=>
'304 Not Modified'
);
exit
;
}
}
}
}
return
0
;
}
}
# Have to add the cookies in.
# Have to add the cookies in.
...
...
Bugzilla/WebService/Bug.pm
View file @
37ce30c4
...
@@ -349,6 +349,18 @@ sub get {
...
@@ -349,6 +349,18 @@ sub get {
push
(
@bugs
,
$self
->
_bug_to_hash
(
$bug
,
$params
));
push
(
@bugs
,
$self
->
_bug_to_hash
(
$bug
,
$params
));
}
}
# Set the ETag before inserting the update tokens
# since the tokens will always be unique even if
# the data has not changed.
$self
->
bz_etag
(
\
@bugs
);
if
(
Bugzilla
->
user
->
id
)
{
foreach
my
$bug
(
@bugs
)
{
my
$token
=
issue_hash_token
([
$bug
->
{
'id'
},
$bug
->
{
'last_change_time'
}]);
$bug
->
{
'update_token'
}
=
$self
->
type
(
'string'
,
$token
);
}
}
return
{
bugs
=>
\
@bugs
,
faults
=>
\
@faults
};
return
{
bugs
=>
\
@bugs
,
faults
=>
\
@faults
};
}
}
...
@@ -986,11 +998,6 @@ sub _bug_to_hash {
...
@@ -986,11 +998,6 @@ sub _bug_to_hash {
}
}
}
}
if
(
Bugzilla
->
user
->
id
)
{
my
$token
=
issue_hash_token
([
$bug
->
id
,
$bug
->
delta_ts
]);
$item
{
'update_token'
}
=
$self
->
type
(
'string'
,
$token
);
}
# The "accessible" bits go here because they have long names and it
# The "accessible" bits go here because they have long names and it
# makes the code look nicer to separate them out.
# makes the code look nicer to separate them out.
$item
{
'is_cc_accessible'
}
=
$self
->
type
(
'boolean'
,
$item
{
'is_cc_accessible'
}
=
$self
->
type
(
'boolean'
,
...
...
Bugzilla/WebService/Server.pm
View file @
37ce30c4
...
@@ -14,6 +14,9 @@ use Bugzilla::Error;
...
@@ -14,6 +14,9 @@ use Bugzilla::Error;
use
Bugzilla::
Util
qw(datetime_from)
;
use
Bugzilla::
Util
qw(datetime_from)
;
use
Scalar::
Util
qw(blessed)
;
use
Scalar::
Util
qw(blessed)
;
use
Digest::
MD5
qw(md5_base64)
;
use
Storable
qw(freeze)
;
sub
handle_login
{
sub
handle_login
{
my
(
$self
,
$class
,
$method
,
$full_method
)
=
@_
;
my
(
$self
,
$class
,
$method
,
$full_method
)
=
@_
;
...
@@ -29,7 +32,7 @@ sub handle_login {
...
@@ -29,7 +32,7 @@ sub handle_login {
sub
datetime_format_inbound
{
sub
datetime_format_inbound
{
my
(
$self
,
$time
)
=
@_
;
my
(
$self
,
$time
)
=
@_
;
my
$converted
=
datetime_from
(
$time
,
Bugzilla
->
local_timezone
);
my
$converted
=
datetime_from
(
$time
,
Bugzilla
->
local_timezone
);
if
(
!
defined
$converted
)
{
if
(
!
defined
$converted
)
{
ThrowUserError
(
'illegal_date'
,
{
date
=>
$time
});
ThrowUserError
(
'illegal_date'
,
{
date
=>
$time
});
...
@@ -55,8 +58,63 @@ sub datetime_format_outbound {
...
@@ -55,8 +58,63 @@ sub datetime_format_outbound {
return
$time
->
iso8601
();
return
$time
->
iso8601
();
}
}
# ETag support
sub
bz_etag
{
my
(
$self
,
$data
)
=
@_
;
my
$cache
=
Bugzilla
->
request_cache
;
if
(
defined
$data
)
{
# Serialize the data if passed a reference
local
$
Storable::
canonical
=
1
;
$data
=
freeze
(
$data
)
if
ref
$data
;
# Wide characters cause md5_base64() to die.
utf8::
encode
(
$data
)
if
utf8::
is_utf8
(
$data
);
# Append content_type to the end of the data
# string as we want the etag to be unique to
# the content_type. We do not need this for
# XMLRPC as text/xml is always returned.
if
(
blessed
(
$self
)
&&
$self
->
can
(
'content_type'
))
{
$data
.=
$self
->
content_type
if
$self
->
content_type
;
}
$cache
->
{
'bz_etag'
}
=
md5_base64
(
$data
);
}
return
$cache
->
{
'bz_etag'
};
}
1
;
1
;
=
head1
NAME
Bugzilla::WebService::
Server
-
Base
server
class
for
the
WebService
API
=
head1
DESCRIPTION
Bugzilla::WebService::
Server
is
the
base
class
for
the
individual
WebService
API
servers
such
as
XMLRPC
,
JSONRPC
,
and
REST
.
You
never
actually
create
a
Bugzilla::WebService::
Server
directly
,
you
only
make
subclasses
of
it
.
=
head1
FUNCTIONS
=
over
=
item
C
<
bz_etag
>
This
function
is
used
to
store
an
ETag
value
that
will
be
used
when
returning
the
data
by
the
different
API
server
modules
such
as
XMLRPC
,
or
REST
.
The
individual
webservice
methods
can
also
set
the
value
earlier
in
the
process
if
needed
such
as
before
a
unique
update
token
is
added
.
If
a
value
is
not
set
earlier
,
an
etag
will
automatically
be
created
using
the
returned
data
except
in
some
cases
when
an
error
has
occurred
.
=
back
=
head1
SEE
ALSO
L
<
Bugzilla::WebService::Server::
XMLRPC
|
XMLRPC
>
,
L
<
Bugzilla::WebService::Server::
JSONRPC
|
JSONRPC
>
,
and
L
<
Bugzilla::WebService::Server::
REST
|
REST
>.
=
head1
B
<
Methods
in
need
of
POD
>
=
head1
B
<
Methods
in
need
of
POD
>
=
over
=
over
...
...
Bugzilla/WebService/Server/JSONRPC.pm
View file @
37ce30c4
...
@@ -75,12 +75,12 @@ sub response_header {
...
@@ -75,12 +75,12 @@ sub response_header {
sub
response
{
sub
response
{
my
(
$self
,
$response
)
=
@_
;
my
(
$self
,
$response
)
=
@_
;
my
$cgi
=
$self
->
cgi
;
# Implement JSONP.
# Implement JSONP.
if
(
my
$callback
=
$self
->
_bz_callback
)
{
if
(
my
$callback
=
$self
->
_bz_callback
)
{
my
$content
=
$response
->
content
;
my
$content
=
$response
->
content
;
$response
->
content
(
"$callback($content)"
);
$response
->
content
(
"$callback($content)"
);
}
}
# Use $cgi->header properly instead of just printing text directly.
# Use $cgi->header properly instead of just printing text directly.
...
@@ -95,9 +95,18 @@ sub response {
...
@@ -95,9 +95,18 @@ sub response {
push
(
@header_args
,
"-$name"
,
$value
);
push
(
@header_args
,
"-$name"
,
$value
);
}
}
}
}
my
$cgi
=
$self
->
cgi
;
print
$cgi
->
header
(
-
status
=>
$response
->
code
,
@header_args
);
# ETag support
print
$response
->
content
;
my
$etag
=
$self
->
bz_etag
;
if
(
$etag
&&
$cgi
->
check_etag
(
$etag
))
{
push
(
@header_args
,
"-ETag"
,
$etag
);
print
$cgi
->
header
(
-
status
=>
'304 Not Modified'
,
@header_args
);
}
else
{
push
(
@header_args
,
"-ETag"
,
$etag
)
if
$etag
;
print
$cgi
->
header
(
-
status
=>
$response
->
code
,
@header_args
);
print
$response
->
content
;
}
}
}
# The JSON-RPC 1.1 GET specification is not so great--you can't specify
# The JSON-RPC 1.1 GET specification is not so great--you can't specify
...
@@ -257,7 +266,17 @@ sub _handle {
...
@@ -257,7 +266,17 @@ sub _handle {
my
$self
=
shift
;
my
$self
=
shift
;
my
(
$obj
)
=
@_
;
my
(
$obj
)
=
@_
;
$self
->
{
_bz_request_id
}
=
$obj
->
{
id
};
$self
->
{
_bz_request_id
}
=
$obj
->
{
id
};
return
$self
->
SUPER::
_handle
(
@_
);
my
$result
=
$self
->
SUPER::
_handle
(
@_
);
# Set the ETag if not already set in the webservice methods.
my
$etag
=
$self
->
bz_etag
;
if
(
!
$etag
&&
ref
$result
)
{
my
$data
=
$self
->
json
->
decode
(
$result
)
->
{
'result'
};
$self
->
bz_etag
(
$data
);
}
return
$result
;
}
}
# Make all error messages returned by JSON::RPC go into the 100000
# Make all error messages returned by JSON::RPC go into the 100000
...
...
Bugzilla/WebService/Server/REST.pm
View file @
37ce30c4
...
@@ -125,6 +125,10 @@ sub response {
...
@@ -125,6 +125,10 @@ sub response {
# Access Control
# Access Control
$response
->
header
(
"Access-Control-Allow-Origin"
,
"*"
);
$response
->
header
(
"Access-Control-Allow-Origin"
,
"*"
);
# ETag support
my
$etag
=
$self
->
bz_etag
;
$self
->
bz_etag
(
$result
)
if
!
$etag
;
# If accessing through web browser, then display in readable format
# If accessing through web browser, then display in readable format
if
(
$self
->
content_type
eq
'text/html'
)
{
if
(
$self
->
content_type
eq
'text/html'
)
{
$result
=
$self
->
json
->
pretty
->
canonical
->
encode
(
$result
);
$result
=
$self
->
json
->
pretty
->
canonical
->
encode
(
$result
);
...
...
Bugzilla/WebService/Server/XMLRPC.pm
View file @
37ce30c4
...
@@ -21,8 +21,8 @@ if ($ENV{MOD_PERL}) {
...
@@ -21,8 +21,8 @@ if ($ENV{MOD_PERL}) {
use
Bugzilla::WebService::
Constants
;
use
Bugzilla::WebService::
Constants
;
use
Bugzilla::
Util
;
use
Bugzilla::
Util
;
# Allow WebService methods to call XMLRPC::Lite's type method directly
BEGIN
{
BEGIN
{
# Allow WebService methods to call XMLRPC::Lite's type method directly
*
Bugzilla::WebService::
type
=
sub
{
*
Bugzilla::WebService::
type
=
sub
{
my
(
$self
,
$type
,
$value
)
=
@_
;
my
(
$self
,
$type
,
$value
)
=
@_
;
if
(
$type
eq
'dateTime'
)
{
if
(
$type
eq
'dateTime'
)
{
...
@@ -39,6 +39,11 @@ BEGIN {
...
@@ -39,6 +39,11 @@ BEGIN {
}
}
return
XMLRPC::
Data
->
type
(
$type
)
->
value
(
$value
);
return
XMLRPC::
Data
->
type
(
$type
)
->
value
(
$value
);
};
};
# Add support for ETags into XMLRPC WebServices
*
Bugzilla::WebService::
bz_etag
=
sub
{
return
Bugzilla::WebService::
Server
->
bz_etag
(
$_
[
1
]);
};
}
}
sub
initialize
{
sub
initialize
{
...
@@ -52,22 +57,38 @@ sub initialize {
...
@@ -52,22 +57,38 @@ sub initialize {
sub
make_response
{
sub
make_response
{
my
$self
=
shift
;
my
$self
=
shift
;
my
$cgi
=
Bugzilla
->
cgi
;
$self
->
SUPER::
make_response
(
@_
);
$self
->
SUPER::
make_response
(
@_
);
# XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
# XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
# its cookies in Bugzilla::CGI, so we need to copy them over.
# its cookies in Bugzilla::CGI, so we need to copy them over.
foreach
my
$cookie
(
@
{
Bugzilla
->
cgi
->
{
'Bugzilla_cookie_list'
}})
{
foreach
my
$cookie
(
@
{
$
cgi
->
{
'Bugzilla_cookie_list'
}})
{
$self
->
response
->
headers
->
push_header
(
'Set-Cookie'
,
$cookie
);
$self
->
response
->
headers
->
push_header
(
'Set-Cookie'
,
$cookie
);
}
}
# Copy across security related headers from Bugzilla::CGI
# Copy across security related headers from Bugzilla::CGI
foreach
my
$header
(
split
(
/[\r\n]+/
,
Bugzilla
->
cgi
->
header
))
{
foreach
my
$header
(
split
(
/[\r\n]+/
,
$
cgi
->
header
))
{
my
(
$name
,
$value
)
=
$header
=~
/^([^:]+): (.*)/
;
my
(
$name
,
$value
)
=
$header
=~
/^([^:]+): (.*)/
;
if
(
!
$self
->
response
->
headers
->
header
(
$name
))
{
if
(
!
$self
->
response
->
headers
->
header
(
$name
))
{
$self
->
response
->
headers
->
header
(
$name
=>
$value
);
$self
->
response
->
headers
->
header
(
$name
=>
$value
);
}
}
}
}
# ETag support
my
$etag
=
$self
->
bz_etag
;
if
(
!
$etag
)
{
my
$data
=
$self
->
response
->
as_string
;
$etag
=
$self
->
bz_etag
(
$data
);
}
if
(
$etag
&&
$cgi
->
check_etag
(
$etag
))
{
$self
->
response
->
headers
->
push_header
(
'ETag'
,
$etag
);
$self
->
response
->
headers
->
push_header
(
'status'
,
'304 Not Modified'
);
}
elsif
(
$etag
)
{
$self
->
response
->
headers
->
push_header
(
'ETag'
,
$etag
);
}
}
}
sub
handle_login
{
sub
handle_login
{
...
...
config.cgi
View file @
37ce30c4
...
@@ -142,7 +142,11 @@ sub display_data {
...
@@ -142,7 +142,11 @@ sub display_data {
utf8::
encode
(
$digest_data
)
if
utf8::
is_utf8
(
$digest_data
);
utf8::
encode
(
$digest_data
)
if
utf8::
is_utf8
(
$digest_data
);
my
$digest
=
md5_base64
(
$digest_data
);
my
$digest
=
md5_base64
(
$digest_data
);
$cgi
->
check_etag
(
$digest
);
if
(
$cgi
->
check_etag
(
$digest
))
{
print
$cgi
->
header
(
-
ETag
=>
$digest
,
-
status
=>
'304 Not Modified'
);
exit
;
}
print
$cgi
->
header
(
-
ETag
=>
$digest
,
print
$cgi
->
header
(
-
ETag
=>
$digest
,
-
type
=>
$format
->
{
'ctype'
});
-
type
=>
$format
->
{
'ctype'
});
...
...
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