Skip to content

Commit

Permalink
Merge pull request #2065 from libgit2/proxy-options
Browse files Browse the repository at this point in the history
Add proxy options
  • Loading branch information
bording authored Dec 3, 2023
2 parents 1cc55f0 + 01a6ccb commit cd24df2
Show file tree
Hide file tree
Showing 19 changed files with 444 additions and 142 deletions.
108 changes: 56 additions & 52 deletions LibGit2Sharp.Tests/CloneFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,14 @@ public void CallsProgressCallbacks(string url)

Repository.Clone(url, scd.DirectoryPath, new CloneOptions()
{
OnTransferProgress = _ => { transferWasCalled = true; return true; },
OnProgress = progress => { progressWasCalled = true; return true; },
OnUpdateTips = (name, oldId, newId) => { updateTipsWasCalled = true; return true; },
FetchOptions =
{
OnTransferProgress = _ => { transferWasCalled = true; return true; },
OnProgress = progress => { progressWasCalled = true; return true; },
OnUpdateTips = (name, oldId, newId) => { updateTipsWasCalled = true; return true; }
},
OnCheckoutProgress = (a, b, c) => checkoutWasCalled = true

});

Assert.True(transferWasCalled);
Expand All @@ -174,7 +178,7 @@ public void CanCloneWithCredentials()
string clonedRepoPath = Repository.Clone(Constants.PrivateRepoUrl, scd.DirectoryPath,
new CloneOptions()
{
CredentialsProvider = Constants.PrivateRepoCredentials
FetchOptions = { CredentialsProvider = Constants.PrivateRepoCredentials }
});


Expand Down Expand Up @@ -249,43 +253,46 @@ public void CanInspectCertificateOnClone(string url, string hostname, Type certT

var options = new CloneOptions
{
CertificateCheck = (cert, valid, host) =>
FetchOptions =
{
wasCalled = true;

Assert.Equal(hostname, host);
Assert.Equal(certType, cert.GetType());

if (certType == typeof(CertificateX509))
CertificateCheck = (cert, valid, host) =>
{
Assert.True(valid);
var x509 = ((CertificateX509)cert).Certificate;
// we get a string with the different fields instead of a structure, so...
Assert.Contains("CN=github.com,", x509.Subject);
checksHappy = true;
return false;
}
wasCalled = true;

Assert.Equal(hostname, host);
Assert.Equal(certType, cert.GetType());

if (certType == typeof(CertificateX509))
{
Assert.True(valid);
var x509 = ((CertificateX509)cert).Certificate;
// we get a string with the different fields instead of a structure, so...
Assert.Contains("CN=github.com,", x509.Subject);
checksHappy = true;
return false;
}

if (certType == typeof(CertificateSsh))
{
var hostkey = (CertificateSsh)cert;
Assert.True(hostkey.HasMD5);
/*
* Once you've connected and thus your ssh has stored the hostkey,
* you can get the hostkey for a host with
*
* ssh-keygen -F github.com -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':'
*
* though GitHub's hostkey won't change anytime soon.
*/
Assert.Equal("1627aca576282d36631b564debdfa648",
BitConverter.ToString(hostkey.HashMD5).ToLower().Replace("-", ""));
checksHappy = true;
return false;
}

if (certType == typeof(CertificateSsh))
{
var hostkey = (CertificateSsh)cert;
Assert.True(hostkey.HasMD5);
/*
* Once you've connected and thus your ssh has stored the hostkey,
* you can get the hostkey for a host with
*
* ssh-keygen -F github.com -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':'
*
* though GitHub's hostkey won't change anytime soon.
*/
Assert.Equal("1627aca576282d36631b564debdfa648",
BitConverter.ToString(hostkey.HashMD5).ToLower().Replace("-", ""));
checksHappy = true;
return false;
}

return false;
},
}
};

Assert.Throws<UserCancelledException>(() =>
Expand Down Expand Up @@ -432,9 +439,12 @@ public void CanRecursivelyCloneSubmodules()
{
RecurseSubmodules = true,
OnCheckoutProgress = checkoutProgressHandler,
OnUpdateTips = remoteRefUpdated,
RepositoryOperationStarting = repositoryOperationStarting,
RepositoryOperationCompleted = repositoryOperationCompleted,
FetchOptions =
{
OnUpdateTips = remoteRefUpdated,
RepositoryOperationStarting = repositoryOperationStarting,
RepositoryOperationCompleted = repositoryOperationCompleted
}
};

string clonedRepoPath = Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options);
Expand Down Expand Up @@ -517,7 +527,7 @@ public void CanCancelRecursiveClone()
CloneOptions options = new CloneOptions()
{
RecurseSubmodules = true,
RepositoryOperationStarting = repositoryOperationStarting,
FetchOptions = { RepositoryOperationStarting = repositoryOperationStarting }
};

