9 通信

【この訳に固有の表記規約】

この訳の,~algoや定義の記述に利用されている各種記号( ~LET, 此れ, ~IF, ~THROW, 等々)の意味や定義の詳細は、~SYMBOL_DEF_REFを~~参照されたし。

9.1. `MessageEvent$I ~interface

`~server-sent~event$における~message, ~web-socket, `文書間~messaging$, `~channel~messaging$, `~broadcast~channel$ では、各 `message$et ~eventに `MessageEvent$I ~interfaceを利用する: ◎ Messages in server-sent events, Web sockets, cross-document messaging, channel messaging, and broadcast channels use the MessageEvent interface for their message events:

[Constructor(DOMString type, optional `MessageEventInit$I eventInitDict), Exposed=(Window,Worker)]
interface `MessageEvent@I : `Event$I {
  readonly attribute any `data$m;
  readonly attribute USVString `origin$m;
  readonly attribute DOMString `lastEventId$m;
  readonly attribute `MessageEventSource$I? `source$m;
  readonly attribute FrozenArray<`MessagePort$I> `ports$m;

 void `initMessageEvent$m(DOMString %type, optional boolean %bubbles = false, optional boolean %cancelable = false, optional any %data = null, optional USVString %origin = "", optional DOMString %lastEventId = "", optional `MessageEventSource$I? %source = null, optional sequence<`MessagePort$I> %ports = []);
};

dictionary `MessageEventInit@I : `EventInit$I {
  any data = null;
  USVString origin = "";
  DOMString lastEventId = "";
  `MessageEventSource$I? source = null;
  sequence<`MessagePort$I> ports = [];
};

typedef (`WindowProxy$I or `MessagePort$I or `ServiceWorker$I) `MessageEventSource@I;
%event . `data$m
~messageの~dataを返す。 ◎ Returns the data of the message.
%event . `origin$m
[ `~server-sent~event$ / `文書間~messaging$ ]の下では、~messageの生成元を返す。 ◎ Returns the origin of the message, for server-sent events and cross-document messaging.
%event . `lastEventId$m
`~server-sent~event$の下では、`最後の~event~ID文字列$eSを返す。 ◎ Returns the last event ID string, for server-sent events.
%event . `source$m
`文書間~messaging$の下では、~source~window `送信-元~window^tnote の `WindowProxy$I を返す。 `SharedWorkerGlobalScope$I ~objに向けて発火された `connect$et ~eventにおいては、添付されている `MessagePort$Iを返す。 ◎ Returns the WindowProxy of the source window, for cross-document messaging, and the MessagePort being attached, in the connect event fired at SharedWorkerGlobalScope objects.
%event . `ports$m
[ `文書間~messaging$ / `~channel~messaging$ ]の下では、~messageに伴われて送信された `MessagePort$I 配列を返す。 ◎ Returns the MessagePort array sent with the message, for cross-document messaging and channel messaging.
`data@m
取得子は、初期化-時の値を返さ~MUST。 送信されてきた~messageを表現する。 ◎ The data attribute must return the value it was initialized to. It represents the message being sent.
`origin@m
取得子は、初期化-時の値を返さ~MUST。 これは、[ `~server-sent~event$ / `文書間~messaging$ ]の下では、~messageを送信した文書の`生成元$を表現する(概して 当の文書の[ ~scheme, ~hostname, ~port ]からなるなるが、その[ ~path/`素片$url ]は含まない )。 ◎ The origin attribute must return the value it was initialized to. It represents, in server-sent events and cross-document messaging, the origin of the document that sent the message (typically the scheme, hostname, and port of the document, but not its path or fragment).
`lastEventId@m
取得子は、初期化-時の値を返さ~MUST。 これは、`~server-sent~event$の下では、 `EventSource$I ~objの`最後の~event~ID文字列$eSを表現する。 ◎ The lastEventId attribute must return the value it was initialized to. It represents, in server-sent events, the last event ID string of the event source.
`source@m
取得子は、初期化-時の値を返さ~MUST。 これは、`文書間~messaging$の下では、~messageを送ってきた `Window$I ~objの`閲覧文脈$の `WindowProxy$I を表現する。 `共用~worker内$で利用される `connect$et ~eventにおいては、新たに接続している `MessagePort$I になる。 ◎ The source attribute must return the value it was initialized to. It represents, in cross-document messaging, the WindowProxy of the browsing context of the Window object from which the message came; and in the connect events used by shared workers, the newly connecting MessagePort.
`ports@m
取得子は、初期化-時の値を返さ~MUST。 これは、[ `文書間~messaging$ / `~channel~messaging$ ]の下では、~messageに伴って送信される `MessagePort$I 配列を表現する。 ◎ The ports attribute must return the value it was initialized to. It represents, in cross-document messaging and channel messaging, the MessagePort array being sent.
`initMessageEvent()@m
被呼出時には、似た命名の `initEvent()$m ~methodに相似的な方式で~eventを初期化し~MUST。 `DOM$r ◎ The initMessageEvent() method must initialize the event in a manner analogous to the similarly-named initEvent() method. [DOM]

注記: 種々の~API(例: `WebSocket$I や `EventSource$I )は、 `MessagePort$I ~APIを利用せずに, `MessageEvent$I ~interfaceを `message$et ~eventに利用する。 ◎ Various APIs (e.g., WebSocket, EventSource) use the MessageEvent interface for their message event without using the MessagePort API.

9.2. ~server-sent~event

9.2.1. 序論

~INFORMATIVE

~serverが~Web頁に向けて,~HTTPを通じて, あるいは 専用の[ “server-push” ~protocol ]を利用して ~dataを~pushできるようにするため、この仕様は `EventSource$I ~interfaceを導入する。 ◎ To enable servers to push data to Web pages over HTTP or using dedicated server-push protocols, this specification introduces the EventSource interface.

この~APIの用法は、 `EventSource$I ~objを作成して,~event~listenerを登録するだけである。 ◎ Using this API consists of creating an EventSource object and registering an event listener.

var %source = new EventSource('updates.cgi');
%source.onmessage = function (%event) {
  alert(%event.data);
};

