2010-04-25

Performing PROPFIND from Python

Surprising, when I went looking for examples of performing PROPFIND requests from Python I found very little information. For testing OpenGroupware Coil's WebDAV presentation I needed a simple way to perform the PROPFIND required to list the entities in a collection and then request each entity. With a bit of scratching through the thin documentation I was able to come up with the following:
  1. import httplib, urllib2, base64, sys
  2. from lxml import etree
  3. PROPFIND = u'''<?xml version="1.0" encoding="utf-8"?>
  4. <propfind xmlns="DAV:">
  5. <prop>
  6. <getetag/>
  7. </prop>
  8. </propfind>'''
  9. SERVER_HOST = '127.0.0.1'
  10. SERVER_PORT = 8080
  11. SERVER_PATH = '/dav/Contacts'
  12. CLIENT_AGENT = 'Whitemice rules/so very true'
  13. auth_string = 'Basic {0}'.format(base64.encodestring('adam:fred123')[:-1])
  14. urllib2.install_opener(urllib2.build_opener(urllib2.HTTPHandler()))
  15. connection = httplib.HTTPConnection(SERVER_HOST, SERVER_PORT)
  16. connection.putrequest('PROPFIND', SERVER_PATH)
  17. connection.putheader('Authorization', auth_string)
  18. connection.putheader('User-Agent', CLIENT_AGENT)
  19. connection.putheader('Depth', 1)
  20. connection.putheader('Content-Length', str(len(PROPFIND)))
  21. connection.endheaders()
  22. connection.send(PROPFIND)
  23. response = connection.getresponse()
  24. if response.status == 207:
  25.   data = response.read()
  26.   connection.close()
  27.   response = None
  28.   namespace_prefix_map = { 'D' : 'DAV:' }
  29.   document = etree.fromstring(data)
  30.   for path in document.xpath('/D:multistatus/D:response/D:href/text()',
  31.       namespaces=namespace_prefix_map):
  32.     if (path != SERVER_PATH):
  33.       connection = httplib.HTTPConnection('127.0.0.1', 8080)
  34.       connection.putrequest('GET', path)
  35.       connection.putheader('Authorization', auth_string)
  36.       connection.putheader('User-Agent', CLIENT_AGENT)
  37.       connection.endheaders()
  38.       response = connection.getresponse()
  39.       if response.status != 200:
  40.         print 'Error retrieving {0}'.format(path)
  41.         sys.exit(1)

This will make the PROPFIND for all the items in the collection, requesting the getetag property, and then from the response perform an HTTP GET for every item. Even better would be if it requested isCollection and knew better than to perform GETs on collections.  I hope this simple example will be of use to someone.

1 comment:

  1. Interesting. I was looking for the same thing to create a simple webdav client. Thanks for the info.

    ReplyDelete