2015-11-29 00:13:03 +01:00
/ *
_ _ _ ____ _ _____
/ \ _ __ ___ | | __ ( _ ) / ___ | | | _ ___ __ _ _ __ ___ | ___ | __ _ _ __ _ __ ___
/ _ \ | ' __ | / __ | | ' _ \ | | \ ___ \ | __ | / _ \ / _ ` | | ' _ ` _ \ | | _ / _ ` | | ' __ | | ' _ ` _ \
/ ___ \ | | | ( __ | | | | | | ___ ) | | | _ | __ / | ( _ | | | | | | | | | _ | | ( _ | | | | | | | | | |
/ _ / \ _ \ | _ | \ ___ | | _ | | _ | | _ | | ____ / \ __ | \ ___ | \ __ , _ | | _ | | _ | | _ | | _ | \ __ , _ | | _ | | _ | | _ | | _ |
2016-01-16 04:21:36 +01:00
Copyright 2015 - 2016 Ł 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 ;
2016-11-24 07:32:16 +01:00
using HtmlAgilityPack ;
using Newtonsoft.Json ;
using Newtonsoft.Json.Linq ;
2015-11-25 16:31:39 +01:00
namespace ArchiSteamFarm {
2016-04-12 16:58:45 +02:00
internal sealed class WebBrowser {
2016-01-14 20:37:01 +01:00
internal const byte MaxRetries = 5 ; // Defines maximum number of retries, UrlRequest() does not handle retry by itself (it's app responsibility)
2016-01-14 02:48:56 +01:00
2016-03-15 05:15:22 +01:00
private const byte MaxConnections = 10 ; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state
private const byte MaxIdleTime = 15 ; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
2016-04-12 16:58:45 +02:00
internal readonly CookieContainer CookieContainer = new CookieContainer ( ) ;
2016-03-06 23:28:56 +01:00
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
2016-11-24 07:32:16 +01:00
internal WebBrowser ( ArchiLogger archiLogger ) {
if ( archiLogger = = null ) {
throw new ArgumentNullException ( nameof ( archiLogger ) ) ;
}
ArchiLogger = archiLogger ;
2016-11-24 07:46:37 +01:00
HttpClientHandler httpClientHandler = new HttpClientHandler {
AutomaticDecompression = DecompressionMethods . Deflate | DecompressionMethods . GZip ,
CookieContainer = CookieContainer
} ;
HttpClient = new HttpClient ( httpClientHandler ) {
Timeout = TimeSpan . FromSeconds ( Program . GlobalConfig . HttpTimeout )
} ;
2016-11-24 07:32:16 +01:00
// Most web services expect that UserAgent is set, so we declare it globally
HttpClient . DefaultRequestHeaders . UserAgent . ParseAdd ( "ArchiSteamFarm/" + SharedInfo . Version ) ;
}
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
2016-04-12 07:40:02 +02:00
#if ! __MonoCS__
2016-07-25 06:53:16 +02:00
// We run Windows-compiled ASF on both Windows and Mono. Normally we'd simply put code in the if
2016-07-25 06:44:10 +02:00
// However, if we did that, then we would still crash on Mono due to potentially calling non-existing methods
// Therefore, call mono-incompatible options in their own function to avoid that, and just leave the function call here
// When compiling on Mono, this section is omitted entirely as we never run Mono-compiled ASF on Windows
2016-07-25 06:53:16 +02:00
// Moreover, Mono compiler doesn't even include ReusePort field in ServicePointManager, so it's crucial to avoid compilation error
2016-08-02 22:51:09 +02:00
if ( Runtime . IsRuntimeSupported & & ! Runtime . IsRunningOnMono ) {
2016-07-25 06:44:10 +02:00
InitNonMonoBehaviour ( ) ;
}
2016-04-12 07:40:02 +02:00
#endif
2015-11-25 16:31:39 +01:00
}
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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & ( result = = null ) ; i + + ) {
result = await UrlGetToBytes ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ! = null ) {
return result ;
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + 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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & ( result = = null ) ; i + + ) {
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 ;
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + request ) ;
2016-05-30 01:57:06 +02:00
return null ;
}
2016-08-22 00:10:29 +02:00
internal async Task < JObject > UrlGetToJObjectRetry ( 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
JObject result = null ;
2016-05-30 01:57:06 +02:00
for ( byte i = 0 ; ( i < MaxRetries ) & & ( result = = null ) ; i + + ) {
2016-08-22 00:10:29 +02:00
result = await UrlGetToJObject ( request , referer ) . ConfigureAwait ( false ) ;
2016-05-30 01:57:06 +02:00
}
if ( result ! = null ) {
return result ;
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + 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 ) ) ;
2016-08-22 00:10:29 +02:00
return default ( T ) ;
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 ) ) {
return default ( T ) ;
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 ) ;
2016-08-22 00:10:29 +02:00
return default ( T ) ;
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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & ( result = = null ) ; i + + ) {
result = await UrlGetToXML ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ! = null ) {
return result ;
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + 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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & ! result ; i + + ) {
result = await UrlHead ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ) {
return true ;
}
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + 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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & ( result = = null ) ; i + + ) {
result = await UrlHeadToUri ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( result ! = null ) {
return result ;
}
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + request ) ;
2016-11-24 07:32:16 +01:00
return null ;
}
2016-12-04 01:07:37 +01:00
internal async Task < bool > UrlPost ( string request , IEnumerable < KeyValuePair < string , string > > data = null , string referer = null ) {
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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & ! result ; i + + ) {
result = await UrlPost ( request , data , referer ) . ConfigureAwait ( false ) ;
}
if ( result ) {
return true ;
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + 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 ) ;
if ( string . IsNullOrEmpty ( content ) ) {
return null ;
}
HtmlDocument htmlDocument = new HtmlDocument ( ) ;
htmlDocument . LoadHtml ( WebUtility . HtmlDecode ( content ) ) ;
return htmlDocument ;
}
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 ) ) ;
2016-08-22 00:10:29 +02:00
return default ( T ) ;
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 ) ) {
return default ( T ) ;
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 ) ;
2016-08-22 00:10:29 +02:00
return default ( T ) ;
2016-07-16 21:03:39 +02:00
}
}
2016-11-24 07:32:16 +01:00
#if ! __MonoCS__
private static void InitNonMonoBehaviour ( ) = > ServicePointManager . ReusePort = true ;
#endif
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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & string . IsNullOrEmpty ( result ) ; i + + ) {
result = await UrlGetToContent ( request , referer ) . ConfigureAwait ( false ) ;
}
if ( ! string . IsNullOrEmpty ( result ) ) {
return result ;
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + 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 ) ;
2016-02-22 18:34:45 +01:00
if ( string . IsNullOrEmpty ( content ) ) {
2016-01-14 02:48:56 +01:00
return null ;
}
2016-02-22 18:34:45 +01:00
HtmlDocument htmlDocument = new HtmlDocument ( ) ;
2016-04-22 17:50:01 +02:00
htmlDocument . LoadHtml ( WebUtility . HtmlDecode ( content ) ) ;
2016-02-22 18:34:45 +01:00
return htmlDocument ;
2015-11-25 16:31:39 +01:00
}
2016-05-30 01:57:06 +02:00
private async Task < JObject > UrlGetToJObject ( 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-07-25 06:08:45 +02:00
string json = await UrlGetToContent ( request , referer ) . ConfigureAwait ( false ) ;
if ( string . IsNullOrEmpty ( json ) ) {
2015-11-25 16:31:39 +01:00
return null ;
}
2016-01-14 02:48:56 +01:00
JObject jObject ;
try {
2016-07-25 06:08:45 +02:00
jObject = JObject . Parse ( json ) ;
2016-04-12 07:40:02 +02:00
} catch ( JsonException e ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericException ( e ) ;
2015-11-25 16:31:39 +01:00
return null ;
}
2016-01-14 02:48:56 +01:00
return jObject ;
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 ) {
if ( ! string . IsNullOrEmpty ( request ) ) {
return await UrlRequest ( request , HttpMethod . Get , null , referer ) . ConfigureAwait ( false ) ;
}
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 < 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 ) ) {
return await UrlRequest ( request , HttpMethod . Head , null , referer ) . ConfigureAwait ( false ) ;
}
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
}
2016-07-16 21:03:39 +02:00
private async Task < string > UrlPostToContent ( string request , IEnumerable < 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-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 ;
for ( byte i = 0 ; ( i < MaxRetries ) & & string . IsNullOrEmpty ( result ) ; i + + ) {
result = await UrlPostToContent ( request , data , referer ) . ConfigureAwait ( false ) ;
}
if ( ! string . IsNullOrEmpty ( result ) ) {
return result ;
}
2016-11-06 12:06:02 +01:00
ArchiLogger . LogGenericWarning ( "Request failed even after " + MaxRetries + " tries" ) ;
2016-12-08 01:02:45 +01:00
ArchiLogger . LogGenericDebug ( "Failing request: " + request ) ;
2016-08-22 00:10:29 +02:00
return null ;
}
2016-07-16 21:03:39 +02:00
private async Task < HttpResponseMessage > UrlPostToResponse ( string request , IEnumerable < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-05-30 01:57:06 +02:00
if ( ! string . IsNullOrEmpty ( request ) ) {
return await UrlRequest ( 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
}
2016-07-16 21:03:39 +02:00
private async Task < HttpResponseMessage > UrlRequest ( string request , HttpMethod httpMethod , IEnumerable < KeyValuePair < string , string > > data = null , string referer = null ) {
2016-05-13 06:32:42 +02:00
if ( string . IsNullOrEmpty ( request ) | | ( httpMethod = = null ) ) {
2016-11-06 12:06:02 +01:00
ArchiLogger . LogNullError ( nameof ( request ) + " || " + nameof ( httpMethod ) ) ;
2015-11-25 16:31:39 +01:00
return null ;
}
2016-02-22 18:34:45 +01:00
HttpResponseMessage responseMessage ;
using ( HttpRequestMessage requestMessage = new HttpRequestMessage ( httpMethod , request ) ) {
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
if ( Debugging . IsDebugBuild | | Program . GlobalConfig . Debug ) {
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 ;
}
if ( Debugging . IsDebugBuild | | Program . GlobalConfig . Debug ) {
2016-12-08 03:47:07 +01:00
ArchiLogger . LogGenericDebug ( "Request: " + request + " failed!" ) ;
ArchiLogger . LogGenericDebug ( "Status code: " + responseMessage . StatusCode ) ;
ArchiLogger . LogGenericDebug ( "Content: " + Environment . NewLine + await responseMessage . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ) ;
2015-11-25 16:31:39 +01:00
}
2016-05-13 06:32:42 +02:00
responseMessage . Dispose ( ) ;
return null ;
2015-11-25 16:31:39 +01:00
}
}
2016-11-24 07:32:16 +01:00
}