Permalink
Browse files

Implement transport over HTTP => 4/5 Transport tests now succeed.

Signed-off-by: caytchen <caytchen@gmail.com>
  • Loading branch information...
1 parent e870e66 commit 211e12b8528b05cb645230deabcca8df58194591 @stschake stschake committed Aug 25, 2009
@@ -171,7 +171,7 @@
<Compile Include="UnpackedObjectLoader.cs" />
<Compile Include="Util\AtomicReferenceArray.cs" />
<Compile Include="Util\AtomicValue.cs" />
- <Compile Include="Util\FileStream.cs" />
+ <Compile Include="Util\Stream.cs" />
<Compile Include="Util\FS.cs" />
<Compile Include="Util\GenericComparer.cs" />
<Compile Include="Util\Inspect.cs" />
@@ -70,7 +70,7 @@ public Ref GetRef(string name)
public abstract void Close();
- protected void available(Dictionary<string, Ref> all)
+ public void available(Dictionary<string, Ref> all)
{
advertisedRefs = all;
}
@@ -111,6 +111,9 @@ public static List<Transport> openAll(Repository local, RemoteConfig cfg)
*/
public static Transport Open(Repository local, URIish remote)
{
+ if (TransportHttp.canHandle(remote))
+ return new TransportHttp(local, remote);
+
throw new NotSupportedException("URI not supported: " + remote);
}
@@ -38,6 +38,11 @@
*/
using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using GitSharp.Exceptions;
+using GitSharp.Util;
namespace GitSharp.Transport
{
@@ -53,24 +58,226 @@ public static bool canHandle(URIish uri)
return "http".Equals(s) || "https".Equals(s) || "ftp".Equals(s);
}
+ private readonly Uri baseUrl;
+ private readonly Uri objectsUrl;
+
public TransportHttp(Repository local, URIish uri)
: base(local, uri)
{
+ try
+ {
+ string uriString = uri.ToString();
+ if (!uriString.EndsWith("/"))
+ uriString += "/";
+ baseUrl = new Uri(uriString);
+ objectsUrl = new Uri(baseUrl, "objects/");
+ }
+ catch (UriFormatException e)
+ {
+ throw new NotSupportedException("Invalid URL " + uri, e);
+ }
}
public override IFetchConnection openFetch()
{
- throw new NotImplementedException();
+ HttpObjectDB c = new HttpObjectDB(objectsUrl);
+ WalkFetchConnection r = new WalkFetchConnection(this, c);
+ r.available(c.readAdvertisedRefs());
+ return r;
}
public override IPushConnection openPush()
{
- throw new NotImplementedException();
+ string s = uri.Scheme;
+ throw new NotSupportedException("Push not supported over " + s + ".");
}
public override void close()
{
- throw new NotImplementedException();
+ }
+
+ private class HttpObjectDB : WalkRemoteObjectDatabase
+ {
+ private readonly Uri objectsUrl;
+
+ public HttpObjectDB(Uri b)
+ {
+ objectsUrl = b;
+ }
+
+ public override URIish getURI()
+ {
+ return new URIish(objectsUrl);
+ }
+
+ public override List<WalkRemoteObjectDatabase> getAlternates()
+ {
+ try
+ {
+ return readAlternates(INFO_HTTP_ALTERNATES);
+ }
+ catch (FileNotFoundException)
+ {
+ }
+
+ try
+ {
+ return readAlternates(INFO_ALTERNATES);
+ }
+ catch (FileNotFoundException)
+ {
+ }
+
+ return null;
+ }
+
+ public override WalkRemoteObjectDatabase openAlternate(string location)
+ {
+ return new HttpObjectDB(new Uri(objectsUrl, location));
+ }
+
+ public override List<string> getPackNames()
+ {
+ List<string> packs = new List<string>();
+ try
+ {
+ StreamReader br = openReader(INFO_PACKS);
+ try
+ {
+ for (;;)
+ {
+ string s = br.ReadLine();
+ if (string.IsNullOrEmpty(s))
+ break;
+ if (!s.StartsWith("P pack-") || !s.EndsWith(".pack"))
+ throw invalidAdvertisement(s);
+ packs.Add(s.Substring(2));
+ }
+ return packs;
+ }
+ finally
+ {
+ br.Close();
+ }
+ }
+ catch (FileNotFoundException)
+ {
+ return packs;
+ }
+ }
+
+ public override Stream open(string path)
+ {
+ Uri @base = objectsUrl;
+ Uri u = new Uri(@base, path);
+
+ HttpWebRequest c = (HttpWebRequest) WebRequest.Create(u);
+ HttpWebResponse response = (HttpWebResponse) c.GetResponse();
+
+ switch (response.StatusCode)
+ {
+ case HttpStatusCode.OK:
+ return response.GetResponseStream();
+
+ case HttpStatusCode.NotFound:
+ throw new FileNotFoundException(u.ToString());
+
+ default:
+ throw new IOException(u + ": " + response.StatusDescription);
+ }
+ }
+
+ public Dictionary<string, Ref> readAdvertisedRefs()
+ {
+ try
+ {
+ StreamReader br = openReader(INFO_REFS);
+ try
+ {
+ return readAdvertisedImpl(br);
+ }
+ finally
+ {
+ br.Close();
+ }
+ }
+ catch (IOException err)
+ {
+ try
+ {
+ throw new TransportException(new Uri(objectsUrl, INFO_REFS) + ": cannot read available refs", err);
+ }
+ catch (UriFormatException)
+ {
+ throw new TransportException(objectsUrl + INFO_REFS + ": cannot read available refs", err);
+ }
+ }
+ }
+
+ private static Dictionary<string, Ref> readAdvertisedImpl(TextReader br)
+ {
+ Dictionary<string, Ref> avail = new Dictionary<string, Ref>();
+ for (;;)
+ {
+ string line = br.ReadLine();
+ if (line == null)
+ break;
+
+ int tab = line.IndexOf('\t');
+ if (tab < 0)
+ throw invalidAdvertisement(line);
+
+ string name = line.Substring(tab + 1);
+ ObjectId id = ObjectId.FromString(line.Slice(0, tab));
+ if (name.EndsWith("^{}"))
+ {
+ name = name.Slice(0, name.Length - 3);
+ Ref prior = avail[name];
+ if (prior == null)
+ throw outOfOrderAdvertisement(name);
+
+ if (prior.PeeledObjectId != null)
+ throw duplicateAdvertisement(name + "^{}");
+
+ avail.Add(name, new Ref(Ref.Storage.Network, name, prior.ObjectId, id, true));
+ }
+ else
+ {
+ Ref prior = null;
+ if (avail.ContainsKey(name))
+ {
+ prior = avail[name];
+ avail[name] = new Ref(Ref.Storage.Network, name, id);
+ }
+ else
+ {
+ avail.Add(name, new Ref(Ref.Storage.Network, name, id));
+ }
+ if (prior != null)
+ throw duplicateAdvertisement(name);
+ }
+ }
+ return avail;
+ }
+
+ private static PackProtocolException outOfOrderAdvertisement(string n)
+ {
+ return new PackProtocolException("advertisement of " + n +"^{} came before " + n);
+ }
+
+ private static PackProtocolException invalidAdvertisement(string n)
+ {
+ return new PackProtocolException("invalid advertisement of " + n);
+ }
+
+ private static PackProtocolException duplicateAdvertisement(string n)
+ {
+ return new PackProtocolException("duplicate advertisements of " + n);
+ }
+
+ public override void close()
+ {
+ }
}
}
}
@@ -767,7 +767,7 @@ public void openIndex(IProgressMonitor pm)
}
- FileStream s = connection.open("pack/" + idxName);
+ Stream s = connection.open("pack/" + idxName);
pm.BeginTask("Get " + idxName.Slice(0, 12) + "..idx", s.Length < 0 ? -1 : (int)(s.Length / 1024));
try
{
@@ -817,7 +817,7 @@ public void openIndex(IProgressMonitor pm)
public void downloadPack(IProgressMonitor monitor)
{
- FileStream s = connection.open("pack/" + packName);
+ Stream s = connection.open("pack/" + packName);
IndexPack ip = IndexPack.create(local, s);
ip.setFixThin(false);
ip.setObjectChecker(objCheck);
@@ -54,7 +54,7 @@ public abstract class WalkRemoteObjectDatabase
public abstract URIish getURI();
public abstract List<string> getPackNames();
public abstract List<WalkRemoteObjectDatabase> getAlternates();
- public abstract FileStream open(string path);
+ public abstract Stream open(string path);
public abstract WalkRemoteObjectDatabase openAlternate(string location);
public abstract void close();
@@ -117,7 +117,7 @@ public void writeInfoPacks(List<string> packNames)
public StreamReader openReader(string path)
{
- FileStream s = open(path);
+ Stream s = open(path);
// StreamReader buffers itself
return new StreamReader(s, Constants.CHARSET);
}
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009, Stefan Schake <caytchen@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Note: jgit has implemented its own FileStream in WalkRemoteObjectDatabase */
+
+using System.IO;
+
+namespace GitSharp.Util
+{
+
+ public static class FileStreamExtensions
+ {
+ public static byte[] toArray(this Stream stream)
+ {
+ try
+ {
+ // Note: if we can seek, it's likely we have a length
+ if (stream.CanSeek)
+ {
+ if (stream.Length >= 0)
+ {
+ byte[] r = new byte[stream.Length];
+ NB.ReadFully(stream, r, 0, r.Length);
+ return r;
+ }
+ }
+
+ MemoryStream m = new MemoryStream();
+ byte[] buf = new byte[2048];
+ int n;
+ while ((n = stream.Read(buf, 0, buf.Length)) > 0)
+ m.Write(buf, 0, n);
+ return m.ToArray();
+ }
+ finally
+ {
+ stream.Close();
+ }
+ }
+ }
+
+}

0 comments on commit 211e12b

Please sign in to comment.