Skip to content

Instantly share code, notes, and snippets.

@pwkelley
Created November 12, 2012 01:19
Show Gist options
  • Save pwkelley/4057030 to your computer and use it in GitHub Desktop.
Save pwkelley/4057030 to your computer and use it in GitHub Desktop.
Libgit2sharp bindings for smart protocol subtransports
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
using Xunit.Extensions;
namespace LibGit2Sharp.Tests
{
public class SmartSubtransportFixture : BaseFixture
{
[Theory]
[InlineData("http://github.com/libgit2/TestGitRepository")]
[InlineData("https://github.com/libgit2/TestGitRepository")]
public void HttpWebRequestSubtransportTest(String url)
{
string remoteName = "testRemote";
var scd = BuildSelfCleaningDirectory();
using (new SmartTransportDefinition<MockSubtransport>("http://", 2))
using (new SmartTransportDefinition<MockSubtransport>("https://", 2))
using (var repo = Repository.Init(scd.RootedDirectoryPath))
{
Remote remote = repo.Remotes.Add(remoteName, url);
// Set up structures for the expected results
// and verifying the RemoteUpdateTips callback.
TestRemoteInfo expectedResults = TestRemoteInfo.TestRemoteInstance;
ExpectedFetchState expectedFetchState = new ExpectedFetchState(remoteName);
// Add expected branch objects
foreach (KeyValuePair<string, ObjectId> kvp in expectedResults.BranchTips)
{
expectedFetchState.AddExpectedBranch(kvp.Key, ObjectId.Zero, kvp.Value);
}
// Add the expected tags
string[] expectedTagNames = { "blob", "commit_tree", "annotated_tag" };
foreach (string tagName in expectedTagNames)
{
TestRemoteInfo.ExpectedTagInfo expectedTagInfo = expectedResults.Tags[tagName];
expectedFetchState.AddExpectedTag(tagName, ObjectId.Zero, expectedTagInfo);
}
// Perform the actual fetch
remote.Fetch(onUpdateTips: expectedFetchState.RemoteUpdateTipsHandler);
// Verify the expected
expectedFetchState.CheckUpdatedReferences(repo);
}
}
[RpcSmartSubtransport]
private class MockSubtransport : SmartSubtransport
{
public override SmartSubtransportStream Action(String url, SmartService service)
{
String serviceUrl;
String contentType = null;
bool isPost = false;
bool isChunked = false;
switch (service)
{
case SmartService.UploadPackList:
serviceUrl = String.Concat(url, "/info/refs?service=git-upload-pack");
break;
case SmartService.UploadPack:
serviceUrl = String.Concat(url, "/git-upload-pack");
contentType = "application/x-git-upload-pack-request";
isPost = true;
break;
case SmartService.ReceivePackList:
serviceUrl = String.Concat(url, "/info/refs?service=git-receive-pack");
break;
case SmartService.ReceivePack:
serviceUrl = String.Concat(url, "/git-receive-pack");
contentType = "application/x-git-receive-pack-request";
isPost = true;
isChunked = true;
break;
default:
throw new InvalidOperationException();
}
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(serviceUrl);
webRequest.UserAgent = "git/1.0 (libgit2 custom transport)";
webRequest.ServicePoint.Expect100Continue = false;
if (isPost)
{
webRequest.Method = "POST";
webRequest.ContentType = contentType;
}
if (isChunked)
{
webRequest.SendChunked = true;
}
return new MockSubtransportStream(this, webRequest);
}
}
private class MockSubtransportStream : SmartSubtransportStream
{
public MockSubtransportStream(MockSubtransport subtransport, HttpWebRequest webRequest)
: base(subtransport)
{
this.webRequest = webRequest;
}
protected override void Dispose()
{
if (null != requestStream)
{
requestStream.Dispose();
requestStream = null;
}
if (null != responseStream)
{
responseStream.Dispose();
responseStream = null;
}
base.Dispose();
}
public override int Read(Stream dataStream, long length, out long bytesRead)
{
bytesRead = 0;
if (null != requestStream)
{
requestStream.Dispose();
requestStream = null;
}
if (null == responseStream)
{
WebResponse response = webRequest.GetResponse();
try
{
responseStream = response.GetResponseStream();
}
catch
{
((IDisposable)response).Dispose();
throw;
}
}
byte[] buffer = new byte[4096];
while (length > 0)
{
int wireBytesRead = responseStream.Read(buffer, 0, (int)Math.Min(buffer.Length, length));
if (0 == wireBytesRead)
break;
dataStream.Write(buffer, 0, wireBytesRead);
bytesRead += wireBytesRead;
length -= wireBytesRead;
}
return 0;
}
public override int Write(Stream dataStream, long length)
{
if (null == requestStream)
{
requestStream = webRequest.GetRequestStream();
}
byte[] buffer = new byte[4096];
while (length > 0)
{
int inputBytesRead = dataStream.Read(buffer, 0, (int)Math.Min(buffer.Length, length));
if (0 == inputBytesRead)
break;
requestStream.Write(buffer, 0, inputBytesRead);
length -= inputBytesRead;
}
return 0;
}
private readonly HttpWebRequest webRequest;
private Stream requestStream;
private Stream responseStream;
}
}
}
@Aimeast
Copy link

Aimeast commented Apr 4, 2013

Hi, I think it is a great implement, but I very wonder that where is MockSubtransport & SmartSubtransportStream?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment