I'm experiencing a weird issue with both of these commands:
nuget.exe push -Source <url> -ApiKey <key> <package-file>
dotnet nuget push -s <url> -k <key> <package-file>
The source NuGet server is a private BaGetter service. Both commands fail, because the HTTP PUT request that they issue to the server arrives with the following headers and no body:
Content-Length: 0
Content-Type: multipart/form-data; boundary="<random-guid>"
I've confirmed this by temporarily plugging a dummy handler in place of BaGetter that only logs the headers and body.
What's interesting is that a raw Postman HTTP PUT request works fine and the package arrives as expected. However, the headers then look like this:
Content-Length: 1695506
Content-Type: application/octet-stream
What am I missing with the original nuget push commands?
FWIW: The BaGetter server is behind a Cloudflare tunnel and is not exposed directly to the internet.
UPDATE
I tried the following:
- disabling HSTS requirements on Cloudflare for the specific domain where my Bagetter service is hosted
- lowering TLS requirement all the way down to 1.0
Both to no avail.
As suggested by @zivkan, I even tried making my own simple C# Console app with HttpClient. It worked without a problem, as expected. I still have no idea why nuget.exe and dotnet nuget push commands keep failing.
Here's my app's code in its entirety:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace FauxNuGetClient
{
public class Program
{
public static async Task<int> Main(string[] args)
{
if (args == null || args.Length == 0 || !String.Equals(args[0], "push", StringComparison.OrdinalIgnoreCase))
{
Console.Error.WriteLine("Invalid args. Only 'push' is supported.");
return -1;
}
var pairs = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
string pendingKey = null;
string package = null;
for (var i = 1; i < args.Length; i++)
{
if (pendingKey != null)
{
pairs[pendingKey] = args[i];
pendingKey = null;
continue;
}
switch (args[i].ToLowerInvariant())
{
case "-source":
case "-apikey":
case "-verbosity":
{
pendingKey = args[i].TrimStart('-');
continue;
}
}
if (i == 1 || i == args.Length - 1)
{
package = args[i];
continue;
}
Console.Error.WriteLine("Invalid args. The 'push' command only recognizes -Source, -ApiKey, and -Verbosity parameters.");
return -2;
}
if (String.IsNullOrEmpty(package) || !pairs.TryGetValue("source", out var url) || !Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
Console.Error.WriteLine("Invalid args. The 'push' command requires -Source parameter that contains a valid absolute URL.");
return -3;
}
if (!File.Exists(package))
{
Console.Error.WriteLine("Invalid args. The 'push' command requires an existing local file name.");
return -4;
}
try
{
var uploadUrl = uri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped).TrimEnd('/') + "/api/v2/package/";
if (!Uri.TryCreate(uploadUrl, UriKind.Absolute, out uri))
{
Console.Error.WriteLine("Invalid args. Unable to reparse the URI.");
return -5;
}
using (var client = new HttpClient
{
BaseAddress = uri,
Timeout = TimeSpan.FromSeconds(45)
})
{
Console.WriteLine("PUT " + uri.ToString());
using (var fileStream = new FileStream(package, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var requestContent = new MultipartFormDataContent();
var packageContent = new StreamContent(fileStream);
packageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
requestContent.Add(packageContent, "package", "package.nupkg");
if (pairs.TryGetValue("apikey", out var apiKey) && !String.IsNullOrWhiteSpace(apiKey))
{
requestContent.Headers.Add("X-NuGet-ApiKey", apiKey.Trim());
}
using (var response = await client.PutAsync("", requestContent))
{
if (response.IsSuccessStatusCode)
{
Console.WriteLine("OK.");
return 0;
}
Console.WriteLine("Failed. Status code: " + response.StatusCode.ToString());
return -6;
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Failed. Exception: " + e.Message);
return -7;
}
}
}
}
HttpClient. Try writing your own simple console app that usesHttpClientto post or put to the server, to see if it's something nuget is doing specifically, or if .net's httpclient is doing it. github.com/NuGet/NuGet.Client/blob/…