Refactored the HttpDispatchers.

This commit is contained in:
Taloth Saldono 2015-10-10 22:20:17 +02:00
parent e13c89521d
commit fe76d0f98f
7 changed files with 290 additions and 294 deletions

View File

@ -11,36 +11,22 @@ using NzbDrone.Test.Common.Categories;
using NLog; using NLog;
using NzbDrone.Common.TPL; using NzbDrone.Common.TPL;
using Moq; using Moq;
using NzbDrone.Common.Http.Dispatchers;
namespace NzbDrone.Common.Test.Http namespace NzbDrone.Common.Test.Http
{ {
[TestFixture(true)]
[TestFixture(false)]
[IntegrationTest] [IntegrationTest]
public class HttpClientFixture : TestBase<HttpClient> [TestFixture(typeof(ManagedHttpDispatcher))]
{ [TestFixture(typeof(CurlHttpDispatcher))]
private bool _forceCurl; public class HttpClientFixture<TDispatcher> : TestBase<HttpClient> where TDispatcher : IHttpDispatcher
{
public HttpClientFixture(bool forceCurl)
{
_forceCurl = forceCurl;
}
[SetUp] [SetUp]
public void SetUp() public void SetUp()
{ {
Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>()); Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>());
Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>()); Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>());
Mocker.SetConstant<IEnumerable<IHttpRequestInterceptor>>(new IHttpRequestInterceptor[0]); Mocker.SetConstant<IEnumerable<IHttpRequestInterceptor>>(new IHttpRequestInterceptor[0]);
Mocker.SetConstant<IHttpDispatcher>(Mocker.Resolve<TDispatcher>());
if (_forceCurl)
{
Mocker.SetConstant<IHttpDispatcher>(Mocker.Resolve<CurlHttpDispatcher>());
}
else
{
Mocker.SetConstant<IHttpDispatcher>(Mocker.Resolve<ManagedHttpDispatcher>());
}
} }
[Test] [Test]

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
@ -13,20 +12,13 @@ using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Common.Http namespace NzbDrone.Common.Http.Dispatchers
{ {
public class CurlHttpClient public class CurlHttpDispatcher : IHttpDispatcher
{ {
private static Logger Logger = NzbDroneLogger.GetLogger(typeof(CurlHttpClient));
private static readonly Regex ExpiryDate = new Regex(@"(expires=)([^;]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex ExpiryDate = new Regex(@"(expires=)([^;]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public CurlHttpClient() private static readonly Logger _logger = NzbDroneLogger.GetLogger(typeof(CurlHttpDispatcher));
{
if (!CheckAvailability())
{
throw new ApplicationException("Curl failed to initialize.");
}
}
public static bool CheckAvailability() public static bool CheckAvailability()
{ {
@ -36,13 +28,23 @@ namespace NzbDrone.Common.Http
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.TraceException("Initializing curl failed", ex); _logger.TraceException("Initializing curl failed", ex);
return false; return false;
} }
} }
public HttpResponse GetResponse(HttpRequest httpRequest, HttpWebRequest webRequest) public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
{ {
if (!CheckAvailability())
{
throw new ApplicationException("Curl failed to initialize.");
}
if (request.NetworkCredential != null)
{
throw new NotImplementedException("Credentials not supported for curl dispatcher.");
}
lock (CurlGlobalHandle.Instance) lock (CurlGlobalHandle.Instance)
{ {
Stream responseStream = new MemoryStream(); Stream responseStream = new MemoryStream();
@ -61,33 +63,47 @@ namespace NzbDrone.Common.Http
headerStream.Write(b, 0, s * n); headerStream.Write(b, 0, s * n);
return s * n; return s * n;
}; };
curlEasy.Url = request.Url.AbsoluteUri;
switch (request.Method)
{
case HttpMethod.GET:
curlEasy.HttpGet = true;
break;
curlEasy.UserAgent = webRequest.UserAgent; case HttpMethod.POST:
curlEasy.FollowLocation = webRequest.AllowAutoRedirect; curlEasy.Post = true;
curlEasy.HttpGet = webRequest.Method == "GET"; break;
curlEasy.Post = webRequest.Method == "POST";
curlEasy.Put = webRequest.Method == "PUT"; case HttpMethod.PUT:
curlEasy.Url = webRequest.RequestUri.AbsoluteUri; curlEasy.Put = true;
break;
default:
throw new NotSupportedException(string.Format("HttpCurl method {0} not supported", request.Method));
}
curlEasy.UserAgent = UserAgentBuilder.UserAgent;
curlEasy.FollowLocation = request.AllowAutoRedirect;
if (OsInfo.IsWindows) if (OsInfo.IsWindows)
{ {
curlEasy.CaInfo = "curl-ca-bundle.crt"; curlEasy.CaInfo = "curl-ca-bundle.crt";
} }
if (webRequest.CookieContainer != null) if (cookies != null)
{ {
curlEasy.Cookie = webRequest.CookieContainer.GetCookieHeader(webRequest.RequestUri); curlEasy.Cookie = cookies.GetCookieHeader(request.Url);
} }
if (!httpRequest.Body.IsNullOrWhiteSpace()) if (!request.Body.IsNullOrWhiteSpace())
{ {
// TODO: This might not go well with encoding. // TODO: This might not go well with encoding.
curlEasy.PostFieldSize = httpRequest.Body.Length; curlEasy.PostFieldSize = request.Body.Length;
curlEasy.SetOpt(CurlOption.CopyPostFields, httpRequest.Body); curlEasy.SetOpt(CurlOption.CopyPostFields, request.Body);
} }
// Yes, we have to keep a ref to the object to prevent corrupting the unmanaged state // Yes, we have to keep a ref to the object to prevent corrupting the unmanaged state
using (var httpRequestHeaders = SerializeHeaders(webRequest)) using (var httpRequestHeaders = SerializeHeaders(request))
{ {
curlEasy.HttpHeader = httpRequestHeaders; curlEasy.HttpHeader = httpRequestHeaders;
@ -99,60 +115,38 @@ namespace NzbDrone.Common.Http
} }
} }
var webHeaderCollection = ProcessHeaderStream(webRequest, headerStream); var webHeaderCollection = ProcessHeaderStream(request, cookies, headerStream);
var responseData = ProcessResponseStream(webRequest, responseStream, webHeaderCollection); var responseData = ProcessResponseStream(request, responseStream, webHeaderCollection);
var httpHeader = new HttpHeader(webHeaderCollection); var httpHeader = new HttpHeader(webHeaderCollection);
return new HttpResponse(httpRequest, httpHeader, responseData, (HttpStatusCode)curlEasy.ResponseCode); return new HttpResponse(request, httpHeader, responseData, (HttpStatusCode)curlEasy.ResponseCode);
} }
} }
} }
private CurlSlist SerializeHeaders(HttpWebRequest webRequest) private CurlSlist SerializeHeaders(HttpRequest request)
{ {
if (webRequest.SendChunked) if (!request.Headers.ContainsKey("Accept-Encoding"))
{ {
throw new NotSupportedException("Chunked transfer is not supported"); request.Headers.Add("Accept-Encoding", "gzip");
} }
if (webRequest.ContentLength > 0) if (request.Headers.ContentType == null)
{ {
webRequest.Headers.Add("Content-Length", webRequest.ContentLength.ToString()); request.Headers.ContentType = string.Empty;
} }
if (webRequest.AutomaticDecompression.HasFlag(DecompressionMethods.GZip))
{
if (webRequest.AutomaticDecompression.HasFlag(DecompressionMethods.Deflate))
{
webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
}
else
{
webRequest.Headers.Add("Accept-Encoding", "gzip");
}
}
else
{
if (webRequest.AutomaticDecompression.HasFlag(DecompressionMethods.Deflate))
{
webRequest.Headers.Add("Accept-Encoding", "deflate");
}
}
var curlHeaders = new CurlSlist(); var curlHeaders = new CurlSlist();
for (int i = 0; i < webRequest.Headers.Count; i++) foreach (var header in request.Headers)
{ {
curlHeaders.Append(webRequest.Headers.GetKey(i) + ": " + webRequest.Headers.Get(i)); curlHeaders.Append(header.Key + ": " + header.Value.ToString());
} }
curlHeaders.Append("Content-Type: " + webRequest.ContentType ?? string.Empty);
return curlHeaders; return curlHeaders;
} }
private WebHeaderCollection ProcessHeaderStream(HttpWebRequest webRequest, Stream headerStream) private WebHeaderCollection ProcessHeaderStream(HttpRequest request, CookieContainer cookies, Stream headerStream)
{ {
headerStream.Position = 0; headerStream.Position = 0;
var headerData = headerStream.ToBytes(); var headerData = headerStream.ToBytes();
@ -168,9 +162,9 @@ namespace NzbDrone.Common.Http
} }
var setCookie = webHeaderCollection.Get("Set-Cookie"); var setCookie = webHeaderCollection.Get("Set-Cookie");
if (setCookie != null && setCookie.Length > 0 && webRequest.CookieContainer != null) if (setCookie != null && setCookie.Length > 0 && cookies != null)
{ {
webRequest.CookieContainer.SetCookies(webRequest.RequestUri, FixSetCookieHeader(setCookie)); cookies.SetCookies(request.Url, FixSetCookieHeader(setCookie));
} }
return webHeaderCollection; return webHeaderCollection;
@ -180,30 +174,30 @@ namespace NzbDrone.Common.Http
{ {
// fix up the date if it was malformed // fix up the date if it was malformed
var setCookieClean = ExpiryDate.Replace(setCookie, delegate(Match match) var setCookieClean = ExpiryDate.Replace(setCookie, delegate(Match match)
{ {
string format = "ddd, dd-MMM-yyyy HH:mm:ss"; string format = "ddd, dd-MMM-yyyy HH:mm:ss";
DateTime dt = Convert.ToDateTime(match.Groups[2].Value); DateTime dt = Convert.ToDateTime(match.Groups[2].Value);
return match.Groups[1].Value + dt.ToUniversalTime().ToString(format) + " GMT"; return match.Groups[1].Value + dt.ToUniversalTime().ToString(format) + " GMT";
}); });
return setCookieClean; return setCookieClean;
} }
private byte[] ProcessResponseStream(HttpWebRequest webRequest, Stream responseStream, WebHeaderCollection webHeaderCollection) private byte[] ProcessResponseStream(HttpRequest request, Stream responseStream, WebHeaderCollection webHeaderCollection)
{ {
responseStream.Position = 0; responseStream.Position = 0;
if (responseStream.Length != 0 && webRequest.AutomaticDecompression != DecompressionMethods.None) if (responseStream.Length != 0)
{ {
var encoding = webHeaderCollection["Content-Encoding"]; var encoding = webHeaderCollection["Content-Encoding"];
if (encoding != null) if (encoding != null)
{ {
if (webRequest.AutomaticDecompression.HasFlag(DecompressionMethods.GZip) && encoding.IndexOf("gzip") != -1) if (encoding.IndexOf("gzip") != -1)
{ {
responseStream = new GZipStream(responseStream, CompressionMode.Decompress); responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
webHeaderCollection.Remove("Content-Encoding"); webHeaderCollection.Remove("Content-Encoding");
} }
else if (webRequest.AutomaticDecompression.HasFlag(DecompressionMethods.Deflate) && encoding.IndexOf("deflate") != -1) else if (encoding.IndexOf("deflate") != -1)
{ {
responseStream = new DeflateStream(responseStream, CompressionMode.Decompress); responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);

View File

@ -0,0 +1,60 @@
using System;
using System.Net;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Http.Dispatchers
{
public class FallbackHttpDispatcher : IHttpDispatcher
{
private readonly Logger _logger;
private readonly ICached<bool> _curlTLSFallbackCache;
private readonly ManagedHttpDispatcher _managedDispatcher;
private readonly CurlHttpDispatcher _curlDispatcher;
public FallbackHttpDispatcher(ICached<bool> curlTLSFallbackCache, Logger logger)
{
_logger = logger;
_curlTLSFallbackCache = curlTLSFallbackCache;
_managedDispatcher = new ManagedHttpDispatcher();
_curlDispatcher = new CurlHttpDispatcher();
}
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
{
if (OsInfo.IsMonoRuntime && request.Url.Scheme == "https")
{
if (!_curlTLSFallbackCache.Find(request.Url.Host))
{
try
{
return _managedDispatcher.GetResponse(request, cookies);
}
catch (Exception ex)
{
if (ex.ToString().Contains("The authentication or decryption has failed."))
{
_logger.Debug("https request failed in tls error for {0}, trying curl fallback.", request.Url.Host);
_curlTLSFallbackCache.Set(request.Url.Host, true);
}
else
{
throw;
}
}
}
if (CurlHttpDispatcher.CheckAvailability())
{
return _curlDispatcher.GetResponse(request, cookies);
}
_logger.Trace("Curl not available, using default WebClient.");
}
return _managedDispatcher.GetResponse(request, cookies);
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.TPL;
namespace NzbDrone.Common.Http.Dispatchers
{
public interface IHttpDispatcher
{
HttpResponse GetResponse(HttpRequest request, CookieContainer cookies);
}
}

View File

@ -0,0 +1,122 @@
using System;
using System.Net;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Common.Http.Dispatchers
{
public class ManagedHttpDispatcher : IHttpDispatcher
{
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
{
var webRequest = (HttpWebRequest)WebRequest.Create(request.Url);
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
webRequest.Credentials = request.NetworkCredential;
webRequest.Method = request.Method.ToString();
webRequest.UserAgent = UserAgentBuilder.UserAgent;
webRequest.KeepAlive = false;
webRequest.AllowAutoRedirect = request.AllowAutoRedirect;
webRequest.ContentLength = 0;
webRequest.CookieContainer = cookies;
if (request.Headers != null)
{
AddRequestHeaders(webRequest, request.Headers);
}
if (!request.Body.IsNullOrWhiteSpace())
{
var bytes = request.Headers.GetEncodingFromContentType().GetBytes(request.Body.ToCharArray());
webRequest.ContentLength = bytes.Length;
using (var writeStream = webRequest.GetRequestStream())
{
writeStream.Write(bytes, 0, bytes.Length);
}
}
HttpWebResponse httpWebResponse;
try
{
httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
httpWebResponse = (HttpWebResponse)e.Response;
if (httpWebResponse == null)
{
throw;
}
}
byte[] data = null;
using (var responseStream = httpWebResponse.GetResponseStream())
{
if (responseStream != null)
{
data = responseStream.ToBytes();
}
}
return new HttpResponse(request, new HttpHeader(httpWebResponse.Headers), data, httpWebResponse.StatusCode);
}
protected virtual void AddRequestHeaders(HttpWebRequest webRequest, HttpHeader headers)
{
foreach (var header in headers)
{
switch (header.Key)
{
case "Accept":
webRequest.Accept = header.Value.ToString();
break;
case "Connection":
webRequest.Connection = header.Value.ToString();
break;
case "Content-Length":
webRequest.ContentLength = Convert.ToInt64(header.Value);
break;
case "Content-Type":
webRequest.ContentType = header.Value.ToString();
break;
case "Date":
webRequest.Date = (DateTime)header.Value;
break;
case "Expect":
webRequest.Expect = header.Value.ToString();
break;
case "Host":
webRequest.Host = header.Value.ToString();
break;
case "If-Modified-Since":
webRequest.IfModifiedSince = (DateTime)header.Value;
break;
case "Range":
throw new NotImplementedException();
break;
case "Referer":
webRequest.Referer = header.Value.ToString();
break;
case "Transfer-Encoding":
webRequest.TransferEncoding = header.Value.ToString();
break;
case "User-Agent":
throw new NotSupportedException("User-Agent other than Sonarr not allowed.");
case "Proxy-Connection":
throw new NotImplementedException();
break;
default:
webRequest.Headers.Add(header.Key, header.Value.ToString());
break;
}
}
}
}
}

View File

@ -8,6 +8,7 @@ using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http.Dispatchers;
using NzbDrone.Common.TPL; using NzbDrone.Common.TPL;
namespace NzbDrone.Common.Http namespace NzbDrone.Common.Http
@ -23,119 +24,6 @@ namespace NzbDrone.Common.Http
HttpResponse<T> Post<T>(HttpRequest request) where T : new(); HttpResponse<T> Post<T>(HttpRequest request) where T : new();
} }
public interface IHttpDispatcher
{
HttpResponse GetResponse(HttpRequest request, HttpWebRequest webRequest);
}
public class ManagedHttpDispatcher : IHttpDispatcher
{
public HttpResponse GetResponse(HttpRequest request, HttpWebRequest webRequest)
{
if (!request.Body.IsNullOrWhiteSpace())
{
var bytes = request.Headers.GetEncodingFromContentType().GetBytes(request.Body.ToCharArray());
webRequest.ContentLength = bytes.Length;
using (var writeStream = webRequest.GetRequestStream())
{
writeStream.Write(bytes, 0, bytes.Length);
}
}
HttpWebResponse httpWebResponse;
try
{
httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
httpWebResponse = (HttpWebResponse)e.Response;
if (httpWebResponse == null)
{
throw;
}
}
Byte[] data = null;
using (var responseStream = httpWebResponse.GetResponseStream())
{
if (responseStream != null)
{
data = responseStream.ToBytes();
}
}
return new HttpResponse(request, new HttpHeader(httpWebResponse.Headers), data, httpWebResponse.StatusCode);
}
}
public class CurlHttpDispatcher : IHttpDispatcher
{
public HttpResponse GetResponse(HttpRequest request, HttpWebRequest webRequest)
{
var curlClient = new CurlHttpClient();
return curlClient.GetResponse(request, webRequest);
}
}
public class FallbackHttpDispatcher : IHttpDispatcher
{
private readonly Logger _logger;
private readonly ICached<bool> _curlTLSFallbackCache;
public FallbackHttpDispatcher(ICached<bool> curlTLSFallbackCache, Logger logger)
{
_logger = logger;
_curlTLSFallbackCache = curlTLSFallbackCache;
}
public HttpResponse GetResponse(HttpRequest request, HttpWebRequest webRequest)
{
ManagedHttpDispatcher managedDispatcher = new ManagedHttpDispatcher();
CurlHttpDispatcher curlDispatcher = new CurlHttpDispatcher();
if (OsInfo.IsMonoRuntime && webRequest.RequestUri.Scheme == "https")
{
if (!_curlTLSFallbackCache.Find(webRequest.RequestUri.Host))
{
try
{
return managedDispatcher.GetResponse(request, webRequest);
}
catch (Exception ex)
{
if (ex.ToString().Contains("The authentication or decryption has failed."))
{
_logger.Debug("https request failed in tls error for {0}, trying curl fallback.", webRequest.RequestUri.Host);
_curlTLSFallbackCache.Set(webRequest.RequestUri.Host, true);
}
else
{
throw;
}
}
}
if (CurlHttpClient.CheckAvailability())
{
return curlDispatcher.GetResponse(request, webRequest);
}
_logger.Trace("Curl not available, using default WebClient.");
}
return managedDispatcher.GetResponse(request, webRequest);
}
}
public class HttpClient : IHttpClient public class HttpClient : IHttpClient
{ {
private readonly Logger _logger; private readonly Logger _logger;
@ -176,37 +64,23 @@ namespace NzbDrone.Common.Http
_logger.Trace(request); _logger.Trace(request);
var webRequest = (HttpWebRequest)WebRequest.Create(request.Url);
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
webRequest.Credentials = request.NetworkCredential;
webRequest.Method = request.Method.ToString();
webRequest.UserAgent = UserAgentBuilder.UserAgent;
webRequest.KeepAlive = false;
webRequest.AllowAutoRedirect = request.AllowAutoRedirect;
webRequest.ContentLength = 0;
var stopWatch = Stopwatch.StartNew(); var stopWatch = Stopwatch.StartNew();
if (request.Headers != null) var cookies = PrepareRequestCookies(request);
{
AddRequestHeaders(webRequest, request.Headers);
}
PrepareRequestCookies(request, webRequest); var response = _httpDispatcher.GetResponse(request, cookies);
var response = _httpDispatcher.GetResponse(request, webRequest); HandleResponseCookies(request, cookies);
HandleResponseCookies(request, webRequest);
stopWatch.Stop(); stopWatch.Stop();
_logger.Trace("{0} ({1:n0} ms)", response, stopWatch.ElapsedMilliseconds); _logger.Trace("{0} ({1:n0} ms)", response, stopWatch.ElapsedMilliseconds);
foreach (var interceptor in _requestInterceptors)
{
response = interceptor.PostResponse(response);
}
if (!RuntimeInfoBase.IsProduction && if (!RuntimeInfoBase.IsProduction &&
(response.StatusCode == HttpStatusCode.Moved || (response.StatusCode == HttpStatusCode.Moved ||
response.StatusCode == HttpStatusCode.MovedPermanently || response.StatusCode == HttpStatusCode.MovedPermanently ||
@ -229,15 +103,10 @@ namespace NzbDrone.Common.Http
} }
} }
foreach (var interceptor in _requestInterceptors)
{
response = interceptor.PostResponse(response);
}
return response; return response;
} }
private void PrepareRequestCookies(HttpRequest request, HttpWebRequest webRequest) private CookieContainer PrepareRequestCookies(HttpRequest request)
{ {
lock (_cookieContainerCache) lock (_cookieContainerCache)
{ {
@ -258,21 +127,15 @@ namespace NzbDrone.Common.Http
var requestCookies = persistentCookieContainer.GetCookies(request.Url); var requestCookies = persistentCookieContainer.GetCookies(request.Url);
if (requestCookies.Count == 0 && !request.StoreResponseCookie) var cookieContainer = new CookieContainer();
{
return;
}
if (webRequest.CookieContainer == null) cookieContainer.Add(requestCookies);
{
webRequest.CookieContainer = new CookieContainer();
}
webRequest.CookieContainer.Add(requestCookies); return cookieContainer;
} }
} }
private void HandleResponseCookies(HttpRequest request, HttpWebRequest webRequest) private void HandleResponseCookies(HttpRequest request, CookieContainer cookieContainer)
{ {
if (!request.StoreResponseCookie) if (!request.StoreResponseCookie)
{ {
@ -283,7 +146,7 @@ namespace NzbDrone.Common.Http
{ {
var persistentCookieContainer = _cookieContainerCache.Get("container", () => new CookieContainer()); var persistentCookieContainer = _cookieContainerCache.Get("container", () => new CookieContainer());
var cookies = webRequest.CookieContainer.GetCookies(request.Url); var cookies = cookieContainer.GetCookies(request.Url);
persistentCookieContainer.Add(cookies); persistentCookieContainer.Add(cookies);
} }
@ -349,56 +212,5 @@ namespace NzbDrone.Common.Http
var response = Post(request); var response = Post(request);
return new HttpResponse<T>(response); return new HttpResponse<T>(response);
} }
protected virtual void AddRequestHeaders(HttpWebRequest webRequest, HttpHeader headers)
{
foreach (var header in headers)
{
switch (header.Key)
{
case "Accept":
webRequest.Accept = header.Value.ToString();
break;
case "Connection":
webRequest.Connection = header.Value.ToString();
break;
case "Content-Length":
webRequest.ContentLength = Convert.ToInt64(header.Value);
break;
case "Content-Type":
webRequest.ContentType = header.Value.ToString();
break;
case "Date":
webRequest.Date = (DateTime)header.Value;
break;
case "Expect":
webRequest.Expect = header.Value.ToString();
break;
case "Host":
webRequest.Host = header.Value.ToString();
break;
case "If-Modified-Since":
webRequest.IfModifiedSince = (DateTime)header.Value;
break;
case "Range":
throw new NotImplementedException();
break;
case "Referer":
webRequest.Referer = header.Value.ToString();
break;
case "Transfer-Encoding":
webRequest.TransferEncoding = header.Value.ToString();
break;
case "User-Agent":
throw new NotSupportedException("User-Agent other than Sonarr not allowed.");
case "Proxy-Connection":
throw new NotImplementedException();
break;
default:
webRequest.Headers.Add(header.Key, header.Value.ToString());
break;
}
}
}
} }
} }

View File

@ -141,7 +141,10 @@
<Compile Include="Extensions\UrlExtensions.cs" /> <Compile Include="Extensions\UrlExtensions.cs" />
<Compile Include="Extensions\XmlExtentions.cs" /> <Compile Include="Extensions\XmlExtentions.cs" />
<Compile Include="HashUtil.cs" /> <Compile Include="HashUtil.cs" />
<Compile Include="Http\CurlHttpClient.cs" /> <Compile Include="Http\Dispatchers\CurlHttpDispatcher.cs" />
<Compile Include="Http\Dispatchers\FallbackHttpDispatcher.cs" />
<Compile Include="Http\Dispatchers\IHttpDispatcher.cs" />
<Compile Include="Http\Dispatchers\ManagedHttpDispatcher.cs" />
<Compile Include="Http\GZipWebClient.cs"> <Compile Include="Http\GZipWebClient.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>