Software Mechanics
Why do we even have that lever?

Hosting BZR Repositories on IIS

September 16, 2008 16:42 by chris

I posted quite a while ago about using the Bazaar distributed version control system to provide offline capabilities for TFS. I've still been using it that way, but I've found that Bazaar is working quite well for me as a personal, low overhead source control system.

One of the nicer things about Bazaar is the easy hosting and sharing of repositories. All you need for a read-only repository is to put it up on web server. No special configuration required. And yet, every time I tried putting a branch up on this server, it failed.

Turned out that the problem comes down to the bazaar repository format. More specifically, there are filenames in there without file extensions, and IIS just doesn't like that (unless you put in a wildcard mapping which has tons of other issues). I was at a loss, when I remembered that I can just fake it with ASP.NET.

The trick was to give the request an extension. And there's an extension already configured that's perfect here - .ashx, or the ASP.NET HTTP Handler. So what I did was build a hander that takes an url like this:

http://www.tavaresstudios.com/branches.ashx/[Repository Name]/... bzr paths here ...

and feed the resulting files back to the bazaar client. The actual path gets munged a little. I don't need to worry about encoding or anything else, just stream the bytes straight back out to the client.

Here's the code:

using System;
using System.Web;
using System.IO;
using System.Configuration;

/// <summary>
/// A small <see cref="IHttpHandler"/> that returns the contents of the file
/// under given pathdata. Used to serve up files that don't have an extension.
/// </summary>
public class BranchesHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string requestedPath = context.Request.PathInfo;
        string root = GetBranchRoot();

        string resultPath = context.Request.MapPath(root + requestedPath, root, false);
        string rootPath = context.Request.MapPath(".", root, false);

        if (!resultPath.StartsWith(rootPath))
        {
            throw new HttpException(404, "File not found");
        }


        context.Response.ContentType = "application/octet-stream";
        CopyFileToResponse(resultPath, context.Response);
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    private string GetBranchRoot()
    {
        return ConfigurationManager.AppSettings["BranchRoot"];
    }

    private void CopyFileToResponse(string filePath, HttpResponse response)
    {
        if (!File.Exists(filePath))
        {
            throw new HttpException(404, "File not found");
        }

        response.TransmitFile(filePath);
    }
}

As I build future samples, I'll still make them available as .zip files, but I'm also planning to put the bazaar repository up as well for folks who want to track them.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET | Personal
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed
Comments are closed