About WebDAV: do it yourself ..

Facing an integration task using WebDAV brought me to take a look closer at WebDAV and corresponding tools for .Net platform. This is part of a short series:

-----

Why pay others do have fun and use the protocol? How hard could be to implement just the few pieces I need ..

What do I need ?

The simplest scenario you can get from WebDAV:

  • List folder contents, get name/urls, size, differentiate files & subfolders
  • upload a file from memory
  • download a file to memory

For testing purposes I use IIS 7.5 as my WebDAV server.

What IS WebDAV ?

Basically an extension of HTTP protocol to use web servers as file systems. It is described in IETF RFC 4918. A Quick overview can be get from wiki and there’s an official-like site webdav.org which provides more links and resources. 

how to Get List of contents ?

I could simply make an HTTP GET request and a html page from get web server containing links to its contents. But this is ugly and there is the webdav way using PROPFIND instead of GET.

PROPFIND relies on xml query sent with http request. RFC contains also some example queries. The query I need would be something like this:

<?xml version="1.0" encoding="utf-8"?>
<D:propfind xmlns:D="DAV:" xmlns:ns0="DAV:">
<D:prop>
<ns0:displayname/>
<ns0:iscollection/>
<ns0:getcontentlength/>
</D:prop>
</D:propfind>

To send the query to web server using PROPFIND in simple:

var request = (HttpWebRequest)HttpWebRequest.Create(targetUri);
request.UseDefaultCredentials = true;
request.Method = "PROPFIND";

var bytes = Encoding.UTF8.GetBytes(query);
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
request.ContentType = "text/xml";

But now you’ll get an error which is not the most helpful:
System.Net.WebException: The remote server returned an error: (403) Forbidden.

The resolve is to read the spec and find the mandatory “Depth” header which determines if you want properties only on the targeted item (value 0), with direct children (value 1) or recursively (value “infinity”). To add that header:

request.Headers.Add("Depth", "1");

Now the request is set up, reading the response gives as requested data in xml format:

using (var response = (HttpWebResponse)request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var responseContents = new MemoryStream(2048))
{
responseStream.CopyTo(responseContents, 2048);
return Encoding.UTF8.GetString(responseContents.ToArray());
}

The result could be something like this:

<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://imrepyhvel/webDavTest/</D:href>
<D:propstat>
<D:status>HTTP/1.1 200 OK</D:status>
<D:prop>
<D:displayname>webDavTest</D:displayname>
<D:getcontentlength>0</D:getcontentlength>
<D:iscollection>1</D:iscollection>
</D:prop>
</D:propstat>
</D:response>
<D:response>
<D:href>http://imrepyhvel/webDavTest/bb.txt</D:href>
<D:propstat>
<D:status>HTTP/1.1 200 OK</D:status>
<D:prop>
<D:displayname>bb.txt</D:displayname>
<D:getcontentlength>4</D:getcontentlength>
<D:iscollection>0</D:iscollection>
</D:prop>
</D:propstat>
</D:response>
</D:multistatus>

The tricky part is that different servers may return data in slightly different ways. For example folders may not have some properties (like “getcontentlength”) in which case there’s another “propstat”-block with different “D:status". RFC describes the possible statuses.

Another suggestion is to help clean up the HTTP communication and use these optional settings for HTTP request which obviously remove HTTP 100 and continuous handshaking:

request.PreAuthenticate = true;
request.ServicePoint.Expect100Continue = false;

How to download A file ?

Heey, you already know that. That's what HTTP GET method is about ..

How to upload a file?

This is less common but still simple:

WebRequest request = WebRequest.Create(targetPath);
request.UseDefaultCredentials = true;
request.Method = "PUT";

using (Stream stream = request.GetRequestStream())
{
contents.CopyTo(stream, 2048);
}
request.GetResponse();

What do I think ?

Most is simple HTTP action. The only tricky part is working with metadata (PROPFIND) but with help of RFC and google, you won't get stuck. If you are on low budget or only need simple scenarios then doing WebDav by yourself is not a problem.

The good:

  • what you do yourself is free
    • No licence fees
    • no limitations on deployment
    • no copyright or copyleft unless you want to create one.
  • Seems simple enough
  • know-how can be applied using every language capable of creating-sending-receiving HTTP traffic
  • Performance & traffic is as efficient as you write it
    • 3 tasks = auth challenge + 3 request-response pairs
    • approx 41 ms

image

The bad:

  • Requires some time to explore RFC and write/google the proof of concept codes
    • Some hours will do for simple scenarios.
  • Requires more time in case of problems
    • no support/bugfixes from outside
    • the reasons behind those uninformative 403s are hard to track down.
  • Requires more time to test
    • there will be quirks on different WebDAV servers as experienced by running my code in both IIS and on livelink folders.

Kommentaare ei ole: