X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=OpenTween%2FConnection%2FNetworking.cs;h=b75013cebc26b9bb50ff2fb58da97479f2269263;hb=86a1e3bef40f255d5ef28e81767e0a4842752732;hp=dd8b01278aac30ca65da714afdcfa5607832d97c;hpb=603b19634d8c90ed4a8becd8bf1a8f9eb5fb087b;p=opentween%2Fopen-tween.git diff --git a/OpenTween/Connection/Networking.cs b/OpenTween/Connection/Networking.cs index dd8b0127..b75013ce 100644 --- a/OpenTween/Connection/Networking.cs +++ b/OpenTween/Connection/Networking.cs @@ -19,11 +19,14 @@ // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, // Boston, MA 02110-1301, USA. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; +using System.Net.Cache; using System.Net.Http; using System.Text; using System.Threading; @@ -35,44 +38,55 @@ namespace OpenTween.Connection { public static TimeSpan DefaultTimeout { get; set; } + public static TimeSpan UploadImageTimeout { get; set; } + /// /// 通信に使用するプロキシの種類 /// - public static ProxyType ProxyType - { - get { return proxyType; } - } + public static ProxyType ProxyType { get; private set; } = ProxyType.IE; /// /// 通信に使用するプロキシ /// - public static IWebProxy Proxy - { - get { return proxy; } - } + public static IWebProxy? Proxy { get; private set; } = null; /// /// OpenTween 内で共通して使用する HttpClient インスタンス /// - public static HttpClient Http + public static HttpClient Http => globalHttpClient; + + /// + /// pbs.twimg.com で IPv4 を強制的に使用する + /// + public static bool ForceIPv4 { - get { return globalHttpClient; } + get => forceIPv4; + set + { + if (forceIPv4 == value) + return; + + forceIPv4 = value; + + // Network.Http を再作成させる + OnWebProxyChanged(EventArgs.Empty); + } } /// /// Webプロキシの設定が変更された場合に発生します /// - public static event EventHandler WebProxyChanged; + public static event EventHandler? WebProxyChanged; private static bool initialized = false; private static HttpClient globalHttpClient; - private static ProxyType proxyType = ProxyType.IE; - private static IWebProxy proxy = null; + private static bool forceIPv4 = false; [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")] static Networking() { DefaultTimeout = TimeSpan.FromSeconds(20); + UploadImageTimeout = TimeSpan.FromSeconds(60); globalHttpClient = CreateHttpClient(new HttpClientHandler()); } @@ -84,12 +98,17 @@ namespace OpenTween.Connection Networking.initialized = true; ServicePointManager.Expect100Continue = false; + ServicePointManager.CheckCertificateRevocationList = true; } - public static void SetWebProxy(ProxyType proxyType, string proxyAddress, int proxyPort, - string proxyUser, string proxyPassword) + public static void SetWebProxy( + ProxyType proxyType, + string proxyAddress, + int proxyPort, + string proxyUser, + string proxyPassword) { - IWebProxy proxy; + IWebProxy? proxy; switch (proxyType) { case ProxyType.None: @@ -97,7 +116,7 @@ namespace OpenTween.Connection break; case ProxyType.Specified: proxy = new WebProxy(proxyAddress, proxyPort); - if (!string.IsNullOrEmpty(proxyUser) || !string.IsNullOrEmpty(proxyPassword)) + if (!MyCommon.IsNullOrEmpty(proxyUser) || !MyCommon.IsNullOrEmpty(proxyPassword)) proxy.Credentials = new NetworkCredential(proxyUser, proxyPassword); break; case ProxyType.IE: @@ -106,24 +125,26 @@ namespace OpenTween.Connection break; } - Networking.proxyType = proxyType; - Networking.proxy = proxy; + Networking.ProxyType = proxyType; + Networking.Proxy = proxy; - NativeMethods.SetProxy(proxyType, proxyAddress, proxyPort, proxyUser, proxyPassword); + NativeMethods.SetProxy(proxyType, proxyAddress, proxyPort); OnWebProxyChanged(EventArgs.Empty); } /// - /// プロキシ等の設定を施した HttpClient インスタンスを生成します + /// OpenTween で必要な設定を施した HttpClientHandler インスタンスを生成します /// - /// - /// 通常は Networking.Http を使用すべきです。 - /// このメソッドを使用する場合は、WebProxyChanged イベントが発生する度に HttpClient を生成し直すように実装してください。 - /// [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")] - public static HttpClient CreateHttpClient(HttpClientHandler handler) + public static WebRequestHandler CreateHttpClientHandler() { + var handler = new WebRequestHandler + { + UseCookies = false, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + }; + if (Networking.Proxy != null) { handler.UseProxy = true; @@ -134,9 +155,26 @@ namespace OpenTween.Connection handler.UseProxy = false; } - var client = new HttpClient(handler); + return handler; + } + + /// + /// OpenTween で必要な設定を施した HttpClient インスタンスを生成します + /// + /// + /// 通常は Networking.Http を使用すべきです。 + /// このメソッドを使用する場合は、WebProxyChanged イベントが発生する度に HttpClient を生成し直すように実装してください。 + /// + [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")] + public static HttpClient CreateHttpClient(HttpMessageHandler handler) + { + HttpClient client; + if (ForceIPv4) + client = new HttpClient(new ForceIPv4Handler(handler)); + else + client = new HttpClient(handler); + client.Timeout = Networking.DefaultTimeout; - client.DefaultRequestHeaders.Add("User-Agent", Networking.GetUserAgentString()); return client; } @@ -144,9 +182,9 @@ namespace OpenTween.Connection public static string GetUserAgentString(bool fakeMSIE = false) { if (fakeMSIE) - return MyCommon.GetAssemblyName() + "/" + MyCommon.FileVersion + " (compatible; MSIE 10.0)"; + return ApplicationSettings.AssemblyName + "/" + MyCommon.FileVersion + " (compatible; MSIE 10.0)"; else - return MyCommon.GetAssemblyName() + "/" + MyCommon.FileVersion; + return ApplicationSettings.AssemblyName + "/" + MyCommon.FileVersion; } /// @@ -161,12 +199,42 @@ namespace OpenTween.Connection [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")] private static void OnWebProxyChanged(EventArgs e) { - var newClient = Networking.CreateHttpClient(new HttpClientHandler()); + var newClient = Networking.CreateHttpClient(Networking.CreateHttpClientHandler()); var oldClient = Interlocked.Exchange(ref globalHttpClient, newClient); oldClient.Dispose(); - if (WebProxyChanged != null) - WebProxyChanged(null, e); + WebProxyChanged?.Invoke(null, e); + } + + private class ForceIPv4Handler : DelegatingHandler + { + private readonly IPAddress? ipv4Address; + + public ForceIPv4Handler(HttpMessageHandler innerHandler) + : base(innerHandler) + { + foreach (var address in Dns.GetHostAddresses("pbs.twimg.com")) + { + if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + this.ipv4Address = address; + } + } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (this.ipv4Address != null) + { + var requestUri = request.RequestUri; + if (requestUri.Host == "pbs.twimg.com") + { + var rewriteUriStr = requestUri.GetLeftPart(UriPartial.Scheme) + this.ipv4Address + requestUri.PathAndQuery; + request.RequestUri = new Uri(rewriteUriStr); + request.Headers.Host = "pbs.twimg.com"; + } + } + + return base.SendAsync(request, cancellationToken); + } } }