##// END OF EJS Templates
httprepo: remove is-comparison with string literal...
Dan Villiom Podlaski Christiansen -
r13006:ea68947a stable
parent child Browse files
Show More
@@ -1,203 +1,203 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httprepo.py - HTTP repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from node import nullid
9 from node import nullid
10 from i18n import _
10 from i18n import _
11 import changegroup, statichttprepo, error, url, util, wireproto
11 import changegroup, statichttprepo, error, url, util, wireproto
12 import os, urllib, urllib2, urlparse, zlib, httplib
12 import os, urllib, urllib2, urlparse, zlib, httplib
13 import errno, socket
13 import errno, socket
14
14
15 def zgenerator(f):
15 def zgenerator(f):
16 zd = zlib.decompressobj()
16 zd = zlib.decompressobj()
17 try:
17 try:
18 for chunk in util.filechunkiter(f):
18 for chunk in util.filechunkiter(f):
19 while chunk:
19 while chunk:
20 yield zd.decompress(chunk, 2**18)
20 yield zd.decompress(chunk, 2**18)
21 chunk = zd.unconsumed_tail
21 chunk = zd.unconsumed_tail
22 except httplib.HTTPException:
22 except httplib.HTTPException:
23 raise IOError(None, _('connection ended unexpectedly'))
23 raise IOError(None, _('connection ended unexpectedly'))
24 yield zd.flush()
24 yield zd.flush()
25
25
26 class httprepository(wireproto.wirerepository):
26 class httprepository(wireproto.wirerepository):
27 def __init__(self, ui, path):
27 def __init__(self, ui, path):
28 self.path = path
28 self.path = path
29 self.caps = None
29 self.caps = None
30 self.handler = None
30 self.handler = None
31 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
31 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
32 if query or frag:
32 if query or frag:
33 raise util.Abort(_('unsupported URL component: "%s"') %
33 raise util.Abort(_('unsupported URL component: "%s"') %
34 (query or frag))
34 (query or frag))
35
35
36 # urllib cannot handle URLs with embedded user or passwd
36 # urllib cannot handle URLs with embedded user or passwd
37 self._url, authinfo = url.getauthinfo(path)
37 self._url, authinfo = url.getauthinfo(path)
38
38
39 self.ui = ui
39 self.ui = ui
40 self.ui.debug('using %s\n' % self._url)
40 self.ui.debug('using %s\n' % self._url)
41
41
42 self.urlopener = url.opener(ui, authinfo)
42 self.urlopener = url.opener(ui, authinfo)
43
43
44 def __del__(self):
44 def __del__(self):
45 for h in self.urlopener.handlers:
45 for h in self.urlopener.handlers:
46 h.close()
46 h.close()
47 if hasattr(h, "close_all"):
47 if hasattr(h, "close_all"):
48 h.close_all()
48 h.close_all()
49
49
50 def url(self):
50 def url(self):
51 return self.path
51 return self.path
52
52
53 # look up capabilities only when needed
53 # look up capabilities only when needed
54
54
55 def get_caps(self):
55 def get_caps(self):
56 if self.caps is None:
56 if self.caps is None:
57 try:
57 try:
58 self.caps = set(self._call('capabilities').split())
58 self.caps = set(self._call('capabilities').split())
59 except error.RepoError:
59 except error.RepoError:
60 self.caps = set()
60 self.caps = set()
61 self.ui.debug('capabilities: %s\n' %
61 self.ui.debug('capabilities: %s\n' %
62 (' '.join(self.caps or ['none'])))
62 (' '.join(self.caps or ['none'])))
63 return self.caps
63 return self.caps
64
64
65 capabilities = property(get_caps)
65 capabilities = property(get_caps)
66
66
67 def lock(self):
67 def lock(self):
68 raise util.Abort(_('operation not supported over http'))
68 raise util.Abort(_('operation not supported over http'))
69
69
70 def _callstream(self, cmd, **args):
70 def _callstream(self, cmd, **args):
71 if cmd is 'pushkey':
71 if cmd == 'pushkey':
72 args['data'] = ''
72 args['data'] = ''
73 data = args.pop('data', None)
73 data = args.pop('data', None)
74 headers = args.pop('headers', {})
74 headers = args.pop('headers', {})
75 self.ui.debug("sending %s command\n" % cmd)
75 self.ui.debug("sending %s command\n" % cmd)
76 q = {"cmd": cmd}
76 q = {"cmd": cmd}
77 q.update(args)
77 q.update(args)
78 qs = '?%s' % urllib.urlencode(q)
78 qs = '?%s' % urllib.urlencode(q)
79 cu = "%s%s" % (self._url, qs)
79 cu = "%s%s" % (self._url, qs)
80 req = urllib2.Request(cu, data, headers)
80 req = urllib2.Request(cu, data, headers)
81 if data is not None:
81 if data is not None:
82 # len(data) is broken if data doesn't fit into Py_ssize_t
82 # len(data) is broken if data doesn't fit into Py_ssize_t
83 # add the header ourself to avoid OverflowError
83 # add the header ourself to avoid OverflowError
84 size = data.__len__()
84 size = data.__len__()
85 self.ui.debug("sending %s bytes\n" % size)
85 self.ui.debug("sending %s bytes\n" % size)
86 req.add_unredirected_header('Content-Length', '%d' % size)
86 req.add_unredirected_header('Content-Length', '%d' % size)
87 try:
87 try:
88 resp = self.urlopener.open(req)
88 resp = self.urlopener.open(req)
89 except urllib2.HTTPError, inst:
89 except urllib2.HTTPError, inst:
90 if inst.code == 401:
90 if inst.code == 401:
91 raise util.Abort(_('authorization failed'))
91 raise util.Abort(_('authorization failed'))
92 raise
92 raise
93 except httplib.HTTPException, inst:
93 except httplib.HTTPException, inst:
94 self.ui.debug('http error while sending %s command\n' % cmd)
94 self.ui.debug('http error while sending %s command\n' % cmd)
95 self.ui.traceback()
95 self.ui.traceback()
96 raise IOError(None, inst)
96 raise IOError(None, inst)
97 except IndexError:
97 except IndexError:
98 # this only happens with Python 2.3, later versions raise URLError
98 # this only happens with Python 2.3, later versions raise URLError
99 raise util.Abort(_('http error, possibly caused by proxy setting'))
99 raise util.Abort(_('http error, possibly caused by proxy setting'))
100 # record the url we got redirected to
100 # record the url we got redirected to
101 resp_url = resp.geturl()
101 resp_url = resp.geturl()
102 if resp_url.endswith(qs):
102 if resp_url.endswith(qs):
103 resp_url = resp_url[:-len(qs)]
103 resp_url = resp_url[:-len(qs)]
104 if self._url.rstrip('/') != resp_url.rstrip('/'):
104 if self._url.rstrip('/') != resp_url.rstrip('/'):
105 self.ui.status(_('real URL is %s\n') % resp_url)
105 self.ui.status(_('real URL is %s\n') % resp_url)
106 self._url = resp_url
106 self._url = resp_url
107 try:
107 try:
108 proto = resp.getheader('content-type')
108 proto = resp.getheader('content-type')
109 except AttributeError:
109 except AttributeError:
110 proto = resp.headers['content-type']
110 proto = resp.headers['content-type']
111
111
112 safeurl = url.hidepassword(self._url)
112 safeurl = url.hidepassword(self._url)
113 # accept old "text/plain" and "application/hg-changegroup" for now
113 # accept old "text/plain" and "application/hg-changegroup" for now
114 if not (proto.startswith('application/mercurial-') or
114 if not (proto.startswith('application/mercurial-') or
115 proto.startswith('text/plain') or
115 proto.startswith('text/plain') or
116 proto.startswith('application/hg-changegroup')):
116 proto.startswith('application/hg-changegroup')):
117 self.ui.debug("requested URL: '%s'\n" % url.hidepassword(cu))
117 self.ui.debug("requested URL: '%s'\n" % url.hidepassword(cu))
118 raise error.RepoError(
118 raise error.RepoError(
119 _("'%s' does not appear to be an hg repository:\n"
119 _("'%s' does not appear to be an hg repository:\n"
120 "---%%<--- (%s)\n%s\n---%%<---\n")
120 "---%%<--- (%s)\n%s\n---%%<---\n")
121 % (safeurl, proto, resp.read()))
121 % (safeurl, proto, resp.read()))
122
122
123 if proto.startswith('application/mercurial-'):
123 if proto.startswith('application/mercurial-'):
124 try:
124 try:
125 version = proto.split('-', 1)[1]
125 version = proto.split('-', 1)[1]
126 version_info = tuple([int(n) for n in version.split('.')])
126 version_info = tuple([int(n) for n in version.split('.')])
127 except ValueError:
127 except ValueError:
128 raise error.RepoError(_("'%s' sent a broken Content-Type "
128 raise error.RepoError(_("'%s' sent a broken Content-Type "
129 "header (%s)") % (safeurl, proto))
129 "header (%s)") % (safeurl, proto))
130 if version_info > (0, 1):
130 if version_info > (0, 1):
131 raise error.RepoError(_("'%s' uses newer protocol %s") %
131 raise error.RepoError(_("'%s' uses newer protocol %s") %
132 (safeurl, version))
132 (safeurl, version))
133
133
134 return resp
134 return resp
135
135
136 def _call(self, cmd, **args):
136 def _call(self, cmd, **args):
137 fp = self._callstream(cmd, **args)
137 fp = self._callstream(cmd, **args)
138 try:
138 try:
139 return fp.read()
139 return fp.read()
140 finally:
140 finally:
141 # if using keepalive, allow connection to be reused
141 # if using keepalive, allow connection to be reused
142 fp.close()
142 fp.close()
143
143
144 def _callpush(self, cmd, cg, **args):
144 def _callpush(self, cmd, cg, **args):
145 # have to stream bundle to a temp file because we do not have
145 # have to stream bundle to a temp file because we do not have
146 # http 1.1 chunked transfer.
146 # http 1.1 chunked transfer.
147
147
148 type = ""
148 type = ""
149 types = self.capable('unbundle')
149 types = self.capable('unbundle')
150 # servers older than d1b16a746db6 will send 'unbundle' as a
150 # servers older than d1b16a746db6 will send 'unbundle' as a
151 # boolean capability
151 # boolean capability
152 try:
152 try:
153 types = types.split(',')
153 types = types.split(',')
154 except AttributeError:
154 except AttributeError:
155 types = [""]
155 types = [""]
156 if types:
156 if types:
157 for x in types:
157 for x in types:
158 if x in changegroup.bundletypes:
158 if x in changegroup.bundletypes:
159 type = x
159 type = x
160 break
160 break
161
161
162 tempname = changegroup.writebundle(cg, None, type)
162 tempname = changegroup.writebundle(cg, None, type)
163 fp = url.httpsendfile(tempname, "rb")
163 fp = url.httpsendfile(tempname, "rb")
164 headers = {'Content-Type': 'application/mercurial-0.1'}
164 headers = {'Content-Type': 'application/mercurial-0.1'}
165
165
166 try:
166 try:
167 try:
167 try:
168 r = self._call(cmd, data=fp, headers=headers, **args)
168 r = self._call(cmd, data=fp, headers=headers, **args)
169 return r.split('\n', 1)
169 return r.split('\n', 1)
170 except socket.error, err:
170 except socket.error, err:
171 if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
171 if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
172 raise util.Abort(_('push failed: %s') % err.args[1])
172 raise util.Abort(_('push failed: %s') % err.args[1])
173 raise util.Abort(err.args[1])
173 raise util.Abort(err.args[1])
174 finally:
174 finally:
175 fp.close()
175 fp.close()
176 os.unlink(tempname)
176 os.unlink(tempname)
177
177
178 def _abort(self, exception):
178 def _abort(self, exception):
179 raise exception
179 raise exception
180
180
181 def _decompress(self, stream):
181 def _decompress(self, stream):
182 return util.chunkbuffer(zgenerator(stream))
182 return util.chunkbuffer(zgenerator(stream))
183
183
184 class httpsrepository(httprepository):
184 class httpsrepository(httprepository):
185 def __init__(self, ui, path):
185 def __init__(self, ui, path):
186 if not url.has_https:
186 if not url.has_https:
187 raise util.Abort(_('Python support for SSL and HTTPS '
187 raise util.Abort(_('Python support for SSL and HTTPS '
188 'is not installed'))
188 'is not installed'))
189 httprepository.__init__(self, ui, path)
189 httprepository.__init__(self, ui, path)
190
190
191 def instance(ui, path, create):
191 def instance(ui, path, create):
192 if create:
192 if create:
193 raise util.Abort(_('cannot create new http repository'))
193 raise util.Abort(_('cannot create new http repository'))
194 try:
194 try:
195 if path.startswith('https:'):
195 if path.startswith('https:'):
196 inst = httpsrepository(ui, path)
196 inst = httpsrepository(ui, path)
197 else:
197 else:
198 inst = httprepository(ui, path)
198 inst = httprepository(ui, path)
199 inst.between([(nullid, nullid)])
199 inst.between([(nullid, nullid)])
200 return inst
200 return inst
201 except error.RepoError:
201 except error.RepoError:
202 ui.note('(falling back to static-http)\n')
202 ui.note('(falling back to static-http)\n')
203 return statichttprepo.instance(ui, "static-" + path, create)
203 return statichttprepo.instance(ui, "static-" + path, create)
General Comments 0
You need to be logged in to leave comments. Login now