Created
November 12, 2012 01:19
-
-
Save pwkelley/4057030 to your computer and use it in GitHub Desktop.
Libgit2sharp bindings for smart protocol subtransports
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I think it is a great implement, but I very wonder that where is MockSubtransport & SmartSubtransportStream?