2017-11-18 17:27:06 +01:00
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
//
2018-01-01 02:56:53 +01:00
// Copyright 2015-2018 Łukasz "JustArchi" Domeradzki
2017-11-18 17:27:06 +01:00
// Contact: JustArchi@JustArchi.net
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2015-11-29 00:13:03 +01:00
2015-11-25 16:31:39 +01:00
using System ;
using System.Collections.Generic ;
2017-12-16 11:34:04 +01:00
using System.IO ;
2015-11-25 16:31:39 +01:00
using System.Net ;
using System.Net.Http ;
using System.Threading.Tasks ;
2016-03-15 04:20:28 +01:00
using System.Xml ;
2017-01-06 15:32:12 +01:00
using ArchiSteamFarm.Localization ;
2016-11-24 07:32:16 +01:00
using HtmlAgilityPack ;
using Newtonsoft.Json ;
2015-11-25 16:31:39 +01:00
namespace ArchiSteamFarm {
2017-08-04 19:26:37 +02:00
internal sealed class WebBrowser : IDisposable {
2018-04-13 09:49:54 +02:00
internal 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
2017-07-09 09:09:46 +02:00
internal const byte MaxTries = 5 ; // Defines maximum number of recommended tries for a single request
2016-01-14 02:48:56 +01:00
2017-07-09 09:09:46 +02:00
private const byte ExtendedTimeoutMultiplier = 10 ; // Defines multiplier of timeout for WebBrowsers dealing with huge data (ASF update)
private const byte MaxIdleTime = 15 ; // Defines in seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
2016-03-15 05:15:22 +01:00
2016-04-12 16:58:45 +02:00
internal readonly CookieContainer CookieContainer = new CookieContainer ( ) ;
2016-03-06 23:28:56 +01:00
2017-09-09 20:24:57 +02:00
internal TimeSpan Timeout = > HttpClient . Timeout ;
2016-11-06 12:06:02 +01:00
private readonly ArchiLogger ArchiLogger ;
2016-04-12 16:58:45 +02:00
private readonly HttpClient HttpClient ;
2015-12-01 01:34:05 +01:00
2018-05-09 05:31:48 +02:00
internal WebBrowser ( ArchiLogger archiLogger , IWebProxy webProxy = null , bool extendedTimeout = false ) {
2017-03-14 08:20:29 -03:00
ArchiLogger = archiLogger ? ? throw new ArgumentNullException ( nameof ( archiLogger ) ) ;
2016-11-24 07:32:16 +01:00
2016-11-24 07:46:37 +01:00
HttpClientHandler httpClientHandler = new HttpClientHandler {
2018-02-17 03:57:09 +01:00
AllowAutoRedirect = false , // This must be false if we want to handle custom redirection schemes such as "steammobile"
2016-11-24 07:46:37 +01:00
AutomaticDecompression = DecompressionMethods . Deflate | DecompressionMethods . GZip ,
2017-07-09 09:53:26 +02:00
CookieContainer = CookieContainer ,
2018-05-09 05:31:48 +02:00
Proxy = webProxy ,
UseProxy = webProxy ! = null
2016-11-24 07:46:37 +01:00
} ;
2018-06-03 07:51:20 +02:00
if ( ! RuntimeCompatibility . IsRunningOnMono ) {
httpClientHandler . MaxConnectionsPerServer = MaxConnections ;
}
2017-11-28 21:31:45 +01:00
HttpClient = new HttpClient ( httpClientHandler ) { Timeout = TimeSpan . FromSeconds ( extendedTimeout ? ExtendedTimeoutMultiplier * Program . GlobalConfig . ConnectionTimeout : Program . GlobalConfig . ConnectionTimeout ) } ;
2016-11-24 07:32:16 +01:00
// Most web services expect that UserAgent is set, so we declare it globally
2017-12-29 03:40:44 +01:00
HttpClient . DefaultRequestHeaders . UserAgent . ParseAdd ( SharedInfo . PublicIdentifier + "/" + SharedInfo . Version ) ;
2016-11-24 07:32:16 +01:00
}
2017-08-04 19:26:37 +02:00
public void Dispose ( ) = > HttpClient . Dispose ( ) ;
2016-04-12 16:58:45 +02:00
internal static void Init ( ) {
2016-01-14 20:37:01 +01:00
// Set max connection limit from default of 2 to desired value
ServicePointManager . DefaultConnectionLimit = MaxConnections ;
// Set max idle time from default of 100 seconds (100 * 1000) to desired value
2016-11-24 07:49:44 +01:00
ServicePointManager . MaxServicePointIdleTime = MaxIdleTime * 1000 ;
2015-12-13 15:25:00 +01:00
2016-01-14 20:37:01 +01:00
// Don't use Expect100Continue, we're sure about our POSTs, save some TCP packets
2015-12-13 15:25:00 +01:00
ServicePointManager . Expect100Continue = false ;
2015-11-25 16:31:39 +01:00
2017-06-26 03:36:51 +02:00
// Reuse ports if possible
2018-06-03 07:51:20 +02:00
if ( ! RuntimeCompatibility . IsRunningOnMono ) {
ServicePointManager . ReusePort = true ;
}
2015-11-25 16:31:39 +01:00
}
2017-02-06 15:46:42 +01:00
internal static HtmlDocument StringToHtmlDocument ( string html ) {
2018-02-17 03:57:09 +01:00
if ( html = = null ) {
2017-02-06 15:46:42 +01:00
ASF . ArchiLogger . LogNullError ( nameof ( html ) ) ;
return null ;
}
HtmlDocument htmlDocument = new HtmlDocument ( ) ;
htmlDocument . LoadHtml ( html ) ;
return htmlDocument ;
}
2018-03-09 23:48:47 +01:00
internal async Task < BinaryResponse > UrlGetToBinaryWithProgress ( string request , string referer = null , byte maxTries = MaxTries ) {
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2018-03-09 23:51:51 +01:00
for ( byte i = 0 ; i < maxTries ; i + + ) {
2018-03-09 23:48:47 +01:00
const byte printPercentage = 10 ;
const byte maxBatches = 99 / printPercentage ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
2018-03-09 23:48:47 +01:00
using ( HttpResponseMessage response = await InternalGet ( request , referer , HttpCompletionOption . ResponseHeadersRead ) . ConfigureAwait ( false ) ) {
if ( response = = null ) {
continue ;
}
2016-05-30 01:57:06 +02:00
2018-03-09 23:48:47 +01:00
ArchiLogger . LogGenericDebug ( "0%..." ) ;
uint contentLength = ( uint ) response . Content . Headers . ContentLength . GetValueOrDefault ( ) ;
using ( MemoryStream ms = new MemoryStream ( ( int ) contentLength ) ) {
try {
using ( Stream contentStream = await response . Content . ReadAsStreamAsync ( ) . ConfigureAwait ( false ) ) {
byte batch = 0 ;
uint readThisBatch = 0 ;
byte [ ] buffer = new byte [ 8192 ] ; // This is HttpClient's buffer, using more doesn't make sense
while ( contentStream . CanRead ) {
int read = await contentStream . ReadAsync ( buffer , 0 , buffer . Length ) . ConfigureAwait ( false ) ;
if ( read = = 0 ) {
break ;
}
await ms . WriteAsync ( buffer , 0 , read ) . ConfigureAwait ( false ) ;
if ( ( contentLength = = 0 ) | | ( batch > = maxBatches ) ) {
continue ;
}
readThisBatch + = ( uint ) read ;
if ( readThisBatch < contentLength / printPercentage ) {
continue ;
}
readThisBatch - = contentLength / printPercentage ;
ArchiLogger . LogGenericDebug ( + + batch * printPercentage + "%..." ) ;
}
}
} catch ( Exception e ) {
ArchiLogger . LogGenericDebuggingException ( e ) ;
return null ;
}
ArchiLogger . LogGenericDebug ( "100%" ) ;
return new BinaryResponse ( response , ms . ToArray ( ) ) ;
}
}
2016-05-30 01:57:06 +02:00
}
2018-03-10 02:33:50 +01:00
if ( maxTries > 1 ) {
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , maxTries ) ) ;
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
}
2018-03-09 23:48:47 +01:00
return null ;
2016-05-30 01:57:06 +02:00
}
2018-03-09 23:48:47 +01:00
internal async Task < HtmlDocumentResponse > UrlGetToHtmlDocument ( string request , string referer = null , byte maxTries = MaxTries ) {
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2018-03-09 23:48:47 +01:00
StringResponse response = await UrlGetToString ( request , referer , maxTries ) . ConfigureAwait ( false ) ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return response ! = null ? new HtmlDocumentResponse ( response ) : null ;
2016-05-30 01:57:06 +02:00
}
2018-03-10 12:52:23 +01:00
internal async Task < ObjectResponse < T > > UrlGetToJsonObject < T > ( string request , string referer = null , byte maxTries = MaxTries ) where T : class {
2018-03-09 23:48:47 +01:00
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-05-30 01:57:06 +02:00
}
2018-03-09 23:48:47 +01:00
StringResponse response = await UrlGetToString ( request , referer , maxTries ) . ConfigureAwait ( false ) ;
2018-03-09 18:02:39 +01:00
if ( string . IsNullOrEmpty ( response ? . Content ) ) {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-05-30 01:57:06 +02:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
T obj ;
2016-08-22 00:10:29 +02:00
try {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
obj = JsonConvert . DeserializeObject < T > ( response . Content ) ;
2016-08-22 00:10:29 +02:00
} catch ( JsonException e ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericException ( e ) ;
2017-04-05 14:16:47 +02:00
if ( Debugging . IsUserDebugging ) {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . Content , response . Content ) ) ;
2017-04-05 14:16:47 +02:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-04-12 07:40:02 +02:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return new ObjectResponse < T > ( response , obj ) ;
2016-04-12 07:40:02 +02:00
}
2018-03-16 23:37:27 +01:00
internal async Task < XmlDocumentResponse > UrlGetToXmlDocument ( string request , string referer = null , byte maxTries = MaxTries ) {
2018-03-09 23:48:47 +01:00
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2018-03-09 23:48:47 +01:00
StringResponse response = await UrlGetToString ( request , referer , maxTries ) . ConfigureAwait ( false ) ;
2018-03-09 18:02:39 +01:00
if ( string . IsNullOrEmpty ( response ? . Content ) ) {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-11-24 07:32:16 +01:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
XmlDocument xmlDocument = new XmlDocument ( ) ;
2016-11-24 07:32:16 +01:00
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
try {
xmlDocument . LoadXml ( response . Content ) ;
} catch ( XmlException e ) {
ArchiLogger . LogGenericException ( e ) ;
return null ;
2016-11-24 07:32:16 +01:00
}
2018-03-16 23:37:27 +01:00
return new XmlDocumentResponse ( response , xmlDocument ) ;
2016-11-24 07:32:16 +01:00
}
2018-03-09 23:48:47 +01:00
internal async Task < BasicResponse > UrlHead ( string request , string referer = null , byte maxTries = MaxTries ) {
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
2018-03-09 15:43:25 +01:00
return null ;
2016-11-24 07:32:16 +01:00
}
2018-03-09 23:48:47 +01:00
for ( byte i = 0 ; i < maxTries ; i + + ) {
using ( HttpResponseMessage response = await InternalHead ( request , referer ) . ConfigureAwait ( false ) ) {
if ( response = = null ) {
continue ;
}
2016-11-24 07:32:16 +01:00
2018-03-09 23:48:47 +01:00
return new BasicResponse ( response ) ;
}
2016-12-04 01:07:37 +01:00
}
2018-03-10 02:33:50 +01:00
if ( maxTries > 1 ) {
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , maxTries ) ) ;
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
}
2018-03-09 23:48:47 +01:00
return null ;
2016-12-04 01:07:37 +01:00
}
2018-03-09 23:48:47 +01:00
internal async Task < BasicResponse > UrlPost ( string request , IReadOnlyCollection < KeyValuePair < string , string > > data = null , string referer = null , byte maxTries = MaxTries ) {
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-05-30 01:57:06 +02:00
}
2018-03-09 23:48:47 +01:00
for ( byte i = 0 ; i < maxTries ; i + + ) {
using ( HttpResponseMessage response = await InternalPost ( request , data , referer ) . ConfigureAwait ( false ) ) {
if ( response = = null ) {
continue ;
}
2016-05-30 01:57:06 +02:00
2018-03-09 23:48:47 +01:00
return new BasicResponse ( response ) ;
}
2016-05-30 01:57:06 +02:00
}
2018-03-10 02:33:50 +01:00
if ( maxTries > 1 ) {
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , maxTries ) ) ;
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
}
2018-03-09 23:48:47 +01:00
return null ;
2016-05-30 01:57:06 +02:00
}
2018-03-09 23:48:47 +01:00
internal async Task < HtmlDocumentResponse > UrlPostToHtmlDocument ( string request , IReadOnlyCollection < KeyValuePair < string , string > > data = null , string referer = null , byte maxTries = MaxTries ) {
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
2016-11-17 21:30:17 +01:00
return null ;
}
2018-03-09 23:48:47 +01:00
StringResponse response = await UrlPostToString ( request , data , referer , maxTries ) . ConfigureAwait ( false ) ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return response ! = null ? new HtmlDocumentResponse ( response ) : null ;
2016-11-17 21:30:17 +01:00
}
2018-03-10 12:52:23 +01:00
internal async Task < ObjectResponse < T > > UrlPostToJsonObject < T > ( string request , IReadOnlyCollection < KeyValuePair < string , string > > data = null , string referer = null , byte maxTries = MaxTries ) where T : class {
2018-03-09 23:48:47 +01:00
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-07-16 21:03:39 +02:00
}
2018-03-09 23:48:47 +01:00
StringResponse response = await UrlPostToString ( request , data , referer , maxTries ) . ConfigureAwait ( false ) ;
2018-03-09 18:02:39 +01:00
if ( string . IsNullOrEmpty ( response ? . Content ) ) {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-07-16 21:03:39 +02:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
T obj ;
2016-08-22 00:10:29 +02:00
try {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
obj = JsonConvert . DeserializeObject < T > ( response . Content ) ;
2016-08-22 00:10:29 +02:00
} catch ( JsonException e ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericException ( e ) ;
2017-04-05 14:16:47 +02:00
if ( Debugging . IsUserDebugging ) {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . Content , response . Content ) ) ;
2017-04-05 14:16:47 +02:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-07-16 21:03:39 +02:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return new ObjectResponse < T > ( response , obj ) ;
2016-07-16 21:03:39 +02:00
}
2018-03-09 23:48:47 +01:00
private async Task < HttpResponseMessage > InternalGet ( string request , string referer = null , HttpCompletionOption httpCompletionOptions = HttpCompletionOption . ResponseContentRead ) {
2016-03-15 04:20:28 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-03-15 04:20:28 +01:00
return null ;
}
2018-03-09 23:48:47 +01:00
return await InternalRequest ( new Uri ( request ) , HttpMethod . Get , null , referer , httpCompletionOptions ) . ConfigureAwait ( false ) ;
2016-03-15 04:20:28 +01:00
}
2018-03-09 23:48:47 +01:00
private async Task < HttpResponseMessage > InternalHead ( string request , string referer = null ) {
2016-04-29 16:37:42 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
return null ;
2016-05-30 01:57:06 +02:00
}
2018-03-09 23:48:47 +01:00
return await InternalRequest ( new Uri ( request ) , HttpMethod . Head , null , referer ) . ConfigureAwait ( false ) ;
2016-05-30 01:57:06 +02:00
}
2018-03-09 23:48:47 +01:00
private async Task < HttpResponseMessage > InternalPost ( string request , IReadOnlyCollection < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-04-14 22:23:37 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-04-14 22:23:37 +02:00
return null ;
}
2018-03-09 23:48:47 +01:00
return await InternalRequest ( new Uri ( request ) , HttpMethod . Post , data , referer ) . ConfigureAwait ( false ) ;
2016-04-14 22:23:37 +02:00
}
2018-03-09 23:48:47 +01:00
private async Task < HttpResponseMessage > InternalRequest ( Uri requestUri , HttpMethod httpMethod , IReadOnlyCollection < KeyValuePair < string , string > > data = null , string referer = null , HttpCompletionOption httpCompletionOption = HttpCompletionOption . ResponseContentRead , byte maxRedirections = MaxTries ) {
2017-06-26 04:02:11 +02:00
if ( ( requestUri = = null ) | | ( httpMethod = = null ) ) {
ArchiLogger . LogNullError ( nameof ( requestUri ) + " || " + nameof ( httpMethod ) ) ;
2015-11-25 16:31:39 +01:00
return null ;
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
HttpResponseMessage response ;
using ( HttpRequestMessage request = new HttpRequestMessage ( httpMethod , requestUri ) ) {
2016-07-16 21:03:39 +02:00
if ( data ! = null ) {
2016-02-22 18:34:45 +01:00
try {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
request . Content = new FormUrlEncodedContent ( data ) ;
2016-02-22 18:34:45 +01:00
} catch ( UriFormatException e ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericException ( e ) ;
2016-02-22 18:34:45 +01:00
return null ;
}
}
2015-11-25 16:31:39 +01:00
2016-03-09 03:10:33 +01:00
if ( ! string . IsNullOrEmpty ( referer ) ) {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
request . Headers . Referrer = new Uri ( referer ) ;
2016-02-22 18:34:45 +01:00
}
2015-11-25 16:31:39 +01:00
2018-04-11 18:32:45 +02:00
if ( Debugging . IsUserDebugging ) {
ArchiLogger . LogGenericDebug ( httpMethod + " " + requestUri ) ;
}
2016-02-22 18:34:45 +01:00
try {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
response = await HttpClient . SendAsync ( request , httpCompletionOption ) . ConfigureAwait ( false ) ;
2016-06-11 03:39:25 +02:00
} catch ( Exception e ) {
2017-11-26 19:08:48 +01:00
ArchiLogger . LogGenericDebuggingException ( e ) ;
2016-02-22 18:34:45 +01:00
return null ;
}
2015-11-25 16:31:39 +01:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
if ( response = = null ) {
2018-04-11 22:23:31 +02:00
if ( Debugging . IsUserDebugging ) {
ArchiLogger . LogGenericDebug ( "null <- " + httpMethod + " " + requestUri ) ;
}
2016-04-22 17:50:01 +02:00
return null ;
}
2018-04-11 22:23:31 +02:00
if ( Debugging . IsUserDebugging ) {
ArchiLogger . LogGenericDebug ( response . StatusCode + " <- " + httpMethod + " " + requestUri ) ;
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
if ( response . IsSuccessStatusCode ) {
return response ;
2016-05-13 06:32:42 +02:00
}
2018-02-17 03:57:09 +01:00
// WARNING: We still have undisposed response by now, make sure to dispose it ASAP if we're not returning it!
2018-02-17 04:07:26 +01:00
if ( ( response . StatusCode > = HttpStatusCode . Ambiguous ) & & ( response . StatusCode < HttpStatusCode . BadRequest ) & & ( maxRedirections > 0 ) ) {
2018-02-17 03:57:09 +01:00
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 ;
2017-06-26 04:02:11 +02:00
}
} else {
2018-02-17 03:57:09 +01:00
redirectUri = new Uri ( requestUri . GetLeftPart ( UriPartial . Authority ) + redirectUri ) ;
}
2017-06-26 04:02:11 +02:00
2018-02-17 03:57:09 +01:00
response . Dispose ( ) ;
2018-03-09 23:48:47 +01:00
return await InternalRequest ( redirectUri , httpMethod , data , referer , httpCompletionOption , - - maxRedirections ) . ConfigureAwait ( false ) ;
2018-02-17 03:57:09 +01:00
}
2018-04-13 09:17:27 +02:00
using ( response ) {
if ( Debugging . IsUserDebugging ) {
ArchiLogger . LogGenericDebug ( string . Format ( Strings . Content , await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ) ) ;
}
return null ;
}
2015-11-25 16:31:39 +01:00
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
2018-03-09 23:48:47 +01:00
private async Task < StringResponse > UrlGetToString ( string request , string referer = null , byte maxTries = MaxTries ) {
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
return null ;
}
for ( byte i = 0 ; i < maxTries ; i + + ) {
using ( HttpResponseMessage response = await InternalGet ( request , referer ) . ConfigureAwait ( false ) ) {
if ( response = = null ) {
continue ;
}
return new StringResponse ( response , await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ) ;
}
}
2018-03-10 02:33:50 +01:00
if ( maxTries > 1 ) {
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , maxTries ) ) ;
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
}
2018-03-09 23:48:47 +01:00
return null ;
}
private async Task < StringResponse > UrlPostToString ( string request , IReadOnlyCollection < KeyValuePair < string , string > > data = null , string referer = null , byte maxTries = MaxTries ) {
if ( string . IsNullOrEmpty ( request ) | | ( maxTries = = 0 ) ) {
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( maxTries ) ) ;
return null ;
}
for ( byte i = 0 ; i < maxTries ; i + + ) {
using ( HttpResponseMessage response = await InternalPost ( request , data , referer ) . ConfigureAwait ( false ) ) {
if ( response = = null ) {
continue ;
}
return new StringResponse ( response , await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ) ;
}
}
2018-03-10 02:33:50 +01:00
if ( maxTries > 1 ) {
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , maxTries ) ) ;
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
}
2018-03-09 23:48:47 +01:00
return null ;
}
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
internal class BasicResponse {
2018-02-17 03:57:09 +01:00
internal readonly Uri FinalUri ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
internal BasicResponse ( HttpResponseMessage httpResponseMessage ) {
if ( httpResponseMessage = = null ) {
throw new ArgumentNullException ( nameof ( httpResponseMessage ) ) ;
}
2018-02-17 03:57:09 +01:00
FinalUri = httpResponseMessage . Headers . Location ? ? httpResponseMessage . RequestMessage . RequestUri ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
}
internal BasicResponse ( BasicResponse basicResponse ) {
if ( basicResponse = = null ) {
throw new ArgumentNullException ( nameof ( basicResponse ) ) ;
}
2018-02-17 03:57:09 +01:00
FinalUri = basicResponse . FinalUri ;
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
}
}
internal sealed class BinaryResponse : BasicResponse {
internal readonly byte [ ] Content ;
internal BinaryResponse ( HttpResponseMessage httpResponseMessage , byte [ ] content ) : base ( httpResponseMessage ) {
if ( ( httpResponseMessage = = null ) | | ( content = = null ) ) {
throw new ArgumentNullException ( nameof ( httpResponseMessage ) + " || " + nameof ( content ) ) ;
}
Content = content ;
}
}
internal sealed class HtmlDocumentResponse : BasicResponse {
internal readonly HtmlDocument Content ;
internal HtmlDocumentResponse ( StringResponse stringResponse ) : base ( stringResponse ) {
if ( stringResponse = = null ) {
throw new ArgumentNullException ( nameof ( stringResponse ) ) ;
}
Content = StringToHtmlDocument ( stringResponse . Content ) ;
}
}
internal sealed class ObjectResponse < T > : BasicResponse {
internal readonly T Content ;
internal ObjectResponse ( StringResponse stringResponse , T content ) : base ( stringResponse ) {
if ( stringResponse = = null ) {
throw new ArgumentNullException ( nameof ( stringResponse ) ) ;
}
Content = content ;
}
}
internal sealed class StringResponse : BasicResponse {
internal readonly string Content ;
internal StringResponse ( HttpResponseMessage httpResponseMessage , string content ) : base ( httpResponseMessage ) {
if ( ( httpResponseMessage = = null ) | | ( content = = null ) ) {
throw new ArgumentNullException ( nameof ( httpResponseMessage ) + " || " + nameof ( content ) ) ;
}
Content = content ;
}
}
2018-03-16 23:37:27 +01:00
internal sealed class XmlDocumentResponse : BasicResponse {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
internal readonly XmlDocument Content ;
2018-03-16 23:37:27 +01:00
internal XmlDocumentResponse ( StringResponse stringResponse , XmlDocument content ) : base ( stringResponse ) {
Rewrite entire ASF HTTP stack
Previous implementation was quite naive and assumed a lot of non-guaranteed premises. Checking if our session is valid before doing each request is very stupid, but it was needed for multi-user sessions. Next, even if we checked that our session is valid (or revalidated it if needed), we then assumed it's valid for at least X seconds, which is once again entirely false. Moreover, on top of those two issues, refreshing our session could do absolutely nothing as there is no guarantee that once-refreshes session stays like that even for our very next request.
Get rid of all of this shit and rewrite it with proper mechanism. We're making a request, if that request results in redirection to session refresh, refresh session, then repeat the same request again. Add failsafes for infinite loops, make it enough thread-safe and optimized for concurrent usage.
This commit won't only improve previously half-valid implementation, but will also greatly optimize number of requests being sent, as we won't need to check our session before each request. The entire thing should work like that since beginning.
2018-02-16 15:49:18 +01:00
if ( stringResponse = = null ) {
throw new ArgumentNullException ( nameof ( stringResponse ) ) ;
}
Content = content ;
}
}
2015-11-25 16:31:39 +01:00
}
2016-11-24 07:32:16 +01:00
}