Peer instances are supposed to conform to a well-defined API so
consumers can be agnostic about the underlying peer type.
To reinforce this, this commit renames a handful of instance
attributes on httpeer so they no longer have a "public" name.
| hg-reviewers |
Peer instances are supposed to conform to a well-defined API so
consumers can be agnostic about the underlying peer type.
To reinforce this, this commit renames a handful of instance
attributes on httpeer so they no longer have a "public" name.
| Automatic diff as part of commit; lint not applicable. |
| Automatic diff as part of commit; unit tests not applicable. |
| hint=_('this may be an intermittent network failure; ' | hint=_('this may be an intermittent network failure; ' | ||||
| 'if the error persists, consider contacting the ' | 'if the error persists, consider contacting the ' | ||||
| 'network or server operator')) | 'network or server operator')) | ||||
| resp.__class__ = readerproxy | resp.__class__ = readerproxy | ||||
| class httppeer(wireproto.wirepeer): | class httppeer(wireproto.wirepeer): | ||||
| def __init__(self, ui, path): | def __init__(self, ui, path): | ||||
| self.path = path | self._path = path | ||||
| self.caps = None | self._caps = None | ||||
| self.urlopener = None | self._urlopener = None | ||||
| self.requestbuilder = None | self._requestbuilder = None | ||||
| u = util.url(path) | u = util.url(path) | ||||
| if u.query or u.fragment: | if u.query or u.fragment: | ||||
| raise error.Abort(_('unsupported URL component: "%s"') % | raise error.Abort(_('unsupported URL component: "%s"') % | ||||
| (u.query or u.fragment)) | (u.query or u.fragment)) | ||||
| # urllib cannot handle URLs with embedded user or passwd | # urllib cannot handle URLs with embedded user or passwd | ||||
| self._url, authinfo = u.authinfo() | self._url, authinfo = u.authinfo() | ||||
| self.ui = ui | self.ui = ui | ||||
| self.ui.debug('using %s\n' % self._url) | self.ui.debug('using %s\n' % self._url) | ||||
| self.urlopener = url.opener(ui, authinfo) | self._urlopener = url.opener(ui, authinfo) | ||||
| self.requestbuilder = urlreq.request | self._requestbuilder = urlreq.request | ||||
| def __del__(self): | def __del__(self): | ||||
| urlopener = getattr(self, 'urlopener', None) | urlopener = getattr(self, '_urlopener', None) | ||||
| if urlopener: | if urlopener: | ||||
| for h in urlopener.handlers: | for h in urlopener.handlers: | ||||
| h.close() | h.close() | ||||
| getattr(h, "close_all", lambda : None)() | getattr(h, "close_all", lambda : None)() | ||||
| def url(self): | def url(self): | ||||
| return self.path | return self._path | ||||
| # look up capabilities only when needed | # look up capabilities only when needed | ||||
| def _fetchcaps(self): | def _fetchcaps(self): | ||||
| self.caps = set(self._call('capabilities').split()) | self._caps = set(self._call('capabilities').split()) | ||||
| def _capabilities(self): | def _capabilities(self): | ||||
| if self.caps is None: | if self._caps is None: | ||||
| try: | try: | ||||
| self._fetchcaps() | self._fetchcaps() | ||||
| except error.RepoError: | except error.RepoError: | ||||
| self.caps = set() | self._caps = set() | ||||
| self.ui.debug('capabilities: %s\n' % | self.ui.debug('capabilities: %s\n' % | ||||
| (' '.join(self.caps or ['none']))) | (' '.join(self._caps or ['none']))) | ||||
| return self.caps | return self._caps | ||||
| def _callstream(self, cmd, _compressible=False, **args): | def _callstream(self, cmd, _compressible=False, **args): | ||||
| if cmd == 'pushkey': | if cmd == 'pushkey': | ||||
| args['data'] = '' | args['data'] = '' | ||||
| data = args.pop('data', None) | data = args.pop('data', None) | ||||
| headers = args.pop('headers', {}) | headers = args.pop('headers', {}) | ||||
| self.ui.debug("sending %s command\n" % cmd) | self.ui.debug("sending %s command\n" % cmd) | ||||
| q = [('cmd', cmd)] | q = [('cmd', cmd)] | ||||
| headersize = 0 | headersize = 0 | ||||
| varyheaders = [] | varyheaders = [] | ||||
| # Important: don't use self.capable() here or else you end up | # Important: don't use self.capable() here or else you end up | ||||
| # with infinite recursion when trying to look up capabilities | # with infinite recursion when trying to look up capabilities | ||||
| # for the first time. | # for the first time. | ||||
| postargsok = self.caps is not None and 'httppostargs' in self.caps | postargsok = self._caps is not None and 'httppostargs' in self._caps | ||||
| # TODO: support for httppostargs when data is a file-like | # TODO: support for httppostargs when data is a file-like | ||||
| # object rather than a basestring | # object rather than a basestring | ||||
| canmungedata = not data or isinstance(data, basestring) | canmungedata = not data or isinstance(data, basestring) | ||||
| if postargsok and canmungedata: | if postargsok and canmungedata: | ||||
| strargs = urlreq.urlencode(sorted(args.items())) | strargs = urlreq.urlencode(sorted(args.items())) | ||||
| if strargs: | if strargs: | ||||
| if not data: | if not data: | ||||
| data = strargs | data = strargs | ||||
| headers['Content-Type'] = 'application/mercurial-0.1' | headers['Content-Type'] = 'application/mercurial-0.1' | ||||
| # Tell the server we accept application/mercurial-0.2 and multiple | # Tell the server we accept application/mercurial-0.2 and multiple | ||||
| # compression formats if the server is capable of emitting those | # compression formats if the server is capable of emitting those | ||||
| # payloads. | # payloads. | ||||
| protoparams = [] | protoparams = [] | ||||
| mediatypes = set() | mediatypes = set() | ||||
| if self.caps is not None: | if self._caps is not None: | ||||
| mt = self.capable('httpmediatype') | mt = self.capable('httpmediatype') | ||||
| if mt: | if mt: | ||||
| protoparams.append('0.1') | protoparams.append('0.1') | ||||
| mediatypes = set(mt.split(',')) | mediatypes = set(mt.split(',')) | ||||
| if '0.2tx' in mediatypes: | if '0.2tx' in mediatypes: | ||||
| protoparams.append('0.2') | protoparams.append('0.2') | ||||
| headersize or 1024) | headersize or 1024) | ||||
| for header, value in protoheaders: | for header, value in protoheaders: | ||||
| headers[header] = value | headers[header] = value | ||||
| varyheaders.append(header) | varyheaders.append(header) | ||||
| if varyheaders: | if varyheaders: | ||||
| headers['Vary'] = ','.join(varyheaders) | headers['Vary'] = ','.join(varyheaders) | ||||
| req = self.requestbuilder(cu, data, headers) | req = self._requestbuilder(cu, data, headers) | ||||
| if data is not None: | if data is not None: | ||||
| self.ui.debug("sending %s bytes\n" % size) | self.ui.debug("sending %s bytes\n" % size) | ||||
| req.add_unredirected_header('Content-Length', '%d' % size) | req.add_unredirected_header('Content-Length', '%d' % size) | ||||
| try: | try: | ||||
| resp = self.urlopener.open(req) | resp = self._urlopener.open(req) | ||||
| except urlerr.httperror as inst: | except urlerr.httperror as inst: | ||||
| if inst.code == 401: | if inst.code == 401: | ||||
| raise error.Abort(_('authorization failed')) | raise error.Abort(_('authorization failed')) | ||||
| raise | raise | ||||
| except httplib.HTTPException as inst: | except httplib.HTTPException as inst: | ||||
| self.ui.debug('http error while sending %s command\n' % cmd) | self.ui.debug('http error while sending %s command\n' % cmd) | ||||
| self.ui.traceback() | self.ui.traceback() | ||||
| raise IOError(None, inst) | raise IOError(None, inst) | ||||