Charlie Reis | cf8e81f | 2020-06-26 05:14:09 | [diff] [blame] | 1 | # Special Case URLs |
| 2 | |
| 3 | Several types of URLs lead to special case behavior in Chromium and are worth |
| 4 | considering as new features are built. |
| 5 | |
| 6 | [TOC] |
| 7 | |
| 8 | |
| 9 | ## about:blank |
| 10 | |
| 11 | `about:blank` may sound like the simplest document in a browser, but it is |
| 12 | actually a huge source of corner cases and confusion: |
| 13 | |
| 14 | * **It may not be empty.** The creator of an `about:blank` document may inject |
| 15 | content into it, using `document.write` or other DOM APIs like |
| 16 | `document.body.innerHTML`. |
| 17 | * **It may inherit an origin.** Navigating to `about:blank` in the address bar |
| 18 | has a unique, opaque origin, but an `about:blank` iframe or popup created by |
| 19 | another document will inherit that document's origin. (Caveat: Chromium's |
| 20 | process model uses the initiator of the navigation to determine which process |
| 21 | it belongs in, but Blink currently uses the parent's origin even if the |
| 22 | initiator is not the parent, which we would like to fix in |
| 23 | [issue 585649](https://crbug.com/585649). Blink also aliases the origin, so a |
| 24 | modification of `document.domain` in the parent unexpectedly affects the |
| 25 | `about:blank` document as well.) |
| 26 | * **It may change its URL.** When another document uses `document.open` or |
| 27 | `document.write` on an `about:blank` document, the `about:blank` document |
| 28 | inherits `location.href` from the other document. However, this type of URL |
| 29 | change does not occur for other DOM APIs (e.g., `document.body.innerHTML` |
| 30 | modifications), and the browser process does not yet learn about the URL |
| 31 | update at all (and thus the URL in the address bar does not change). |
| 32 | * **It may have URL parameters.** Some pages navigate `about:blank` documents |
| 33 | to fragments (e.g., `about:blank#foo`) or query parameters to communicate |
| 34 | with scripts that have been injected into the document. For this reason, we |
| 35 | recommend using `GURL::IsAboutBlank` to detect `about:blank` documents rather |
| 36 | than comparing directly against `kAboutBlankURL`. |
| 37 | * **It may be considered dangerous.** An `about:blank` document may inherit an |
| 38 | origin of a broken HTTPS document or an origin initially blocked by Safe |
| 39 | Browsing, resulting in potentially surprising address bar security |
| 40 | indicators. |
| 41 | * **It is present as the initial empty document of every frame.** While most |
| 42 | users will not see `about:blank` in the address bar very often, it is created |
| 43 | extremely frequently. Each main frame and subframe starts on `about:blank` |
| 44 | until the first document commits, and many real pages create `about:blank` |
| 45 | iframes to inject script code or other content into them. |
| 46 | * **It may or may not commit.** Surprisingly, only some of the above cases |
| 47 | generate navigation commit events in the browser process. The initial empty |
| 48 | document will commit if the iframe or `window.open` call has no URL or |
| 49 | `"about:blank"` itself, but if the iframe or `window.open` call use a real |
| 50 | (potentially slow) URL, there will be no commit for the initial empty |
| 51 | document. |
| 52 | * **It may or may not stay in session history.** In most cases, the initial |
| 53 | empty document is replaced in session history when the first non-blank URL |
| 54 | commits, such that you cannot go back to the `about:blank` NavigationEntry. |
| 55 | This is not true if a window is created with `window.open("about:blank")`, |
| 56 | though, in which case the NavigationEntry is preserved. |
| 57 | |
| 58 | |
| 59 | ## about:srcdoc |
| 60 | |
| 61 | This URL commits when an iframe is created with a `srcdoc` parameter to define |
| 62 | its contents. The contents can only be defined by the parent (or a same-origin |
| 63 | document with access to the parent), and the document inherits its parent's |
| 64 | origin. |
| 65 | |
| 66 | |
| 67 | ## iframe sandbox |
| 68 | |
| 69 | When an iframe has a `sandbox` attribute (which does not include |
| 70 | `allow-same-origin`), it can load its content from a URL but the document has an |
| 71 | opaque origin, rather than the origin of the URL. For this reason, it is |
| 72 | important for most security checks to look at the origin rather than the URL |
| 73 | (see [Origin vs URL](security/origin-vs-url.md)). |
| 74 | |
| 75 | |
Chris Palmer | 6f13140 | 2023-05-18 23:59:28 | [diff] [blame] | 76 | ## chrome: and os: URLs |
Charlie Reis | cf8e81f | 2020-06-26 05:14:09 | [diff] [blame] | 77 | |
| 78 | `chrome:` URLs are used for privileged pages that are part of Chromium, such as |
Chris Palmer | 6f13140 | 2023-05-18 23:59:28 | [diff] [blame] | 79 | `chrome://settings`. Similarly, `os:` URLs are privileged pages that are part of |
| 80 | ChromiumOS. Web pages are not allowed to navigate to them, to reduce the risk of |
| 81 | privilege escalation attacks. Note that there are a subset of `chrome:` URLs |
| 82 | that are used for debug commands, described under [Debug URLs](#debug-urls) |
| 83 | below. |
Charlie Reis | cf8e81f | 2020-06-26 05:14:09 | [diff] [blame] | 84 | |
| 85 | |
| 86 | ## Debug URLs |
| 87 | |
| 88 | Chromium supports a series of "debug URLs" listed at the bottom of |
| 89 | `chrome://chrome-urls`, such as `chrome://crash`. These are used to crash, hang, |
| 90 | exit, or perform other debug actions. Like `javascript:` URLs, these URLs |
| 91 | represent a command rather than a destination, and they do not go through the |
| 92 | normal navigation flow or commit at all. Like the other |
| 93 | [chrome: URLs](#chrome_urls) discussed above, web pages are not allowed to |
| 94 | navigate to them. |
| 95 | |
| 96 | |
| 97 | ## javascript: URLs |
| 98 | |
| 99 | Navigating to a `javascript:` URL is essentially evaluating a JavaScript |
| 100 | expression in the target document, rather than navigating to a new document. As |
| 101 | a result, the Same Origin Policy only allows navigating same-origin documents to |
| 102 | `javascript:` URLs. A `javascript:` URL will never commit to session history. |
| 103 | However, if it evaluates to a string (e.g., `javascript:"foo"`), then the |
| 104 | contents of the document will be replaced with the string, similar to a |
| 105 | `document.write("foo")` statement. (This does create a new Document in Blink, |
| 106 | though, while document.write does not.) |
| 107 | |
| 108 | |
| 109 | ## `chrome-error://chromewebdata` |
| 110 | |
| 111 | When Chromium navigates to an error page, it commits as |
| 112 | `chrome-error://chromewebdata`. This URL is not displayed to the user (in favor |
| 113 | of the URL that failed or was blocked). Note that this error URL is not stored |
| 114 | in the NavigationEntry, but error pages can also be detected using the |
| 115 | `url_is_unreachable` bit on the commit params. |