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