[EME] Bug 26683 - Replace MediaKeyMessageEvent's "destinationURL" attribute with a "type" attribute
authorDavid Dorwin <ddorwin@google.com>
Fri, 19 Sep 2014 10:43:04 -0700
changeset 433 18f364378718
parent 432 d4cd783f02b3
child 434 f18f378041a2
[EME] Bug 26683 - Replace MediaKeyMessageEvent's "destinationURL" attribute with a "type" attribute
encrypted-media/encrypted-media.html
encrypted-media/encrypted-media.xml
--- a/encrypted-media/encrypted-media.html	Fri Sep 19 09:33:16 2014 -0700
+++ b/encrypted-media/encrypted-media.html	Fri Sep 19 10:43:04 2014 -0700
@@ -554,7 +554,7 @@
 <p>Run the following steps asynchronously:</p>
         <ol>
           <li><p>Let <var title="true">session id</var> be the empty string.</p></li>
-          <li><p>Let <var title="true">request</var> be null.</p></li>
+          <li><p>Let <var title="true">message</var> be null.</p></li>
           <li><p>Let <var title="true">cdm</var> be the CDM loaded during the <a href="#dom-create">initialization</a> of <var title="true">media keys</var>.</p></li>
           <li>
 <p>Use the <var title="true">cdm</var> to execute the following steps:</p>
@@ -579,7 +579,7 @@
                 <p>If <var title="true">session type</var> is "<code><a href="#dom-sessiontypepersistent">persistent</a></code>", the ID must be unique within the the <a href="http://www.w3.org/TR/html5/browsers.html#origin-0">origin</a> of this object's <code><a href="http://www.w3.org/TR/dom/#document">Document</a></code> over time, including across Documents and browsing sessions.</p>
               </li>
               <li>
-<p>Let <var title="true">request</var> be a request <span class="non-normative">(e.g. a license request)</span> for the <var title="true">requested session type</var> generated based on the <var>init data</var>, which is interpreted per <var title="true">initDataType</var>.</p>
+<p>Let <var title="true">message</var> be a request <span class="non-normative">(e.g. a license request)</span> for the <var title="true">requested session type</var> generated based on the <var>init data</var>, which is interpreted per <var title="true">initDataType</var>.</p>
                 <p>The <var title="true">cdm</var> must not use any stream-specific data, including <a href="http://www.w3.org/TR/html5/embedded-content-0.html#media-data">media data</a>, not provided via the <var>init data</var>.</p>
                 <p>The <var title="true">cdm</var> should <em>not</em> store session data, including the session ID, at this point. See <a href="#session-storage">Session Storage and Persistence</a>.</p>
               </li>
@@ -588,7 +588,7 @@
           <li><p>If any of the preceding steps failed, reject <var>promise</var> with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is the appropriate <a href="#error-names">error name</a>.</p></li>
           <li><p>Set the <code><a href="#dom-sessionid">sessionId</a></code> attribute to <var title="true">session id</var>.</p></li>
           <li><p>Let this object's <var title="true">callable</var> be true.</p></li>
-          <li><p>Run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">request</var> and <code>null</code>.</p></li>
+          <li><p>Run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing "<code><a href="#dom-licenserequest">licenserequest</a></code>" and <var title="true">message</var>.</p></li>
           <li><p>Resolve <var>promise</var>.</p></li>
         </ol>
       </li>
@@ -609,8 +609,8 @@
 <p>Run the following steps asynchronously:</p>
         <ol>
           <li><p>Let <var title="true">expiration time</var> be <code>NaN</code>.</p></li>
-          <li><p>Let <var title="true">request</var> be null.</p></li>
-          <li><p>Let <var title="true">destination URL</var> be null.</p></li>
+          <li><p>Let <var title="true">message</var> be null.</p></li>
+          <li><p>Let <var title="true">message type</var> be null.</p></li>
           <li><p>Let <var title="true">origin</var> be the <a href="http://www.w3.org/TR/html5/browsers.html#origin-0">origin</a> of this object's <code><a href="http://www.w3.org/TR/dom/#document">Document</a></code>.</p></li>
           <li><p>Let <var title="true">cdm</var> be the CDM loaded during the <a href="#dom-create">initialization</a> of <var title="true">media keys</var>.</p></li>
           <li>
@@ -628,8 +628,8 @@
               <li>
 <p>If the CDM needs to send a message:</p>
                 <ol>
-                  <li><p>Let <var title="true">request</var> be a request generated by the <a href="#cdm">CDM</a> based on the <var title="true">session data</var>.</p></li>
-                  <li><p>If the <var title="true">session data</var> indicates a destination URL for the request, let <var title="true">destination URL</var> be that URL. The URL may be validated and/or normalized.</p></li>
+                  <li><p>Let <var title="true">message</var> be a message generated by the <a href="#cdm">CDM</a> based on the <var title="true">session data</var>.</p></li>
+                  <li><p>Let <var title="true">message type</var> be the appropriate <code><a href="#dom-mediakeymessagetype">MediaKeyMessageType</a></code> for the message.</p></li>
                 </ol>
               </li>
             </ol>
@@ -642,7 +642,7 @@
             <p>The algorithm may also be run later should additional processing be necessary to determine with certainty whether one or more keys is usable.</p>
           </li>
           <li><p>Run the <a href="#algorithms-update-expiration">Update Expiration</a> algorithm on the <var title="true">session</var>, providing <var title="true">expiration time</var>.</p></li>
-          <li><p>If <var title="true">request</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">request</var> and <var title="true">destination URL</var>.</p></li>
+          <li><p>If <var title="true">message</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">message type</var> and <var title="true">message</var>.</p></li>
           <li><p>Resolve <var>promise</var> with <code>true</code>.</p></li>
         </ol>
       </li>
