From 790e6baf46c51c225eb88f94f4c6c329c39f7775 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Tue, 12 Apr 2016 16:58:45 +0200 Subject: [PATCH] ASF-specific WebBrowser enhancements, closes #192 --- ArchiSteamFarm/ArchiWebHandler.cs | 42 +++++++------- ArchiSteamFarm/Program.cs | 3 + ArchiSteamFarm/WebBrowser.cs | 96 +++++++++++++++---------------- 3 files changed, 73 insertions(+), 68 deletions(-) diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 1e6717b53..fb8c66568 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -45,7 +45,7 @@ namespace ArchiSteamFarm { private readonly Bot Bot; private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1); - private readonly CookieContainer CookieContainer = new CookieContainer(); + private readonly WebBrowser WebBrowser; private DateTime LastSessionRefreshCheck = DateTime.MinValue; @@ -60,6 +60,8 @@ namespace ArchiSteamFarm { } Bot = bot; + + WebBrowser = new WebBrowser(bot.BotName); } internal bool Init(SteamClient steamClient, string webAPIUserNonce, string parentalPin) { @@ -114,13 +116,13 @@ namespace ArchiSteamFarm { Logging.LogGenericInfo("Success!", Bot.BotName); - CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunity)); + WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunity)); string steamLogin = authResult["token"].Value; - CookieContainer.Add(new Cookie("steamLogin", steamLogin, "/", "." + SteamCommunity)); + WebBrowser.CookieContainer.Add(new Cookie("steamLogin", steamLogin, "/", "." + SteamCommunity)); string steamLoginSecure = authResult["tokensecure"].Value; - CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", "." + SteamCommunity)); + WebBrowser.CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", "." + SteamCommunity)); if (!UnlockParentalAccount(parentalPin).Result) { return false; @@ -133,7 +135,7 @@ namespace ArchiSteamFarm { internal async Task IsLoggedIn() { HtmlDocument htmlDocument = null; for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) { - htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/profile", CookieContainer).ConfigureAwait(false); + htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/profile").ConfigureAwait(false); } if (htmlDocument == null) { @@ -184,7 +186,7 @@ namespace ArchiSteamFarm { XmlDocument response = null; for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) { - response = await WebBrowser.UrlGetToXML(request, CookieContainer).ConfigureAwait(false); + response = await WebBrowser.UrlGetToXML(request).ConfigureAwait(false); } if (response == null) { @@ -289,7 +291,7 @@ namespace ArchiSteamFarm { return false; } - string sessionID = CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); + string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); if (string.IsNullOrEmpty(sessionID)) { Logging.LogNullError("sessionID"); return false; @@ -304,7 +306,7 @@ namespace ArchiSteamFarm { bool result = false; for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { - result = await WebBrowser.UrlPost(request, data, CookieContainer).ConfigureAwait(false); + result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false); } if (!result) { @@ -324,7 +326,7 @@ namespace ArchiSteamFarm { return false; } - string sessionID = CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); + string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); if (string.IsNullOrEmpty(sessionID)) { Logging.LogNullError("sessionID"); return false; @@ -341,7 +343,7 @@ namespace ArchiSteamFarm { bool result = false; for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { - result = await WebBrowser.UrlPost(request, data, CookieContainer, referer).ConfigureAwait(false); + result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false); } if (!result) { @@ -359,7 +361,7 @@ namespace ArchiSteamFarm { JObject jObject = null; for (byte i = 0; i < WebBrowser.MaxRetries && jObject == null; i++) { - jObject = await WebBrowser.UrlGetToJObject(SteamCommunityURL + "/my/inventory/json/753/6?trading=1", CookieContainer).ConfigureAwait(false); + jObject = await WebBrowser.UrlGetToJObject(SteamCommunityURL + "/my/inventory/json/753/6?trading=1").ConfigureAwait(false); } if (jObject == null) { @@ -394,7 +396,7 @@ namespace ArchiSteamFarm { return false; } - string sessionID = CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); + string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); if (string.IsNullOrEmpty(sessionID)) { Logging.LogNullError("sessionID"); return false; @@ -437,7 +439,7 @@ namespace ArchiSteamFarm { bool result = false; for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { - result = await WebBrowser.UrlPost(request, data, CookieContainer, referer).ConfigureAwait(false); + result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false); } if (!result) { @@ -460,7 +462,7 @@ namespace ArchiSteamFarm { HtmlDocument htmlDocument = null; for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) { - htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/badges?p=" + page, CookieContainer).ConfigureAwait(false); + htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/badges?p=" + page).ConfigureAwait(false); } if (htmlDocument == null) { @@ -482,7 +484,7 @@ namespace ArchiSteamFarm { HtmlDocument htmlDocument = null; for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) { - htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/gamecards/" + appID, CookieContainer).ConfigureAwait(false); + htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/gamecards/" + appID).ConfigureAwait(false); } if (htmlDocument == null) { @@ -500,7 +502,7 @@ namespace ArchiSteamFarm { bool result = false; for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { - result = await WebBrowser.UrlGet(SteamCommunityURL + "/my/inventory", CookieContainer).ConfigureAwait(false); + result = await WebBrowser.UrlGet(SteamCommunityURL + "/my/inventory").ConfigureAwait(false); } if (!result) { @@ -520,7 +522,7 @@ namespace ArchiSteamFarm { return false; } - string sessionID = CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); + string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); if (string.IsNullOrEmpty(sessionID)) { Logging.LogNullError("sessionID"); return false; @@ -533,7 +535,7 @@ namespace ArchiSteamFarm { bool result = false; for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { - result = await WebBrowser.UrlPost(request, data, CookieContainer).ConfigureAwait(false); + result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false); } if (!result) { @@ -559,7 +561,7 @@ namespace ArchiSteamFarm { HttpResponseMessage response = null; for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) { - response = await WebBrowser.UrlPostToResponse(request, data, CookieContainer, referer).ConfigureAwait(false); + response = await WebBrowser.UrlPostToResponse(request, data, referer).ConfigureAwait(false); } if (response == null) { @@ -589,7 +591,7 @@ namespace ArchiSteamFarm { } Logging.LogGenericInfo("Success!", Bot.BotName); - CookieContainer.Add(new Cookie("steamparental", setCookie, "/", "." + SteamCommunity)); + WebBrowser.CookieContainer.Add(new Cookie("steamparental", setCookie, "/", "." + SteamCommunity)); return true; } diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 65bf2ba84..7fcf82263 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -82,6 +82,7 @@ namespace ArchiSteamFarm { private static Timer AutoUpdatesTimer; private static EMode Mode = EMode.Normal; + private static WebBrowser WebBrowser; internal static async Task CheckForUpdate() { string oldExeFile = ExecutableFile + ".old"; @@ -369,6 +370,8 @@ namespace ArchiSteamFarm { ArchiWebHandler.Init(); WebBrowser.Init(); WCF.Init(); + + WebBrowser = new WebBrowser("Main"); } private static void ParseArgs(string[] args) { diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index b16cd71c0..cfcb3f07e 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -34,31 +34,20 @@ using System.Threading.Tasks; using System.Xml; namespace ArchiSteamFarm { - internal static class WebBrowser { + internal sealed class WebBrowser { internal const byte MaxRetries = 5; // Defines maximum number of retries, UrlRequest() does not handle retry by itself (it's app responsibility) private const byte MaxConnections = 10; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state private const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it - internal static readonly CookieContainer CookieContainer = new CookieContainer(); - private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program.Version; - private static readonly HttpClientHandler HttpClientHandler = new HttpClientHandler { - AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, - CookieContainer = CookieContainer - }; - private static readonly HttpClient HttpClient = new HttpClient(HttpClientHandler) { - Timeout = TimeSpan.FromSeconds(GlobalConfig.DefaultHttpTimeout) - }; + internal readonly CookieContainer CookieContainer = new CookieContainer(); + + private readonly HttpClient HttpClient; + private readonly string Identifier; internal static void Init() { - HttpClient.Timeout = TimeSpan.FromSeconds(Program.GlobalConfig.HttpTimeout); - - // Most web services expect that UserAgent is set, so we declare it globally - // Any request can override that on as-needed basis (see: RequestOptions.FakeUserAgent) - HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(DefaultUserAgent); - // Set max connection limit from default of 2 to desired value ServicePointManager.DefaultConnectionLimit = MaxConnections; @@ -74,12 +63,32 @@ namespace ArchiSteamFarm { #endif } - internal static async Task UrlGet(string request, CookieContainer cookieContainer = null, string referer = null) { + internal WebBrowser(string identifier) { + if (string.IsNullOrEmpty(identifier)) { + return; + } + + Identifier = identifier; + + HttpClientHandler httpClientHandler = new HttpClientHandler { + AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, + CookieContainer = CookieContainer + }; + + HttpClient = new HttpClient(httpClientHandler) { + Timeout = TimeSpan.FromSeconds(Program.GlobalConfig.HttpTimeout) + }; + + // Most web services expect that UserAgent is set, so we declare it globally + HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(DefaultUserAgent); + } + + internal async Task UrlGet(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { return false; } - HttpResponseMessage response = await UrlGetToResponse(request, cookieContainer, referer).ConfigureAwait(false); + HttpResponseMessage response = await UrlGetToResponse(request, referer).ConfigureAwait(false); if (response == null) { return false; } @@ -88,12 +97,12 @@ namespace ArchiSteamFarm { return true; } - internal static async Task UrlPost(string request, Dictionary data = null, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlPost(string request, Dictionary data = null, string referer = null) { if (string.IsNullOrEmpty(request)) { return false; } - HttpResponseMessage response = await UrlPostToResponse(request, data, cookieContainer, referer).ConfigureAwait(false); + HttpResponseMessage response = await UrlPostToResponse(request, data, referer).ConfigureAwait(false); if (response == null) { return false; } @@ -102,28 +111,28 @@ namespace ArchiSteamFarm { return true; } - internal static async Task UrlGetToResponse(string request, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlGetToResponse(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { return null; } - return await UrlRequest(request, HttpMethod.Get, null, cookieContainer, referer).ConfigureAwait(false); + return await UrlRequest(request, HttpMethod.Get, null, referer).ConfigureAwait(false); } - internal static async Task UrlPostToResponse(string request, Dictionary data = null, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlPostToResponse(string request, Dictionary data = null, string referer = null) { if (string.IsNullOrEmpty(request)) { return null; } - return await UrlRequest(request, HttpMethod.Post, data, cookieContainer, referer).ConfigureAwait(false); + return await UrlRequest(request, HttpMethod.Post, data, referer).ConfigureAwait(false); } - internal static async Task UrlGetToContent(string request, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlGetToContent(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { return null; } - HttpResponseMessage httpResponse = await UrlGetToResponse(request, cookieContainer, referer).ConfigureAwait(false); + HttpResponseMessage httpResponse = await UrlGetToResponse(request, referer).ConfigureAwait(false); if (httpResponse == null) { return null; } @@ -134,12 +143,12 @@ namespace ArchiSteamFarm { return result; } - internal static async Task UrlGetToStream(string request, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlGetToStream(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { return null; } - HttpResponseMessage httpResponse = await UrlGetToResponse(request, cookieContainer, referer).ConfigureAwait(false); + HttpResponseMessage httpResponse = await UrlGetToResponse(request, referer).ConfigureAwait(false); if (httpResponse == null) { return null; } @@ -150,12 +159,12 @@ namespace ArchiSteamFarm { return result; } - internal static async Task UrlGetToHtmlDocument(string request, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlGetToHtmlDocument(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { return null; } - string content = await UrlGetToContent(request, cookieContainer, referer).ConfigureAwait(false); + string content = await UrlGetToContent(request, referer).ConfigureAwait(false); if (string.IsNullOrEmpty(content)) { return null; } @@ -167,12 +176,12 @@ namespace ArchiSteamFarm { return htmlDocument; } - internal static async Task UrlGetToJObject(string request, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlGetToJObject(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { return null; } - string content = await UrlGetToContent(request, cookieContainer, referer).ConfigureAwait(false); + string content = await UrlGetToContent(request, referer).ConfigureAwait(false); if (string.IsNullOrEmpty(content)) { return null; } @@ -189,12 +198,12 @@ namespace ArchiSteamFarm { return jObject; } - internal static async Task UrlGetToXML(string request, CookieContainer cookieContainer = null, string referer = null) { + internal async Task UrlGetToXML(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { return null; } - string content = await UrlGetToContent(request, cookieContainer, referer).ConfigureAwait(false); + string content = await UrlGetToContent(request, referer).ConfigureAwait(false); if (string.IsNullOrEmpty(content)) { return null; } @@ -211,7 +220,7 @@ namespace ArchiSteamFarm { return xmlDocument; } - private static async Task UrlRequest(string request, HttpMethod httpMethod, Dictionary data = null, CookieContainer cookieContainer = null, string referer = null) { + private async Task UrlRequest(string request, HttpMethod httpMethod, Dictionary data = null, string referer = null) { if (string.IsNullOrEmpty(request) || httpMethod == null) { return null; } @@ -236,16 +245,7 @@ namespace ArchiSteamFarm { } try { - if (cookieContainer == null) { - responseMessage = await HttpClient.SendAsync(requestMessage).ConfigureAwait(false); - } else { - using (HttpClientHandler httpClientHandler = new HttpClientHandler { - AutomaticDecompression = HttpClientHandler.AutomaticDecompression, - CookieContainer = cookieContainer - }) using (HttpClient httpClient = new HttpClient(httpClientHandler)) { - responseMessage = await httpClient.SendAsync(requestMessage).ConfigureAwait(false); - } - } + responseMessage = await HttpClient.SendAsync(requestMessage).ConfigureAwait(false); } catch { // Request failed, we don't need to know the exact reason, swallow exception return null; } @@ -253,10 +253,10 @@ namespace ArchiSteamFarm { if (responseMessage == null || !responseMessage.IsSuccessStatusCode) { if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) { - Logging.LogGenericError("Request: " + request + " failed!"); + Logging.LogGenericError("Request: " + request + " failed!", Identifier); if (responseMessage != null) { - Logging.LogGenericError("Status code: " + responseMessage.StatusCode); - Logging.LogGenericError("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false)); + Logging.LogGenericError("Status code: " + responseMessage.StatusCode, Identifier); + Logging.LogGenericError("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false), Identifier); } } return null;