Assert.Throws<UserCancelledException>(() =>
Expand Down Expand Up @@ -557,10 +567,8 @@ public void CannotCloneWithForbiddenCustomHeaders()
const string url = "https://github.com/libgit2/TestGitRepository";

const string knownHeader = "User-Agent: mygit-201";
var cloneOptions = new CloneOptions()
{
FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } }
};
var cloneOptions = new CloneOptions();
cloneOptions.FetchOptions.CustomHeaders = new string[] { knownHeader };

Assert.Throws<LibGit2SharpException>(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions));
}
Expand All @@ -573,10 +581,8 @@ public void CannotCloneWithMalformedCustomHeaders()
const string url = "https://github.com/libgit2/TestGitRepository";

const string knownHeader = "hello world";
var cloneOptions = new CloneOptions()
{
FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } }
};
var cloneOptions = new CloneOptions();
cloneOptions.FetchOptions.CustomHeaders = new string[] { knownHeader };

Assert.Throws<LibGit2SharpException>(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions));
}
Expand All @@ -589,10 +595,8 @@ public void CanCloneWithCustomHeaders()
const string url = "https://github.com/libgit2/TestGitRepository";

const string knownHeader = "X-Hello: world";
var cloneOptions = new CloneOptions()
{
FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } }
};
var cloneOptions = new CloneOptions();
cloneOptions.FetchOptions.CustomHeaders = new string[] { knownHeader };

var clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, cloneOptions);
Assert.True(Directory.Exists(clonedRepoPath));
Expand Down
4 changes: 2 additions & 2 deletions LibGit2Sharp.Tests/SubmoduleFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Linq;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
using Xunit.Extensions;

namespace LibGit2Sharp.Tests
{
Expand Down Expand Up @@ -240,9 +239,10 @@ public void CanUpdateSubmodule()
OnCheckoutProgress = (x, y, z) => checkoutProgressCalled = true,
OnCheckoutNotify = (x, y) => { checkoutNotifyCalled = true; return true; },
CheckoutNotifyFlags = CheckoutNotifyFlags.Updated,
OnUpdateTips = (x, y, z) => { updateTipsCalled = true; return true; },
};

options.FetchOptions.OnUpdateTips = (x, y, z) => { updateTipsCalled = true; return true; };

repo.Submodules.Init(submodule.Name, false);
repo.Submodules.Update(submodule.Name, options);

Expand Down
4 changes: 2 additions & 2 deletions LibGit2Sharp/CloneOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace LibGit2Sharp
/// <summary>
/// Options to define clone behaviour
/// </summary>
public sealed class CloneOptions : FetchOptionsBase, IConvertableToGitCheckoutOpts
public sealed class CloneOptions : IConvertableToGitCheckoutOpts
{
/// <summary>
/// Creates default <see cref="CloneOptions"/> for a non-bare clone
Expand Down Expand Up @@ -46,7 +46,7 @@ public CloneOptions()
/// <summary>
/// Gets or sets the fetch options.
/// </summary>
public FetchOptions FetchOptions { get; set; }
public FetchOptions FetchOptions { get; } = new();

#region IConvertableToGitCheckoutOpts

Expand Down
3 changes: 1 addition & 2 deletions LibGit2Sharp/Commands/Fetch.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using LibGit2Sharp;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;

Expand Down Expand Up @@ -75,7 +74,7 @@ public static void Fetch(Repository repository, string remote, IEnumerable<strin
fetchOptions.CustomHeaders = GitStrArrayManaged.BuildFrom(options.CustomHeaders);
}

fetchOptions.ProxyOptions = new GitProxyOptions { Version = 1 };
fetchOptions.ProxyOptions = options.ProxyOptions.CreateGitProxyOptions();

Proxy.git_remote_fetch(remoteHandle, refspecs, fetchOptions, logMessage);
}
Expand Down
9 changes: 5 additions & 4 deletions LibGit2Sharp/Core/GitFetchOptionsWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