@@ -655,32 +655,32 @@
     <ol>
       <li><p>If this object's <var title="true">callable</var> value is false, return a promise rejected with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is <code><a href="#dfn-InvalidStateError">"InvalidStateError"</a></code>.</p></li>
       <li><p>If <var title="true">response</var> is an empty array, return a promise rejected with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</p></li>
-      <li><p>Let <var>message</var> be a copy of the contents of the <var title="true">response</var> parameter.</p></li>
+      <li><p>Let <var>response copy</var> be a copy of the contents of the <var title="true">response</var> parameter.</p></li>
       <li><p>Let <var>promise</var> be a new promise.</p></li>
       <li>
 <p>Run the following steps asynchronously:</p>
         <ol>
           <li><p>Let <var title="true">cdm</var> be the CDM loaded during the <a href="#dom-create">initialization</a> of the <code><a href="#dom-mediakeys">MediaKeys</a></code> object that created this object.</p></li>
-          <li><p>Let <var title="true">request</var> be null.</p></li>
-          <li><p>Let <var title="true">destination URL</var> be null.</p></li>
+          <li><p>Let <var title="true">message</var> be null.</p></li>
+          <li><p>Let <var title="true">message type</var> be null.</p></li>
           <li>
 <p>Use the <var title="true">cdm</var> to execute the following steps:</p>
             <ol>
-              <li><p>If the format of <var>message</var> is invalid in any way, reject <var>promise</var> with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</p></li>
+              <li><p>If the format of <var>response copy</var> is invalid in any way, reject <var>promise</var> with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</p></li>
               <li>
-<p>Process <var>message</var>, following the stipulation for the first matching condition from the following list:</p>
+<p>Process <var>response copy</var>, following the stipulation for the first matching condition from the following list:</p>
                 <dl class="switch">
-                  <dt>If <var title="true">sessionType</var> is "<code><a href="#dom-sessiontypetemporary">temporary</a></code>" and <var>message</var> does not specify that session data, including any license, key(s), or similar session data it contains, should be stored</dt>
-                  <dd>Continue processing <var>message</var>, not storing any session data.</dd>
+                  <dt>If <var title="true">sessionType</var> is "<code><a href="#dom-sessiontypetemporary">temporary</a></code>" and <var>response copy</var> does not specify that session data, including any license, key(s), or similar session data it contains, should be stored</dt>
+                  <dd>Continue processing <var>response copy</var>, not storing any session data.</dd>
                   <dt>If <var title="true">sessionType</var> is "<code><a href="#dom-sessiontypepersistent">persistent</a></code>"</dt>
-                  <dd>Continue processing <var>message</var>, storing the license, key(s), or similar session data contained in <var>message</var> as permitted or instructed by the license.
+                  <dd>Continue processing <var>response copy</var>, storing the license, key(s), or similar session data contained in <var>response copy</var> as permitted or instructed by the license.
                     Such data must be stored such that only the <a href="http://www.w3.org/TR/html5/browsers.html#origin-0">origin</a> of this object's <code><a href="http://www.w3.org/TR/dom/#document">Document</a></code> can access it.
                   </dd>
                   <dt>Otherwise</dt>
                   <dd>Reject <var>promise</var> with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</dd>
                 </dl>
                 <p>See also <a href="#session-storage">Session Storage and Persistence</a>.</p>
-                <p class="non-normative">Note: When <var>message</var> contains key(s) and/or related data, <var title="true">cdm</var> will likely cache the key and related data indexed by key ID.</p>
+                <p class="non-normative">Note: When <var>response copy</var> contains key(s) and/or related data, <var title="true">cdm</var> will likely cache the key and related data indexed by key ID.</p>
                 <p class="non-normative">Note: The replacement algorithm within a session is <a href="#key-system">Key System</a>-dependent.</p>
                 <p class="non-normative">Note: Keys from different sessions should be cached independently such that closing one session does not affect keys in other sessions, even if they have overlapping key IDs.</p>
                 <p class="non-normative">Note: It is recommended that CDMs support a standard and reasonably high minimum number of keys per <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object, including a standard replacement algorithm, and a standard and reasonably high minimum number of <code><a href="#dom-mediakeysession">MediaKeySession</a></code> objects.
@@ -693,16 +693,16 @@
               </li>
               <li><p>If the expiration time for the session changed, run the <a href="#algorithms-update-expiration">Update Expiration</a> algorithm on the <var title="true">session</var>, providing the new expiration time.</p></li>
               <li>
-<p>If another message needs to be sent to the server, execute the following steps:</p>
+<p>If a message needs to be sent to the server, execute the following steps:</p>
                 <ol>
-                  <li><p>Let <var title="true">request</var> be that message.</p></li>
-                  <li><p>If there is a specific destination URL for the message, let <var title="true">destination URL</var> be that URL. The URL may be validated and/or normalized.</p></li>
+                  <li><p>Let <var title="true">message</var> be that message.</p></li>
+                  <li><p>Let <var title="true">message type</var> be the appropriate <code><a href="#dom-mediakeymessagetype">MediaKeyMessageType</a></code> for the message.</p></li>
                 </ol>
               </li>
             </ol>
           </li>
           <li><p>If any of the preceding steps failed, reject <var>promise</var> with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is the appropriate <a href="#error-names">error name</a>.</p></li>
-          <li><p>If <var title="true">request</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">request</var> and <var title="true">destination URL</var>.</p></li>
+          <li><p>If <var title="true">message</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">message type</var> and <var title="true">message</var>.</p></li>
           <li><p>Resolve <var>promise</var>.</p></li>
         </ol>
       </li>
@@ -814,15 +814,17 @@
 </pre>
 
     <pre class="idl">
