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 .
* /
using HtmlAgilityPack ;
2015-11-25 16:31:39 +01:00
using Newtonsoft.Json.Linq ;
using System ;
using System.Collections.Generic ;
using System.Net ;
using System.Net.Http ;
using System.Text ;
using System.Threading.Tasks ;
namespace ArchiSteamFarm {
internal static class WebBrowser {
2016-01-14 20:37:01 +01:00
internal const byte HttpTimeout = 180 ; // In seconds, how long we can wait for server's response
2016-02-22 18:34:45 +01: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
2016-01-14 20:37:01 +01:00
internal const byte MaxIdleTime = 15 ; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
internal 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-01-22 10:19:19 +01:00
private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program . Version ;
2016-02-22 18:34:45 +01:00
private static readonly HttpClient HttpClient = new HttpClient ( new HttpClientHandler {
UseCookies = false
} ) {
Timeout = TimeSpan . FromSeconds ( HttpTimeout )
} ;
2015-11-25 16:31:39 +01:00
internal static void Init ( ) {
2016-01-16 05:02:50 +01:00
// Most web services expect that UserAgent is set, so we declare it globally
// Any request can override that on as-needed basis (see: RequestOptions.FakeUserAgent)
2016-01-22 10:19:19 +01:00
HttpClient . DefaultRequestHeaders . UserAgent . ParseAdd ( DefaultUserAgent ) ;
2015-12-01 01:34:05 +01:00
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
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-02-22 18:34:45 +01:00
// Reuse ports if possible
// TODO: Mono doesn't support that feature yet
//ServicePointManager.ReusePort = true;
2015-11-25 16:31:39 +01:00
}
2016-02-22 18:34:45 +01:00
internal static async Task < HttpResponseMessage > UrlGet ( string request , Dictionary < string , string > cookies = null , string referer = null ) {
2015-11-25 16:31:39 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
return null ;
}
2016-02-22 18:34:45 +01:00
return await UrlRequest ( request , HttpMethod . Get , null , cookies , referer ) . ConfigureAwait ( false ) ;
2015-11-25 16:31:39 +01:00
}
2016-02-22 18:34:45 +01:00
internal static async Task < HttpResponseMessage > UrlPost ( string request , Dictionary < string , string > data = null , Dictionary < string , string > cookies = null , string referer = null ) {
2015-11-25 16:31:39 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
return null ;
}
2016-02-22 18:34:45 +01:00
return await UrlRequest ( request , HttpMethod . Post , data , cookies , referer ) . ConfigureAwait ( false ) ;
2015-11-25 16:31:39 +01:00
}
2016-02-22 18:34:45 +01:00
internal static async Task < string > UrlGetToContent ( string request , Dictionary < string , string > cookies , string referer = null ) {
2015-11-25 16:31:39 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
return null ;
}
2016-02-22 18:34:45 +01:00
HttpResponseMessage httpResponse = await UrlGet ( request , cookies , referer ) . ConfigureAwait ( false ) ;
2016-01-14 02:48:56 +01:00
if ( httpResponse = = null ) {
2015-11-25 16:31:39 +01:00
return null ;
}
2016-01-14 02:48:56 +01:00
HttpContent httpContent = httpResponse . Content ;
if ( httpContent = = null ) {
return null ;
}
return await httpContent . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
2015-11-25 16:31:39 +01:00
}
2016-02-22 18:34:45 +01:00
internal static async Task < HtmlDocument > UrlGetToHtmlDocument ( string request , Dictionary < string , string > cookies = null , string referer = null ) {
2015-11-25 16:31:39 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
return null ;
}
2016-02-22 18:34:45 +01:00
string content = await UrlGetToContent ( request , cookies , referer ) . ConfigureAwait ( false ) ;
if ( string . IsNullOrEmpty ( content ) ) {
2016-01-14 02:48:56 +01:00
return null ;
}
2016-02-22 18:34:45 +01:00
content = WebUtility . HtmlDecode ( content ) ;
HtmlDocument htmlDocument = new HtmlDocument ( ) ;
htmlDocument . LoadHtml ( content ) ;
2015-11-25 16:31:39 +01:00
2016-02-22 18:34:45 +01:00
return htmlDocument ;
2015-11-25 16:31:39 +01:00
}
2016-02-22 18:34:45 +01:00
internal static async Task < JObject > UrlGetToJObject ( string request , Dictionary < string , string > cookies = null , string referer = null ) {
2015-11-25 16:31:39 +01:00
if ( string . IsNullOrEmpty ( request ) ) {
return null ;
}
2016-02-22 18:34:45 +01:00
string content = await UrlGetToContent ( request , cookies , referer ) . ConfigureAwait ( false ) ;
2016-01-14 02:48:56 +01:00
if ( string . IsNullOrEmpty ( content ) ) {
2015-11-25 16:31:39 +01:00
return null ;
}
2016-01-14 02:48:56 +01:00
JObject jObject ;
try {
jObject = JObject . Parse ( content ) ;
} catch ( Exception e ) {
Logging . 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-02-22 18:34:45 +01:00
private static async Task < HttpResponseMessage > UrlRequest ( string request , HttpMethod httpMethod , Dictionary < string , string > data = null , Dictionary < string , string > cookies = null , string referer = null ) {
if ( string . IsNullOrEmpty ( request ) | | httpMethod = = null ) {
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 ) ) {
if ( data ! = null ) {
try {
requestMessage . Content = new FormUrlEncodedContent ( data ) ;
} catch ( UriFormatException e ) {
Logging . LogGenericException ( e ) ;
return null ;
}
}
2015-11-25 16:31:39 +01:00
2016-02-22 18:34:45 +01:00
if ( cookies ! = null & & cookies . Count > 0 ) {
StringBuilder cookieHeader = new StringBuilder ( ) ;
foreach ( KeyValuePair < string , string > cookie in cookies ) {
cookieHeader . Append ( cookie . Key + "=" + cookie . Value + ";" ) ;
}
requestMessage . Headers . Add ( "Cookie" , cookieHeader . ToString ( ) ) ;
}
2015-11-25 16:31:39 +01:00
2016-02-22 18:34:45 +01:00
if ( referer ! = null ) {
requestMessage . Headers . Referrer = new Uri ( referer ) ;
}
2015-11-25 16:31:39 +01:00
2016-02-22 18:34:45 +01:00
try {
responseMessage = await HttpClient . SendAsync ( requestMessage ) . ConfigureAwait ( false ) ;
} catch { // Request failed, we don't need to know the exact reason, swallow exception
return null ;
}
2015-11-25 16:31:39 +01:00
}
2016-02-22 18:34:45 +01:00
if ( responseMessage = = null | | ! responseMessage . IsSuccessStatusCode ) {
2015-11-25 16:31:39 +01:00
return null ;
}
2016-02-22 18:34:45 +01:00
return responseMessage ;
2015-11-25 16:31:39 +01:00
}
}
}