HttpRequester
The default (ready-to-use) HTTP requester.
using AngleSharp.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace AngleSharp.Network.Default
{
public sealed class HttpRequester : IRequester
{
private sealed class RequestState
{
private readonly CookieContainer ;
private readonly HttpWebRequest _http;
private readonly IRequest _request;
private readonly byte[] _buffer;
public RequestState(IRequest request, IDictionary<string, string> headers)
{
string orDefault = request.Headers.GetOrDefault(HeaderNames.Cookie, string.Empty);
_cookies = new CookieContainer();
_request = request;
_http = (WebRequest.Create(request.Address) as HttpWebRequest);
_http.CookieContainer = _cookies;
_http.Method = request.Method.ToString().ToUpperInvariant();
_buffer = new byte[4096];
foreach (KeyValuePair<string, string> header in headers) {
AddHeader(header.Key, header.Value);
}
foreach (KeyValuePair<string, string> header2 in request.Headers) {
AddHeader(header2.Key, header2.Value);
}
_cookies.SetCookies(_http.RequestUri, orDefault);
}
public async Task<IResponse> RequestAsync(CancellationToken cancellationToken)
{
HttpWebRequest http = _http;
cancellationToken.Register(((WebRequest)http).Abort);
if (_request.Method == HttpMethod.Post || _request.Method == HttpMethod.Put) {
TaskFactory factory = Task.Factory;
HttpWebRequest http2 = _http;
Func<AsyncCallback, object, IAsyncResult> beginMethod = ((WebRequest)http2).BeginGetRequestStream;
HttpWebRequest http3 = _http;
SendRequest(await factory.FromAsync(beginMethod, (Func<IAsyncResult, Stream>)((WebRequest)http3).EndGetRequestStream, (object)null).ConfigureAwait(false));
}
WebResponse response;
try {
TaskFactory factory2 = Task.Factory;
HttpWebRequest http4 = _http;
Func<AsyncCallback, object, IAsyncResult> beginMethod2 = ((WebRequest)http4).BeginGetResponse;
HttpWebRequest http5 = _http;
response = await factory2.FromAsync(beginMethod2, (Func<IAsyncResult, WebResponse>)((WebRequest)http5).EndGetResponse, (object)null).ConfigureAwait(false);
} catch (WebException ex) {
response = ex.Response;
}
return GetResponse(response as HttpWebResponse);
}
private void SendRequest(Stream target)
{
Stream content = _request.Content;
while (content != null) {
int num = content.Read(_buffer, 0, 4096);
if (num == 0)
break;
target.Write(_buffer, 0, num);
}
}
private Response GetResponse(HttpWebResponse response)
{
if (response != null) {
Response response2 = new Response();
string cookieHeader = _cookies.GetCookieHeader(response.ResponseUri);
var enumerable = from m in response.Headers.AllKeys
select new {
Key = m,
Value = response.Headers.get_Item(m)
};
response2.Content = response.GetResponseStream();
response2.StatusCode = response.StatusCode;
response2.Address = Url.Convert(response.ResponseUri);
foreach (var item in enumerable) {
response2.Headers.Add(item.Key, item.Value);
}
if (cookieHeader != null)
response2.Headers[HeaderNames.SetCookie] = cookieHeader;
return response2;
}
return null;
}
private void AddHeader(string key, string value)
{
if (key == HeaderNames.Accept)
_http.Accept = value;
else if (key == HeaderNames.ContentType) {
_http.ContentType = value;
} else if (key == HeaderNames.Expect) {
SetProperty(HeaderNames.Expect, value);
} else if (key == HeaderNames.Date) {
SetProperty(HeaderNames.Date, DateTime.Parse(value));
} else if (key == HeaderNames.Host) {
SetProperty(HeaderNames.Host, value);
} else if (key == HeaderNames.IfModifiedSince) {
SetProperty("IfModifiedSince", DateTime.Parse(value));
} else if (key == HeaderNames.Referer) {
SetProperty(HeaderNames.Referer, value);
} else if (key == HeaderNames.UserAgent) {
SetProperty("UserAgent", value);
} else if (key != HeaderNames.Connection && key != HeaderNames.Range && key != HeaderNames.ContentLength && key != HeaderNames.TransferEncoding) {
_http.Headers.set_Item(key, value);
}
}
private void SetProperty(string name, object value)
{
if (!_propCache.ContainsKey(name))
_propCache.Add(name, _http.GetType().GetTypeInfo().GetDeclaredProperty(name));
PropertyInfo propertyInfo = _propCache[name];
if (!_restricted.Contains(name) && (object)propertyInfo != null && propertyInfo.CanWrite)
try {
propertyInfo.SetValue(_http, value, null);
} catch {
_restricted.Add(name);
}
}
}
private const int BufferSize = 4096;
private static readonly string _version;
private static readonly string _agentName;
private static readonly Dictionary<string, PropertyInfo> _propCache;
private static readonly List<string> _restricted;
private TimeSpan _timeOut;
private readonly Dictionary<string, string> _headers;
public Dictionary<string, string> Headers => _headers;
public TimeSpan Timeout {
get {
return _timeOut;
}
set {
_timeOut = value;
}
}
static HttpRequester()
{
_version = typeof(HttpRequester).GetTypeInfo().get_Assembly().GetCustomAttribute<AssemblyFileVersionAttribute>()
.Version;
_agentName = "AngleSharp/" + _version;
_propCache = new Dictionary<string, PropertyInfo>();
_restricted = new List<string>();
}
public HttpRequester(string userAgent = null)
{
_timeOut = new TimeSpan(0, 0, 0, 45);
_headers = new Dictionary<string, string>();
_headers.Add("User-Agent", userAgent ?? _agentName);
}
public bool SupportsProtocol(string protocol)
{
return protocol.IsOneOf(KnownProtocols.Http, KnownProtocols.Https);
}
public Task<IResponse> RequestAsync(IRequest request, CancellationToken cancellationToken)
{
RequestState requestState = new RequestState(request, _headers);
return requestState.RequestAsync(cancellationToken);
}
}
}