0%

Origins and Cross-Site Requests · practice

Origins and Sites

Open mini_browser.py. Near the top are a few constants and three supplied helpers that Chapter 9 needs. Below them are the rules, and each one still only raises NotImplementedError. Run the file in the :

python mini_browser.py
Each page below is compared with https://reading.example.
The last column: does the session cookie go along when the page posts a form to the reading list?

page                           site                     same origin      same site        cookie sent
https://reading.example        not written yet          not written yet  not written yet  not written yet
https://app.reading.example    not written yet          not written yet  not written yet  not written yet
https://notes.reading.example  not written yet          not written yet  not written yet  not written yet
https://other.example          not written yet          not written yet  not written yet  not written yet

One row per name, and nothing in it yet. This lesson fills three of the four columns.

The origin as text

Lesson 1 defined an in words: scheme, host, and . origin_of(url) returns it as text, always in the same form, so that two origins can be compared with ==:

  • the scheme, then ://, then the host: https://reading.example

  • then : and the port, unless the port is the default of the scheme: http://reading.example:8080

urlsplit(url) gives you the pieces. parts.scheme and parts.hostname come back in lower case, so HTTPS://Reading.Example needs no extra work. parts.port is a number, or None when the names no port. The supplied DEFAULT_PORTS holds 80 for "http" and 443 for "https". A port that is None or equal to the default is left out of the text. Any other port is kept.

The model knows http and https URLs that have a host, and nothing else. For ftp://reading.example/x, the scheme is not a key of DEFAULT_PORTS. For a bare path such as /books, parts.hostname is None. In both cases origin_of raises .

same_origin(a, b) takes two URLs and says whether their origins are equal.

A site is coarser

Three of the four names belong together: reading.example, app.reading.example, and notes.reading.example. The origin does not show that. Three hosts are three origins.

are older than the protection of origins, and they go by a coarser unit. The SameSite flag you set in Chapter 4 compares sites.

A site is the scheme plus the registrable domain: the part of a host name that someone registered, such as reading.example. A real browser finds that part with the public suffix , because some names end in a suffix of more than one label. A label is one piece of a host name between two dots. co.uk and github.io are such suffixes, so the registrable domain of shop.example.co.uk is example.co.uk, three labels long.

The model has no such list, and its rule is a model rule: every name in this course ends in a suffix of one label, so the site is the scheme plus the last two labels of the host.

site https://reading.example
+----------------------------------------+
|  origin https://reading.example        |
|  origin https://app.reading.example    |
|  origin https://notes.reading.example  |
+----------------------------------------+

site https://other.example
+----------------------------------------+
|  origin https://other.example          |
+----------------------------------------+

The three hosts that end in reading.example are three origins inside one site, https://reading.example. https://other.example is one origin, and it is a site of its own.

https://reading.example, https://app.reading.example, and https://notes.reading.example are

The scheme is part of a site, as it is part of an origin. A page that came over plain http does not belong to the site of the https pages on the same host. That is the standard’s rule, and Chromium applies it to cookies. Firefox and Safari still treat the two as one site when they decide whether a SameSite cookie goes along. Lesson 3 lists this with the other differences.

Are http://reading.example and https://reading.example the same site?

Why would the two-label rule be wrong for shop.example.co.uk?

The rule has a second limit. A host that is an , or a single label, has no registrable domain, and the two-label rule gives a wrong answer for it. Never give the model such a host. Check my work does not.

What a site ignores

A site has no port. https://reading.example:8443 and https://reading.example are two origins, because the ports differ, and one site. So site_of starts from the host name alone: split parts.hostname at the dots, keep the last two labels with labels[-2:], and join them with "." again. Put the scheme and :// in front.

With the four functions written, what does this line print?

print(site_of("https://app.reading.example:8443/x"), same_site("https://notes.reading.example", "https://reading.example"), same_origin("https://notes.reading.example", "https://reading.example"))

Your task

In mini_browser.py, write the four that carry the comment # Write this function in Lesson 2.:

  1. origin_of(url) returns the origin as text, and raises ValueError for a URL the model does not know.

  2. same_origin(a, b) compares the origins of two URLs.

  3. site_of(url) returns the site as text: the scheme, ://, and the last two labels of the host.

  4. same_site(a, b) compares the sites of two URLs.

Each function keeps its name, its , and its docstring. Replace the comment and the raise line with your code. site_of and the two same_ functions can each call a function you wrote just before.

Then run python mini_browser.py again:

page                           site                     same origin      same site        cookie sent
https://reading.example        https://reading.example  True             True             not written yet
https://app.reading.example    https://reading.example  False            True             not written yet
https://notes.reading.example  https://reading.example  False            True             not written yet
https://other.example          https://other.example    False            False            not written yet

Read the two middle columns from top to bottom. Only the reading list shares an origin with itself. Its two neighbors are other origins on the same site, and other.example is neither. That difference between the second and the third column is what the rest of this chapter is about.

Then press Check my work. The last column waits for Lesson 3, which decides when a cookie goes along.

Task

Write the first four rules of the model, in mini_browser.py.

origin_of(url) returns the of a as text: the scheme, ://, the host in lower case, and then : and the unless the port is the default of the scheme (80 for http, 443 for https). The path and the query are dropped.

  • origin_of("HTTPS://Reading.Example:443/books?x=1") returns "https://reading.example".

  • origin_of("http://reading.example:8080/a") returns "http://reading.example:8080".

It raises for anything but an http or https URL with a host, such as "ftp://reading.example/x" or "/books".

site_of(url) returns the site of a URL as text: the scheme, ://, and the last two labels of the host. A site has no port.

  • site_of("https://notes.reading.example/page") returns "https://reading.example".

  • site_of("http://reading.example:8080") returns "http://reading.example".

same_origin(a, b) and same_site(a, b) each take two URLs and return True or False: whether the two have the same origin, and whether they have the same site.

Run python mini_browser.py and read the table.

Then press Check my work. It calls the four with URLs you have not seen: URLs with a path and a query, with capital letters in the scheme and the host, with the default port written out, and with other ports; three URLs that origin_of must refuse with ValueError; hosts of two, three, and five labels; and pairs that differ only in the scheme, only in the port, or only in one label. It never passes an or a host of one label. Nothing from your is graded.