+enum <dfn id="dom-mediakeymessagetype">MediaKeyMessageType</dfn> { "<dfn id="dom-licenserequest">licenserequest</dfn>", "<dfn id="dom-licenserenewal">licenserenewal</dfn>", "<dfn id="dom-licenserelease">licenserelease</dfn>" };
+
 [Constructor(DOMString type, optional <a href="#dom-mediakeymessageeventinit">MediaKeyMessageEventInit</a> eventInitDict)]
 interface <dfn id="dom-mediakeymessageevent">MediaKeyMessageEvent</dfn> : <a href="http://www.w3.org/TR/dom/#event">Event</a> {
+  readonly attribute <a href="#dom-mediakeymessagetype">MediaKeyMessageType</a> <a href="#dom-type">type</a>;
   readonly attribute ArrayBuffer <a href="#dom-message">message</a>;
-  readonly attribute DOMString? <a href="#dom-destinationurl">destinationURL</a>;
 };
 
 dictionary <dfn id="dom-mediakeymessageeventinit">MediaKeyMessageEventInit</dfn> : <a href="http://www.w3.org/TR/dom/#eventinit">EventInit</a> {
+  <a href="#dom-mediakeymessagetype">MediaKeyMessageType</a> <a href="#dom-type">type</a> = "<a href="#dom-licenserequest">licenserequest</a>";
   ArrayBuffer <a href="#dom-message">message</a> = ArrayBuffer();
-  DOMString? <a href="#dom-destinationurl">destinationURL</a> = null;
 };
 </pre>
 
@@ -840,31 +842,23 @@
        <p>Returns the <a href="#initialization-data">Initialization Data</a> related to the event.</p>
      </dd>
      <dt>
+<var title="">event</var> . <code><a href="#dom-type">type</a></code>
+</dt>
+     <dd>
+       <p>Returns the type of the message.</p>
+     </dd>
+     <dt>
 <var title="">event</var> . <code><a href="#dom-message">message</a></code>
 </dt>
      <dd>
        <p>Returns the message <span class="non-normative">(i.e. license request)</span> to send.</p>
      </dd>
-     <dt>
-<var title="">event</var> . <code><a href="#dom-destinationurl">destinationURL</a></code>
-</dt>
-     <dd>
-       <p>Returns the URL to which the <code><a href="#dom-message">message</a></code> should be sent.</p>
-     </dd>
     </dl>
     <div class="impl">
     <p>The <dfn id="dom-initdatatype"><code>initDataType</code></dfn> attribute contains a string indicating the <a href="#initialization-data-type">initialization data type</a> specific to the event. The format of the <code><a href="#dom-initdata">initData</a></code> will vary according to the <code><a href="#dom-initdatatype">initDataType</a></code>.</p>
     <p>The <dfn id="dom-initdata"><code>initData</code></dfn> attribute contains <a href="#initialization-data">Initialization Data</a> specific to the event.</p>
-    <p>The <dfn id="dom-message"><code>message</code></dfn> attribute contains a message from the CDM. Messages are Key System-specific. <span class="non-normative">In most cases, it should be sent to a key server.</span></p>
-    <p>The <dfn id="dom-destinationurl"><code>destinationURL</code></dfn> is the URL to which the <code><a href="#dom-message">message</a></code> should be sent.
-       It may be null.
-       An application <em>may</em> choose not to send the message to this URL.
-       Implementations may validate and/or normalize the URL, which could result in a value that is different from the original or null. Applications should not assume that the value of this attribute will be identical across implementations.
-    </p>
-    <div class="issue">
-<div class="issue-title"><span>Issue 3</span></div>
-<p class=""><a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=26683">Bug 26683</a> - destinationURL may be removed.</p>
-</div>
+    <p>The <dfn id="dom-type"><code>type</code></dfn> is the type of the message.</p>
+    <p>The <dfn id="dom-message"><code>message</code></dfn> attribute contains a message from the CDM. Messages are Key System-specific.</p>
     <p>Events are constructed as defined in <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#constructing-events">Constructing events</a>, in [DOM4].</p>
     </div>
 
@@ -909,15 +903,12 @@
         <tr>
           <td><dfn id="dom-eventkeyschange"><code>keyschange</code></dfn></td>
           <td><code><a href="http://www.w3.org/TR/dom/#event">Event</a></code></td>
-          <td>There has been a change in usable keys.</td>
+          <td>There has been a change in usable keys in the session.</td>
         </tr>
         <tr>
           <td><dfn id="dom-eventmessage"><code>message</code></dfn></td>
           <td><code><a href="#dom-mediakeymessageevent">MediaKeyMessageEvent</a></code></td>
-          <td>
-            A message has been generated <span class="non-normative">(and likely needs to be sent to a server)</span>.
-            <span class="non-normative">For example, a license request has been generated as the result of a <code><a href="#dom-generaterequest">generateRequest()</a></code> call or another message must be sent in response to an <code><a href="#dom-update">update()</a></code> call.</span>
-          </td>
+          <td>The CDM has generated a message for the session.</td>
         </tr>
       </tbody>
     </table>
@@ -926,7 +917,7 @@
 
     <h4 id="algorithms-queue-message">3.5.1. Queue a "message" Event</h4>
     <p>The Queue a "message" Event algorithm is run when the CDM needs to queue a message event to a <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.
-    Requests to run this algorithm include a target <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object, a <var title="true">request</var>, and a <var title="true">destination URL</var>.
+    Requests to run this algorithm include a target <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object, a <var title="true">message type</var>, and a <var title="true">message</var>.
     </p>
     <p>The following steps are run:</p>
     <ol>
