annotate mercurial/wireprotov2peer.py @ 40026:7e807b8a9e56

wireprotov2: client support for following content redirects And with the server actually sending content redirects, it is finally time to implement client support for following them! When a redirect response is seen, we wait until all data for that request has been received (it should be nearly immediate since no data is expected to follow the redirect message). Then we use a URL opener to make a request. We stuff that response into the client handler and construct a new response object to track it. When readdata() is called for servicing requests, we attempt to read data from the first redirected response. During data reading, data is processed similarly to as if it came from a frame payload. The existing test for the functionality demonstrates the client transparently following the redirect and obtaining the command response data from an alternate URL! There is still plenty of work to do here, including shoring up testing. I'm not convinced things will work in the presence of multiple redirect responses. And we don't yet implement support for integrity verification or configuring server certificates to validate the connection. But it's a start. And it should enable us to start experimenting with "real" caches. Differential Revision: https://phab.mercurial-scm.org/D4778
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 26 Sep 2018 18:08:08 -0700
parents 86b22a4cfab1
children cfeba1aafb9d
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
1 # wireprotov2peer.py - client side code for wire protocol version 2
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
2 #
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
4 #
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
5 # This software may be used and distributed according to the terms of the
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
6 # GNU General Public License version 2 or any later version.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
7
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
8 from __future__ import absolute_import
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
9
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
10 import threading
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
11
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
12 from .i18n import _
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
13 from . import (
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
14 encoding,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
15 error,
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
16 pycompat,
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
17 sslutil,
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
18 url as urlmod,
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
19 util,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
20 wireprotoframing,
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
21 wireprototypes,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
22 )
39450
9f51fd22ed50 wireprotov2peer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39438
diff changeset
23 from .utils import (
9f51fd22ed50 wireprotov2peer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39438
diff changeset
24 cborutil,
9f51fd22ed50 wireprotov2peer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39438
diff changeset
25 )
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
26
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
27 def formatrichmessage(atoms):
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
28 """Format an encoded message from the framing protocol."""
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
29
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
30 chunks = []
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
31
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
32 for atom in atoms:
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
33 msg = _(atom[b'msg'])
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
34
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
35 if b'args' in atom:
39486
43d92d68ac88 wireprotov2peer: properly format errors
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39485
diff changeset
36 msg = msg % tuple(atom[b'args'])
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
37
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
38 chunks.append(msg)
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
39
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
40 return b''.join(chunks)
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
41
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
42 SUPPORTED_REDIRECT_PROTOCOLS = {
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
43 b'http',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
44 b'https',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
45 }
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
46
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
47 SUPPORTED_CONTENT_HASHES = {
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
48 b'sha1',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
49 b'sha256',
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
50 }
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
51
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
52 def redirecttargetsupported(ui, target):
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
53 """Determine whether a redirect target entry is supported.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
54
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
55 ``target`` should come from the capabilities data structure emitted by
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
56 the server.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
57 """
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
58 if target.get(b'protocol') not in SUPPORTED_REDIRECT_PROTOCOLS:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
59 ui.note(_('(remote redirect target %s uses unsupported protocol: %s)\n')
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
60 % (target[b'name'], target.get(b'protocol', b'')))
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
61 return False
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
62
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
63 if target.get(b'snirequired') and not sslutil.hassni:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
64 ui.note(_('(redirect target %s requires SNI, which is unsupported)\n') %
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
65 target[b'name'])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
66 return False
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
67
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
68 if b'tlsversions' in target:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
69 tlsversions = set(target[b'tlsversions'])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
70 supported = set()
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
71
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
72 for v in sslutil.supportedprotocols:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
73 assert v.startswith(b'tls')
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
74 supported.add(v[3:])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
75
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
76 if not tlsversions & supported:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
77 ui.note(_('(remote redirect target %s requires unsupported TLS '
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
78 'versions: %s)\n') % (
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
79 target[b'name'], b', '.join(sorted(tlsversions))))
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
80 return False
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
81
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
82 ui.note(_('(remote redirect target %s is compatible)\n') % target[b'name'])
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
83
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
84 return True
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
85
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
86 def supportedredirects(ui, apidescriptor):
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
87 """Resolve the "redirect" command request key given an API descriptor.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
88
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
89 Given an API descriptor returned by the server, returns a data structure
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
90 that can be used in hte "redirect" field of command requests to advertise
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
91 support for compatible redirect targets.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
92
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
93 Returns None if no redirect targets are remotely advertised or if none are
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
94 supported.
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
95 """
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
96 if not apidescriptor or b'redirect' not in apidescriptor:
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
97 return None
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
98
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
99 targets = [t[b'name'] for t in apidescriptor[b'redirect'][b'targets']
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
100 if redirecttargetsupported(ui, t)]
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
101
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
102 hashes = [h for h in apidescriptor[b'redirect'][b'hashes']
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
103 if h in SUPPORTED_CONTENT_HASHES]
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
104
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
105 return {
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
106 b'targets': targets,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
107 b'hashes': hashes,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
108 }
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
109
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
110 class commandresponse(object):
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
111 """Represents the response to a command request.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
112
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
113 Instances track the state of the command and hold its results.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
114
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
115 An external entity is required to update the state of the object when
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
116 events occur.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
117 """
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
118
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
119 def __init__(self, requestid, command, fromredirect=False):
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
120 self.requestid = requestid
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
121 self.command = command
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
122 self.fromredirect = fromredirect
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
123
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
124 # Whether all remote input related to this command has been
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
125 # received.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
126 self._inputcomplete = False
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
127
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
128 # We have a lock that is acquired when important object state is
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
129 # mutated. This is to prevent race conditions between 1 thread
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
130 # sending us new data and another consuming it.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
131 self._lock = threading.RLock()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
132
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
133 # An event is set when state of the object changes. This event
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
134 # is waited on by the generator emitting objects.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
135 self._serviceable = threading.Event()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
136
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
137 self._pendingevents = []
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
138 self._decoder = cborutil.bufferingdecoder()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
139 self._seeninitial = False
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
140 self._redirect = None
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
141
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
142 def _oninputcomplete(self):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
143 with self._lock:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
144 self._inputcomplete = True
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
145 self._serviceable.set()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
146
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
147 def _onresponsedata(self, data):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
148 available, readcount, wanted = self._decoder.decode(data)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
149
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
150 if not available:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
151 return
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
152
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
153 with self._lock:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
154 for o in self._decoder.getavailable():
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
155 if not self._seeninitial and not self.fromredirect:
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
156 self._handleinitial(o)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
157 continue
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
158
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
159 # We should never see an object after a content redirect,
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
160 # as the spec says the main status object containing the
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
161 # content redirect is the only object in the stream. Fail
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
162 # if we see a misbehaving server.
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
163 if self._redirect:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
164 raise error.Abort(_('received unexpected response data '
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
165 'after content redirect; the remote is '
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
166 'buggy'))
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
167
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
168 self._pendingevents.append(o)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
169
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
170 self._serviceable.set()
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
171
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
172 def _handleinitial(self, o):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
173 self._seeninitial = True
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
174 if o[b'status'] == b'ok':
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
175 return
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
176
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
177 elif o[b'status'] == b'redirect':
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
178 l = o[b'location']
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
179 self._redirect = wireprototypes.alternatelocationresponse(
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
180 url=l[b'url'],
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
181 mediatype=l[b'mediatype'],
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
182 size=l.get(b'size'),
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
183 fullhashes=l.get(b'fullhashes'),
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
184 fullhashseed=l.get(b'fullhashseed'),
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
185 serverdercerts=l.get(b'serverdercerts'),
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
186 servercadercerts=l.get(b'servercadercerts'))
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
187 return
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
188
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
189 atoms = [{'msg': o[b'error'][b'message']}]
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
190 if b'args' in o[b'error']:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
191 atoms[0]['args'] = o[b'error'][b'args']
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
192
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
193 raise error.RepoError(formatrichmessage(atoms))
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
194
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
195 def objects(self):
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
196 """Obtained decoded objects from this response.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
197
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
198 This is a generator of data structures that were decoded from the
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
199 command response.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
200
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
201 Obtaining the next member of the generator may block due to waiting
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
202 on external data to become available.
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
203
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
204 If the server encountered an error in the middle of serving the data
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
205 or if another error occurred, an exception may be raised when
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
206 advancing the generator.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
207 """
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
208 while True:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
209 # TODO this can infinite loop if self._inputcomplete is never
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
210 # set. We likely want to tie the lifetime of this object/state
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
211 # to that of the background thread receiving frames and updating
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
212 # our state.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
213 self._serviceable.wait(1.0)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
214
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
215 with self._lock:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
216 self._serviceable.clear()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
217
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
218 # Make copies because objects could be mutated during
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
219 # iteration.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
220 stop = self._inputcomplete
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
221 pending = list(self._pendingevents)
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
222 self._pendingevents[:] = []
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
223
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
224 for o in pending:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
225 yield o
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
226
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
227 if stop:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
228 break
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
229
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
230 class clienthandler(object):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
231 """Object to handle higher-level client activities.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
232
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
233 The ``clientreactor`` is used to hold low-level state about the frame-based
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
234 protocol, such as which requests and streams are active. This type is used
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
235 for higher-level operations, such as reading frames from a socket, exposing
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
236 and managing a higher-level primitive for representing command responses,
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
237 etc. This class is what peers should probably use to bridge wire activity
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
238 with the higher-level peer API.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
239 """
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
240
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
241 def __init__(self, ui, clientreactor, opener=None,
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
242 requestbuilder=util.urlreq.request):
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
243 self._ui = ui
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
244 self._reactor = clientreactor
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
245 self._requests = {}
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
246 self._futures = {}
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
247 self._responses = {}
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
248 self._redirects = []
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
249 self._frameseof = False
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
250 self._opener = opener or urlmod.opener(ui)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
251 self._requestbuilder = requestbuilder
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
252
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
253 def callcommand(self, command, args, f, redirect=None):
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
254 """Register a request to call a command.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
255
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
256 Returns an iterable of frames that should be sent over the wire.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
257 """
40024
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
258 request, action, meta = self._reactor.callcommand(command, args,
86b22a4cfab1 wireprotov2: client support for advertising redirect targets
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40019
diff changeset
259 redirect=redirect)
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
260
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
261 if action != 'noop':
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
262 raise error.ProgrammingError('%s not yet supported' % action)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
263
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
264 rid = request.requestid
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
265 self._requests[rid] = request
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
266 self._futures[rid] = f
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
267 # TODO we need some kind of lifetime on response instances otherwise
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
268 # objects() may deadlock.
37720
d715a85003c8 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37719
diff changeset
269 self._responses[rid] = commandresponse(rid, command)
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
270
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
271 return iter(())
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
272
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
273 def flushcommands(self):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
274 """Flush all queued commands.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
275
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
276 Returns an iterable of frames that should be sent over the wire.
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
277 """
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
278 action, meta = self._reactor.flushcommands()
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
279
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
280 if action != 'sendframes':
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
281 raise error.ProgrammingError('%s not yet supported' % action)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
282
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
283 return meta['framegen']
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
284
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
285 def readdata(self, framefh):
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
286 """Attempt to read data and do work.
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
287
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
288 Returns None if no data was read. Presumably this means we're
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
289 done with all read I/O.
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
290 """
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
291 if not self._frameseof:
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
292 frame = wireprotoframing.readframe(framefh)
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
293 if frame is None:
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
294 # TODO tell reactor?
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
295 self._frameseof = True
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
296 else:
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
297 self._ui.note(_('received %r\n') % frame)
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
298 self._processframe(frame)
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
299
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
300 # Also try to read the first redirect.
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
301 if self._redirects:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
302 if not self._processredirect(*self._redirects[0]):
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
303 self._redirects.pop(0)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
304
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
305 if self._frameseof and not self._redirects:
40019
f5a05bb48116 wireprotov2: change name and behavior of readframe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39561
diff changeset
306 return None
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
307
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
308 return True
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
309
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
310 def _processframe(self, frame):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
311 """Process a single read frame."""
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
312
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
313 action, meta = self._reactor.onframerecv(frame)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
314
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
315 if action == 'error':
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
316 e = error.RepoError(meta['message'])
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
317
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
318 if frame.requestid in self._responses:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
319 self._responses[frame.requestid]._oninputcomplete()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
320
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
321 if frame.requestid in self._futures:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
322 self._futures[frame.requestid].set_exception(e)
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
323 del self._futures[frame.requestid]
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
324 else:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
325 raise e
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
326
39559
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39486
diff changeset
327 return
07b58266bce3 wireprotov2: implement commands as a generator of objects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39486
diff changeset
328
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
329 if frame.requestid not in self._requests:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
330 raise error.ProgrammingError(
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
331 'received frame for unknown request; this is either a bug in '
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
332 'the clientreactor not screening for this or this instance was '
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
333 'never told about this request: %r' % frame)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
334
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
335 response = self._responses[frame.requestid]
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
336
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
337 if action == 'responsedata':
39485
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
338 # Any failures processing this frame should bubble up to the
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
339 # future tracking the request.
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
340 try:
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
341 self._processresponsedata(frame, meta, response)
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
342 except BaseException as e:
42bc1c70a6b8 wireprotov2peer: report exceptions in frame handling against request future
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39450
diff changeset
343 self._futures[frame.requestid].set_exception(e)
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
344 del self._futures[frame.requestid]
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
345 response._oninputcomplete()
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
346 else:
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
347 raise error.ProgrammingError(
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
348 'unhandled action from clientreactor: %s' % action)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
349
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
350 def _processresponsedata(self, frame, meta, response):
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
351 # This can raise. The caller can handle it.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
352 response._onresponsedata(meta['data'])
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
353
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
354 # If we got a content redirect response, we want to fetch it and
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
355 # expose the data as if we received it inline. But we also want to
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
356 # keep our internal request accounting in order. Our strategy is to
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
357 # basically put meaningful response handling on pause until EOS occurs
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
358 # and the stream accounting is in a good state. At that point, we follow
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
359 # the redirect and replace the response object with its data.
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
360
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
361 redirect = response._redirect
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
362 handlefuture = False if redirect else True
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
363
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
364 if meta['eos']:
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
365 response._oninputcomplete()
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
366 del self._requests[frame.requestid]
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
367
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
368 if redirect:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
369 self._followredirect(frame.requestid, redirect)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
370 return
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
371
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
372 if not handlefuture:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
373 return
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
374
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
375 # If the command has a decoder, we wait until all input has been
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
376 # received before resolving the future. Otherwise we resolve the
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
377 # future immediately.
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
378 if frame.requestid not in self._futures:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
379 return
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
380
39561
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
381 if response.command not in COMMAND_DECODERS:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
382 self._futures[frame.requestid].set_result(response.objects())
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
383 del self._futures[frame.requestid]
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
384 elif response._inputcomplete:
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
385 decoded = COMMAND_DECODERS[response.command](response.objects())
d06834e0f48e wireprotov2peer: stream decoded responses
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39559
diff changeset
386 self._futures[frame.requestid].set_result(decoded)
39438
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
387 del self._futures[frame.requestid]
c734a5c82f38 wireprotov2peer: split responsedata handling into separate function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39435
diff changeset
388
40026
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
389 def _followredirect(self, requestid, redirect):
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
390 """Called to initiate redirect following for a request."""
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
391 self._ui.note(_('(following redirect to %s)\n') % redirect.url)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
392
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
393 # TODO handle framed responses.
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
394 if redirect.mediatype != b'application/mercurial-cbor':
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
395 raise error.Abort(_('cannot handle redirects for the %s media type')
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
396 % redirect.mediatype)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
397
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
398 if redirect.fullhashes:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
399 self._ui.warn(_('(support for validating hashes on content '
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
400 'redirects not supported)\n'))
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
401
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
402 if redirect.serverdercerts or redirect.servercadercerts:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
403 self._ui.warn(_('(support for pinning server certificates on '
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
404 'content redirects not supported)\n'))
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
405
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
406 headers = {
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
407 r'Accept': redirect.mediatype,
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
408 }
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
409
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
410 req = self._requestbuilder(pycompat.strurl(redirect.url), None, headers)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
411
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
412 try:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
413 res = self._opener.open(req)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
414 except util.urlerr.httperror as e:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
415 if e.code == 401:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
416 raise error.Abort(_('authorization failed'))
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
417 raise
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
418 except util.httplib.HTTPException as e:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
419 self._ui.debug('http error requesting %s\n' % req.get_full_url())
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
420 self._ui.traceback()
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
421 raise IOError(None, e)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
422
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
423 urlmod.wrapresponse(res)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
424
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
425 # The existing response object is associated with frame data. Rather
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
426 # than try to normalize its state, just create a new object.
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
427 oldresponse = self._responses[requestid]
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
428 self._responses[requestid] = commandresponse(requestid,
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
429 oldresponse.command,
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
430 fromredirect=True)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
431
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
432 self._redirects.append((requestid, res))
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
433
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
434 def _processredirect(self, rid, res):
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
435 """Called to continue processing a response from a redirect."""
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
436 response = self._responses[rid]
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
437
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
438 try:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
439 data = res.read(32768)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
440 response._onresponsedata(data)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
441
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
442 # We're at end of stream.
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
443 if not data:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
444 response._oninputcomplete()
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
445
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
446 if rid not in self._futures:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
447 return
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
448
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
449 if response.command not in COMMAND_DECODERS:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
450 self._futures[rid].set_result(response.objects())
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
451 del self._futures[rid]
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
452 elif response._inputcomplete:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
453 decoded = COMMAND_DECODERS[response.command](response.objects())
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
454 self._futures[rid].set_result(decoded)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
455 del self._futures[rid]
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
456
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
457 return bool(data)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
458
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
459 except BaseException as e:
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
460 self._futures[rid].set_exception(e)
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
461 del self._futures[rid]
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
462 response._oninputcomplete()
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
463 return False
7e807b8a9e56 wireprotov2: client support for following content redirects
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40024
diff changeset
464
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
465 def decodebranchmap(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
466 # Response should be a single CBOR map of branch name to array of nodes.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
467 bm = next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
468
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
469 return {encoding.tolocal(k): v for k, v in bm.items()}
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
470
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
471 def decodeheads(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
472 # Array of node bytestrings.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
473 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
474
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
475 def decodeknown(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
476 # Bytestring where each byte is a 0 or 1.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
477 raw = next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
478
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
479 return [True if c == '1' else False for c in raw]
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
480
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
481 def decodelistkeys(objs):
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
482 # Map with bytestring keys and values.
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
483 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
484
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
485 def decodelookup(objs):
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
486 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
487
37725
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
488 def decodepushkey(objs):
3ea8323d6f95 wireprotov2: change command response protocol to include a leading map
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
489 return next(objs)
37721
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
490
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
491 COMMAND_DECODERS = {
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
492 'branchmap': decodebranchmap,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
493 'heads': decodeheads,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
494 'known': decodeknown,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
495 'listkeys': decodelistkeys,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
496 'lookup': decodelookup,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
497 'pushkey': decodepushkey,
f7673845b167 wireprotov2: decode responses to their expected types
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37720
diff changeset
498 }