Mobile Free (Partial Solution – Calendar Edition)

The holy grail is to have a computer at home, a computer at work and a computer (or a phone) in your pocket. Those things have calendars and contacts and email on them. You might use them at different times, but in the end, you want to know what you need to do tomorrow while you’re sitting on the couch surfing the web on your MacBook Pro. And you want to know if you have plans tonight while your at work figuring out if you have time to start one more thing.

MobileMe seemed like a promising service that would do all of this, allowing you to sync all of your computers with the data on your iPhone. It happened over-the-air and gave all of the systems the same, unified view. And it works. Sort of. As long as you’re just using a Mac and an iPhone. Usually.

Outlook support seems to be incredibly hit and miss. To the point where it’s just not worth the hassle. You can read the forums about all the trouble people are having syncing with Outlook. Some people blame it on having Outlook hooked up to Exchange. Hello? That’s like saying your browser won’t work hooked up to the web? Who uses Outlook willingly without Exchange involved?

Partial Solution – WebDAV

Setup a WebDAV Server

There are plenty of Web Servers out there and plenty of hosting services. Many of them can support WebDAV. I’m using Apache 2.2 as my Web Server so I setup WebDAV there. Your configuration might vary based on what you are using of course.

Apache Configuration

I created a new virtual host for my WebDAV server and configured it as such:

<VirtualHost *:80>
    ServerName dav.zorched.net
 
    DavLockDB /var/www/var/DavLock
    DocumentRoot /var/www/dav
    <Directory />
        AuthType Basic
        AuthName "Zorched.net DAV"
        AuthUserFile /etc/apache2/dav_svn.passwd
        Require valid-user
 
        Dav On
    </Directory>
 
    ErrorLog /var/log/apache2/dav_error.log
 
    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn
 
    CustomLog /var/log/apache2/dav_access.log combined
    ServerSignature On
</VirtualHost>

Publish your Outlook 2007 Work Calendar to WebDAV

In Outlook. Right click on a Calendar and Choose Publish to Internet -> Publish to WebDAV Server

Publish Outlook Calendar to WebDAV
Publish Outlook Calendar to WebDAV

Enter in a path to an existing directory on the WebDAV server. This copies an ics file out to your WebDAV server and will periodically update it out on the server.

Publish your Apple iCal Calendar to WebDAV

In Apple iCal. Right click on your calendar and choose Publish. In the Publish on drop down, choose a Private Server and enter in the proper details.

Publish your home calendar from Apple iCal
Publish your home calendar from Apple iCal

This will push the calendar out to the server so that you can subscribe to it from Outlook.

Subscribe to your Home Calendar in Outlook 2007

In Outlook. Choose Tools -> Account Settings from the toolbar. Then choose the Internet Calendars tab. Click the New… button.

Subscribe to a WebDAV calendar in Outlook
Subscribe to a WebDAV calendar in Outlook

Enter in the full path to the shared ics file on the WebDAV server.

Subscribe to your Work Calendar in Apple iCal

In Apple iCal. Choose the menu Calendar -> Subscribe and enter in the URL of the work calendar.

Subscribe to a shared Calendar in iCal
Subscribe to a shared Calendar in iCal

Limitations

Now I sync my iPhone with my MacBook pro and all of the info gets onto the iPhone. Any changes on the iPhone to the Home calendar get pushed into iCal and get synced up to the WebDAV server. So the next day when I come into the office they show up in Outlook when it pulls down the changes from the Home calendar.

This is not MobileMe though. There is no over-the-air syncing. Each of the calendars is still only editable from its origin. (You can only edit the Work calendar from Outlook and the Home calendar from iCal.) But it works.

More WebDAV Tips, Tricks and Bugs

My WebDAV with ASP.NET post has proved to be very popular and gets me emails, so I figured I’d share some more tidbits that I’ve picked up along the way.

What do you learn when you write your own server to implement a standard protocol? Well you learn that protocols share a lot in common with legal contracts. People interpret them in different ways, often in the way that is most advantageous to what they are doing. In writing a WebDAV server, I’ve found out a lot more about Windows than I think I ever wanted to know. I figured I’d write down some of that stuff so that I could remember it, and maybe someone out there on the internet will find it useful as well.

There is not 1 WebDAV for Windows

You can’t really say Microsoft Windows supports WebDAV and think of a monolithic chunk of code that everything uses to talk WebDAV. Windows Explorer uses what’s called the Mini-Redirector. The min-redirector allows you to map a WebDAV location to a Drive letter the same as if you were using a Windows File Sharing/SMB/CIFS share. The mini-redirector has some limitations though.

