Files
ArchiSteamFarm/ArchiSteamFarm/WebBrowser.cs

583 lines
20 KiB
C#
Raw Normal View History

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;
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
internal readonly CookieContainer CookieContainer = new CookieContainer();
2016-03-06 23:28:56 +01:00
internal TimeSpan Timeout => HttpClient.Timeout;
private readonly ArchiLogger ArchiLogger;
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));
HttpClientHandler httpClientHandler = new HttpClientHandler {
AllowAutoRedirect = false, // This must be false if we want to handle custom redirection schemes such as "steammobile"
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip,
CookieContainer = CookieContainer,
2017-12-12 14:12:21 +01:00
MaxConnectionsPerServer = MaxConnections,
UseProxy = false
};
2017-11-28 21:31:45 +01:00
HttpClient = new HttpClient(httpClientHandler) { Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeoutMultiplier * Program.GlobalConfig.ConnectionTimeout : Program.GlobalConfig.ConnectionTimeout) };
// 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);
}
2017-08-04 19:26:37 +02:00
public void Dispose() => HttpClient.Dispose();
internal static void Init() {
// 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
// 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 (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;
}
internal async Task<BinaryResponse> UrlGetToBinaryWithProgressRetry(string request, string referer = null) {
2016-05-30 01:57:06 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2016-05-30 01:57:06 +02:00
return null;
}
BinaryResponse response = null;
for (byte i = 0; (i < MaxTries) && (response == null); i++) {
response = await UrlGetToBinaryWithProgress(request, referer).ConfigureAwait(false);
2016-05-30 01:57:06 +02:00
}
2018-03-09 15:43:25 +01:00
if (response == null) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, MaxTries));
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
return null;
2016-05-30 01:57:06 +02:00
}
2018-03-09 15:43:25 +01:00
return response;
2016-05-30 01:57:06 +02:00
}
internal async Task<HtmlDocumentResponse> UrlGetToHtmlDocumentRetry(string request, string referer = null) {
2016-05-30 01:57:06 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2016-05-30 01:57:06 +02:00
return null;
}
StringResponse response = await UrlGetToStringRetry(request, referer).ConfigureAwait(false);
return response != null ? new HtmlDocumentResponse(response) : null;
2016-05-30 01:57:06 +02:00
}
2018-03-09 14:26:20 +01:00
internal async Task<ObjectResponse<T>> UrlGetToJsonObjectRetry<T>(string request, string referer = null) {
2016-05-30 01:57:06 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
2016-05-30 01:57:06 +02:00
}
StringResponse response = await UrlGetToStringRetry(request, referer).ConfigureAwait(false);
2018-03-09 18:02:39 +01:00
if (string.IsNullOrEmpty(response?.Content)) {
return null;
2016-05-30 01:57:06 +02:00
}
T obj;
2016-08-22 00:10:29 +02:00
try {
obj = JsonConvert.DeserializeObject<T>(response.Content);
2016-08-22 00:10:29 +02:00
} catch (JsonException e) {
ArchiLogger.LogGenericException(e);
if (Debugging.IsUserDebugging) {
ArchiLogger.LogGenericDebug(string.Format(Strings.Content, response.Content));
}
return null;
}
return new ObjectResponse<T>(response, obj);
}
internal async Task<XmlResponse> UrlGetToXmlRetry(string request, string referer = null) {
2015-11-25 16:31:39 +01:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2016-05-30 01:57:06 +02:00
return null;
}
StringResponse response = await UrlGetToStringRetry(request, referer).ConfigureAwait(false);
2016-05-30 01:57:06 +02:00
2018-03-09 18:02:39 +01:00
if (string.IsNullOrEmpty(response?.Content)) {
return null;
}
XmlDocument xmlDocument = new XmlDocument();
try {
xmlDocument.LoadXml(response.Content);
} catch (XmlException e) {
ArchiLogger.LogGenericException(e);
return null;
}
return new XmlResponse(response, xmlDocument);
}
internal async Task<BasicResponse> UrlHeadRetry(string request, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
BasicResponse response = null;
for (byte i = 0; (i < MaxTries) && (response == null); i++) {
response = await UrlHead(request, referer).ConfigureAwait(false);
}
2018-03-09 15:43:25 +01:00
if (response == null) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, MaxTries));
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
return null;
}
2018-03-09 15:43:25 +01:00
return response;
}
internal async Task<BasicResponse> UrlPost(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
using (HttpResponseMessage response = await UrlPostToHttp(request, data, referer).ConfigureAwait(false)) {
return response != null ? new BasicResponse(response) : null;
}
}
internal async Task<BasicResponse> UrlPostRetry(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
2016-05-30 01:57:06 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
2016-05-30 01:57:06 +02:00
}
BasicResponse response = null;
for (byte i = 0; (i < MaxTries) && (response == null); i++) {
response = await UrlPost(request, data, referer).ConfigureAwait(false);
2016-05-30 01:57:06 +02:00
}
2018-03-09 15:43:25 +01:00
if (response == null) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, MaxTries));
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
return null;
2016-05-30 01:57:06 +02:00
}
2018-03-09 15:43:25 +01:00
return response;
2016-05-30 01:57:06 +02:00
}
internal async Task<HtmlDocumentResponse> UrlPostToHtmlDocumentRetry(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
StringResponse response = await UrlPostToStringRetry(request, data, referer).ConfigureAwait(false);
return response != null ? new HtmlDocumentResponse(response) : null;
}
2018-03-09 14:26:20 +01:00
internal async Task<ObjectResponse<T>> UrlPostToJsonObjectRetry<T>(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
StringResponse response = await UrlPostToStringRetry(request, data, referer).ConfigureAwait(false);
2018-03-09 18:02:39 +01:00
if (string.IsNullOrEmpty(response?.Content)) {
return null;
}
T obj;
2016-08-22 00:10:29 +02:00
try {
obj = JsonConvert.DeserializeObject<T>(response.Content);
2016-08-22 00:10:29 +02:00
} catch (JsonException e) {
ArchiLogger.LogGenericException(e);
if (Debugging.IsUserDebugging) {
ArchiLogger.LogGenericDebug(string.Format(Strings.Content, response.Content));
}
return null;
}
return new ObjectResponse<T>(response, obj);
}
private async Task<BinaryResponse> UrlGetToBinaryWithProgress(string request, string referer = null) {
2016-05-30 01:57:06 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2015-11-25 16:31:39 +01:00
return null;
}
2017-12-16 11:34:04 +01:00
const byte printPercentage = 10;
2017-12-19 12:40:54 +01:00
const byte maxBatches = 99 / printPercentage;
2017-12-16 11:34:04 +01:00
using (HttpResponseMessage response = await UrlGetToHttp(request, referer, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false)) {
if (response == null) {
2016-04-14 22:23:37 +02:00
return null;
}
2015-11-25 16:31:39 +01:00
2017-12-16 11:40:38 +01:00
ArchiLogger.LogGenericDebug("0%...");
2017-12-16 11:34:04 +01:00
uint contentLength = (uint) response.Content.Headers.ContentLength.GetValueOrDefault();
2017-12-19 12:40:54 +01:00
using (MemoryStream ms = new MemoryStream((int) contentLength)) {
2017-12-16 11:40:38 +01:00
try {
using (Stream contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) {
2017-12-16 11:40:38 +01:00
byte batch = 0;
uint readThisBatch = 0;
byte[] buffer = new byte[8192]; // This is HttpClient's buffer, using more doesn't make sense
2017-12-16 11:34:04 +01:00
2017-12-16 11:40:38 +01:00
while (contentStream.CanRead) {
int read = await contentStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
if (read == 0) {
break;
}
2017-12-16 11:34:04 +01:00
2017-12-16 11:40:38 +01:00
await ms.WriteAsync(buffer, 0, read).ConfigureAwait(false);
2017-12-16 11:34:04 +01:00
2017-12-19 12:40:54 +01:00
if ((contentLength == 0) || (batch >= maxBatches)) {
2017-12-16 11:40:38 +01:00
continue;
}
2017-12-16 11:34:04 +01:00
2017-12-16 11:40:38 +01:00
readThisBatch += (uint) read;
2017-12-16 11:34:04 +01:00
2017-12-16 11:40:38 +01:00
if (readThisBatch < contentLength / printPercentage) {
continue;
}
2017-12-19 12:40:54 +01:00
readThisBatch -= contentLength / printPercentage;
2017-12-16 11:40:38 +01:00
ArchiLogger.LogGenericDebug(++batch * printPercentage + "%...");
}
2017-12-16 11:34:04 +01:00
}
2017-12-16 11:40:38 +01:00
} catch (Exception e) {
ArchiLogger.LogGenericDebuggingException(e);
return null;
2017-12-16 11:34:04 +01:00
}
2017-12-16 11:40:38 +01:00
ArchiLogger.LogGenericDebug("100%");
return new BinaryResponse(response, ms.ToArray());
2017-12-16 11:34:04 +01:00
}
2015-11-25 16:31:39 +01:00
}
}
private async Task<HttpResponseMessage> UrlGetToHttp(string request, string referer = null, HttpCompletionOption httpCompletionOptions = HttpCompletionOption.ResponseContentRead) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2015-11-25 16:31:39 +01:00
return null;
}
2018-03-09 15:43:25 +01:00
return await UrlRequest(new Uri(request), HttpMethod.Get, null, referer, httpCompletionOptions).ConfigureAwait(false);
2015-11-25 16:31:39 +01:00
}
private async Task<StringResponse> UrlGetToString(string request, string referer = null) {
2016-08-22 00:10:29 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2016-08-22 00:10:29 +02:00
return null;
}
using (HttpResponseMessage response = await UrlGetToHttp(request, referer).ConfigureAwait(false)) {
return response != null ? new StringResponse(response, await response.Content.ReadAsStringAsync().ConfigureAwait(false)) : null;
2016-08-22 00:10:29 +02:00
}
}
private async Task<StringResponse> UrlGetToStringRetry(string request, string referer = null) {
2015-11-25 16:31:39 +01:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2015-11-25 16:31:39 +01:00
return null;
}
StringResponse response = null;
2015-11-25 16:31:39 +01:00
for (byte i = 0; (i < MaxTries) && (response == null); i++) {
response = await UrlGetToString(request, referer).ConfigureAwait(false);
2016-05-30 01:57:06 +02:00
}
2018-03-09 15:43:25 +01:00
if (response == null) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, MaxTries));
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
return null;
}
2018-03-09 15:43:25 +01:00
return response;
2016-05-30 01:57:06 +02:00
}
private async Task<BasicResponse> UrlHead(string request, string referer = null) {
2016-03-15 04:20:28 +01:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2016-03-15 04:20:28 +01:00
return null;
}
using (HttpResponseMessage response = await UrlHeadToHttp(request, referer).ConfigureAwait(false)) {
return response != null ? new BasicResponse(response) : null;
2016-03-15 04:20:28 +01:00
}
}
private async Task<HttpResponseMessage> UrlHeadToHttp(string request, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
2016-05-30 01:57:06 +02:00
}
2018-03-09 15:43:25 +01:00
return await UrlRequest(new Uri(request), HttpMethod.Head, null, referer).ConfigureAwait(false);
2016-05-30 01:57:06 +02:00
}
private async Task<HttpResponseMessage> UrlPostToHttp(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
2016-04-14 22:23:37 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2016-04-14 22:23:37 +02:00
return null;
}
2018-03-09 15:43:25 +01:00
return await UrlRequest(new Uri(request), HttpMethod.Post, data, referer).ConfigureAwait(false);
2016-04-14 22:23:37 +02:00
}
private async Task<StringResponse> UrlPostToString(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
using (HttpResponseMessage response = await UrlPostToHttp(request, data, referer).ConfigureAwait(false)) {
return response != null ? new StringResponse(response, await response.Content.ReadAsStringAsync().ConfigureAwait(false)) : null;
}
}
private async Task<StringResponse> UrlPostToStringRetry(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
2016-08-22 00:10:29 +02:00
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
2016-08-22 00:10:29 +02:00
return null;
}
StringResponse response = null;
for (byte i = 0; (i < MaxTries) && (response == null); i++) {
response = await UrlPostToString(request, data, referer).ConfigureAwait(false);
2016-08-22 00:10:29 +02:00
}
2018-03-09 15:43:25 +01:00
if (response == null) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, MaxTries));
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request));
return null;
2016-08-22 00:10:29 +02:00
}
2018-03-09 15:43:25 +01:00
return response;
2016-08-22 00:10:29 +02:00
}
2017-12-16 11:34:04 +01:00
private async Task<HttpResponseMessage> UrlRequest(Uri requestUri, HttpMethod httpMethod, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, byte maxRedirections = MaxTries) {
if ((requestUri == null) || (httpMethod == null)) {
ArchiLogger.LogNullError(nameof(requestUri) + " || " + nameof(httpMethod));
2015-11-25 16:31:39 +01:00
return null;
}
HttpResponseMessage response;
using (HttpRequestMessage request = new HttpRequestMessage(httpMethod, requestUri)) {
if (data != null) {
2016-02-22 18:34:45 +01:00
try {
request.Content = new FormUrlEncodedContent(data);
2016-02-22 18:34:45 +01:00
} catch (UriFormatException e) {
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)) {
request.Headers.Referrer = new Uri(referer);
2016-02-22 18:34:45 +01:00
}
2015-11-25 16:31:39 +01:00
2016-02-22 18:34:45 +01:00
try {
response = await HttpClient.SendAsync(request, httpCompletionOption).ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericDebuggingException(e);
2016-02-22 18:34:45 +01:00
return null;
}
2015-11-25 16:31:39 +01:00
}
if (response == null) {
2016-04-22 17:50:01 +02:00
return null;
}
if (response.IsSuccessStatusCode) {
return response;
2016-05-13 06:32:42 +02: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)) {
Uri redirectUri = response.Headers.Location;
if (redirectUri.IsAbsoluteUri) {
switch (redirectUri.Scheme) {
case "http":
case "https":
break;
case "steammobile":
// Those redirections are invalid, but we're aware of that and we have extra logic for them
return response;
default:
// We have no clue about those, but maybe HttpClient can handle them for us
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(redirectUri.Scheme), redirectUri.Scheme));
break;
}
} else {
redirectUri = new Uri(requestUri.GetLeftPart(UriPartial.Authority) + redirectUri);
}
response.Dispose();
return await UrlRequest(redirectUri, httpMethod, data, referer, httpCompletionOption, --maxRedirections).ConfigureAwait(false);
}
using (response) {
2018-03-09 15:43:25 +01:00
if (Debugging.IsDebugBuild) {
ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, requestUri));
ArchiLogger.LogGenericDebug(string.Format(Strings.StatusCode, response.StatusCode));
ArchiLogger.LogGenericDebug(string.Format(Strings.Content, await response.Content.ReadAsStringAsync().ConfigureAwait(false)));
}
2015-11-25 16:31:39 +01:00
return null;
}
2015-11-25 16:31:39 +01:00
}
internal class BasicResponse {
internal readonly Uri FinalUri;
internal BasicResponse(HttpResponseMessage httpResponseMessage) {
if (httpResponseMessage == null) {
throw new ArgumentNullException(nameof(httpResponseMessage));
}
FinalUri = httpResponseMessage.Headers.Location ?? httpResponseMessage.RequestMessage.RequestUri;
}
internal BasicResponse(BasicResponse basicResponse) {
if (basicResponse == null) {
throw new ArgumentNullException(nameof(basicResponse));
}
FinalUri = basicResponse.FinalUri;
}
}
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;
}
}
internal sealed class XmlResponse : BasicResponse {
internal readonly XmlDocument Content;
internal XmlResponse(StringResponse stringResponse, XmlDocument content) : base(stringResponse) {
if (stringResponse == null) {
throw new ArgumentNullException(nameof(stringResponse));
}
Content = content;
}
}
2015-11-25 16:31:39 +01:00
}
}