##// END OF EJS Templates
statichttprepo: don't send Range header when requesting entire file...
Alexander Boyd -
r16882:a2d6e336 stable
parent child Browse files
Show More
@@ -1,139 +1,140 b''
1 # statichttprepo.py - simple http repository class for mercurial
1 # statichttprepo.py - simple http repository class for mercurial
2 #
2 #
3 # This provides read-only repo access to repositories exported via static http
3 # This provides read-only repo access to repositories exported via static http
4 #
4 #
5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 from i18n import _
10 from i18n import _
11 import changelog, byterange, url, error
11 import changelog, byterange, url, error
12 import localrepo, manifest, util, scmutil, store
12 import localrepo, manifest, util, scmutil, store
13 import urllib, urllib2, errno
13 import urllib, urllib2, errno
14
14
15 class httprangereader(object):
15 class httprangereader(object):
16 def __init__(self, url, opener):
16 def __init__(self, url, opener):
17 # we assume opener has HTTPRangeHandler
17 # we assume opener has HTTPRangeHandler
18 self.url = url
18 self.url = url
19 self.pos = 0
19 self.pos = 0
20 self.opener = opener
20 self.opener = opener
21 self.name = url
21 self.name = url
22 def seek(self, pos):
22 def seek(self, pos):
23 self.pos = pos
23 self.pos = pos
24 def read(self, bytes=None):
24 def read(self, bytes=None):
25 req = urllib2.Request(self.url)
25 req = urllib2.Request(self.url)
26 end = ''
26 end = ''
27 if bytes:
27 if bytes:
28 end = self.pos + bytes - 1
28 end = self.pos + bytes - 1
29 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
29 if self.pos or end:
30 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
30
31
31 try:
32 try:
32 f = self.opener.open(req)
33 f = self.opener.open(req)
33 data = f.read()
34 data = f.read()
34 # Python 2.6+ defines a getcode() function, and 2.4 and
35 # Python 2.6+ defines a getcode() function, and 2.4 and
35 # 2.5 appear to always have an undocumented code attribute
36 # 2.5 appear to always have an undocumented code attribute
36 # set. If we can't read either of those, fall back to 206
37 # set. If we can't read either of those, fall back to 206
37 # and hope for the best.
38 # and hope for the best.
38 code = getattr(f, 'getcode', lambda : getattr(f, 'code', 206))()
39 code = getattr(f, 'getcode', lambda : getattr(f, 'code', 206))()
39 except urllib2.HTTPError, inst:
40 except urllib2.HTTPError, inst:
40 num = inst.code == 404 and errno.ENOENT or None
41 num = inst.code == 404 and errno.ENOENT or None
41 raise IOError(num, inst)
42 raise IOError(num, inst)
42 except urllib2.URLError, inst:
43 except urllib2.URLError, inst:
43 raise IOError(None, inst.reason[1])
44 raise IOError(None, inst.reason[1])
44
45
45 if code == 200:
46 if code == 200:
46 # HTTPRangeHandler does nothing if remote does not support
47 # HTTPRangeHandler does nothing if remote does not support
47 # Range headers and returns the full entity. Let's slice it.
48 # Range headers and returns the full entity. Let's slice it.
48 if bytes:
49 if bytes:
49 data = data[self.pos:self.pos + bytes]
50 data = data[self.pos:self.pos + bytes]
50 else:
51 else:
51 data = data[self.pos:]
52 data = data[self.pos:]
52 elif bytes:
53 elif bytes:
53 data = data[:bytes]
54 data = data[:bytes]
54 self.pos += len(data)
55 self.pos += len(data)
55 return data
56 return data
56 def __iter__(self):
57 def __iter__(self):
57 return iter(self.read().splitlines(1))
58 return iter(self.read().splitlines(1))
58 def close(self):
59 def close(self):
59 pass
60 pass
60
61
61 def build_opener(ui, authinfo):
62 def build_opener(ui, authinfo):
62 # urllib cannot handle URLs with embedded user or passwd
63 # urllib cannot handle URLs with embedded user or passwd
63 urlopener = url.opener(ui, authinfo)
64 urlopener = url.opener(ui, authinfo)
64 urlopener.add_handler(byterange.HTTPRangeHandler())
65 urlopener.add_handler(byterange.HTTPRangeHandler())
65
66
66 class statichttpopener(scmutil.abstractopener):
67 class statichttpopener(scmutil.abstractopener):
67 def __init__(self, base):
68 def __init__(self, base):
68 self.base = base
69 self.base = base
69
70
70 def __call__(self, path, mode="r", atomictemp=None):
71 def __call__(self, path, mode="r", atomictemp=None):
71 if mode not in ('r', 'rb'):
72 if mode not in ('r', 'rb'):
72 raise IOError('Permission denied')
73 raise IOError('Permission denied')
73 f = "/".join((self.base, urllib.quote(path)))
74 f = "/".join((self.base, urllib.quote(path)))
74 return httprangereader(f, urlopener)
75 return httprangereader(f, urlopener)
75
76
76 return statichttpopener
77 return statichttpopener
77
78
78 class statichttprepository(localrepo.localrepository):
79 class statichttprepository(localrepo.localrepository):
79 def __init__(self, ui, path):
80 def __init__(self, ui, path):
80 self._url = path
81 self._url = path
81 self.ui = ui
82 self.ui = ui
82
83
83 self.root = path
84 self.root = path
84 u = util.url(path.rstrip('/') + "/.hg")
85 u = util.url(path.rstrip('/') + "/.hg")
85 self.path, authinfo = u.authinfo()
86 self.path, authinfo = u.authinfo()
86
87
87 opener = build_opener(ui, authinfo)
88 opener = build_opener(ui, authinfo)
88 self.opener = opener(self.path)
89 self.opener = opener(self.path)
89 self._phasedefaults = []
90 self._phasedefaults = []
90
91
91 try:
92 try:
92 requirements = scmutil.readrequires(self.opener, self.supported)
93 requirements = scmutil.readrequires(self.opener, self.supported)
93 except IOError, inst:
94 except IOError, inst:
94 if inst.errno != errno.ENOENT:
95 if inst.errno != errno.ENOENT:
95 raise
96 raise
96 requirements = set()
97 requirements = set()
97
98
98 # check if it is a non-empty old-style repository
99 # check if it is a non-empty old-style repository
99 try:
100 try:
100 fp = self.opener("00changelog.i")
101 fp = self.opener("00changelog.i")
101 fp.read(1)
102 fp.read(1)
102 fp.close()
103 fp.close()
103 except IOError, inst:
104 except IOError, inst:
104 if inst.errno != errno.ENOENT:
105 if inst.errno != errno.ENOENT:
105 raise
106 raise
106 # we do not care about empty old-style repositories here
107 # we do not care about empty old-style repositories here
107 msg = _("'%s' does not appear to be an hg repository") % path
108 msg = _("'%s' does not appear to be an hg repository") % path
108 raise error.RepoError(msg)
109 raise error.RepoError(msg)
109
110
110 # setup store
111 # setup store
111 self.store = store.store(requirements, self.path, opener)
112 self.store = store.store(requirements, self.path, opener)
112 self.spath = self.store.path
113 self.spath = self.store.path
113 self.sopener = self.store.opener
114 self.sopener = self.store.opener
114 self.sjoin = self.store.join
115 self.sjoin = self.store.join
115 self._filecache = {}
116 self._filecache = {}
116
117
117 self.manifest = manifest.manifest(self.sopener)
118 self.manifest = manifest.manifest(self.sopener)
118 self.changelog = changelog.changelog(self.sopener)
119 self.changelog = changelog.changelog(self.sopener)
119 self._tags = None
120 self._tags = None
120 self.nodetagscache = None
121 self.nodetagscache = None
121 self._branchcache = None
122 self._branchcache = None
122 self._branchcachetip = None
123 self._branchcachetip = None
123 self.encodepats = None
124 self.encodepats = None
124 self.decodepats = None
125 self.decodepats = None
125 self.capabilities.difference_update(["pushkey"])
126 self.capabilities.difference_update(["pushkey"])
126
127
127 def url(self):
128 def url(self):
128 return self._url
129 return self._url
129
130
130 def local(self):
131 def local(self):
131 return False
132 return False
132
133
133 def lock(self, wait=True):
134 def lock(self, wait=True):
134 raise util.Abort(_('cannot lock static-http repository'))
135 raise util.Abort(_('cannot lock static-http repository'))
135
136
136 def instance(ui, path, create):
137 def instance(ui, path, create):
137 if create:
138 if create:
138 raise util.Abort(_('cannot create new static-http repository'))
139 raise util.Abort(_('cannot create new static-http repository'))
139 return statichttprepository(ui, path[7:])
140 return statichttprepository(ui, path[7:])
General Comments 0
You need to be logged in to leave comments. Login now