namespace LibGit2Sharp.Core
{
/// <summary>
/// Git fetch options wrapper. Disposable wrapper for GitFetchOptions
/// <summary>
/// Git fetch options wrapper. Disposable wrapper for GitFetchOptions
/// </summary>
internal class GitFetchOptionsWrapper : IDisposable
{
public GitFetchOptionsWrapper() : this(new GitFetchOptions()) { }

public GitFetchOptionsWrapper(GitFetchOptions fetchOptions)
{
this.Options = fetchOptions;
Options = fetchOptions;
}

public GitFetchOptions Options { get; private set; }
Expand All @@ -23,7 +23,8 @@ protected virtual void Dispose(bool disposing)
if (disposedValue)
return;

this.Options.CustomHeaders.Dispose();
Options.CustomHeaders.Dispose();
EncodingMarshaler.Cleanup(Options.ProxyOptions.Url);
disposedValue = true;
}

Expand Down
6 changes: 3 additions & 3 deletions LibGit2Sharp/Core/GitProxyOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ internal struct GitProxyOptions
public uint Version;
public GitProxyType Type;
public IntPtr Url;
public IntPtr CredentialsCb;
public IntPtr CertificateCheck;
public IntPtr CbPayload;
public NativeMethods.git_cred_acquire_cb Credentials;
public NativeMethods.git_transport_certificate_check_cb CertificateCheck;
public IntPtr Payload;
}
}
32 changes: 32 additions & 0 deletions LibGit2Sharp/Core/GitProxyOptionsWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;

namespace LibGit2Sharp.Core
{
internal class GitProxyOptionsWrapper : IDisposable
{
public GitProxyOptionsWrapper() : this(new GitProxyOptions()) { }

public GitProxyOptionsWrapper(GitProxyOptions fetchOptions)
{
Options = fetchOptions;
}

public GitProxyOptions Options { get; private set; }

private bool disposedValue = false;

protected virtual void Dispose(bool disposing)
{
if (disposedValue)
return;

EncodingMarshaler.Cleanup(Options.Url);
disposedValue = true;
}

public void Dispose()
{
Dispose(true);
}
}
}
1 change: 1 addition & 0 deletions LibGit2Sharp/Core/GitPushOptionsWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ protected virtual void Dispose(bool disposing)
return;

this.Options.CustomHeaders.Dispose();
EncodingMarshaler.Cleanup(Options.ProxyOptions.Url);
disposedValue = true;
}

Expand Down
2 changes: 0 additions & 2 deletions LibGit2Sharp/Core/GitSubmoduleOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ internal struct GitSubmoduleUpdateOptions

public GitFetchOptions FetchOptions;

public CheckoutStrategy CloneCheckoutStrategy;

public int AllowFetch;
}
}
8 changes: 4 additions & 4 deletions LibGit2Sharp/FetchOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ public sealed class FetchOptions : FetchOptionsBase

/// <summary>
/// Get/Set the custom headers.
///
/// <para>
/// This allows you to set custom headers (e.g. X-Forwarded-For,
///
/// <para>
/// This allows you to set custom headers (e.g. X-Forwarded-For,
/// X-Request-Id, etc),
/// </para>
/// </summary>
/// <remarks>
/// Libgit2 sets some headers for HTTP requests (User-Agent, Host,
/// Libgit2 sets some headers for HTTP requests (User-Agent, Host,
/// Accept, Content-Type, Transfer-Encoding, Content-Length, Accept) that
/// cannot be overriden.
/// </remarks>
Expand Down
7 changes: 6 additions & 1 deletion LibGit2Sharp/FetchOptionsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal FetchOptionsBase()

/// <summary>
/// This handler will be called to let the user make a decision on whether to allow
/// the connection to preoceed based on the certificate presented by the server.
/// the connection to proceed based on the certificate presented by the server.
/// </summary>
public CertificateCheckHandler CertificateCheck { get; set; }

Expand All @@ -48,5 +48,10 @@ internal FetchOptionsBase()
/// Completed operating on the current repository.
/// </summary>
public RepositoryOperationCompleted RepositoryOperationCompleted { get; set; }

/// <summary>
/// Options for connecting through a proxy.
/// </summary>
public ProxyOptions ProxyOptions { get; } = new();
}
}
1 change: 1 addition & 0 deletions LibGit2Sharp/LibGit2Sharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<TargetFrameworks>net472;net6.0</TargetFrameworks>
<LangVersion>10.0</LangVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Description>LibGit2Sharp brings all the might and speed of libgit2, a native Git implementation, to the managed world of .NET</Description>
<Company>LibGit2Sharp contributors</Company>
Expand Down
Loading

0 comments on commit cd24df2

Please sign in to comment.