@@ -935,8 +926,8 @@
         <p><a href="http://www.w3.org/TR/html5/webappapis.html#queue-a-task">Queue a task</a> to <a href="http://www.w3.org/TR/html5/webappapis.html#fire-a-simple-event">fire a simple event</a> named <code><a href="#dom-eventmessage">message</a></code> at the <var title="true">session</var>.</p>
         <p>The event is of type <code><a href="#dom-mediakeymessageevent">MediaKeyMessageEvent</a></code> and has:</p>
         <ul style="list-style-type:none"><li>
-          <code><a href="#dom-message">message</a></code> = the specified <var title="true">request</var><br>
-          <code><a href="#dom-destinationurl">destinationURL</a></code> = the specified <var title="true">destination URL</var>
+          <code><a href="#dom-type">type</a></code> = the specified <var title="true">message type</var><br>
+          <code><a href="#dom-message">message</a></code> = the specified <var title="true">message</var>
         </li></ul>
       </li>
     </ol>
@@ -1342,7 +1333,7 @@
       <li>
 <p>In the <code><a href="#dom-generaterequest">generateRequest()</a></code> algorithm:</p>
         <ul>
-          <li><p>The generated <var title="true">request</var> is a JSON object encoded in UTF-8 as described in <a href="#clear-key-request-format">License Request Format</a>.</p></li>
+          <li><p>The generated <var title="true">message</var> is a JSON object encoded in UTF-8 as described in <a href="#clear-key-request-format">License Request Format</a>.</p></li>
           <li><p>The request is generated by extracting the key IDs from the <var>init data</var>.</p></li>
           <li><p>The "type" member value is the value of the <var title="true">sessionType</var> parameter.</p></li>
         </ul>
@@ -1353,7 +1344,7 @@
 <p>In the <code><a href="#dom-update">update()</a></code> algorithm:</p>
         <ul>
           <li><p>The <var title="true">response</var> parameter is a JWK Set as described in <a href="#clear-key-license-format">License Format</a>.</p></li>
-          <li><p><var>message</var> is considered invalid if it is not a valid JWK Set with at least one valid JWK key of a valid length for the media type.</p></li>
+          <li><p><var>response copy</var> is considered invalid if it is not a valid JWK Set with at least one valid JWK key of a valid length for the media type.</p></li>
         </ul>
       </li>
       <li><p>The <code><a href="#dom-getusablekeyids">getUsableKeyIds()</a></code> method always returns all key IDs that have been provided via <code><a href="#dom-update">update()</a></code>.</p></li>
@@ -1452,14 +1443,7 @@
     </p>
     <p>Implementations should not return active content or passive content that affects program control flow to the application.
     For example, it is not safe to expose URLs or other information that may have come from media data, such as is the case for the Initialization Data passed to <code><a href="#dom-generaterequest">generateRequest()</a></code>.
-    An exception is made for information extracted from a license or other messages from the license server, which is assumed to be trusted by the application.
-    (This requires that the application be responsible for determining the location of the license or the URL of the license server.)
-    For example, a license may include a destination URL to receive renewal requests.
-    </p>
-    <p>Applications should validate any URLs or other "instructions" provided by the user agent (or CDM).
-    Specifically, applications should validate that any <code><a href="#dom-destinationurl">destinationURL</a></code> value represents a trusted and expected origin and path.
-    A restrictive whitelist, possibly using strict patterns, is recommended.
-    Applications should reject URLs that do not have a secure origin (e.g. HTTPS).
+    Applications should determine the URLs to use. The <code><a href="#dom-type">type</a></code> attribute of the <code><a href="#dom-eventmessage">message</a></code> event can be used by the application to select among a set of URLs if applicable.
     </p>
     <p>User Agents are responsible for providing users with a secure way to browse the web. Since User Agents may integrate with third party CDM implementations, CDM implementers must provide sufficient information and controls to user agent implementers to enable them to properly asses the security implications of integrating with the Key System.</p>
     <p>Note: Unsandboxed CDMs (or CDMs that use platform features) and UAs that use them must be especially careful in all areas of security, including parsing of key and media data, etc. due to the potential for compromises to provide access to OS/platform features, interact with or run as root, access drivers, kernel, firmware, hardware, etc., all of which may not be written to be robust against hostile software or web-based attacks. Additionally, CDMs may not be updated with security fixes as frequently, especially when part of the OS, platform or hardware.</p>
@@ -1554,7 +1538,7 @@
     </dl>
 
     <p>While these suggestions prevent trivial use of this feature for user tracking, they do not block it altogether. Within a single domain, a site can continue to track the user during a session, and can then pass all this information to a third party along with any identifying information (names, credit card numbers, addresses) obtained by the site. If a third party cooperates with multiple sites to obtain such information, and if identifiers are not per-origin, then a profile can still be created.</p>
-    <p>It is important to note that identifiers that are non-clearable, non-origin-specific or hardware-bound exceed the tracking impact of existing techniques such as Cookies or session identifiers embedded in URLs.</p>
+    <p>It is important to note that identifiers that are non-clearable, non-origin-specific or hardware-bound exceed the tracking impact of existing techniques such as cookies or session identifiers embedded in URLs.</p>
     <p>Thus, in addition to the various mitigations described above, if a browser supports a mode of operation intended to preserve user anonymity, then User Agent implementers should carefully consider whether access to Key Systems should be disabled in this mode.</p>
 
     <h3 id="privacy-storedinfo">7.2. Information Stored on User Devices</h3>
@@ -1792,6 +1776,7 @@
   var mediaKeys;
 
   // See previous examples for implementations of these functions.
+  // selectKeySystem() additionally sets renewalUrl.
   function selectKeySystem() { ... }
   function handleInitData(event) { ... }
 
@@ -1817,10 +1802,13 @@
     );
   }
 
