mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 03:52:33 +02:00
Refactored HttpRequest and HttpRequestBuilder, moving most of the logic to the HttpRequestBuilder.
Added ContentSummary to be able to describe the ContentData in a human readable form. (Useful for JsonRpc and FormData).
This commit is contained in:
parent
7818f0c59b
commit
2ffbbb0e71
@ -58,18 +58,20 @@ public void should_execute_typed_get()
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Url.Should().Be(request.Url.ToString());
|
||||
response.Resource.Url.Should().Be(request.Url.AbsoluteUri);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_execute_simple_post()
|
||||
{
|
||||
var message = "{ my: 1 }";
|
||||
|
||||
var request = new HttpRequest("http://eu.httpbin.org/post");
|
||||
request.Body = "{ my: 1 }";
|
||||
request.SetContent(message);
|
||||
|
||||
var response = Subject.Post<HttpBinResource>(request);
|
||||
|
||||
response.Resource.Data.Should().Be(request.Body);
|
||||
response.Resource.Data.Should().Be(message);
|
||||
}
|
||||
|
||||
[TestCase("gzip")]
|
||||
@ -162,7 +164,7 @@ public void should_not_download_file_with_error()
|
||||
public void should_send_cookie()
|
||||
{
|
||||
var request = new HttpRequest("http://eu.httpbin.org/get");
|
||||
request.AddCookie("my", "cookie");
|
||||
request.Cookies["my"] = "cookie";
|
||||
|
||||
var response = Subject.Get<HttpBinResource>(request);
|
||||
|
||||
@ -176,7 +178,7 @@ public void should_send_cookie()
|
||||
public void GivenOldCookie()
|
||||
{
|
||||
var oldRequest = new HttpRequest("http://eu.httpbin.org/get");
|
||||
oldRequest.AddCookie("my", "cookie");
|
||||
oldRequest.Cookies["my"] = "cookie";
|
||||
|
||||
var oldClient = new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<ICacheManager>(), Mocker.Resolve<IRateLimitService>(), Mocker.Resolve<IHttpDispatcher>(), Mocker.Resolve<Logger>());
|
||||
|
||||
@ -260,7 +262,7 @@ public void should_overwrite_response_cookie()
|
||||
var requestSet = new HttpRequest("http://eu.httpbin.org/cookies/set?my=cookie");
|
||||
requestSet.AllowAutoRedirect = false;
|
||||
requestSet.StoreResponseCookie = true;
|
||||
requestSet.AddCookie("my", "oldcookie");
|
||||
requestSet.Cookies["my"] = "oldcookie";
|
||||
|
||||
var responseSet = Subject.Get(requestSet);
|
||||
|
||||
@ -322,10 +324,10 @@ public void should_parse_malformed_cloudflare_cookie(string culture)
|
||||
{
|
||||
// the date is bad in the below - should be 13-Jul-2016
|
||||
string malformedCookie = @"__cfduid=d29e686a9d65800021c66faca0a29b4261436890790; expires=Wed, 13-Jul-16 16:19:50 GMT; path=/; HttpOnly";
|
||||
string url = "http://eu.httpbin.org/response-headers?Set-Cookie=" +
|
||||
System.Uri.EscapeUriString(malformedCookie);
|
||||
var requestSet = new HttpRequestBuilder("http://eu.httpbin.org/response-headers")
|
||||
.AddQueryParam("Set-Cookie", malformedCookie)
|
||||
.Build();
|
||||
|
||||
var requestSet = new HttpRequest(url);
|
||||
requestSet.AllowAutoRedirect = false;
|
||||
requestSet.StoreResponseCookie = true;
|
||||
|
||||
@ -376,6 +378,21 @@ public void should_reject_malformed_domain_cookie(string malformedCookie)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void should_submit_formparameters_in_body()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
public void should_submit_attachments_as_multipart()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
public void should_submit_formparameters_as_multipart_if_attachments_exist()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
public class HttpBinResource
|
||||
|
@ -1,4 +1,5 @@
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Test.Common;
|
||||
@ -8,14 +9,32 @@ namespace NzbDrone.Common.Test.Http
|
||||
[TestFixture]
|
||||
public class HttpRequestBuilderFixture : TestBase
|
||||
{
|
||||
[TestCase("http://host/{seg}/some", "http://host/dir/some")]
|
||||
[TestCase("http://host/some/{seg}", "http://host/some/dir")]
|
||||
public void should_add_single_segment_url_segments(string url, string result)
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(url);
|
||||
|
||||
requestBuilder.SetSegment("seg", "dir");
|
||||
|
||||
requestBuilder.Build().Url.Should().Be(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldnt_add_value_for_nonexisting_segment()
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder("http://host/{seg}/some");
|
||||
Assert.Throws<InvalidOperationException>(() => requestBuilder.SetSegment("seg2", "dir"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_duplicated_slashes()
|
||||
{
|
||||
var builder = new HttpRequestBuilder("http://domain/");
|
||||
|
||||
var request = builder.Build("/v1/");
|
||||
var request = builder.Resource("/v1/").Build();
|
||||
|
||||
request.Url.ToString().Should().Be("http://domain/v1/");
|
||||
request.Url.AbsoluteUri.Should().Be("http://domain/v1/");
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -8,22 +8,5 @@ namespace NzbDrone.Common.Test.Http
|
||||
[TestFixture]
|
||||
public class HttpRequestFixture
|
||||
{
|
||||
[TestCase("http://host/{seg}/some", "http://host/dir/some")]
|
||||
[TestCase("http://host/some/{seg}", "http://host/some/dir")]
|
||||
public void should_add_single_segment_url_segments(string url, string result)
|
||||
{
|
||||
var request = new HttpRequest(url);
|
||||
|
||||
request.AddSegment("seg", "dir");
|
||||
|
||||
request.Url.Should().Be(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void shouldnt_add_value_for_nonexisting_segment()
|
||||
{
|
||||
var request = new HttpRequest("http://host/{seg}/some");
|
||||
Assert.Throws<InvalidOperationException>(() => request.AddSegment("seg2", "dir"));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using NzbDrone.Common.Http;
|
||||
|
||||
namespace NzbDrone.Common.Cloud
|
||||
{
|
||||
public interface IDroneServicesRequestBuilder
|
||||
{
|
||||
HttpRequest Build(string path);
|
||||
}
|
||||
|
||||
public class DroneServicesHttpRequestBuilder : HttpRequestBuilder, IDroneServicesRequestBuilder
|
||||
{
|
||||
private const string ROOT_URL = "http://services.sonarr.tv/v1/";
|
||||
|
||||
public DroneServicesHttpRequestBuilder()
|
||||
: base(ROOT_URL)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
28
src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs
Normal file
28
src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using NzbDrone.Common.Http;
|
||||
|
||||
namespace NzbDrone.Common.Cloud
|
||||
{
|
||||
public interface ISonarrCloudRequestBuilder
|
||||
{
|
||||
IHttpRequestBuilderFactory Services { get; }
|
||||
IHttpRequestBuilderFactory SkyHookTvdb { get; }
|
||||
}
|
||||
|
||||
public class SonarrCloudRequestBuilder : ISonarrCloudRequestBuilder
|
||||
{
|
||||
public SonarrCloudRequestBuilder()
|
||||
{
|
||||
Services = new HttpRequestBuilder("http://services.sonarr.tv/v1/")
|
||||
.CreateFactory();
|
||||
|
||||
SkyHookTvdb = new HttpRequestBuilder("http://skyhook.sonarr.tv/v1/tvdb/{route}/{language}/")
|
||||
.SetSegment("language", "en")
|
||||
.CreateFactory();
|
||||
}
|
||||
|
||||
public IHttpRequestBuilderFactory Services { get; private set; }
|
||||
|
||||
public IHttpRequestBuilderFactory SkyHookTvdb { get; private set; }
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Di
|
||||
|
||||
public static void Add<TKey, TValue>(this ICollection<KeyValuePair<TKey, TValue>> collection, TKey key, TValue value)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
collection.Add(new KeyValuePair<TKey, TValue>(key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,11 @@ public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
|
||||
curlEasy.UserAgent = UserAgentBuilder.UserAgent;
|
||||
curlEasy.FollowLocation = request.AllowAutoRedirect;
|
||||
|
||||
if (request.RequestTimeout != TimeSpan.Zero)
|
||||
{
|
||||
curlEasy.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalSeconds);
|
||||
}
|
||||
|
||||
if (OsInfo.IsWindows)
|
||||
{
|
||||
curlEasy.CaInfo = "curl-ca-bundle.crt";
|
||||
@ -96,11 +101,10 @@ public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
|
||||
curlEasy.Cookie = cookies.GetCookieHeader(request.Url);
|
||||
}
|
||||
|
||||
if (!request.Body.IsNullOrWhiteSpace())
|
||||
if (request.ContentData != null)
|
||||
{
|
||||
// TODO: This might not go well with encoding.
|
||||
curlEasy.PostFieldSize = request.Body.Length;
|
||||
curlEasy.SetOpt(CurlOption.CopyPostFields, request.Body);
|
||||
curlEasy.PostFieldSize = request.ContentData.Length;
|
||||
curlEasy.SetOpt(CurlOption.CopyPostFields, new string(Array.ConvertAll(request.ContentData, v => (char)v)));
|
||||
}
|
||||
|
||||
// Yes, we have to keep a ref to the object to prevent corrupting the unmanaged state
|
||||
|
@ -23,19 +23,22 @@ public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
|
||||
webRequest.ContentLength = 0;
|
||||
webRequest.CookieContainer = cookies;
|
||||
|
||||
if (request.RequestTimeout != TimeSpan.Zero)
|
||||
{
|
||||
webRequest.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalMilliseconds);
|
||||
}
|
||||
|
||||
if (request.Headers != null)
|
||||
{
|
||||
AddRequestHeaders(webRequest, request.Headers);
|
||||
}
|
||||
|
||||
if (!request.Body.IsNullOrWhiteSpace())
|
||||
if (request.ContentData != null)
|
||||
{
|
||||
var bytes = request.Headers.GetEncodingFromContentType().GetBytes(request.Body.ToCharArray());
|
||||
|
||||
webRequest.ContentLength = bytes.Length;
|
||||
webRequest.ContentLength = request.ContentData.Length;
|
||||
using (var writeStream = webRequest.GetRequestStream())
|
||||
{
|
||||
writeStream.Write(bytes, 0, bytes.Length);
|
||||
writeStream.Write(request.ContentData, 0, request.ContentData.Length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,43 +78,43 @@ protected virtual void AddRequestHeaders(HttpWebRequest webRequest, HttpHeader h
|
||||
switch (header.Key)
|
||||
{
|
||||
case "Accept":
|
||||
webRequest.Accept = header.Value.ToString();
|
||||
webRequest.Accept = header.Value;
|
||||
break;
|
||||
case "Connection":
|
||||
webRequest.Connection = header.Value.ToString();
|
||||
webRequest.Connection = header.Value;
|
||||
break;
|
||||
case "Content-Length":
|
||||
webRequest.ContentLength = Convert.ToInt64(header.Value);
|
||||
break;
|
||||
case "Content-Type":
|
||||
webRequest.ContentType = header.Value.ToString();
|
||||
webRequest.ContentType = header.Value;
|
||||
break;
|
||||
case "Date":
|
||||
webRequest.Date = (DateTime)header.Value;
|
||||
webRequest.Date = HttpHeader.ParseDateTime(header.Value);
|
||||
break;
|
||||
case "Expect":
|
||||
webRequest.Expect = header.Value.ToString();
|
||||
webRequest.Expect = header.Value;
|
||||
break;
|
||||
case "Host":
|
||||
webRequest.Host = header.Value.ToString();
|
||||
webRequest.Host = header.Value;
|
||||
break;
|
||||
case "If-Modified-Since":
|
||||
webRequest.IfModifiedSince = (DateTime)header.Value;
|
||||
webRequest.IfModifiedSince = HttpHeader.ParseDateTime(header.Value);
|
||||
break;
|
||||
case "Range":
|
||||
throw new NotImplementedException();
|
||||
case "Referer":
|
||||
webRequest.Referer = header.Value.ToString();
|
||||
webRequest.Referer = header.Value;
|
||||
break;
|
||||
case "Transfer-Encoding":
|
||||
webRequest.TransferEncoding = header.Value.ToString();
|
||||
webRequest.TransferEncoding = header.Value;
|
||||
break;
|
||||
case "User-Agent":
|
||||
throw new NotSupportedException("User-Agent other than Sonarr not allowed.");
|
||||
case "Proxy-Connection":
|
||||
throw new NotImplementedException();
|
||||
default:
|
||||
webRequest.Headers.Add(header.Key, header.Value.ToString());
|
||||
webRequest.Headers.Add(header.Key, header.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,11 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http.Dispatchers;
|
||||
using NzbDrone.Common.TPL;
|
||||
|
||||
|
@ -8,7 +8,7 @@ public class HttpException : Exception
|
||||
public HttpResponse Response { get; private set; }
|
||||
|
||||
public HttpException(HttpRequest request, HttpResponse response)
|
||||
: base(string.Format("HTTP request failed: [{0}:{1}] [{2}] at [{3}]", (int)response.StatusCode, response.StatusCode, request.Method, request.Url.ToString()))
|
||||
: base(string.Format("HTTP request failed: [{0}:{1}] [{2}] at [{3}]", (int)response.StatusCode, response.StatusCode, request.Method, request.Url.AbsoluteUri))
|
||||
{
|
||||
Request = request;
|
||||
Response = response;
|
||||
|
14
src/NzbDrone.Common/Http/HttpFormData.cs
Normal file
14
src/NzbDrone.Common/Http/HttpFormData.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Common.Http
|
||||
{
|
||||
public class HttpFormData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public byte[] ContentData { get; set; }
|
||||
public string ContentType { get; set; }
|
||||
}
|
||||
}
|
@ -4,37 +4,92 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
|
||||
namespace NzbDrone.Common.Http
|
||||
{
|
||||
public class HttpHeader : Dictionary<string, object>
|
||||
public class HttpHeader : NameValueCollection, IEnumerable<KeyValuePair<string, string>>, IEnumerable
|
||||
{
|
||||
public HttpHeader(NameValueCollection headers) : base(StringComparer.OrdinalIgnoreCase)
|
||||
public HttpHeader(NameValueCollection headers)
|
||||
: base(headers)
|
||||
{
|
||||
foreach (var key in headers.AllKeys)
|
||||
|
||||
}
|
||||
|
||||
public HttpHeader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
key = key.ToLowerInvariant();
|
||||
return AllKeys.Any(v => v.ToLowerInvariant() == key);
|
||||
}
|
||||
|
||||
public string GetSingleValue(string key)
|
||||
{
|
||||
var values = GetValues(key);
|
||||
if (values == null || values.Length == 0)
|
||||
{
|
||||
this[key] = headers[key];
|
||||
return null;
|
||||
}
|
||||
if (values.Length > 1)
|
||||
{
|
||||
throw new ApplicationException(string.Format("Expected {0} to occur only once.", key));
|
||||
}
|
||||
|
||||
return values[0];
|
||||
}
|
||||
|
||||
protected T? GetSingleValue<T>(string key, Func<string, T> converter) where T : struct
|
||||
{
|
||||
var value = GetSingleValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return converter(value);
|
||||
}
|
||||
protected void SetSingleValue(string key, string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Remove(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
Set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public HttpHeader() : base(StringComparer.OrdinalIgnoreCase)
|
||||
protected void SetSingleValue<T>(string key, T? value, Func<T, string> converter = null) where T : struct
|
||||
{
|
||||
|
||||
if (!value.HasValue)
|
||||
{
|
||||
Remove(key);
|
||||
}
|
||||
else if (converter != null)
|
||||
{
|
||||
Set(key, converter(value.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
Set(key, value.Value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public long? ContentLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ContainsKey("Content-Length"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Convert.ToInt64(this["Content-Length"]);
|
||||
return GetSingleValue("Content-Length", Convert.ToInt64);
|
||||
}
|
||||
set
|
||||
{
|
||||
this["Content-Length"] = value;
|
||||
SetSingleValue("Content-Length", value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,15 +97,11 @@ public string ContentType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ContainsKey("Content-Type"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return this["Content-Type"].ToString();
|
||||
return GetSingleValue("Content-Type");
|
||||
}
|
||||
set
|
||||
{
|
||||
this["Content-Type"] = value;
|
||||
SetSingleValue("Content-Type", value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,25 +109,36 @@ public string Accept
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ContainsKey("Accept"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return this["Accept"].ToString();
|
||||
return GetSingleValue("Accept");
|
||||
}
|
||||
set
|
||||
{
|
||||
this["Accept"] = value;
|
||||
SetSingleValue("Accept", value);
|
||||
}
|
||||
}
|
||||
|
||||
public new IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||
{
|
||||
return AllKeys.SelectMany(GetValues, (k, c) => new KeyValuePair<string, string>(k, c)).ToList().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return base.GetEnumerator();
|
||||
}
|
||||
|
||||
public Encoding GetEncodingFromContentType()
|
||||
{
|
||||
return GetEncodingFromContentType(ContentType ?? string.Empty);
|
||||
}
|
||||
|
||||
public static Encoding GetEncodingFromContentType(string contentType)
|
||||
{
|
||||
Encoding encoding = null;
|
||||
|
||||
if (ContentType.IsNotNullOrWhiteSpace())
|
||||
if (contentType.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var charset = ContentType.ToLowerInvariant()
|
||||
var charset = contentType.ToLowerInvariant()
|
||||
.Split(';', '=', ' ')
|
||||
.SkipWhile(v => v != "charset")
|
||||
.Skip(1).FirstOrDefault();
|
||||
@ -99,5 +161,18 @@ public Encoding GetEncodingFromContentType()
|
||||
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public static DateTime ParseDateTime(string value)
|
||||
{
|
||||
return DateTime.ParseExact(value, "R", CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal);
|
||||
}
|
||||
|
||||
public static List<KeyValuePair<string, string>> ParseCookies(string cookies)
|
||||
{
|
||||
return cookies.Split(';')
|
||||
.Select(v => v.Trim().Split('='))
|
||||
.Select(v => new KeyValuePair<string, string>(v[0], v[1]))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Common.Http
|
||||
{
|
||||
public class HttpRequest
|
||||
{
|
||||
private readonly Dictionary<string, string> _segments;
|
||||
|
||||
public HttpRequest(string url, HttpAccept httpAccept = null)
|
||||
public HttpRequest(string uri, HttpAccept httpAccept = null)
|
||||
{
|
||||
UriBuilder = new UriBuilder(url);
|
||||
UrlBuilder = new UriBuilder(uri);
|
||||
Headers = new HttpHeader();
|
||||
_segments = new Dictionary<string, string>();
|
||||
AllowAutoRedirect = true;
|
||||
Cookies = new Dictionary<string, string>();
|
||||
|
||||
@ -28,73 +28,41 @@ public HttpRequest(string url, HttpAccept httpAccept = null)
|
||||
}
|
||||
}
|
||||
|
||||
public UriBuilder UriBuilder { get; private set; }
|
||||
|
||||
public Uri Url
|
||||
{
|
||||
get
|
||||
{
|
||||
var uri = UriBuilder.Uri.ToString();
|
||||
|
||||
foreach (var segment in _segments)
|
||||
{
|
||||
uri = uri.Replace(segment.Key, segment.Value);
|
||||
}
|
||||
|
||||
return new Uri(uri);
|
||||
}
|
||||
}
|
||||
|
||||
public UriBuilder UrlBuilder { get; private set; }
|
||||
public Uri Url { get { return UrlBuilder.Uri; } }
|
||||
public HttpMethod Method { get; set; }
|
||||
public HttpHeader Headers { get; set; }
|
||||
public string Body { get; set; }
|
||||
public byte[] ContentData { get; set; }
|
||||
public string ContentSummary { get; set; }
|
||||
public NetworkCredential NetworkCredential { get; set; }
|
||||
public bool SuppressHttpError { get; set; }
|
||||
public bool AllowAutoRedirect { get; set; }
|
||||
public Dictionary<string, string> Cookies { get; private set; }
|
||||
public bool StoreResponseCookie { get; set; }
|
||||
public TimeSpan RequestTimeout { get; set; }
|
||||
public TimeSpan RateLimit { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Body == null)
|
||||
if (ContentSummary == null)
|
||||
{
|
||||
return string.Format("Req: [{0}] {1}", Method, Url);
|
||||
}
|
||||
|
||||
return string.Format("Req: [{0}] {1} {2} {3}", Method, Url, Environment.NewLine, Body);
|
||||
}
|
||||
|
||||
public void AddSegment(string segment, string value)
|
||||
{
|
||||
var key = "{" + segment + "}";
|
||||
|
||||
if (!UriBuilder.Uri.ToString().Contains(key))
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Segment " + key +" is not defined in Uri");
|
||||
return string.Format("Req: [{0}] {1}: {2}", Method, Url, ContentSummary);
|
||||
}
|
||||
|
||||
_segments.Add(key, value);
|
||||
}
|
||||
|
||||
public void AddQueryParam(string segment, string value)
|
||||
public void SetContent(byte[] data)
|
||||
{
|
||||
UriBuilder.SetQueryParam(segment, value);
|
||||
ContentData = data;
|
||||
}
|
||||
|
||||
public void AddCookie(string key, string value)
|
||||
public void SetContent(string data)
|
||||
{
|
||||
Cookies[key] = value;
|
||||
}
|
||||
|
||||
public void AddCookie(string cookies)
|
||||
{
|
||||
foreach (var pair in cookies.Split(';'))
|
||||
{
|
||||
var split = pair.Split('=');
|
||||
|
||||
Cookies[split[0].Trim()] = split[1].Trim();
|
||||
}
|
||||
var encoding = HttpHeader.GetEncodingFromContentType(Headers.ContentType);
|
||||
ContentData = encoding.GetBytes(data);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +1,123 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Common.Http
|
||||
{
|
||||
public class HttpRequestBuilder
|
||||
{
|
||||
public Uri BaseUri { get; private set; }
|
||||
public bool SupressHttpError { get; set; }
|
||||
public HttpMethod Method { get; set; }
|
||||
public HttpAccept HttpAccept { get; set; }
|
||||
public Uri BaseUrl { get; private set; }
|
||||
public string ResourceUrl { get; set; }
|
||||
public List<KeyValuePair<string, string>> QueryParams { get; private set; }
|
||||
public List<KeyValuePair<string, string>> SuffixQueryParams { get; private set; }
|
||||
public Dictionary<string, string> Segments { get; private set; }
|
||||
public HttpHeader Headers { get; private set; }
|
||||
public bool SuppressHttpError { get; set; }
|
||||
public bool AllowAutoRedirect { get; set; }
|
||||
public NetworkCredential NetworkCredential { get; set; }
|
||||
public Dictionary<string, string> Cookies { get; private set; }
|
||||
|
||||
public Action<HttpRequest> PostProcess { get; set; }
|
||||
|
||||
public HttpRequestBuilder(string baseUri)
|
||||
public HttpRequestBuilder(string baseUrl)
|
||||
{
|
||||
BaseUri = new Uri(baseUri);
|
||||
BaseUrl = new Uri(baseUrl);
|
||||
ResourceUrl = string.Empty;
|
||||
Method = HttpMethod.GET;
|
||||
QueryParams = new List<KeyValuePair<string, string>>();
|
||||
SuffixQueryParams = new List<KeyValuePair<string, string>>();
|
||||
Segments = new Dictionary<string, string>();
|
||||
Headers = new HttpHeader();
|
||||
Cookies = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public virtual HttpRequest Build(string path)
|
||||
public HttpRequestBuilder(bool useHttps, string host, int port, string urlBase = null)
|
||||
: this(BuildBaseUrl(useHttps, host, port, urlBase))
|
||||
{
|
||||
if (BaseUri.ToString().EndsWith("/"))
|
||||
|
||||
}
|
||||
|
||||
public static string BuildBaseUrl(bool useHttps, string host, int port, string urlBase = null)
|
||||
{
|
||||
var protocol = useHttps ? "https" : "http";
|
||||
|
||||
if (urlBase.IsNotNullOrWhiteSpace() && !urlBase.StartsWith("/"))
|
||||
{
|
||||
path = path.TrimStart('/');
|
||||
urlBase = "/" + urlBase;
|
||||
}
|
||||
|
||||
var request = new HttpRequest(BaseUri + path)
|
||||
return string.Format("{0}://{1}:{2}{3}", protocol, host, port, urlBase);
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder Clone()
|
||||
{
|
||||
var clone = MemberwiseClone() as HttpRequestBuilder;
|
||||
clone.QueryParams = new List<KeyValuePair<string, string>>(clone.QueryParams);
|
||||
clone.SuffixQueryParams = new List<KeyValuePair<string, string>>(clone.SuffixQueryParams);
|
||||
clone.Segments = new Dictionary<string, string>(clone.Segments);
|
||||
clone.Headers = new HttpHeader(clone.Headers);
|
||||
clone.Cookies = new Dictionary<string, string>(clone.Cookies);
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected virtual Uri CreateUri()
|
||||
{
|
||||
var builder = new UriBuilder(new Uri(BaseUrl, ResourceUrl));
|
||||
|
||||
foreach (var queryParam in QueryParams.Concat(SuffixQueryParams))
|
||||
{
|
||||
SuppressHttpError = SupressHttpError,
|
||||
NetworkCredential = NetworkCredential
|
||||
};
|
||||
builder.SetQueryParam(queryParam.Key, queryParam.Value);
|
||||
}
|
||||
|
||||
if (Segments.Any())
|
||||
{
|
||||
var url = builder.Uri.ToString();
|
||||
|
||||
foreach (var segment in Segments)
|
||||
{
|
||||
url = url.Replace(segment.Key, segment.Value);
|
||||
}
|
||||
|
||||
builder = new UriBuilder(url);
|
||||
}
|
||||
|
||||
return builder.Uri;
|
||||
}
|
||||
|
||||
protected virtual HttpRequest CreateRequest()
|
||||
{
|
||||
return new HttpRequest(CreateUri().ToString(), HttpAccept);
|
||||
}
|
||||
|
||||
protected virtual void Apply(HttpRequest request)
|
||||
{
|
||||
request.Method = Method;
|
||||
request.SuppressHttpError = SuppressHttpError;
|
||||
request.AllowAutoRedirect = AllowAutoRedirect;
|
||||
request.NetworkCredential = NetworkCredential;
|
||||
|
||||
foreach (var header in Headers)
|
||||
{
|
||||
request.Headers.Set(header.Key, header.Value);
|
||||
}
|
||||
|
||||
foreach (var cookie in Cookies)
|
||||
{
|
||||
request.Cookies[cookie.Key] = cookie.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual HttpRequest Build()
|
||||
{
|
||||
var request = CreateRequest();
|
||||
|
||||
Apply(request);
|
||||
|
||||
if (PostProcess != null)
|
||||
{
|
||||
@ -36,5 +126,102 @@ public virtual HttpRequest Build(string path)
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public IHttpRequestBuilderFactory CreateFactory()
|
||||
{
|
||||
return new HttpRequestBuilderFactory(this);
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder Resource(string resourceUrl)
|
||||
{
|
||||
if (!ResourceUrl.IsNotNullOrWhiteSpace() || resourceUrl.StartsWith("/"))
|
||||
{
|
||||
ResourceUrl = resourceUrl.TrimStart('/');
|
||||
}
|
||||
else
|
||||
{
|
||||
ResourceUrl = string.Format("{0}/{1}", ResourceUrl.TrimEnd('/'), resourceUrl);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder Post()
|
||||
{
|
||||
Method = HttpMethod.POST;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder Accept(HttpAccept accept)
|
||||
{
|
||||
HttpAccept = accept;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder SetHeader(string name, string value)
|
||||
{
|
||||
Headers.Set(name, value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder AddQueryParam(string key, object value, bool replace = false)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
QueryParams.RemoveAll(v => v.Key == key);
|
||||
SuffixQueryParams.RemoveAll(v => v.Key == key);
|
||||
}
|
||||
|
||||
QueryParams.Add(key, value.ToString());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder AddSuffixQueryParam(string key, object value, bool replace = false)
|
||||
{
|
||||
if (replace)
|
||||
{
|
||||
QueryParams.RemoveAll(v => v.Key == key);
|
||||
SuffixQueryParams.RemoveAll(v => v.Key == key);
|
||||
}
|
||||
|
||||
SuffixQueryParams.Add(new KeyValuePair<string, string>(key, value.ToString()));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder SetSegment(string segment, string value, bool dontCheck = false)
|
||||
{
|
||||
var key = string.Concat("{", segment, "}");
|
||||
|
||||
if (!dontCheck && !CreateUri().ToString().Contains(key))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Segment {0} is not defined in Uri", segment));
|
||||
}
|
||||
|
||||
Segments[key] = value;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder SetCookies(IEnumerable<KeyValuePair<string, string>> cookies)
|
||||
{
|
||||
foreach (var cookie in cookies)
|
||||
{
|
||||
Cookies[cookie.Key] = cookie.Value;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual HttpRequestBuilder SetCookie(string key, string value)
|
||||
{
|
||||
Cookies[key] = value;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
36
src/NzbDrone.Common/Http/HttpRequestBuilderFactory.cs
Normal file
36
src/NzbDrone.Common/Http/HttpRequestBuilderFactory.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Common.Http
|
||||
{
|
||||
public interface IHttpRequestBuilderFactory
|
||||
{
|
||||
HttpRequestBuilder Create();
|
||||
}
|
||||
|
||||
public class HttpRequestBuilderFactory : IHttpRequestBuilderFactory
|
||||
{
|
||||
private HttpRequestBuilder _rootBuilder;
|
||||
|
||||
public HttpRequestBuilderFactory(HttpRequestBuilder rootBuilder)
|
||||
{
|
||||
SetRootBuilder(rootBuilder);
|
||||
}
|
||||
|
||||
protected HttpRequestBuilderFactory()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void SetRootBuilder(HttpRequestBuilder rootBuilder)
|
||||
{
|
||||
_rootBuilder = rootBuilder.Clone();
|
||||
}
|
||||
|
||||
public HttpRequestBuilder Create()
|
||||
{
|
||||
return _rootBuilder.Clone();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
|
||||
namespace NzbDrone.Common.Http
|
||||
{
|
||||
public class HttpResponse
|
||||
{
|
||||
private static readonly Regex RegexSetCookie = new Regex("^(.*?)=(.*?)(?:;|$)", RegexOptions.Compiled);
|
||||
|
||||
public HttpResponse(HttpRequest request, HttpHeader headers, byte[] binaryData, HttpStatusCode statusCode = HttpStatusCode.OK)
|
||||
{
|
||||
Request = request;
|
||||
@ -52,11 +57,27 @@ public bool HasHttpError
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> GetCookies()
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
|
||||
foreach (var cookie in Headers.GetValues("Set-Cookie"))
|
||||
{
|
||||
var match = RegexSetCookie.Match(cookie);
|
||||
if (match.Success)
|
||||
{
|
||||
result[match.Groups[1].Value] = match.Groups[2].Value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var result = string.Format("Res: [{0}] {1} : {2}.{3}", Request.Method, Request.Url, (int)StatusCode, StatusCode);
|
||||
|
||||
if (HasHttpError && !Headers.ContentType.Equals("text/html", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (HasHttpError && Headers.ContentType.IsNotNullOrWhiteSpace() && !Headers.ContentType.Equals("text/html", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
result += Environment.NewLine + Content;
|
||||
}
|
||||
|
@ -7,32 +7,87 @@ namespace NzbDrone.Common.Http
|
||||
{
|
||||
public class JsonRpcRequestBuilder : HttpRequestBuilder
|
||||
{
|
||||
public string Method { get; private set; }
|
||||
public List<object> Parameters { get; private set; }
|
||||
public static HttpAccept JsonRpcHttpAccept = new HttpAccept("application/json-rpc, application/json");
|
||||
public static string JsonRpcContentType = "application/json-rpc";
|
||||
|
||||
public JsonRpcRequestBuilder(string baseUri, string method, IEnumerable<object> parameters)
|
||||
: base (baseUri)
|
||||
public string JsonMethod { get; private set; }
|
||||
public List<object> JsonParameters { get; private set; }
|
||||
|
||||
public JsonRpcRequestBuilder(string baseUrl)
|
||||
: base(baseUrl)
|
||||
{
|
||||
Method = method;
|
||||
Parameters = parameters.ToList();
|
||||
Method = HttpMethod.POST;
|
||||
JsonParameters = new List<object>();
|
||||
}
|
||||
|
||||
public override HttpRequest Build(string path)
|
||||
public JsonRpcRequestBuilder(string baseUrl, string method, IEnumerable<object> parameters)
|
||||
: base (baseUrl)
|
||||
{
|
||||
var request = base.Build(path);
|
||||
request.Method = HttpMethod.POST;
|
||||
request.Headers.Accept = "application/json-rpc, application/json";
|
||||
request.Headers.ContentType = "application/json-rpc";
|
||||
Method = HttpMethod.POST;
|
||||
JsonMethod = method;
|
||||
JsonParameters = parameters.ToList();
|
||||
}
|
||||
|
||||
public override HttpRequestBuilder Clone()
|
||||
{
|
||||
var clone = base.Clone() as JsonRpcRequestBuilder;
|
||||
clone.JsonParameters = new List<object>(JsonParameters);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public JsonRpcRequestBuilder Call(string method, params object[] parameters)
|
||||
{
|
||||
var clone = Clone() as JsonRpcRequestBuilder;
|
||||
clone.JsonMethod = method;
|
||||
clone.JsonParameters = parameters.ToList();
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected override void Apply(HttpRequest request)
|
||||
{
|
||||
base.Apply(request);
|
||||
|
||||
request.Headers.ContentType = JsonRpcContentType;
|
||||
|
||||
var parameterData = new object[JsonParameters.Count];
|
||||
var parameterSummary = new string[JsonParameters.Count];
|
||||
|
||||
for (var i = 0; i < JsonParameters.Count; i++)
|
||||
{
|
||||
ConvertParameter(JsonParameters[i], out parameterData[i], out parameterSummary[i]);
|
||||
}
|
||||
|
||||
var message = new Dictionary<string, object>();
|
||||
message["jsonrpc"] = "2.0";
|
||||
message["method"] = Method;
|
||||
message["params"] = Parameters;
|
||||
message["method"] = JsonMethod;
|
||||
message["params"] = parameterData;
|
||||
message["id"] = CreateNextId();
|
||||
|
||||
request.Body = message.ToJson();
|
||||
request.SetContent(message.ToJson());
|
||||
|
||||
return request;
|
||||
if (request.ContentSummary == null)
|
||||
{
|
||||
request.ContentSummary = string.Format("{0}({1})", JsonMethod, string.Join(", ", parameterSummary));
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertParameter(object value, out object data, out string summary)
|
||||
{
|
||||
if (value is byte[])
|
||||
{
|
||||
data = Convert.ToBase64String(value as byte[]);
|
||||
summary = string.Format("[blob {0} bytes]", (value as byte[]).Length);
|
||||
}
|
||||
else if (value is Array && ((Array)value).Length > 0)
|
||||
{
|
||||
data = value;
|
||||
summary = "[...]";
|
||||
}
|
||||
else
|
||||
{
|
||||
data = value;
|
||||
summary = data.ToJson();
|
||||
}
|
||||
}
|
||||
|
||||
public string CreateNextId()
|
||||
|
@ -67,7 +67,7 @@
|
||||
<Compile Include="Cache\CachedDictionary.cs" />
|
||||
<Compile Include="Cache\ICached.cs" />
|
||||
<Compile Include="Cache\ICachedDictionary.cs" />
|
||||
<Compile Include="Cloud\CloudClient.cs" />
|
||||
<Compile Include="Cloud\SonarrCloudRequestBuilder.cs" />
|
||||
<Compile Include="Composition\Container.cs" />
|
||||
<Compile Include="Composition\ContainerBuilderBase.cs" />
|
||||
<Compile Include="Composition\IContainer.cs" />
|
||||
@ -156,6 +156,7 @@
|
||||
<Compile Include="Http\HttpAccept.cs" />
|
||||
<Compile Include="Http\HttpClient.cs" />
|
||||
<Compile Include="Http\HttpException.cs" />
|
||||
<Compile Include="Http\HttpFormData.cs" />
|
||||
<Compile Include="Http\HttpHeader.cs" />
|
||||
<Compile Include="Http\HttpMethod.cs" />
|
||||
<Compile Include="Http\HttpProvider.cs" />
|
||||
@ -168,6 +169,7 @@
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Http\HttpRequestBuilder.cs" />
|
||||
<Compile Include="Http\HttpRequestBuilderFactory.cs" />
|
||||
<Compile Include="Http\TooManyRequestsException.cs" />
|
||||
<Compile Include="Http\UriExtensions.cs" />
|
||||
<Compile Include="Extensions\IEnumerableExtensions.cs" />
|
||||
|
@ -112,7 +112,7 @@ public void Download_should_download_file_if_it_doesnt_exist()
|
||||
|
||||
Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.ToString() == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.AbsoluteUri == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
@ -128,7 +128,7 @@ public void Download_should_replace_illegal_characters_in_title()
|
||||
|
||||
Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.ToString() == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.AbsoluteUri == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(expectedFilename), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ public void Download_should_download_file_if_it_doesnt_exist()
|
||||
|
||||
Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.ToString() == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.AbsoluteUri == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(_filePath), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
@ -109,7 +109,7 @@ public void Download_should_replace_illegal_characters_in_title()
|
||||
|
||||
Subject.Download(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.ToString() == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.Get(It.Is<HttpRequest>(v => v.Url.AbsoluteUri == _downloadUrl)), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenWriteStream(expectedFilename), Times.Once());
|
||||
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ protected void GivenRedirectToTorrent()
|
||||
httpHeader["Location"] = "http://test.sonarr.tv/not-a-real-torrent.torrent";
|
||||
|
||||
Mocker.GetMock<IHttpClient>()
|
||||
.Setup(s => s.Get(It.Is<HttpRequest>(h => h.Url.AbsoluteUri == _downloadUrl)))
|
||||
.Setup(s => s.Get(It.Is<HttpRequest>(h => h.Url.ToString() == _downloadUrl)))
|
||||
.Returns<HttpRequest>(r => new HttpResponse(r, httpHeader, new byte[0], System.Net.HttpStatusCode.Found));
|
||||
}
|
||||
|
||||
|
@ -84,90 +84,6 @@ public void ToBestDateTime_Before_Yesterday()
|
||||
dateTime.ToBestDateString().Should().Be(dateTime.ToShortDateString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParentUriString_should_return_self_if_already_parent()
|
||||
{
|
||||
|
||||
var url = "http://www.sonarr.tv";
|
||||
var uri = new Uri(url);
|
||||
|
||||
|
||||
var result = uri.ParentUriString();
|
||||
|
||||
//Resolve
|
||||
result.Should().Be(url);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParentUriString_should_return_parent_url_when_path_is_passed()
|
||||
{
|
||||
|
||||
var url = "http://www.sonarr.tv/test/";
|
||||
var uri = new Uri(url);
|
||||
|
||||
|
||||
var result = uri.ParentUriString();
|
||||
|
||||
//Resolve
|
||||
result.Should().Be("http://www.sonarr.tv");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParentUriString_should_return_parent_url_when_multiple_paths_are_passed()
|
||||
{
|
||||
|
||||
var url = "http://www.sonarr.tv/test/test2";
|
||||
var uri = new Uri(url);
|
||||
|
||||
|
||||
var result = uri.ParentUriString();
|
||||
|
||||
//Resolve
|
||||
result.Should().Be("http://www.sonarr.tv");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParentUriString_should_return_parent_url_when_url_with_query_string_is_passed()
|
||||
{
|
||||
|
||||
var url = "http://www.sonarr.tv/test.aspx?test=10";
|
||||
var uri = new Uri(url);
|
||||
|
||||
|
||||
var result = uri.ParentUriString();
|
||||
|
||||
//Resolve
|
||||
result.Should().Be("http://www.sonarr.tv");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParentUriString_should_return_parent_url_when_url_with_path_and_query_strings_is_passed()
|
||||
{
|
||||
|
||||
var url = "http://www.sonarr.tv/tester/test.aspx?test=10";
|
||||
var uri = new Uri(url);
|
||||
|
||||
|
||||
var result = uri.ParentUriString();
|
||||
|
||||
//Resolve
|
||||
result.Should().Be("http://www.sonarr.tv");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParentUriString_should_return_parent_url_when_url_with_query_strings_is_passed()
|
||||
{
|
||||
|
||||
var url = "http://www.sonarr.tv/test.aspx?test=10&test2=5";
|
||||
var uri = new Uri(url);
|
||||
|
||||
|
||||
var result = uri.ParentUriString();
|
||||
|
||||
//Resolve
|
||||
result.Should().Be("http://www.sonarr.tv");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MaxOrDefault_should_return_zero_when_collection_is_empty()
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ protected void UseRealHttp()
|
||||
{
|
||||
Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger));
|
||||
Mocker.SetConstant<IHttpClient>(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), TestLogger));
|
||||
Mocker.SetConstant<IDroneServicesRequestBuilder>(new DroneServicesHttpRequestBuilder());
|
||||
Mocker.SetConstant<ISonarrCloudRequestBuilder>(new SonarrCloudRequestBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,13 +15,13 @@ public interface IDailySeriesDataProxy
|
||||
public class DailySeriesDataProxy : IDailySeriesDataProxy
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IDroneServicesRequestBuilder _requestBuilder;
|
||||
private readonly IHttpRequestBuilderFactory _requestBuilder;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DailySeriesDataProxy(IHttpClient httpClient, IDroneServicesRequestBuilder requestBuilder, Logger logger)
|
||||
public DailySeriesDataProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, Logger logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_requestBuilder = requestBuilder;
|
||||
_requestBuilder = requestBuilder.Services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@ -29,7 +29,10 @@ public IEnumerable<int> GetDailySeriesIds()
|
||||
{
|
||||
try
|
||||
{
|
||||
var dailySeriesRequest = _requestBuilder.Build("dailyseries");
|
||||
var dailySeriesRequest = _requestBuilder.Create()
|
||||
.Resource("/dailyseries")
|
||||
.Build();
|
||||
|
||||
var response = _httpClient.Get<List<DailySeries>>(dailySeriesRequest);
|
||||
return response.Resource.Select(c => c.TvdbId);
|
||||
}
|
||||
|
@ -12,17 +12,20 @@ public interface ISceneMappingProxy
|
||||
public class SceneMappingProxy : ISceneMappingProxy
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IDroneServicesRequestBuilder _requestBuilder;
|
||||
private readonly IHttpRequestBuilderFactory _requestBuilder;
|
||||
|
||||
public SceneMappingProxy(IHttpClient httpClient, IDroneServicesRequestBuilder requestBuilder)
|
||||
public SceneMappingProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_requestBuilder = requestBuilder;
|
||||
_requestBuilder = requestBuilder.Services;
|
||||
}
|
||||
|
||||
public List<SceneMapping> Fetch()
|
||||
{
|
||||
var request = _requestBuilder.Build("/scenemapping");
|
||||
var request = _requestBuilder.Create()
|
||||
.Resource("/scenemapping")
|
||||
.Build();
|
||||
|
||||
return _httpClient.Get<List<SceneMapping>>(request).Resource;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cloud;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.DataAugmentation.Xem.Model;
|
||||
@ -18,32 +19,32 @@ public interface IXemProxy
|
||||
|
||||
public class XemProxy : IXemProxy
|
||||
{
|
||||
private const string ROOT_URL = "http://thexem.de/map/";
|
||||
|
||||
private readonly Logger _logger;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
private const string XEM_BASE_URL = "http://thexem.de/map/";
|
||||
private readonly IHttpRequestBuilderFactory _xemRequestBuilder;
|
||||
|
||||
private static readonly string[] IgnoredErrors = { "no single connection", "no show with the tvdb_id" };
|
||||
private HttpRequestBuilder _xemRequestBuilder;
|
||||
|
||||
|
||||
public XemProxy(Logger logger, IHttpClient httpClient)
|
||||
public XemProxy(IHttpClient httpClient, Logger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
|
||||
_xemRequestBuilder = new HttpRequestBuilder(XEM_BASE_URL)
|
||||
{
|
||||
PostProcess = r => r.UriBuilder.SetQueryParam("origin", "tvdb")
|
||||
};
|
||||
_xemRequestBuilder = new HttpRequestBuilder(ROOT_URL)
|
||||
.AddSuffixQueryParam("origin", "tvdb")
|
||||
.CreateFactory();
|
||||
}
|
||||
|
||||
|
||||
public List<int> GetXemSeriesIds()
|
||||
{
|
||||
_logger.Debug("Fetching Series IDs from");
|
||||
|
||||
var request = _xemRequestBuilder.Build("/havemap");
|
||||
var request = _xemRequestBuilder.Create()
|
||||
.Resource("/havemap")
|
||||
.Build();
|
||||
|
||||
var response = _httpClient.Get<XemResult<List<string>>>(request).Resource;
|
||||
CheckForFailureResult(response);
|
||||
|
||||
@ -60,9 +61,10 @@ public List<XemSceneTvdbMapping> GetSceneTvdbMappings(int id)
|
||||
{
|
||||
_logger.Debug("Fetching Mappings for: {0}", id);
|
||||
|
||||
|
||||
var request = _xemRequestBuilder.Build("/all");
|
||||
request.UriBuilder.SetQueryParam("id", id);
|
||||
var request = _xemRequestBuilder.Create()
|
||||
.Resource("/all")
|
||||
.AddQueryParam("id", id)
|
||||
.Build();
|
||||
|
||||
var response = _httpClient.Get<XemResult<List<XemSceneTvdbMapping>>>(request).Resource;
|
||||
|
||||
@ -73,8 +75,10 @@ public List<SceneMapping> GetSceneTvdbNames()
|
||||
{
|
||||
_logger.Debug("Fetching alternate names");
|
||||
|
||||
var request = _xemRequestBuilder.Build("/allNames");
|
||||
request.UriBuilder.SetQueryParam("seasonNumbers", true);
|
||||
var request = _xemRequestBuilder.Create()
|
||||
.Resource("/allNames")
|
||||
.AddQueryParam("seasonNumbers", true)
|
||||
.Build();
|
||||
|
||||
var response = _httpClient.Get<XemResult<Dictionary<int, List<JObject>>>>(request).Resource;
|
||||
|
||||
|
@ -107,7 +107,7 @@ private string DownloadFromWebUrl(RemoteEpisode remoteEpisode, string torrentUrl
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.SeeOther || response.StatusCode == HttpStatusCode.Found)
|
||||
{
|
||||
var locationHeader = (string)response.Headers.GetValueOrDefault("Location", null);
|
||||
var locationHeader = response.Headers.GetSingleValue("Location");
|
||||
|
||||
_logger.Trace("Torrent request is being redirected to: {0}", locationHeader);
|
||||
|
||||
|
@ -63,11 +63,6 @@ public static string ToBestDateString(this DateTime dateTime)
|
||||
return dateTime.ToShortDateString();
|
||||
}
|
||||
|
||||
public static string ParentUriString(this Uri uri)
|
||||
{
|
||||
return uri.AbsoluteUri.Remove(uri.AbsoluteUri.Length - string.Join("", uri.Segments).Length - uri.Query.Length);
|
||||
}
|
||||
|
||||
public static int MaxOrDefault(this IEnumerable<int> ints)
|
||||
{
|
||||
if (ints == null)
|
||||
|
@ -13,9 +13,9 @@ public HttpRequest PreRequest(HttpRequest request)
|
||||
{
|
||||
// torcache behaves strangely when it has query params and/or no Referer or browser User-Agent.
|
||||
// It's a bit vague, and we don't need the query params. So we remove the query params and set a Referer to be safe.
|
||||
if (request.Url.Host == "torcache.net")
|
||||
if (request.UrlBuilder.Host == "torcache.net")
|
||||
{
|
||||
request.UriBuilder.Query = string.Empty;
|
||||
request.UrlBuilder.Query = string.Empty;
|
||||
request.Headers.Add("Referer", request.Url.Scheme + @"://torcache.net/");
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,10 @@ private IEnumerable<IndexerRequest> GetRssRequests()
|
||||
{
|
||||
var request = new IndexerRequest(string.Format("{0}/rss.php?uid={1}&passkey={2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.UserId, Settings.RssPasskey), HttpAccept.Html);
|
||||
|
||||
request.HttpRequest.AddCookie(Settings.Cookie);
|
||||
foreach (var cookie in HttpHeader.ParseCookies(Settings.Cookie))
|
||||
{
|
||||
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
|
||||
}
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
@ -172,14 +172,15 @@ private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, BroadcastheNe
|
||||
parameters = new BroadcastheNetTorrentQuery();
|
||||
}
|
||||
|
||||
var builder = new JsonRpcRequestBuilder(Settings.BaseUrl, "getTorrents", new object[] { Settings.ApiKey, parameters, PageSize, 0 });
|
||||
builder.SupressHttpError = true;
|
||||
var builder = new JsonRpcRequestBuilder(Settings.BaseUrl)
|
||||
.Call("getTorrents", Settings.ApiKey, parameters, PageSize, 0);
|
||||
builder.SuppressHttpError = true;
|
||||
|
||||
for (var page = 0; page < maxPages;page++)
|
||||
{
|
||||
builder.Parameters[3] = page * PageSize;
|
||||
builder.JsonParameters[3] = page * PageSize;
|
||||
|
||||
yield return new IndexerRequest(builder.Build(""));
|
||||
yield return new IndexerRequest(builder.Build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,8 +114,9 @@ private bool TryAddSearchParameters(TorrentQuery query, SearchCriteriaBase searc
|
||||
|
||||
private IEnumerable<IndexerRequest> GetRequest(TorrentQuery query)
|
||||
{
|
||||
var builder = new HttpRequestBuilder(Settings.BaseUrl);
|
||||
var request = builder.Build("/api/torrents");
|
||||
var request = new HttpRequestBuilder(Settings.BaseUrl)
|
||||
.Resource("/api/torrents")
|
||||
.Build();
|
||||
|
||||
request.Method = HttpMethod.POST;
|
||||
const string appJson = "application/json";
|
||||
@ -125,7 +126,7 @@ private IEnumerable<IndexerRequest> GetRequest(TorrentQuery query)
|
||||
query.Username = Settings.Username;
|
||||
query.Passkey = Settings.ApiKey;
|
||||
|
||||
request.Body = query.ToJson();
|
||||
request.SetContent(query.ToJson());
|
||||
|
||||
yield return new IndexerRequest(request);
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ protected virtual IList<ReleaseInfo> FetchReleases(IndexerPageableRequestChain p
|
||||
|
||||
foreach (var request in pageableRequest)
|
||||
{
|
||||
url = request.Url.ToString();
|
||||
url = request.Url.AbsoluteUri;
|
||||
|
||||
var page = FetchPage(request, parser);
|
||||
|
||||
|
@ -27,7 +27,7 @@ protected override bool PreProcess(IndexerResponse indexerResponse)
|
||||
throw new ApiKeyException("Invalid API key");
|
||||
}
|
||||
|
||||
if (!indexerResponse.Request.Url.ToString().Contains("apikey=") && (errorMessage == "Missing parameter" || errorMessage.Contains("apikey")))
|
||||
if (!indexerResponse.Request.Url.AbsoluteUri.Contains("apikey=") && (errorMessage == "Missing parameter" || errorMessage.Contains("apikey")))
|
||||
{
|
||||
throw new ApiKeyException("Indexer requires an API key");
|
||||
}
|
||||
|
@ -75,30 +75,34 @@ public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearc
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string mode, int? tvdbId, string query, params object[] args)
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl)
|
||||
.Resource("/pubapi_v2.php")
|
||||
.Accept(HttpAccept.Json);
|
||||
|
||||
var httpRequest = new HttpRequest(Settings.BaseUrl + "/pubapi_v2.php", HttpAccept.Json);
|
||||
|
||||
httpRequest.AddQueryParam("mode", mode);
|
||||
requestBuilder.AddQueryParam("mode", mode);
|
||||
|
||||
if (tvdbId.HasValue)
|
||||
{
|
||||
httpRequest.AddQueryParam("search_tvdb", tvdbId.Value.ToString());
|
||||
requestBuilder.AddQueryParam("search_tvdb", tvdbId.Value);
|
||||
}
|
||||
|
||||
if (query.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
httpRequest.AddQueryParam("search_string", string.Format(query, args));
|
||||
requestBuilder.AddQueryParam("search_string", string.Format(query, args));
|
||||
}
|
||||
|
||||
if (!Settings.RankedOnly)
|
||||
{
|
||||
httpRequest.AddQueryParam("ranked", "0");
|
||||
requestBuilder.AddQueryParam("ranked", "0");
|
||||
}
|
||||
|
||||
httpRequest.AddQueryParam("category", "18;41");
|
||||
httpRequest.AddQueryParam("limit", "100");
|
||||
httpRequest.AddQueryParam("token", _tokenProvider.GetToken(Settings));
|
||||
httpRequest.AddQueryParam("format", "json_extended");
|
||||
httpRequest.AddQueryParam("app_id", "Sonarr");
|
||||
requestBuilder.AddQueryParam("category", "18;41");
|
||||
requestBuilder.AddQueryParam("limit", "100");
|
||||
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
|
||||
requestBuilder.AddQueryParam("format", "json_extended");
|
||||
requestBuilder.AddQueryParam("app_id", "Sonarr");
|
||||
|
||||
yield return new IndexerRequest(httpRequest);
|
||||
}
|
||||
|
@ -266,18 +266,18 @@ protected virtual string ParseUrl(string value)
|
||||
|
||||
try
|
||||
{
|
||||
var uri = new Uri(value, UriKind.RelativeOrAbsolute);
|
||||
var url = new Uri(value, UriKind.RelativeOrAbsolute);
|
||||
|
||||
if (!uri.IsAbsoluteUri)
|
||||
if (!url.IsAbsoluteUri)
|
||||
{
|
||||
uri = new Uri(_indexerResponse.HttpRequest.Url, uri);
|
||||
url = new Uri(_indexerResponse.HttpRequest.Url, url);
|
||||
}
|
||||
|
||||
return uri.AbsoluteUri;
|
||||
return url.AbsoluteUri;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug(ex, string.Format("Failed to parse Uri {0}, ignoring.", value));
|
||||
_logger.Debug(ex, string.Format("Failed to parse Url {0}, ignoring.", value));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,10 @@ private IEnumerable<IndexerRequest> GetRssRequests(string searchParameters)
|
||||
|
||||
if (Settings.Cookie.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
request.HttpRequest.AddCookie(Settings.Cookie);
|
||||
foreach (var cookie in HttpHeader.ParseCookies(Settings.Cookie))
|
||||
{
|
||||
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
|
||||
}
|
||||
}
|
||||
|
||||
yield return request;
|
||||
|
@ -23,7 +23,7 @@ protected override bool PreProcess(IndexerResponse indexerResponse)
|
||||
|
||||
if (code >= 100 && code <= 199) throw new ApiKeyException("Invalid API key");
|
||||
|
||||
if (!indexerResponse.Request.Url.ToString().Contains("apikey=") && errorMessage == "Missing parameter")
|
||||
if (!indexerResponse.Request.Url.AbsoluteUri.Contains("apikey=") && errorMessage == "Missing parameter")
|
||||
{
|
||||
throw new ApiKeyException("Indexer requires an API key");
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cloud;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
@ -16,20 +17,23 @@ public class SkyHookProxy : IProvideSeriesInfo, ISearchForNewSeries
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly Logger _logger;
|
||||
private readonly HttpRequestBuilder _requestBuilder;
|
||||
|
||||
public SkyHookProxy(IHttpClient httpClient, Logger logger)
|
||||
private readonly IHttpRequestBuilderFactory _requestBuilder;
|
||||
|
||||
public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, Logger logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_requestBuilder = requestBuilder.SkyHookTvdb;
|
||||
_logger = logger;
|
||||
|
||||
_requestBuilder = new HttpRequestBuilder("http://skyhook.sonarr.tv/v1/tvdb/{route}/en/");
|
||||
}
|
||||
|
||||
public Tuple<Series, List<Episode>> GetSeriesInfo(int tvdbSeriesId)
|
||||
{
|
||||
var httpRequest = _requestBuilder.Build(tvdbSeriesId.ToString());
|
||||
httpRequest.AddSegment("route", "shows");
|
||||
var httpRequest = _requestBuilder.Create()
|
||||
.SetSegment("route", "shows")
|
||||
.Resource(tvdbSeriesId.ToString())
|
||||
.Build();
|
||||
|
||||
httpRequest.AllowAutoRedirect = true;
|
||||
httpRequest.SuppressHttpError = true;
|
||||
|
||||
@ -81,9 +85,10 @@ public List<Series> SearchForNewSeries(string title)
|
||||
}
|
||||
|
||||
var term = System.Web.HttpUtility.UrlEncode((title.ToLower().Trim()));
|
||||
var httpRequest = _requestBuilder.Build("?term={term}");
|
||||
httpRequest.AddSegment("route", "search");
|
||||
httpRequest.AddSegment("term", term);
|
||||
var httpRequest = _requestBuilder.Create()
|
||||
.SetSegment("route", "search")
|
||||
.AddQueryParam("term", title.ToLower().Trim())
|
||||
.Build();
|
||||
|
||||
var httpResponse = _httpClient.Get<List<ShowResource>>(httpRequest);
|
||||
|
||||
|
@ -21,15 +21,14 @@ public void Notify(MediaBrowserSettings settings, string title, string message)
|
||||
{
|
||||
var path = "/Notifications/Admin";
|
||||
var request = BuildRequest(path, settings);
|
||||
request.Headers.ContentType = "application/json";
|
||||
|
||||
request.Body = new
|
||||
request.SetContent(new
|
||||
{
|
||||
Name = title,
|
||||
Description = message,
|
||||
ImageUrl = "https://raw.github.com/NzbDrone/NzbDrone/develop/Logo/64.png"
|
||||
}.ToJson();
|
||||
|
||||
request.Headers.ContentType = "application/json";
|
||||
}.ToJson());
|
||||
|
||||
ProcessRequest(request, settings);
|
||||
}
|
||||
@ -58,7 +57,7 @@ private HttpRequest BuildRequest(string path, MediaBrowserSettings settings)
|
||||
{
|
||||
var url = string.Format(@"http://{0}/mediabrowser", settings.Address);
|
||||
|
||||
return new HttpRequestBuilder(url).Build(path);
|
||||
return new HttpRequestBuilder(url).Resource(path).Build();
|
||||
}
|
||||
|
||||
private void CheckForError(HttpResponse response)
|
||||
|
@ -15,20 +15,22 @@ public interface IUpdatePackageProvider
|
||||
public class UpdatePackageProvider : IUpdatePackageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IDroneServicesRequestBuilder _requestBuilder;
|
||||
private readonly IHttpRequestBuilderFactory _requestBuilder;
|
||||
|
||||
public UpdatePackageProvider(IHttpClient httpClient, IDroneServicesRequestBuilder requestBuilder)
|
||||
public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_requestBuilder = requestBuilder;
|
||||
_requestBuilder = requestBuilder.Services;
|
||||
}
|
||||
|
||||
public UpdatePackage GetLatestUpdate(string branch, Version currentVersion)
|
||||
{
|
||||
var request = _requestBuilder.Build("/update/{branch}");
|
||||
request.UriBuilder.SetQueryParam("version", currentVersion);
|
||||
request.UriBuilder.SetQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant());
|
||||
request.AddSegment("branch", branch);
|
||||
var request = _requestBuilder.Create()
|
||||
.Resource("/update/{branch}")
|
||||
.AddQueryParam("version", currentVersion)
|
||||
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
|
||||
.SetSegment("branch", branch)
|
||||
.Build();
|
||||
|
||||
var update = _httpClient.Get<UpdatePackageAvailable>(request).Resource;
|
||||
|
||||
@ -39,10 +41,12 @@ public UpdatePackage GetLatestUpdate(string branch, Version currentVersion)
|
||||
|
||||
public List<UpdatePackage> GetRecentUpdates(string branch, Version currentVersion)
|
||||
{
|
||||
var request = _requestBuilder.Build("/update/{branch}/changes");
|
||||
request.UriBuilder.SetQueryParam("version", currentVersion);
|
||||
request.UriBuilder.SetQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant());
|
||||
request.AddSegment("branch", branch);
|
||||
var request = _requestBuilder.Create()
|
||||
.Resource("/update/{branch}/changes")
|
||||
.AddQueryParam("version", currentVersion)
|
||||
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
|
||||
.SetSegment("branch", branch)
|
||||
.Build();
|
||||
|
||||
var updates = _httpClient.Get<List<UpdatePackage>>(request);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user