Rev 56: Split out dav_server into its own file. in http://bazaar.launchpad.net/%7Ebzr/bzr.webdav/webdav

Vincent Ladeuil v.ladeuil+lp at free.fr
Mon Jun 9 09:02:20 BST 2008


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

------------------------------------------------------------
revno: 56
revision-id: v.ladeuil+lp at free.fr-20080609080217-73bsl8r1x7b19fut
parent: v.ladeuil+lp at free.fr-20080609075046-9k3hzahkjjbjbki1
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: webdav
timestamp: Mon 2008-06-09 10:02:17 +0200
message:
  Split out dav_server into its own file.
added:
  tests/dav_server.py            dav_server.py-20080609075311-lfywqma6p6uijow7-1
modified:
  TODO                           todo-20060820113924-ioaocfzvsb4wq9z1-1
  tests/test_webdav.py           test_webdav.py-20060823130244-qvg4wqdodnmf5nhs-1
  webdav.py                      webdav.py-20060816232542-enpjxth2743ttqpq-3
-------------- next part --------------
=== modified file 'TODO'
--- a/TODO	2008-06-09 07:50:46 +0000
+++ b/TODO	2008-06-09 08:02:17 +0000
@@ -26,8 +26,6 @@
 
 * tests
 
-** Move the server into its own file
-
 ** Implement the testing of the range header for PUT requests
    (GET request are already heavily tested in bzr). Test servers
    are available there too. This will also help for reporting

