Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/CD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ jobs:
src/CHttpExecutor/bin/Release/${{ env.GH_PACKAGE_VERSION }}/linux-x64/publish/chttpexec-linux-x64
- name: Build VSCodeExtension dependencies
run: |
dotnet publish src/CHttpExtension -r linux-x64 -f net10.0
dotnet publish src/CHttpExtension -r linux-x64 -f net9.0 # .NET9.0
- name: Upload CHttpExtension file to artifacts (linux-x64)
uses: actions/upload-artifact@v7
with:
name: CHttpExtension-linux-x64 # The name of the artifact bundle
path: src/CHttpExtension/bin/Release/net10.0/linux-x64/publish/*
path: src/CHttpExtension/bin/Release/net9.0/linux-x64/publish/*

cross-compile-linux-aot:
runs-on: ubuntu-26.04-arm
Expand All @@ -110,12 +110,12 @@ jobs:
run: echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
- name: Build VSCodeExtension dependencies
run: |
dotnet publish src/CHttpExtension -r linux-arm64 -f net10.0
dotnet publish src/CHttpExtension -r linux-arm64 -f net9.0 # .NET9.0
- name: Upload CHttpExtension file to artifacts (linux-arm64)
uses: actions/upload-artifact@v7
with:
name: CHttpExtension-linux-arm64 # The name of the artifact bundle
path: src/CHttpExtension/bin/Release/net10.0/linux-arm64/publish/*
path: src/CHttpExtension/bin/Release/net9.0/linux-arm64/publish/*

cross-compile-windows-aot:
runs-on: windows-latest
Expand Down Expand Up @@ -144,18 +144,18 @@ jobs:
src/CHttp/bin/Release/${{ env.GH_PACKAGE_VERSION }}/win-arm64/publish/chttp-win-arm64-aot.exe
- name: Build VSCodeExtension dependencies
run: |
dotnet publish src/CHttpExtension -r win-x64 -f net10.0
dotnet publish src/CHttpExtension -r win-arm64 -f net10.0
dotnet publish src/CHttpExtension -r win-x64 -f net9.0 # .NET9.0
dotnet publish src/CHttpExtension -r win-arm64 -f net9.0 # .NET9.0
- name: Upload CHttpExtension file to artifacts (win-x64)
uses: actions/upload-artifact@v7
with:
name: CHttpExtension-win-x64 # The name of the artifact bundle
path: src/CHttpExtension/bin/Release/net10.0/win-x64/publish/*
path: src/CHttpExtension/bin/Release/net9.0/win-x64/publish/*
- name: Upload CHttpExtension file to artifacts (win-arm64)
uses: actions/upload-artifact@v7
with:
name: CHttpExtension-win-arm64 # The name of the artifact bundle
path: src/CHttpExtension/bin/Release/net10.0/win-arm64/publish/*
path: src/CHttpExtension/bin/Release/net9.0/win-arm64/publish/*

vscodeextension-linux-x64:
runs-on: ubuntu-latest
Expand Down
40 changes: 21 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,27 @@ Description:
Send HTTP request

Usage:
CHttp [command] [options]
chttp [command] [options]

Options:
-?, -h, --help Show help and usage information
--version Show version information
-v, --http-version <1.0|1.1|2|3> The version of the HTTP request: 1.0, 1.1, 2, 3 [default:
3.0]
-v, --http-version <1.0|1.1|2|3> The version of the HTTP request: 1.0, 1.1, 2, 3 [default: 3.0]
-m, --method <CONNECT|DELETE|GET|HEAD|OPTIONS|POST|PUT|TRACE> HTTP Method [default: GET]
-h, --header Headers Key-Value pairs separated by ':'. For example --header="key:myvalue" []
-t, --timeout Timeout in seconds. [default: 30]
--no-redirects Disables following redirects on requests [default: False]
--no-cert-validation, --no-certificate-validation Disables certificate validation [default: False]
-h, --header <header> Headers Key-Value pairs separated by ':'. For example --header="key:myvalue"
-t, --timeout <timeout> Timeout in seconds. [default: 30]
--no-redirects Disables following redirects on requests
--no-cert-validation, --no-certificate-validation Disables certificate validation
-l, --log <Normal|Quiet|Silent|Verbose> Level of logging details. [default: Verbose]
-o, --output Output to file.
--cookie-container A file to share cookies among requests.
-b, --body Request body or a file path containing the request
-u, --uri (REQUIRED) The URL of the resource
--upload-throttle Specify HTTP level throttling in kbyte/sec when sending the request []
-k, --kerberos-auth Use Kerberos Auth [default: False]
-o, --output <output> Output to file.
--cookie-container <cookie-container> A file to share cookies among requests.
--clientCertificatePath <clientCertificatePath> A PEM file containing the public key of the client certificate for mTLS authentication.
--clientCertificateKeyPath <clientCertificateKeyPath> A PEM file containing the private key of the client certificate for mTLS authentication.
-b, --body <body> Request body or a file path containing the request
-u, --uri <uri> (REQUIRED) The URL of the resource
--upload-throttle <upload-throttle> Specify HTTP level throttling in kbyte/sec when sending the request
-k, --kerberos-auth Use Kerberos Auth
--decompressResponse Automatically decompress response.
-?, -h, --help Show help and usage information
--version Show version information

Commands:
forms Forms request
Expand Down Expand Up @@ -302,10 +304,10 @@ Run the following commands to publish the native dependencis of the VS Code Exte
For this use that latest .NET major version:

```$
dotnet publish src/CHttpExtension -r win-x64 -f net10.0
cp ./src/CHttpExtension/bin/Release/net10.0/win-x64/publish/* ./src/VSCodeExt/src/chttp-win32-x64
dotnet publish src/CHttpExtension -r linux-x64 -f net10.0
cp ./src/CHttpExtension/bin/Release/net10.0/linux-x64/publish/* ./src/VSCodeExt/src/chttp-linux-x64
dotnet publish src/CHttpExtension -r win-x64 -f net9.0
cp ./src/CHttpExtension/bin/Release/net9.0/win-x64/publish/* ./src/VSCodeExt/src/chttp-win32-x64
dotnet publish src/CHttpExtension -r linux-x64 -f net9.0
cp ./src/CHttpExtension/bin/Release/net9.0/linux-x64/publish/* ./src/VSCodeExt/src/chttp-linux-x64
```

### Cleanup NPM
Expand Down
2 changes: 1 addition & 1 deletion src/CHttp.Api/CHttp.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="11.0.0-preview.6.26359.118" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="11.0.0-preview.7.26381.103" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.17.0" />
</ItemGroup>

Expand Down
32 changes: 30 additions & 2 deletions src/CHttp/Binders/HttpBehaviorBinder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.CommandLine;
using System.Security.Cryptography.X509Certificates;
using CHttp.Http;

namespace CHttp.Binders;
Expand All @@ -9,14 +10,18 @@ internal sealed class HttpBehaviorBinder(
Option<double> timeout,
Option<FileInfo?> cookieContainerOption,
Option<bool> kerberosAuthOption,
Option<bool> decompressResponse)
Option<bool> decompressResponse,
Option<FileInfo?> clientCertificatePath,
Option<FileInfo?> clientCertificateKeyPath)
{
private readonly Option<bool> _redirectBinder = redirectBinder;
private readonly Option<bool> _validateCertificateValidationBinder = validateCertificateValidationBinder;
private readonly Option<double> _timeoutOption = timeout;
private readonly Option<FileInfo?> _cookieContainerOption = cookieContainerOption;
private readonly Option<bool> _kerberosAuthOption = kerberosAuthOption;
private readonly Option<bool> _decompressResponse = decompressResponse;
private readonly Option<FileInfo?> _clientCertificatePath = clientCertificatePath;
private readonly Option<FileInfo?> _clientCertificateKeyPath = clientCertificateKeyPath;

internal HttpBehavior Bind(ParseResult parseResult)
{
Expand All @@ -26,6 +31,29 @@ internal HttpBehavior Bind(ParseResult parseResult)
var cookieContainer = parseResult.GetValue(_cookieContainerOption)?.FullName ?? string.Empty;
var kerberosAuth = parseResult.GetValue(_kerberosAuthOption);
var decompressResponse = parseResult.GetValue(_decompressResponse);
return new HttpBehavior(timeout, ToUtf8: true, cookieContainer, new SocketBehavior(redirects, enableCertificateValidation, kerberosAuth, 1, decompressResponse));
var clientCertificatePath = parseResult.GetValue(_clientCertificatePath)?.FullName ?? string.Empty;
X509Certificate2? clientCertificate = null;

if (!string.IsNullOrWhiteSpace(clientCertificatePath))
{
if (Path.GetExtension(clientCertificatePath) == ".pfx")
clientCertificate = X509CertificateLoader.LoadPkcs12FromFile(clientCertificatePath, parseResult.GetValue(_clientCertificateKeyPath)?.Name); // Handle KeyPath as a password as opposed file.
else
{
clientCertificate = X509Certificate2.CreateFromPemFile(clientCertificatePath, parseResult.GetValue(_clientCertificateKeyPath)?.FullName);
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
#if NET10_0_OR_GREATER
var exported = clientCertificate.ExportPkcs12(Pkcs12ExportPbeParameters.Default, null);
#else
var exported = clientCertificate.Export(X509ContentType.Pkcs12);
#endif
clientCertificate = X509CertificateLoader.LoadPkcs12(exported, null);
}
}
}

return new HttpBehavior(timeout, ToUtf8: true, cookieContainer,
new SocketBehavior(redirects, enableCertificateValidation, kerberosAuth, 1, decompressResponse, clientCertificate));
}
}
4 changes: 2 additions & 2 deletions src/CHttp/CHttp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0;net11.0</TargetFrameworks>
<TargetFrameworks>net9.0;net10.0;net11.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackAsTool>true</PackAsTool>
Expand All @@ -19,7 +19,7 @@

<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.17.0" />
<PackageReference Include="System.CommandLine" Version="3.0.0-preview.6.26359.118" />
<PackageReference Include="System.CommandLine" Version="3.0.0-preview.7.26381.103" />
</ItemGroup>

<ItemGroup>
Expand Down
38 changes: 32 additions & 6 deletions src/CHttp/CommandFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,17 @@ public static Command CreateRootCommand(
Required = false,
};

var clientCertPathOption = new Option<FileInfo?>(name: "--clientCertificatePath")
{
Description = "A PEM file containing the public key of the client certificate for mTLS authentication.",
Required = false,
};
var clientCertKeyPathOption = new Option<FileInfo?>(name: "--clientCertificateKeyPath")
{
Description = "A PEM file containing the private key of the client certificate for mTLS authentication.",
Required = false,
};

var rootCommand = new RootCommand("Send HTTP request");

// Only applies to the Root command.
Expand All @@ -245,11 +256,11 @@ public static Command CreateRootCommand(
//rootCommand.Options.Add(uploadThrottleOption);
//rootCommand.Options.Add(kerberosAuthOption);

CreateFormsCommand(writer, fileSystem, versionOptions, methodOptions, headerOptions, formsOptions, timeoutOption, redirectOption, validateCertificateOption, uriOption, logOption, outputFileOption, cookieContainer, kerberosAuthOption, decompressResponseOption, rootCommand);
CreateFormsCommand(writer, fileSystem, versionOptions, methodOptions, headerOptions, formsOptions, timeoutOption, redirectOption, validateCertificateOption, uriOption, logOption, outputFileOption, cookieContainer, kerberosAuthOption, decompressResponseOption, clientCertPathOption, clientCertKeyPathOption, rootCommand);

CreateDefaultCommand(writer, fileSystem, versionOptions, methodOptions, headerOptions, bodyOptions, timeoutOption, redirectOption, validateCertificateOption, uriOption, logOption, outputFileOption, cookieContainer, uploadThrottleOption, kerberosAuthOption, decompressResponseOption, rootCommand);
CreateDefaultCommand(writer, fileSystem, versionOptions, methodOptions, headerOptions, bodyOptions, timeoutOption, redirectOption, validateCertificateOption, uriOption, logOption, outputFileOption, cookieContainer, uploadThrottleOption, kerberosAuthOption, decompressResponseOption, clientCertPathOption, clientCertKeyPathOption, rootCommand);

CreateMeasureCommand(console, fileSystem, versionOptions, methodOptions, headerOptions, bodyOptions, timeoutOption, redirectOption, validateCertificateOption, uriOption, nOption, cOption, outputFileOption, metricsOption, cookieContainer, kerberosAuthOption, shareSocketsHandlerOption, decompressResponseOption, rootCommand);
CreateMeasureCommand(console, fileSystem, versionOptions, methodOptions, headerOptions, bodyOptions, timeoutOption, redirectOption, validateCertificateOption, uriOption, nOption, cOption, outputFileOption, metricsOption, cookieContainer, kerberosAuthOption, shareSocketsHandlerOption, decompressResponseOption, clientCertPathOption, clientCertKeyPathOption, rootCommand);

CreateDiffCommand(console, fileSystem, diffFileOption, rootCommand);

Expand All @@ -271,6 +282,8 @@ private static void CreateFormsCommand(IWriter? writer,
Option<FileInfo?> cookieContainerOption,
Option<bool> kerberosAuthOption,
Option<bool> decompressResponseOption,
Option<FileInfo?> clientCertificatePathOption,
Option<FileInfo?> clientCertificateKeyPathOption,
RootCommand rootCommand)
{
var formsCommand = new Command("forms", "Forms request");
Expand All @@ -285,6 +298,8 @@ private static void CreateFormsCommand(IWriter? writer,
formsCommand.Options.Add(logOption);
formsCommand.Options.Add(outputFileOption);
formsCommand.Options.Add(cookieContainerOption);
formsCommand.Options.Add(clientCertificatePathOption);
formsCommand.Options.Add(clientCertificateKeyPathOption);

// Specific options
formsCommand.Options.Add(formsOptions);
Expand All @@ -293,7 +308,8 @@ private static void CreateFormsCommand(IWriter? writer,
formsCommand.SetAction(async (parseResult, cancellationToken) =>
{
var outputBehavior = new OutputBehaviorBinder(logOption, outputFileOption).Bind(parseResult);
var httpBehavior = new HttpBehaviorBinder(redirectOption, validateCertificateOption, timeoutOption, cookieContainerOption, kerberosAuthOption, decompressResponseOption).Bind(parseResult);
var httpBehavior = new HttpBehaviorBinder(redirectOption, validateCertificateOption, timeoutOption, cookieContainerOption,
kerberosAuthOption, decompressResponseOption, clientCertificatePathOption, clientCertificateKeyPathOption).Bind(parseResult);
writer ??= new WriterStrategy(outputBehavior);
var cookieContainer = new PersistentCookieContainer(fileSystem ??= new FileSystem(), httpBehavior.CookieContainer);
var client = new HttpMessageSender(writer, cookieContainer, new SingleSocketsHandlerProvider(), httpBehavior);
Expand Down Expand Up @@ -323,6 +339,8 @@ private static void CreateDefaultCommand(IWriter? writer,
Option<int?> uploadThrottleOption,
Option<bool> kerberosAuthOption,
Option<bool> decompressResponseOption,
Option<FileInfo?> clientCertificatePathOption,
Option<FileInfo?> clientCertificateKeyPathOption,
RootCommand rootCommand)
{
// Shared options
Expand All @@ -335,6 +353,8 @@ private static void CreateDefaultCommand(IWriter? writer,
rootCommand.Options.Add(logOption);
rootCommand.Options.Add(outputFileOption);
rootCommand.Options.Add(cookieContainerOption);
rootCommand.Options.Add(clientCertificatePathOption);
rootCommand.Options.Add(clientCertificateKeyPathOption);

// Specific options
rootCommand.Options.Add(bodyOptions);
Expand All @@ -345,7 +365,8 @@ private static void CreateDefaultCommand(IWriter? writer,
rootCommand.SetAction(async (parseResult, cancellationToken) =>
{
var outputBehavior = new OutputBehaviorBinder(logOption, outputFileOption).Bind(parseResult);
var httpBehavior = new HttpBehaviorBinder(redirectOption, validateCertificateOption, timeoutOption, cookieContainerOption, kerberosAuthOption, decompressResponseOption).Bind(parseResult);
var httpBehavior = new HttpBehaviorBinder(redirectOption, validateCertificateOption, timeoutOption, cookieContainerOption,
kerberosAuthOption, decompressResponseOption, clientCertificatePathOption, clientCertificateKeyPathOption).Bind(parseResult);
var requestDetails = new HttpRequestDetailsBinder(methodOptions, uriOption, versionOptions, headerOptions).Bind(parseResult);
var body = parseResult.GetValue(bodyOptions);
var uploadThrottle = parseResult.GetValue(uploadThrottleOption);
Expand Down Expand Up @@ -382,6 +403,8 @@ private static void CreateMeasureCommand(IConsole? console,
Option<bool> kerberosAuthOption,
Option<bool> decompressResponseOption,
Option<bool> shareSocketsHandlerOption,
Option<FileInfo?> clientCertificatePathOption,
Option<FileInfo?> clientCertificateKeyPathOption,
RootCommand rootCommand)
{
var perfCommand = new Command("perf", "Performance Measure");
Expand All @@ -396,6 +419,8 @@ private static void CreateMeasureCommand(IConsole? console,
perfCommand.Options.Add(outputFileOption);
perfCommand.Options.Add(cookieContainerOption);
perfCommand.Options.Add(kerberosAuthOption);
perfCommand.Options.Add(clientCertificatePathOption);
perfCommand.Options.Add(clientCertificateKeyPathOption);

// Specific options
perfCommand.Options.Add(nOption);
Expand All @@ -407,7 +432,8 @@ private static void CreateMeasureCommand(IConsole? console,
rootCommand.Add(perfCommand);
perfCommand.SetAction(async (parseResult, cancellationToken) =>
{
var httpBehavior = new HttpBehaviorBinder(redirectOption, validateCertificateOption, timeoutOption, cookieContainerOption, kerberosAuthOption, decompressResponseOption).Bind(parseResult);
var httpBehavior = new HttpBehaviorBinder(redirectOption, validateCertificateOption, timeoutOption, cookieContainerOption,
kerberosAuthOption, decompressResponseOption, clientCertificatePathOption, clientCertificateKeyPathOption).Bind(parseResult);
var requestDetails = new HttpRequestDetailsBinder(methodOptions, uriOption, versionOptions, headerOptions).Bind(parseResult);
var performanceBehavior = new PerformanceBehaviorBinder(nOption, cOption, shareSocketsHandlerOption).Bind(parseResult);
var body = parseResult.GetValue(bodyOptions);
Expand Down
Loading
Loading