~server側の~script(この事例では `updates.cgi^l )は、~MIME型に `text/event-stream$c を伴う~messageを,次の形で送信する: ◎ On the server-side, the script ("updates.cgi" in this case) sends messages in the following form, with the text/event-stream MIME type:

data: 第一~message

data: 第二~message
data: この~messageは 2 行0からなる

data: 第三~message

【 各~messageは、空行(言い換えれば,連続する 2 個以上の改行( `end-of-line$P ))で終端する。 】【 このページの各~stream例は、特に断らない限り,暗黙的に空行で終端されている。 】


作者は、異なる~event型を利用することにより,各~eventを~~分類できる。 ここに 2 種の~event型, `add^l, `remove^l が含まれた~streamがあるとする: ◎ Authors can separate events by using different event types. Here is a stream that has two event types, "add" and "remove":

event: add
data: 73857293

event: remove
data: 2153

event: add
data: 113411

そのような~streamを取扱う~scriptは、次の様になるであろう( %addHandler, %removeHandler は、 1 個の~event引数をとる関数とする): ◎ The script to handle such a stream would look like this (where addHandler and removeHandler are functions that take one argument, the event):

var %source = new EventSource('updates.cgi');
source.addEventListener('add', %addHandler, false);
source.addEventListener('remove', %removeHandler, false);

既定の~event型は `message^l である。 `すなわち、最初の例のように "event:" 行0が省略されている場合^tnote ◎ The default event type is "message".

~event~streamは、常に~UTF-8として復号される。 別の文字~符号化方式を指定する仕方はない。 ◎ Event streams are always decoded as UTF-8. There is no way to specify another character encoding.


~event~stream要請は、通常の~HTTP要請と同様に,~HTTP `301^st/ `307^st 応答~codeにより~redirectされ得る(できる)。 接続が~closeされた場合、~clientは 再接続することになる。 ~serverは、~HTTP `204^st "No Content" 応答~codeを用いて,~clientにこの再接続を停止するよう伝えれる。 ◎ Event stream requests can be redirected using HTTP 301 and 307 redirects as with normal HTTP requests. Clients will reconnect if the connection is closed; a client can be told to stop reconnecting using the HTTP 204 No Content response code.

この~APIを用いれば — `XMLHttpRequest$I や `iframe$e を用いてそれを模倣せずに — ~UAは、~UAの実装者と~network運用者が より高度に協調できる事例においては,~network資源をより良く利用できるようになる。 これには、携帯機の~battery~~寿命を有意に節約できる便益もある — それについては、`無接続~push$節にて更に論じられる。 ◎ Using this API rather than emulating it using XMLHttpRequest or an iframe allows the user agent to make better use of network resources in cases where the user agent implementor and the network operator are able to coordinate in advance. Amongst other benefits, this can result in significant savings in battery life on portable devices. This is discussed further in the section below on connectionless push.

9.2.2. ``EventSource^I ~interface

[``Constructor$m(USVString %url, optional `EventSourceInit$I %eventSourceInitDict), Exposed=(Window,Worker)]
interface `EventSource@I : `EventTarget$I {
  readonly attribute USVString ``url$m;
  readonly attribute boolean ``withCredentials$m;

  // ready state
  const unsigned short ``CONNECTING$m = 0;
  const unsigned short ``OPEN$m = 1;
  const unsigned short ``CLOSED$m = 2;
  readonly attribute unsigned short ``readyState$m;

  // networking
  attribute `EventHandler$I ``onopen$m;
  attribute `EventHandler$I ``onmessage$m;
  attribute `EventHandler$I ``onerror$m;
  void ``close$m();
};

dictionary `EventSourceInit@I {
  boolean `withCredentials@m = false;
};

各 `EventSource$I ~objには、次のものが結付けられる: ◎ Each EventSource object has the following associated with it:

`~url@eS
`~URL~record$。 構築-時に設定される。 ◎ A url (a URL record). Set during construction.
`要請@eS
初期~時には ~NULL にされ~MUST。 ◎ A request. This must initially be null.
【 これもまた、構築-時に`要請$に設定される。 】
`再接続~時間@eS
~milli秒単位。 初期~時には ~UAにより定義される値 — おそらく,数秒を超えない~~範囲 — にされ~MUST。 ◎ A reconnection time, in milliseconds. This must initially be a user-agent-defined value, probably in the region of a few seconds.
`最後の~event~ID文字列@eS
初期~時には空~文字列にされ~MUST。 ◎ A last event ID string. This must initially be the empty string.

`~url$eS を除き,これらは、現時点では `EventSource$I ~objに公開されていない。 ◎ Apart from url these are not currently exposed on the EventSource object.

`EventSource(url, eventSourceInitDict)@m

この構築子の被呼出時には、次を走らせ~MUST: ◎ The EventSource(url, eventSourceInitDict) constructor, when invoked, must run these steps:

  1. %event ~LET 新たな `EventSource$I ~obj ◎ Let ev be a new EventSource object.
  2. %設定群 ~LET %event に`関連する設定群~obj$ ◎ Let settings be ev's relevant settings object.
  3. %~url~record ~LET 次を与える下で, %~url を`~URL構文解析器$にかけた結果 ⇒ ( %設定群 の`~API基底~URL$, %設定群 の`~API~URL文字~符号化方式$ ) ◎ Let urlRecord be the result of parsing url with settings's API base URL and settings's API URL character encoding.
  4. ~IF[ %~url~record ~EQ 失敗 ] ⇒ ~THROW `SyntaxError$E ◎ If urlRecord is failure, then throw a "SyntaxError" DOMException.
  5. %event の`~url$eS ~SET %~url~record ◎ Set ev's url to urlRecord.
  6. %~CORS属性~状態 ~LET `Anonymous$st ◎ Let corsAttributeState be Anonymous.
  7. ~IF[ %evententSourceInitDict の `withCredentials$m ~memberの値 ~EQ ~T ] ⇒ %~CORS属性~状態 ~SET `Use Credentials$st;
    %event の ``withCredentials$m 属性 ~SET ~T ◎ If the value of eventSourceInitDict's withCredentials member is true, then set corsAttributeState to Use Credentials and set ev's withCredentials attribute to true.
  8. %要請 ~LET 次を与える下で,`~CORSになり得る要請を作成-$した結果 ⇒ ( %~url~record, 空~文字列, %~CORS属性~状態, `同一生成元~fallback~flag^i ~ON ) ◎ Let request be the result of creating a potential-CORS request given urlRecord, the empty string, and corsAttributeState, and with the same-origin fallback flag set.
  9. %要請 の`~client$rq ~SET %設定群 ◎ Set request's client to settings.
  10. ~UAの任意選択で ⇒ %要請 の`~header~list$rq内で ( `Accept$h / `text/event-stream$bl ) を`設定-$hLする ◎ User agents may set `Accept`/`text/event-stream` in request's header list.
  11. %要請 の`~cache~mode$rq ~SET `no-store^l ◎ Set request's cache mode to "no-store".
  12. %event の`要請$eS ~SET %要請 ◎ Set ev's request to request.
  13. ~RET %event — ただし、以降の手続きは`並列的$に継続する ◎ Return ev, but continue these steps in parallel.
  14. %要請 を`~fetch$する ◎ Fetch request.
``url@m
取得子は、此れの`~url$eSを`~URL直列化器$にかけた結果を返さ~MUST。 ◎ The url attribute's getter must return the serialization of this EventSource object's url.
``withCredentials@m
取得子は、最後に初期化された値を返さ~MUST。 此れの作成-時には、 ~F に初期化され~MUST。 ◎ The withCredentials attribute must return the value to which it was last initialized. When the object is created, it must be initialized to false.
``readyState@m

この属性は、当の接続の状態を表現する。 次のいずれかの値をとり得る: ◎ The readyState attribute represents the state of the connection. It can have the following values:

``CONNECTING@m (数値 0 )
接続は、まだ確立されていないか,または ~closeされていて~UAは再接続している。 ◎ The connection has not yet been established, or it was closed and the user agent is reconnecting.
``OPEN@m (数値 1 )
~UAは,~open接続を有していて、~eventが受信され次第 それを配送している。 ◎ The user agent has an open connection and is dispatching events as it receives them.
``CLOSED@m (数値 2 )
接続は~openしておらず,~UAは再接続しようと試行していない。 何らかの致命的~errorがあったか, ``close()$m ~methodが呼出された。 ◎ The connection is not open, and the user agent is not trying to reconnect. Either there was a fatal error or the close() method was invoked.
此れの作成-時には、その ``readyState$m は ``CONNECTING$m ( 0 )に設定され~MUST。 値がいつ変化するかは、下に与える,接続を取扱うための規則にて定義される。 ◎ When the object is created its readyState must be set to CONNECTING (0). The rules given below for handling the connection define when the value changes.
``close()@m
被呼出時には、此れのために開始された`~fetch$ ~algoがあれば すべて中止した上で、 此れの ``readyState$m 属性を ``CLOSED$m に設定し~MUST。 ◎ The close() method must abort any instances of the fetch algorithm started for this EventSource object, and must set the readyState attribute to CLOSED.

`EventSource$I ~interfaceを実装している~すべての~objは、以下に挙げる各種`~event~handler$, および対応する各種`~event~handler~event型$を,`~event~handler~IDL属性$として~supportし~MUST: ◎ The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the EventSource interface:

`~event~handler$ `~event~handler~event型$
``onopen@m `open$et
``onmessage@m `message$et
``onerror@m `error$et

9.2.3. 処理~model

`EventSource()$m 構築子の引数にて指示される資源は、その構築子が走るときに~fetchされる。 ◎ The resource indicated in the argument to the EventSource constructor is fetched when the constructor is run.

~dataが受信されるに伴い,それを取扱うために `~network用~task源$により待入される`~task$は、以下に従って動作し~MUST: ◎ As data is received, the tasks queued by the networking task source to handle the data must act as follows.

~HTTP `200^st "OK" 応答に対しては、 `Content-Type$h ~header値は 型 `text/event-stream$bl を指定している — `~MIME型$ ~parameterは無視して — ならば, ~event~streamの解釈-法 に従って 行0ごとに処理され~MUST。 ◎ HTTP 200 OK responses with a `Content-Type` header specifying the type `text/event-stream`, ignoring any MIME type parameters, must be processed line by line as described below.

~UAは、自身が~supportする`~MIME型$を伴う応答が成功裡に受信されたときは、~streamの内容を構文解析し始めるときに,`接続を公告-$し~MUST。 ◎ When a successful response with a supported MIME type is received, such that the user agent begins parsing the contents of the stream, the user agent must announce the connection.

`~network用~task源$から`~task待行列$に設置した`~task$が,そのような(正しい`~MIME型$を伴う)資源に対する~fetchingを完了したなら、~UAは,`並列的$に`接続を再確立-$し~MUST。 これは、接続が上品に~closeされようが 予期せず~closeされようが,適用される(が、~UAが ~fetchingを取消したとき(例えば `window.stop()$m に呼応して)には適用されない — そのような事例では `~task$は最終的に実際に破棄されるので)。 ただし、下に挙げる~error条態に対しては、明示的に指定されない限り,適用されない。 ◎ The task that the networking task source places on the task queue once fetching for such a resource (with the correct MIME type) has completed must cause the user agent to reestablish the connection in parallel. This applies whether the connection is closed gracefully or unexpectedly (but does not apply when fetching is canceled by the user agent, e.g., in response to window.stop(), since in those cases the final task is actually discarded). It doesn't apply for the error conditions listed below except where explicitly specified.

~HTTP `200^st "OK" 応答に対しては、応答の `Content-Type$h が[ 伴われていない / 未~supportの型を指定している ]場合、~UAは`接続を失敗させ$~MUST。 ◎ HTTP 200 OK responses that have a Content-Type specifying an unsupported type, or that have no Content-Type at all, must cause the user agent to fail the connection.

最初の~~段階で接続を確立できなくするような,~network~error(例: ~DNS~error)に対しては、~UAは`並列的$に`接続を再確立-$するべきである — ただし,~UAは、そうしても無益なことを知っている場合は,`接続を失敗させ$てよい。 ◎ Network errors that prevents the connection from being established in the first place (e.g. DNS errors), should cause the user agent to reestablish the connection in parallel, unless the user agent knows that to be futile, in which case the user agent may fail the connection.

ここに挙げなかった他の~HTTP応答~codeに対しては, および ~UAが~fetch~algoを取消した場合は(例えば `window.stop()$m に呼応して, あるいは 利用者が~network接続を手動で取消した)、~UAは`接続を失敗させ$~MUST。 ◎ Any other HTTP response code not listed here, as well as the cancelation of the fetch algorithm by the user agent (e.g. in response to window.stop() or the user canceling the network connection manually) must cause the user agent to fail the connection.


~UAは, `接続を公告-@ するときは、次を走らす`~taskを待入し$~MUST:

  1. %O ~LET 当の `EventSource$I ~obj
  2. ~IF[ %O の ``readyState$m 属性~値 ~EQ ``CLOSED$m ] ⇒ ~RET
  3. %O の ``readyState$m 属性 ~SET ``OPEN$m
  4. %O に向けて,名前 `open$et の`~eventを発火-$する
◎ When a user agent is to announce the connection, the user agent must queue a task which, if the readyState attribute is set to a value other than CLOSED, sets the readyState attribute to OPEN and fires an event named open at the EventSource object.

~UAは、 `接続を再確立-@ するときは、次の手続きを走らせ~MUST: ◎ When a user agent is to reestablish the connection, the user agent must run the following steps. These steps are run in parallel, not as part of a task. (The tasks that it queues, of course, are run like normal tasks and not themselves in parallel.)

  1. ~RET — ただし、以降の手続きは`並列的$に継続する ◎ ↑
  2. %O ~LET 当の `EventSource$I ~obj ◎ ↓
  3. 次の手続きを走らす`~taskを待入する$: ◎ Queue a task to run the following steps:

    1. ~IF[ %O の ``readyState$m 属性 ~NEQ ``CLOSED$m ] ⇒ ~RET ◎ If the readyState attribute is set to CLOSED, abort the task.
    2. %O の ``readyState$m 属性 ~SET ``CONNECTING$m ◎ Set the readyState attribute to CONNECTING.
    3. %O に向けて,名前 `error$et の`~eventを発火-$する ◎ Fire an event named error at the EventSource object.
  4. %O の`再接続~時間$eSだけ待機する ◎ Wait a delay equal to the reconnection time of the event source.
  5. ~UAの任意選択で ⇒ 更にいくばくか待機する。 特に、前回の試みが失敗した場合,~serverはすでに過負荷にあるかもしれないので、~UAは ベキ乗打ち切り待機法( exponential backoff )による遅延を導入することもできる。 あるいは,~OSから~network接続できないと報告された場合には、~OSから その~~回復が公告されるまで待機する。 ◎ Optionally, wait some more. In particular, if the previous attempt failed, then user agents might introduce an exponential backoff delay to avoid overloading a potentially already overloaded server. Alternatively, if the operating system has reported that there is no network connectivity, user agents might wait for the operating system to announce that the network connection has returned before retrying.
  6. 上で待入した~taskがまだ走っていないならば,走るまで待機する ◎ Wait until the aforementioned task has run, if it has not yet run.
  7. 次の手続きを走らす`~taskを待入する$: ◎ Queue a task to run the following steps:

    1. ~IF[ %O の ``readyState$m 属性 ~NEQ ``CONNECTING$m ] ⇒ ~RET ◎ If the EventSource object's readyState attribute is not set to CONNECTING, abort these steps.
    2. %要請 ~LET %O の`要請$eS ◎ Let request be the EventSource object's request.
    3. ~IF[ %O の`最後の~event~ID文字列$eS ~NEQ 空~文字列 ] ⇒ %要請 の`~header~list$rq内で ( `Last-Event-ID$h / `最後の~event~ID文字列$eS を~UTF-8に符号化した結果 ) を`設定-$hLする ◎ If the EventSource object's last event ID string is not the empty string, set `Last-Event-ID`/last event ID string, encoded as UTF-8, in request's header list.
    4. %要請 を`~fetch$する ⇒ この~fetchに対する応答は、この節の最初あたりで述べたように処理する ◎ Fetch request and process the response obtained in this fashion, if any, as described earlier in this section.

~UAは, `接続を失敗させ@ るときは、次を走らす`~taskを待入し$~MUST:

  1. %O ~LET 当の `EventSource$I ~obj ◎ ↓
  2. ~IF[ %O の ``readyState$m 属性 ~EQ ``CLOSED$m ] ⇒ ~RET
  3. %O の ``readyState$m 属性 ~SET ``CLOSED$m
  4. %O に向けて,名前 `error$et の`~eventを発火-$する

~UAは、`接続を失敗させ$たときは,再接続しようと 試みないこと

◎ When a user agent is to fail the connection, the user agent must queue a task which, if the readyState attribute is set to a value other than CLOSED, sets the readyState attribute to CLOSED and fires an event named error at the EventSource object. Once the user agent has failed the connection, it does not attempt to reconnect!

`EventSource$I ~objにより`待入され$るどの`~task$に対しても,その`~task源$は `~remote~event~task源@ とする。 ◎ The task source for any tasks that are queued by EventSource objects is the remote event task source.

9.2.4. ~event~streamの構文解析

この~event~stream形式の`~MIME型$は、 `text/event-stream$c である。 ◎ This event stream format's MIME type is text/event-stream.

~event~stream形式は、次の `ABNF$r における `stream$P 生成規則で与えられる — この~ABNFの文字~集合は~Unicodeとする: ◎ The event stream format is as described by the stream production of the following ABNF, the character set for which is Unicode. [ABNF]

`stream@P        = [ `bom$P ] *`event$P
`event@P         = *( `comment$P / `field$P ) `end-of-line$P
`comment@P       = `colon$P *`any-char$P `end-of-line$P
`field@P         = 1*`name-char$P [ `colon$P [ `space$P ] *`any-char$P ] `end-of-line$P
`end-of-line@P   = ( `cr$P `lf$P / `cr$P / `lf$P )

; 各種~文字
`lf@P            = `000A^0x ; U+000A LINE FEED (LF)
`cr@P            = `000D^0x ; U+000D CARRIAGE RETURN (CR)
`space@P         = `0020^0x ; U+0020 SPACE
`colon@P         = `003A^0x ; U+003A COLON (:)
`bom@P           = `FEFF^0x ; U+FEFF BYTE ORDER MARK
`name-char@P     = `0000-0009^0x / `000B-000C^0x / `000E-0039^0x / `003B-10FFFF^0x
                ; 
`lf$P, `cr$P, `colon$P 以外の`~Unicode文字$
◎
; a Unicode character other than U+000A LINE FEED (LF), U+000D CARRIAGE RETURN (CR), or U+003A COLON (:)

`any-char@P      = `0000-0009^0x / `000B-000C^0x / `000E-10FFFF^0x
                ; 
`lf$P, `cr$P 以外の`~Unicode文字$
◎
; a Unicode character other than U+000A LINE FEED (LF) 

この形式による~event~streamは、常に ~UTF-8に符号化され~MUST。 `ENCODING$r ◎ Event streams in this format must always be encoded as UTF-8. [ENCODING]

各 行0どうしは、 `end-of-line$P( `cr$P +`lf$P, `lf$P, `cr$P のいずれか)で分離され~MUST。 ◎ Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, a single U+000A LINE FEED (LF) character, or a single U+000D CARRIAGE RETURN (CR) character.

そのような資源のために確立された~remote~serverへの接続は,長く生き残るものと予期されるので、~UAは 適切な~bufferingが利用されることを確保するべきである。 特に,各 行0が 1 個の `lf$P で終端するように定義される~bufferingは安全である一方で、~block~bufferingや, 異なる行0終端-法を期待する行0~bufferingは,~event配送-を遅延させ得る。 ◎ Since connections established to remote servers for such resources are expected to be long-lived, UAs should ensure that appropriate buffering is used. In particular, while line buffering with lines are defined to end with a single U+000A LINE FEED (LF) character is safe, block buffering or line buffering with different expected line endings can cause delays in event dispatch.

9.2.5. ~event~streamの解釈-法

~streamは、`~UTF-8復号-$~algoで復号され~MUST。 ◎ Streams must be decoded using the UTF-8 decode algorithm.

注記: `~UTF-8復号-$~algoは、先頭に~UTF-8 Byte Order Mark ( `bom$P )があれば それを剥ぎ取る。 ◎ The UTF-8 decode algorithm strips one leading UTF-8 Byte Order Mark (BOM), if any.

~streamは、行0ごとに そこに現れるすべてを読取ることにより,構文解析され~MUST。 行0が終端するのは、次のいずれか( “改行” )が現れる所に限られるとする:

  • `cr$P + `lf$P 文字~pair
  • `cr$P が先行しない 1 個の `lf$P
  • `lf$P が後続しない 1 個の `cr$P
`改行~自身は行0には含まれない。^tnote ◎ The stream must then be parsed by reading everything line by line, with a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, a single U+000A LINE FEED (LF) character not preceded by a U+000D CARRIAGE RETURN (CR) character, and a single U+000D CARRIAGE RETURN (CR) character not followed by a U+000A LINE FEED (LF) character being the ways in which a line can end.

~streamを構文解析する~algoの各~instanceには,変数[ %~data~buffer, %~event型~buffer, %最後の~event~ID~buffer ]が結付けられ、いずれも空~文字列に初期化され~MUST。 ◎ When a stream is parsed, a data buffer, an event type buffer, and a last event ID buffer must be associated with it. They must be initialized to the empty string

それは、~EACH ( 行0 %行0 ) に対し,受信された順序で、次を走らす: ◎ Lines must be processed, in the order they are received, as follows:

  1. ~IF[ %行0 は空である(空行) ] ⇒ 下に定義されるように`~eventを配送-$する ◎ If the line is empty (a blank line) ◎ • Dispatch the event, as defined below.
  2. ~ELIF[ %行0 の先頭の文字 ~EQ `colon$P ] ⇒ ~CONTINUE ◎ If the line starts with a U+003A COLON character (:) ◎ • Ignore the line.
  3. ~IF[ %行0 は `colon$P を包含する ]: ◎ If the line contains a U+003A COLON character (:)

    1. ( %名, %値 ) ~LET %行0 内の最初の `colon$P より ( 前の部分の文字列, 後の部分の文字列 ) ◎ Collect the characters on the line before the first U+003A COLON character (:), and let field be that string. ◎ Collect the characters on the line after the first U+003A COLON character (:), and let value be that string. If value starts with a U+0020 SPACE character, remove it from value.
    2. ~IF[ %値 の先頭の文字 ~EQ `space$P ] ⇒ %値 から先頭の文字を除去する ◎ ↑
    3. ( %名, %値 ) に対し`~fieldを処理する$ ◎ Process the field using the steps described below, using field as the field name and value as the field value.
  4. ~ELSE(文字列は空でないが `colon$P を包含しない) ⇒ ( %行0, 空~文字列 ) に対し`~fieldを処理する$ ◎ Otherwise, the string is not empty but does not contain a U+003A COLON character (:) ◎ Process the field using the steps described below, using the whole line as the field name, and the empty string as the field value.

~streamの終端-に達したときの最後の~blockが,空行で終端されていない場合、その~blockの~dataは破棄され~MUST。 (そのような~blockに対しては、~eventは配送されない。) (~blockとは、空行で互いに分離されていない,一連の行0を意味する。) ◎ Once the end of the file is reached, any pending data must be discarded. (If the file ends in the middle of an event, before the final empty line, the incomplete event is not dispatched.)


`~fieldを処理する@ 手続きは、所与の ( %名, %値 ) に対し %名 に応じて: ◎ The steps to process the field given a field name and a field value depend on the field name, as given in the following list. Field names must be compared literally, with no case folding performed.

`event^l ◎ If the field name is "event"
%~event型~buffer ~SET %値 ◎ Set the event type buffer to field value.
`data^l ◎ If the field name is "data"
[ %値, 1 個の `lf$P ]を,順に %~data~buffer に付加する ◎ Append the field value to the data buffer, then append a single U+000A LINE FEED (LF) character to the data buffer.
`id^l ◎ If the field name is "id"
%最後の~event~ID~buffer ~SET %値 ◎ Set the last event ID buffer to the field value.
`retry^l ◎ If the field name is "retry"

~IF[ %値 は`~ASCII数字$のみからなる ] ⇒ ~event~streamの`再接続~時間$eS ~SET %値 を基数 10 の整数に解釈した結果

(他の場合、この~fieldは無視する。)

◎ If the field value consists of only ASCII digits, then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer. Otherwise, ignore the field.
他の場合 ◎ Otherwise
何もしない(この~fieldは無視する。) ◎ The field is ignored.
`この例は、訳者による補足。^tnote

したがって、次の例の様に,同じ~block内に複数の `event^l 行0が含まれている場合、最後に現れたものが、他を上書きすることになる( `id^l についても同様になる):

event: add
event: remove
data: 1234

対照的に, `data^l 行0は、行0ごとに~data + `lf$P を付加する。 ただし,~block内の最後の `lf$P は除かれる(下に述べる~eventを配送する手続きの中で除去される)。

~UAは、 `~eventを配送-@ するよう要求されたときは、 ( %~data~buffer, %~event型~buffer, %最後の~event~ID~buffer ) を~UAに適切な手続きを用いて処理し~MUST。 ◎ When the user agent is required to dispatch the event, the user agent must process the data buffer, the event type buffer, and the last event ID buffer using steps appropriate for the user agent.

~Web~browserに対しては、`~eventを配送-$する適切な手続きは,次に従うとする: ◎ For Web browsers, the appropriate steps to dispatch the event are as follows:

  1. %O ~LET 当の `EventSource$I ~obj ◎ ↓
  2. %O の`最後の~event~ID文字列$eS ~SET %最後の~event~ID~buffer

    この~bufferは, `他の~bufferと違って ~eventが生じるごとに^tnote 再設定されないので、 %O の`最後の~event~ID文字列$eSは,この~bufferが次回に~serverにより設定されるまで残り続ける。

    ◎ Set the last event ID string of the event source to the value of the last event ID buffer. The buffer does not get reset, so the last event ID string of the event source remains set to this value until the next time it is set by the server.
  3. ~IF[ %~data~buffer ~EQ 空~文字列 ] ⇒ ( %~data~buffer, %~event型~buffer ) ~SET ( 空~文字列, 空~文字列 );
    ~RET ◎ If the data buffer is an empty string, set the data buffer and the event type buffer to the empty string and abort these steps.
  4. ~IF[ %~data~buffer の最後の文字 ~EQ `lf$P ] ⇒ %~data~buffer から最後の文字を除去する ◎ If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer.
  5. %~event ~LET 次を与える下で,`~eventを作成-$した結果 ⇒ ( %O に`関連する~Realm$, `MessageEvent$I ~interface ) ◎ Let event be the result of creating an event using MessageEvent, in the relevant Realm of the EventSource object.
  6. %~event の各種~属性を次のように初期化する:

    • `type$m ~SET `message$et
    • `data$m ~SET %~data
    • `origin$m ~SET 当の~event~streamの最終的な~URL(すなわち~redirect後の~URL)の`生成元$の`~Unicode直列化$
    • `lastEventId$m ~SET %O の`最後の~event~ID文字列$eS
    ◎ Initialize event's type attribute to message, its data attribute to data, its origin attribute to the Unicode serialization of the origin of the event stream's final URL (i.e. the URL after redirects), and its lastEventId attribute to the last event ID string of the event source.
  7. ~IF[ %~event型~buffer ~NEQ 空~文字列 ] ⇒ %~event の `type$m ~SET %~event型~buffer ◎ If the event type buffer has a value other than the empty string, change the type of the newly created event to equal the value of the event type buffer.
  8. ( %~data~buffer, %~event型~buffer ) ~SET ( 空~文字列, 空~文字列 ) ◎ Set the data buffer and the event type buffer to the empty string.
  9. 次を走らす`~taskを待入する$:

    1. ~IF[ %O の ``readyState$m 属性~値 ~NEQ ``CLOSED$m ] ⇒ %O に向けて %~event を`配送-$する
    ◎ Queue a task which, if the readyState attribute is set to a value other than CLOSED, dispatches the newly created event at the EventSource object.

注記: ~event( `event$P )に `id^l ~fieldが伴われていない場合、その~eventから生じる `MessageEvent$I ~event の `lastEventId$m ~fieldは、最後に~~見出された `id^l ~fieldの値 — すなわち,その前の~eventにより設定された`最後の~event~ID文字列$eS 【 `id^l がまだ見出されていなければ,空~文字列( %最後の~event~ID~buffer の初期~値) 】 — に設定されることになる。 ◎ If an event doesn't have an "id" field, but an earlier event did set the event source's last event ID string, then the event's lastEventId field will be set to the value of whatever the last seen "id" field was.

他の~UAに対しては、`~eventを配送-$する適切な手続きは 実装に依存するが、最小限,手続きを終える前に[ %~data~buffer, %~event型~buffer ]を空~文字列に設定し~MUST。 ◎ For other user agents, the appropriate steps to dispatch the event are implementation dependent, but at a minimum they must set the data and event type buffers to the empty string before returning.

次の~event~stream(空行で終端されている)に対しては: ◎ The following event stream, once followed by a blank line:

data: YHOO
data: +2
data: 10

`EventSource$I ~objに向けて, `MessageEvent$I ~interfaceを利用する `message$et ~eventを配送させることになる。 ~eventの `data$m 属性は、文字列 `YHOO\n+2\n10^l を包含することになる( `\n^l は改行文字( `lf$P )を表現する)。 ◎ ...would cause an event message with the interface MessageEvent to be dispatched on the EventSource object. The event's data attribute would contain the string "YHOO\n+2\n10" (where "\n" represents a newline).

これは、次のように利用できる: ◎ This could be used as follows:

var %stocks = new EventSource("https://stocks.example.com/ticker.php");
stocks.onmessage = function (%event) {
  var %data = %event.data.split('\n');
  updateStocks(%data[0], %data[1], %data[2]);
};

( `updateStocks()^c は、~data処理用の何らかの関数。) ◎ ...where updateStocks() is a function defined as: ◎ function updateStocks(symbol, delta, value) { ... } ◎ ...or some such.

次の~streamは、 4 個の~blockを包含する。 1 個目の~blockは、~commentなので,~eventは発火されない。 2 個目の~blockに対しては、~eventが発火されることになる — そこには、名前 `data^l の~field(値に `first event^l を伴う)に加え,名前 `id^l の~fieldもあり、`最後の~event~ID文字列$eS を `1^l に設定することになる。 この~blockと次の~blockの合間で接続が切れた場合、再接続-時に,~serverに向けて値 `1^l を伴う `Last-Event-ID$h ~headerが送信されることになる。 3 個目の~blockも~eventを発火し, `data^l の値に `second event^l を伴うが、 `id^l ~fieldには値は伴われていない — それは、`最後の~event~ID文字列$eS を空~文字列に再設定する(今度は、再接続が試みられる場合には, `Last-Event-ID$h ~headerは送信されないことを意味する)。 最後の 4 個目の~blockは、単に~dataに ` third event^l (先頭の文字は `space$P )を伴わせた~eventを発火する。 最後の~blockであっても,空行で終端させる必要があることに注意 — ~streamが終端するだけでは,最後の~blockに対する~event配送を誘発するには十分でない。 ◎ The following stream contains four blocks. The first block has just a comment, and will fire nothing. The second block has two fields with names "data" and "id" respectively; an event will be fired for this block, with the data "first event", and will then set the last event ID to "1" so that if the connection died between this block and the next, the server would be sent a `Last-Event-ID` header with the value "1". The third block fires an event with data "second event", and also has an "id" field, this time with no value, which resets the last event ID to the empty string (meaning no `Last-Event-ID` header will now be sent in the event of a reconnection being attempted). Finally, the last block just fires an event with the data " third event" (with a single leading space character). Note that the last still has to end with a blank line, the end of the stream is not enough to trigger the dispatch of the last event.

: test stream

data: first event
id: 1

data:second event
id

data:  third event

次の~streamは、最後の~blockは空行で終端されていないならば, 2 個の~eventを発火する: ◎ The following stream fires two events:

data

data
data

data:

1 個目の~blockは、~data が空~文字列にされた~eventを発火する。 2 個目の~blockは、~dataを 1 個の改行文字に設定した上で,~eventを発火する。 3 個目の~blockは、空行が後続していないので,破棄される。 ◎ The first block fires events with the data set to the empty string, as would the last block if it was followed by a blank line. The middle block fires an event with the data set to a single newline character. The last block is discarded because it is not followed by a blank line.

次の~streamは、 2 個の~~等価な~eventを発火する: ◎ The following stream fires two identical events:

data:test

data: test

`colon$P の直後にある 1 個の `space$P は、無視されるので。 ◎ This is because the space after the colon is ignored if present.

9.2.6. 著作~上の注記

旧来の~proxy~serverは、ある種の事例では、短い~timeout後に~HTTP接続を落とすことが知られている。 作者は、およそ毎 15 秒ごとに,~comment行0(`colon$P から開始される行0)を含ませることにより,そのような~proxy~serverに抗して保護できる。 ◎ Legacy proxy servers are known to, in certain cases, drop HTTP connections after a short timeout. To protect against such proxy servers, authors can include a comment line (one starting with a ':' character) every 15 seconds or so.

~event~source接続を[ 互いに, あるいは以前に~serveされた特定の文書 ]に関係させたいと望む作者は、~IP~addressに依拠するのでは,うまく働かないことを見出すであろう — (複数の~proxy~serverを通すことに因り)同じ~clientが 複数の~IP~addressから接続することもあれば、(~proxy~serverを共有していることに因り)複数の~clientが 同じ~IP~addressから接続することもあるので。 文書を~serveするときに,その文書~内に一意な識別子を含ませておいて、接続の確立-時に その識別子を~URLの一部として渡す方が良い。 ◎ Authors wishing to relate event source connections to each other or to specific documents previously served might find that relying on IP addresses doesn't work, as individual clients can have multiple IP addresses (due to having multiple proxy servers) and individual IP addresses can have multiple clients (due to sharing a proxy server). It is better to include a unique identifier in the document when it is served and then pass that identifier as part of the URL when the connection is established.

作者は,また、~HTTPが規定する~chunkingは,この~protocolの信頼性に 予期されない負の効果をもたらし得ることにも警戒すること — 特に、~chunkingが~timing要件に関知しない層で行われている場合には。 これが問題になる場合、~event~streamの~serveに対しては,~chunkingを不能化できる。 ◎ Authors are also cautioned that HTTP chunking can have unexpected negative effects on the reliability of this protocol, in particular if the chunking is done by a different layer unaware of the timing requirements. If this is a problem, chunking can be disabled for serving event streams.

【 ~chunking( chunking ) — おそらく, chunked transfer coding を指す。 】

~HTTPによる~server単位の接続~数~制限を~supportする~clientは、ある~siteから複数の頁を~openしたとき,その各~頁に同じ~domainへの `EventSource$I がある場合に 困らされることもある。 作者がこれを避ける方法には、次が挙げられる:

  • より複雑な仕組みを用いる
  • 接続ごとに一意な~domain名を用いる
  • 利用者が頁ごとに `EventSource$I の機能性を可能化したり不能化できるようにする
  • 単独の `EventSource$I ~objを`共用~worker内$で共有する

【 接続~数~制限 — おそらく, RFC7230, 6.4 節 を指す。 】

◎ Clients that support HTTP's per-server connection limitation might run into trouble when opening multiple pages from a site if each page has an EventSource to the same domain. Authors can avoid this using the relatively complex mechanism of using unique domain names per connection, or by allowing the user to enable or disable the EventSource functionality on a per-page basis, or by sharing a single EventSource object using a shared worker.

9.2.7. 無接続~pushと他の特色機能

制御~下にある環境で走っている~UA — 例えば,特定の~carrierに束ねられている携帯機の~browser — は、接続の管理を~network上の~proxyに負荷移譲してよい。 適合性の目的においては、そのような状況における~UAは,その携帯機~softwareと~network~proxyの両者を含むものと見なされる。 ◎ User agents running in controlled environments, e.g. browsers on mobile handsets tied to specific carriers, may offload the management of the connection to a proxy on the network. In such a situation, the user agent for the purposes of conformance is considered to include both the handset software and the network proxy.

例えば,携帯機の~browserは、接続を確立した後に、その接続は `~proxyが^tnote ~supportしている~networkであることを検出して,その~network上の~proxy~serverに接続の管理を司るよう要請するかもしれない。 そのような状況においては、次のような経過を辿ることになる: ◎ For example, a browser on a mobile device, after having established a connection, might detect that it is on a supporting network and request that a proxy server on the network take over the management of the connection. The timeline for such a situation might be as follows:

  1. ~browserは、作者が `EventSource()$m 構築子にて指定した資源を,~remote~HTTP~serverへ接続して要請する。 ◎ Browser connects to a remote HTTP server and requests the resource specified by the author in the EventSource constructor.
  2. ~serverは、各~messageを不定期に送信する。 ◎ The server sends occasional messages.
  3. ~browserは、ある 2 つの~messageの合間に,[ ~TCP接続を~~維持し続けるための~network活動を除き,自身は遊休~中にある ]ことを検出したので、電力を節約するため,~sleep~modeへ切替えることにした。 ◎ In between two messages, the browser detects that it is idle except for the network activity involved in keeping the TCP connection alive, and decides to switch to sleep mode to save power.
  4. ~browserは、~serverから切断される。 ◎ The browser disconnects from the server.
  5. ~browserは、当の接続を維持する代わりに,上述した~network上の~serviceに接触して “~push~proxy” ~serviceを要請する。 ◎ The browser contacts a service on the network, and requests that the service, a "push proxy", maintain the connection instead.
  6. “~push~proxy” ~serviceは、~remote~HTTP~serverに接触して,作者が `EventSource()$m 構築子にて指定した資源を要請する(場合によっては, `Last-Event-ID$h ~HTTP~header, 等々が含まれる)。 ◎ The "push proxy" service contacts the remote HTTP server and requests the resource specified by the author in the EventSource constructor (possibly including a `Last-Event-ID` HTTP header, etc).
  7. ~browserは、携帯機に~sleepすることを許容する。 ◎ The browser allows the mobile device to go to sleep.
  8. ~serverは、別の~messageを送信する。 ◎ The server sends another message.
  9. “~push~proxy” ~serviceは、~eventを携帯機に運ぶため,~OMA~pushなどの技術を利用する — それは、~eventを処理するに足るだけ携帯機を目覚めさせてから,~sleepに戻す。 `OMA = おそらく、 Open Mobile Alliance(携帯電話の規格を策定する組織)を指す。^tnote ◎ The "push proxy" service uses a technology such as OMA push to convey the event to the mobile device, which wakes only enough to process the event and then returns to sleep.

これは,総~data使用量を抑制する結果、~~相当に電力を節約する。 ◎ This can reduce the total data usage, and can therefore result in considerable power savings.

[ 既存の~API, および `text/event-stream$c 伝送路~形式 ]を[ この仕様により定義されるように, および 上に述べたような より分散的な仕方 ]で実装することに加え、`適用し得る仕様$により定義される~event~framingの形式も~supportされてよい。 この仕様は、それがどう構文解析され, 処理されるかは,定義しない。 ◎ As well as implementing the existing API and text/event-stream wire format as defined by this specification and in more distributed ways as described above, formats of event framing defined by other applicable specifications may be supported. This specification does not define how they are to be parsed or processed.

9.2.8. ~garbage収集

[ `Window$I / `WorkerGlobalScope$I ]~obj %G 内の構築子を呼出して作成された `EventSource$I ~obj %O に対しては、次のいずれかが満たされている間は, %G から %O への強い参照-が~MUST: ◎ ↓

  • [ %O の ``readyState$m ~EQ ``CONNECTING$m ]~AND[ %O には[ `open$et / `message$et /`error$et ]~eventに対する~event~listenerが 1 個~以上~登録されている ] ◎ While an EventSource object's readyState is CONNECTING, and the object has one or more event listeners registered for open, message or error events, there must be a strong reference from the Window or WorkerGlobalScope object that the EventSource object's constructor was invoked from to the EventSource object itself.
  • [ %O の ``readyState$m ~EQ ``OPEN$m ]~AND[ %O には[ `message$et / `error$et ]~eventに対する~event~listenerが 1 個~以上~登録されている ] ◎ While an EventSource object's readyState is OPEN, and the object has one or more event listeners registered for message or error events, there must be a strong reference from the Window or WorkerGlobalScope object that the EventSource object's constructor was invoked from to the EventSource object itself.
  • %O により`~remote~event~task源$から待入された~taskがある ◎ While there is a task queued by an EventSource object on the remote event task source, there must be a strong reference from the Window or WorkerGlobalScope object that the EventSource object's constructor was invoked from to that EventSource object.

~UAは、 `EventSource$I ~obj %O を `強制的に~closeする@ ときは(これは `Document$I ~objが永続的に消去ったときに起こる),次を走らせ~MUST:

  1. %O のために開始された すべての`~fetch$~algoを中止する
  2. %O の ``readyState$m 属性 ~SET ``CLOSED$m
◎ If a user agent is to forcibly close an EventSource object (this happens when a Document object goes away permanently), the user agent must abort any instances of the fetch algorithm started for this EventSource object, and must set the readyState attribute to CLOSED.

`EventSource$I ~obj %O が,接続が依然として~openしている間に~garbage収集された場合、 ~UAは, %O のために開始された すべての`~fetch$~algoを中止し~MUST。 ◎ If an EventSource object is garbage collected while its connection is still open, the user agent must abort any instance of the fetch algorithm opened by this EventSource.

9.2.9. 実装への~advice

~INFORMATIVE

この~APIを利用している作者による~codeの~debugを支援するため、~UAには,[ `EventSource$I ~obj, および それに関係する~network接続 ]についての詳細な診断~情報を,開発~console内に提供することが強く督促される。 ◎ User agents are strongly urged to provide detailed diagnostic information about EventSource objects and their related network connections in their development consoles, to aid authors in debugging code using this API.

例えば~UAは、頁が作成した すべての `EventSource$I ~objのそれぞれについて 次を表示するような~panelを備えることもできる:

  • 構築子の引数
  • ~network~errorが生じたかどうか
  • 接続の~CORS~statusは何であるか
  • その~statusに導いた(~clientが送信した/ ~serverから受信された)~headerたち
  • 受信された~message
  • その~messageはどう構文解析されたか, 等々。
◎ For example, a user agent could have a panel displaying all the EventSource objects a page has created, each listing the constructor's arguments, whether there was a network error, what the CORS status of the connection is and what headers were sent by the client and received from the server to lead to that status, the messages that were received and how they were parsed, and so forth.

とりわけ, `error$et ~eventが発火されたときには、実装には,詳細な情報を自身の開発~consoleに報告することが奨励される — ~event自体から可用になる情報は少ししかないので。 ◎ Implementations are especially encouraged to report detailed information to their development consoles whenever an error event is fired, since little to no information can be made available in the events themselves.

9.3. ~web-socket

【 この節の内容の和訳は、別ページにて。 】

9.4. 文書間~messaging

保安や~privacyの理由から、~web~browserは,異なる~domainに属する文書どうしが互いに影響しあうのを防止する — すなわち、~XSSは不許可にされる。 ◎ Web browsers, for security and privacy reasons, prevent documents in different domains from affecting each other; that is, cross-site scripting is disallowed.

これは重要な保安~用の特色機能であるが、異なる~domainに属する頁との通信は,その頁が敵対的でなくとも防止される。 この節では、~source~domainに関わらず,文書どうしが互いに~messageを通信しあえるようにする~systemを、~XSS攻撃を可能化しないように設計される仕方で導入する。 ◎ While this is an important security feature, it prevents pages from different domains from communicating even when those pages are not hostile. This section introduces a messaging system that allows documents to communicate with each other regardless of their source domain, in a way designed to not enable cross-site scripting attacks.

注記: この~APIには、直ぐには明らかにならないかもしれない ある~privacy上の含意がある。 ◎ This API has some privacy implications that might not be immediately obvious.

`投函済み~message~task源@ が、`文書間~messaging$における`~task$の`~task源$になる。 ◎ The task source for the tasks in cross-document messaging is the posted message task source.

9.4.1. 序論

~INFORMATIVE

例えば,ある文書 %A が `iframe$e 要素を包含していて, その要素は 別の文書 %B を包含している下で, %A 内の~scriptが %B の `Window$I ~objの `window.postMessage()$m を~callした場合、~message~eventは,その~objに向けて発火される — %A の `Window$I を出自にしているよう~markされた上で。 %A 内の~scriptは次の様になるであろう: ◎ For example, if document A contains an iframe element that contains document B, and script in document A calls postMessage() on the Window object of document B, then a message event will be fired on that object, marked as originating from the Window of document A. The script in document A might look like:

var %o = document.getElementsByTagName('iframe')[0];
%o.contentWindow.postMessage('Hello world', 'https://b.example.org/');

%B 内の~scriptは、入って来る~eventに対する~event~handlerを登録するため、 `addEventListener()^m (または類似する仕組み)を利用することになる。 例えば,次の様になるであろう: ◎ To register an event handler for incoming events, the script would use addEventListener() (or similar mechanisms). For example, the script in document B might look like:

window.addEventListener('message', receiver, false);
function receiver(%e) {
  if (%e.origin == 'https://example.com') {
    if (%e.data == 'Hello world') {
      %e.source.postMessage('Hello', %e.origin);
    } else {
      alert(%e.data);
    }
  }
}

この~scriptは、まず,~domainが期待されるものかどうか検査する。 次に,~messageの中身に応じて、利用者に表示するか,または ~message送信してきた文書に ~messageを返信して応答する。 ◎ This script first checks the domain is the expected domain, and then looks at the message, which it either displays to the user, or responds to by sending a message back to the document which sent the message in the first place.

9.4.2. 保安

9.4.2.1. 作者

利己~目的で~siteを濫用する敵対的~主体から 利用者を保護するため、この~APIの利用にあたっては,格別に注意することが要求される。 ◎ Use of this API requires extra care to protect users from hostile entities abusing a site for their own purposes.

作者は、 `origin$m 属性を検査して,受容する~messageを,自身が期待する~domainから受信されるものに限ることを確保するべきである。 作者の~message取扱い~code内に~bugがある場合、敵対的~siteにより悪用され得ることになる。 ◎ Authors should check the origin attribute to ensure that messages are only accepted from domains that they expect to receive messages from. Otherwise, bugs in the author's message handling code could be exploited by hostile sites.

加えて, `origin$m 属性を検査した後でも、作者は,当の~dataが期待される形式であるかどうか検査するべきある。 さもなければ、~eventの~sourceが~XSSに対する欠陥を突いて攻撃されていた場合に、 `window.postMessage()$m ~methodで送信された情報は,攻撃により受信器にまで伝播されることになる。 ◎ Furthermore, even after checking the origin attribute, authors should also check that the data in question is of the expected format. Otherwise, if the source of the event has been attacked using a cross-site scripting flaw, further unchecked processing of information sent using the postMessage() method could result in the attack being propagated into the receiver.

作者は、機密的~情報を包含するような~messageに対しては,生成元~引数( %targetOrigin )に~wildcard-keyword ( `*^l )を渡すべきでない。 そうしない以外に、~messageの送達-先を意図された受信者のみに限るよう保証する仕方はない。 ◎ Authors should not use the wildcard keyword (*) in the targetOrigin argument in messages that contain any confidential information, as otherwise there is no way to guarantee that the message is only delivered to the recipient to which it was intended.


どの生成元からの~messageも受容する作者には、~DoS攻撃の~riskを考慮することが奨励される。 攻撃者は大容量の~messageを送信することもできる。 受信-中の頁が高価な計算を遂行したり,そのような各~messageごとに 送信-による~network流通が生じる場合、攻撃者の~messageは,~DoS攻撃~用に増殖される。 作者には、そのような攻撃が実用的でなくなるよう,~rate制限-法を使役することが奨励される(毎分あたりの~message数を一定に抑えるなど)。 ◎ Authors who accept messages from any origin are encouraged to consider the risks of a denial-of-service attack. An attacker could send a high volume of messages; if the receiving page performs expensive computation or causes network traffic to be sent for each such message, the attacker's message could be multiplied into a denial-of-service attack. Authors are encouraged to employ rate limiting (only accepting a certain number of messages per minute) to make such attacks impractical.

9.4.2.2. ~UA

この~API `による~message^tnote の完全性は、ある`生成元$の~scriptが,任意の~eventを(`同一生成元$でない)他の生成元に属する~objへ( `dispatchEvent()^m などを用いて)投函できないことに基づいている。 ◎ The integrity of this API is based on the inability for scripts of one origin to post arbitrary events (using dispatchEvent() or otherwise) to objects in other origins (those that are not the same).

注記: 実装者には、この特色機能を実装するにあたり,格別に注意することが督促される。 この特色機能は、作者がある~domainから別の~domainへ情報を伝送できるようにする — 通常は 保安の理由から不許可にされるような。 また,~UAには、ある種の~propertyへの~accessを,一方には許容しつつ, 他方には許容しないよう注意深くなることが要求される。 ◎ Implementors are urged to take extra care in the implementation of this feature. It allows authors to transmit information from one domain to another domain, which is normally disallowed for security reasons. It also requires that UAs be careful to allow access to certain properties but not others.


簡易的な~siteを~DoS攻撃から保護するため、~UAには,異なる`生成元$の間での~message流通~rateの制限-法を考慮することが奨励される。 ◎ User agents are also encouraged to consider rate-limiting message traffic between different origins, to protect naïve sites from denial-of-service attacks.

9.4.3. ~messageの投函-法

%window . `postMessage(message, targetOrigin [, transfer ] )$m

%message を %window へ投函する。 %message は有構造~objにもなり得る。 例えば次のものを包含できる:

  • 入子にされた~objや配列
  • ~JS値( `string^jT, `number^jT, `Date$jT ~obj, 等々)
  • `File$I, `Blob$I, `FileList$I, `ArrayBuffer$I などの,ある種の~data~obj
◎ Posts a message to the given window. Messages can be structured objects, e.g. nested objects and arrays, can contain JavaScript values (strings, numbers, Date objects, etc), and can contain certain data objects such as File Blob, FileList, and ArrayBuffer objects.
%transfer 内に~listされた~objは、~cloneされるのみならず転送される — すなわち,送信-側からは、それ以降,それらを利用できなくなる。 ◎ Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.
宛先 %window の生成元が,生成元 %targetOrigin に合致しない場合、情報~漏洩を避けるため,~messageは 破棄される。 生成元に関わらず,~messageを宛先に送信したければ、 %targetOrigin に `*^l を与える。 生成元を明示的に与えずに ~messageを同一生成元の宛先のみに制約したければ、 %targetOrigin に `/^l を与える。 ◎ If the origin of the target window doesn't match the given origin, the message is discarded, to avoid information leakage. To send the message to the target regardless of origin, set the target origin to "*". To restrict the message to same-origin targets only, without needing to explicitly state the origin, set the target origin to "/".
次の場合は `DataCloneError$E が投出される ⇒ %transfer 配列が同じ~objを重複して包含する場合/ %message を~cloneできなかった場合 ◎ Throws a "DataCloneError" DOMException if transfer array contains duplicate objects or if message could not be cloned.

注記: ~navigateされたばかりの`閲覧文脈$に属する新たな `Document$I の `Window$I に,~messageを投函した場合、その~messageは,意図された受信者に受信されない見込みが高い — 宛先 `閲覧文脈$内の~scriptは、~messageに対する~listenerを設定しておく時間を要するので。 したがって,具体例として、~messageが 新たに作成された子 `iframe$e の `Window$I に送信される状況においては、作者には、子 `Document$I から先に,受信する用意が整った旨を親~宛に公告する~messageを投函させ、親は,この~messageを待機してから~messageを投函し始めるようにすることを勧める。 ◎ When posting a message to a Window of a browsing context that has just been navigated to a new Document is likely to result in the message not receiving its intended recipient: the scripts in the target browsing context have to have had time to set up listeners for the messages. Thus, for instance, in situations where a message is to be sent to the Window of newly created child iframe, authors are advised to have the child Document post a message to their parent announcing their readiness to receive messages, and for the parent to wait for this message before beginning posting messages.

`Window$I ~obj上の `postMessage( message, targetOrigin, transfer )@m の被呼出時には、次の手続きを走らせ~MUST: ◎ The postMessage(message, targetOrigin, transfer) method, when invoked on a Window object must run the following steps:

  1. %宛先~window ~LET 此れ ◎ Let targetWindow be this Window object.
  2. %宛先~Realm ~LET %宛先~window の`~Realm$ ◎ Let targetRealm be targetWindow's Realm.
  3. %現任の設定群 ~LET `現任の設定群~obj$ ◎ Let incumbentSettings be the incumbent settings object.
  4. %宛先~生成元 ~LET ε ◎ ↓
  5. ~IF[ %targetOrigin ~EQ U+002F ( `/^l ) ] ⇒ %宛先~生成元 ~SET %現任の設定群 の`生成元$enV ◎ If targetOrigin is a single U+002F SOLIDUS character (/), then set targetOrigin to incumbentSettings's origin.
  6. ~ELIF[ %targetOrigin ~NEQ U+002A ( `*^l ) ]: ◎ Otherwise, if targetOrigin is not a single U+002A ASTERISK character (*), then:

    1. %解析済み~URL ~LET %targetOrigin を`~URL構文解析器$にかけた結果 ◎ Let parsedURL be the result of running the URL parser on targetOrigin.
    2. ~IF[ %解析済み~URL ~EQ `失敗^i ] ⇒ ~THROW `SyntaxError$E ◎ If parsedURL is failure, then throw a "SyntaxError" DOMException.
    3. %宛先~生成元 ~SET %解析済み~URL の`生成元$url ◎ Set targetOrigin to parsedURL's origin.
  7. %~clone~record ~LET `StructuredCloneWithTransfer$jA( %message, %transfer, %宛先~Realm ) (例外投出あり) ◎ Let cloneRecord be StructuredCloneWithTransfer(message, transfer, targetRealm). Rethrow any exceptions.
  8. %~message~clone ~LET %~clone~record . `Deserialized^sl ◎ Let messageClone be cloneRecord.[[Deserialized]].
  9. %新~port~list ~LET %~clone~record . `TransferredValues^sl 内のすべての `MessagePort$I ~objからなる,同順の新たな `凍結~配列$ ◎ Let newPorts be a new frozen array consisting of all MessagePort objects in cloneRecord.[[TransferredValues]], if any, maintaining their relative order.
  10. ~RET — ただし、以降の手続きは`並列的$に継続する ◎ Return, but continue running these steps in in parallel.
  11. ~IF[ %宛先~生成元 ~NEQ ε ]~AND[ ( %宛先~window に`結付けられている文書$の`生成元$, %宛先~生成元 ) は`同一生成元$でない ] ⇒ ~RET ◎ If the targetOrigin argument is not a single literal U+002A ASTERISK character (*) and targetWindow's associated Document's origin is not same origin with targetOrigin, then abort these steps.
  12. `投函済み~message~task源$から,次を走らす`~taskを待入する$ ⇒ %宛先~window に向けて,次のように初期化された名前 `message$et の`~eventを発火-$する:

    • `MessageEvent$I を利用する
    • `data$m 属性 ~SET %~message~clone
    • `origin$m 属性 ~SET %現任の設定群 の`生成元$enVの`~Unicode直列化$
    • `source$m 属性 ~SET `WindowProxy$I ~obj’s corresponding`?^tnote %現任の設定群 の`大域~obj$enV ( `Window$I ~obj)
    • `ports$m 属性 ~SET %新~port~list
    ◎ Queue a task on the posted message task source to fire an event named message at targetWindow, using MessageEvent, with the data attribute initialized to messageClone, the origin attribute initialized to the Unicode serialization of incumbentSettings's origin, the source attribute initialized to the WindowProxy object's corresponding incumbentSettings's global object (a Window object), and the ports attribute initialized to newPorts.

9.5. ~channel~messaging

9.5.1. 序論

~INFORMATIVE

`~channel~messaging$ `channel messaging ( “~channelを介した~messageの送信-法” )^tnote を利用すれば、作者は,独立な~code片どうし(例えば,異なる`閲覧文脈$内で走っているもの)を 直接的に通信させれる。 ◎ To enable independent pieces of code (e.g. running in different browsing contexts) to communicate directly, authors can use channel messaging.

この仕組みにおける通信~channelは、両端に~portを伴う,二重化された~pipeとして実装される。 一方の~portに送信される~messageは,他方の~portに送達され、逆も同様になる。 各~messageは、走っている`~task$を中断したり阻むことなく,~DOM~eventとして送達される。 ◎ Communication channels in this mechanism are implemented as two-ways pipes, with a port at each end. Messages sent in one port are delivered at the other port, and vice-versa. Messages are delivered as DOM events, without interrupting or blocking running tasks.

接続( “連絡された” 2 個の~port)を作成するためには、 `MessageChannel()$m 構築子を~callする: ◎ To create a connection (two "entangled" ports), the MessageChannel() constructor is called:

var %channel = new MessageChannel();

一方の~portは 局所~portとして保たれ、他方の~portは ~remote~codeへ送信される — 例えば `window.postMessage()$m を用いて: ◎ One of the ports is kept as the local port, and the other port is sent to the remote code, e.g. using postMessage():

%otherWindow.postMessage('hello', 'https://example.com', [%channel.port2]);

~messageを送信するためには、局所~port上の ``postMessage()$m ~methodを利用する: ◎ To send messages, the postMessage() method on the port is used:

%channel.port1.postMessage('hello');

~messageを受信するためには、 `message$et ~eventを~listenする: ◎ To receive messages, one listens to message events:

%channel.port1.onmessage = handleMessage;
function handleMessage(%event) {
  /* 
~messageは %event の`data$m 属性~内にある
◎
message is in event.data
 */
  // ...
}

~portに送信する~dataは、有構造~dataも可能である。 例えば,次では、一連の文字列からなる配列が `MessagePort$I に渡される: ◎ Data sent on a port can be structured data; for example here an array of strings is passed on a MessagePort:

%channel.port1.postMessage(['hello', 'world']);

9.5.1.1. 例

~INFORMATIVE

この例では、 2 つの~JS~libraryが `MessagePort$I を用いて互いに接続される。 これにより,~libraryは、~APIを何ら変更することなく,後で[ `~worker$ ~obj/異なる~frame ]内に~hostすることも可能になる。 ◎ In this example, two JavaScript libraries are connected to each other using MessagePorts. This allows the libraries to later be hosted in different frames, or in Worker objects, without any change to the APIs.

<script src="contacts.js"></script> <!-- 
%contacts ~objを公開する
◎
exposes a contacts object
 -->
<script src="compose-mail.js"></script> <!-- 
%composer ~objを公開する
◎
exposes a composer object
 -->
<script>
 var %channel = new MessageChannel();
 %composer.addContactsProvider(%channel.port1);
 %contacts.registerConsumer(%channel.port2);
</script>

`addContactsProvider()^c 関数の実装は、次の様になる: ◎ Here's what the "addContactsProvider()" function's implementation could look like:

function addContactsProvider(%port) {
  %port.onmessage = function (%event) {
    switch (%event.data.messageType) {
      'search-result': handleSearchResult(%event.data.results); break;
      'search-done': handleSearchDone(); break;
      'search-error': handleSearchError(%event.data.message); break;
      // ...
    }
  };
};

あるいは、次の様に実装することもできる: ◎ Alternatively, it could be implemented as follows:

function addContactsProvider(%port) {
  %port.addEventListener('message', function (%event) {
    if (%event.data.messageType == 'search-result')
      handleSearchResult(%event.data.results);
  });
  %port.addEventListener('message', function (%event) {
    if (%event.data.messageType == 'search-done')
      handleSearchDone();
  });
  %port.addEventListener('message', function (%event) {
    if (%event.data.messageType == 'search-error')
      handleSearchError(%event.data.message);
  });
  // ...
  %port.start();
};

上の 2 つの~codeにおける~~主な違いは、 `addEventListener()$m を利用した場合, ``start()$m ~methodも呼出す必要がある点にある。 ``onmessage$m を利用した場合,暗黙的に ``start()$m も~callされる。 ◎ The key difference is that when using addEventListener(), the start() method must also be invoked. When using onmessage, the call to start() is implied.

``start()$m ~methodは、明示的に~callされようが,( ``onmessage$m を設定することにより)暗黙的に~callされようが,~messageの~flowを開始する。 その前の初期~時においては、~message~portに投函された~messageは,~scriptが自身による~handlerを設定しておく機会を得る前に どこかへ落とされないよう,一時停止される。 ◎ The start() method, whether called explicitly or implicitly (by setting onmessage), starts the flow of messages: messages posted on message ports are initially paused, so that they don't get dropped on the floor before the script has had a chance to set up its handlers.

9.5.1.2. ~web上の~obj能力~modelの基礎としての~port

~INFORMATIVE

~obj能力~model

~portは、[ ~system内の他の動作者に,制限された能力を公開する仕方 ]と捉えることもできる(~obj能力~model的意味で)。 これは、弱い能力~systemにも、強い能力~modelにもなり得る。 弱い能力~systemにおける~portは、単に同じ生成元の中で便利用~modelとして利用される。 強い能力~systemにおける~portは、ある生成元に属する %提供者 ( provider )から 別の生成元に属する %消費者 ( consumer )に向けて, %消費者 が[ %提供者 に効果を及ぼせる / %提供者 からの情報を得る ]ような唯一の仕組みとして,提供される。 ◎ Ports can be viewed as a way to expose limited capabilities (in the object-capability model sense) to other actors in the system. This can either be a weak capability system, where the ports are merely used as a convenient model within a particular origin, or as a strong capability model, where they are provided by one origin provider as the only mechanism by which another origin consumer can effect change in or obtain information from provider.

例えば、ある %~social~site の頁が,次のような 2 個の `iframe$e を埋込んでいる状況を考える:

  • %提供者~frame は、( %~social~site とは別の生成元に属する) %提供者 — ここでは,利用者の~address-bookを提供している~serviceとする — からの内容を含んでいる
  • %消費者~frame は、(また別の生成元に属する) %消費者 — 例えば,ある~game~siteなど — からの内容を含んでいる

%~social~site 頁, および %消費者~frame 内からは、 %提供者~frame の内側にあるものには~accessできない — これら二者が %提供者~frame の内側に何か及ぼせるのは、次に限られる:

◎ For example, consider a situation in which a social Web site embeds in one iframe the user's e-mail contacts provider (an address book site, from a second origin), and in a second iframe a game (from a third origin). The outer social site and the game in the second iframe cannot access anything inside the first iframe; together they can only:
  • %提供者~frame を[ %提供者~frame の~URLと`素片$urlだけ異なる`~URL$ ]へ`~navigate$する — %提供者~frame 内の `Window$I は `hashchange$et ~eventを受信することになる。 ◎ Navigate the iframe to a new URL, such as the same URL but with a different fragment, causing the Window in the iframe to receive a hashchange event.
  • %提供者~frame を~resizeする — %提供者~frame 内の `Window$I は `resize$et ~eventを受信することになる。 ◎ Resize the iframe, causing the Window in the iframe to receive a resize event.
  • `window.postMessage()$m ~APIを用いて, %提供者~frame 内の `Window$I へ `message$et ~eventを送信する。 ◎ Send a message event to the Window in the iframe using the window.postMessage() API.

%提供者 は、これらのうち,特に 3 番目の~method — `message$et ~event — を利用して、他の生成元から~accessできるような,利用者の~address-bookを操作するための~APIを提供する。 例えば、~message "add-contact: Guillaume Tell <tell@pomme.example.net>" に対し、それが与える個人名とその~e-mail~addressを 利用者の~address-bookに追加することにより,応答することもできる。 ◎ The contacts provider can use these methods, most particularly the third one, to provide an API that can be accessed by other origins to manipulate the user's address book. For example, it could respond to a message "add-contact Guillaume Tell <tell@pomme.example.net>" by adding the given person and e-mail address to the user's address book.

~Web上の どの~siteも利用者の~address-bookを操作できては困るので、 %提供者 は,当の %~social~site など, 一定の信用済み~siteに限って,これを許容するであろう。 ◎ To avoid any site on the Web being able to manipulate the user's contacts, the contacts provider might only allow certain trusted sites, such as the social site, to do this.

ここで、 %消費者 は,利用者の~address-bookにメールアドレス(例えば、~gameの対戦相手の)を追加したいと求めていて、 %~social~site は,自らに利するため それを許容するつもりにあるとする — それは,本質的には、 %提供者 が %~social~site と信用-を “共有すること” に等しい。 これを行う仕方にはいくつかあり、最も単純なのは, %~social~site が %消費者 ~siteと %提供者 ~siteとの間の~messageを代理することであろう。 しかしながら、この解決策には 難点がある:

  • %~social~site は、[ %消費者 ~siteが特権を濫用しないこと ]を完全に信用するか,あるいは 許容したくない要請(メールアドレスを[ 複数~追加する / 読取る / 削除する ]など)ではないことを確かめるため,各~要請を検証0することが要求される。
  • 他にもいくつかの %消費者 が居て,同時的に %提供者 と相互作用することもあり得る場合、複雑さが増す。
◎ Now suppose the game wanted to add a contact to the user's address book, and that the social site was willing to allow it to do so on its behalf, essentially "sharing" the trust that the contacts provider had with the social site. There are several ways it could do this; most simply, it could just proxy messages between the game site and the contacts site. However, this solution has a number of difficulties: it requires the social site to either completely trust the game site not to abuse the privilege, or it requires that the social site verify each request to make sure it's not a request that it doesn't want to allow (such as adding multiple contacts, reading the contacts, or deleting them); it also requires some additional complexity if there's ever the possibility of multiple games simultaneously trying to interact with the contacts provider.

~message~channelと `MessagePort$I ~objを用いれば、これらの問題すべてを消し去れる。 %消費者 がメールアドレスを追加したいと求める旨を %~social~site に伝えたとき、 %~social~site は、メールアドレスを追加することではなく,[ 1 個のメールアドレスを追加する能力 ]について, %提供者 に~~要請できる。 それに対し, %提供者 は、 `MessagePort$I ~objの~pairを作成して,その片方を %~social~site に返信する。 %~social~site は、受信したそれを %消費者 に回送する。 それにより、 %消費者 と %提供者 は,直接的に接続されることになり、 %提供者 は, “1 個のメールアドレスを追加する” 要請のみ尊守すればよいことを知る。 言い換えれば、 %消費者 には, 1 個のメールアドレスを追加する能力が是認されたことになる。 ◎ Using message channels and MessagePort objects, however, all of these problems can go away. When the game tells the social site that it wants to add a contact, the social site can ask the contacts provider not for it to add a contact, but for the capability to add a single contact. The contacts provider then creates a pair of MessagePort objects, and sends one of them back to the social site, who forwards it on to the game. The game and the contacts provider then have a direct connection, and the contacts provider knows to only honor a single "add contact" request, nothing else. In other words, the game has been granted the capability to add a single contact.

9.5.1.3. ~service実装を抽象~化する基礎としての~port

~INFORMATIVE

前~節からの例を引き継いで、特に, %提供者 側を考える。 初期~実装では、単純に~serviceの `iframe$e 内で `XMLHttpRequest$I ~objを利用していたが、~serviceの発展に伴い,単独の `WebSocket$I 接続を備える`共用~worker$の利用に代えたいと求めることもあろう。 ◎ Continuing the example from the previous section, consider the contacts provider in particular. While an initial implementation might have simply used XMLHttpRequest objects in the service's iframe, an evolution of the service might instead want to use a shared worker with a single WebSocket connection.

初期~設計の段階で, `MessagePort$I ~objを[ 能力を是認するため/ または単に複数の同時的な独立~sessionを許容するため ]に利用していたなら、~service実装は,~APIに全く手を加えずに[ 各 `iframe$e ごとに `XMLHttpRequest$I を用いる~model ]から[ `WebSocket$I を共有する~model ]へ切替えれるようになる — ~service提供者~側のすべての~portは、~APIの利用者にまったく影響することなく,共用~workerに回送できる。 ◎ If the initial design used MessagePort objects to grant capabilities, or even just to allow multiple simultaneous independent sessions, the service implementation can switch from the XMLHttpRequests-in-each-iframe model to the shared-WebSocket model without changing the API at all: the ports on the service provider side can all be forwarded to the shared worker without it affecting the users of the API in the slightest.

9.5.2. ~message~channel

[Constructor, Exposed=(Window,Worker)]
interface `MessageChannel@I {
  readonly attribute `MessagePort$I `port1$m;
  readonly attribute `MessagePort$I `port2$m;
};
%channel = new `MessageChannel()$m
2 個の新たな `MessagePort$I ~objが伴われた,新たな `MessageChannel$I ~objを返す。 ◎ Returns a new MessageChannel object with two new MessagePort objects.
%channel . `port1$m
1 個目の `MessagePort$I ~objを返す。 ◎ Returns the first MessagePort object.
%channel . `port2$m
2 個目の `MessagePort$I ~objを返す。 ◎ Returns the second MessagePort object.
`MessageChannel()@m

この構築子の被呼出時には、次を走らせ~MUST: ◎ When the MessageChannel() constructor is called, it must run the following algorithm:

  1. %port1 ~LET `現任の設定群~obj$から`新たな~MessagePort~objを作成-$した結果 ◎ Create a new MessagePort object whose owner is the incumbent settings object, and let port1 be that object.
  2. %port2 ~LET `現任の設定群~obj$から`新たな~MessagePort~objを作成-$した結果 ◎ Create a new MessagePort object whose owner is the incumbent settings object, and let port2 be that object.
  3. ( %port1, %port2 ) を`連絡-$する ◎ Entangle the port1 and port2 objects.
  4. %~channel ~LET 新たな `MessageChannel$I ~obj ◎ Instantiate a new MessageChannel object, and let channel be that object.
  5. %~channel の `port1$m 属性 ~SET %port1 ◎ Let the port1 attribute of the channel object be port1.
  6. %~channel の `port2$m 属性 ~SET %port2 ◎ Let the port2 attribute of the channel object be port2.
  7. ~RET %~channel ◎ Return channel.
`port1@m
`port2@m
いずれの取得子も、此れの作成-時にあてがわれた値を返さ~MUST。 ◎ The port1 and port2 attributes must return the values they were assigned when the MessageChannel object was created.

9.5.3. ~message~port

各~channelは、 2 個の~message~portを持つ。 一方の~portから送信された~dataは,他方の~portに受信され、逆も同様になる。 ◎ Each channel has two message ports. Data sent through one port is received by the other port, and vice versa.

[Exposed=(Window,Worker) `Transferable$]
interface `MessagePort@I : `EventTarget$I {
  void ``postMessage$m(any %message, optional sequence<`object$I> %transfer = []);
  void ``start$m();
  void ``close$m();

  // event handlers
  attribute `EventHandler$I ``onmessage$m;
};
%port . ``postMessage( message [, transfer] )$m
~channelを通して~messageを投函する。 %transfer 内に~listされた~objは、~cloneされるのみならず転送される — すなわち,送信-側からは、それ以降,それらを利用できなくなる。 ◎ Posts a message through the channel. Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.
次の場合は `DataCloneError$E が投出される ⇒ %transfer 配列が 同じ~objを重複して包含する場合 / %transfer 配列が この~port自身や宛先~portを包含する場合 / %message を~cloneできなかった場合 ◎ Throws a "DataCloneError" DOMException if transfer array contains duplicate objects or the source or target ports, or if message could not be cloned.
%port . ``start()$m
この~portに受信される/された~messageを配送させ始める。 ◎ Begins dispatching messages received on the port.
%port . ``close()$m
この~portを切断する。 以降、この~portは 作動中でなくなる。 ◎ Disconnects the port, so that it is no longer active.

各 `MessagePort$I ~objは、別のそれと連絡され得る(その関係性は対称になる)。

【 `port1$m, `port2$m のどちらを手元において もう片方を転送しようがかまわない。 】

各 `MessagePort$I ~objは、次のものを持つ:

`~port~message待行列@
`~task源$†。 初期~時には空とする。 `~port~message待行列$は、初期~時には不能化されており,ある時点で可能化され得る。 可能化された後,再び不能化されることは決してない(待行列~内の~messageたちは、別の待行列へ移動されたり,すべて除去されることもあるが — それは、不能化されるのとほぼ同じ効果になる)。
【† ここでは、個々の`~task源$と 個々の`~task待行列$としての`~port~message待行列$とが,同一視されている。 】
`搬送済み~flag@
初期~時には ~OFF にされ~MUST
`所有者@
~objの作成-時に 下に述べるように設定される,`設定群~obj$。
◎ Each MessagePort object can be entangled with another (a symmetric relationship). Each MessagePort object also has a task source called the port message queue, initially empty. A port message queue can be enabled or disabled, and is initially disabled. Once enabled, a port can never be disabled again (though messages in the queue can get moved to another queue or removed altogether, which has much the same effect). A MessagePort also has a has been shipped flag, which must initially be false, and an owner, which is a settings object set when the object is created, as described below.

ある~port %P の`~port~message待行列$ %Q が可能化されたときは、 `~event-loop$は, %Q をその`~task源$の一つとして利用し~MUST。 %P の`所有者$が指定する`担当の~event-loop$が`閲覧文脈~event-loop$である場合、 %Q に入れられた`~task$に結付けられる文書は,[ %P の`所有者$が指定する`担当の文書$ ]にされ~MUST。 ◎ When a port's port message queue is enabled, the event loop must use it as one of its task sources. When a port's owner specifies a responsible event loop that is a browsing context event loop, all tasks queued on its port message queue must be associated with the responsible document specified by the port's owner.

注記: ~portの`所有者$が指定する`担当の文書$が`全部的に作動中$であって、~portに登録されたすべての~event~listenerの~scriptは,[ その`設定群~obj$が `全部的に作動中$でない`担当の文書$を指定する ]場合、待入された~messageたちは,失われることになる。 ◎ If the port's owner specifies a responsible document that is fully active, but the event listeners all have scripts whose settings objects specify responsible documents that are not fully active, then the messages will be lost.

各 `~event-loop$は、 `未搬送の~port~message待行列@ と呼ばれる`~task源$を持つ。 これは, “仮想の†” 待行列であり、[ 下の条件を満たす各 `MessagePort$I %P の`~port~message待行列$ ]内の~taskすべてを,~taskが待入された順序††で包含しているかのように動作し~MUST — ~taskが`未搬送の~port~message待行列$から除去されるときは、代わりに,それが実際に属する`~port~message待行列$から除去され~MUST。

ここで、各 %P は,次をすべて満たすとする:

  • %P の`搬送済み~flag$ ~EQ ~OFF
  • %P の`~port~message待行列$は可能化されている
  • %P の`所有者$が指定する`担当の~event-loop$ ~EQ 当の`~event-loop$

【† “仮想の” — すなわち、いくつかの待行列を包装するだけの,それ自身は実体を持たない待行列。 】【†† 異なる`~port~message待行列$に属する~taskどうしの,`未搬送の~port~message待行列$の中での順序がどう定義されるのかは、明確に述べられていない(単に時系列順?)。 】

◎ Each event loop has a task source called the unshipped port message queue. This is a virtual task source: it must act as if it contained the tasks of each port message queue of each MessagePort whose has been shipped flag is false, whose port message queue is enabled, and whose owner specifies that event loop as the responsible event loop, in the order in which they were added to their respective task source. When a task would be removed from the unshipped port message queue, it must instead be removed from its port message queue.

[ `MessagePort$I の`搬送済み~flag$ ~EQ ~OFF ]の下では、その`~port~message待行列$は,`~event-loop$の目的においては無視され~MUST(代わりに,`未搬送の~port~message待行列$が利用される)。 ◎ When a MessagePort's has been shipped flag is false, its port message queue must be ignored for the purposes of the event loop. (The unshipped port message queue is used instead.)

注記: `MessagePort$I ~obj %P の`搬送済み~flag$は、[ %P, %P の相手~側~port, %P の~clone元~obj ]のいずれかが,転送されるか, すでにされている ]ときに ~ON にされる。 %P の`搬送済み~flag$が ~ON にされて以降は、 %P の`~port~message待行列$は first-class `~task源$ `すなわち, “通常の,独立な” ~task源^tnote として動作し,`未搬送の~port~message待行列$には影響しなくなる `その一部を成さなくなる^tnote。 ◎ The has been shipped flag is set to true when a port, its twin, or the object it was cloned from, is or has been transferred. When a MessagePort's has been shipped flag is true, its port message queue acts as a first-class task source, unaffected to any unshipped port message queue.

~UAは,所与の`環境~設定群~obj$ %所有者 から `新たな~MessagePort~objを作成-@ するときは、新たな `MessagePort$I ~objを,[ その`所有者$ ~SET %所有者 ]にした上で 返さ~MUST。 ◎ When the user agent is to create a new MessagePort object with a particular environment settings object as its owner, it must instantiate a new MessagePort object, and let its owner be owner.

~UAは, 2 個の `MessagePort$I ~obj %A, %B を `連絡-@ するときは、次の手続きを走らせ~MUST: ◎ When the user agent is to entangle two MessagePort objects, it must run the following steps:

  1. ~FOR ~EACH ( %P ~IN { %A, %B } ) に対し ⇒ ~IF[ %P に連絡されている別の `MessagePort$I ~obj %Q がある ] ⇒ %P と %Q との連絡を解く ◎ If one of the ports is already entangled, then disentangle it and the port that it was entangled with.

    注記: %P, %Q が,ある `MessageChannel$I ~obj %C の 2 個の~portであった場合、 %C は最早~実際の~channelを表現しなくなる — それ以降、 %P と %Q が連絡されることはない。 ◎ If those two previously entangled ports were the two ports of a MessageChannel object, then that MessageChannel object no longer represents an actual channel: the two ports in that object are no longer entangled.

  2. %A, %B を連絡されるように結付ける — ある新たな~channelの 2 個の部位を形成するように(その~channelを表現する `MessageChannel$I ~objは,まだない) ◎ Associate the two ports to be entangled, so that they form the two parts of a new channel. (There is no MessageChannel object that represents this channel.)

    この時点で %A, %B は 互いに連絡されたことになる ◎ Two ports A and B that have gone through this step are now said to be entangled; one is entangled to the other, and vice versa.

    注記: この仕様は,この処理-を instantaneous として述べるが、実装は,~message passing を介して実装する見込みが高い`?^tnote。 要は、他の~algoと同様,その最終的な結果が、~black-box的意味で “単に” 仕様が定めるものと判別できなければよい。 ◎ While this specification describes this process as instantaneous, implementations are more likely to implement it via message passing. As with all algorithms, the key is "merely" that the end result be indistinguishable, in a black-box sense, from the specification.


`MessagePort$I ~objは`転送可能~obj$である。 ◎ MessagePort objects are transferable objects. Their transfer steps, given value and dataHolder, are:

その`転送-手続き$は、所与の ( %値, %~data保持体 ) に対し,次を走らす: ◎ ↑

  1. %値 の`搬送済み~flag$ ~SET ~ON ◎ Set value's has been shipped flag to true.
  2. %~data保持体 . `PortMessageQueue^sl ~SET %値 の`~port~message待行列$ ◎ Set dataHolder.[[PortMessageQueue]] to value's port message queue.
  3. ~IF[ ある別~port %~remote~port が %値 に連絡されている ]: ◎ If value is entangled with another port remotePort, then:

    1. %~remote~port の`搬送済み~flag$ ~SET ~ON ◎ Set remotePort's has been shipped flag to true.
    2. %~data保持体 . `RemotePort^sl ~SET %~remote~port ◎ Set dataHolder.[[RemotePort]] to remotePort.

  4. ~ELSE ⇒ %~data保持体 . `RemotePort^sl ~SET ~NULL ◎ Otherwise, set dataHolder.[[RemotePort]] to null.

その`転送-受信-時の手続き$は、所与の ( %~data保持体, %値 ) に対し,次を走らす: ◎ Their transfer-receiving steps, given dataHolder and value, are:

  1. %値 の`搬送済み~flag$ ~SET ~ON ◎ Set value's has been shipped flag to true.
  2. %所有者 ~LET %値 に`関連する設定群~obj$ ◎ ↓
  3. %値 の`所有者$ ~SET %所有者 ◎ Set value's owner to value's relevant settings object.
  4. %~data保持体 . `PortMessageQueue^sl 内の[ `message$et ~eventを発火する`~task$ ]すべてを %値 の`~port~message待行列$に移動する — その際には:

    • %値 の`~port~message待行列$は,(初期~時の)不能化~状態のまま変えない
    • [ %所有者 が指定する`担当の~event-loop$は `閲覧文脈~event-loop$である ]場合、移動された`~task$に, %所有者 が指定する`担当の文書$を結付ける
    ◎ Move all the tasks that are to fire message events in dataHolder.[[PortMessageQueue]] to the port message queue of value, if any, leaving value's port message queue in its initial disabled state, and, if value's owner specifies a responsible event loop that is a browsing context event loop, associating the moved tasks with the responsible document specified by value's owner.
  5. ~IF[ %~data保持体 . `RemotePort^sl ~NEQ ~NULL ] ⇒ ( %~data保持体 . `RemotePort^sl, %値 ) を`連絡-$する (これは、元の転送された~portと %~data保持体 . `RemotePort^sl との連絡を解くことになる。) ◎ If dataHolder.[[RemotePort]] is not null, then entangle dataHolder.[[RemotePort]] and value. (This will disentangle dataHolder.[[RemotePort]] from the original port that was transferred.)

``postMessage( message, transfer )@m

被呼出時には、次の手続きを走らせ~MUST: ◎ The postMessage(message, transfer) method, when invoked on a MessagePort object, must run the following steps:

  1. %宛先~port ~LET 此れに連絡されている~portが[ あれば それ / なければ ~NULL ] ◎ Let targetPort be the port with which this MessagePort is entangled, if any; otherwise let it be null.
  2. ~IF[ %transfer 内に此れがある† ] ⇒ ~THROW `DataCloneError$E ◎ If any of the objects in transfer are this MessagePort, then throw a "DataCloneError" DOMException and abort these steps.

    【† “内にある” が、 “配列~内に直接的に含まれている” ことを意味するのか,深く入子にされて含まれている場合も含めるのか、はっきりしない。 (後者については、下の `StructuredCloneWithTransfer$jA() にて取扱われるのかも?) 】

  3. %破棄予定 ~LET ~F ◎ Let doomed be false.
  4. ~IF[ %宛先~port ~NEQ ~NULL ]~AND[ %transfer 内に %宛先~port はある ]:

    1. %破棄予定 ~SET ~T
    2. 任意選択で ⇒ %宛先~port が自身に向けて投函された結果,通信~channelは失われることを、~UAの開発者~consoleに報告する
    ◎ If targetPort is not null and any of the objects in transfer are targetPort, then set doomed to true, and optionally report to a developer console that the target port was posted to itself, causing the communication channel to be lost.
  5. %転送-を伴う直列化-結果 ~LET `StructuredSerializeWithTransfer$jA( %message, %transfer ) (例外投出あり) ◎ Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.
  6. ~IF[ %宛先~port ~EQ ~NULL ]~OR[ %破棄予定 ~EQ ~T ] ⇒ ~RET ◎ If there is no targetPort (i.e. if this MessagePort is not entangled), or if doomed is true, then abort these steps.
  7. 次の手続きを走らす`~task$を %宛先~port の`~port~message待行列$に追加する: ◎ Add a task that runs the following steps to the port message queue of targetPort:

    1. %最終~宛先~port ~LET この~taskが見出される`~port~message待行列$を持つ `MessagePort$I ~obj ◎ Let finalTargetPort be the MessagePort in whose port message queue the task now finds itself.

      これは %宛先~port と異なり得る — %宛先~port 自身が転送されるに伴い,その~taskすべても移動された場合には。 ◎ This can be different from targetPort, if targetPort itself was transferred and thus all its tasks moved along with it.

    2. %宛先~Realm ~LET %最終~宛先~port に`関連する~Realm$ ◎ Let targetRealm be finalTargetPort's relevant Realm.
    3. %逆直列化-~record ~LET `StructuredDeserializeWithTransfer$jA( %転送-を伴う直列化-結果, %宛先~Realm ) ◎ Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).
    4. %~message~clone ~LET %逆直列化-~record . `Deserialized^sl ◎ Let messageClone be deserializeRecord.[[Deserialized]].
    5. %新~port~list ~LET %逆直列化-~record . `TransferredValues^sl 内の すべての `MessagePort$I ~objからなる,同順の新たな`凍結~配列$ ◎ Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]], if any, maintaining their relative order.
    6. %~event ~LET %宛先~Realm 内の `MessageEvent$I を用いて`~eventを作成-$した結果 ◎ Let e be the result of creating an event using MessageEvent in targetRealm.
    7. %~event の ( `type$m, `data$m, `ports$m ) 属性 ~SET ( `message$et, %~message~clone, %新~port~list ) に初期化する ◎ Initialize e's type attribute to message, its data attribute to messageClone, and its ports attribute to newPorts.
    8. %最終~宛先~port に向けて %~event を`配送-$する ◎ Dispatch e at finalTargetPort.
``start()@m
被呼出時には、まだ可能化されていなければ,此れの`~port~message待行列$を可能化し~MUST。 ◎ The start() method must enable its port's port message queue, if it is not already enabled.
``close()@m
被呼出時には、此れに別~portが連絡されていれば,それを解か~MUST。 ◎ The close() method, when called on a port local port that is entangled with another port, must cause the user agent to disentangle the two ports. If the method is called on a port that is not entangled, then the method must do nothing.

`MessagePort$I ~interfaceを実装している~すべての~objは、以下に挙げる`~event~handler$, および対応する`~event~handler~event型$を,`~event~handler~IDL属性$として~supportし~MUST: ◎ The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the MessagePort interface:

`~event~handler$ `~event~handler~event型$
``onmessage@m `message$et

%P の`~port~message待行列$は、 `MessagePort$I ~obj %P の ``onmessage$m ~IDL属性が初回に設定された時点で, %P の ``start()$m ~methodが~callされたかのように可能化され~MUST。 ◎ The first time a MessagePort object's onmessage IDL attribute is set, the port's port message queue must be enabled, as if the start() method had been called.

9.5.4. 多数の~portへの~broadcast法

~INFORMATIVE

多数の~portへ~broadcastすることは、原則的には,比較的~単純であり、~messageを送信-用の `MessagePort$I ~objからなる配列を保っておいて,配列~内を反復して, ~messageを送信すればよい。 しかしながら、相手~側が消去っても それらの~portを~garbage収集できなくなるという,困った効果もある。 この問題を避けるには、相手~側から自身の存在を認知させるような,単純な~protocolを実装するとよい — 一定時間そうしなかったなら,消去ったと見做して、 `MessagePort$I ~objを~closeすることにより,~garbage収集に任せるような。 ◎ Broadcasting to many ports is in principle relatively simple: keep an array of MessagePort objects to send messages to, and iterate through the array to send a message. However, this has one rather unfortunate effect: it prevents the ports from being garbage collected, even if the other side has gone away. To avoid this problem, implement a simple protocol whereby the other side acknowledges it still exists. If it doesn't do so after a certain amount of time, assume it's gone, close the MessagePort object, and let it be garbage collected.

9.5.5. ~portと~garbage収集

`MessagePort$I ~obj %O が連絡されたときは、~UAは,次のいずれかから %O への強い参照-があるかのように動作し~MUST:

  • %O に連絡されている `MessagePort$I ~obj
  • %O の`所有者$が指定する`大域~obj$enV
◎ When a MessagePort object o is entangled, user agents must either act as if o's entangled MessagePort object has a strong reference to o, or as if the global object specified by o's owner has a strong reference to o.

注記: したがって,~message~portは、受信して~event~listenerをあてがった後は,放置しておくこともできる — その~event~listenerが~messageを受信できる限り,~channelは維持される。 ◎ Thus, a message port can be received, given an event listener, and then forgotten, and so long as that event listener could receive a message, the channel will be maintained.

無論,これが当の~channelの両~側に生じた場合、両~portとも~garbage収集され得る — それらは、互いに強い参照-があるとしても,生きた~codeからは到達できなくなるので。 ◎ Of course, if this was to occur on both sides of the channel, then both ports could be garbage collected, since they would not be reachable from live code, despite having a strong reference to each other.

更には, `MessagePort$I ~obj %O は、次のいずれかが満たされている間は,~garbage収集されては~MUST_NOT:

  • ある`~task待行列$内の ある`~task$が、 %O に向けて配送される~eventを参照している
  • %O の`~port~message待行列$は、空でない, かつ 可能化されている
◎ Furthermore, a MessagePort object must not be garbage collected while there exists an event referenced by a task in a task queue that is to be dispatched on that MessagePort object, or while the MessagePort object's port message queue is enabled and not empty.

注記: 作者には、 `MessagePort$I ~objを明示的に~closeして,それらの連絡を解くことが強く奨励される — そうすれば、それらの資源は再収集できるようになる。 多数の `MessagePort$I ~objを作成して,それらを~closeすることなく破棄することは、一時的に多量の~memoryを~~消費させ得る — ~garbage収集は、とりわけ, `MessagePort$I に対する~garbage収集に~cross-processの協調も孕まれ得る所では、即座に遂行されるとは限らないので。 ◎ Authors are strongly encouraged to explicitly close MessagePort objects to disentangle them, so that their resources can be recollected. Creating many MessagePort objects and discarding them without closing them can lead to high transient memory usage since garbage collection is not necessarily performed promptly, especially for MessagePorts where garbage collection can involve cross-process coordination.

9.6. 他の閲覧文脈への~broadcast法

ときには、[ 同じ~UA内で同じ利用者により~openされているが,互いに関係しない異なる`閲覧文脈$内にある ]ような,同じ`生成元$に属する複数の頁どうしが、互いに通知を送信しあう必要が生じることもある。 例えば、 “利用者がこっちに~log-inしたから、そっちでも資格証を再度~検査してくれ” 。 ◎ Pages on a single origin opened by the same user in the same user agent but in different unrelated browsing contexts sometimes need to send notifications to each other, for example "hey, the user logged in over here, check your credentials again".

もっと手の込んだ事例においては、`共用~worker$が最も適切な解決策になる — 例えば: 共有されている状態の~lockingを管理する / ~serverと複数の局所~clientとの間で 資源の同期を管理する / `WebSocket$I 接続を~remote~hostと共有する,等々。 ◎ For elaborate cases, e.g. to manage locking of shared state, to manage synchronization of resources between a server and multiple local clients, to share a WebSocket connection with a remote host, and so forth, shared workers are the most appropriate solution.

共用~workerでは大げさにすぎるような単純な事例では、作者は,この節に述べる 単純な~channelに基づく~broadcastの仕組みを利用できる。 ◎ For simple cases, though, where a shared worker would be an unreasonable overhead, authors can use the simple channel-based broadcast mechanism described in this section.

[``Constructor$m(DOMString %name), Exposed=(Window,Worker)]
interface `BroadcastChannel@I : `EventTarget$I {
  readonly attribute DOMString ``name$m;
  void ``postMessage$m(any %message);
  void ``close$m();
  attribute `EventHandler$I ``onmessage$m;
};
%broadcastChannel = new `BroadcastChannel(name)$m
~channel名 %name の~channelを介して~messageを[ 送信できる/受信できる ]ような,新たな `BroadcastChannel$I ~objを返す。 ◎ Returns a new BroadcastChannel object via which messages for the given channel name can be sent and received.
%broadcastChannel . ``name$m
(構築子に渡された)~channel名を返す。 ◎ Returns the channel name (as passed to the constructor).
%broadcastChannel . ``postMessage( message )$m
所与の~messageを,この~channelに設定しておかれた 他の `BroadcastChannel$I ~objへ送信する。 ~messageは、入子の~objや配列など,有構造~dataも可能である。 ◎ Sends the given message to other BroadcastChannel objects set up for this channel. Messages can be structured objects, e.g. nested objects and arrays.
%broadcastChannel . ``close()$m
`BroadcastChannel$I ~objを~closeして,~garbage収集に委ねる。 ◎ Closes the BroadcastChannel object, opening it up to garbage collection.

`BroadcastChannel$I ~objは、次のものを持つ:

`~channel名@
共有する通信~channelを識別する文字列。
`~BroadcastChannel設定群~obj@
`環境~設定群~obj$。
`~close済み~flag@
~ON ならば、通信は~closeされたことを指示する。
◎ A BroadcastChannel object has a channel name, a BroadcastChannel settings object, and a closed flag.
`BroadcastChannel( name )@m

この構築子の被呼出時には、次のように設定された新たな `BroadcastChannel$I ~objを返さ~MUST:

  • `~channel名$ ~SET %name
  • `~BroadcastChannel設定群~obj$ ~SET `現任の設定群~obj$
  • `~close済み~flag$ ~SET ~OFF
◎ The BroadcastChannel() constructor, when invoked, must create and return a BroadcastChannel object whose channel name is the constructor's first argument, whose BroadcastChannel settings object is the incumbent settings object, and whose closed flag is false.
``name@m
取得子は、此れの`~channel名$を返さ~MUST。 ◎ The name attribute must return the channel name.
``postMessage( message )@m

被呼出時には、次の手続きを走らせ~MUST: ◎ The postMessage(message) method, when invoked on a BroadcastChannel object, must run the following steps:

  1. %~source設定群 ~LET 此れの`~BroadcastChannel設定群~obj$ ◎ Let source be this BroadcastChannel. ◎ Let sourceSettings be source's BroadcastChannel settings object.
  2. ~IF[ 此れの`~close済み~flag$ ~EQ ~ON ] ⇒ ~THROW `InvalidStateError$E ◎ If source's closed flag is true, then throw an "InvalidStateError" DOMException and abort these steps.
  3. %~source~channel ~LET 此れの`~channel名$ ◎ Let sourceChannel be source's channel name.
  4. %宛先~Realm ~LET ~UAにより定義される~Realm ◎ Let targetRealm be a user-agent defined Realm.
  5. %直列形 ~LET `StructuredSerialize$jA( %~message, %宛先~Realm ) (例外投出あり) ◎ Let serialized be StructuredSerialize(message). Rethrow any exceptions.
  6. %行先~list ~LET 次をすべて満たす `BroadcastChannel$I ~obj %O すべてからなる~list: ◎ Let destinations be a list of BroadcastChannel objects that match the following criteria:

    • %O の`~BroadcastChannel設定群~obj$を %設定群, %設定群 が指定する`大域~obj$enV を %G とするとき: ◎ Their BroadcastChannel settings object specifies either:

      • 次のいずれかが満たされる:

        • [ %G は `Window$I ~objである ]~AND[ %設定群 の`担当の文書$は`全部的に作動中$である ] ◎ a global object that is a Window object and a responsible document that is fully active, or
        • [ %G は `WorkerGlobalScope$I ~objである ]~AND[ %G の `~closing~flag$ ~EQ ~F ]~AND[ %G の`~worker$は`休止可能$である ] ◎ a global object that is a WorkerGlobalScope object whose closing flag is false and whose worker is a suspendable worker.
      • ( %設定群 の`生成元$enV, %~source設定群 の`生成元$enV ) は`同一生成元$である ◎ Their BroadcastChannel settings object's origin is same origin with sourceSettings's origin.
    • %O の`~channel名$ ~EQ %~source~channel ◎ Their channel name is a case-sensitive match for sourceChannel.
    • %O の`~close済み~flag$ ~EQ ~OFF ◎ Their closed flag is false.
  7. %行先~list から此れを除去する ◎ Remove source from destinations.
  8. %行先~list を,次が満たされるように~sortする ⇒ %行先~list 内の `BroadcastChannel$I ~objのうち,[ その`~BroadcastChannel設定群~obj$が同じ`担当の~event-loop$を指定するもの ]どうしは、古いものから,作成した順に並ぶ (これは、完全な順序付けは定義しない。~UAは、この拘束の下で,自身が定義する方式で更に~sortしてよい。) ◎ Sort destinations such that all BroadcastChannel objects whose BroadcastChannel settings objects specify the same responsible event loop are sorted in creation order, oldest first. (This does not define a complete ordering. Within this constraint, user agents may sort the list in any user-agent defined manner.)
  9. %行先~list 内の ~EACH( `BroadcastChannel$I ~obj %行先 ) に対し ⇒ 次の手続きを走らす`~taskを待入する$: ◎ For each BroadcastChannel object destination in destinations, queue a task that runs the following steps:

    1. %宛先~Realm ~LET %行先 に`関連する~Realm$ ◎ Let targetRealm be destination's relevant Realm.
    2. %~data ~LET `StructuredDeserialize$jA( %直列形, %宛先~Realm ) ◎ Let data be StructuredDeserialize(serialized, targetRealm).
    3. %行先 に向けて,次のように初期化された 名前 `message$et の`~eventを発火-$する

      • `MessageEvent$I ~interfaceを利用する
      • `data$m 属性 ~SET %~data
      • `origin$m 属性 ~SET %~source設定群 の`生成元$enVの`~Unicode直列化$
      ◎ Fire an event named message at destination, using MessageEvent, with the data attribute initialized to data and the origin attribute initialized to the Unicode serialization of sourceSettings's origin.

    この段の`~task$に対しては、次が要求される:

    • `~DOM操作~task源$を利用する
    • %行先 の`~BroadcastChannel設定群~obj$ %O が指定する`~event-loop$が`閲覧文脈~event-loop$である場合、~taskに結付けられる文書は, %O が指定する`担当の文書$とする
    ◎ The tasks must use the DOM manipulation task source, and, for those where the event loop specified by the target BroadcastChannel object's BroadcastChannel settings object is a browsing context event loop, must be associated with the responsible document specified by that target BroadcastChannel object's BroadcastChannel settings object.

`BroadcastChannel$I ~obj %O に対しては、次がいずれも満たされている間は,[ %O の`~BroadcastChannel設定群~obj$が指定する`大域~obj$enV ]から %O への強い参照-が~MUST:

  • %O の`~close済み~flag$ ~EQ ~OFF
  • %O 向けの `message$et ~eventに対し登録されている~event~listenerがある
◎ While a BroadcastChannel object whose closed flag is false has an event listener registered for message events, there must be a strong reference from global object specified by the BroadcastChannel object's BroadcastChannel settings object to the BroadcastChannel object itself.
``close()@m
被呼出時には、[ 此れの`~close済み~flag$ ~SET ~ON ]にし~MUST ◎ The close() method must set the closed flag of the BroadcastChannel object on which it was invoked to true.

注記: 作者には、 `BroadcastChannel$I ~objが不要になり次第,~UAが~garbage収集できるように 明示的に~closeすることが強く奨励される。 多数の `BroadcastChannel$I ~objを作成して,~event~listenerを伴わせたまま ~closeすることなく破棄した場合、目に見える~memory漏洩-をもたらす — それらの~objは、~event~listenerがある限り(または、それらが属する[ 頁/~worker ]が~closeされるまで),生き残り続けようとするので。 ◎ Authors are strongly encouraged to explicitly close BroadcastChannel objects when they are no longer needed, so that they can be garbage collected. Creating many BroadcastChannel objects and discarding them while leaving them with an event listener and without closing them can lead to an apparent memory leak, since the objects will continue to live for as long as they have an event listener (or until their page or worker is closed).


`BroadcastChannel$I ~interfaceを実装している~すべての~objは、以下に挙げる`~event~handler$, および対応する`~event~handler~event型$を,`~event~handler~IDL属性$として~supportし~MUST: ◎ The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the BroadcastChannel interface:

`~event~handler$ `~event~handler~event型$
``onmessage@m `message$et

ある頁が利用者が,いつ~log-outしたか知りたいと求めているとする — 同じ~siteに属する別の~tabの頁から利用者がそうしたときでも: ◎ Suppose a page wants to know when the user logs out, even when the user does so from another tab at the same site:

var %authChannel = new BroadcastChannel('auth');
%authChannel.onmessage = function (%event) {
  if (%event.data == 'logout')
    showLogout();
}

function logoutRequested() {
  /* 
利用者から~log-outを請われたとき,~callされる
◎
called when the user asks us to log them out
 */
  doLogout();
  showLogout();
  %authChannel.postMessage('logout');
}

function doLogout() {
  /* 
利用者は実際に~log-outした(例: ~cookieを~clearするなど)
◎
actually log the user out (e.g. clearing cookies)
 */
  // ...
}

function showLogout() {
  /* 
~log-outしたことを指示するように,~UIを更新する
◎
update the UI to indicate we're logged out
 */
  // ...
}