daveBlog

There is a madness to my method…

View My GitHub Profile

Follow me on Twitter

Come work with me!

Site feed

MonkeySpace Talk Slides and Notes

I delivered my first conference talk at MonkeySpace yesterday. The video will be available at some point, but in the meantime, here are the slides and some notes to help make sense of them.

Overview

Mono is a potentially attractive option for organizations that are already using ASP.NET because IIS is a pain to configure and Windows licenses can get really expensive.

Many libraries indicate that they support Mono, but there is little information about using it for web sites and services beyond basic, “getting started” tutorials. I’m trying to document and publish my experiments as I go along to help others who might be trying this and in the hope that more people will start documenting their experiences, too.

The major snags I encountered were:

  • xbuild doesn’t have a good fallback mechanism for unkown profiles (we use the Client Profile for some assemblies)
  • Microsoft’s format for Forms Authentication cookies is undocumented and difficult to reverse engineer. (see my earlier post on this topic)
  • Mono’s support for SQL Server hasn’t received significant updates for 2008 and 2012.
  • New Relic—an awesome monitoring service we use—doesn’t support Mono.

I worked around all of these issues and even built my own version of the New Relic Profiler (linked below). In testing a simple service, I encountered very inconsistent performance that was quite sensitive to GC pauses.

There was a period of about seven minutes during which the performance of the Mono version of the service was as good as—or better than—its Windows counterpart, so I plan to continue investigating. These are some initial areas I intend to look into:

  • Is the New Relic profiler itself causing noise?
  • Does Mono 3.2 solve this issue? (I tested with one of the 3.0.x releases)
  • Is there something about the application’s architecture that causes difficulty for sgen?
  • Would a stack other than ASP.NET MVC give me better throughput?

Image Credits

Several of the images that I used were licensed under Creative Commons. Here are links to their original locations:

HTTP 100 Continue, Latency, and You

TL;DR

You probably shouldn’t send an Expect: 100-continue header in your HTTP requests—especially if you’re making requests against a server running IIS or Nginx. If you’re using .NET, you have to explicitly opt out of sending this header by setting Expect100Continue to false on the ServicePoint of any HttpWebRequest that you create.

Background

In a recent project, I found myself digging into the details surrounding the 100 Continue status in HTTP 1.1. The project involves uploading (potentially) large files to the server, and it initially seemed like explicitly supporting 100 Continue would be a good way to preserve bandwidth.

The Problem

First off, there’s surprisingly little reliable documentation about this status code beyond RFC 2616 itself. IIS automatically sends a 100 Continue for any request containing an Expect: 100-Continue header, and it wasn’t clear from my research whether there is actually a way to disable this—at the very least, it’s not possible from within the context of a plain old ASP.NET application.

As I investigated further, I discovered that it’s actually somewhat common for servers to handle this without allowing application code to have a say in what happens. Nginx’s reverse proxy module behaves this way, and projects like Gunicorn even depend on this behavior in order to prevent a certain class of DOS attack.

Normally, this would be the end of my investigation: what initially seemed like a cool feature would be a pain to implement, and after reading up on it more, it really seemed to be of dubious value. But then I started reading up on related parts of the .NET framework…

HttpWebRequest

It seems that the designers of the .NET framework weren’t allowed to talk to the developers of IIS. If they had, the .NET framework designers might have noticed that sending an Expect: 100-Continue header to servers that always respond with 100 Continue serves absolutely no purpose. In fact, the current behavior is worse than useless because it introduces unnecessary latency any time that you call out to an external web service. For an application that makes an occasional web request, this might not be so bad, but inside of a web service with cross-service dependencies, or on a mobile device with naturally high latency, this is a big deal.

Fortunately, this header can be disabled: every HttpWebRequest has a ServicePoint with an Expect100Continue property. If you set this to false, you’ll save yourself an unnecessary round trip. Better yet: write yourself a little utility method that creates an HttpWebRequest and disables the header, then flame anyone who doesn’t use it.

Happy Hacking!

Decoding Forms Authentication Cookies With Mono

Lately, I’ve been experimenting with migrating web services from .NET on Windows to Mono on Ubuntu. While getting the code building and running in a VM was not terribly difficult, I soon found that authentication was a roadblock.

