diff --git a/doc/Sources/user-guide.md b/doc/Sources/user-guide.md index 9f0fffe..ab8eeea 100644 --- a/doc/Sources/user-guide.md +++ b/doc/Sources/user-guide.md @@ -35,6 +35,8 @@ toc-own-page: true WEBサイトをリロードした際に「フォームを再送信しますか?」ダイアログが表示されたとき、自動でキャンセルしリロードを中止するソリューションです。 誤操作によるフォーム再送信の防止を目的としています。  +また、「フォームを再送信しますか?」というエラーページ(ERR_CACHE_MISS)が表示された場合に、自動でそのエラーページを閉じます。 + \newpage # システム要件 @@ -381,7 +383,7 @@ https://example.com/* #### @WARNING_WHEN_CLOSE_DIALOG -フォームを再送信しますか?」ダイアログをキャンセルしたとき、以下のような追加の警告ダイアログを表示します。 +「フォームを再送信しますか?」ダイアログをキャンセルしたとき、以下のような追加の警告ダイアログを表示します。 ![](user-guide/media/image31.png) @@ -392,6 +394,8 @@ https://example.com/* @WARNING_WHEN_CLOSE_DIALOG ``` +「フォームを再送信しますか?」のエラーページ(ERR_CACHE_MISS)が表示され、自動でそのエラーページを閉じるケースでは、この警告ダイアログは表示されません。 + ### 対象URL一覧 対象URL一覧については、`[TARGETS]`セクションに記載します。 diff --git a/doc/verify/sources/PreReleaseTests.md b/doc/verify/sources/PreReleaseTests.md index f95f181..8761d0f 100644 --- a/doc/verify/sources/PreReleaseTests.md +++ b/doc/verify/sources/PreReleaseTests.md @@ -33,17 +33,31 @@ #### 検証 -* https://www.google.com/ を開く - * すべてのURLを対象としている場合も、http/httpsのサイトを開いていないとアドインが動作しないため +##### ダイアログを自動でキャンセルするケース + +* `powershell doc\verify\sources\TestTools\http_server.ps1`でローカルのWebサーバーを起動する + * `http://localhost:8080`で簡易Webサーバーが起動する * `doc\verify\sources\TestTools\form.html` を開く * フォームに「test」と入力して、「送信」ボタンを押す -* 「form.html」 をリロードする +* 遷移先の http://localhost:8080 をリロードする * [ ] 「フォームを再送信しますか?」ダイアログ一瞬表示され、キャンセルされること * この状態で、2分程待機する(時間経過で拡張機能が停止しないことの確認) -* 「form.html」 をリロードする +* http://localhost:8080 をリロードする * [ ] 「フォームを再送信しますか?」ダイアログ一瞬表示され、キャンセルされること -### すべてのURLを対象にした時の動作確認(警告ダイアログ無) +##### ERR_CACHE_MISSページを自動で閉じるケース + +* `powershell doc\verify\sources\TestTools\http_server.ps1`でローカルのWebサーバーを起動する + * `http://localhost:8080`で簡易Webサーバーが起動する +* `doc\verify\sources\TestTools\form.html` を開く +* 「フォームをダイアログで開くボタン」を押す + * ポップアップダイアログが開く +* フォームに「test」と入力して、「送信」ボタンを押す +* 遷移先の http://localhost:8080 で右クリックし、「戻る」を押す +* 遷移先の 「form.html」 で右クリックし、「進む」を押す + * [ ] ポップアップダイアログが閉じること + +### すべてのURLを対象にした時の動作確認(警告ダイアログ有) #### 準備 @@ -55,8 +69,10 @@ #### 検証 -* https://www.google.com/ を開く - * すべてのURLを対象としている場合も、http/httpsのサイトを開いていないとアドインが動作しないため +##### ダイアログを自動でキャンセルするケース + +* `powershell doc\verify\sources\TestTools\http_server.ps1`でローカルのWebサーバーを起動する + * `http://localhost:8080`で簡易Webサーバーが起動する * `doc\verify\sources\TestTools\form.html` を開く * フォームに「test」と入力して、「送信」ボタンを押す * 「form.html」 をリロードする @@ -72,11 +88,25 @@ * [ ] 警告ダイアログが前面に表示されること(Edgeの後ろに隠れないこと) * すべての警告ダイアログをOKで閉じる -### 特定のURLを対象にした時の動作確認(警告ダイアログ無) +##### ERR_CACHE_MISSページを自動で閉じるケース + +* `powershell doc\verify\sources\TestTools\http_server.ps1`でローカルのWebサーバーを起動する + * `http://localhost:8080`で簡易Webサーバーが起動する +* `doc\verify\sources\TestTools\form.html` を開く +* 「フォームをダイアログで開くボタン」を押す + * ポップアップダイアログが開く +* フォームに「test」と入力して、「送信」ボタンを押す +* 遷移先の http://localhost:8080 で右クリックし、「戻る」を押す +* 遷移先の 「form.html」 で右クリックし、「進む」を押す + * [ ] 「フォームの再送信が発生するため、このサイトでのリロードは禁止されています。\n\nリロードはキャンセルされました。」という警告ダイアログが表示**されない**こと + * このケースは非サポート。警告を出しているネイティブアプリ側ではなく、拡張機能側が閉じていることと、そもそもキャンセルされているので。 + * [ ] ポップアップダイアログが閉じること + +### ダイアログを閉じる機能で特定のURLを対象にした時の動作確認(警告ダイアログ無) #### 補足 -本アドオンは、現在のタブが指定したURLを開いていなくても、いずれかのタブで指定したURLが開いている場合に動作する。 +本アドオンのダイアログを自動でキャンセルする機能は、現在のタブが指定したURLを開いていなくても、いずれかのタブで指定したURLが開いている場合に動作する。 これは、ネイティブアプリ側で現在開いているタブを判定するのが難しいためである。 #### 準備 @@ -95,6 +125,10 @@ #### 検証 +##### ダイアログを自動でキャンセルするケース + +* `powershell doc\verify\sources\TestTools\http_server.ps1`でローカルのWebサーバーを起動する + * `http://localhost:8080`で簡易Webサーバーが起動する * `https://example.com/jp/exclude` を開く * `doc\verify\sources\TestTools\form.html` を開く * フォームに「test」と入力して、「送信」ボタンを押す @@ -123,4 +157,64 @@ * `doc\verify\sources\TestTools\form.html` を開く * フォームに「test」と入力して、「送信」ボタンを押す * 「form.html」 をリロードする - * [ ] 「フォームを再送信しますか?」ダイアログ一瞬表示され、キャンセルされること \ No newline at end of file + * [ ] 「フォームを再送信しますか?」ダイアログ一瞬表示され、キャンセルされること + +### ERR_CACHE_MISSページを閉じる機能で特定のURLを対象にした時の動作確認 + +#### 補足 + +ERR_CACHE_MISSページを閉じる機能は指定したURLでのみ動作する。 + +#### 対象のページではない場合 + +##### 準備 + +以下の通り設定して検証を行う。 + +* [doc\verify\sources\TestTools/Scenarios/scenario3.ini](../TestTools/Scenarios/scenario3.ini) を `C:\Program Files\RepostConfirmationCanceler\RepostConfirmationCanceler.ini` に配置する。 + * 設定の内容は以下の通り + * 以下のサイトを対象とする + * `*://example.com/jp*` + * `*://example.com/us/??/` + * `https://www.clear-code.com/` + * 以下のサイトを除外する + * `*://example.com/jp/exclude*` +* 念のためEdgeを再起動する + +##### 検証 + +* `powershell doc\verify\sources\TestTools\http_server.ps1`でローカルのWebサーバーを起動する + * `http://localhost:8080`で簡易Webサーバーが起動する +* `doc\verify\sources\TestTools\form.html` を開く +* 「フォームをダイアログで開くボタン」を押す + * ポップアップダイアログが開く +* フォームに「test」と入力して、「送信」ボタンを押す +* 遷移先の http://localhost:8080 で右クリックし、「戻る」を押す +* 遷移先の 「form.html」 で右クリックし、「進む」を押す + * [ ] ERR_CACHE_MISS(フォームの再送信しますか?)エラーページが表示されること + +#### 対象のページの場合 + +##### 準備 + +以下の通り設定して検証を行う。 + +* [doc\verify\sources\TestTools/Scenarios/scenario4.ini](../TestTools/Scenarios/scenario4.ini) を `C:\Program Files\RepostConfirmationCanceler\RepostConfirmationCanceler.ini` に配置する。 + * 設定の内容は以下の通り + * 以下のサイトを対象とする + * `*://localhost:8080*` +* 念のためEdgeを再起動する + +補足: マッチング処理の実装はダイアログキャンセルと同様であるため、ここでは詳しいマッチング処理の判定まではテストしない。 + +##### 検証 + +* `powershell doc\verify\sources\TestTools\http_server.ps1`でローカルのWebサーバーを起動する + * `http://localhost:8080`で簡易Webサーバーが起動する +* `doc\verify\sources\TestTools\form.html` を開く +* 「フォームをダイアログで開くボタン」を押す + * ポップアップダイアログが開く +* フォームに「test」と入力して、「送信」ボタンを押す +* 遷移先の http://localhost:8080 で右クリックし、「戻る」を押す +* 遷移先の 「form.html」 で右クリックし、「進む」を押す + * [ ] ダイアログが閉じること \ No newline at end of file diff --git a/doc/verify/sources/TestTools/Senarios/scenario4.ini b/doc/verify/sources/TestTools/Senarios/scenario4.ini new file mode 100644 index 0000000..a649ffd --- /dev/null +++ b/doc/verify/sources/TestTools/Senarios/scenario4.ini @@ -0,0 +1,2 @@ +[TARGETS] +*://localhost:8080* diff --git a/doc/verify/sources/TestTools/form.html b/doc/verify/sources/TestTools/form.html index 4ce5c81..2cec5b7 100644 --- a/doc/verify/sources/TestTools/form.html +++ b/doc/verify/sources/TestTools/form.html @@ -7,10 +7,20 @@

