Tuesday, April 27, 2010

HTTP Headers are a multi-map

RFC 2616:
Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma.
Today, I found and fixed a cool bug in the AmazonCloudFront client for .NET. The original implementation of the client used the System.Net.WebHeaderCollection.Add() method to specify headers for a CloudFront request. An example of one of the request headers is If-Match - this header uniquely identifies a CloudFront distribution, and the value associated with this header is the ETag specified for the request.

Using the Add method is fine if a new request object is created for every CloudFront request; the issue arises when an attempt is made to reuse an existing SetDistributionConfigRequest object to perform another CloudFront request, albeit with new parameters. In the reuse case, the new header values will be appended to the existing headers' values.

Let's take the case of If-Match: when the request was sent over HTTP, CloudFront received a comma-separated value for If-Match containing all the ETags specified during the lifetime of the request object. When CloudFront received this string, it couldn't verify the identity of the distribution, and rejected the request.

The fix: Use the WebHeaderCollection's [] accessor to set a unique value for every request header. Fixing this bug makes it now possible for the same request object to be reused for multiple calls.

No comments:

Post a Comment