Fix of work item 4050: push does not follow redirect.

This commit is contained in:
feiling 2014-03-06 17:19:09 -08:00
Родитель 6c62b543c7
Коммит 2cda345ffd
3 изменённых файлов: 84 добавлений и 24 удалений

11
src/Core/Resources/NuGetResources.Designer.cs сгенерированный
Просмотреть файл

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.34003 // Runtime Version:4.0.30319.34011
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@ -285,6 +285,15 @@ namespace NuGet.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Too many automatic redirections were attempted..
/// </summary>
public static string Error_TooManyRedirections {
get {
return ResourceManager.GetString("Error_TooManyRedirections", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to An error occurred while loading packages from &apos;{0}&apos;: {1}. /// Looks up a localized string similar to An error occurred while loading packages from &apos;{0}&apos;: {1}.
/// </summary> /// </summary>

Просмотреть файл

@ -469,4 +469,7 @@
<data name="Log_UninstallPackageFromProject" xml:space="preserve"> <data name="Log_UninstallPackageFromProject" xml:space="preserve">
<value>Remove '{0}' from project {1}.</value> <value>Remove '{0}' from project {1}.</value>
</data> </data>
<data name="Error_TooManyRedirections" xml:space="preserve">
<value>Too many automatic redirections were attempted.</value>
</data>
</root> </root>

Просмотреть файл

@ -10,8 +10,9 @@ namespace NuGet
{ {
private const string ServiceEndpoint = "/api/v2/package"; private const string ServiceEndpoint = "/api/v2/package";
private const string ApiKeyHeader = "X-NuGet-ApiKey"; private const string ApiKeyHeader = "X-NuGet-ApiKey";
private const int MaxRediretionCount = 20;
private readonly Lazy<Uri> _baseUri; private Lazy<Uri> _baseUri;
private readonly string _source; private readonly string _source;
private readonly string _userAgent; private readonly string _userAgent;
@ -79,34 +80,50 @@ namespace NuGet
long packageSize, long packageSize,
int timeout) int timeout)
{ {
HttpClient client = GetClient("", "PUT", "application/octet-stream"); int redirectionCount = 0;
while (true)
client.SendingRequest += (sender, e) =>
{ {
SendingRequest(this, e); HttpClient client = GetClient("", "PUT", "application/octet-stream");
var request = (HttpWebRequest)e.Request;
request.AllowWriteStreamBuffering = false;
// Set the timeout client.SendingRequest += (sender, e) =>
if (timeout <= 0)
{ {
timeout = request.ReadWriteTimeout; // Default to 5 minutes if the value is invalid. SendingRequest(this, e);
var request = (HttpWebRequest)e.Request;
request.AllowWriteStreamBuffering = false;
// Set the timeout
if (timeout <= 0)
{
timeout = request.ReadWriteTimeout; // Default to 5 minutes if the value is invalid.
}
request.Timeout = timeout;
request.ReadWriteTimeout = timeout;
if (!String.IsNullOrEmpty(apiKey))
{
request.Headers.Add(ApiKeyHeader, apiKey);
}
var multiPartRequest = new MultipartWebRequest();
multiPartRequest.AddFile(packageStreamFactory, "package", packageSize);
multiPartRequest.CreateMultipartRequest(request);
};
// Since AllowWriteStreamBuffering is set to false, redirection will not be handled
// automatically by HttpWebRequest. So we need to check redirect status code and
// update _baseUri and retry if redirection happens.
if (EnsureSuccessfulResponse(client))
{
return;
} }
request.Timeout = timeout; ++redirectionCount;
request.ReadWriteTimeout = timeout; if (redirectionCount > MaxRediretionCount)
if (!String.IsNullOrEmpty(apiKey))
{ {
request.Headers.Add(ApiKeyHeader, apiKey); throw new WebException(NuGetResources.Error_TooManyRedirections);
} }
}
var multiPartRequest = new MultipartWebRequest();
multiPartRequest.AddFile(packageStreamFactory, "package", packageSize);
multiPartRequest.CreateMultipartRequest(request);
};
EnsureSuccessfulResponse(client);
} }
/// <summary> /// <summary>
@ -214,7 +231,15 @@ namespace NuGet
return requestUri; return requestUri;
} }
private static void EnsureSuccessfulResponse(HttpClient client, HttpStatusCode? expectedStatusCode = null) /// <summary>
/// Ensures that success response is received.
/// </summary>
/// <param name="client">The client that is making the request.</param>
/// <param name="expectedStatusCode">The exected status code.</param>
/// <returns>True if success response is received; false if redirection response is received.
/// In this case, _baseUri will be updated to be the new redirected Uri and the requrest
/// should be retried.</returns>
private bool EnsureSuccessfulResponse(HttpClient client, HttpStatusCode? expectedStatusCode = null)
{ {
HttpWebResponse response = null; HttpWebResponse response = null;
try try
@ -229,6 +254,8 @@ namespace NuGet
{ {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.PackageServerError, response.StatusDescription, String.Empty)); throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.PackageServerError, response.StatusDescription, String.Empty));
} }
return true;
} }
catch (WebException e) catch (WebException e)
{ {
@ -237,10 +264,31 @@ namespace NuGet
throw; throw;
} }
response = (HttpWebResponse)e.Response; response = (HttpWebResponse)e.Response;
// Check if the error is caused by redirection
if (response.StatusCode == HttpStatusCode.MultipleChoices ||
response.StatusCode == HttpStatusCode.MovedPermanently ||
response.StatusCode == HttpStatusCode.Found ||
response.StatusCode == HttpStatusCode.SeeOther ||
response.StatusCode == HttpStatusCode.TemporaryRedirect)
{
var location = response.Headers["Location"];
Uri newUri;
if (!Uri.TryCreate(client.Uri, location, out newUri))
{
throw;
}
_baseUri = new Lazy<Uri>(() => newUri);
return false;
}
if (expectedStatusCode != response.StatusCode) if (expectedStatusCode != response.StatusCode)
{ {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.PackageServerError, response.StatusDescription, e.Message), e); throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.PackageServerError, response.StatusDescription, e.Message), e);
} }
return true;
} }
finally finally
{ {