2 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org
.spearce
.jgit
.transport
;
40 import java
.io
.BufferedReader
;
41 import java
.io
.FileNotFoundException
;
42 import java
.io
.IOException
;
43 import java
.io
.InputStream
;
44 import java
.net
.HttpURLConnection
;
45 import java
.net
.MalformedURLException
;
46 import java
.net
.Proxy
;
47 import java
.net
.ProxySelector
;
49 import java
.util
.ArrayList
;
50 import java
.util
.Collection
;
52 import java
.util
.TreeMap
;
54 import org
.spearce
.jgit
.errors
.NotSupportedException
;
55 import org
.spearce
.jgit
.errors
.PackProtocolException
;
56 import org
.spearce
.jgit
.errors
.TransportException
;
57 import org
.spearce
.jgit
.lib
.ObjectId
;
58 import org
.spearce
.jgit
.lib
.Ref
;
59 import org
.spearce
.jgit
.lib
.Repository
;
60 import org
.spearce
.jgit
.util
.HttpSupport
;
63 * Transport over the non-Git aware HTTP and FTP protocol.
65 * The HTTP transport does not require any specialized Git support on the remote
66 * (server side) repository. Object files are retrieved directly through
67 * standard HTTP GET requests, making it easy to serve a Git repository through
68 * a standard web host provider that does not offer specific support for Git.
70 * @see WalkFetchConnection
72 public class TransportHttp
extends HttpTransport
implements WalkTransport
{
73 static boolean canHandle(final URIish uri
) {
76 final String s
= uri
.getScheme();
77 return "http".equals(s
) || "https".equals(s
) || "ftp".equals(s
);
80 private final URL baseUrl
;
82 private final URL objectsUrl
;
84 private final ProxySelector proxySelector
;
86 TransportHttp(final Repository local
, final URIish uri
)
87 throws NotSupportedException
{
90 String uriString
= uri
.toString();
91 if (!uriString
.endsWith("/"))
93 baseUrl
= new URL(uriString
);
94 objectsUrl
= new URL(baseUrl
, "objects/");
95 } catch (MalformedURLException e
) {
96 throw new NotSupportedException("Invalid URL " + uri
, e
);
98 proxySelector
= ProxySelector
.getDefault();
102 public FetchConnection
openFetch() throws TransportException
{
103 final HttpObjectDB c
= new HttpObjectDB(objectsUrl
);
104 final WalkFetchConnection r
= new WalkFetchConnection(this, c
);
105 r
.available(c
.readAdvertisedRefs());
110 public PushConnection
openPush() throws NotSupportedException
,
112 final String s
= getURI().getScheme();
113 throw new NotSupportedException("Push not supported over " + s
+ ".");
117 public void close() {
118 // No explicit connections are maintained.
121 class HttpObjectDB
extends WalkRemoteObjectDatabase
{
122 private final URL objectsUrl
;
124 HttpObjectDB(final URL b
) {
130 return new URIish(objectsUrl
);
134 Collection
<WalkRemoteObjectDatabase
> getAlternates() throws IOException
{
136 return readAlternates(INFO_HTTP_ALTERNATES
);
137 } catch (FileNotFoundException err
) {
142 return readAlternates(INFO_ALTERNATES
);
143 } catch (FileNotFoundException err
) {
151 WalkRemoteObjectDatabase
openAlternate(final String location
)
153 return new HttpObjectDB(new URL(objectsUrl
, location
));
157 Collection
<String
> getPackNames() throws IOException
{
158 final Collection
<String
> packs
= new ArrayList
<String
>();
160 final BufferedReader br
= openReader(INFO_PACKS
);
163 final String s
= br
.readLine();
164 if (s
== null || s
.length() == 0)
166 if (!s
.startsWith("P pack-") || !s
.endsWith(".pack"))
167 throw invalidAdvertisement(s
);
168 packs
.add(s
.substring(2));
174 } catch (FileNotFoundException err
) {
180 FileStream
open(final String path
) throws IOException
{
181 final URL base
= objectsUrl
;
182 final URL u
= new URL(base
, path
);
183 final Proxy proxy
= HttpSupport
.proxyFor(proxySelector
, u
);
184 final HttpURLConnection c
;
186 c
= (HttpURLConnection
) u
.openConnection(proxy
);
187 switch (HttpSupport
.response(c
)) {
188 case HttpURLConnection
.HTTP_OK
:
189 final InputStream in
= c
.getInputStream();
190 final int len
= c
.getContentLength();
191 return new FileStream(in
, len
);
192 case HttpURLConnection
.HTTP_NOT_FOUND
:
193 throw new FileNotFoundException(u
.toString());
195 throw new IOException(u
.toString() + ": "
196 + HttpSupport
.response(c
) + " "
197 + c
.getResponseMessage());
201 Map
<String
, Ref
> readAdvertisedRefs() throws TransportException
{
203 final BufferedReader br
= openReader(INFO_REFS
);
205 return readAdvertisedImpl(br
);
209 } catch (IOException err
) {
211 throw new TransportException(new URL(objectsUrl
, INFO_REFS
)
212 + ": cannot read available refs", err
);
213 } catch (MalformedURLException mue
) {
214 throw new TransportException(objectsUrl
+ INFO_REFS
215 + ": cannot read available refs", err
);
220 private Map
<String
, Ref
> readAdvertisedImpl(final BufferedReader br
)
221 throws IOException
, PackProtocolException
{
222 final TreeMap
<String
, Ref
> avail
= new TreeMap
<String
, Ref
>();
224 String line
= br
.readLine();
228 final int tab
= line
.indexOf('\t');
230 throw invalidAdvertisement(line
);
235 name
= line
.substring(tab
+ 1);
236 id
= ObjectId
.fromString(line
.substring(0, tab
));
237 if (name
.endsWith("^{}")) {
238 name
= name
.substring(0, name
.length() - 3);
239 final Ref prior
= avail
.get(name
);
241 throw outOfOrderAdvertisement(name
);
243 if (prior
.getPeeledObjectId() != null)
244 throw duplicateAdvertisement(name
+ "^{}");
246 avail
.put(name
, new Ref(Ref
.Storage
.NETWORK
, name
, prior
247 .getObjectId(), id
, true));
249 final Ref prior
= avail
.put(name
, new Ref(
250 Ref
.Storage
.NETWORK
, name
, id
));
252 throw duplicateAdvertisement(name
);
258 private PackProtocolException
outOfOrderAdvertisement(final String n
) {
259 return new PackProtocolException("advertisement of " + n
260 + "^{} came before " + n
);
263 private PackProtocolException
invalidAdvertisement(final String n
) {
264 return new PackProtocolException("invalid advertisement of " + n
);
267 private PackProtocolException
duplicateAdvertisement(final String n
) {
268 return new PackProtocolException("duplicate advertisements of " + n
);
273 // We do not maintain persistent connections.