Rev 58: Implent PROPFIND in the dav test server to make bzr test suite happy. in http://bazaar.launchpad.net/%7Ebzr/bzr.webdav/webdav

Vincent Ladeuil v.ladeuil+lp at free.fr
Mon Jun 9 15:24:28 BST 2008


At http://bazaar.launchpad.net/%7Ebzr/bzr.webdav/webdav

------------------------------------------------------------
revno: 58
revision-id: v.ladeuil+lp at free.fr-20080609142425-xqm4pmfv2spdatgj
parent: v.ladeuil+lp at free.fr-20080609081450-xvf1ilxvwdvf9st5
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: webdav
timestamp: Mon 2008-06-09 16:24:25 +0200
message:
  Implent PROPFIND in the dav test server to make bzr test suite happy.
  
  * tests/dav_server.py:
  (TestingDAVRequestHandler._generate_response,
  TestingDAVRequestHandler._generate_dir_responses,
  TestingDAVRequestHandler.do_PROPFIND): Implements PROPPFIND
  request.
modified:
  tests/dav_server.py            dav_server.py-20080609075311-lfywqma6p6uijow7-1
  webdav.py                      webdav.py-20060816232542-enpjxth2743ttqpq-3
-------------- next part --------------
=== modified file 'tests/dav_server.py'
--- a/tests/dav_server.py	2008-06-09 08:14:50 +0000
+++ b/tests/dav_server.py	2008-06-09 14:24:25 +0000
@@ -26,12 +26,14 @@
 import os.path # FIXME: Can't we use bzrlib.osutils ?
 import re
 import shutil # FIXME: Can't we use bzrlib.osutils ?
-import urlparse # FIXME: Can't we use bzrlib.utlutils ?
+import stat
+import urlparse # FIXME: Can't we use bzrlib.urlutils ?
 
 
 from bzrlib import (
     tests,
     trace,
+    urlutils,
     )
 from bzrlib.tests import http_server
 
@@ -273,7 +275,7 @@
 
         url_to = self.headers.get('Destination')
         if url_to is None:
-            self.send_error(400,"Destination header missing")
+            self.send_error(400, "Destination header missing")
             return
         overwrite_header = self.headers.get('Overwrite')
         if overwrite_header == 'F':
@@ -288,15 +290,15 @@
         abs_from = self.translate_path(self.path)
         abs_to = self.translate_path(rel_to)
         if should_overwrite is False and os.access(abs_to, os.F_OK):
-            self.send_error(412,"Precondition Failed")
+            self.send_error(412, "Precondition Failed")
             return
         try:
             os.rename(abs_from, abs_to)
         except (IOError, OSError), e:
             if e.errno == errno.ENOENT:
-                self.send_error(404,"File not found") ;
+                self.send_error(404, "File not found") ;
             else:
-                self.send_error(409,"Conflict") ;
+                self.send_error(409, "Conflict") ;
         else:
             # TODO: We may be able  to return 204 "No content" if
             # rel_to was existing (even  if the "No content" part
@@ -304,6 +306,110 @@
             self.send_response(201)
             self.end_headers()
 
+    def _generate_response(self, path):
+        local_path = self.translate_path(path)
+        st = os.stat(local_path)
+        prop = dict()
+
+        def _prop(ns, name, value=None):
+            if value is None:
+                return '<%s:%s/>' % (ns, name)
+            else:
+                return '<%s:%s>%s</%s:%s>' % (ns, name, value, ns, name)
+
+        # For namespaces (and test purposes), where apache2 use:
+        # - lp1, we use liveprop,
+        # - lp2, we use bzr
+        if stat.S_ISDIR(st.st_mode):
+            dpath = path
+            if not dpath.endswith('/'):
+                dpath +=  '/'
+            prop['href'] = _prop('D', 'href', dpath)
+            prop['type'] = _prop('liveprop', 'resourcetype', '<D:collection/>')
+            prop['length'] = ''
+            prop['exec'] = ''
+        else:
+            # FIXME: assert S_ISREG ? Handle symlinks ?
+            prop['href'] = _prop('D', 'href', path)
+            prop['type'] = _prop('liveprop', 'resourcetype')
+            prop['length'] = _prop('liveprop', 'getcontentlength',
+                                          st.st_size)
+            if st.st_mode & stat.S_IXUSR:
+                is_exec = 'T'
+            else:
+                is_exec = 'F'
+            prop['exec'] = _prop('bzr', 'excutable', is_exec)
+        prop['status'] = _prop('D', 'status', 'HTTP/1.1 200 OK')
+
+        response = """<D:response xmlns:liveprop="DAV:" xmlns:bzr="DAV:">
+    %(href)s
+    <D:propstat>
+        <D:prop>
+             %(type)s
+             %(length)s
+             %(exec)s
+        </D:prop>
+        %(status)s
+    </D:propstat>
+</D:response>
+""" % prop
+        return response, st
+
+    def _generate_dir_responses(self, path, depth):
+        local_path = self.translate_path(path)
+        entries = os.listdir(local_path)
+
+        for entry in entries:
+            entry_path = urlutils.escape(entry)
+            if path.endswith('/'):
+                entry_path = path + entry_path
+            else:
+                entry_path = path + '/' + entry_path
+            response, st = self._generate_response(entry_path)
+            yield response
+            if depth == 'Infinity' and stat.S_ISDIR(st.st_mode):
+                for sub_resp in self._generate_dir_responses(entry_path, depth):
+                    yield sub_resp
+
+    def do_PROPFIND(self):
+        """Serve a PROPFIND request."""
+        depth = self.headers.get('Depth')
+        if depth is None:
+            depth = 'Infinity'
+        if depth not in ('0', '1', 'Infinity'):
+            self.send_error(400, "Bad Depth")
+            return
+
+        path = self.translate_path(self.path)
+        # Don't bother parsing the body, we handle only allprop anyway.
+        # FIXME: Handle the body :)
+        data = self.read_body()
+
+        try:
+            response, st = self._generate_response(self.path)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                self.send_error(404)
+                return
+            else:
+                raise
+
+        if depth in ('1', 'Infinity') and stat.S_ISDIR(st.st_mode):
+            dir_responses = self._generate_dir_responses(self.path, depth)
+        else:
+            dir_responses = []
+
+        # Generate the response, we don't care about performance, so we just
+        # expand everything into a big string.
+        response = """<?xml version="1.0" encoding="utf-8"?>
+<D:multistatus xmlns:D="DAV:" xmlns:ns0="DAV:">
+%s%s
+</D:multistatus>""" % (response, ''.join(list(dir_responses)))
+
+        self.send_response(207)
+        self.send_header('Content-length', len(response))
+        self.end_headers()
+        self.wfile.write(response)
 
 class DAVServer(http_server.HttpServer):
     """Subclass of HttpServer that gives http+webdav urls.

=== modified file 'webdav.py'
--- a/webdav.py	2008-06-09 08:14:50 +0000
+++ b/webdav.py	2008-06-09 14:24:25 +0000
@@ -774,6 +774,7 @@
         if code == 404:
             raise errors.NoSuchFile(abspath)
         if code == 409:
+            # FIXME: Could this really occur ?
             # More precisely some intermediate directories are missing
             raise errors.NoSuchFile(abspath)
         if code != 207:



More information about the bazaar-commits mailing list