technical

bholt's picture

302 Redirect Handling in IE and Firefox

An apparent defect in how IE handled our OAuth consent flow at work turned out to be an interesting difference in how Firefox and IE (Firefox 6 and IE8, in this case) handle content loaded via a 302 HTTP response.

After one of our UI developers beautified our OAuth consent page (where the user authorizes a client application to use data on his or her behalf), one of our testers pointed out that the overall flow stopped working in Internet Explorer. It still worked in Firefox, though, and she told us that if she permanently authorized the client in Firefox, the flow still worked in Internet Explorer.

We allow OAuth clients to provide an image that will be displayed when we ask users for consent. However, it’s not required, and so occasionally on the consent page the IMG tag would have an empty SRC attribute: <img src="" alt="client Logo"/>.

screen capture of OAuth consent page with broken image

When the SRC attribute is empty, the browser loads the page URI instead. (So, it’s a self-reference, like the . entry on a filesystem.) This is where the difference between Firefox and IE comes in.

When a user accesses our site, he or she needs an OAuth access token for the site to work, and so Spring issues a 302 redirect from whatever URI was originally being accessed to the consent page. For example, if the user requests / (the home page), they’ll be redirected to /consentToUseOfData?oauth_token={tokenId}. (In the background, Spring obtains an OAuth request token from the OAuth provider, and replaces {tokenId} with the request token.)

As a result, the URI for the page had two wrinkles. The original URI for the page being loaded was /, but this was temporarily redirected to /consentToUseOfData?oauth_token={tokenId}. When the self-referring IMG tag is encountered, IE uses the original URI while Firefox uses the redirected URI.

While everyone loves to hate on Internet Explorer, initially I didn’t disagree with their approach here. The HTTP spec says, Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. I thought the request triggered by the IMG should be considered a “future request,” meaning Internet Explorer’s behavior would be correct.

However, I did a little more digging. The HTML4 spec for IMG (The choice of HTML4 was admittedly arbitrary, since we’re using the essentially spec-less HTML5.) says the SRC attribute is a URI: Relative URIs are resolved to full URIs using a base URI. … For more information about base URIs, please consult the section on base URIs in the chapter on links.

The relevant section states,

12.4.1 Resolving relative URIs

User agents must calculate the base URI for resolving relative URIs according to [RFC1808], section 3. The following describes how [RFC1808] applies specifically to HTML.

User agents must calculate the base URI according to the following precedences (highest priority to lowest):

  1. The base URI is set by the BASE element.
  2. The base URI is given by meta data discovered during a protocol interaction, such as an HTTP header (see [RFC2616]).
  3. By default, the base URI is that of the current document. Not all HTML documents have a base URI (e.g., a valid HTML document may appear in an email and may not be designated by a URI). Such HTML documents are considered erroneous if they contain relative URIs and rely on a default base URI.

We define no BASE element, nor does the response contain a Content-Location header (per RFC2616, this is how HTTP defines a Base URI), so the following section of RFC1808 applies:

3.3. Base URL from the Retrieval URL

If no base URL is embedded and the document is not encapsulated within some other entity (e.g., the top level of a composite entity), then, if a URL was used to retrieve the base document, that URL shall be considered the base URL. Note that if the retrieval was the result of a redirected request, the last URL used (i.e., that which resulted in he actual retrieval of the document) is the base URL.[emphasis added]

So, as usual, Firefox appears to be following the relevant spec and Internet Explorer is not. This one is pretty esoteric, though, so I’m tempted to forgive them.

Ultimately, we resolved the problem by removing the IMG tag when no image is provided. The fact that it was loading a broken image was a defect itself, of course.

bholt's picture

Free iPhone Ringtones

I ordered the new iPhone 3GS shortly after its announcement earlier this month, as I’ve wanted one for some time. I was mainly waiting for a 32GB version, which provides enough room for a reasonable (Your definition of reasonable may vary.) number of songs and videos. After anxiously awaiting its delivery, a slight mishap on delivery day, and eventual successful delivery, I excitedly unwrapped my new toy, activated it, and started transferring my media library.

Eventually I started looking for a new ringtone. The included choices are decent, including a good “old fashioned” ringer, but I wanted something more flashy—and I certainly was not going to pay $0.99 for something that would only play for up to forty seconds at a time. Luckily, iPhones ringtones are just short AAC clips, and are therefore easily created from the songs already in your music library. This article will share how to do it yourself.

bholt's picture

Introduction to jQuery

While I’m far from an expert on the subject, I’ve had the opportunity to introduce jQuery to some of my fellow developers here in India. I thought I'd share the presentations in the hopes that someone else might find them useful as well.

bholt's picture

jQuery Footnotes

jFootnotes is a jQuery plugin that creates and formats footnotes based on inline content. I have used it fairly extensively on this site, and thought I’d share it with the world. It has been tested with jQuery 1.2.6, but I have no reason to believe it won’t work with 1.3.x as well.

Once the module has been included in a page, it can be called as follows:

$("div").footnotes();

Pretty straightforward. By default, it will look for

  • any span elements with the footnotes class, and
  • any blockquote elements with a title attribute

within the outer selection (e.g., within any div elements, in this case). The matches will be extracted and moved to footnotes.

Syndicate content