-  function sendMessage(message, keySession) {
+  function sendMessage(type, message, keySession) {
+    var url = licenseUrl;
+    if (type == "<a href="#dom-licenserenewal">licenserenewal</a>")
+      url = renewalUrl;
     xmlhttp = new XMLHttpRequest();
     xmlhttp.keySession = keySession;
-    xmlhttp.open("POST", licenseUrl);
+    xmlhttp.open("POST", url);
     xmlhttp.onreadystatechange = function() {
       if (xmlhttp.readyState == 4)
         handleMessageResponse(xmlhttp.keySession, xmlhttp.response);
@@ -1829,7 +1817,7 @@
   }
 
   function handleMessage(event) {
-    sendMessage(event.<a href="#dom-message">message</a>, event.target);
+    sendMessage(event.<a href="#dom-type">type</a>, event.<a href="#dom-message">message</a>, event.target);
   }
 
   function handleKeysChange(event) {
--- a/encrypted-media/encrypted-media.xml	Fri Sep 19 09:33:16 2014 -0700
+++ b/encrypted-media/encrypted-media.xml	Fri Sep 19 10:43:04 2014 -0700
@@ -533,7 +533,7 @@
       <li><p>Run the following steps asynchronously:</p>
         <ol>
           <li><p>Let <var title="true">session id</var> be the empty string.</p></li>
-          <li><p>Let <var title="true">request</var> be null.</p></li>
+          <li><p>Let <var title="true">message</var> be null.</p></li>
           <li><p>Let <var title="true">cdm</var> be the CDM loaded during the <a href="#dom-create">initialization</a> of <var title="true">media keys</var>.</p></li>
           <li><p>Use the <var title="true">cdm</var> to execute the following steps:</p>
             <ol>
@@ -552,7 +552,7 @@
               <li><p>Let <var title="true">session id</var> be a unique <a href="#session-id">Session ID</a> string.</p>
                 <p>If <var title="true">session type</var> is "<coderef prefix="sessiontype">persistent</coderef>", the ID must be unique within the the <a href="http://www.w3.org/TR/html5/browsers.html#origin-0">origin</a> of this object's <code><dom4ref name="document">Document</dom4ref></code> over time, including across Documents and browsing sessions.</p>
               </li>
-              <li><p>Let <var title="true">request</var> be a request <span class="non-normative">(e.g. a license request)</span> for the <var title="true">requested session type</var> generated based on the <var>init data</var>, which is interpreted per <var title="true">initDataType</var>.</p>
+              <li><p>Let <var title="true">message</var> be a request <span class="non-normative">(e.g. a license request)</span> for the <var title="true">requested session type</var> generated based on the <var>init data</var>, which is interpreted per <var title="true">initDataType</var>.</p>
                 <p>The <var title="true">cdm</var> must not use any stream-specific data, including <videoanchor name="media-data">media data</videoanchor>, not provided via the <var>init data</var>.</p>
                 <p>The <var title="true">cdm</var> should <em>not</em> store session data, including the session ID, at this point. See <a href="#session-storage">Session Storage and Persistence</a>.</p>
               </li>
@@ -561,7 +561,7 @@
           <li><p>If any of the preceding steps failed, reject <var>promise</var> with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is the appropriate <a href="#error-names">error name</a>.</p></li>
           <li><p>Set the <coderef>sessionId</coderef> attribute to <var title="true">session id</var>.</p></li>
           <li><p>Let this object's <var title="true">callable</var> be true.</p></li>
-          <li><p>Run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">request</var> and <code>null</code>.</p></li>
+          <li><p>Run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing "<coderef>licenserequest</coderef>" and <var title="true">message</var>.</p></li>
           <li><p>Resolve <var>promise</var>.</p></li>
         </ol>
       </li>
@@ -581,8 +581,8 @@
       <li><p>Run the following steps asynchronously:</p>
         <ol>
           <li><p>Let <var title="true">expiration time</var> be <code>NaN</code>.</p></li>
-          <li><p>Let <var title="true">request</var> be null.</p></li>
-          <li><p>Let <var title="true">destination URL</var> be null.</p></li>
+          <li><p>Let <var title="true">message</var> be null.</p></li>
+          <li><p>Let <var title="true">message type</var> be null.</p></li>
           <li><p>Let <var title="true">origin</var> be the <a href="http://www.w3.org/TR/html5/browsers.html#origin-0">origin</a> of this object's <code><dom4ref name="document">Document</dom4ref></code>.</p></li>
           <li><p>Let <var title="true">cdm</var> be the CDM loaded during the <a href="#dom-create">initialization</a> of <var title="true">media keys</var>.</p></li>
           <li><p>Use the <var title="true">cdm</var> to execute the following steps:</p>
@@ -597,8 +597,8 @@
               <li><p>If the <var title="true">session data</var> indicates an expiration time for the session, let <var title="true">expiration time</var> be the expiration time in milliseconds since 01 January 1970 UTC.</p></li>
               <li><p>If the CDM needs to send a message:</p>
                 <ol>
-                  <li><p>Let <var title="true">request</var> be a request generated by the <a href="#cdm">CDM</a> based on the <var title="true">session data</var>.</p></li>
-                  <li><p>If the <var title="true">session data</var> indicates a destination URL for the request, let <var title="true">destination URL</var> be that URL. The URL may be validated and/or normalized.</p></li>
+                  <li><p>Let <var title="true">message</var> be a message generated by the <a href="#cdm">CDM</a> based on the <var title="true">session data</var>.</p></li>
+                  <li><p>Let <var title="true">message type</var> be the appropriate <coderef>MediaKeyMessageType</coderef> for the message.</p></li>
                 </ol>
               </li>
             </ol>
@@ -610,7 +610,7 @@
             <p>The algorithm may also be run later should additional processing be necessary to determine with certainty whether one or more keys is usable.</p>
           </li>
           <li><p>Run the <a href="#algorithms-update-expiration">Update Expiration</a> algorithm on the <var title="true">session</var>, providing <var title="true">expiration time</var>.</p></li>
-          <li><p>If <var title="true">request</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">request</var> and <var title="true">destination URL</var>.</p></li>
+          <li><p>If <var title="true">message</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">message type</var> and <var title="true">message</var>.</p></li>
           <li><p>Resolve <var>promise</var> with <code>true</code>.</p></li>
         </ol>
       </li>
@@ -623,29 +623,29 @@
     <ol>
       <li><p>If this object's <var title="true">callable</var> value is false, return a promise rejected with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is <code><a href="#dfn-InvalidStateError">"InvalidStateError"</a></code>.</p></li>
       <li><p>If <var title="true">response</var> is an empty array, return a promise rejected with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</p></li>
-      <li><p>Let <var>message</var> be a copy of the contents of the <var title="true">response</var> parameter.</p></li>
+      <li><p>Let <var>response copy</var> be a copy of the contents of the <var title="true">response</var> parameter.</p></li>
       <li><p>Let <var>promise</var> be a new promise.</p></li>
       <li><p>Run the following steps asynchronously:</p>
         <ol>
           <li><p>Let <var title="true">cdm</var> be the CDM loaded during the <a href="#dom-create">initialization</a> of the <coderef>MediaKeys</coderef> object that created this object.</p></li>
-          <li><p>Let <var title="true">request</var> be null.</p></li>
-          <li><p>Let <var title="true">destination URL</var> be null.</p></li>
+          <li><p>Let <var title="true">message</var> be null.</p></li>
+          <li><p>Let <var title="true">message type</var> be null.</p></li>
           <li><p>Use the <var title="true">cdm</var> to execute the following steps:</p>
             <ol>
-              <li><p>If the format of <var>message</var> is invalid in any way, reject <var>promise</var> with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</p></li>
-              <li><p>Process <var>message</var>, following the stipulation for the first matching condition from the following list:</p>
+              <li><p>If the format of <var>response copy</var> is invalid in any way, reject <var>promise</var> with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</p></li>
+              <li><p>Process <var>response copy</var>, following the stipulation for the first matching condition from the following list:</p>
                 <dl class="switch">
-                  <dt>If <var title="true">sessionType</var> is "<coderef prefix="sessiontype">temporary</coderef>" and <var>message</var> does not specify that session data, including any license, key(s), or similar session data it contains, should be stored</dt>
-                  <dd>Continue processing <var>message</var>, not storing any session data.</dd>
+                  <dt>If <var title="true">sessionType</var> is "<coderef prefix="sessiontype">temporary</coderef>" and <var>response copy</var> does not specify that session data, including any license, key(s), or similar session data it contains, should be stored</dt>
+                  <dd>Continue processing <var>response copy</var>, not storing any session data.</dd>
                   <dt>If <var title="true">sessionType</var> is "<coderef prefix="sessiontype">persistent</coderef>"</dt>
-                  <dd>Continue processing <var>message</var>, storing the license, key(s), or similar session data contained in <var>message</var> as permitted or instructed by the license.
+                  <dd>Continue processing <var>response copy</var>, storing the license, key(s), or similar session data contained in <var>response copy</var> as permitted or instructed by the license.
                     Such data must be stored such that only the <a href="http://www.w3.org/TR/html5/browsers.html#origin-0">origin</a> of this object's <code><dom4ref name="document">Document</dom4ref></code> can access it.
                   </dd>
                   <dt>Otherwise</dt>
                   <dd>Reject <var>promise</var> with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code>.</dd>
                 </dl>
                 <p>See also <a href="#session-storage">Session Storage and Persistence</a>.</p>
-                <p class="non-normative">Note: When <var>message</var> contains key(s) and/or related data, <var title="true">cdm</var> will likely cache the key and related data indexed by key ID.</p>
+                <p class="non-normative">Note: When <var>response copy</var> contains key(s) and/or related data, <var title="true">cdm</var> will likely cache the key and related data indexed by key ID.</p>
                 <p class="non-normative">Note: The replacement algorithm within a session is <a href="#key-system">Key System</a>-dependent.</p>
                 <p class="non-normative">Note: Keys from different sessions should be cached independently such that closing one session does not affect keys in other sessions, even if they have overlapping key IDs.</p>
                 <p class="non-normative">Note: It is recommended that CDMs support a standard and reasonably high minimum number of keys per <coderef>MediaKeySession</coderef> object, including a standard replacement algorithm, and a standard and reasonably high minimum number of <coderef>MediaKeySession</coderef> objects.
@@ -656,16 +656,16 @@
                 <p>The algorithm may also be run later should additional processing be necessary to determine with certainty whether one or more keys is usable.</p>
               </li>
               <li><p>If the expiration time for the session changed, run the <a href="#algorithms-update-expiration">Update Expiration</a> algorithm on the <var title="true">session</var>, providing the new expiration time.</p></li>
-              <li><p>If another message needs to be sent to the server, execute the following steps:</p>
+              <li><p>If a message needs to be sent to the server, execute the following steps:</p>
                 <ol>
-                  <li><p>Let <var title="true">request</var> be that message.</p></li>
-                  <li><p>If there is a specific destination URL for the message, let <var title="true">destination URL</var> be that URL. The URL may be validated and/or normalized.</p></li>
+                  <li><p>Let <var title="true">message</var> be that message.</p></li>
+                  <li><p>Let <var title="true">message type</var> be the appropriate <coderef>MediaKeyMessageType</coderef> for the message.</p></li>
                 </ol>
               </li>
             </ol>
           </li>
           <li><p>If any of the preceding steps failed, reject <var>promise</var> with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is the appropriate <a href="#error-names">error name</a>.</p></li>
-          <li><p>If <var title="true">request</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">request</var> and <var title="true">destination URL</var>.</p></li>
+          <li><p>If <var title="true">message</var> is not null, run the <a href="#algorithms-queue-message">Queue a "message" Event</a> algorithm on the <var title="true">session</var>, providing <var title="true">message type</var> and <var title="true">message</var>.</p></li>
           <li><p>Resolve <var>promise</var>.</p></li>
         </ol>
       </li>
@@ -770,15 +770,17 @@
 </pre>
 
     <pre class="idl">
+enum <precodedfn>MediaKeyMessageType</precodedfn> { "<precodedfn>licenserequest</precodedfn>", "<precodedfn>licenserenewal</precodedfn>", "<precodedfn>licenserelease</precodedfn>" };
+
 [Constructor(DOMString type, optional <precoderef>MediaKeyMessageEventInit</precoderef> eventInitDict)]
 interface <precodedfn>MediaKeyMessageEvent</precodedfn> : <dom4ref name="event">Event</dom4ref> {
+  readonly attribute <precoderef>MediaKeyMessageType</precoderef> <precoderef>type</precoderef>;
   readonly attribute ArrayBuffer <precoderef>message</precoderef>;
-  readonly attribute DOMString? <precoderef>destinationURL</precoderef>;
 };
 
 dictionary <precodedfn>MediaKeyMessageEventInit</precodedfn> : <dom4ref name="eventinit">EventInit</dom4ref> {
+  <precoderef>MediaKeyMessageType</precoderef> <precoderef>type</precoderef> = "<precoderef>licenserequest</precoderef>";
   ArrayBuffer <precoderef>message</precoderef> = ArrayBuffer();
-  DOMString? <precoderef>destinationURL</precoderef> = null;
 };
 </pre>
 
@@ -791,25 +793,20 @@
      <dd>
        <p>Returns the <a href="#initialization-data">Initialization Data</a> related to the event.</p>
      </dd>
+     <dt><var title="">event</var> . <coderef>type</coderef></dt>
+     <dd>
+       <p>Returns the type of the message.</p>
+     </dd>
      <dt><var title="">event</var> . <coderef>message</coderef></dt>
      <dd>
        <p>Returns the message <span class="non-normative">(i.e. license request)</span> to send.</p>
      </dd>
-     <dt><var title="">event</var> . <coderef>destinationURL</coderef></dt>
-     <dd>
-       <p>Returns the URL to which the <coderef>message</coderef> should be sent.</p>
-     </dd>
     </dl>
     <div class="impl">
     <p>The <codedfn>initDataType</codedfn> attribute contains a string indicating the <a href="#initialization-data-type">initialization data type</a> specific to the event. The format of the <coderef>initData</coderef> will vary according to the <coderef>initDataType</coderef>.</p>
     <p>The <codedfn>initData</codedfn> attribute contains <a href="#initialization-data">Initialization Data</a> specific to the event.</p>
-    <p>The <codedfn>message</codedfn> attribute contains a message from the CDM. Messages are Key System-specific. <span class="non-normative">In most cases, it should be sent to a key server.</span></p>
-    <p>The <codedfn>destinationURL</codedfn> is the URL to which the <coderef>message</coderef> should be sent.
-       It may be null.
-       An application <em>may</em> choose not to send the message to this URL.
-       Implementations may validate and/or normalize the URL, which could result in a value that is different from the original or null. Applications should not assume that the value of this attribute will be identical across implementations.
-    </p>
-    <div class="issue"><div class="issue-title"><span>Issue 3</span></div><p class=""><a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=26683">Bug 26683</a> - destinationURL may be removed.</p></div>
+    <p>The <codedfn>type</codedfn> is the type of the message.</p>
+    <p>The <codedfn>message</codedfn> attribute contains a message from the CDM. Messages are Key System-specific.</p>
     <p>Events are constructed as defined in <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#constructing-events">Constructing events</a>, in [DOM4].</p>
     </div>
 
@@ -853,15 +850,12 @@
         <tr>
           <td><codedfn prefix="event">keyschange</codedfn></td>
           <td><code><dom4ref name="event">Event</dom4ref></code></td>
-          <td>There has been a change in usable keys.</td>
+          <td>There has been a change in usable keys in the session.</td>
         </tr>
         <tr>
           <td><codedfn prefix="event">message</codedfn></td>
           <td><coderef>MediaKeyMessageEvent</coderef></td>
-          <td>
-            A message has been generated <span class="non-normative">(and likely needs to be sent to a server)</span>.
-            <span class="non-normative">For example, a license request has been generated as the result of a <methodref>generateRequest</methodref> call or another message must be sent in response to an <methodref>update</methodref> call.</span>
-          </td>
+          <td>The CDM has generated a message for the session.</td>
         </tr>
       </tbody>
     </table>
@@ -870,7 +864,7 @@
 
     <h4 id="algorithms-queue-message">3.5.1. Queue a "message" Event</h4>
     <p>The Queue a "message" Event algorithm is run when the CDM needs to queue a message event to a <coderef>MediaKeySession</coderef> object.
-    Requests to run this algorithm include a target <coderef>MediaKeySession</coderef> object, a <var title="true">request</var>, and a <var title="true">destination URL</var>.
+    Requests to run this algorithm include a target <coderef>MediaKeySession</coderef> object, a <var title="true">message type</var>, and a <var title="true">message</var>.
     </p>
     <p>The following steps are run:</p>
     <ol>
@@ -879,8 +873,8 @@
         <p><Queue-a-task/> to <fire-a-simple-event/> named <coderef prefix="event">message</coderef> at the <var title="true">session</var>.</p>
         <p>The event is of type <coderef>MediaKeyMessageEvent</coderef> and has:</p>
         <ul style="list-style-type:none"><li>
-          <coderef>message</coderef> = the specified <var title="true">request</var><br></br>
-          <coderef>destinationURL</coderef> = the specified <var title="true">destination URL</var>
+          <coderef>type</coderef> = the specified <var title="true">message type</var><br></br>
+          <coderef>message</coderef> = the specified <var title="true">message</var>
         </li></ul>
       </li>
     </ol>
@@ -1267,7 +1261,7 @@
     <ul>
       <li><p>In the <methodref>generateRequest</methodref> algorithm:</p>
         <ul>
-          <li><p>The generated <var title="true">request</var> is a JSON object encoded in UTF-8 as described in <a href="#clear-key-request-format">License Request Format</a>.</p></li>
+          <li><p>The generated <var title="true">message</var> is a JSON object encoded in UTF-8 as described in <a href="#clear-key-request-format">License Request Format</a>.</p></li>
           <li><p>The request is generated by extracting the key IDs from the <var>init data</var>.</p></li>
           <li><p>The "type" member value is the value of the <var title="true">sessionType</var> parameter.</p></li>
         </ul>
@@ -1277,7 +1271,7 @@
       <li><p>In the <methodref>update</methodref> algorithm:</p>
         <ul>
           <li><p>The <var title="true">response</var> parameter is a JWK Set as described in <a href="#clear-key-license-format">License Format</a>.</p></li>
-          <li><p><var>message</var> is considered invalid if it is not a valid JWK Set with at least one valid JWK key of a valid length for the media type.</p></li>
+          <li><p><var>response copy</var> is considered invalid if it is not a valid JWK Set with at least one valid JWK key of a valid length for the media type.</p></li>
         </ul>
       </li>
       <li><p>The <methodref>getUsableKeyIds</methodref> method always returns all key IDs that have been provided via <methodref>update</methodref>.</p></li>
@@ -1375,14 +1369,7 @@
     </p>
     <p>Implementations should not return active content or passive content that affects program control flow to the application.
     For example, it is not safe to expose URLs or other information that may have come from media data, such as is the case for the Initialization Data passed to <methodref>generateRequest</methodref>.
-    An exception is made for information extracted from a license or other messages from the license server, which is assumed to be trusted by the application.
-    (This requires that the application be responsible for determining the location of the license or the URL of the license server.)
-    For example, a license may include a destination URL to receive renewal requests.
-    </p>
-    <p>Applications should validate any URLs or other "instructions" provided by the user agent (or CDM).
-    Specifically, applications should validate that any <coderef>destinationURL</coderef> value represents a trusted and expected origin and path.
-    A restrictive whitelist, possibly using strict patterns, is recommended.
-    Applications should reject URLs that do not have a secure origin (e.g. HTTPS).
+    Applications should determine the URLs to use. The <coderef>type</coderef> attribute of the <coderef prefix="event">message</coderef> event can be used by the application to select among a set of URLs if applicable.
     </p>
     <p>User Agents are responsible for providing users with a secure way to browse the web. Since User Agents may integrate with third party CDM implementations, CDM implementers must provide sufficient information and controls to user agent implementers to enable them to properly asses the security implications of integrating with the Key System.</p>
     <p>Note: Unsandboxed CDMs (or CDMs that use platform features) and UAs that use them must be especially careful in all areas of security, including parsing of key and media data, etc. due to the potential for compromises to provide access to OS/platform features, interact with or run as root, access drivers, kernel, firmware, hardware, etc., all of which may not be written to be robust against hostile software or web-based attacks. Additionally, CDMs may not be updated with security fixes as frequently, especially when part of the OS, platform or hardware.</p>
@@ -1477,7 +1464,7 @@
     </dl>
 
     <p>While these suggestions prevent trivial use of this feature for user tracking, they do not block it altogether. Within a single domain, a site can continue to track the user during a session, and can then pass all this information to a third party along with any identifying information (names, credit card numbers, addresses) obtained by the site. If a third party cooperates with multiple sites to obtain such information, and if identifiers are not per-origin, then a profile can still be created.</p>
-    <p>It is important to note that identifiers that are non-clearable, non-origin-specific or hardware-bound exceed the tracking impact of existing techniques such as Cookies or session identifiers embedded in URLs.</p>
+    <p>It is important to note that identifiers that are non-clearable, non-origin-specific or hardware-bound exceed the tracking impact of existing techniques such as cookies or session identifiers embedded in URLs.</p>
     <p>Thus, in addition to the various mitigations described above, if a browser supports a mode of operation intended to preserve user anonymity, then User Agent implementers should carefully consider whether access to Key Systems should be disabled in this mode.</p>
 
     <h3 id="privacy-storedinfo">7.2. Information Stored on User Devices</h3>
@@ -1715,6 +1702,7 @@
   var mediaKeys;
 
   // See previous examples for implementations of these functions.
+  // selectKeySystem() additionally sets renewalUrl.
   function selectKeySystem() { ... }
   function handleInitData(event) { ... }
 
@@ -1740,10 +1728,13 @@
     );
   }
 
-  function sendMessage(message, keySession) {
+  function sendMessage(type, message, keySession) {
+    var url = licenseUrl;
+    if (type == "<precoderef>licenserenewal</precoderef>")
+      url = renewalUrl;
     xmlhttp = new XMLHttpRequest();
     xmlhttp.keySession = keySession;
-    xmlhttp.open("POST", licenseUrl);
+    xmlhttp.open("POST", url);
     xmlhttp.onreadystatechange = function() {
       if (xmlhttp.readyState == 4)
         handleMessageResponse(xmlhttp.keySession, xmlhttp.response);
@@ -1752,7 +1743,7 @@
   }
 
   function handleMessage(event) {
-    sendMessage(event.<precoderef>message</precoderef>, event.target);
+    sendMessage(event.<precoderef>type</precoderef>, event.<precoderef>message</precoderef>, event.target);
   }
 
   function handleKeysChange(event) {