※ 使うな危険! このアプローチを使うと死亡します。
題名長い。
問題について前回記事をご覧ください。
対策コードはこちらです。
// MIT license internal sealed class PatchedHttpClientHandler : MessageProcessingHandler { public static HttpMessageHandler PatchOrDefault(HttpClientHandler handler) { if (handler.MaxAutomaticRedirections != 10) return handler; return new PatchedHttpClientHandler(handler); } private bool _disposed = false; private HttpClientHandler _innerHandler; public PatchedHttpClientHandler(HttpClientHandler handler) : base(handler) { this._innerHandler = handler; } protected override void Dispose(bool disposing) { if (disposing && !this._disposed) { this._disposed = true; if (this._innerHandler != null) { this._innerHandler.Dispose(); this._innerHandler = null; } } base.Dispose(disposing); } protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken) { return request; } protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken) { this.ProcessResponseCookies(response); return response; } private void ProcessResponseCookies(HttpResponseMessage response) { IEnumerable<string> cookies = null; if (this._innerHandler.UseCookies && response.Headers.TryGetValues("Set-Cookie", out cookies)) { foreach (var item in cookies) { if (!string.IsNullOrWhiteSpace(item)) { try { var requestUri = response.RequestMessage.RequestUri; var temporaryCookieContainer = new CookieContainer(); temporaryCookieContainer.SetCookies(requestUri, item); foreach (var cookie in temporaryCookieContainer.GetCookies(requestUri).Cast<Cookie>()) { if (cookie.HttpOnly) { this._innerHandler.CookieContainer.Add(response.RequestMessage.RequestUri, cookie); } } } catch (Exception) { } } } } } }
使い方は
this._clientHandler = new HttpClientHandler() { AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, }; this._Client = new HttpClient(PatchedHttpClientHandler.PatchOrDefault(this._clientHandler));
という感じ。UWP じゃない (ProcessResponseCookies
が HttpClientHandler
に存在しない) とき、自動で HttpOnly 属性が付いたものを追加する処理になっています。簡単ですね。
二度クッキーをパースしてるのが気になるところですが…
以上です。
追記:
handler.MaxAutomaticRedirections != 10
で patch するかどうか決めてるので仕様変更に弱そう (.NET Native で private methods がとれないからこの方法しか思いつかない… 誰かいい方法あれば)