Chromium offers two ways for an end-user to view the source code of a web page: 1) the Developer Tools, and 2) The longstanding view-source
viewer. Of these, the Developer Tools have received almost all of the attention over the last decade, but in this post I want to take a quick look at the older view-source
feature.
To get to the View Page Source feature, you can use the the Ctrl+U
keyboard shortcut, the View page source context menu item, or add view-source:
prefix before a URL in the omnibox. No matter what mechanism you use, you’ll get a new tab containing a simple view of the original source code of the page, not the current document’s DOM (which may have been extensively modified by script or the user).
Implementation
Over the years, I’ve landed a few fixes to the View-Source code, including security fixes and user-experience fixes (e.g. support for rendering Dark Mode). The feature doesn’t get a lot of love, but its implementation is interesting. Why?
First, let’s start with the URL. Chromium uses a BrowserURLHandler
to rewrite all URLs with a view-source:
prefix by stripping off the prefix; a VirtualUrl is set on the navigation entry so the user continues to see the view-source
prefix in the omnibox, even as the renderer uses the inner url as the source location:
If the user tries to use view-source
against an unsupported scheme like javascript:
, the rewriter changes the inner url to about:blank
.
If the user invokes View page source on a given document, the WebContents’ ViewSource()
function takes the current document’s URL, slaps a view-source:
prefix on the front, massages a few things, and opens the resulting URL in a new tab.
Most interestingly, View Source is implemented as a mode for a Document loaded inside Blink– you simply call SetIsViewSource(true)
on the Document, and then the ComputeDocumentType sets things up such that the CreateDocument()
function creates a HTMLViewSourceDocument
instead of a plain HTMLDocument
. The ViewSource document uses a simpler parser and it does not do much beyond adding markup to display basic color highlighting on HTML elements and their attributes. The resulting “source-formatted” HTML is displayed as text to the user.
Deprecation?
Generally, products try not to expose multiple features to achieve the same task, especially when they use different code to do it. For a while, the View-Source viewer had some unique features that justified its existence; e.g. it integrated with the XSS Auditor to mark blocks of code that the Auditor had deemed reflected XSS attacks:

However, the XSS Auditor was removed more than two years ago. Similarly, many years ago, a site could link directly to a view-source
URL (e.g. a HTML tutorial website might do this), but that capability was removed in 2016 for security reasons.
Nowadays, the viewer offers a subset of the features of the Developer Tools’ Sources
tab. The Sources
tab offers several cool features, including Pretty Print, red-underlines for script errors, and the ability to switch between all of the sources used by the currently loaded page:
The Elements
tab is different than both the Sources
tab and the view-source
viewer because it reflects the current state of the DOM of the currently-loaded page– modifications made to the page by JavaScript are shown in the Elements
tab.
At this point, you might naturally wonder why the old viewer still exists.
Part of the answer is “Well, it’s been there forever, and doesn’t cost too much to maintain.” It’s been proposed that perhaps the CTRL+U
shortcut should just open the Developer Tools’ Sources
tab. However, there are some non-obvious reasons that the old viewer continues to live on:
- For Chromium on Android1, adding the
view-source
prefix in the omnibox is the only convenient way to view source without first tethering your device to a DevTools instance running on a desktop PC. - The
HTMLViewSourceDocument
code that makes up the bulk of the feature cannot be deleted because the default XML rendering view depends upon it.
If the user navigates to an XML file that lacks an XSLT, the XML parser callsGetDocument()->SetIsViewSource(true);
which results in the browser rendering the plain XML as a document tree:
May the Source be with you!
-Eric
1 Unfortunately, Chromium on iOS doesn’t support either view-source
or the Developer Tools. If the iOS browser syncs a view-source
url from another platform, the prefix is simply stripped off.
Minor correction: “No matter what mechanism you use, you’ll get a new tab containing a simple view of the original source code of the page”
You will actually get a *FRESH* copy of the source from a *BRAND NEW* reload of the request. GRRR! Wrong Implementation!
Thus if your page did a “one time only” thing… you will not see it :-( You’ll need to use a tool like Fiddler ;-) to capture the original source.
Firefox will return the *REAL* source of the original request… with the one exception of this new bug they have where the view-source fails after a redirection: https://bugzilla.mozilla.org/show_bug.cgi?id=1699785
Your description is not entirely accurate, no. A simple repro is to visit https://www.bayden.com/test/xhr/clock.asp, wait a few seconds, and hit `Ctrl+U`. You’ll note that the time from the original page load is shown.
It probably _is_ true that sometimes a cached resource can’t be used; bugs of that nature have been fixed before. Got a repro?
Hmm, yeah in *every* case for a secure application (which, should basically be all of them), the HTML page has a no-cache header, thus the bug listed comes into effect. The various comments sum up the disappointment.
The developer is *expecting* the source shown to be the source received by the browser, not to fetch a new copy.
It’s sad that https://bugs.chromium.org/p/chromium/issues/detail?id=4539 is listed as won’t fix. I’d gladly pay for an “as loaded” view-source.
It’s unclear to me why you’d expect a “secure application” to be specifying “no-cache”? (Commonly, developers expect no-cache to mean “don’t cache this” which isn’t at all what it means.)