-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove the storage mutex #342
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -637,11 +637,6 @@ | |
be thought of as completely serialising the execution of all scripts in all <span data-x="browsing | ||
context">browsing contexts</span>.</p> | ||
|
||
<p class="note">The <code | ||
data-x="dom-navigator-yieldForStorageUpdates">navigator.yieldForStorageUpdates()</code> method, in | ||
this model, is equivalent to allowing other scripts to run while the calling script is | ||
blocked.</p> | ||
|
||
</div> | ||
|
||
|
||
|
@@ -8288,24 +8283,31 @@ partial /*sealed*/ interface <dfn>Document</dfn> { | |
<p id="sandboxCookies">On getting, if the document is a <span>cookie-averse <code>Document</code> | ||
object</span>, then the user agent must return the empty string. Otherwise, if the | ||
<code>Document</code>'s <span>origin</span> is not a scheme/host/port tuple, the user agent must | ||
throw a <code>SecurityError</code> exception. Otherwise, the user agent must first <span>obtain | ||
the storage mutex</span> and then return the <span>cookie-string</span> for <span>the document's address</span> | ||
for a "non-HTTP" API, decoded using the <span>UTF-8 decoder</span>. <ref spec=COOKIES> | ||
<!--INSERT FINGERPRINT--> | ||
throw a <code>SecurityError</code> exception. Otherwise, the user agent must return the | ||
<span>cookie-string</span> for <span>the document's address</span> for a "non-HTTP" API, decoded | ||
using the <span>UTF-8 decoder</span>. <ref spec=COOKIES> <!--INSERT FINGERPRINT--> | ||
</p> | ||
|
||
<p>On setting, if the document is a <span>cookie-averse <code>Document</code> object</span>, then | ||
the user agent must do nothing. Otherwise, if the <code>Document</code>'s <span>origin</span> is | ||
not a scheme/host/port tuple, the user agent must throw a <code>SecurityError</code> exception. | ||
Otherwise, the user agent must <span>obtain the storage mutex</span> and then act as it would when | ||
<span data-x="receives a set-cookie-string">receiving a set-cookie-string</span> for <span>the | ||
document's address</span> via a "non-HTTP" API, consisting of the new value encoded as UTF-8. <ref | ||
spec=COOKIES> <ref spec=ENCODING></p> | ||
Otherwise, the user agent must act as it would when <span data-x="receives a | ||
set-cookie-string">receiving a set-cookie-string</span> for <span>the document's address</span> | ||
via a "non-HTTP" API, consisting of the new value encoded as UTF-8. <ref spec=COOKIES> <ref | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Everything else in this paragraph says "the user agent must", so I'd prefix "return" with that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
spec=ENCODING></p> | ||
|
||
<p class="note">Since the <code data-x="dom-document-cookie">cookie</code> attribute is accessible | ||
across frames, the path restrictions on cookies are only a tool to help manage which cookies are | ||
sent to which parts of the site, and are not in any way a security feature.</p> | ||
|
||
<p class="warning">The <code data-x="dom-document-cookie">cookie</code> attribute's getter and | ||
setter synchronously access shared state. Since there is no locking mechanism, other browsing | ||
contexts in a multiprocess user agent can modify cookies while scripts are running. A site could, | ||
for instance, try to read a cookie, increment its value, then write it back out, using the new | ||
value of the cookie as a unique identifier for the session; if the site does this twice in two | ||
different browser windows at the same time, it might end up using the same "unique" identifier for | ||
both sessions, with potentially disastrous effects.</p> | ||
|
||
<hr> | ||
|
||
</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd love a code example if possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In particular, maybe one that echoes the removed - ... a site could,
- for instance, try to read a cookie, increment its value, then write it back out, using the new
- value of the cookie as a unique identifier for the session; if the site does this twice in two
- different browser windows at the same time, it might end up using the same "unique" identifier for
- both sessions, with potentially disastrous effects. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, restored some of that text in the warning. |
||
|
@@ -12884,8 +12886,6 @@ people expect to have work and what is necessary. | |
<li><p>If the <code>meta</code> element has no <code data-x="attr-meta-content">content</code> | ||
attribute, or if that attribute's value is the empty string, then abort these steps.</p></li> | ||
|
||
<li><p><span>Obtain the storage mutex</span>.</p></li> | ||
|
||
<li><p>Act as if <span data-x="receives a set-cookie-string">receiving a | ||
set-cookie-string</span> for <span>the document's address</span> via a "non-HTTP" API, | ||
consisting of the value of the element's <code data-x="attr-meta-content">content</code> | ||
|
@@ -79689,8 +79689,6 @@ x === this; // true</pre> | |
|
||
</li> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li> | ||
|
||
<p>Set the attribute's value to <var>new value</var>.</p> | ||
|
@@ -81482,8 +81480,6 @@ State: <OUTPUT NAME=I>1</OUTPUT> <INPUT VALUE="Increment" TYPE=BUTTON O | |
|
||
<ol> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li id="sandboxLinks"> | ||
|
||
<p>If the <span>source browsing context</span> is not <span>allowed to navigate</span> the | ||
|
@@ -83084,8 +83080,6 @@ dictionary <dfn>PageTransitionEventInit</dfn> : <span>EventInit</span> { | |
<li><p>Decrease the <span>event loop</span>'s <span>termination nesting level</span> by | ||
one.</p></li> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li><p>If any event listeners were triggered by the earlier <i>dispatch</i> step, then set the | ||
<code>Document</code>'s <i data-x="concept-document-salvageable">salvageable</i> state to | ||
false.</p></li> | ||
|
@@ -83193,8 +83187,6 @@ dictionary <dfn>PageTransitionEventInit</dfn> : <span>EventInit</span> { | |
<li><p>Decrease the <span>event loop</span>'s <span>termination nesting level</span> by | ||
one.</p></li> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li><p>If any event listeners were triggered by the earlier <i>unload event</i> step, then set | ||
the <code>Document</code> object's <i data-x="concept-document-salvageable">salvageable</i> state | ||
to false and set the <code>Document</code>'s <span>fired unload</span> flag to true.</p></li> | ||
|
@@ -86693,34 +86685,6 @@ dictionary <dfn>PromiseRejectionEventInit</dfn> : <span>EventInit</span> { | |
microtask checkpoint</dfn> flag, which must initially be false. It is used to prevent reentrant | ||
invocation of the <span>perform a microtask checkpoint</span> algorithm.</p> | ||
|
||
<hr> | ||
|
||
<p>A user agent may have one <dfn>storage mutex</dfn>. This mutex is used to control access to | ||
shared state like cookies. At any one point, the <span>storage mutex</span> is either free, or | ||
owned by a particular <span>event loop</span> or instance of the <span | ||
data-x="concept-fetch">fetching</span> algorithm.</p> | ||
|
||
<p>If a user agent does not implement a <span>storage mutex</span>, it is exempt from implementing | ||
the requirements that require it to acquire or release it.</p> | ||
|
||
<p class="note">User agent implementors have to make a choice between two evils. On the one hand, | ||
not implementing the storage mutex means that there is a risk of data corruption: a site could, | ||
for instance, try to read a cookie, increment its value, then write it back out, using the new | ||
value of the cookie as a unique identifier for the session; if the site does this twice in two | ||
different browser windows at the same time, it might end up using the same "unique" identifier for | ||
both sessions, with potentially disastrous effects. On the other hand, implementing the storage | ||
mutex has potentially serious performance implications: whenever a site uses Web Storage or | ||
cookies, all other sites that try to use Web Storage or cookies are blocked until the first site | ||
finishes.</p> | ||
|
||
<p class="warning">So far, all browsers faced with this decision have opted to not implement the | ||
<span>storage mutex</span>.</p> | ||
|
||
<p>Whenever a <span data-x="concept-script">script</span> calls into a <span>plugin</span>, and | ||
whenever a <span>plugin</span> calls into a <span data-x="concept-script">script</span>, the user | ||
agent must release the <span>storage mutex</span>.</p> | ||
|
||
|
||
<h5>Processing model</h5> <!-- EVENT LOOP --> | ||
|
||
<p>An <span>event loop</span> must continually run through the following steps for as long as it | ||
|
@@ -86750,9 +86714,6 @@ dictionary <dfn>PromiseRejectionEventInit</dfn> : <span>EventInit</span> { | |
<li><p>Set the <span>event loop</span>'s <span>currently running task</span> back to | ||
null.</p></li> | ||
|
||
<li><p>If the <span>storage mutex</span> is now owned by the <span>event loop</span>, release it | ||
so that it is once again free.</p></li> | ||
|
||
<li><p>Remove the task that was run in the <i>run</i> step above from its <span>task | ||
queue</span>.</p></li> | ||
|
||
|
@@ -86913,9 +86874,6 @@ dictionary <dfn>PromiseRejectionEventInit</dfn> : <span>EventInit</span> { | |
<li><p>Set the <span>event loop</span>'s <span>currently running task</span> back to | ||
null.</p></li> | ||
|
||
<li><p>If the <span>storage mutex</span> is now owned by the <span>event loop</span>, release it | ||
so that it is once again free.</p></li> | ||
|
||
<li><p>Remove the <span>microtask</span> run in the step above from the <span>microtask | ||
queue</span>, and return to the <i>microtask queue handling</i> step.</p></li> | ||
|
||
|
@@ -87042,28 +87000,6 @@ dictionary <dfn>PromiseRejectionEventInit</dfn> : <span>EventInit</span> { | |
|
||
</ol> | ||
|
||
<hr> | ||
|
||
<p>When a user agent is to <dfn>obtain the storage mutex</dfn> as part of running a <span | ||
data-x="concept-task">task</span>, it must run through the following steps:</p> | ||
|
||
<ol> | ||
|
||
<li><p>If the <span>storage mutex</span> is already owned by this <span | ||
data-x="concept-task">task</span>'s <span>event loop</span>, then abort these steps.</p></li> | ||
|
||
<li><p>Otherwise, <span>pause</span> until the <span>storage mutex</span> can be taken by the | ||
<span>event loop</span>.</p></li> | ||
|
||
<li><p>Take ownership of the <span>storage mutex</span>.</p></li> | ||
|
||
</ol> | ||
|
||
</div> | ||
|
||
|
||
<div w-nodev> | ||
|
||
<h5>Generic task sources</h5> | ||
|
||
<p>The following <span data-x="task source">task sources</span> are used by a number of mostly | ||
|
@@ -88247,8 +88183,6 @@ interface <dfn>WindowBase64</dfn> { | |
|
||
</li> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li><p>Set the <code>Document</code>'s <i | ||
data-x="concept-document-salvageable">salvageable</i> state to false.</p></li> | ||
|
||
|
@@ -88964,10 +88898,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
|
||
<p>Displays a modal alert with the given message, and waits for the user to dismiss it.</p> | ||
|
||
<p>A call to the <code | ||
data-x="dom-navigator-yieldForStorageUpdates">navigator.yieldForStorageUpdates()</code> method is | ||
implied when this method is invoked.</p> | ||
|
||
</dd> | ||
|
||
<dt><var>result</var> = <var>window</var> . <code subdfn data-x="dom-confirm">confirm</code>(<var>message</var>)</dt> | ||
|
@@ -88976,10 +88906,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
<p>Displays a modal OK/Cancel prompt with the given message, waits for the user to dismiss it, | ||
and returns true if the user clicks OK and false if the user clicks Cancel.</p> | ||
|
||
<p>A call to the <code | ||
data-x="dom-navigator-yieldForStorageUpdates">navigator.yieldForStorageUpdates()</code> method is | ||
implied when this method is invoked.</p> | ||
|
||
</dd> | ||
|
||
<dt><var>result</var> = <var>window</var> . <code subdfn data-x="dom-prompt">prompt</code>(<var>message</var> [, <var>default</var>] )</dt> | ||
|
@@ -88989,10 +88915,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
and returns the value that the user entered. If the user cancels the prompt, then returns null | ||
instead. If the second argument is present, then the given value is used as a default.</p> | ||
|
||
<p>A call to the <code | ||
data-x="dom-navigator-yieldForStorageUpdates">navigator.yieldForStorageUpdates()</code> method is | ||
implied when this method is invoked.</p> | ||
|
||
</dd> | ||
|
||
</dl> | ||
|
@@ -89011,8 +88933,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
<li><p>If the <span>event loop</span>'s <span>termination nesting level</span> is non-zero, | ||
optionally abort these steps.</p></li> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li><p>If the <span>active sandboxing flag set</span> of the <span>active document</span> of | ||
the <span>responsible browsing context</span> specified by the <span>incumbent settings | ||
object</span> has the <span>sandboxed modals flag</span> set, then abort these | ||
|
@@ -89041,8 +88961,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
<li><p>If the <span>event loop</span>'s <span>termination nesting level</span> is non-zero, | ||
optionally abort these steps, returning false.</p></li> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li><p>If the <span>active sandboxing flag set</span> of the <span>active document</span> of | ||
the <span>responsible browsing context</span> specified by the <span>incumbent settings | ||
object</span> has the <span>sandboxed modals flag</span> set, then return false and abort these | ||
|
@@ -89069,8 +88987,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
<li><p>If the <span>event loop</span>'s <span>termination nesting level</span> is non-zero, | ||
optionally abort these steps, returning null.</p></li> | ||
|
||
<li><p>Release the <span>storage mutex</span>.</p></li> | ||
|
||
<li><p>If the <span>active sandboxing flag set</span> of the <span>active document</span> of | ||
the <span>responsible browsing context</span> specified by the <span>incumbent settings | ||
object</span> has the <span>sandboxed modals flag</span> set, then return null and abort these | ||
|
@@ -89104,10 +89020,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
|
||
<p>Prompts the user to print the page.</p> | ||
|
||
<p>A call to the <code | ||
data-x="dom-navigator-yieldForStorageUpdates">navigator.yieldForStorageUpdates()</code> method is | ||
implied when this method is invoked.</p> | ||
|
||
</dd> | ||
|
||
</dl> | ||
|
@@ -89167,12 +89079,6 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
|
||
</li> | ||
|
||
<li> | ||
|
||
<p>The user agent must release the <span>storage mutex</span>.</p> | ||
|
||
</li> | ||
|
||
<li> | ||
|
||
<p>The user agent should offer the user the opportunity to <span>obtain a physical form</span> | ||
|
@@ -89223,7 +89129,7 @@ scheduleWork(); // queues a task to do lots of work</pre> | |
<span>Navigator</span> implements <span>NavigatorLanguage</span>; | ||
<span>Navigator</span> implements <span>NavigatorOnLine</span>; | ||
<span>Navigator</span> implements <span>NavigatorContentUtils</span>; | ||
<span>Navigator</span> implements <span>NavigatorStorageUtils</span>; | ||
<span>Navigator</span> implements <span>NavigatorCookies</span>; | ||
<span>Navigator</span> implements <span>NavigatorPlugins</span>;</pre> | ||
|
||
<!-- v2: | ||
|
@@ -90122,12 +90028,11 @@ interface <dfn>NavigatorContentUtils</dfn> { | |
|
||
|
||
|
||
<h5>Manually releasing the storage mutex</h5> | ||
<h5>Cookies</h5> | ||
|
||
<pre class="idl">[NoInterfaceObject] | ||
interface <dfn>NavigatorStorageUtils</dfn> { | ||
interface <dfn>NavigatorCookies</dfn> { | ||
readonly attribute boolean <span data-x="dom-navigator-cookieEnabled">cookieEnabled</span>; | ||
void <span data-x="dom-navigator-yieldForStorageUpdates">yieldForStorageUpdates</span>(); | ||
};</pre> | ||
|
||
<dl class="domintro"> | ||
|
@@ -90140,26 +90045,6 @@ interface <dfn>NavigatorStorageUtils</dfn> { | |
|
||
</dd> | ||
|
||
|
||
<dt><var>window</var> . <code data-x="dom-navigator">navigator</code> . <code subdfn data-x="dom-navigator-yieldForStorageUpdates">yieldForStorageUpdates</code>()</dt> | ||
|
||
<dd> | ||
|
||
<p>If a script uses the <code data-x="dom-document-cookie">document.cookie</code> API, or the | ||
<code data-x="dom-localStorage">localStorage</code> API, the browser will block other scripts | ||
from accessing cookies or storage until the first script finishes.</p> | ||
|
||
<p>Calling the <code | ||
data-x="dom-navigator-yieldForStorageUpdates">navigator.yieldForStorageUpdates()</code> method | ||
tells the user agent to unblock any other scripts that may be blocked, even though the script | ||
hasn't returned.</p> | ||
|
||
<p>Values of cookies and items in the <code>Storage</code> objects of <code | ||
data-x="dom-localStorage">localStorage</code> attributes can change after calling this method, | ||
whence its name.</p> | ||
|
||
</dd> | ||
|
||
</dl> | ||
|
||
<div w-nodev> | ||
|
@@ -90168,11 +90053,6 @@ interface <dfn>NavigatorStorageUtils</dfn> { | |
return true if the user agent attempts to handle cookies according to the cookie specification, | ||
and false if it ignores cookie change requests. <ref spec=COOKIES></p> | ||
|
||
<p>The <dfn><code data-x="dom-navigator-yieldForStorageUpdates">yieldForStorageUpdates()</code></dfn> method, | ||
when invoked, must, if the <span>storage mutex</span> is owned by the <span>event loop</span> of | ||
the <span data-x="concept-task">task</span> that resulted in the method being called, release the | ||
<span>storage mutex</span> so that it is once again free. Otherwise, it must do nothing.</p> | ||
|
||
</div> | ||
|
||
|
||
|
@@ -96386,13 +96266,13 @@ interface <dfn>WindowLocalStorage</dfn> { | |
<code>Window</code> object's <code data-x="dom-localStorage">localStorage</code> attribute's | ||
<code>Storage</code> object is associated with the same storage area, other than <var>x</var>, <span>send a storage notification</span>. | ||
|
||
<p id="localStorageMutex">Whenever the properties of a <code | ||
data-x="dom-localStorage">localStorage</code> attribute's <code>Storage</code> object are to be | ||
examined, returned, set, or deleted, whether as part of a direct property access, when checking | ||
for the presence of a property, during property enumeration, when determining the number of | ||
properties present, or as part of the execution of any of the methods or attributes defined on the | ||
<code>Storage</code> interface, the user agent must first <span>obtain the storage | ||
mutex</span>.</p> | ||
<p class="warning">The <code data-x="dom-localStorage">localStorage</code> attribute provides | ||
access to shared state. This specification does not define the interaction with other browsing | ||
contexts in a multiprocess user agent, and authors are encourages to assume that there is no | ||
locking mechanism. A site could, for instance, try to read the value of a key, increment its | ||
value, then write it back out, using the new value as a unique identifier for the session; if the | ||
site does this twice in two different browser windows at the same time, it might end up using the | ||
same "unique" identifier for both sessions, with potentially disastrous effects.</p> | ||
|
||
|
||
<h4>The <code data-x="event-storage">storage</code> event</h4> | ||
|
@@ -96478,18 +96358,6 @@ dictionary <dfn>StorageEventInit</dfn> : <span>EventInit</span> { | |
initialised to null. It represents the <code>Storage</code> object that was affected.</p> | ||
|
||
|
||
|
||
<h4>Threads</h4> | ||
|
||
<p>Because of <a href="#localStorageMutex">the use</a> of the <span>storage mutex</span>, multiple | ||
browsing contexts will be able to access the local storage areas simultaneously in such a manner | ||
that scripts cannot detect any concurrent script execution.</p> | ||
|
||
<p>Thus, the <code data-x="dom-Storage-length">length</code> attribute of a <code>Storage</code> | ||
object, and the value of the various properties of that object, cannot change while a script is | ||
executing, other than in a way that is predictable by the script itself.</p> | ||
|
||
|
||
<h3>Disk space</h3> | ||
|
||
<p>User agents should limit the total amount of space allowed for storage areas, because hostile | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this section is still valuable. You can just remove the note. Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.