2015-11-29 00:13:03 +01:00
/ *
_ _ _ ____ _ _____
/ \ _ __ ___ | | __ ( _ ) / ___ | | | _ ___ __ _ _ __ ___ | ___ | __ _ _ __ _ __ ___
/ _ \ | ' __ | / __ | | ' _ \ | | \ ___ \ | __ | / _ \ / _ ` | | ' _ ` _ \ | | _ / _ ` | | ' __ | | ' _ ` _ \
/ ___ \ | | | ( __ | | | | | | ___ ) | | | _ | __ / | ( _ | | | | | | | | | _ | | ( _ | | | | | | | | | |
/ _ / \ _ \ | _ | \ ___ | | _ | | _ | | _ | | ____ / \ __ | \ ___ | \ __ , _ | | _ | | _ | | _ | | _ | \ __ , _ | | _ | | _ | | _ | | _ |
2017-01-02 20:05:21 +01:00
Copyright 2015 - 2017 Ł ukasz "JustArchi" Domeradzki
2015-11-29 00:13:03 +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-25 16:31:39 +01:00
using System ;
using System.Collections.Generic ;
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 {
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 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 ; // 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
2017-07-05 07:30:08 +02:00
internal WebBrowser ( ArchiLogger archiLogger , 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 {
AutomaticDecompression = DecompressionMethods . Deflate | DecompressionMethods . GZip ,
2017-07-09 09:53:26 +02:00
CookieContainer = CookieContainer ,
MaxConnectionsPerServer = MaxConnections
2016-11-24 07:46:37 +01:00
} ;
HttpClient = new HttpClient ( httpClientHandler ) {
2017-07-05 07:30:08 +02:00
Timeout = TimeSpan . FromSeconds ( extendedTimeout ? ExtendedTimeoutMultiplier * Program . GlobalConfig . ConnectionTimeout : Program . GlobalConfig . ConnectionTimeout )
2016-11-24 07:46:37 +01:00
} ;
2016-11-24 07:32:16 +01:00
// Most web services expect that UserAgent is set, so we declare it globally
2017-07-01 04:06:33 +02:00
HttpClient . DefaultRequestHeaders . UserAgent . ParseAdd ( SharedInfo . AssemblyName + "/" + 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
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 ) {
if ( string . IsNullOrEmpty ( html ) ) {
ASF . ArchiLogger . LogNullError ( nameof ( html ) ) ;
return null ;
}
HtmlDocument htmlDocument = new HtmlDocument ( ) ;
htmlDocument . LoadHtml ( html ) ;
return htmlDocument ;
}
2016-05-30 01:57:06 +02:00
internal async Task < byte [ ] > UrlGetToBytesRetry ( string request , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
byte [ ] result = null ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & ( result = = null ) ; i + + ) {
2016-05-30 01:57:06 +02:00
result = await UrlGetToBytes ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ! = null ) {
return result ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2016-08-22 00:10:29 +02:00
internal async Task < HtmlDocument > UrlGetToHtmlDocumentRetry ( string request , string referer = null ) {
2016-05-30 01:57:06 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2016-08-22 00:10:29 +02:00
HtmlDocument result = null ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & ( result = = null ) ; i + + ) {
2016-08-22 00:10:29 +02:00
result = await UrlGetToHtmlDocument ( request , referer ) . ConfigureAwait ( false ) ;
2016-05-30 01:57:06 +02:00
}
2016-08-22 00:10:29 +02:00
if ( result ! = null ) {
2016-05-30 01:57:06 +02:00
return result ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2016-08-22 00:10:29 +02:00
internal async Task < T > UrlGetToJsonResultRetry < T > ( string request , string referer = null ) {
2016-05-30 01:57:06 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2017-07-14 16:24:30 +02:00
return default ;
2016-05-30 01:57:06 +02:00
}
2016-08-22 00:10:29 +02:00
string json = await UrlGetToContentRetry ( request , referer ) . ConfigureAwait ( false ) ;
if ( string . IsNullOrEmpty ( json ) ) {
2017-07-14 16:24:30 +02:00
return default ;
2016-05-30 01:57:06 +02:00
}
2016-08-22 00:10:29 +02:00
try {
return JsonConvert . DeserializeObject < T > ( json ) ;
} 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 ) {
ArchiLogger . LogGenericDebug ( string . Format ( Strings . Content , json ) ) ;
}
2017-07-14 16:24:30 +02:00
return default ;
2016-04-12 07:40:02 +02:00
}
}
2016-05-30 01:57:06 +02:00
internal async Task < XmlDocument > UrlGetToXMLRetry ( string request , string referer = null ) {
2015-11-25 16:31:39 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
XmlDocument result = null ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & ( result = = null ) ; i + + ) {
2016-05-30 01:57:06 +02:00
result = await UrlGetToXML ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ! = null ) {
return result ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2016-11-24 07:32:16 +01:00
internal async Task < bool > UrlHeadRetry ( string request , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) ) {
ArchiLogger . LogNullError ( nameof ( request ) ) ;
return false ;
}
bool result = false ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & ! result ; i + + ) {
2016-11-24 07:32:16 +01:00
result = await UrlHead ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ) {
return true ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-11-24 07:32:16 +01:00
return false ;
}
internal async Task < Uri > UrlHeadToUriRetry ( string request , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) ) {
ArchiLogger . LogNullError ( nameof ( request ) ) ;
return null ;
}
Uri result = null ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & ( result = = null ) ; i + + ) {
2016-11-24 07:32:16 +01:00
result = await UrlHeadToUri ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ! = null ) {
return result ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-11-24 07:32:16 +01:00
return null ;
}
2017-06-26 04:02:11 +02:00
internal async Task < bool > UrlPost ( string request , ICollection < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-12-04 01:07:37 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
ArchiLogger . LogNullError ( nameof ( request ) ) ;
return false ;
}
using ( HttpResponseMessage response = await UrlPostToResponse ( request , data , referer ) . ConfigureAwait ( false ) ) {
return response ! = null ;
}
}
2016-07-16 21:03:39 +02:00
internal async Task < bool > UrlPostRetry ( string request , ICollection < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-05-30 01:57:06 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-05-30 01:57:06 +02:00
return false ;
}
bool result = false ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & ! result ; i + + ) {
2016-05-30 01:57:06 +02:00
result = await UrlPost ( request , data , referer ) . ConfigureAwait ( false ) ;
}
if ( result ) {
return true ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-05-30 01:57:06 +02:00
return false ;
}
2016-11-17 21:30:17 +01:00
internal async Task < HtmlDocument > UrlPostToHtmlDocumentRetry ( string request , ICollection < KeyValuePair < string , string > > data = null , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) ) {
ArchiLogger . LogNullError ( nameof ( request ) ) ;
return null ;
}
string content = await UrlPostToContentRetry ( request , data , referer ) . ConfigureAwait ( false ) ;
2017-02-06 15:46:42 +01:00
return ! string . IsNullOrEmpty ( content ) ? StringToHtmlDocument ( content ) : null ;
2016-11-17 21:30:17 +01:00
}
2016-08-22 00:10:29 +02:00
internal async Task < T > UrlPostToJsonResultRetry < T > ( string request , ICollection < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-07-16 21:03:39 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2017-07-14 16:24:30 +02:00
return default ;
2016-07-16 21:03:39 +02:00
}
2016-08-22 00:10:29 +02:00
string json = await UrlPostToContentRetry ( request , data , referer ) . ConfigureAwait ( false ) ;
if ( string . IsNullOrEmpty ( json ) ) {
2017-07-14 16:24:30 +02:00
return default ;
2016-07-16 21:03:39 +02:00
}
2016-08-22 00:10:29 +02:00
try {
return JsonConvert . DeserializeObject < T > ( json ) ;
} 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 ) {
ArchiLogger . LogGenericDebug ( string . Format ( Strings . Content , json ) ) ;
}
2017-07-14 16:24:30 +02:00
return default ;
2016-07-16 21:03:39 +02:00
}
}
2016-05-30 01:57:06 +02:00
private async Task < byte [ ] > UrlGetToBytes ( string request , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2015-11-25 16:31:39 +01:00
return null ;
}
2016-04-14 22:23:37 +02:00
using ( HttpResponseMessage httpResponse = await UrlGetToResponse ( request , referer ) . ConfigureAwait ( false ) ) {
if ( httpResponse = = null ) {
return null ;
}
2015-11-25 16:31:39 +01:00
2016-05-30 01:57:06 +02:00
return await httpResponse . Content . ReadAsByteArrayAsync ( ) . ConfigureAwait ( false ) ;
2015-11-25 16:31:39 +01:00
}
2016-04-12 07:40:02 +02:00
}
2016-05-30 01:57:06 +02:00
private async Task < string > UrlGetToContent ( string request , string referer = null ) {
2016-04-12 07:40:02 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2015-11-25 16:31:39 +01:00
return null ;
}
2016-04-14 22:23:37 +02:00
using ( HttpResponseMessage httpResponse = await UrlGetToResponse ( request , referer ) . ConfigureAwait ( false ) ) {
if ( httpResponse = = null ) {
return null ;
}
2016-03-09 03:10:33 +01:00
2016-05-30 01:57:06 +02:00
return await httpResponse . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
2016-03-09 03:10:33 +01:00
}
2015-11-25 16:31:39 +01:00
}
2016-08-22 00:10:29 +02:00
private async Task < string > UrlGetToContentRetry ( string request , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-08-22 00:10:29 +02:00
return null ;
}
string result = null ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & string . IsNullOrEmpty ( result ) ; i + + ) {
2016-08-22 00:10:29 +02:00
result = await UrlGetToContent ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( ! string . IsNullOrEmpty ( result ) ) {
return result ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-08-22 00:10:29 +02:00
return null ;
}
2016-05-30 01:57:06 +02:00
private async Task < HtmlDocument > UrlGetToHtmlDocument ( string request , string referer = null ) {
2015-11-25 16:31:39 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2015-11-25 16:31:39 +01:00
return null ;
}
2016-04-12 16:58:45 +02:00
string content = await UrlGetToContent ( request , referer ) . ConfigureAwait ( false ) ;
2017-02-06 15:46:42 +01:00
return ! string . IsNullOrEmpty ( content ) ? StringToHtmlDocument ( content ) : null ;
2015-11-25 16:31:39 +01:00
}
2016-05-30 01:57:06 +02:00
private async Task < HttpResponseMessage > UrlGetToResponse ( string request , string referer = null ) {
2017-07-05 07:30:08 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
ArchiLogger . LogNullError ( nameof ( request ) ) ;
return null ;
2016-05-30 01:57:06 +02:00
}
2017-07-05 07:30:08 +02:00
HttpResponseMessage result = await UrlRequest ( new Uri ( request ) , HttpMethod . Get , null , referer ) . ConfigureAwait ( false ) ;
return result ;
2016-05-30 01:57:06 +02:00
}
private async Task < XmlDocument > UrlGetToXML ( string request , string referer = null ) {
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 ;
}
2016-07-25 06:08:45 +02:00
string xml = await UrlGetToContent ( request , referer ) . ConfigureAwait ( false ) ;
if ( string . IsNullOrEmpty ( xml ) ) {
2016-03-15 04:20:28 +01:00
return null ;
}
XmlDocument xmlDocument = new XmlDocument ( ) ;
try {
2016-07-25 06:08:45 +02:00
xmlDocument . LoadXml ( xml ) ;
2016-03-15 04:20:28 +01:00
} catch ( XmlException e ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericException ( e ) ;
2016-03-15 04:20:28 +01:00
return null ;
}
return xmlDocument ;
}
2016-05-30 01:57:06 +02:00
private async Task < bool > UrlHead ( 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 ) ) ;
2016-04-29 16:37:42 +02:00
return false ;
}
2016-05-30 01:57:06 +02:00
using ( HttpResponseMessage response = await UrlHeadToResponse ( request , referer ) . ConfigureAwait ( false ) ) {
2016-04-29 16:37:42 +02:00
return response ! = null ;
}
}
2016-05-30 01:57:06 +02:00
private async Task < HttpResponseMessage > UrlHeadToResponse ( string request , string referer = null ) {
if ( ! string . IsNullOrEmpty ( request ) ) {
2017-06-26 04:02:11 +02:00
return await UrlRequest ( new Uri ( request ) , HttpMethod . Head , null , referer ) . ConfigureAwait ( false ) ;
2016-05-30 01:57:06 +02:00
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
private async Task < Uri > UrlHeadToUri ( string request , 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 ;
}
2016-05-30 01:57:06 +02:00
using ( HttpResponseMessage response = await UrlHeadToResponse ( request , referer ) . ConfigureAwait ( false ) ) {
2016-07-10 20:17:35 +02:00
return response ? . RequestMessage . RequestUri ;
2016-05-30 01:57:06 +02:00
}
2016-04-14 22:23:37 +02:00
}
2017-06-26 04:02:11 +02:00
private async Task < string > UrlPostToContent ( string request , ICollection < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-07-16 21:03:39 +02:00
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-07-16 21:03:39 +02:00
return null ;
}
using ( HttpResponseMessage httpResponse = await UrlPostToResponse ( request , data , referer ) . ConfigureAwait ( false ) ) {
if ( httpResponse = = null ) {
return null ;
}
return await httpResponse . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
}
}
2016-08-22 00:10:29 +02:00
private async Task < string > UrlPostToContentRetry ( string request , ICollection < KeyValuePair < string , string > > data = null , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-08-22 00:10:29 +02:00
return null ;
}
string result = null ;
2017-07-09 09:09:46 +02:00
for ( byte i = 0 ; ( i < MaxTries ) & & string . IsNullOrEmpty ( result ) ; i + + ) {
2016-08-22 00:10:29 +02:00
result = await UrlPostToContent ( request , data , referer ) . ConfigureAwait ( false ) ;
}
if ( ! string . IsNullOrEmpty ( result ) ) {
return result ;
}
2017-07-09 09:09:46 +02:00
ArchiLogger . LogGenericWarning ( string . Format ( Strings . ErrorRequestFailedTooManyTimes , MaxTries ) ) ;
2017-01-06 15:32:12 +01:00
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , request ) ) ;
2016-08-22 00:10:29 +02:00
return null ;
}
2017-06-26 04:02:11 +02:00
private async Task < HttpResponseMessage > UrlPostToResponse ( string request , ICollection < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-05-30 01:57:06 +02:00
if ( ! string . IsNullOrEmpty ( request ) ) {
2017-06-26 04:02:11 +02:00
return await UrlRequest ( new Uri ( request ) , HttpMethod . Post , data , referer ) . ConfigureAwait ( false ) ;
2016-04-14 22:23:37 +02:00
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) ) ;
2016-05-30 01:57:06 +02:00
return null ;
2016-04-14 22:23:37 +02:00
}
2017-07-09 09:09:46 +02:00
private async Task < HttpResponseMessage > UrlRequest ( Uri requestUri , HttpMethod httpMethod , ICollection < KeyValuePair < string , string > > data = null , string referer = null , 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 ;
}
2016-02-22 18:34:45 +01:00
HttpResponseMessage responseMessage ;
2017-06-26 04:02:11 +02:00
using ( HttpRequestMessage requestMessage = new HttpRequestMessage ( httpMethod , requestUri ) ) {
2016-07-16 21:03:39 +02:00
if ( data ! = null ) {
2016-02-22 18:34:45 +01:00
try {
requestMessage . Content = new FormUrlEncodedContent ( data ) ;
} 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 ) ) {
2016-02-22 18:34:45 +01:00
requestMessage . Headers . Referrer = new Uri ( referer ) ;
}
2015-11-25 16:31:39 +01:00
2016-02-22 18:34:45 +01:00
try {
2016-04-12 16:58:45 +02:00
responseMessage = await HttpClient . SendAsync ( requestMessage ) . ConfigureAwait ( false ) ;
2016-06-11 03:39:25 +02:00
} catch ( Exception e ) {
// This exception is really common, don't bother with it unless debug mode is enabled
2017-01-31 09:08:53 +01:00
if ( Debugging . IsUserDebugging ) {
2016-12-08 03:47:07 +01:00
ArchiLogger . LogGenericDebugException ( e ) ;
2016-06-11 03:39:25 +02:00
}
2016-02-22 18:34:45 +01:00
return null ;
}
2015-11-25 16:31:39 +01:00
}
2016-04-22 17:50:01 +02:00
if ( responseMessage = = null ) {
return null ;
}
2016-05-13 06:32:42 +02:00
if ( responseMessage . IsSuccessStatusCode ) {
return responseMessage ;
}
2017-06-26 04:02:11 +02:00
Uri redirectUri ;
using ( responseMessage ) {
2017-06-26 04:03:47 +02:00
ushort status = ( ushort ) responseMessage . StatusCode ;
2017-06-26 04:02:11 +02:00
if ( ( status > = 300 ) & & ( status < = 399 ) & & ( maxRedirections > 0 ) ) {
redirectUri = responseMessage . Headers . Location ;
2017-08-01 18:59:10 +02:00
2017-08-01 19:04:55 +02:00
if ( redirectUri . IsAbsoluteUri ) {
switch ( redirectUri . Scheme ) {
case "http" :
case "https" :
break ;
default :
// Invalid ones such as "steammobile"
return null ;
}
} else {
2017-06-26 04:02:11 +02:00
redirectUri = new Uri ( requestUri . GetLeftPart ( UriPartial . Authority ) + redirectUri ) ;
}
} else {
if ( ! Debugging . IsDebugBuild ) {
return null ;
}
ArchiLogger . LogGenericDebug ( string . Format ( Strings . ErrorFailingRequest , requestUri ) ) ;
ArchiLogger . LogGenericDebug ( string . Format ( Strings . StatusCode , responseMessage . StatusCode ) ) ;
ArchiLogger . LogGenericDebug ( string . Format ( Strings . Content , await responseMessage . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ) ) ;
return null ;
}
2015-11-25 16:31:39 +01:00
}
2017-06-26 04:02:11 +02:00
return await UrlRequest ( redirectUri , httpMethod , data , referer , - - maxRedirections ) . ConfigureAwait ( false ) ;
2015-11-25 16:31:39 +01:00
}
}
2016-11-24 07:32:16 +01:00
}