* 仕様書

[REFS[
- [2] [CITE@en[RFC 8030 - Generic Event Delivery Using HTTP Push]], [TIME[2020-03-09 00:13:33 +09:00]] <https://tools.ietf.org/html/rfc8030>
- [73] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#dfn-push-subscription>
- [77] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#dfn-push-endpoint>
- [78] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#dfn-subscription-expiration-time>
- [90] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#dfn-refresh>
- [103] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#dfn-deactivate>
- [105] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#security-and-privacy-considerations>
- [113] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#pushsubscriptionoptions-interface>
- [118] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#pushsubscriptionoptionsinit-dictionary>
- [123] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#pushsubscription-interface>
- [160] [CITE@en-US[Push API]], [TIME[2020-02-04 16:21:34 +09:00]] <https://w3c.github.io/push-api/#events>
]REFS]

* 意味

[3] 
[DFN[[RUBYB[プッシュメッセージ購読][push message subscription]]]]は、
[[利用者エージェント]]と[[プッシュサービス]]の間で確立された[RUBYB[メッセージ配送文脈][message delivery context]]であって、
[[アプリケーションサーバー]]と共有されるものです。
[[プッシュメッセージ]]はすべてある[[プッシュメッセージ購読]]と関連付けられています。
[SRC[>>2 1.1.]]
[[プッシュサービス資源]]により作成されます。

[74] 
[DFN[[RUBYB[プッシュ購読][push subscription]]]]は、
[[利用者エージェント]]と[[プッシュサービス]]の間に、
[[Webアプリケーション]]にかわって確立されたメッセージ配送文脈です。
[SRC[>>73]]



[4] [[プッシュメッセージ購読集合]]の[[要素]]です。

[5] [[RFC 8030]] が [DFN[message subscription]]、
[DFN[subscription]] とだけ言っているものも、
[[プッシュメッセージ購読]]を意味すると思われます。

