Bug 66474 - Dynamically injected base tag from external script causes extra requests
Summary: Dynamically injected base tag from external script causes extra requests
Status: RESOLVED WONTFIX
Alias: None
Product: WebKit
Classification: Unclassified
Component: Page Loading (show other bugs)
Version: 528+ (Nightly build)
Hardware: Mac (Intel) OS X 10.7
: P2 Normal
Assignee: Nobody
URL: http://jsbin.com/umulij/8
Keywords:
Depends on:
Blocks:
 
Reported: 2011-08-18 09:41 PDT by Scott Jehl
Modified: 2011-08-19 06:25 PDT (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Scott Jehl 2011-08-18 09:41:38 PDT
When referencing an external script that dynamically injects a base tag with a new base href, the browser downloads subsequent assets twice each: once with a path that respects the base href, then again with a path that does not. This problem is only true in externally-referenced scripts; inline scripts work as expected, causing one request that is routed through the base href.

Steps to reproduce:

1. open http://jsbin.com/umulij/8 in Chrome (currently running version 13.0.782.112)
2. Inspect the resources panel and notice two requests to the image referenced in the body

Note that the image references are not real, so the 404s are expected.

You can view the source for this demo here:
http://jsbin.com/umulij/8/edit

The  referenced JavaScript file simply creates a base element with a faux href and injects it as a first child of the head element:
http://filamentgroup.com/examples/rwdtemp/test.js

Note that when this same script is inline in the head of the document, only one request is made. This is the intended behavior.
http://jsbin.com/ucunip/5 (source can be viewed here: http://jsbin.com/ucunip/5/edit )

As an aside, this bug now also exists in Firefox 6. Previously, this was not the behavior in either browser.
Comment 1 Alexey Proskuryakov 2011-08-18 12:07:59 PDT
I wonder if these are preloaded generated requests that are being carried on.
Comment 2 Antti Koivisto 2011-08-18 13:40:58 PDT
Pretty sure they are. This is not a reasonable thing to do. -> wontfix
Comment 3 Scott Jehl 2011-08-18 20:21:45 PDT
(In reply to comment #2)
> Pretty sure they are. This is not a reasonable thing to do. -> wontfix

I'd really appreciate if this issue could be given a little more consideration. Injecting and/or modifying and existing base element via JavaScript is useful for a number of reasons. 

For one, modifying the base href is a reliable way to ensure assets that are requested via ajax-appended markup are routed through the relative URL they come from (for example, when appended HTML contains scripts, styles, images, etc). We modify the base element constantly in the jQuery Mobile framework as new pages are brought in via Ajax. I can test to see if this change has any effect there currently, as I'm not sure if it does.

The case I was concerned with in particular was that the "Responsive Images" technique, which is one of only a few ways to currently route images appropriately based on screen resolution in responsive designs, no longer works because of this recent change. While this can be done other ways, the base tag approach can be the most useful depending on the site. (more here: http://filamentgroup.com/lab/responsive_images_experimenting_with_context_aware_image_sizing/ )


That said, I think the part that needs clarification most here is why this technique works perfectly when the script is inline in the head, but not when it's referenced externally. Shouldn't these two scenarios behave the same?

I've noticed that an externally referenced script is able to set a cookie that is subsequently carried by the image request, so the problem does not appear to be related to timing. In fact, looking at the profiler, the request to the non-base-href image src goes out AFTER the one that is routed properly. This seems to suggest a bug, rather than an optimized prefetch.

I ask that you reconsider this bug, as it doesn't appear to match expected behavior.
Thanks so much
Comment 4 Kyle Simpson 2011-08-18 21:16:36 PDT
> That said, I think the part that needs clarification most here is why this technique works perfectly when the script is inline in the head, but not when it's referenced externally. Shouldn't these two scenarios behave the same?

Sounds like the difference is that the browser knows immediately during parsing the contents of inline script blocks, so it can abandon an invalidated resource preload right away if a base tag is injected. For an external script resource, the base tag injection may/will happen "later", when the script finishes loading and executes, which is likely well after the other resource loading has already started. Aborting a request/response in mid flight is probably harder to do, and also probably doesn't really save much in bandwidth on either side of the fence.
Comment 5 Scott Jehl 2011-08-18 21:30:20 PDT
Thanks, Kyle. 

That's a helpful theory, but it's interesting that a cookie set within an external is successfully carried with both image requests. That seems to suggest that the script is executed before these requests go out, as I'd expect, but for some reason the base tag situation is different.

Here's a demo showing image requests carrying cookies from that JS file: 
http://jsbin.com/ifupav/2 (src: http://jsbin.com/ifupav/2/edit )
Comment 6 Antti Koivisto 2011-08-19 06:25:47 PDT
Inserting base element effectively changes all the subsequent URLs on the page. Any script may insert one so to avoid double loads we could never load anything else as long as there is a pending script load. This would mean disabling preloading, which is out of the question.

Only reasonable fix would be to ignore the base url change for elements for which we have already started loads for (HTML5 text could be interpreted like that). However that could break something and is probably not worth the effort in any case.