mirror of https://github.com/Radarr/Radarr
Fixed: Stream leakage inside CurlHttpDispatcher
This commit is contained in:
parent
d02d71c336
commit
899bd086ec
|
@ -66,95 +66,96 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||||
|
|
||||||
lock (CurlGlobalHandle.Instance)
|
lock (CurlGlobalHandle.Instance)
|
||||||
{
|
{
|
||||||
Stream responseStream = new MemoryStream();
|
using (Stream responseStream = new MemoryStream())
|
||||||
Stream headerStream = new MemoryStream();
|
using (Stream headerStream = new MemoryStream())
|
||||||
|
|
||||||
using (var curlEasy = new CurlEasy())
|
|
||||||
{
|
{
|
||||||
curlEasy.AutoReferer = false;
|
using (var curlEasy = new CurlEasy())
|
||||||
curlEasy.WriteFunction = (b, s, n, o) =>
|
|
||||||
{
|
{
|
||||||
responseStream.Write(b, 0, s * n);
|
curlEasy.AutoReferer = false;
|
||||||
return s * n;
|
curlEasy.WriteFunction = (b, s, n, o) =>
|
||||||
};
|
|
||||||
curlEasy.HeaderFunction = (b, s, n, o) =>
|
|
||||||
{
|
|
||||||
headerStream.Write(b, 0, s * n);
|
|
||||||
return s * n;
|
|
||||||
};
|
|
||||||
|
|
||||||
AddProxy(curlEasy, request);
|
|
||||||
|
|
||||||
curlEasy.Url = request.Url.FullUri;
|
|
||||||
|
|
||||||
switch (request.Method)
|
|
||||||
{
|
|
||||||
case HttpMethod.GET:
|
|
||||||
curlEasy.HttpGet = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HttpMethod.POST:
|
|
||||||
curlEasy.Post = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HttpMethod.PUT:
|
|
||||||
curlEasy.Put = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException(string.Format("HttpCurl method {0} not supported", request.Method));
|
|
||||||
}
|
|
||||||
curlEasy.FollowLocation = false;
|
|
||||||
curlEasy.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; ;
|
|
||||||
|
|
||||||
if (request.RequestTimeout != TimeSpan.Zero)
|
|
||||||
{
|
|
||||||
curlEasy.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OsInfo.IsWindows)
|
|
||||||
{
|
|
||||||
curlEasy.CaInfo = _caBundleFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cookies != null)
|
|
||||||
{
|
|
||||||
curlEasy.Cookie = cookies.GetCookieHeader((Uri)request.Url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.ContentData != null)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
using (var httpRequestHeaders = SerializeHeaders(request))
|
|
||||||
{
|
|
||||||
curlEasy.HttpHeader = httpRequestHeaders;
|
|
||||||
|
|
||||||
var result = curlEasy.Perform();
|
|
||||||
|
|
||||||
if (result != CurlCode.Ok)
|
|
||||||
{
|
{
|
||||||
switch (result)
|
responseStream.Write(b, 0, s * n);
|
||||||
|
return s * n;
|
||||||
|
};
|
||||||
|
curlEasy.HeaderFunction = (b, s, n, o) =>
|
||||||
|
{
|
||||||
|
headerStream.Write(b, 0, s * n);
|
||||||
|
return s * n;
|
||||||
|
};
|
||||||
|
|
||||||
|
AddProxy(curlEasy, request);
|
||||||
|
|
||||||
|
curlEasy.Url = request.Url.FullUri;
|
||||||
|
|
||||||
|
switch (request.Method)
|
||||||
|
{
|
||||||
|
case HttpMethod.GET:
|
||||||
|
curlEasy.HttpGet = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HttpMethod.POST:
|
||||||
|
curlEasy.Post = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HttpMethod.PUT:
|
||||||
|
curlEasy.Put = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException(string.Format("HttpCurl method {0} not supported", request.Method));
|
||||||
|
}
|
||||||
|
curlEasy.FollowLocation = false;
|
||||||
|
curlEasy.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; ;
|
||||||
|
|
||||||
|
if (request.RequestTimeout != TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
curlEasy.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OsInfo.IsWindows)
|
||||||
|
{
|
||||||
|
curlEasy.CaInfo = _caBundleFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cookies != null)
|
||||||
|
{
|
||||||
|
curlEasy.Cookie = cookies.GetCookieHeader((Uri)request.Url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.ContentData != null)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
using (var httpRequestHeaders = SerializeHeaders(request))
|
||||||
|
{
|
||||||
|
curlEasy.HttpHeader = httpRequestHeaders;
|
||||||
|
|
||||||
|
var result = curlEasy.Perform();
|
||||||
|
|
||||||
|
if (result != CurlCode.Ok)
|
||||||
{
|
{
|
||||||
case CurlCode.SslCaCert:
|
switch (result)
|
||||||
case (CurlCode)77:
|
{
|
||||||
throw new WebException(string.Format("Curl Error {0} for Url {1}, issues with your operating system SSL Root Certificate Bundle (ca-bundle).", result, curlEasy.Url));
|
case CurlCode.SslCaCert:
|
||||||
default:
|
case (CurlCode)77:
|
||||||
throw new WebException(string.Format("Curl Error {0} for Url {1}", result, curlEasy.Url));
|
throw new WebException(string.Format("Curl Error {0} for Url {1}, issues with your operating system SSL Root Certificate Bundle (ca-bundle).", result, curlEasy.Url));
|
||||||
|
default:
|
||||||
|
throw new WebException(string.Format("Curl Error {0} for Url {1}", result, curlEasy.Url));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var webHeaderCollection = ProcessHeaderStream(request, cookies, headerStream);
|
||||||
|
var responseData = ProcessResponseStream(request, responseStream, webHeaderCollection);
|
||||||
|
|
||||||
|
var httpHeader = new HttpHeader(webHeaderCollection);
|
||||||
|
|
||||||
|
return new HttpResponse(request, httpHeader, responseData, (HttpStatusCode)curlEasy.ResponseCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
var webHeaderCollection = ProcessHeaderStream(request, cookies, headerStream);
|
|
||||||
var responseData = ProcessResponseStream(request, responseStream, webHeaderCollection);
|
|
||||||
|
|
||||||
var httpHeader = new HttpHeader(webHeaderCollection);
|
|
||||||
|
|
||||||
return new HttpResponse(request, httpHeader, responseData, (HttpStatusCode)curlEasy.ResponseCode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,6 +260,7 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||||
|
|
||||||
private byte[] ProcessResponseStream(HttpRequest request, Stream responseStream, WebHeaderCollection webHeaderCollection)
|
private byte[] ProcessResponseStream(HttpRequest request, Stream responseStream, WebHeaderCollection webHeaderCollection)
|
||||||
{
|
{
|
||||||
|
byte[] bytes = null;
|
||||||
responseStream.Position = 0;
|
responseStream.Position = 0;
|
||||||
|
|
||||||
if (responseStream.Length != 0)
|
if (responseStream.Length != 0)
|
||||||
|
@ -268,21 +270,27 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||||
{
|
{
|
||||||
if (encoding.IndexOf("gzip") != -1)
|
if (encoding.IndexOf("gzip") != -1)
|
||||||
{
|
{
|
||||||
responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
|
using (var zipStream = new GZipStream(responseStream, CompressionMode.Decompress))
|
||||||
|
{
|
||||||
|
bytes = zipStream.ToBytes();
|
||||||
|
}
|
||||||
|
|
||||||
webHeaderCollection.Remove("Content-Encoding");
|
webHeaderCollection.Remove("Content-Encoding");
|
||||||
}
|
}
|
||||||
else if (encoding.IndexOf("deflate") != -1)
|
else if (encoding.IndexOf("deflate") != -1)
|
||||||
{
|
{
|
||||||
responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);
|
using (var deflateStream = new DeflateStream(responseStream, CompressionMode.Decompress))
|
||||||
|
{
|
||||||
|
bytes = deflateStream.ToBytes();
|
||||||
|
}
|
||||||
|
|
||||||
webHeaderCollection.Remove("Content-Encoding");
|
webHeaderCollection.Remove("Content-Encoding");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseStream.ToBytes();
|
if (bytes == null) bytes = responseStream.ToBytes();
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue