comparison mercurial/wireprotoframing.py @ 40024:86b22a4cfab1

wireprotov2: client support for advertising redirect targets With the server now able to emit a redirect target descriptor, we can start to teach the client to recognize it. This commit implements support for filtering the advertised redirect targets against supported features and for advertising compatible redirect targets as part of command requests. It also adds the minimal boilerplate required to fail when a content redirect is seen. The server doesn't yet do anything with the advertised redirect targets. And the client can't yet follow redirects if it did. But at least we're putting bytes on the wire. Differential Revision: https://phab.mercurial-scm.org/D4776
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 26 Sep 2018 15:02:19 -0700
parents ed919b90acda
children b099e6032f38
comparison
equal deleted inserted replaced
40023:10cf8b116dd8 40024:86b22a4cfab1
278 278
279 return frame(h.requestid, h.streamid, h.streamflags, h.typeid, h.flags, 279 return frame(h.requestid, h.streamid, h.streamflags, h.typeid, h.flags,
280 payload) 280 payload)
281 281
282 def createcommandframes(stream, requestid, cmd, args, datafh=None, 282 def createcommandframes(stream, requestid, cmd, args, datafh=None,
283 maxframesize=DEFAULT_MAX_FRAME_SIZE): 283 maxframesize=DEFAULT_MAX_FRAME_SIZE,
284 redirect=None):
284 """Create frames necessary to transmit a request to run a command. 285 """Create frames necessary to transmit a request to run a command.
285 286
286 This is a generator of bytearrays. Each item represents a frame 287 This is a generator of bytearrays. Each item represents a frame
287 ready to be sent over the wire to a peer. 288 ready to be sent over the wire to a peer.
288 """ 289 """
289 data = {b'name': cmd} 290 data = {b'name': cmd}
290 if args: 291 if args:
291 data[b'args'] = args 292 data[b'args'] = args
293
294 if redirect:
295 data[b'redirect'] = redirect
292 296
293 data = b''.join(cborutil.streamencode(data)) 297 data = b''.join(cborutil.streamencode(data))
294 298
295 offset = 0 299 offset = 0
296 300
1133 return self._makeerrorresult(_('server already errored')) 1137 return self._makeerrorresult(_('server already errored'))
1134 1138
1135 class commandrequest(object): 1139 class commandrequest(object):
1136 """Represents a request to run a command.""" 1140 """Represents a request to run a command."""
1137 1141
1138 def __init__(self, requestid, name, args, datafh=None): 1142 def __init__(self, requestid, name, args, datafh=None, redirect=None):
1139 self.requestid = requestid 1143 self.requestid = requestid
1140 self.name = name 1144 self.name = name
1141 self.args = args 1145 self.args = args
1142 self.datafh = datafh 1146 self.datafh = datafh
1147 self.redirect = redirect
1143 self.state = 'pending' 1148 self.state = 'pending'
1144 1149
1145 class clientreactor(object): 1150 class clientreactor(object):
1146 """Holds state of a client issuing frame-based protocol requests. 1151 """Holds state of a client issuing frame-based protocol requests.
1147 1152
1176 self._outgoingstream = stream(1) 1181 self._outgoingstream = stream(1)
1177 self._pendingrequests = collections.deque() 1182 self._pendingrequests = collections.deque()
1178 self._activerequests = {} 1183 self._activerequests = {}
1179 self._incomingstreams = {} 1184 self._incomingstreams = {}
1180 1185
1181 def callcommand(self, name, args, datafh=None): 1186 def callcommand(self, name, args, datafh=None, redirect=None):
1182 """Request that a command be executed. 1187 """Request that a command be executed.
1183 1188
1184 Receives the command name, a dict of arguments to pass to the command, 1189 Receives the command name, a dict of arguments to pass to the command,
1185 and an optional file object containing the raw data for the command. 1190 and an optional file object containing the raw data for the command.
1186 1191
1190 raise error.ProgrammingError('cannot issue new commands') 1195 raise error.ProgrammingError('cannot issue new commands')
1191 1196
1192 requestid = self._nextrequestid 1197 requestid = self._nextrequestid
1193 self._nextrequestid += 2 1198 self._nextrequestid += 2
1194 1199
1195 request = commandrequest(requestid, name, args, datafh=datafh) 1200 request = commandrequest(requestid, name, args, datafh=datafh,
1201 redirect=redirect)
1196 1202
1197 if self._buffersends: 1203 if self._buffersends:
1198 self._pendingrequests.append(request) 1204 self._pendingrequests.append(request)
1199 return request, 'noop', {} 1205 return request, 'noop', {}
1200 else: 1206 else:
1254 1260
1255 res = createcommandframes(self._outgoingstream, 1261 res = createcommandframes(self._outgoingstream,
1256 request.requestid, 1262 request.requestid,
1257 request.name, 1263 request.name,
1258 request.args, 1264 request.args,
1259 request.datafh) 1265 datafh=request.datafh,
1266 redirect=request.redirect)
1260 1267
1261 for frame in res: 1268 for frame in res:
1262 yield frame 1269 yield frame
1263 1270
1264 request.state = 'sent' 1271 request.state = 'sent'