The Mini-Redirector:

  • No support for HTTPS
  • No support for declared ports (http://example.com:8080/path)
  • No support for LOCK and UNLOCK commands

There is also a system called Web Folders. Web Folders is the WebDAV implementation for Microsoft Office products. Web Folders supports all of the things that the Mini-Redirector doesn’t, including SSL, file locking, etc.

Right now, you might find yourself asking: “If there are two implementations and one is really limited and one is more featured, then why not just replace the worse version with the better?”. Yeah, I asked the same question and don’t know the answer.

When you map a WebDAV drive in Windows and want to open a Microsoft Office document, you get the distinct pleasure of using both WebDAV implementations. The Mini-Redirector asks the server for the file and once it gets it it opens Office and then Office re-asks the server for the same file again after doing some server discovery and file locking. The hand-off means that Office has to re-authenticate if your WebDAV server uses Digest Authentication, so you get to see a login dialog again. What fun!?

Server Discovery

Office uses the OPTIONS command do to Server discovery. Server discovery is basically the process of trying to figure out what kind of server it is and what protocols it supports.

The Office Web Folders always requests OPTIONS from the root (/) of the web server making a horrible assumption that any any server that supports WebDAV must support all the way to the root of the server.

Often when you are allowing users to manipulate files and folders across the internet you might want to use some form of authentication. Digest Authentication is more secure than Basic Authentication which sends the user name and password in plain-text form, so it is a good choice for authentication if you are not going to use a secure (HTTPS) connection. There’s only one small problem with this. There is a bug in the Web Folders implementation so it will not send Authentication headers on OPTIONS requests. That means you have to return an OPTIONS response regardless of what lives at a URL or whether a user is authenticated or they can’t properly open Office documents.

The Office Web Folders support does not just do WebDAV, it can also use Front Page Extensions. Since Front Page is a Microsoft proprietary product, Office prefers to use Front Page over WebDAV. In fact, it prefers it so much, that one of the only ways to get Office to use WebDAV is to use a custom header in OPTIONS requests: MS-Author-Via: DAV
The MS-Author-Via header tells Office that you don’t care how bad it wants to try Front Page, just use WebDAV.

Some Other Resources

Mini-Redirector Issues:
http://greenbytes.de/tech/webdav/webdav-redirector-list.html

Web Folder Client Issues:
http://greenbytes.de/tech/webdav/webfolder-client-list.html

WebDAV Reference Book:
WebDAV: Next-Generation Collaborative Web Authoring by Lisa Dusseault

Custom WebDAV Server Using .NET

As I discussed in a previous post "ASP.NET Web Application without ASPX Extension", I’ve been working on a custom WebDAV server for a client. The initial proof-of-concept was just to see if we could get some .NET code that would respond to all paths for a given web application. From there I had to make WebDAV work.

What is WebDAV

To recap: WebDAV is an IETF Standard Protocol. It is an extension to the ubiquitous HTTP standard, adding on request methods to get property information about files and folders, make folders (called collections in WebDAV parlance), change properties, lock files, etc. Basically anything that you would want on a distributed file system. WebDAV is natively supported by Windows 2000 and XP, Mac OS X, and Linux (using davfs). When using this native support, you’re able to interact with WebDAV just like you are using a local filesystem or a network share. There are also many standalone client implementations that act more like FTP clients.

Why Would You Write Your Own DAV Server?

Sharing files over a network is nothing new of course. Using Windows File Sharing, many people are used to using network shares to store files on a server and to share with their coworkers. The limitation of most of these file sharing systems is that they share exactly what is on the filesystem. What if you want to integrate file sharing with an application that stores file meta-data in a database? What if you want to programmatically control the files and folders that you show to your users? By building your own WebDAV server you can query a database to get all of the meta-data (and even file contents) to serve to your users.

How To Build a WebDAV Server

I did quite a bit of searching and found WebDAV server implementation in Python, Ruby, and Java, but could not find anything done in a .NET language which my client uses for all of their application infrastructure. So, I built one!

As I mentioned in my previous post, we can take over the complete HTTP request for all requested paths. I use a Command Pattern to handle the different types of WebDAV requests. The Commands are responsible for getting information from the HTTP Request that they need to fulfill the request and for writing the proper HTTP Response. Each of the Commands delegates the actual File manipulation to a set of provider classes. Those classes are accessed through an Abstract Factory which allows for me to easily change the backend implementation. This allows for a good separation of concerns. The WebDAV Service layer knows how to read and write WebDAV and the File Provider layer knows how to get and store information about files and folders. (The abstraction between the Commands and the File Providers is a bit leaky still, but I’m confident I’ll be able to refactor it into a cleaner separation.)

The first backend provider that I created for testing was a FileSystem provider. I’ve mapped the WebDAV server to a specific directory and use standard System.IO commands to manipulate files. This is a lot easier because it allowed me to focus on implementing the protocol without worrying about interacting with a less familiar data access layer.

Test Your Implementation

The WebDAV folks have built a great test suite called Litmus that you can use to validate your server implementation. It performs all of the basic operations on files and collections to validate that the server performs to the specification. Start with Litmus and you’ve got your entire functional test harness written for you. That is some TDD in action!
Litmus goes a long way to get you to protocol compliance, but it took a bit of cleaning and tweaking before Windows Explorer would happily mount the Web Folder.

In addition to Litmus I found a couple of other tools really handy for debugging:

  • Ethereal – a very nice protocol analyzer that will let you inspect a series of requests and responses.
  • DAVExplorer – a Java WebDAV client that will write detailed logs of requests and responses.

Don’t be afraid to write your own WebDAV server, it’s really fun!

References

WebDAV Reference Book:
WebDAV: Next-Generation Collaborative Web Authoring by Lisa Dusseault

ASP.NET Web Application Without .ASPX Extension

The Problem

Ok, let’s say you want to create an application in ASP.NET. That application should be able to execute .NET code regardless of the path that is requested. You don’t want to map the .NET execution to a specific extension and you want handle all requests in a simple manner. Well, I think I figured out how.

In the Java Servlet world, you can easily map arbitrary paths to a servlet handler, such that all request to ‘/somedirectory’ are handled by your ‘SomeDirectoryServlet’. Ruby on Rails uses a controller as well and you can do URL rewriting with that controller very easily to support arbitrary path schemes. But in the .NET/IIS world, all of the configuration for handling is based solely on file extensions.

An Actual Project That Needs This

At SpiderLogic (where I work), we are working on a client project where their current infrastructure is all .NET. Their current application is entirely web based. It allows users to (among other things) upload files and share them among a group of users. Now they want to allow users to access files on a Windows desktop and interact with them in a much more natural way, by dragging and dropping, etc. Windows Explorer has the ability to mount WebDAV paths the same as it can with windows file sharing. So, basically we wanted to see if we could build a virtual WebDAV server that would allow us to read file meta-data from a Database and then expose that over the web as a WebDAV share.

WebDAV is an extension to HTTP that allows for Distributed Authoring and Versioning. Basically it looks a lot like HTTP, where it has verbs and requests files.

A WebDAV header might look something like:

PROPFIND /some/path/
HOST www.example.com

The Solution

As I said above, IIS exclusively uses file extensions to map files to code to execute the file. .NET provides HTTP Handlers and HTTP Modules that allow you to handle requests that should not be handled by a traditional Page. A Module registers itself when it is loaded to respond to specific events in the HTTP Request life-cycle. Sometimes this is called an Intercepting Filter. Modules listen to events and can respond to that event. They can do many things, check security, add content to the response, transform an XML response into an appropriate form based on the calling device, etc. They can also take over the entire request-response and handle it in its entirety.

For our example, we want to respond to a very early event – BeginRequest and fulfill the request ourselves.

using System;
using System.Web;
 
public class DavModule : IHttpModule {
 
    private HttpApplication context = null;
 
    public void Dispose() {
        context.BeginRequest -= new EventHandler(context_BeginRequest);
    }
 
    public void Init(HttpApplication context) {
        this.context = context;
        this.context.BeginRequest += new EventHandler(context_BeginRequest);
    }
 
    void context_BeginRequest(object sender, EventArgs e) {
        HttpApplication app = (HttpApplication) sender;
        app.Response.ContentType = "text/plain";
 
        if (app.Request.Path.EndsWith("Help"))
            app.Server.Transfer("Help.aspx");
        else {
            app.Response.Write("Path: " + app.Request.Path);
            app.Response.End();
        }
    }
}

The IHttpModule responds to begin request events and takes over handling the fulfillment of the HTTP response. The example demonstrates that you can get the request path and then parse it to handle different cases. One use would be for doing internal URL rewriting (although I suspect that this kind of URL rewriting would break the post-back of .aspx files). As I said at the start, we plan on trying to implement a virtual directory using WebDAV. The possibilities are limited only by your imagination.

The handler itself is made available to a web application by registering it in the Web.config file for the application.

Web.config configuration:

    <system.web>
      <httpModules>
        <add name="DavModule" type="DavModule"/>
      </httpModules>
    </system.web>

Of course if that was all there was too it, this would be a much less interesting article. The trick to making this all work is to properly configure IIS. We want to handle all requests to our application using the .NET code that we have written. We don’t want IIS to return 404s (Not Found) for files that don’t exist since we want to implement a dynamic, virtual directory and not just deal with files on the file system.

To do this, you have to remove all of the existing handlers under the Application Configuration. Then you want to map all extensions (.*) and in our case all Verbs (GET, POST, PROPFIND, MKCOL – which allows us to hopefully respond to WebDAV verbs as well) to the aspnet_isapi.dll.

Overview of ISS configuration.

Here’s the editing screen that you will see:

Details of ISS configuration.

This was Step 1 of the proof of concept to see if we can make the WebDAV system work. Hopefully a future posting will be about the success of the implementation.

This is a very non-obvious thing to do in IIS/ASP.NET, but for some applications it is a necessary thing. Of course if you have more control over the tools and language you use to implement it, then maybe you could choose something that was better suited for this application. Maybe someone else will find this useful? What do you think?

Thanks to Brennan and Oliver who work at SpiderLogic for their help with this.

Update
Under Windows Server 2003: .* is not allowed in the mapping , there is an extra ‘all extensions’ section where you can add the aspnet_isapi.dll.