WPFでCefSharp（Chromiumの.NET向け実装）を使う - 3

# 概要

今回はIRequestHandlerについて書きます。

IRequestHandlerはその名の通りブラウザのリクエストをハンドリングするためのインタフェースなのですが、やたらと定義すべきメソッドが多いにもかかわらずデフォルト実装がありません。

幸いコメントは充実しているのとサンプル実装は用意されているので、それを基に何ができるのか検証します。

# IRequestCallbackについて

定義を読んでいくと、IRequestCallbackのContinueを呼べだとかCancelを呼べだとか書いてある箇所が出てきます。

IRequestHandlerの説明に移る前に、IRequestCallbackが何者なのかについても調べておきます。

[定義](https://github.com/cefsharp/CefSharp/blob/cd934267c65f494ceb9ee75995cd2a1ca0954543/CefSharp/Callback/IRequestCallback.cs)

## void Continue(bool allow)

引数としてtrueを渡すとリクエストの処理を継続して、falseを渡すとキャンセルされます。

## void Cancel()

リクエストがキャンセルされます。

`Continue(false)`と`Cancel()`の違いは何なんだろうか……

# IRequestHandlerで定義すべきメソッド

[定義](https://github.com/cefsharp/CefSharp/blob/cd934267c65f494ceb9ee75995cd2a1ca0954543/CefSharp/Handler/IRequestHandler.cs)

## bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)

ブラウザの遷移前に呼び出されるメソッドです。

以下コメントの直訳（間違ってても許して）

> ナビゲーションが許可された場合、`IWebBrowser.FrameLoadStart`と`IWebBrowser.FrameLoadEnd`が呼び出される。  
> ナビゲーションがキャンセルされた場合、`IWebBrowser.LoadError`イベントが発火し、イベントの引数として`CefErrorCode.Aborted`が渡される。

引数は型との仮引数の名前でどんなものか想像つくので省略しますが返り値がぱっと見だとよくわからないのでこれも直訳してみます。

> trueを返すとナビゲーションがキャンセルされる。  
> falseを返すとナビゲーションの進行を許可する。

とのことなので、デフォルトの挙動としてはfalseを返し、何か画面遷移を止めたい場合のみtrueを返すことになるはずです。

## bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)

新しいタブやブラウザでurlを開こうとしたときに呼び出されるメソッドです。

> 新しいブラウザやタブで開くのが望ましい場合に、OnBeforeBrowseが呼び出される前にUIスレッドで呼び出される。  
> "新しいブラウザやタブで開くのが望ましい場合"とは中央ボタンのクリックやCtrl + 左クリック、クロスオリジンのナビゲーションがあったときのことを指す。

これの返り値もOnBeforeBrowseと同様に、falseを返すとナビゲーション続けてtrueを返すとナビゲーションをキャンセルします。

これはデフォルト値どうするか迷いますが（アプリに組み込むWebViewで新しいタブとか開かれたくない気がする）、サンプル実装だとfalseを返しているようです。

## bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback)

ダメなSSLのときに呼ばれるメソッドです。

> 不正なSSL証明書のリクエストをハンドリングするために呼び出される。  
> trueを返して`IRequestCallback.Continue`を呼び出すことで処理を継続させることができる。  
> `CefSettings.IgnoreCertificateErrors`を使うとこのメソッドを呼ばずにすべてのsslを許可することもできる。  
> falseを返すと即座にリクエストがキャンセルされる。

サンプル実装のコメントには、このメソッド実装したくないならfalse返しとけばいいよって書いてあるので基本false返すようにしとけばいいはずです。

## void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath);

プラグインがクラッシュしたときに呼ばれるメソッドです。

空の実装でも問題なさそうです。

## CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)

リクエストが投げられる前に呼ばれるメソッドです。

> リソースのリクエスト前に呼ばれる。  
> asyncで処理したいなら`CefReturnValue.ContinueAsync`を返して`IRequestCallback.Continue`か`IRequestCallback.Cancel`を呼ぶ。

引数で受け取ったrequestは変更可能となっているので、このメソッドの中でリクエストにヘッダを追加したりできます。

`CefReturnValue.Cancel`を返すことでリソースのロードをキャンセルすることができます。

## bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)

ブラウザがユーザに認証情報を要求するときに呼ばれるらしいです（Basic認証とか？）。

IAuthCallbackのContinueがユーザ名とパスワードを引数として受け取れるので、trueを返しつつ`IAuthCallback.Continue`を呼ぶことで処理を継続することができそうです。

falseを返すとリクエストがキャンセルされます。

## bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)

受け取った鍵の認証局を選ぶときに呼ばれるっぽいです。

trueを返しつつ`ISelectClientCertificateCallback.Select`を呼べば手動で選べるけどfalseを返しておけば自動で選んでくれるみたいなのでfalseを返しておけばいいはずです。

## void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status)

予期せぬ理由で描画が止まってしまったときに呼び出されます。

どんなときかよくわからなかったのでCefTerminationStatusを見てみると、終了コードが0以外だった場合とタスクマネージャからKillされた場合とせぐふぉの場合って書いてました。

## bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, Int64 newSize, IRequestCallback callback)

webkitStorageInfo.requestQuotaが呼ばれたときに呼び出されるようです。

false返してキャンセルしておけば基本問題ないでしょう。

## void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl)

302とかが返ってきたときに呼び出されます。

requestは編集不可ですがリダイレクト先のURLは書き換えられるみたいです。

## bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)

ブラウザで処理できないプロトコルが指定されたときに呼び出されます（多分mailtoとか）。

trueを返すとOSにそのプロトコルのハンドリングを任せて、falseを返すと何もしないみたいです。

## void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)

UIスレッドの準備ができたとき？に呼ばれます。

多分空の実装でOKです。

## bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)

レスポンスを受信したときに呼ばれます。

trueを返すとリクエストを再送することができて、requestの編集も可能です。

falseを返すとそのまま処理を続けます。

## IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)

IResponseFilerを実装したオブジェクトを返すことでレスポンスのstreamをフィルタリングできるようです。

## void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)

リソースのロードが完了したときに呼ばれます。

# まとめ

* リクエストの送信前からレスポンスの受信完了まで様々なタイミングで処理を挟むことができる
* boolを返すメソッドは基本falseで問題なし
* voidを返すメソッドは基本空の実装で問題なし

次回はCustom URL Schemeを扱うためのハンドラについて書きます。

[元記事](http://ghken.hatenablog.com/entry/2017/05/02/001717)