diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 09627912e..fce9f6a6a 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -1240,6 +1240,16 @@ namespace ArchiSteamFarm { return state != null; } + private static bool IsSessionExpiredUri(Uri uri) { + if (uri == null) { + ASF.ArchiLogger.LogNullError(nameof(uri)); + return false; + } + + bool result = uri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal) || uri.Host.Equals("lostauth"); + return result; + } + private static bool ParseItems(Dictionary descriptions, IReadOnlyCollection input, ICollection output) { if ((descriptions == null) || (input == null) || (input.Count == 0) || (output == null)) { ASF.ArchiLogger.LogNullError(nameof(descriptions) + " || " + nameof(input) + " || " + nameof(output)); @@ -1416,7 +1426,7 @@ namespace ArchiSteamFarm { return null; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return response.Content; } @@ -1460,7 +1470,7 @@ namespace ArchiSteamFarm { return default; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return response.Content; } @@ -1504,7 +1514,7 @@ namespace ArchiSteamFarm { return null; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return response.Content; } @@ -1548,7 +1558,7 @@ namespace ArchiSteamFarm { return false; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return true; } @@ -1607,7 +1617,7 @@ namespace ArchiSteamFarm { return false; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return true; } @@ -1666,7 +1676,7 @@ namespace ArchiSteamFarm { return null; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return response.Content; } @@ -1725,7 +1735,7 @@ namespace ArchiSteamFarm { return default; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return response.Content; } @@ -1787,7 +1797,7 @@ namespace ArchiSteamFarm { return default; } - if (!response.RequestUri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal)) { + if (!IsSessionExpiredUri(response.FinalUri)) { return response.Content; } diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index 774d77724..c48ffeacf 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -49,6 +49,7 @@ namespace ArchiSteamFarm { ArchiLogger = archiLogger ?? throw new ArgumentNullException(nameof(archiLogger)); HttpClientHandler httpClientHandler = new HttpClientHandler { + AllowAutoRedirect = false, // This must be false if we want to handle custom redirection schemes such as "steammobile" AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, CookieContainer = CookieContainer, MaxConnectionsPerServer = MaxConnections, @@ -78,7 +79,7 @@ namespace ArchiSteamFarm { } internal static HtmlDocument StringToHtmlDocument(string html) { - if (string.IsNullOrEmpty(html)) { + if (html == null) { ASF.ArchiLogger.LogNullError(nameof(html)); return null; } @@ -466,49 +467,56 @@ namespace ArchiSteamFarm { return response; } - Uri redirectUri; + // WARNING: We still have undisposed response by now, make sure to dispose it ASAP if we're not returning it! - using (response) { - ushort status = (ushort) response.StatusCode; - if ((status >= 300) && (status <= 399) && (maxRedirections > 0)) { - redirectUri = response.Headers.Location; + ushort status = (ushort) response.StatusCode; - if (redirectUri.IsAbsoluteUri) { - switch (redirectUri.Scheme) { - case "http": - case "https": - break; - default: - // Invalid ones such as "steammobile" - return null; - } - } else { - redirectUri = new Uri(requestUri.GetLeftPart(UriPartial.Authority) + redirectUri); + if ((status >= 300) && (status < 400) && (maxRedirections > 0)) { + Uri redirectUri = response.Headers.Location; + + if (redirectUri.IsAbsoluteUri) { + switch (redirectUri.Scheme) { + case "http": + case "https": + break; + case "steammobile": + // Those redirections are invalid, but we're aware of that and we have extra logic for them + return response; + default: + // We have no clue about those, but maybe HttpClient can handle them for us + ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(redirectUri.Scheme), redirectUri.Scheme)); + break; } } else { - if (!Debugging.IsDebugBuild) { - return null; - } - - ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, requestUri)); - ArchiLogger.LogGenericDebug(string.Format(Strings.StatusCode, response.StatusCode)); - ArchiLogger.LogGenericDebug(string.Format(Strings.Content, await response.Content.ReadAsStringAsync().ConfigureAwait(false))); - return null; + redirectUri = new Uri(requestUri.GetLeftPart(UriPartial.Authority) + redirectUri); } + + response.Dispose(); + return await UrlRequest(redirectUri, httpMethod, data, referer, httpCompletionOption, --maxRedirections).ConfigureAwait(false); } - return await UrlRequest(redirectUri, httpMethod, data, referer, httpCompletionOption, --maxRedirections).ConfigureAwait(false); + using (response) { + if (!Debugging.IsDebugBuild) { + return null; + } + + ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, requestUri)); + ArchiLogger.LogGenericDebug(string.Format(Strings.StatusCode, response.StatusCode)); + ArchiLogger.LogGenericDebug(string.Format(Strings.Content, await response.Content.ReadAsStringAsync().ConfigureAwait(false))); + + return null; + } } internal class BasicResponse { - internal readonly Uri RequestUri; + internal readonly Uri FinalUri; internal BasicResponse(HttpResponseMessage httpResponseMessage) { if (httpResponseMessage == null) { throw new ArgumentNullException(nameof(httpResponseMessage)); } - RequestUri = httpResponseMessage.RequestMessage.RequestUri; + FinalUri = httpResponseMessage.Headers.Location ?? httpResponseMessage.RequestMessage.RequestUri; } internal BasicResponse(BasicResponse basicResponse) { @@ -516,7 +524,7 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(basicResponse)); } - RequestUri = basicResponse.RequestUri; + FinalUri = basicResponse.FinalUri; } }