Skip to content

Commit ae59ffa

Browse files
authored
Merge pull request #2052 from James-LG/master
feat: Add CustomHeaders to PushOptions
2 parents 8c32b61 + 714a426 commit ae59ffa

File tree

4 files changed

+98
-6
lines changed

4 files changed

+98
-6
lines changed

LibGit2Sharp.Tests/PushFixture.cs

+27
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,33 @@ public void CanForcePush()
196196
}
197197
}
198198

199+
[Fact]
200+
public void CanPushWithCustomHeaders()
201+
{
202+
const string knownHeader = "X-Hello: mygit-201";
203+
var options = new PushOptions { CustomHeaders = new string[] { knownHeader } };
204+
AssertPush(repo =>
205+
repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options));
206+
}
207+
208+
[Fact]
209+
public void CannotPushWithForbiddenCustomHeaders()
210+
{
211+
const string knownHeader = "User-Agent: mygit-201";
212+
var options = new PushOptions { CustomHeaders = new string[] { knownHeader } };
213+
Assert.Throws<LibGit2SharpException>(
214+
() => AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options)));
215+
}
216+
217+
[Fact]
218+
public void CannotPushWithMalformedCustomHeaders()
219+
{
220+
const string knownHeader = "Hello world";
221+
var options = new PushOptions { CustomHeaders = new string[] { knownHeader } };
222+
Assert.Throws<LibGit2SharpException>(
223+
() => AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options)));
224+
}
225+
199226
private static void AssertRemoteHeadTipEquals(IRepository localRepo, string sha)
200227
{
201228
var remoteReferences = localRepo.Network.ListReferences(localRepo.Network.Remotes.Single());
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
3+
namespace LibGit2Sharp.Core
4+
{
5+
/// <summary>
6+
/// Git push options wrapper. Disposable wrapper for <see cref="GitPushOptions"/>.
7+
/// </summary>
8+
internal class GitPushOptionsWrapper : IDisposable
9+
{
10+
public GitPushOptionsWrapper() : this(new GitPushOptions()) { }
11+
12+
public GitPushOptionsWrapper(GitPushOptions pushOptions)
13+
{
14+
this.Options = pushOptions;
15+
}
16+
17+
public GitPushOptions Options { get; private set; }
18+
19+
#region IDisposable
20+
private bool disposedValue = false; // To detect redundant calls
21+
protected virtual void Dispose(bool disposing)
22+
{
23+
if (disposedValue)
24+
return;
25+
26+
this.Options.CustomHeaders.Dispose();
27+
disposedValue = true;
28+
}
29+
30+
public void Dispose()
31+
{
32+
Dispose(true);
33+
}
34+
#endregion
35+
}
36+
}

LibGit2Sharp/Network.cs

+15-6
Original file line numberDiff line numberDiff line change
@@ -365,18 +365,27 @@ public virtual void Push(Remote remote, IEnumerable<string> pushRefSpecs, PushOp
365365

366366
// Load the remote.
367367
using (RemoteHandle remoteHandle = Proxy.git_remote_lookup(repository.Handle, remote.Name, true))
368+
369+
// Create a git options wrapper so managed strings are disposed.
370+
using (var pushOptionsWrapper = new GitPushOptionsWrapper())
368371
{
369372
var callbacks = new RemoteCallbacks(pushOptions);
370373
GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks();
371374

375+
var gitPushOptions = pushOptionsWrapper.Options;
376+
gitPushOptions.PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism;
377+
gitPushOptions.RemoteCallbacks = gitCallbacks;
378+
gitPushOptions.ProxyOptions = new GitProxyOptions { Version = 1 };
379+
380+
// If there are custom headers, create a managed string array.
381+
if (pushOptions.CustomHeaders != null && pushOptions.CustomHeaders.Length > 0)
382+
{
383+
gitPushOptions.CustomHeaders = GitStrArrayManaged.BuildFrom(pushOptions.CustomHeaders);
384+
}
385+
372386
Proxy.git_remote_push(remoteHandle,
373387
pushRefSpecs,
374-
new GitPushOptions()
375-
{
376-
PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism,
377-
RemoteCallbacks = gitCallbacks,
378-
ProxyOptions = new GitProxyOptions { Version = 1 },
379-
});
388+
gitPushOptions);
380389
}
381390
}
382391

LibGit2Sharp/PushOptions.cs

+20
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,25 @@ public sealed class PushOptions
5151
/// information about what updates will be performed.
5252
/// </summary>
5353
public PrePushHandler OnNegotiationCompletedBeforePush { get; set; }
54+
55+
/// <summary>
56+
/// Get/Set the custom headers.
57+
/// <para>
58+
/// This allows you to set custom headers (e.g. X-Forwarded-For,
59+
/// X-Request-Id, etc),
60+
/// </para>
61+
/// </summary>
62+
/// <remarks>
63+
/// Libgit2 sets some headers for HTTP requests (User-Agent, Host,
64+
/// Accept, Content-Type, Transfer-Encoding, Content-Length, Accept) that
65+
/// cannot be overriden.
66+
/// </remarks>
67+
/// <example>
68+
/// var pushOptions - new PushOptions() {
69+
/// CustomHeaders = new String[] {"X-Request-Id: 12345"}
70+
/// };
71+
/// </example>
72+
/// <value>The custom headers string array</value>
73+
public string[] CustomHeaders { get; set; }
5474
}
5575
}

0 commit comments

Comments
 (0)