[FIG(list members)[ [14] [[プッシュ購読]] ([[アプリケーションサーバー]])

: [F[プッシュエンドポイント]] :
[[絶対URL]]。
作成時に[[利用者エージェント]]から得たもの。
: [F[購読満期時刻]] :
[[ミリ秒Unix time]]または [CODE[null]]。
作成時に[[利用者エージェント]]から得たもの。
: [F[[CODE[aes128gcm]] 用鍵ペア][aes128gcm]] : [[公開鍵]]のみ。
[[利用者エージェント]]から得たもの。
[[公開鍵]]と[[秘密鍵]]。
: [F[authentication secret][aes128gcm]] : 
[[利用者エージェント]]から得たもの。
: [F[特定[[アプリケーションサーバー]]に制限されている]] :
[[プッシュ購読]]作成時に [[VAPID 用のアプリケーションサーバーの公開鍵][applicationServerKey]]が指定されたかどうか。
: [F[[[VAPID]] 用[[鍵ペア]] : [[公開鍵]]、[[秘密鍵]]。
作成時までに生成したもの。


]FIG]

[FIG(list members)[ [15] [[プッシュ購読]] ([[プッシュサービス]])

: [F[プッシュエンドポイント]] :
[[絶対URL]]。作成時に生成したもの。
: [F[購読満期時刻]] :
[[ミリ秒Unix time]]または [CODE[null]]。
作成時に決定したもの。
: [F[特定[[アプリケーションサーバー]]に制限されている]] :
[[プッシュ購読]]作成時に [[VAPID 用のアプリケーションサーバーの公開鍵][applicationServerKey]]が指定されたかどうか。
: [F[[[VAPID]] 用[[鍵ペア]] : [[公開鍵]]のみ。
作成時に[[利用者エージェント]]から提供されたもの。
: [F[プッシュメッセージ購読資源]] :
[[絶対URL]]。作成時に生成したもの。
: [F[プッシュメッセージ購読集合]] :
所属する[[プッシュメッセージ購読集合]]または [CODE[null]]。
作成時に決定したもの。

]FIG]

[FIG(list members)[ [75] [[プッシュ購読]] ([[利用者エージェント]])
: [F[サービスワーカー登録]] :
[[プッシュ購読]]は、
[[サービスワーカー登録]]に関連付けられます。
[[サービスワーカー登録]]は、[[高々]]1つ[[プッシュ購読]]を持ちます。
[SRC[>>73]]
破棄されて存在しなくなることがあります。
: [F[プッシュエンドポイント]] :
[[絶対URL]]。
: [F[購読満期時刻]] :
[[ミリ秒Unix time]]または [CODE[null]]。
: [F[[CODE[aes128gcm]] 用鍵ペア][aes128gcm]] : [[作成][プッシュサービス資源]]時に設定された[[鍵ペア]]。 [SRC[>>73]]
[[公開鍵]]と[[秘密鍵]]。
: [F[authentication secret][aes128gcm]] : [[作成][プッシュサービス資源]]時に設定された [[authentication secret]]。 [SRC[>>73]]
: [F[options][PushSubscriptionOptions]] :
作成時に作成された
[CODE[PushSubscriptionOptions]]。
[F[[CODE[userVisibleOnly]]]] を持つ。
: [F[[[非活性化][プッシュ購読の非活性化]]済み]] :
: [F[[CODE[push][onpush]]拒絶履歴]] :
[SEE[ [[プッシュメッセージの受信]] ]]
: [F[[[VAPID]] 用[[鍵ペア]]]] : [[公開鍵]]のみ
(= [F[options][PushSubscriptionOptions]]
の
[F[[CODE[applicationServerKey]]]])。
作成時に[[アプリケーション]]から提供されたもの。
: [F[プッシュメッセージ購読資源]] :
[[絶対URL]]。作成時に[[プッシュサービス]]から通知されたもの。
: [F[プッシュメッセージ購読集合]] :
所属する[[プッシュメッセージ購読集合]]または [CODE[null]]。
作成時に[[プッシュサービス]]から通知されたもの。


]FIG]

[125] 
[DFN[[CODE[PushSubscription]]]]
[[インターフェイス]]は、
[[プッシュ購読]]を表します。
[[文書環境]]と[[ワーカー環境]]に[[晒され]]ます。
[CODE[SecureContext]] のみ利用可能です。
[SRC[>>123]]

[FIG(short list)[ [126] [CODE[PushSubscription]] [[インターフェイス]]
- [CODE[endpoint][プッシュエンドポイント]]
- [CODE[expirationTime]]
- [CODE[options][PushSubscriptionOptions]]
- [CODE[getKey]]
- [CODE[unsubscribe]]
- [CODE[toJSON]]
]FIG]

-*-*-

[134] 
[CODE[PushSubscription]]
[[インターフェイス]]の
[DFN[[CODE[getKey]]]]
[[メソッド]] [SRC[>>123]] は、
次のようにしなければ[MUST[なりません]]。

[FIG(steps)[
= [135] [VAR[名前]]を、
第1引数を
[CODE[PushEncryptionKeyName]]
と解釈した結果に設定します。
[SRC[>>123]]
= [157] [VAR[鍵]]を、
[[文脈オブジェクト]]、[VAR[名前]]について鍵を取得した結果に設定します。
= [158] [VAR[鍵]]の [CODE[ArrayBuffer]] を返します。
]FIG]

[159] [DFN[[CODE[PushEncryptionKeyName]]]]
は、
[DFN[[CODE[p256dh]]]]
か
[DFN[[CODE[auth]]]]
です。
[SRC[>>123]]


[156] 
鍵の取得は、
[VAR[プッシュ購読]]、[VAR[名前]]について、
次のようにします。
[SRC[>>123]]

[FIG(steps)[
= [136] [VAR[名前]]が [CODE[p256dh]] の場合、
== [141] [VAR[鍵]]を、
[[文脈オブジェクト]]の[F[鍵ペア]]の[F[公開鍵]]を
[[X9.62]] [[uncompressed format]]
で符号化したものに設定します。
= [137] [VAR[名前]]が [CODE[auth]] の場合、
== [142] 
[VAR[鍵]]を、
[[文脈オブジェクト]]の
[F[authentication secret]]
に設定します。
= [143] [[鍵]]を返します。

]FIG]

;; [138] [[仕様書]]では将来的な[VAR[名前]]の拡張が想定されており、また
[CODE[aes128gcm]]
を使わない場合も一応想定されているので、
[[仕様書]]の記述はここで示したものより抽象的な形になっています。
すなわち、[[非対称鍵ペア]]なら[[公開鍵]]を直列化したもの、
[[対称鍵]]ならそれを直列化したもので、
該当なければ [CODE[null]]
です [SRC[>>123]]。
[[秘密鍵]]にアクセスする方法はありません。

-*-*-

[131] 
[CODE[PushSubscription]]
[[インターフェイス]]の
[DFN[[CODE[options][PushSubscriptionOptions]]]]
[[属性]]の[[取得器]]は、
次のようにしなければ[MUST[なりません]] [SRC[>>123]]。

[FIG(steps)[
= [132] [[文脈オブジェクト]]の
[F[[CODE[options][PushSubscriptionOptions]]]]
を返します。
]FIG]

[133] [[プッシュ購読の作成]]時に設定されます。

[114] 
[DFN[[CODE[PushSubscriptionOptions]]]]
[[インターフェイス]]は、
[[文書環境]]と[[ワーカー環境]]に[[晒され]]ています。
[CODE[SecureContext]]
のみ利用可能です。
[SRC[>>113]]
対応する[[辞書]]
[DFN[[CODE[PushSubscriptionOptionsInit]]]]
[SRC[>>118]]
があります。
[CODE[PushSubscriptionOptionsInit]]
は[[プッシュ購読]]の追加のオプションを表します [SRC[>>118]]。
[[利用者エージェント]]は、
[[利用者]]に [[express permission]]
を求める時にこれを考慮[MAY[できます]] [SRC[>>118, >>105]]。
考慮するオプションについては、
[[プッシュメッセージ]]受信時にこれを適用する[SHOULD[べきです]]
[SRC[>>118]]。
[[プッシュ購読]]作成後にオプションを変更する方法はなく、
[CODE[unsubscribe]] して [CODE[subscribe]]
しなおすほかありません [SRC[>>118]]。


[FIG(list short)[ [115] [CODE[PushSubscriptionOptions]] / [CODE[PushSubscriptionOptionsInit]]
- [CODE[userVisibleOnly]]
- [CODE[applicationServerKey]]
]FIG]

[122] 
[[利用者エージェント]]のオプションへの対応は[[任意選択]]です。
対応しないオプションは[[晒し]]ては[MUST[なりません]]
[SRC[>>118]]。

;; [124] が[[相互運用性]]のため主要な
[[Webブラウザー]]の実装を真似るしかありません。


[116] 
[CODE[PushSubscriptionOptions]] 
[[インターフェイス]]の
[DFN[[CODE[userVisibleOnly]]]]
[[属性]]の[[取得器]] [SRC[>>113]] は、
次のようにしなければなりません。

[FIG(steps)[
= [117] [[文脈オブジェクト]]の
[F[[CODE[userVisibleOnly]]]]
を返します [SRC[>>113]]。
[CODE[boolean]] です [SRC[>>113]]。
]FIG]

[119] 
[CODE[PushSubscriptionOptionsInit]]
[[辞書]]の
[CODE[userVisibleOnly]]
は、
[CODE[boolean]]
で、[[既定値]]は[[偽]]です。
[SRC[>>118]]

[120] 
[CODE[userVisible]] が[[真]]のとき、
当該[[プッシュ購読]]は、
[[利用者]]に表示される[[プッシュメッセージ]]のみに使われることを表します。
[[利用者]]に表示とは、例えば
[[Web Notification]] のようなものをいいます。
[SRC[>>118]]
[[偽]]のとき、そうとは限らないことを表します。
[[プッシュメッセージ]]を表示といっても、
その内容がそのまま
[[Webブラウザー]]により自動的に表示されるのではなく、
[[アプリケーション]]が適宜処理する必要はあります。

-*-*-

[152] 
[CODE[PushSubscription]]
[[インターフェイス]]の
[CODE[toJSON]]
[[メソッド]]は、
次のようにしなければなりません。
[SRC[>>123]]

[FIG(steps)[
= [153] [VAR[json]] を、
新しい
[CODE[PushSubscriptionJSON]]
[[辞書]]に設定します。
[FIG(list members)[ [154] [DFN[[CODE[PushSubscriptionJSON]]]]

: [F[[CODE[endpoint]]]] : [[文脈オブジェクト]]の[F[プッシュエンドポイント]]。
: [F[[CODE[expirationTime]]]] : [[文脈オブジェクト]]の[F[購読満期時刻]]。
[CODE[DOMTimeStamp]]
または
[CODE[null]]。
: [F[[CODE[keys][getKey]]]] :
新しい [CODE[record][record<>]]
[FIG(list members)[ [CODE[record][record<>]]

: [CODE[auth]] : 
[[文脈オブジェクト]]、 [CODE[auth]]
について鍵を取得した結果を、
[[RFC 4648]] 詰めなし [[base64url]] 符号化したもの
: [CODE[p256dh]] :
[[文脈オブジェクト]]、 [CODE[p256dh]]
について鍵を取得した結果を、
[[RFC 4648]] 詰めなし [[base64url]] 符号化したもの

;; 値があるもののみ、名前順に[[整列]]

]FIG]

]FIG]
= [155] [VAR[json]] を返します。
]FIG]

-*-*-


[32] 
[DFN[[RUBYB[プッシュメッセージ購読集合][push message subscription set]]]]は、
[[利用者エージェント]]と[[プッシュサービス]]の間で確立される[RUBYB[メッセージ配送文脈][message delivery context]]であって、
複数の[[プッシュメッセージ購読]]を集めて[[集合]]としたものです。
[SRC[>>2 1.1.]]


[33] 
[[RFC]] は「subscription set」と省略して表記することもあるようです。


[34] 
[[プッシュメッセージ購読]]を集めて[[集合]]化することで、
[[プッシュサービス]]と[[利用者エージェント]]にとって効率化できます。
[SRC[>>2 4.1.]]

[35] 
[[プッシュサービス資源]]を使った[[プッシュメッセージ購読]]作成時に、
[[利用者エージェント]]は[[要求]]で[[プッシュメッセージ購読集合]]を指定し、
そこに作成した[[プッシュメッセージ購読]]を所属させることができます。


[36] 
[[プッシュサービス資源]]を使った[[プッシュメッセージ購読]]作成時に、
[[プッシュサービス]]は[[応答]]で[[プッシュメッセージ購読集合]]を示すことができます。



* プロトコル

[8] 
まず、[[利用者エージェント][利用者エージェント (プッシュ)]]は、
新しい[[プッシュメッセージ購読]]を作成します。
[SRC[>>2 2.]]
作成には[[プッシュサービス資源]]を使います。

[13] 
作成した[[プッシュメッセージ購読]]は、
[[アプリケーション][アプリケーション (プッシュ)]]依存の方法で、
[[アプリケーションサーバー][アプリケーションサーバー (プッシュ)]]へ配布します。
[SRC[>>2 2., 4.]]
特に[[プッシュ資源]]の [[URL]]
の配布は、
秘密の保護や、[[アプリケーションサーバー]]の認証を講じて漏らさないようにしなければ[MUST[なりません]]。
[SRC[>>2 4.]]



[9] 
[[アプリケーションサーバー]]は、
[[プッシュメッセージ購読]]に対し、
[[プッシュ資源]]を使って、
[[利用者エージェント]]に配送する[[プッシュメッセージ]]を、
[[プッシュサービス]]へと送信します。
[SRC[>>2 2., 2.1., 5.]]

[10] 
[[利用者エージェント]]は、
[[プッシュメッセージ購読]]を使って、
到着[[プッシュメッセージ]]がないか[[プッシュサービス]]を[RUBYB[監視][monitor]]します。
[SRC[>>2 2.]]


[11] 
[[プッシュメッセージ購読]]は[[アプリケーション]]に、
1対1で配布して使うことが期待されています。
しかしこれはプロトコル上の制約ではなく、
1つの[[アプリケーション]]が複数の[[プッシュメッセージ購読]]を作ることもできますし、
複数の[[アプリケーション]]が1つの[[プッシュメッセージ購読]]を共有することもできます。
ただ、共有すると[[セキュリティー]]や[[プライバシー]]の問題になりかねないことには要注意です。
[SRC[>>2 2.]]


** プッシュエンドポイント

[18] [[プッシュ購読]]は、
[DFN[[F[[RUBYB[[[プッシュエンドポイント]]][push endpoint]]]]]] [SRC[>>77]]
を持ちます。
[DFN[[RUBYB[プッシュ資源][push resource]]]]
([[リンク関係型]] [DFN[[CODE[urn:ietf:params:push]]]]) [SRC[>>2 2.]]
と呼ばれるのも同じものです。
[WEAK[([[資源]]は[[エンドポイント]]と実質同じ意味の [[IETF]] 語です。厳密にはそれぞれを参照。)]]

[16] 
[[プッシュ資源]]は[[プッシュ購読]]と1対1対応関係があり
[SRC[>>2 2.1.]]、
[[プッシュサービス資源]]が[[プッシュ購読]]を作成したとき、
同時に[[プッシュサービス]]上に作成されます。
[[プッシュ購読]]が削除されるとき、同時に削除されます。


[76] 
[[プッシュエンドポイント]] ([[プッシュ資源]]の [[URL]]) は、
[[プッシュサービス]]が晒した[[絶対URL]]であって、
[[アプリケーションサーバー]]が[[プッシュメッセージ]]の送信先とできるものでなければ[MUST[なりません]]。
[[プッシュエンドポイント]]は、
[[プッシュ購読]]を[[固有]]に識別するものでなければ[MUST[なりません]]。
[SRC[>>77]]
[CODE[https:]] [[URL]] でなければなりません。 [SEE[ [[プッシュサービス]] ]]

[59] [[プライバシー]]のため、
[[プッシュエンドポイント]]は特定[[利用者エージェント]]への通信と関係付けられるものであっては[MUST[なりません]]。
[[利用者]]や[[装置]]に関する情報を含めては[MUST[なりません]]。
複数の[[プッシュエンドポイント]]から相互の関係を知れるものであっては[MUST[なりません]]。
同じ[[利用者エージェント]]の[[プッシュエンドポイント]]から[[利用者エージェント]]との関係を知れるものであっては[MUST[なりません]]。
[SRC[>>2 8.2.]]
[[非活性化][プッシュ購読の非活性化]]済みの[[プッシュエンドポイント]]を再利用しては[MUST[なりません]]
[SRC[>>105]]。


[127] 
[CODE[PushSubscription]] 
[[インターフェイス]]の
[DFN[[CODE[endpoint][プッシュエンドポイント]]]]
[[属性]]の[[取得器]]は、
次のようにしなければ[MUST[なりません]]
[SRC[>>123]]。

[FIG(steps)[
= [128] [[文脈オブジェクト]]の[F[プッシュエンドポイント]]を返します。
[CODE[USVString]]
です。
]FIG]


[19] 
[[プッシュエンドポイント]]は次のように使われます。

-
[7] 
[[プッシュメッセージの送信]]で、
[[アプリケーションサーバー]]が[[プッシュ購読]]に[[プッシュメッセージ]]を受け渡すため、
[[プッシュエンドポイント]]に 
[CODE[POST]]
[[要求]]を送信します。
[SRC[>>2 2., 2.1.]]
[SEE[ [[プッシュメッセージの送信]] ]]
-- [20] 
そのため、[[プッシュサービス]]から[[利用者エージェント]]を経て[[アプリケーションサーバー]]へ共有されます。
[SRC[>>2 2., >>77]]
-
[17] 
[[プッシュメッセージ購読集合]]で、
[[プッシュ購読]]を区別するため[[プッシュエンドポイント]]が使われます。

-*-*-

[26] 
[[プッシュエンドポイント]]の [[URL]] の実例 (実例を基にした架空の例)

- [27] 
[CODE[https://android.googleapis.com/gcm/send/dxUydhng19o:ARAkukSNm67R9rk4XiNJf5WsXegtNRGZWuToMsOfCyJx8L0E1Q9mTSbbHr5OidZHeEtpTvbXd9qL5UY4fbNJ800oZCRigNtZUrdVrG8iuWIyNKviWkoc-F54KnFtje_z4eLtifaa1aH6]]
-- [28] 初期の [[GCM]] ([[Chrome]]) で使われていたもの。
- [29] 
[CODE[https://fcm.googleapis.com/fcm/send/a76z3yHPgwJ:APAOflhvo4lNXLCjSDBdXqacUUxQQ5AsgklIf91bHVzfabs64TLUVglBmb1f9TPZ2WpRGJXvhvnrkIyGUwr0-gn8ilZW0Zk0aB7eukV6icVOlWzSti2OwuKBy6_kuSEbP_piWWZ_fK0a
-- [30] [[GCM]] 改め [[FCM]] ([[Chrome]]) で使われているもの。
- [49] 
[CODE[https://updates.push.services.mozilla.com/wpush/v1/xSsd66AAABXZW8_0Ug9RKAqVt8whjcTT5ls_WLIabvelYDIAGp7OIXHw61Ul5uCaxqxU2F9xCkTiZ220pe5kJuYNtsHREc-toyC849O6gNRFbUQz81SueZSOx4OPCMp7H-U1a7GvH7P6]]
-- [50] [[Firefox]] で使われていたもの。
- [51] 
[CODE[https://updates.push.services.mozilla.com/wpush/v2/xW2OB6JH76gAAAAAgGwdqmCRdWx_JdM3AVDyobT38r8eKJgQFbaL_iR2hM2UrO96kyLmFWQb6eEkdM6OJain1Cr3MLH5cQ2OdlukkV1ZkGhINLPVGAiSa63sE8t8A_oxFa52dp_YfLCVtVBJgyjX-b0l3Z8wZGE6A84VfppcYwUSHpqwMNaOPke]]
-- [52] [[Firefox]] で使われているもの。
- [53] 
[CODE[https://sg2p.notify.windows.com/w/?token=BRxFrpp6w1ecDQYAAdCVf69xCTF7pB2P8eod9b83D3Ibg719zX7FATNOJ8uwlGhGmrH3VwmCNPVnj70yR4GxodG9zv97uxPmoyfAtvdH%2b5DhdcLVI59yAAkM698usDNiSimulLAsQNqC4gy61lrWtM8cIHbU9kZ6qr%2fV2IcVplUFqQa8%2bvA5KQAX8R7xXXPT5nrj0NF8JMAJM8b%2bBJH2XQ7S1iFVNvlr5P1sXmA9Q7vyHc0hERz%2fopXtDHxTMXS92slcezjhKe2ybGshO2JiIoy%2f6pVzkTrhGUvwZveHJ0GN1BstGepEy7qr0D8j0kiljnSvadr1hxoGQMn%2f8wkU%2bg%2fTXvf%2b]]
-- [54] [[Edge]] で使われているもの。
- [58] 
[CODE[https://par02p.notify.windows.com/w/?token=BRxFrpp6w1ecDQYAAdCVf69xCTF7pB2P8eod9b83D3Ibg719zX7FATNOJ8uwlGhGmrH3VwmCNPVnj70yR4GxodG9zv97uxPmoyfAtvdH%2b5DhdcLVI59yAAkM698usDNiSimulLAsQNqC4gy61lrWtM8cIHbU9kZ6qr%2fV2IcVplUFqQa8%2bvA5KQAX8R7xXXPT5nrj0NF8JMAJM8b%2bBJH2XQ7S1iFVNvlr5P1sXmA9Q7vyHc0hERz%2fopXtDHxTMXS92slcezjhKe2ybGshO2JiIoy%2f6pVzkTrhGUvwZveHJ0GN1BstGepEy7qr0D8j0kiljnSvadr1hxoGQMn%2f8wkU%2bg%2fTXvf%2b]]
-- [60] [[Edge]] で使われているもの。

** プッシュメッセージ購読資源とプッシュメッセージ購読集合資源

[6] 
[DFN[[RUBYB[購読資源][subscription resource]]]]、
[DFN[[RUBYB[プッシュメッセージ購読資源][push message subscription resource]]]]は、
[[プッシュメッセージ購読]]から[[プッシュメッセージ]]を受信したり、
[[プッシュメッセージ購読]]を削除したりするため使います。
[SRC[>>2 2., 2.1.]]
[[利用者エージェント]]にのみ使えるものです。
[SRC[>>2 2.1.]]

[37] 
[DFN[[RUBYB[プッシュメッセージ購読集合資源][push message subscription set resource]]]]
([[リンク関係型]] [DFN[[CODE[urn:ietf:params:push:set]]]])
は、
[[プッシュメッセージ購読]]の[[集成]]に対する読み取りや削除のアクセスを提供します。
[[利用者エージェント]]は、
[[集合]]中すべての[[プッシュメッセージ購読]]の[[プッシュメッセージ]]を受信できます。
[SRC[>>2 2.1.]]

[21] 
[[プッシュメッセージ購読資源]]は[[プッシュ資源]]と1対1対応関係を持ちます。
[SRC[>>2 2.1.]]
[[プッシュメッセージ購読集合資源]]は、
[[利用者エージェント]]単位で複数の[[プッシュメッセージ購読資源]]を集約したようなものです。

[22] 
[[プッシュメッセージ購読資源]]と[[プッシュメッセージ購読集合資源]]は、
次のように使われます。

-
[23] 
[[プッシュメッセージの受信]]で、
[[利用者エージェント]]が[[プッシュサービス]]から[[プッシュメッセージ]]を受信する
(べく待機する)
ため、
[CODE[GET]]
[[要求]]を送信します。
[SEE[ [[プッシュメッセージの送信]] ]]
- 
[24] 
[[利用者エージェント]]が[[プッシュ購読]]や[[プッシュメッセージ購読集合]]を削除するため、
[CODE[DELETE]]
[[要求]]を送信します。
[SEE[ >>55 ]]

* 作成

[112] 
[[アプリケーション]]は、
[CODE[subscribe]]
[[メソッド]]によって新しい[[プッシュ購読を作成]]できます。
既に作成済みの場合、
[CODE[subscribe]] 
[[メソッド]]や
[CODE[getSubscription]]
[[メソッド]]によって、
[[プッシュ購読]]を取得できます。
[SEE[ [[プッシュ購読の作成]] ]]



* プッシュメッセージ送受信

[25] [[プッシュ購読]]を使って、
[[プッシュメッセージ]]を送信したり、
受信したりできます。
[SEE[ [[プッシュメッセージの送信]] ]]




* 削除

[89] 
[[プッシュ購読]]や[[プッシュメッセージ購読集合]]は、
無効化されることがあります。
[[満期]] ([RUBYB[寿命][lifetime]]到来) による場合、
[[利用者エージェント]]の指示による場合 (>>55)、
その他[[プッシュサービス]]の事情による場合があり得ます。
[SRC[>>2 2., 7.3., 7.3.1.]]

[56] 
[[プッシュメッセージ購読]]が[[満期]]になったり削除されたりした場合、
[[プッシュメッセージ購読集合]]からも削除しなければ[MUST[なりません]]。
[SRC[>>2 7.3.1.]]

[57] 
[[プッシュメッセージ購読集合]]が[[満期]]になったり削除されたりした場合、
所属する[[プッシュメッセージ購読]]もすべて[[満期]]・削除しなければなりません。
[SRC[>>2 7.3.1.]]


[12] 
[[利用者エージェント]]や[[アプリケーションサーバー]]は、
これに対応する準備が必要です。
[SRC[>>2 2., 7.3.]]

[88] 
[[プッシュ購読]]は、
[DFN[[F[[RUBYB[購読満期時刻][subscription expiration time]]]]]]
を持つことが[MAY[できます]]。
その場合、
[[ミリ秒Unix time]]であって、
[[プッシュ購読]]が[[非活性化][プッシュ購読の非活性化]]される[[時刻]]を表すものでなければ[MUST[なりません]]。
[SRC[>>78]]

[129] [CODE[PushSubscription]]
の
[DFN[[CODE[expirationTime]]]]
[[属性]]の[[取得器]]は、
次のようにしなければ[MUST[なりません]]
[SRC[>>123]]。

[FIG(steps)[
= [130] 
[[文脈オブジェクト]]の[F[購読満期時刻]]を返します。
[CODE[DOMTimeStamp]] です。
なければ [CODE[null]] を返します。
]FIG]

-*-*-

[55] 
[[利用者エージェント]]は、
[[プッシュメッセージ購読資源]]に
[CODE[DELETE]]
[[要求]]を送信して、
削除を要求できます
[SRC[>>2 7.3.]]。
その場合所属する[[プッシュメッセージ購読集合]]からも削除されます。
同様に[[プッシュメッセージ購読集合資源]]に
[CODE[DELETE]]
[[要求]]を送信して、
削除を要求できます 
[SRC[>>2 7.3.1.]]。
その場合所属するすべての[[プッシュメッセージ購読]]が同時に削除されます。


-*-*-

[91] [[利用者エージェント]]や[[プッシュサービス]]は、
いつでも、例えば一定時間経過後、
[[プッシュ購読]]を[DFN[[RUBYB[更新][refresh]]][プッシュ購読を更新]]することが[MAY[できます]]。
[SRC[>>90]]

[99] 
[[利用者エージェント]]は、
[[プッシュ購読を更新]]できない場合、
定期的にこれを再試行する[SHOULD[べきです]]。
[SRC[>>90]]

[79] 
[[利用者エージェント]]は、
[[プッシュ購読]]の[F[購読満期時刻]]の到来前に、
[[プッシュ購読の更新]]を試みる[SHOULD[べきです]]。
[SRC[>>78]]

[92] 
[[利用者エージェント]]は、[VAR[旧プッシュ購読]]の[[更新][プッシュ購読を更新]]時、
次のようにしなければ[MUST[なりません]]。
[SRC[>>90]]

[FIG(steps)[
= [93] 
[VAR[プッシュ購読]]を、
[VAR[旧プッシュ購読]]の [F[[CODE[options]]]]
について、
[[プッシュ購読を作成]]した結果に設定します。
[[非同期的]]に待ちます。
[NOTE[
[94] [VAR[旧プッシュ購読]]と[VAR[プッシュ購読]]は、
別の[F[鍵ペア]]でなければ[MUST[なりません]]。
]NOTE]
= [95] [[[CODE[pushsubscriptionchange]]イベントを発火]]します。
[FIG(list members)[
: [VAR[登録]] : [VAR[プッシュ購読]]の[F[サービスワーカー登録]]
: [VAR[旧購読]] : [VAR[旧プッシュ購読]]
: [VAR[新購読]] : [VAR[プッシュ購読]]

]FIG]
= [96] 
[[利用者エージェント]]依存の時間、
最大で[VAR[プッシュ購読]]が[[プッシュメッセージ]]を受け取るまで、
待ちます。
[NOTE[
[97] 
[[アプリケーションサーバー]]の移行を待つべく、
しばらく[VAR[旧プッシュ購読]]を受け付け続けて[MAY[構いません]]。
]NOTE]
= [98] 
[VAR[旧プッシュ購読]]を[[非活性化][プッシュ購読を非活性化]]します。


]FIG]

-*-*-

[100] 
[[利用者エージェント]]は、
[[満期]]その他の理由で[[プッシュ購読]][VAR[プッシュ購読]]が最早利用できないとき、
次のようにしなければ[MUST[なりません]]。
[SRC[>>90]]

[FIG(steps)[
= [101] [[[CODE[pushsubscriptionchange]]イベントを発火]]します。
[FIG(list members)[
: [VAR[登録]] : [VAR[プッシュ購読]]の[F[サービスワーカー登録]]
: [VAR[旧購読]] : [VAR[プッシュ購読]]
: [VAR[新購読]] : [CODE[null]]

]FIG]

]FIG]

-*-*-

[106] 
[[利用者]]は [[permission]] を[[失効]]できます。
[SEE[ [[permission]] ]]
[[利用者エージェント]]は、
[[失効]]時、
当該 [[permission]]
により作られた[[プッシュ購読]][VAR[プッシュ購読]]を次のようにしなければ[MUST[なりません]]。
[SRC[>>105]]

[FIG(steps)[
= [108] [[並列に]]、
== [109] [VAR[プッシュ購読]]を[[非活性化][プッシュ購読の非活性化]]します。
= [107] [[[CODE[pushsubscriptionchange]]イベントを発火]]して[MAY[構いません]]。
[FIG(list members)[
: [VAR[登録]] : [VAR[プッシュ購読]]の[F[サービスワーカー登録]]
: [VAR[旧購読]] : [VAR[プッシュ購読]]
: [VAR[新購読]] : [CODE[null]]

]FIG]

]FIG]


[139] 
[CODE[PushSubscription]]
[[インターフェイス]]の
[DFN[[CODE[unsubscribe]]]]
[[メソッド]]は、
次のようにしなければ[MUST[なりません]] [SRC[>>123]]。

[FIG(steps)[
= [140] [VAR[約束]]を、
[[新しい約束]]に設定します。
= [144] [VAR[約束]]を返します。
]FIG]

[145] [[非同期的]]に、
次のようにしなければ[MUST[なりません]]
[SRC[>>123]]。

[FIG(steps)[
= [146] 
[[文脈オブジェクト]]が[F[[[非活性化][プッシュ購読の非活性化]]済み]]の場合、
== [147] [VAR[約束]]を[[偽]]で[[解決]]し、
ここで停止します。
= [148] [VAR[約束]]を、[[真]]で[[解決]]します。
= [149] [[文脈オブジェクト]]を[[非活性化][プッシュ購読の非活性化]]します。
]FIG]

-*-*-


[102] 
[[利用者エージェント]]や[[プッシュサービス]]は、
[[プッシュ購読]]が[DFN[[RUBYB[非活性化][deactivated]]][プッシュ購読の非活性化]]されたとき、
その詳細情報を削除しなければ[MUST[なりません]]。
[SRC[>>103]]
それ以後当該[[プッシュ購読]]に対する[[プッシュメッセージ]]を配送しては[MUST[なりません]]。
[SRC[>>103, >>123]]

[150] 
[[利用者エージェント]]は、
[[プッシュサービス]]に対する[[プッシュ購読の非活性化]]の要求が失敗した時、
十分な時間再試行する[SHOULD[べきです]]。
[SRC[>>123]]

;; [151] 仕様書はなぜか [CODE[unsubscribe]] の場合にのみこれを規定していますが、
それ以外の事由でもそうなるべきはずです。

[104] 
[[サービスワーカー登録]]が[[登録解除]]されたとき、
[[プッシュ購読]]は[[非活性化][プッシュ購読の非活性化]]しなければ[MUST[なりません]]
[SRC[>>105]]。
それより早く[[非活性化][プッシュ購読の非活性化]]しても[MAY[構いません]]。
[SRC[>>103]]

-*-*-

[31] 
[DFN[[CODE[pushsubscriptionchange]]]]
[[イベント]]は、
[[プッシュ購読]]が[[アプリケーション]]の預かり知らぬところで変更されたことを示します。
[SRC[>>160]]

[163] 
[CODE[ServiceWorkerGlobalScope]]
[[インターフェイス]]の
[DFN[[CODE[onpushsubscriptionchange]]]]
[[属性]]は、
[[イベントハンドラーIDL属性]]です。
[SRC[>>160]]

[38] 
[DFN[[RUBYB[[CODE[pushsubscriptionchange]]イベントを発火][fire the "[CODE[pushsubscriptionchange]]" event]]]]するには、
[[サービスワーカー登録]][VAR[登録]]、
[[プッシュ購読]]または [CODE[null]] [VAR[旧購読]]、
[[プッシュ購読]]または [CODE[null]] [VAR[新購読]]について、
次のようにしなければ[MUST[なりません]]。
[SRC[>>160]]

[FIG(steps)[
= [39] 
[[fire a functional event]] します。
[FIG(list members)[

: [F[イベント名]] : [CODE[pushsubscriptionchange]]
: [F[イベントインターフェイス]] : [CODE[PushSubscriptionChangeEvent]]
: [F[[CODE[newSubscription]]]] : [VAR[新購読]]
: [F[[CODE[oldSubscription]]]] : [VAR[旧購読]]

]FIG]


]FIG]

[40] 
[DFN[[CODE[PushSubscriptionEvent]]]]
[[インターフェイス]]は、
[CODE[ExtendableEvent]]
[[インターフェイス]]を[[継承]]した[[イベントインターフェイス]]です。
[[サービスワーカー環境]]に[[晒され]]、
[CODE[SecureContext]] でのみ利用可能です。
[[イベントコンストラクター]]があります。
[DFN[[CODE[PushSubscriptionEventInit]]]]
[[辞書]]は、
[CODE[PushSubscriptionEvent]]
[[インターフェイス]]に対応する[[辞書]]で、
[CODE[ExtendableEventInit]]
を[[継承]]しています。
[SRC[>>160]]

[FIG(list short)[ [41] [CODE[PushSubscriptionEvent]] [[インターフェイスメンバー]], [CODE[PushSubscriptionEventInit]] [[辞書メンバー]]
- [CODE[ExtendableEvent]], [CODE[ExtendableEventInit]] を[[継承]]
- [CODE[oldSubscription]]
- [CODE[newSubscription]]
]FIG]

[42] 
[CODE[PushSubscriptionEvent]]
[[インターフェイス]]の
[DFN[[CODE[oldSubscription]]]]
[[属性]]の[[取得器]] [SRC[>>160]] は、
次のようにしなければ[MUST[なりません]]。

[FIG(steps)[
= [43] [[文脈オブジェクト]]の
[F[[CODE[oldSubscription]]]]
を返します。
[CODE[PushSubscription]]
または 
[CODE[null]] です。 [SRC[>>160]]
]FIG]

[44] 
[CODE[PushSubscriptionEventInit]]
の
[CODE[oldSubscription]]
は、
[CODE[PushSubscription]]
または 
[CODE[null]] です。 
既定値は 
[CODE[null]]
です。 
[SRC[>>160]]

[48] [CODE[oldSubscription]] で指定された [CODE[PushSubscription]]
は、それ以上使う[SHOULD[べきではありません]]。
データベース破損など[[利用者エージェント]]が詳細を提供できないとき、
[CODE[null]]
となることがあります。
[SRC[>>160]]

[45] 
[CODE[PushSubscriptionEvent]]
[[インターフェイス]]の
[DFN[[CODE[newSubscription]]]]
[[属性]]の[[取得器]] [SRC[>>160]] は、
次のようにしなければ[MUST[なりません]]。

[FIG(steps)[
= [46] [[文脈オブジェクト]]の
[F[[CODE[newSubscription]]]]
を返します。
[CODE[PushSubscription]]
または 
[CODE[null]] です。 [SRC[>>160]]
]FIG]


[47] 
[CODE[PushSubscriptionEventInit]]
の
[CODE[newSubscription]]
は、
[CODE[PushSubscription]]
または 
[CODE[null]] です。 
既定値は 
[CODE[null]]
です。 
[SRC[>>160]]

-*-*-

[82] 
[[利用者エージェント]]は、
[[プッシュ購読]][VAR[プッシュ購読]]について、
何らかの理由で[[鍵]]を変更せざるを得ないとき、
次のようにしなければ[MUST[なりません]]。
[SRC[>>73]]

[FIG(steps)[
= [84] [VAR[新プッシュ購読]]を、新しい[[鍵]]を使った[[プッシュ購読]]に設定します。
= [85] [[[CODE[pushsubscriptionchange]]イベントを発火]]します。
[FIG(list members)[
: [VAR[登録]] : [VAR[プッシュ購読]]の[F[サービスワーカー登録]]
: [VAR[旧購読]] : [VAR[プッシュ購読]]
: [VAR[新購読]] : [VAR[新プッシュ購読]]

]FIG]

]FIG]


* 歴史

[1] [CITE@en[Define exposure of the Push API interfaces]]
([[beverloo]]著, [TIME[2017-05-04 01:32:20 +09:00]])
<https://github.com/w3c/push-api/commit/350ee328178b1635f141412831892b16cb711305>