=== added file 'tests/dav_server.py'
--- a/tests/dav_server.py	1970-01-01 00:00:00 +0000
+++ b/tests/dav_server.py	2008-06-09 08:02:17 +0000
@@ -0,0 +1,392 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""DAV test server.
+
+This defines the TestingDAVRequestHandler and the DAVServer classes which
+implements the DAV specification parts used by the webdav plugin.
+"""
+
+
+import errno
+import os
+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 ?
+
+
+from bzrlib import (
+    tests,
+    trace,
+    )
+from bzrlib.tests import http_server
+
+
+class TestingDAVRequestHandler(http_server.TestingHTTPRequestHandler):
+    """
+    Subclass of TestingHTTPRequestHandler handling DAV requests.
+
+    This is not a full implementation of a DAV server, only the parts
+    really used by the plugin are.
+    """
+
+    _RANGE_HEADER_RE = re.compile(
+        r'bytes (?P<begin>\d+)-(?P<end>\d+)/(?P<size>\d+|\*)')
+
+
+    def _read(self, length):
+        """Read the client socket"""
+        return self.rfile.read(length)
+
+    def _readline(self):
+        """Read a full line on the client socket"""
+        return self.rfile.readline()
+
+    def read_body(self):
+        """Read the body either by chunk or as a whole."""
+        content_length = self.headers.get('Content-Length')
+        encoding = self.headers.get('Transfer-Encoding')
+        if encoding is not None:
+            assert encoding == 'chunked'
+            body = []
+            # We receive the content by chunk
+            while True:
+                length, data = self.read_chunk()
+                if length == 0:
+                    break
+                body.append(data)
+            body = ''.join(body)
+
+        else:
+            if content_length is not None:
+                body = self._read(int(content_length))
+
+        return body
+
+    def read_chunk(self):
+        """Read a chunk of data.
+
+        A chunk consists of:
+        - a line containing the length of the data in hexa,
+        - the data.
+        - a empty line.
+
+        An empty chunk specifies a length of zero
+        """
+        length = int(self._readline(),16)
+        data = None
+        if length != 0:
+            data = self._read(length)
+            # Eats the newline following the chunk
+            self._readline()
+        return length, data
+
+    def send_head(self):
+        """Specialized version of SimpleHttpServer.
+
+        We *don't* want the apache behavior of permanently redirecting
+        directories without trailing slashes to directories with trailing
+        slashes. That's a waste and a severe penalty for clients with high
+        latency.
+
+        The installation documentation of the plugin should mention the
+        DirectorySlash apache directive and insists on turning it *Off*.
+        """
+        path = self.translate_path(self.path)
+        f = None
+        if os.path.isdir(path):
+            for index in "index.html", "index.htm":
+                index = os.path.join(path, index)
+                if os.path.exists(index):
+                    path = index
+                    break
+            else:
+                return self.list_directory(path)
+        ctype = self.guess_type(path)
+        if ctype.startswith('text/'):
+            mode = 'r'
+        else:
+            mode = 'rb'
+        try:
+            f = open(path, mode)
+        except IOError:
+            self.send_error(404, "File not found")
+            return None
+        self.send_response(200)
+        self.send_header("Content-type", ctype)
+        fs = os.fstat(f.fileno())
+        self.send_header("Content-Length", str(fs[6]))
+        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
+        self.end_headers()
+        return f
+
+    def do_PUT(self):
+        """Serve a PUT request."""
+        # FIXME: test_put_file_unicode makes us emit a traceback because a
+        # UnicodeEncodeError occurs after the request headers have been sent be
+        # before the body can be send. It's harmless and do not make the test
+        # fails. Adressing that will mean protecting all reads from the socket,
+        # which is too heavy for now -- vila 20070917
+        path = self.translate_path(self.path)
+        trace.mutter("do_PUT rel: [%s], abs: [%s]" % (self.path,path))
+
+        do_append = False
+        # Check the Content-Range header
+        range_header = self.headers.get('Content-Range')
+        if range_header is not None:
+            match = self._RANGE_HEADER_RE.match(range_header)
+            if match is None:
+                # FIXME: RFC2616 says to return a 501 if we don't
+                # understand the Content-Range header, but Apache
+                # just ignores them (bad Apache).
+                self.send_error(501, 'Not Implemented')
+                return
+            begin = int(match.group('begin'))
+            do_append = True
+
+        if self.headers.get('Expect') == '100-continue':
+            # Tell the client to go ahead, we're ready to get the content
+            self.send_response(100,"Continue")
+            self.end_headers()
+
+        try:
+            trace.mutter("do_PUT will try to open: [%s]" % path)
+            # Always write in binary mode.
+            if do_append:
+                f = open(path,'ab')
+                f.seek(begin)
+            else:
+                f = open(path, 'wb')
+        except (IOError, OSError), e :
+            self.send_error(409, 'Conflict')
+            return
+
+        try:
+            data = self.read_body()
+            f.write(data)
+        except (IOError, OSError):
+            # FIXME: We leave a partially written file here
+            self.send_error(409, "Conflict")
+            f.close()
+            return
+        f.close()
+        trace.mutter("do_PUT done: [%s]" % self.path)
+        self.send_response(201)
+        self.end_headers()
+
+    def do_MKCOL(self):
+        """
+        Serve a MKCOL request.
+
+        MKCOL is an mkdir in DAV terminology for our part.
+        """
+        path = self.translate_path(self.path)
+        trace.mutter("do_MKCOL rel: [%s], abs: [%s]" % (self.path,path))
+        try:
+            os.mkdir(path)
+        except (IOError, OSError),e:
+            if e.errno in (errno.ENOENT, ):
+                self.send_error(409, "Conflict")
+            elif e.errno in (errno.EEXIST, errno.ENOTDIR):
+                self.send_error(405, "Not allowed")
+            else:
+                # Ok we fail for an unnkown reason :-/
+                raise
+        else:
+            self.send_response(201)
+            self.end_headers()
+
+    def do_COPY(self):
+        """Serve a COPY request."""
+
+        url_to = self.headers.get('Destination')
+        if url_to is None:
+            self.send_error(400,"Destination header missing")
+            return
+        (scheme, netloc, rel_to,
+         params, query, fragment) = urlparse.urlparse(url_to)
+        trace.mutter("urlparse: (%s) [%s]" % (url_to, rel_to))
+        trace.mutter("do_COPY rel_from: [%s], rel_to: [%s]" % (self.path,
+                                                               rel_to))
+        abs_from = self.translate_path(self.path)
+        abs_to = self.translate_path(rel_to)
+        try:
+            # TODO:  Check that rel_from  exists and  rel_to does
+            # not.  In the  mean  time, just  go  along and  trap
+            # exceptions
+            shutil.copyfile(abs_from,abs_to)
+        except (IOError, OSError), e:
+            if e.errno == errno.ENOENT:
+                self.send_error(404,"File not found") ;
+            else:
+                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
+            # seems misleading, RFC2518 says so, stop arguing :)
+            self.send_response(201)
+            self.end_headers()
+
+    def do_DELETE(self):
+        """Serve a DELETE request.
+
+        We don't implement a true DELETE as DAV defines it
+        because we *should* fail to delete a non empty dir.
+        """
+        path = self.translate_path(self.path)
+        trace.mutter("do_DELETE rel: [%s], abs: [%s]" % (self.path, path))
+        try:
+            # DAV  makes no  distinction between  files  and dirs
+            # when required to nuke them,  but we have to. And we
+            # also watch out for symlinks.
+            real_path = os.path.realpath(path)
+            if os.path.isdir(real_path):
+                os.rmdir(path)
+            else:
+                os.remove(path)
+        except (IOError, OSError),e:
+            if e.errno in (errno.ENOENT, ):
+                self.send_error(404, "File not found")
+            else:
+                # Ok we fail for an unnkown reason :-/
+                raise
+        else:
+            self.send_response(204) # Default success code
+            self.end_headers()
+
+    def do_MOVE(self):
+        """Serve a MOVE request."""
+
+        url_to = self.headers.get('Destination')
+        if url_to is None:
+            self.send_error(400,"Destination header missing")
+            return
+        overwrite_header = self.headers.get('Overwrite')
+        if overwrite_header == 'F':
+            should_overwrite = False
+        else:
+            should_overwrite = True
+        (scheme, netloc, rel_to,
+         params, query, fragment) = urlparse.urlparse(url_to)
+        trace.mutter("urlparse: (%s) [%s]" % (url_to, rel_to))
+        trace.mutter("do_MOVE rel_from: [%s], rel_to: [%s]" % (self.path,
+                                                               rel_to))
+        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")
+            return
+        try:
+            os.rename(abs_from, abs_to)
+        except (IOError, OSError), e:
+            if e.errno == errno.ENOENT:
+                self.send_error(404,"File not found") ;
+            else:
+                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
+            # seems misleading, RFC2518 says so, stop arguing :)
+            self.send_response(201)
+            self.end_headers()
+
+class TestingDAVAppendRequestHandler(TestingDAVRequestHandler):
+    """
+    Subclass of TestingDAVRequestHandler implementing te APPEND command.
+
+    http://www.ietf.org/internet-drafts/draft-suma-append-patch-00.txt
+    propose two new commands: APPEND and PATCH. Their description
+    is sparse, this is a best effort attempt to implement the
+    APPEND command.
+    """
+    def do_APPEND(self):
+        """Serve an APPEND request"""
+        path = self.translate_path(self.path)
+        trace.mutter("do_APPEND rel: [%s], abs: [%s]" % (self.path,path))
+
+        if self.headers.get('Expect') == '100-continue':
+            # Tell the client to go ahead, we're ready to get the content
+            self.send_response(100,"Continue")
+            self.end_headers()
+
+        try:
+            # Always write in binary mode.
+            trace.mutter("do_APPEND will try to open: [%s]" % path)
+            f = open(path, 'wb+')
+        except (IOError, OSError), e :
+            self.send_error(409, "Conflict")
+            return
+
+        try:
+            data = self.read_body()
+            f.write(data)
+        except (IOError, OSError):
+            # FIXME: We leave a partially updated file here
+            self.send_error(409, "Conflict")
+            f.close()
+            return
+        f.close()
+        trace.mutter("do_APPEND done: [%s]" % self.path)
+        # FIXME: We should send 204 if the file didn't exist before
+        self.send_response(201)
+        self.end_headers()
+
+
+class DAVServer(http_server.HttpServer):
+    """Subclass of HttpServer that gives http+webdav urls.
+
+    This is for use in testing: connections to this server will always go
+    through _urllib where possible.
+    """
+
+    def __init__(self):
+        # We    have   special    requests    to   handle    that
+        # HttpServer_urllib doesn't know about
+        super(DAVServer,self).__init__(TestingDAVRequestHandler)
+
+    # urls returned by this server should require the webdav client impl
+    _url_protocol = 'http+webdav'
+
+
+class DAVServer_append(DAVServer):
+    """Subclass of HttpServer that gives http+webdav urls.
+
+    This is for use in testing: connections to this server will always go
+    through pycurl where possible.
+    This server implements the proposed
+    (www.ietf.org/internet-drafts/draft-suma-append-patch-00.txt)
+    APPEND request.
+    """
+
+    def __init__(self):
+        # We    have   special    requests    to   handle    that
+        # HttpServer_PyCurl don't know about
+        super(DAVServer_append,self).__init__(TestingDAVAppendRequestHandler)
+
+    # urls returned by this server should require the webdav client impl
+    _url_protocol = 'http+webdav'
+
+
+class TestCaseWithDAVServer(tests.TestCaseWithTransport):
+    """A support class that provides urls that are http+webdav://.
+
+    This is done by forcing the server to be an http DAV one.
+    """
+    def setUp(self):
+        super(TestCaseWithDAVServer, self).setUp()
+        self.transport_server = DAVServer
+

=== modified file 'tests/test_webdav.py'
--- a/tests/test_webdav.py	2008-06-09 07:50:46 +0000
+++ b/tests/test_webdav.py	2008-06-09 08:02:17 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 Canonical Ltd
+# Copyright (C) 2008 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -14,400 +14,19 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-"""Tests for the wedav plugin.
-
-This defines the TestingDAVRequestHandler and the DAVServer classes which
-implements the DAV specification parts used by the webdav plugin.
-"""
+"""Tests for the wedav plugin."""
 
 from cStringIO import StringIO
-import errno
-import httplib
-import os
-import os.path
-import re
-import socket
-import string
-import shutil
 import stat
-import sys
-import time
-import urlparse
 
 
 from bzrlib import (
     errors,
     tests,
-    trace,
-    )
-from bzrlib.tests import (
-    http_utils,
-    TestUtil,
-    )
-from bzrlib.tests.http_server import (
-    HttpServer,
-    TestingHTTPRequestHandler,
-    )
-from bzrlib.transport.http import _urllib2_wrappers
-
-
+    )
 from bzrlib.plugins.webdav import webdav
 
 
-class TestingDAVRequestHandler(TestingHTTPRequestHandler):
-    """
-    Subclass of TestingHTTPRequestHandler handling DAV requests.
-
-    This is not a full implementation of a DAV server, only the parts
-    really used by the plugin are.
-    """
-
-    _RANGE_HEADER_RE = re.compile(
-        r'bytes (?P<begin>\d+)-(?P<end>\d+)/(?P<size>\d+|\*)')
-
-
-    def _read(self, length):
-        """Read the client socket"""
-        return self.rfile.read(length)
-
-    def _readline(self):
-        """Read a full line on the client socket"""
-        return self.rfile.readline()
-
-    def read_body(self):
-        """Read the body either by chunk or as a whole."""
-        content_length = self.headers.get('Content-Length')
-        encoding = self.headers.get('Transfer-Encoding')
-        if encoding is not None:
-            assert encoding == 'chunked'
-            body = []
-            # We receive the content by chunk
-            while True:
-                length, data = self.read_chunk()
-                if length == 0:
-                    break
-                body.append(data)
-            body = ''.join(body)
-
-        else:
-            if content_length is not None:
-                body = self._read(int(content_length))
-
-        return body
-
-    def read_chunk(self):
-        """Read a chunk of data.
-
-        A chunk consists of:
-        - a line containing the length of the data in hexa,
-        - the data.
-        - a empty line.
-
-        An empty chunk specifies a length of zero
-        """
-        length = int(self._readline(),16)
-        data = None
-        if length != 0:
-            data = self._read(length)
-            # Eats the newline following the chunk
-            self._readline()
-        return length, data
-
-    def send_head(self):
-        """Specialized version of SimpleHttpServer.
-
-        We *don't* want the apache behavior of permanently redirecting
-        directories without trailing slashes to directories with trailing
-        slashes. That's a waste and a severe penalty for clients with high
-        latency.
-
-        The installation documentation of the plugin should mention the
-        DirectorySlash apache directive and insists on turning it *Off*.
-        """
-        path = self.translate_path(self.path)
-        f = None
-        if os.path.isdir(path):
-            for index in "index.html", "index.htm":
-                index = os.path.join(path, index)
-                if os.path.exists(index):
-                    path = index
-                    break
-            else:
-                return self.list_directory(path)
-        ctype = self.guess_type(path)
-        if ctype.startswith('text/'):
-            mode = 'r'
-        else:
-            mode = 'rb'
-        try:
-            f = open(path, mode)
-        except IOError:
-            self.send_error(404, "File not found")
-            return None
-        self.send_response(200)
-        self.send_header("Content-type", ctype)
-        fs = os.fstat(f.fileno())
-        self.send_header("Content-Length", str(fs[6]))
-        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
-        self.end_headers()
-        return f
-
-    def do_PUT(self):
-        """Serve a PUT request."""
-        # FIXME: test_put_file_unicode makes us emit a traceback because a
-        # UnicodeEncodeError occurs after the request headers have been sent be
-        # before the body can be send. It's harmless and do not make the test
-        # fails. Adressing that will mean protecting all reads from the socket,
-        # which is too heavy for now -- vila 20070917
-        path = self.translate_path(self.path)
-        trace.mutter("do_PUT rel: [%s], abs: [%s]" % (self.path,path))
-
-        do_append = False
-        # Check the Content-Range header
-        range_header = self.headers.get('Content-Range')
-        if range_header is not None:
-            match = self._RANGE_HEADER_RE.match(range_header)
-            if match is None:
-                # FIXME: RFC2616 says to return a 501 if we don't
-                # understand the Content-Range header, but Apache
-                # just ignores them (bad Apache).
-                self.send_error(501, 'Not Implemented')
-                return
-            begin = int(match.group('begin'))
-            do_append = True
-
-        if self.headers.get('Expect') == '100-continue':
-            # Tell the client to go ahead, we're ready to get the content
-            self.send_response(100,"Continue")
-            self.end_headers()
-
-        try:
-            trace.mutter("do_PUT will try to open: [%s]" % path)
-            # Always write in binary mode.
-            if do_append:
-                f = open(path,'ab')
-                f.seek(begin)
-            else:
-                f = open(path, 'wb')
-        except (IOError, OSError), e :
-            self.send_error(409, 'Conflict')
-            return
-
-        try:
-            data = self.read_body()
-            f.write(data)
-        except (IOError, OSError):
-            # FIXME: We leave a partially written file here
-            self.send_error(409, "Conflict")
-            f.close()
-            return
-        f.close()
-        trace.mutter("do_PUT done: [%s]" % self.path)
-        self.send_response(201)
-        self.end_headers()
-
-    def do_MKCOL(self):
-        """
-        Serve a MKCOL request.
-
-        MKCOL is an mkdir in DAV terminology for our part.
-        """
-        path = self.translate_path(self.path)
-        trace.mutter("do_MKCOL rel: [%s], abs: [%s]" % (self.path,path))
-        try:
-            os.mkdir(path)
-        except (IOError, OSError),e:
-            if e.errno in (errno.ENOENT, ):
-                self.send_error(409, "Conflict")
-            elif e.errno in (errno.EEXIST, errno.ENOTDIR):
-                self.send_error(405, "Not allowed")
-            else:
-                # Ok we fail for an unnkown reason :-/
-                raise
-        else:
-            self.send_response(201)
-            self.end_headers()
-
-    def do_COPY(self):
-        """Serve a COPY request."""
-
-        url_to = self.headers.get('Destination')
-        if url_to is None:
-            self.send_error(400,"Destination header missing")
-            return
-        (scheme, netloc, rel_to,
-         params, query, fragment) = urlparse.urlparse(url_to)
-        trace.mutter("urlparse: (%s) [%s]" % (url_to, rel_to))
-        trace.mutter("do_COPY rel_from: [%s], rel_to: [%s]" % (self.path,
-                                                               rel_to))
-        abs_from = self.translate_path(self.path)
-        abs_to = self.translate_path(rel_to)
-        try:
-            # TODO:  Check that rel_from  exists and  rel_to does
-            # not.  In the  mean  time, just  go  along and  trap
-            # exceptions
-            shutil.copyfile(abs_from,abs_to)
-        except (IOError, OSError), e:
-            if e.errno == errno.ENOENT:
-                self.send_error(404,"File not found") ;
-            else:
-                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
-            # seems misleading, RFC2518 says so, stop arguing :)
-            self.send_response(201)
-            self.end_headers()
-
-    def do_DELETE(self):
-        """Serve a DELETE request.
-
-        We don't implement a true DELETE as DAV defines it
-        because we *should* fail to delete a non empty dir.
-        """
-        path = self.translate_path(self.path)
-        trace.mutter("do_DELETE rel: [%s], abs: [%s]" % (self.path, path))
-        try:
-            # DAV  makes no  distinction between  files  and dirs
-            # when required to nuke them,  but we have to. And we
-            # also watch out for symlinks.
-            real_path = os.path.realpath(path)
-            if os.path.isdir(real_path):
-                os.rmdir(path)
-            else:
-                os.remove(path)
-        except (IOError, OSError),e:
-            if e.errno in (errno.ENOENT, ):
-                self.send_error(404, "File not found")
-            else:
-                # Ok we fail for an unnkown reason :-/
-                raise
-        else:
-            self.send_response(204) # Default success code
-            self.end_headers()
-
-    def do_MOVE(self):
-        """Serve a MOVE request."""
-
-        url_to = self.headers.get('Destination')
-        if url_to is None:
-            self.send_error(400,"Destination header missing")
-            return
-        overwrite_header = self.headers.get('Overwrite')
-        if overwrite_header == 'F':
-            should_overwrite = False
-        else:
-            should_overwrite = True
-        (scheme, netloc, rel_to,
-         params, query, fragment) = urlparse.urlparse(url_to)
-        trace.mutter("urlparse: (%s) [%s]" % (url_to, rel_to))
-        trace.mutter("do_MOVE rel_from: [%s], rel_to: [%s]" % (self.path,
-                                                               rel_to))
-        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")
-            return
-        try:
-            os.rename(abs_from, abs_to)
-        except (IOError, OSError), e:
-            if e.errno == errno.ENOENT:
-                self.send_error(404,"File not found") ;
-            else:
-                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
-            # seems misleading, RFC2518 says so, stop arguing :)
-            self.send_response(201)
-            self.end_headers()
-
-class TestingDAVAppendRequestHandler(TestingDAVRequestHandler):
-    """
-    Subclass of TestingDAVRequestHandler implementing te APPEND command.
-
-    http://www.ietf.org/internet-drafts/draft-suma-append-patch-00.txt
-    propose two new commands: APPEND and PATCH. Their description
-    is sparse, this is a best effort attempt to implement the
-    APPEND command.
-    """
-    def do_APPEND(self):
-        """Serve an APPEND request"""
-        path = self.translate_path(self.path)
-        trace.mutter("do_APPEND rel: [%s], abs: [%s]" % (self.path,path))
-
-        if self.headers.get('Expect') == '100-continue':
-            # Tell the client to go ahead, we're ready to get the content
-            self.send_response(100,"Continue")
-            self.end_headers()
-
-        try:
-            # Always write in binary mode.
-            trace.mutter("do_APPEND will try to open: [%s]" % path)
-            f = open(path, 'wb+')
-        except (IOError, OSError), e :
-            self.send_error(409, "Conflict")
-            return
-
-        try:
-            data = self.read_body()
-            f.write(data)
-        except (IOError, OSError):
-            # FIXME: We leave a partially updated file here
-            self.send_error(409, "Conflict")
-            f.close()
-            return
-        f.close()
-        trace.mutter("do_APPEND done: [%s]" % self.path)
-        # FIXME: We should send 204 if the file didn't exist before
-        self.send_response(201)
-        self.end_headers()
-
-
-class DAVServer(HttpServer):
-    """Subclass of HttpServer that gives http+webdav urls.
-
-    This is for use in testing: connections to this server will always go
-    through _urllib where possible.
-    """
-
-    def __init__(self):
-        # We    have   special    requests    to   handle    that
-        # HttpServer_urllib doesn't know about
-        super(DAVServer,self).__init__(TestingDAVRequestHandler)
-
-    # urls returned by this server should require the webdav client impl
-    _url_protocol = 'http+webdav'
-
-
-class DAVServer_append(DAVServer):
-    """Subclass of HttpServer that gives http+webdav urls.
-
-    This is for use in testing: connections to this server will always go
-    through pycurl where possible.
-    This server implements the proposed
-    (www.ietf.org/internet-drafts/draft-suma-append-patch-00.txt)
-    APPEND request.
-    """
-
-    def __init__(self):
-        # We    have   special    requests    to   handle    that
-        # HttpServer_PyCurl don't know about
-        super(DAVServer_append,self).__init__(TestingDAVAppendRequestHandler)
-
-    # urls returned by this server should require the webdav client impl
-    _url_protocol = 'http+webdav'
-
-
-class TestCaseWithDAVServer(tests.TestCaseWithTransport):
-    """A support class that provides urls that are http+webdav://.
-
-    This is done by forcing the server to be an http DAV one.
-    """
-    def setUp(self):
-        super(TestCaseWithDAVServer, self).setUp()
-        self.transport_server = DAVServer
-
 def _get_list_dir_apache2_depth_1_prop():
     return """<?xml version="1.0" encoding="utf-8"?>
 <D:multistatus xmlns:D="DAV:" xmlns:ns0="DAV:">

=== modified file 'webdav.py'
--- a/webdav.py	2008-06-09 07:50:46 +0000
+++ b/webdav.py	2008-06-09 08:02:17 +0000
@@ -866,8 +866,8 @@
 
 def get_test_permutations():
     """Return the permutations to be used in testing."""
-    import tests.test_webdav
-    return [(HttpDavTransport, tests.test_webdav.DAVServer),
+    import tests.dav_server
+    return [(HttpDavTransport, tests.dav_server.DAVServer),
             # Until the Dav transport try to use the APPEND
             # request, there is no need to activate the following
             # (HttpDavTransport, test_webdav.DAVServer_append),



More information about the bazaar-commits mailing list