Our web services run across several subdomains. We’re moving towards using OAuth for everything, but many services still use Forms Authentication with a cookie that is shared across all subdomains. However, when I tried to use my cookie with a service running on Mono, I was treated as an unauthenticated user.

The first barrier to shared authentication between .NET and Mono is actually well-documented: the default cookie name under Mono is .MONOAUTH, rather than .ASPXAUTH. Upon discovering this, I quickly modified my Web.config to explicitly set the cookie to .ASPXAUTH…and nothing happened.

Another early discovery was that Mono base-64 encodes the cookie, while .NET uses base-16. Again, changing this (in my case, by using a custom build of Mono) had no effect—I was still treated as an unauthenticated user.

Eventually, after quite a bit of digging around, I learned that the binary format for .NET’s Forms Authentication cookie is undocumented, so Mono had to implement a reasonable—yet incompatible—alternative format. Furthermore, if you choose to encrypt the cookie, .NET adds an extra 28 bytes of padding to the cookie using an unspecified hash function—my best guess is that this has something to do with avoiding hash collision attacks.

In any case, I spent a lazy Saturday afternoon poking around with the format and arrived at a method of decoding the cookie, which is included here for your reading pleasure:

As you can see, it’s very proof-of-concepty, and it assumes specific encryption and signing algorithms, but it gets the job done and should be pretty easy to extend and generalize. Just drop this code into your Global.asax.cs, provide your favorite implementation of base-16 string to bytes, and you’re good to go.

Happy hacking!

Building Mono on Mac OS X (2011 Edition)

Quite a bit has changed since I wrote my post a few years ago on building Mono for OS X. So much has changed, in fact, that I've decided that a new post on the topic is in order. These instructions assume that you're using Snow Leopard. They should work on Leopard with minimal changes, but your mileage may vary.

Prerequisites

Installing the prerequisites for Mono is much simpler than it once was. Previously, Mono had external dependencies like glib, which would mean you'd need to install MacPorts, but they've taken steps in the last year to reduce and eliminate such dependencies.

Git

If you haven't yet heard about git, stop hiding under that rock! The Mono source is hosted on GitHub, so if you want to download and build it, you'll need a copy of Git. You can acquire it here.

XCode

XCode 4 is now a $4.99 download in the Mac app store. If you're too cheap for that, you can still (as of the time of this writing) grab XCode 3 here (free registration required). A copy may also be on one of the discs that came with your Mac.

Mono

While you can (theoretically) bootstrap Mono, it's not something I recommend unless you enjoy pain. Save yourself some trouble and download the latest version here.

Get the Source

The Mono source code is now hosted on GitHub. Open your Terminal and clone the repository by issuing the command

git clone git://github.com/mono/mono.git

Build and Install

First, you'll need to run autogen.sh. Here's how I usually invoke it:

./autogen.sh --with-sgen=no --with-xen_opt=no --prefix=/opt/mono-`git rev-parse HEAD` --with-mcs-docs=no --disable-nls

My rationale for each option is listed below.

  • --with-sgen=no: The Mono team considers the SGen garbage collector to be production ready, but I've had problems with it, so I still turn it off.
  • --with-xen_opt=no: I'm not running Xen, so there's no need for this.
  • --prefix=/opt/mono-`git rev-parse HEAD`: You may want to just use --prefix=/opt/mono. I include the git revision in the path to make it easier to keep a number of parallel installations around for testing purposes.
  • --with-mcs-docs=no: The documentation takes a while to build and generally won't be much different than what's in your installed copy of Mono. Save yourself some time and leave it out.
  • --disable-nls: I don't need this particular feature. If you do, leave it in.

Assuming that autogen.sh completes successfully, you can now build it with

make -j1

Depending upon how your development environment is set up, you may not need the -j1. However, if your default MAKEFLAGS has a different -j option, you'll want to use this. Otherwise, the Mono build can fail in strange ways. Once this is done, run sudo make install, and you'll be all set!

Rewrite History with git-filter-branch

I've found this page useful on a few occasions, so I'm linking it from here so that I don't forget where it is.

The author demonstrates how to use git-filter-branch to completely remove files from a git repository. I haven't felt compelled to take all the steps that he does in order to get rid of the files, but it's an excellent reference for the command, nonetheless.