Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
ee70a7f5
Commit
ee70a7f5
authored
Mar 03, 1999
by
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
initial
parent
4f0072eb
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1676 additions
and
0 deletions
+1676
-0
lib/python/webdav/Collection.py
lib/python/webdav/Collection.py
+139
-0
lib/python/webdav/NullResource.py
lib/python/webdav/NullResource.py
+165
-0
lib/python/webdav/Resource.py
lib/python/webdav/Resource.py
+401
-0
lib/python/webdav/__init__.py
lib/python/webdav/__init__.py
+157
-0
lib/python/webdav/xmlcmds.py
lib/python/webdav/xmlcmds.py
+372
-0
lib/python/webdav/xmltools.py
lib/python/webdav/xmltools.py
+442
-0
No files found.
lib/python/webdav/Collection.py
0 → 100644
View file @
ee70a7f5
##############################################################################
#
# Zope Public License (ZPL) Version 0.9.4
# ---------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions in source code must retain the above
# copyright notice, this list of conditions, and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions, and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Any use, including use of the Zope software to operate a
# website, must either comply with the terms described below
# under "Attribution" or alternatively secure a separate
# license from Digital Creations.
#
# 4. All advertising materials, documentation, or technical papers
# mentioning features derived from or use of this software must
# display the following acknowledgement:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 5. Names associated with Zope or Digital Creations must not be
# used to endorse or promote products derived from this
# software without prior written permission from Digital
# Creations.
#
# 6. Redistributions of any form whatsoever must retain the
# following acknowledgment:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 7. Modifications are encouraged but must be packaged separately
# as patches to official Zope releases. Distributions that do
# not clearly separate the patches from the original work must
# be clearly labeled as unofficial distributions.
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND
# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL DIGITAL CREATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
# Attribution
#
# Individuals or organizations using this software as a web site
# must provide attribution by placing the accompanying "button"
# and a link to the accompanying "credits page" on the website's
# main entry point. In cases where this placement of
# attribution is not feasible, a separate arrangment must be
# concluded with Digital Creations. Those using the software
# for purposes other than web sites must provide a corresponding
# attribution in locations that include a copyright using a
# manner best suited to the application environment.
#
# This software consists of contributions made by Digital
# Creations and many individuals on behalf of Digital Creations.
# Specific attributions are listed in the accompanying credits
# file.
#
##############################################################################
"""WebDAV support - collection objects."""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
sys
,
os
,
string
,
mimetypes
from
Resource
import
Resource
class
Collection
(
Resource
):
"""The Collection class provides basic WebDAV support for
collection objects. It provides default implementations
for all supported WebDAV HTTP methods. The behaviors of some
WebDAV HTTP methods for collections are slightly different
than those for non-collection resources.
"""
def
redirect_check
(
self
,
req
,
rsp
):
# By the spec, we are not supposed to accept /foo for a
# collection, we have to redirect to /foo/.
if
req
[
'PATH_INFO'
][
-
1
]
==
'/'
:
return
raise
'Moved Permanently'
,
req
[
'URL1'
]
+
'/'
def
HEAD
(
self
,
REQUEST
,
RESPONSE
):
"""Retrieve resource information without a response body."""
self
.
init_headers
(
RESPONSE
)
self
.
redirect_check
(
REQUEST
,
RESPONSE
)
RESPONSE
.
setStatus
(
200
)
return
RESPONSE
def
PUT
(
self
,
REQUEST
,
RESPONSE
):
"""The PUT method has no inherent meaning for collection
resources, though collections are not specifically forbidden
to handle PUT requests. The default response to a PUT request
for collections is 405 (Method Not Allowed)."""
self
.
init_headers
(
RESPONSE
)
self
.
redirect_check
(
REQUEST
,
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
def
DELETE
(
self
,
REQUEST
,
RESPONSE
):
"""Delete a collection resource. For collection resources, DELETE
may return either 200 (OK) or 204 (No Content) to indicate total
success, or may return 207 (Multistatus) to indicate partial
success."""
self
.
init_headers
(
RESPONSE
)
self
.
redirect_check
(
REQUEST
,
RESPONSE
)
if
self
.
dav__is_acquired
():
raise
'Not Found'
,
'The requested resource does not exist.'
path
=
filter
(
None
,
string
.
split
(
REQUEST
[
'PATH_INFO'
],
'/'
))
name
=
path
[
-
1
]
# TODO: add lock check here
self
.
aq_parent
.
_delObject
(
name
)
RESPONSE
.
setStatus
(
204
)
return
RESPONSE
lib/python/webdav/NullResource.py
0 → 100644
View file @
ee70a7f5
##############################################################################
#
# Zope Public License (ZPL) Version 0.9.4
# ---------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions in source code must retain the above
# copyright notice, this list of conditions, and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions, and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Any use, including use of the Zope software to operate a
# website, must either comply with the terms described below
# under "Attribution" or alternatively secure a separate
# license from Digital Creations.
#
# 4. All advertising materials, documentation, or technical papers
# mentioning features derived from or use of this software must
# display the following acknowledgement:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 5. Names associated with Zope or Digital Creations must not be
# used to endorse or promote products derived from this
# software without prior written permission from Digital
# Creations.
#
# 6. Redistributions of any form whatsoever must retain the
# following acknowledgment:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 7. Modifications are encouraged but must be packaged separately
# as patches to official Zope releases. Distributions that do
# not clearly separate the patches from the original work must
# be clearly labeled as unofficial distributions.
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND
# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL DIGITAL CREATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
# Attribution
#
# Individuals or organizations using this software as a web site
# must provide attribution by placing the accompanying "button"
# and a link to the accompanying "credits page" on the website's
# main entry point. In cases where this placement of
# attribution is not feasible, a separate arrangment must be
# concluded with Digital Creations. Those using the software
# for purposes other than web sites must provide a corresponding
# attribution in locations that include a copyright using a
# manner best suited to the application environment.
#
# This software consists of contributions made by Digital
# Creations and many individuals on behalf of Digital Creations.
# Specific attributions are listed in the accompanying credits
# file.
#
##############################################################################
"""WebDAV support - null resource objects."""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
sys
,
os
,
string
,
mimetypes
import
Acquisition
,
OFS
.
content_types
from
Resource
import
Resource
,
aq_base
class
NullResource
(
Acquisition
.
Implicit
,
Resource
):
"""Null resources are used to handle HTTP method calls on
objects which do not yet exist in the url namespace."""
_isNullResource
=
1
def
__init__
(
self
,
parent
,
id
):
self
.
id
=
id
self
.
__parent__
=
parent
self
.
__roles__
=
None
# fix this!!
def
HEAD
(
self
,
REQUEST
,
RESPONSE
):
"""Retrieve resource information without a response message body."""
self
.
init_headers
(
RESPONSE
)
raise
'Not Found'
,
'The requested resource does not exist.'
# Most methods return 404 (Not Found) for null resources.
DELETE
=
OPTIONS
=
TRACE
=
PROPFIND
=
PROPPATCH
=
COPY
=
MOVE
=
HEAD
def
PUT
(
self
,
REQUEST
,
RESPONSE
):
"""Create a new non-collection resource."""
self
.
init_headers
(
RESPONSE
)
type
=
REQUEST
.
get_header
(
'content-type'
,
None
)
body
=
REQUEST
.
get
(
'BODY'
,
''
)
if
type
is
None
:
type
,
enc
=
mimetypes
.
guess_type
(
self
.
id
)
if
type
is
None
:
if
OFS
.
content_types
.
find_binary
(
body
)
>=
0
:
content_type
=
'application/octet-stream'
else
:
type
=
OFS
.
content_types
.
text_type
(
body
)
type
=
string
.
lower
(
type
)
from
OFS.Image
import
Image
,
File
if
type
in
(
'text/html'
,
'text/xml'
,
'text/plain'
):
self
.
__parent__
.
manage_addDTMLDocument
(
self
.
id
,
''
,
body
)
elif
type
[:
6
]
==
'image/'
:
ob
=
Image
(
self
.
id
,
''
,
body
,
content_type
=
type
)
self
.
__parent__
.
_setObject
(
self
.
id
,
ob
)
else
:
ob
=
File
(
self
.
id
,
''
,
body
,
content_type
=
type
)
self
.
__parent__
.
_setObject
(
self
.
id
,
ob
)
RESPONSE
.
setStatus
(
201
)
RESPONSE
.
setBody
(
''
)
return
RESPONSE
def
MKCOL
(
self
,
REQUEST
,
RESPONSE
):
"""Create a new collection resource."""
self
.
init_headers
(
RESPONSE
)
if
REQUEST
.
get
(
'BODY'
,
''
):
raise
'Unsupported Media Type'
,
'Unknown request body.'
parent
=
self
.
__parent__
if
hasattr
(
aq_base
(
parent
),
self
.
id
):
raise
'Method Not Allowed'
,
'The name %s is in use.'
%
self
.
id
if
(
not
hasattr
(
parent
.
aq_base
,
'isAnObjectManager'
))
or
\
(
not
parent
.
isAnObjectManager
):
raise
'Forbidden'
,
'Unable to create collection resource.'
# This should probably do self.__class__(id, ...), except Folder
# doesn't currently have a constructor.
parent
.
manage_addFolder
(
self
.
id
)
RESPONSE
.
setStatus
(
201
)
RESPONSE
.
setBody
(
''
)
return
RESPONSE
def
LOCK
(
self
,
REQUEST
,
RESPONSE
):
"""Create a lock-null resource."""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
def
UNLOCK
(
self
):
"""Remove a lock-null resource."""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
lib/python/webdav/Resource.py
0 → 100644
View file @
ee70a7f5
##############################################################################
#
# Zope Public License (ZPL) Version 0.9.4
# ---------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions in source code must retain the above
# copyright notice, this list of conditions, and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions, and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Any use, including use of the Zope software to operate a
# website, must either comply with the terms described below
# under "Attribution" or alternatively secure a separate
# license from Digital Creations.
#
# 4. All advertising materials, documentation, or technical papers
# mentioning features derived from or use of this software must
# display the following acknowledgement:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 5. Names associated with Zope or Digital Creations must not be
# used to endorse or promote products derived from this
# software without prior written permission from Digital
# Creations.
#
# 6. Redistributions of any form whatsoever must retain the
# following acknowledgment:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 7. Modifications are encouraged but must be packaged separately
# as patches to official Zope releases. Distributions that do
# not clearly separate the patches from the original work must
# be clearly labeled as unofficial distributions.
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND
# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL DIGITAL CREATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
# Attribution
#
# Individuals or organizations using this software as a web site
# must provide attribution by placing the accompanying "button"
# and a link to the accompanying "credits page" on the website's
# main entry point. In cases where this placement of
# attribution is not feasible, a separate arrangment must be
# concluded with Digital Creations. Those using the software
# for purposes other than web sites must provide a corresponding
# attribution in locations that include a copyright using a
# manner best suited to the application environment.
#
# This software consists of contributions made by Digital
# Creations and many individuals on behalf of Digital Creations.
# Specific attributions are listed in the accompanying credits
# file.
#
##############################################################################
"""WebDAV support - resource objects."""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
sys
,
os
,
string
,
time
import
mimetypes
,
xmlcmds
zpns
=
'http://www.zope.org/propertysets/default/'
class
Resource
:
"""The Resource mixin class provides basic WebDAV support for
non-collection objects. It provides default implementations
for most supported WebDAV HTTP methods, however certain methods
such as PUT should be overridden to ensure correct behavior in
the context of the object type."""
__http_methods__
=
(
'GET'
,
'HEAD'
,
'POST'
,
'PUT'
,
'DELETE'
,
'OPTIONS'
,
'TRACE'
,
'PROPFIND'
,
'PROPPATCH'
,
'MKCOL'
,
'COPY'
,
'MOVE'
,
)
__dav_resource__
=
1
def
init_headers
(
self
,
r
):
# Init expected HTTP 1.1 / WebDAV headers which are not
# currently set by the response object automagically.
r
.
setHeader
(
'Connection'
,
'close'
)
r
.
setHeader
(
'Date'
,
rfc1123_date
())
r
.
setHeader
(
'DAV'
,
'1'
)
dav__locks
=
()
def
dav__is_locked
(
self
):
# Return true if this object is locked via a
# session or dav lock.
if
hasattr
(
self
,
'locked_in_session'
)
and
self
.
locked_in_session
():
return
1
return
0
def
dav__get_locks
(
self
):
# Return the current locks on the object.
if
hasattr
(
self
,
'locked_in_session'
)
and
self
.
locked_in_session
():
lock
=
Lock
(
'xxxx'
,
'xxxx'
)
return
self
.
dav__locks
+
(
lock
,)
def
dav__is_acquired
(
self
,
ob
=
None
):
# Return true if this object is not a direct
# subobject of its aq_parent object.
if
ob
is
None
:
ob
=
self
if
not
hasattr
(
ob
,
'aq_parent'
):
return
0
if
hasattr
(
aq_base
(
ob
.
aq_parent
),
absattr
(
ob
.
id
)):
return
0
if
hasattr
(
aq_base
(
ob
),
'isTopLevelPrincipiaApplicationObject'
):
return
0
return
1
# WebDAV class 1 support
def
HEAD
(
self
,
REQUEST
,
RESPONSE
):
"""Retrieve resource information without a response message
body. It would be great if we had a standard way to ask an
arbitrary object for its headers -- that would allow the
default HEAD implementation to handle most needs."""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
def
PUT
(
self
,
REQUEST
,
RESPONSE
):
"""Replace the GET response entity of an existing resource.
Because this is often object-dependent, objects which handle
PUT should override the default PUT implementation with an
object-specific implementation. By default, PUT requests
fail with a 405 (Method Not Allowed)."""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
def
OPTIONS
(
self
,
REQUEST
,
RESPONSE
):
"""Retrieve communication options."""
self
.
init_headers
(
RESPONSE
)
RESPONSE
.
setHeader
(
'Allow'
,
string
.
join
(
self
.
__http_methods__
,
', '
))
RESPONSE
.
setHeader
(
'Content-Length'
,
0
)
RESPONSE
.
setStatus
(
200
)
return
RESPONSE
def
TRACE
(
self
,
REQUEST
,
RESPONSE
):
"""Return the HTTP message received back to the client as the
entity-body of a 200 (OK) response. This will often actually
be intercepted by the web server in use. If not, the TRACE
request will fail with a 405 (Method Not Allowed), since it
is not often possible to reproduce the HTTP request verbatim
from within the Zope environment."""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
def
DELETE
(
self
,
REQUEST
,
RESPONSE
):
"""Delete a resource. For non-collection resources, DELETE may
return either 200 or 204 (No Content) to indicate success."""
self
.
init_headers
(
RESPONSE
)
if
self
.
dav__is_acquired
():
raise
'Not Found'
,
'The requested resource does not exist.'
path
=
filter
(
None
,
string
.
split
(
REQUEST
[
'URL'
],
'/'
))
if
path
[
-
1
]
==
'DELETE'
:
del
path
[
-
1
]
name
=
path
[
-
1
]
# TODO: add lock checking here
self
.
aq_parent
.
_delObject
(
name
)
RESPONSE
.
setStatus
(
204
)
return
RESPONSE
def
PROPFIND
(
self
,
REQUEST
,
RESPONSE
):
"""Retrieve properties defined on the resource."""
self
.
init_headers
(
RESPONSE
)
if
self
.
dav__is_acquired
():
raise
'Not Found'
,
'The requested resource does not exist.'
try
:
request
=
xmlcmds
.
PropFind
(
REQUEST
)
except
:
raise
'Bad Request'
,
'Invalid xml request.'
result
=
request
.
apply
(
self
)
RESPONSE
.
setStatus
(
207
)
RESPONSE
.
setHeader
(
'Content-Type'
,
'text/xml; charset="utf-8"'
)
RESPONSE
.
setBody
(
result
)
return
RESPONSE
def
PROPPATCH
(
self
,
REQUEST
,
RESPONSE
):
"""Set and/or remove properties defined on the resource."""
self
.
init_headers
(
RESPONSE
)
if
self
.
dav__is_acquired
():
raise
'Not Found'
,
'The requested resource does not exist.'
if
not
hasattr
(
self
,
'__propsets__'
):
raise
'Method Not Allowed'
,
(
'Method not supported for this resource.'
)
# TODO: add lock checking here
try
:
request
=
xmlcmds
.
PropPatch
(
REQUEST
)
except
:
raise
'Bad Request'
,
'Invalid xml request.'
result
=
request
.
apply
(
self
)
RESPONSE
.
setStatus
(
207
)
RESPONSE
.
setHeader
(
'Content-Type'
,
'text/xml; charset="utf-8"'
)
RESPONSE
.
setBody
(
result
)
return
RESPONSE
def
MKCOL
(
self
,
REQUEST
,
RESPONSE
):
"""Create a new collection resource. If called on an existing
resource, MKCOL must fail with 405 (Method Not Allowed)."""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
def
COPY
(
self
,
REQUEST
,
RESPONSE
):
"""Create a duplicate of the source resource whose state
and behavior match that of the source resource as closely
as possible. Though we may later try to make a copy appear
seamless across namespaces (e.g. from Zope to Apache), COPY
is currently only supported within the Zope namespace."""
self
.
init_headers
(
RESPONSE
)
if
not
hasattr
(
aq_base
(
self
),
'cb_isCopyable'
)
or
\
not
self
.
cb_isCopyable
():
raise
'Method Not Allowed'
,
'This object may not be copied.'
if
self
.
dav__is_acquired
():
raise
'Not Found'
,
'The requested resource does not exist.'
depth
=
REQUEST
.
get_header
(
'Depth'
,
'infinity'
)
dest
=
REQUEST
.
get_header
(
'Destination'
,
''
)
if
not
dest
:
raise
'Bad Request'
,
'No destination given'
flag
=
REQUEST
.
get_header
(
'Overwrite'
,
'F'
)
flag
=
string
.
upper
(
flag
)
body
=
REQUEST
.
get
(
'BODY'
,
''
)
path
,
name
=
os
.
path
.
split
(
dest
)
try
:
parent
=
REQUEST
.
resolve_url
(
path
)
except
ValueError
:
raise
'Conflict'
,
'Attempt to copy to an unknown namespace.'
except
'Not Found'
:
raise
'Conflict'
,
'The resource %s must exist.'
%
path
except
:
raise
sys
.
exc_type
,
sys
.
exc_value
if
hasattr
(
parent
,
'_isNullResource'
):
raise
'Conflict'
,
'The resource %s must exist.'
%
path
if
self
.
dav__is_acquired
(
parent
):
raise
'Conflict'
,
'The resource %s must exist.'
%
path
existing
=
hasattr
(
aq_base
(
parent
),
name
)
if
existing
and
flag
==
'F'
:
raise
'Precondition Failed'
,
'Resource %s exists.'
%
dest
try
:
parent
.
_checkId
(
name
,
allow_dup
=
1
)
except
:
raise
'Forbidden'
,
sys
.
exc_value
try
:
parent
.
_verifyObjectPaste
(
self
,
REQUEST
)
except
:
raise
'Forbidden'
,
sys
.
exc_value
try
:
self
.
_notifyOfCopyTo
(
parent
,
op
=
0
)
except
:
raise
'Forbidden'
,
sys
.
exc_value
ob
=
self
.
_getCopy
(
parent
)
ob
.
_setId
(
name
)
parent
.
_setObject
(
name
,
ob
)
ob
=
ob
.
__of__
(
parent
)
ob
.
_postCopy
(
parent
,
op
=
0
)
RESPONSE
.
setStatus
(
existing
and
204
or
201
)
if
not
existing
:
RESPONSE
.
setHeader
(
'Location'
,
dest
)
RESPONSE
.
setBody
(
''
)
return
RESPONSE
def
MOVE
(
self
,
REQUEST
,
RESPONSE
):
"""Move a resource to a new location. Though we may later try to
make a move appear seamless across namespaces (e.g. from Zope
to Apache), MOVE is currently only supported within the Zope
namespace."""
self
.
init_headers
(
RESPONSE
)
if
not
hasattr
(
aq_base
(
self
),
'cb_isMoveable'
)
or
\
not
self
.
cb_isMoveable
():
raise
'Method Not Allowed'
,
'This object may not be moved.'
if
self
.
dav__is_acquired
():
raise
'Not Found'
,
'The requested resource does not exist.'
dest
=
REQUEST
.
get_header
(
'Destination'
,
''
)
if
not
dest
:
raise
'Bad Request'
,
'No destination given'
flag
=
REQUEST
.
get_header
(
'Overwrite'
,
'F'
)
flag
=
string
.
upper
(
flag
)
body
=
REQUEST
.
get
(
'BODY'
,
''
)
path
,
name
=
os
.
path
.
split
(
dest
)
try
:
parent
=
REQUEST
.
resolve_url
(
path
)
except
ValueError
:
raise
'Conflict'
,
'Attempt to move to an unknown namespace.'
except
'Not Found'
:
raise
'Conflict'
,
'The resource %s must exist.'
%
path
except
:
raise
sys
.
exc_type
,
sys
.
exc_value
if
hasattr
(
parent
,
'_isNullResource'
):
raise
'Conflict'
,
'The resource %s must exist.'
%
path
if
self
.
dav__is_acquired
(
parent
):
raise
'Conflict'
,
'The resource %s must exist.'
%
path
existing
=
hasattr
(
aq_base
(
parent
),
name
)
if
existing
and
flag
==
'F'
:
raise
'Precondition Failed'
,
'Resource %s exists.'
%
dest
try
:
parent
.
_checkId
(
name
,
allow_dup
=
1
)
except
:
raise
'Forbidden'
,
sys
.
exc_value
try
:
parent
.
_verifyObjectPaste
(
self
,
REQUEST
)
except
:
raise
'Forbidden'
,
sys
.
exc_value
try
:
self
.
_notifyOfCopyTo
(
parent
,
op
=
1
)
except
:
raise
'Forbidden'
,
sys
.
exc_value
ob
=
aq_base
(
self
.
_getCopy
(
parent
))
self
.
aq_parent
.
_delObject
(
absattr
(
self
.
id
))
ob
.
_setId
(
name
)
parent
.
_setObject
(
name
,
ob
)
ob
=
ob
.
__of__
(
parent
)
ob
.
_postCopy
(
parent
,
op
=
1
)
RESPONSE
.
setStatus
(
existing
and
204
or
201
)
if
not
existing
:
RESPONSE
.
setHeader
(
'Location'
,
dest
)
RESPONSE
.
setBody
(
''
)
return
RESPONSE
# Class 2 support
def
LOCK
(
self
,
REQUEST
,
RESPONSE
):
"""A write lock MUST prevent a principal without the lock from
successfully executing a PUT, POST, PROPPATCH, LOCK, UNLOCK, MOVE,
DELETE, or MKCOL on the locked resource. All other current methods,
GET in particular, function independently of the lock.
"""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
def
UNLOCK
(
self
):
"""Remove an existing lock on a resource."""
self
.
init_headers
(
RESPONSE
)
raise
'Method Not Allowed'
,
'Method not supported for this resource.'
class
Lock
:
"""A WebDAV lock object"""
def
__init__
(
self
,
token
,
owner
,
scope
=
'exclusive'
,
type
=
'write'
,
depth
=
'infinity'
,
timeout
=
'Infinite'
):
self
.
token
=
token
self
.
owner
=
owner
self
.
scope
=
scope
self
.
type
=
type
self
.
depth
=
depth
self
.
timeout
=
timeout
def
dav__activelock
(
self
):
txt
=
'<d:activelock>
\
n
'
\
'<d:locktype><d:%(type)s/></d:locktype>
\
n
'
\
'<d:lockscope><d:%(scope)s/></d:lockscope>
\
n
'
\
'<d:depth>%(depth)s</d:depth>
\
n
'
\
'<d:owner>%(owner)s</d:owner>
\
n
'
\
'<d:timeout>%(timeout)s</d:timeout>
\
n
'
\
'<d:locktoken>
\
n
'
\
'<d:href>opaquelocktoken:%(token)s</d:href>
\
n
'
\
'</d:locktoken>
\
n
'
\
'</d:activelock>
\
n
'
%
self
.
__dict__
def
absattr
(
attr
):
if
callable
(
attr
):
return
attr
()
return
attr
def
aq_base
(
ob
):
if
hasattr
(
ob
,
'aq_base'
):
return
ob
.
aq_base
return
ob
def
rfc1123_date
(
ts
=
None
):
# Return an RFC 1123 format date string, required for
# use in HTTP Date headers per the HTTP 1.1 spec.
if
ts
is
None
:
ts
=
time
.
time
()
ts
=
time
.
asctime
(
time
.
gmtime
(
ts
))
ts
=
string
.
split
(
ts
)
return
'%s, %s %s %s %s GMT'
%
(
ts
[
0
],
ts
[
2
],
ts
[
1
],
ts
[
3
],
ts
[
4
])
lib/python/webdav/__init__.py
0 → 100644
View file @
ee70a7f5
##############################################################################
#
# Zope Public License (ZPL) Version 0.9.4
# ---------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions in source code must retain the above
# copyright notice, this list of conditions, and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions, and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Any use, including use of the Zope software to operate a
# website, must either comply with the terms described below
# under "Attribution" or alternatively secure a separate
# license from Digital Creations.
#
# 4. All advertising materials, documentation, or technical papers
# mentioning features derived from or use of this software must
# display the following acknowledgement:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 5. Names associated with Zope or Digital Creations must not be
# used to endorse or promote products derived from this
# software without prior written permission from Digital
# Creations.
#
# 6. Redistributions of any form whatsoever must retain the
# following acknowledgment:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 7. Modifications are encouraged but must be packaged separately
# as patches to official Zope releases. Distributions that do
# not clearly separate the patches from the original work must
# be clearly labeled as unofficial distributions.
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND
# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL DIGITAL CREATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
# Attribution
#
# Individuals or organizations using this software as a web site
# must provide attribution by placing the accompanying "button"
# and a link to the accompanying "credits page" on the website's
# main entry point. In cases where this placement of
# attribution is not feasible, a separate arrangment must be
# concluded with Digital Creations. Those using the software
# for purposes other than web sites must provide a corresponding
# attribution in locations that include a copyright using a
# manner best suited to the application environment.
#
# This software consists of contributions made by Digital
# Creations and many individuals on behalf of Digital Creations.
# Specific attributions are listed in the accompanying credits
# file.
#
##############################################################################
"""The webdav package provides WebDAV class 1 functionality within
the Zope environment. Based on RFC 2518."""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
# Hacks to inject WebDAV support into standard Zope classes.
from
NullResource
import
NullResource
def
folder__getitem__
(
self
,
key
):
if
hasattr
(
self
,
'REQUEST'
):
method
=
self
.
REQUEST
.
get
(
'REQUEST_METHOD'
,
'GET'
)
if
not
method
in
(
'GET'
,
'POST'
):
return
NullResource
(
self
,
key
).
__of__
(
self
)
raise
KeyError
,
key
def
document_put
(
self
,
REQUEST
,
RESPONSE
):
"""Handle HTTP PUT requests."""
self
.
init_headers
(
RESPONSE
)
type
=
REQUEST
.
get_header
(
'content-type'
,
None
)
body
=
REQUEST
.
get
(
'BODY'
,
''
)
self
.
_validateProxy
(
REQUEST
)
self
.
munge
(
body
)
self
.
on_update
()
RESPONSE
.
setStatus
(
204
)
return
RESPONSE
def
image_put
(
self
,
REQUEST
,
RESPONSE
):
"""Handle HTTP PUT requests"""
self
.
init_headers
(
RESPONSE
)
type
=
REQUEST
.
get_header
(
'content-type'
,
None
)
body
=
REQUEST
.
get
(
'BODY'
,
''
)
if
type
is
None
:
type
,
enc
=
mimetypes
.
guess_type
(
self
.
id
())
if
type
is
None
:
if
content_types
.
find_binary
(
body
)
>=
0
:
type
=
'application/octet-stream'
else
:
type
=
content_types
.
text_type
(
body
)
type
=
lower
(
type
)
self
.
update_data
(
body
,
type
)
RESPONSE
.
setStatus
(
204
)
return
RESPONSE
import
OFS.SimpleItem
,
Resource
class
Item
(
OFS
.
SimpleItem
.
Item
,
Resource
.
Resource
):
pass
Item
.
__module__
=
'OFS.SimpleItem'
OFS
.
SimpleItem
.
Item
=
Item
class
Item_w__name__
(
OFS
.
SimpleItem
.
Item_w__name__
,
Resource
.
Resource
):
pass
Item_w__name__
.
__module__
=
'OFS.SimpleItem'
OFS
.
SimpleItem
.
Item_w__name__
=
Item_w__name__
import
OFS.Folder
,
Collection
class
Folder
(
OFS
.
Folder
.
Folder
,
Collection
.
Collection
):
pass
Folder
.
__module__
=
'OFS.Folder'
OFS
.
Folder
.
Folder
=
Folder
OFS
.
Folder
.
Folder
.
__getitem__
=
folder__getitem__
import
OFS.DTMLDocument
,
OFS
.
DTMLMethod
,
OFS
.
Image
OFS
.
DTMLMethod
.
DTMLMethod
.
PUT
=
document_put
OFS
.
DTMLDocument
.
DTMLDocument
.
PUT
=
document_put
OFS
.
Image
.
Image
.
PUT
=
image_put
OFS
.
Image
.
File
.
PUT
=
image_put
lib/python/webdav/xmlcmds.py
0 → 100644
View file @
ee70a7f5
##############################################################################
#
# Zope Public License (ZPL) Version 0.9.4
# ---------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions in source code must retain the above
# copyright notice, this list of conditions, and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions, and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Any use, including use of the Zope software to operate a
# website, must either comply with the terms described below
# under "Attribution" or alternatively secure a separate
# license from Digital Creations.
#
# 4. All advertising materials, documentation, or technical papers
# mentioning features derived from or use of this software must
# display the following acknowledgement:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 5. Names associated with Zope or Digital Creations must not be
# used to endorse or promote products derived from this
# software without prior written permission from Digital
# Creations.
#
# 6. Redistributions of any form whatsoever must retain the
# following acknowledgment:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 7. Modifications are encouraged but must be packaged separately
# as patches to official Zope releases. Distributions that do
# not clearly separate the patches from the original work must
# be clearly labeled as unofficial distributions.
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND
# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL DIGITAL CREATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
# Attribution
#
# Individuals or organizations using this software as a web site
# must provide attribution by placing the accompanying "button"
# and a link to the accompanying "credits page" on the website's
# main entry point. In cases where this placement of
# attribution is not feasible, a separate arrangment must be
# concluded with Digital Creations. Those using the software
# for purposes other than web sites must provide a corresponding
# attribution in locations that include a copyright using a
# manner best suited to the application environment.
#
# This software consists of contributions made by Digital
# Creations and many individuals on behalf of Digital Creations.
# Specific attributions are listed in the accompanying credits
# file.
#
##############################################################################
"""WebDAV XML request objects."""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
sys
,
os
,
string
,
xmllib
from
xmltools
import
XmlParser
from
cStringIO
import
StringIO
zope_id
=
'http://www.zope.org/propsets/default'
dav_id
=
'DAV:'
def
compact
(
self
,
data
):
root
=
XmlParser
().
parse
(
data
)
class
PropFind
:
def
__init__
(
self
,
request
):
self
.
request
=
request
data
=
request
.
get
(
'BODY'
,
''
)
self
.
depth
=
request
.
get_header
(
'Depth'
,
'infinity'
)
self
.
allprop
=
(
not
len
(
data
))
self
.
propname
=
0
self
.
propnames
=
[]
self
.
parse
(
data
)
def
parse
(
self
,
data
):
if
not
data
:
return
root
=
XmlParser
().
parse
(
data
)
e
=
root
.
elements
(
'propfind'
,
ns
=
dav_id
)[
0
]
if
e
.
elements
(
'allprop'
,
ns
=
dav_id
):
self
.
allprop
=
1
return
if
e
.
elements
(
'propname'
,
ns
=
dav_id
):
self
.
propname
=
1
return
prop
=
e
.
elements
(
'prop'
,
ns
=
dav_id
)[
0
]
for
val
in
prop
.
elements
():
self
.
propnames
.
append
((
val
.
name
(),
val
.
namespace
()))
return
def
apply
(
self
,
obj
,
url
=
None
,
depth
=
0
,
result
=
None
,
top
=
1
):
if
result
is
None
:
result
=
StringIO
()
depth
=
self
.
depth
url
=
self
.
request
[
'URL'
]
if
url
[
-
9
:]
==
'/PROPFIND'
:
url
=
url
[:
-
9
]
result
.
write
(
'<?xml version="1.0" encoding="utf-8"?>
\
n
'
\
'<d:multistatus xmlns:d="DAV:" '
\
'xmlns:z="%s">
\
n
'
%
zope_id
)
iscol
=
hasattr
(
aq_base
(
obj
),
'isAnObjectManager'
)
and
\
obj
.
isAnObjectManager
if
iscol
and
url
[
-
1
]
!=
'/'
:
url
=
url
+
'/'
result
.
write
(
'<d:response>
\
n
<d:href>%s</d:href>
\
n
'
%
url
)
if
hasattr
(
obj
,
'__propsets__'
):
for
ps
in
obj
.
propertysheets
.
items
():
if
hasattr
(
aq_base
(
ps
),
'dav__propstat'
):
stat
=
ps
.
dav__propstat
(
self
.
allprop
,
self
.
propnames
)
result
.
write
(
stat
)
result
.
write
(
'</d:response>
\
n
'
)
if
depth
in
(
'1'
,
'infinity'
)
and
iscol
:
for
ob
in
obj
.
objectValues
():
dflag
=
hasattr
(
ob
,
'_p_changed'
)
and
(
ob
.
_p_changed
==
None
)
if
hasattr
(
ob
,
'__dav_resource__'
):
uri
=
os
.
path
.
join
(
url
,
absattr
(
ob
.
id
))
depth
=
depth
==
'infinity'
and
depth
or
0
self
.
apply
(
ob
,
uri
,
depth
,
result
,
top
=
0
)
if
dflag
:
ob
.
_p_deactivate
()
if
not
top
:
return
result
result
.
write
(
'</d:multistatus>'
)
return
result
.
getvalue
()
class
PropPatch
:
def
__init__
(
self
,
request
):
self
.
request
=
request
data
=
request
.
get
(
'BODY'
,
''
)
self
.
values
=
[]
self
.
parse
(
data
)
def
parse
(
self
,
data
):
root
=
XmlParser
().
parse
(
data
)
e
=
root
.
elements
(
'propertyupdate'
,
ns
=
dav_id
)[
0
]
for
ob
in
e
.
elements
():
if
ob
.
name
()
==
'set'
and
ob
.
namespace
()
==
dav_id
:
prop
=
ob
.
elements
(
'prop'
,
ns
=
dav_id
)[
0
]
for
val
in
prop
.
elements
():
# We have to ensure that all tag attrs (including
# an xmlns attr for all xml namespaces used by the
# element and its children) are saved, per rfc2518.
attrs
=
{}
val
.
remap
({})
for
attr
in
val
.
attrs
():
md
[
attr
.
name
()]
=
attr
.
value
()
md
=
{
'attrs'
:
attrs
,
'nsid'
:
val
.
__nskey__
}
item
=
(
val
.
name
(),
val
.
namespace
(),
val
.
strval
(),
md
)
self
.
values
.
append
(
item
)
if
ob
.
name
()
==
'remove'
and
ob
.
namespace
()
==
dav_id
:
prop
=
ob
.
elements
(
'prop'
,
ns
=
dav_id
)[
0
]
for
val
in
prop
.
elements
():
item
=
(
val
.
name
(),
val
.
namespace
())
self
.
values
.
append
(
item
)
def
apply
(
self
,
obj
):
url
=
self
.
request
[
'URL'
]
if
url
[
-
10
:]
==
'/PROPPATCH'
:
url
=
url
[:
-
10
]
if
hasattr
(
aq_base
(
obj
),
'isAnObjectManager'
)
and
\
obj
.
isAnObjectManager
and
url
[
-
1
]
!=
'/'
:
url
=
url
+
'/'
result
=
StringIO
()
errors
=
[]
result
.
write
(
'<?xml version="1.0" encoding="utf-8"?>
\
n
'
\
'<d:multistatus xmlns:d="DAV:" xmlns:z="%s">
\
n
'
\
'<d:response>
\
n
'
\
'<d:href>%s</d:href>
\
n
'
%
(
zope_id
,
url
))
propsets
=
obj
.
propertysheets
for
value
in
self
.
values
:
status
=
'200 OK'
if
len
(
value
)
>
2
:
name
,
ns
,
val
,
md
=
value
propset
=
propsets
.
get
(
ns
,
None
)
if
propset
is
None
:
obj
.
propertysheets
.
manage_addPropertySheet
(
''
,
ns
)
propsets
=
obj
.
propertysheets
.
items
()
propset
=
propsets
.
get
(
ns
)
if
propset
.
hasProperty
(
name
):
try
:
propset
.
_updateProperty
(
name
,
val
,
meta
=
md
)
except
:
errors
.
append
(
str
(
sys
.
exc_value
))
status
=
'409 Conflict'
else
:
try
:
propset
.
_setProperty
(
name
,
val
,
meta
=
md
)
except
:
errors
.
append
(
str
(
sys
.
exc_value
))
status
=
'409 Conflict'
else
:
name
,
ns
=
value
propset
=
propsets
.
get
(
ns
,
None
)
if
propset
is
None
or
not
propset
.
hasProperty
(
name
):
errors
.
append
(
'Property not found: %s'
%
name
)
status
=
'404 Not Found'
else
:
try
:
propset
.
_delProperty
(
name
)
except
:
errors
.
append
(
'%s cannot be deleted.'
%
name
)
status
=
'409 Conflict'
if
result
!=
'200 OK'
:
abort
=
1
result
.
write
(
'<d:propstat xmlns:ps="%s">
\
n
'
\
' <d:prop>
\
n
'
\
' <ps:%s/>
\
n
'
\
' </d:prop>
\
n
'
\
' <d:status>HTTP/1.1 %s</d:status>
\
n
'
\
'</d:propstat>
\
n
'
%
(
ns
,
name
,
status
))
errmsg
=
string
.
join
(
errors
,
'
\
n
'
)
or
'The operation succeded.'
result
.
write
(
'<d:responsedescription>
\
n
'
\
'%s
\
n
'
\
'</d:responsedescription>
\
n
'
\
'</d:response>
\
n
'
\
'</d:multistatus>'
%
errmsg
)
result
=
result
.
getvalue
()
if
not
errors
:
return
result
get_transaction
().
abort
()
result
=
string
.
replace
(
result
,
'200 OK'
,
'424 Failed Dependency'
)
return
result
class
Lock
:
def
__init__
(
self
,
data
):
self
.
scope
=
'exclusive'
self
.
type
=
'write'
self
.
owner
=
''
self
.
parse
(
data
)
def
parse
(
self
,
data
):
root
=
XmlParser
().
parse
(
data
)
info
=
root
.
elements
(
'lockinfo'
,
ns
=
dav_id
)[
0
]
ls
=
info
.
elements
(
'lockscope'
,
ns
=
dav_id
)[
0
]
self
.
scope
=
ls
.
elements
()[
0
].
name
()
lt
=
info
.
elements
(
'locktype'
,
ns
=
dav_id
)[
0
]
self
.
type
=
lt
.
elements
()[
0
].
name
()
lo
=
info
.
elements
(
'owner'
,
ns
=
dav_id
)
if
lo
:
self
.
owner
=
lo
[
0
].
toxml
()
def
absattr
(
attr
):
if
callable
(
attr
):
return
attr
()
return
attr
def
aq_base
(
ob
):
if
hasattr
(
ob
,
'aq_base'
):
return
ob
.
aq_base
return
ob
propfind_xml
=
"""<?xml version="1.0" encoding="utf-8" ?>
<d:propfind xmlns:d="DAV:">
<d:prop xmlns:z="http://www.zope.org/propsets/default">
<z:title/>
<z:author/>
<z:content_type/>
</d:prop>
</d:propfind>
"""
rem_xml
=
"""<?xml version="1.0" encoding="utf-8"?>
<d:propertyupdate xmlns:d="DAV:"
xmlns:z="http://www.zope.org/propsets/default">
<d:remove>
<d:prop>
<z:author/>
<z:title/>
</d:prop>
</d:remove>
</d:propertyupdate>
"""
proppatch_xml
=
"""<?xml version="1.0" encoding="utf-8" ?>
<d:propertyupdate xmlns:d="DAV:"
xmlns:z="http://www.w3.com/standards/z39.50/">
<d:set>
<d:prop>
<z:authors>
<z:Author>Jim Whitehead</z:Author>
<z:Author>Roy Fielding</z:Author>
</z:authors>
</d:prop>
</d:set>
<d:remove>
<d:prop><z:Copyright-Owner/></d:prop>
</d:remove>
</d:propertyupdate>
"""
lock_xml
=
"""<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D='DAV:'>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
<D:owner>
<D:href>http://www.ics.uci.edu/~ejw/contact.html</D:href>
</D:owner>
</D:lockinfo>
"""
multistatus_xml
=
"""<?xml version="1.0" encoding="utf-8" ?>
<multistatus xmlns="DAV:">
<response xmlns:z="http://www.zope.org/dav/">
<href>http://www.foo.bar/container/</href>
<propstat>
<prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox z:type="int"/>
<R:author/>
<creationdate/>
<displayname/>
<resourcetype/>
<supportedlock/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>http://www.foo.bar/container/front.html</href>
<propstat>
<prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox/>
<creationdate/>
<displayname/>
<getcontentlength/>
<getcontenttype/>
<getetag/>
<getlastmodified/>
<resourcetype/>
<supportedlock/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
"""
lib/python/webdav/xmltools.py
0 → 100644
View file @
ee70a7f5
##############################################################################
#
# Zope Public License (ZPL) Version 0.9.4
# ---------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions in source code must retain the above
# copyright notice, this list of conditions, and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions, and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Any use, including use of the Zope software to operate a
# website, must either comply with the terms described below
# under "Attribution" or alternatively secure a separate
# license from Digital Creations.
#
# 4. All advertising materials, documentation, or technical papers
# mentioning features derived from or use of this software must
# display the following acknowledgement:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 5. Names associated with Zope or Digital Creations must not be
# used to endorse or promote products derived from this
# software without prior written permission from Digital
# Creations.
#
# 6. Redistributions of any form whatsoever must retain the
# following acknowledgment:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# 7. Modifications are encouraged but must be packaged separately
# as patches to official Zope releases. Distributions that do
# not clearly separate the patches from the original work must
# be clearly labeled as unofficial distributions.
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND
# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL DIGITAL CREATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
# Attribution
#
# Individuals or organizations using this software as a web site
# must provide attribution by placing the accompanying "button"
# and a link to the accompanying "credits page" on the website's
# main entry point. In cases where this placement of
# attribution is not feasible, a separate arrangment must be
# concluded with Digital Creations. Those using the software
# for purposes other than web sites must provide a corresponding
# attribution in locations that include a copyright using a
# manner best suited to the application environment.
#
# This software consists of contributions made by Digital
# Creations and many individuals on behalf of Digital Creations.
# Specific attributions are listed in the accompanying credits
# file.
#
##############################################################################
"""WebDAV XML parsing tools."""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
sys
,
os
,
string
,
xmllib
from
Acquisition
import
Implicit
from
cStringIO
import
StringIO
type_document
=
0
type_element
=
1
type_attribute
=
2
type_text
=
3
type_cdata
=
4
type_entityref
=
5
type_entity
=
6
type_procinst
=
7
type_comment
=
8
type_notation
=
9
class
Node
(
Implicit
):
"""Common base class for Node objects."""
__name__
=
''
__value__
=
''
__attrs__
=
[]
__nodes__
=
[]
__nskey__
=
''
def
name
(
self
):
return
self
.
__name__
def
attrs
(
self
):
return
self
.
__attrs__
def
value
(
self
):
return
self
.
__value__
def
nodes
(
self
):
return
self
.
__nodes__
def
nskey
(
self
):
return
self
.
__nskey__
def
addNode
(
self
,
node
):
self
.
__nodes__
.
append
(
node
.
__of__
(
self
))
def
namespace
(
self
):
nskey
=
self
.
__nskey__
while
1
:
if
hasattr
(
self
,
'__nsdef__'
):
val
=
self
.
__nsdef__
.
get
(
nskey
,
None
)
if
val
is
not
None
:
return
val
if
not
hasattr
(
self
,
'aq_parent'
):
return
''
self
=
self
.
aq_parent
def
elements
(
self
,
name
=
None
,
ns
=
None
,
lower
=
string
.
lower
):
nodes
=
[]
name
=
name
and
lower
(
name
)
for
node
in
self
.
__nodes__
:
if
node
.
__type__
==
type_element
and
\
((
name
is
None
)
or
(
lower
(
node
.
__name__
)
==
name
))
and
\
((
ns
is
None
)
or
(
node
.
namespace
()
==
ns
)):
nodes
.
append
(
node
)
return
nodes
def
__getitem__
(
self
,
n
):
return
self
.
__nodes__
[
n
]
def
qname
(
self
):
ns
=
self
.
__nskey__
if
ns
:
ns
=
'%s:'
%
ns
return
'%s%s'
%
(
ns
,
self
.
__name__
)
def
toxml
(
self
):
return
self
.
__value__
def
strval
(
self
):
return
self
.
toxml
()
class
Document
(
Node
):
def
__init__
(
self
,
encoding
=
'utf-8'
,
stdalone
=
''
):
self
.
__name__
=
'document'
self
.
__nodes__
=
[]
self
.
encoding
=
encoding
self
.
stdalone
=
stdalone
self
.
document
=
self
def
toxml
(
self
):
result
=
[
'<?xml version="1.0" encoding="%s"?>'
%
self
.
encoding
]
for
node
in
self
.
__nodes__
:
result
.
append
(
node
.
toxml
())
return
string
.
join
(
result
,
''
)
def
__del__
(
self
):
self
.
document
=
None
print
'bye!'
class
Element
(
Node
):
__type__
=
type_element
def
__init__
(
self
,
name
,
attrs
=
{}):
self
.
__name__
=
name
self
.
__attrs__
=
[]
self
.
__nodes__
=
[]
self
.
__nsdef__
=
{}
self
.
__nskey__
=
''
for
name
,
val
in
attrs
.
items
():
attr
=
Attribute
(
name
,
val
)
self
.
__attrs__
.
append
(
attr
)
self
.
ns_parse
()
parts
=
string
.
split
(
self
.
__name__
,
':'
)
if
len
(
parts
)
>
1
:
self
.
__nskey__
=
parts
[
0
]
self
.
__name__
=
string
.
join
(
parts
[
1
:],
':'
)
def
ns_parse
(
self
):
nsdef
=
self
.
__nsdef__
=
{}
for
attr
in
self
.
attrs
():
name
,
val
=
attr
.
name
(),
attr
.
value
()
key
=
string
.
lower
(
name
)
if
key
[:
6
]
==
'xmlns:'
:
nsdef
[
name
[
6
:]]
=
val
elif
key
==
'xmlns'
:
nsdef
[
''
]
=
val
def
fixup
(
self
):
self
.
__attrs__
=
map
(
lambda
n
,
s
=
self
:
n
.
__of__
(
s
),
self
.
__attrs__
)
def
get_attr
(
self
,
name
,
ns
=
None
,
default
=
None
):
for
attr
in
self
.
__attrs__
:
if
attr
.
name
()
==
name
and
(
ns
is
None
)
or
(
ns
==
attr
.
namespace
()):
return
attr
return
default
def
remap
(
self
,
dict
,
n
=
0
,
top
=
1
):
# The remap method effectively rewrites an element and all of its
# children, consolidating namespace declarations into the element
# on which the remap function is called and fixing up namespace
# lookup structures.
nsval
=
self
.
namespace
()
if
not
nsval
:
nsid
=
''
elif
not
dict
.
has_key
(
nsval
):
nsid
=
'ns%d'
%
n
dict
[
nsval
]
=
nsid
n
=
n
+
1
else
:
nsid
=
dict
[
nsval
]
for
attr
in
self
.
__attrs__
:
dict
,
n
=
attr
.
remap
(
dict
,
n
,
0
)
for
node
in
self
.
elements
():
dict
,
n
=
node
.
remap
(
dict
,
n
,
0
)
attrs
=
[]
for
attr
in
self
.
__attrs__
:
name
=
attr
.
__name__
if
not
(((
len
(
name
)
>=
6
)
and
(
name
[:
6
]
==
'xmlns:'
))
or
\
name
==
'xmlns'
):
attrs
.
append
(
attr
)
self
.
__attrs__
=
attrs
self
.
__nsdef__
=
{}
self
.
__nskey__
=
nsid
if
top
:
attrs
=
self
.
__attrs__
keys
=
dict
.
keys
()
keys
.
sort
()
for
key
in
keys
:
attr
=
Attribute
(
'xmlns:%s'
%
dict
[
key
],
key
)
attrs
.
append
(
attr
.
__of__
(
self
))
self
.
__attrs__
=
attrs
self
.
ns_parse
()
return
dict
,
n
def
toxml
(
self
):
qname
=
self
.
qname
()
result
=
[
'<%s'
%
qname
]
for
attr
in
self
.
__attrs__
:
result
.
append
(
attr
.
toxml
())
if
not
self
.
__value__
and
not
self
.
__nodes__
:
result
.
append
(
'/>'
)
else
:
result
.
append
(
'>'
)
for
node
in
self
.
__nodes__
:
result
.
append
(
node
.
toxml
())
result
.
append
(
'</%s>'
%
qname
)
return
string
.
join
(
result
,
''
)
def
strval
(
self
,
top
=
1
):
if
not
self
.
__value__
and
not
self
.
__nodes__
:
return
''
result
=
map
(
lambda
n
:
n
.
toxml
(),
self
.
__nodes__
)
return
string
.
join
(
result
,
''
)
class
Attribute
(
Node
):
__type__
=
type_attribute
def
__init__
(
self
,
name
,
val
):
self
.
__name__
=
name
self
.
__value__
=
val
self
.
__nskey__
=
''
parts
=
string
.
split
(
name
,
':'
)
if
len
(
parts
)
>
1
:
pre
=
string
.
lower
(
parts
[
0
])
if
not
(
pre
in
(
'xml'
,
'xmlns'
)):
self
.
__nskey__
=
parts
[
0
]
self
.
__name__
=
string
.
join
(
parts
[
1
:],
':'
)
def
remap
(
self
,
dict
,
n
=
0
,
top
=
1
):
nsval
=
self
.
namespace
()
if
not
nsval
:
nsid
=
''
elif
not
dict
.
has_key
(
nsval
):
nsid
=
'ns%d'
%
n
dict
[
nsval
]
=
nsid
n
=
n
+
1
else
:
nsid
=
dict
[
nsval
]
self
.
__nskey__
=
nsid
return
dict
,
n
def
toxml
(
self
):
ns
=
self
.
__nskey__
if
ns
:
ns
=
'%s:'
%
ns
return
' %s%s="%s"'
%
(
ns
,
self
.
__name__
,
self
.
__value__
)
class
Text
(
Node
):
__name__
=
'#text'
__type__
=
type_text
def
__init__
(
self
,
val
):
self
.
__value__
=
val
def
toxml
(
self
):
return
escape
(
self
.
__value__
)
class
CData
(
Node
):
__type__
=
type_cdata
__name__
=
'#cdata'
def
__init__
(
self
,
val
):
self
.
__value__
=
val
def
toxml
(
self
):
return
'<![CDATA[%s]]>'
%
self
.
__value__
class
EntityRef
(
Node
):
__name__
=
'#entityref'
__type__
=
type_entityref
def
__init__
(
self
,
val
):
self
.
__value__
=
val
def
toxml
(
self
):
return
'&%s;'
%
self
.
__value__
class
Entity
(
Node
):
__name__
=
'#entity'
__type__
=
type_entity
def
__init__
(
self
,
name
,
pubid
,
sysid
,
nname
):
self
.
__value__
=
val
def
toxml
(
self
):
return
''
class
ProcInst
(
Node
):
__type__
=
type_procinst
def
__init__
(
self
,
name
,
val
):
self
.
__name__
=
name
self
.
__value__
=
val
def
toxml
(
self
):
return
'<?%s %s?>'
%
(
self
.
__name__
,
self
.
__value__
)
class
Comment
(
Node
):
__name__
=
'#comment'
__type__
=
type_comment
def
__init__
(
self
,
val
):
self
.
__value__
=
val
def
toxml
(
self
):
return
'<!--%s-->'
%
self
.
__value__
class
XmlParser
(
xmllib
.
XMLParser
):
def
__init__
(
self
):
xmllib
.
XMLParser
.
__init__
(
self
)
self
.
root
=
None
self
.
node
=
None
def
parse
(
self
,
data
):
self
.
feed
(
data
)
self
.
close
()
return
self
.
root
def
add
(
self
,
node
):
self
.
node
.
addNode
(
node
)
def
push
(
self
,
node
):
self
.
node
.
addNode
(
node
)
self
.
node
=
self
.
node
.
__nodes__
[
-
1
]
def
pop
(
self
):
self
.
node
=
self
.
node
.
aq_parent
def
unknown_starttag
(
self
,
name
,
attrs
):
node
=
Element
(
name
,
attrs
)
self
.
push
(
node
)
# Fixup aq chain!
self
.
node
.
fixup
()
def
unknown_endtag
(
self
,
name
):
self
.
pop
()
def
handle_xml
(
self
,
encoding
,
stdalone
):
self
.
root
=
Document
(
encoding
,
stdalone
)
self
.
node
=
self
.
root
def
handle_doctype
(
self
,
tag
,
pubid
,
syslit
,
data
):
pass
def
handle_entity
(
self
,
name
,
strval
,
pubid
,
syslit
,
ndata
):
self
.
add
(
Entity
(
name
,
strval
,
pubid
,
syslit
,
ndata
))
def
handle_cdata
(
self
,
data
):
self
.
add
(
CData
(
data
))
def
handle_proc
(
self
,
name
,
data
):
self
.
add
(
ProcInst
(
name
,
data
))
def
handle_comment
(
self
,
data
):
self
.
add
(
Comment
(
data
))
def
handle_data
(
self
,
data
):
self
.
add
(
Text
(
data
))
def
unknown_entityref
(
self
,
data
):
self
.
add
(
EntityRef
(
data
))
def
escape
(
data
,
entities
=
{}):
# snarfed from xml.util...
data
=
string
.
replace
(
data
,
"&"
,
"&"
)
data
=
string
.
replace
(
data
,
"<"
,
"<"
)
data
=
string
.
replace
(
data
,
">"
,
">"
)
for
chars
,
entity
in
entities
.
items
():
data
=
string
.
replace
(
data
,
chars
,
entity
)
return
data
def
remap
(
data
):
root
=
XmlParser
().
parse
(
data
)
dict
=
{
'DAV:'
:
'd'
,
'http://www.zope.org/propsets/default'
:
'z'
}
root
.
elements
()[
0
].
remap
(
dict
,
0
)
return
root
.
toxml
()
def
remap_test
():
file
=
open
(
'big.xml'
,
'r'
)
data
=
file
.
read
()
file
.
close
()
data
=
remap
(
data
)
file
=
open
(
'new.xml'
,
'w'
)
file
.
write
(
data
)
file
.
close
()
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