フォーム再送信サンプル

送信ボタンを押下後、リロードすると「フォームを再送信しますか?」ダイアログが表示されます。

-
+

送信ボタンを押下後、ブラウザの「戻る」「進む」を実行すると、「フォームを再送信しますか?」(ERR_CACHE_MISS)エラーページが表示されます。

+
-

本フォームは自分自身にデータ送信するため、外部にはデータ送信はしません。

+

本フォームは外部にはデータ送信しません。

+ + + diff --git a/doc/verify/sources/TestTools/http_server.ps1 b/doc/verify/sources/TestTools/http_server.ps1 new file mode 100644 index 0000000..e9f3fff --- /dev/null +++ b/doc/verify/sources/TestTools/http_server.ps1 @@ -0,0 +1,37 @@ +Add-Type -AssemblyName System.Net + +$listener = New-Object System.Net.HttpListener +$listener.Prefixes.Add("http://localhost:8080/") +$listener.Start() +Write-Host "HTTP server running: http://localhost:8080/" + +while ($listener.IsListening) { + try { + $context = $listener.GetContext() + $response = $context.Response + $request = $context.Request + + # Disable cache in order to cause ERR_CACHE_MISS + $response.Headers.Add("Cache-Control", "no-store, no-cache, must-revalidate") + $response.Headers.Add("Pragma", "no-cache") + $response.ContentType = "text/html" + + $html = @" + + +PowerShell HTTP Server + +

No cached page

+

This page is not cached

+ + +"@ + + $buffer = [System.Text.Encoding]::UTF8.GetBytes($html) + $response.ContentLength64 = $buffer.Length + $response.OutputStream.Write($buffer, 0, $buffer.Length) + $response.OutputStream.Close() + } catch { + Write-Warning "Error: $_" + } +} diff --git a/webextensions/edge/background.js b/webextensions/edge/background.js index eb46b16..8954d82 100644 --- a/webextensions/edge/background.js +++ b/webextensions/edge/background.js @@ -47,13 +47,13 @@ function wildcardToRegexp(source) { * ] * } */ -const RepostConfirmationCancelerTalkClient = { +const RepostConfirmationCanceler = { cached: null, init() { this.cached = null; this.ensureLoadedAndConfigured(); - console.log('Running as RepostConfirmationCancelerTalkClient Talk client'); + console.log('Running RepostConfirmationCanceler'); }, async ensureLoadedAndConfigured() { @@ -114,7 +114,7 @@ const RepostConfirmationCancelerTalkClient = { return false; }, - handleURL(config, url){ + handleURL(config, url, callbackWhenMatch){ if (!url) { console.log(`* Empty URL found`); return false; @@ -135,7 +135,7 @@ const RepostConfirmationCancelerTalkClient = { console.log(`handleURL: check for section ${section.Name} (${JSON.stringify(section)})`); if (this.match(section, urlToMatch)) { console.log(` => unmatched`); - this.startMonitoring(); + callbackWhenMatch(); return true; } else { @@ -153,7 +153,7 @@ const RepostConfirmationCancelerTalkClient = { for (const tab of tabs) { const url = tab.url ?? tab.pendingUrl; console.log(`handleAllTabs ${url} (tab=${tab.id})`); - if(this.handleURL(config, url)){ + if(this.handleURL(config, url, this.startMonitoring)){ break; } }; @@ -169,15 +169,40 @@ const RepostConfirmationCancelerTalkClient = { const config = this.cached; const url = tab.pendingUrl || tab.url; - this.handleURL(config, url); + this.handleURL(config, url, this.startMonitoring); }, onNavigationCommitted(details) { const url = details.url; console.log(`onNavigationCommitted: ${url}`); const config = this.cached; - this.handleURL(config, url); + this.handleURL(config, url, this.startMonitoring); }, + + onErrorOccurred(details) { + console.log('onErrorOccurred:', details); + if (details.error === 'net::ERR_CACHE_MISS') { + const url = details.url; + const tabId = details.tabId; + const config = this.cached; + this.handleURL(config, url, () => { + this.closeTab(tabId); + }); + } + }, + + closeTab(tabId) { + if (tabId !== -1) { + console.log("Closing tab:", tabId); + chrome.tabs.remove(tabId, () => { + if (chrome.runtime.lastError) { + console.log("Error while closing tab:", chrome.runtime.lastError.message) + } else { + console.log("Tab closed"); + } + }); + } + } }; /* Refresh config for every N minute */ @@ -186,14 +211,19 @@ chrome.alarms.create('poll-config', {'periodInMinutes': ALARM_MINUTES}); chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'poll-config') { - RepostConfirmationCancelerTalkClient.configure(); - RepostConfirmationCancelerTalkClient.handleAllTabs(); + RepostConfirmationCanceler.configure(); + RepostConfirmationCanceler.handleAllTabs(); //handleURL for all url in tabs. } }); +chrome.webRequest.onErrorOccurred.addListener( + RepostConfirmationCanceler.onErrorOccurred.bind(RepostConfirmationCanceler), + {urls: [""]} +); + /* Tab book-keeping for intelligent tab handlings */ -chrome.tabs.onUpdated.addListener(RepostConfirmationCancelerTalkClient.onTabUpdated.bind(RepostConfirmationCancelerTalkClient)); -chrome.webNavigation.onCommitted.addListener(RepostConfirmationCancelerTalkClient.onNavigationCommitted.bind(RepostConfirmationCancelerTalkClient)); +chrome.tabs.onUpdated.addListener(RepostConfirmationCanceler.onTabUpdated.bind(RepostConfirmationCanceler)); +chrome.webNavigation.onCommitted.addListener(RepostConfirmationCanceler.onNavigationCommitted.bind(RepostConfirmationCanceler)); -RepostConfirmationCancelerTalkClient.init(); +RepostConfirmationCanceler.init(); diff --git a/webextensions/edge/manifest.json b/webextensions/edge/manifest.json index ed45573..b4f62be 100644 --- a/webextensions/edge/manifest.json +++ b/webextensions/edge/manifest.json @@ -7,7 +7,8 @@ "nativeMessaging", "alarms", "tabs", - "webNavigation" + "webNavigation", + "webRequest" ], "host_permissions": [ ""