##// END OF EJS Templates
wireprotov2: server support for sending content redirects...
Gregory Szorc -
r40061:b099e603 default
parent child Browse files
Show More
@@ -21,6 +21,7 b' from .thirdparty import ('
21 from . import (
21 from . import (
22 encoding,
22 encoding,
23 error,
23 error,
24 pycompat,
24 util,
25 util,
25 wireprototypes,
26 wireprototypes,
26 )
27 )
@@ -429,6 +430,26 b' def createcommandresponseeosframe(stream'
429 flags=FLAG_COMMAND_RESPONSE_EOS,
430 flags=FLAG_COMMAND_RESPONSE_EOS,
430 payload=b'')
431 payload=b'')
431
432
433 def createalternatelocationresponseframe(stream, requestid, location):
434 data = {
435 b'status': b'redirect',
436 b'location': {
437 b'url': location.url,
438 b'mediatype': location.mediatype,
439 }
440 }
441
442 for a in (r'size', r'fullhashes', r'fullhashseed', r'serverdercerts',
443 r'servercadercerts'):
444 value = getattr(location, a)
445 if value is not None:
446 data[b'location'][pycompat.bytestr(a)] = value
447
448 return stream.makeframe(requestid=requestid,
449 typeid=FRAME_TYPE_COMMAND_RESPONSE,
450 flags=FLAG_COMMAND_RESPONSE_CONTINUATION,
451 payload=b''.join(cborutil.streamencode(data)))
452
432 def createcommanderrorresponse(stream, requestid, message, args=None):
453 def createcommanderrorresponse(stream, requestid, message, args=None):
433 # TODO should this be using a list of {'msg': ..., 'args': {}} so atom
454 # TODO should this be using a list of {'msg': ..., 'args': {}} so atom
434 # formatting works consistently?
455 # formatting works consistently?
@@ -813,6 +834,7 b' class serverreactor(object):'
813
834
814 def sendframes():
835 def sendframes():
815 emitted = False
836 emitted = False
837 alternatelocationsent = False
816 emitter = bufferingcommandresponseemitter(stream, requestid)
838 emitter = bufferingcommandresponseemitter(stream, requestid)
817 while True:
839 while True:
818 try:
840 try:
@@ -841,6 +863,25 b' class serverreactor(object):'
841 break
863 break
842
864
843 try:
865 try:
866 # Alternate location responses can only be the first and
867 # only object in the output stream.
868 if isinstance(o, wireprototypes.alternatelocationresponse):
869 if emitted:
870 raise error.ProgrammingError(
871 'alternatelocationresponse seen after initial '
872 'output object')
873
874 yield createalternatelocationresponseframe(
875 stream, requestid, o)
876
877 alternatelocationsent = True
878 emitted = True
879 continue
880
881 if alternatelocationsent:
882 raise error.ProgrammingError(
883 'object follows alternatelocationresponse')
884
844 if not emitted:
885 if not emitted:
845 yield createcommandresponseokframe(stream, requestid)
886 yield createcommandresponseokframe(stream, requestid)
846 emitted = True
887 emitted = True
@@ -977,6 +1018,7 b' class serverreactor(object):'
977 'requestid': requestid,
1018 'requestid': requestid,
978 'command': request[b'name'],
1019 'command': request[b'name'],
979 'args': request[b'args'],
1020 'args': request[b'args'],
1021 'redirect': request.get(b'redirect'),
980 'data': entry['data'].getvalue() if entry['data'] else None,
1022 'data': entry['data'].getvalue() if entry['data'] else None,
981 }
1023 }
982
1024
@@ -368,3 +368,20 b' class encodedresponse(object):'
368 and the content from this object is used instead.
368 and the content from this object is used instead.
369 """
369 """
370 data = attr.ib()
370 data = attr.ib()
371
372 @attr.s
373 class alternatelocationresponse(object):
374 """Represents a response available at an alternate location.
375
376 Instances are sent in place of actual response objects when the server
377 is sending a "content redirect" response.
378
379 Only compatible with wire protocol version 2.
380 """
381 url = attr.ib()
382 mediatype = attr.ib()
383 size = attr.ib(default=None)
384 fullhashes = attr.ib(default=None)
385 fullhashseed = attr.ib(default=None)
386 serverdercerts = attr.ib(default=None)
387 servercadercerts = attr.ib(default=None)
@@ -312,7 +312,7 b' def _httpv2runcommand(ui, repo, req, res'
312 res.headers[b'Content-Type'] = FRAMINGTYPE
312 res.headers[b'Content-Type'] = FRAMINGTYPE
313
313
314 try:
314 try:
315 objs = dispatch(repo, proto, command['command'])
315 objs = dispatch(repo, proto, command['command'], command['redirect'])
316
316
317 action, meta = reactor.oncommandresponsereadyobjects(
317 action, meta = reactor.oncommandresponsereadyobjects(
318 outstream, command['requestid'], objs)
318 outstream, command['requestid'], objs)
@@ -339,7 +339,7 b' def _httpv2runcommand(ui, repo, req, res'
339 def getdispatchrepo(repo, proto, command):
339 def getdispatchrepo(repo, proto, command):
340 return repo.filtered('served')
340 return repo.filtered('served')
341
341
342 def dispatch(repo, proto, command):
342 def dispatch(repo, proto, command, redirect):
343 """Run a wire protocol command.
343 """Run a wire protocol command.
344
344
345 Returns an iterable of objects that will be sent to the client.
345 Returns an iterable of objects that will be sent to the client.
@@ -364,8 +364,17 b' def dispatch(repo, proto, command):'
364 yield o
364 yield o
365 return
365 return
366
366
367 if redirect:
368 redirecttargets = redirect[b'targets']
369 redirecthashes = redirect[b'hashes']
370 else:
371 redirecttargets = []
372 redirecthashes = []
373
367 cacher = makeresponsecacher(repo, proto, command, args,
374 cacher = makeresponsecacher(repo, proto, command, args,
368 cborutil.streamencode)
375 cborutil.streamencode,
376 redirecttargets=redirecttargets,
377 redirecthashes=redirecthashes)
369
378
370 # But we have no cacher. Do default handling.
379 # But we have no cacher. Do default handling.
371 if not cacher:
380 if not cacher:
@@ -751,7 +760,8 b' def makecommandcachekeyfn(command, local'
751
760
752 return cachekeyfn
761 return cachekeyfn
753
762
754 def makeresponsecacher(repo, proto, command, args, objencoderfn):
763 def makeresponsecacher(repo, proto, command, args, objencoderfn,
764 redirecttargets, redirecthashes):
755 """Construct a cacher for a cacheable command.
765 """Construct a cacher for a cacheable command.
756
766
757 Returns an ``iwireprotocolcommandcacher`` instance.
767 Returns an ``iwireprotocolcommandcacher`` instance.
@@ -430,10 +430,10 b' Command frames can be reflected via debu'
430 s> Server: testing stub value\r\n
430 s> Server: testing stub value\r\n
431 s> Date: $HTTP_DATE$\r\n
431 s> Date: $HTTP_DATE$\r\n
432 s> Content-Type: text/plain\r\n
432 s> Content-Type: text/plain\r\n
433 s> Content-Length: 205\r\n
433 s> Content-Length: 223\r\n
434 s> \r\n
434 s> \r\n
435 s> received: 1 1 1 \xa2Dargs\xa2Dbar1CvalCfooDval1DnameHcommand1\n
435 s> received: 1 1 1 \xa2Dargs\xa2Dbar1CvalCfooDval1DnameHcommand1\n
436 s> ["runcommand", {"args": {"bar1": "val", "foo": "val1"}, "command": "command1", "data": null, "requestid": 1}]\n
436 s> ["runcommand", {"args": {"bar1": "val", "foo": "val1"}, "command": "command1", "data": null, "redirect": null, "requestid": 1}]\n
437 s> received: <no frame>\n
437 s> received: <no frame>\n
438 s> {"action": "noop"}
438 s> {"action": "noop"}
439
439
@@ -1,11 +1,20 b''
1 $ . $TESTDIR/wireprotohelpers.sh
1 $ . $TESTDIR/wireprotohelpers.sh
2
2
3 $ cat >> $HGRCPATH << EOF
4 > [extensions]
5 > blackbox =
6 > [blackbox]
7 > track = simplecache
8 > EOF
9
3 $ hg init server
10 $ hg init server
4 $ enablehttpv2 server
11 $ enablehttpv2 server
5 $ cd server
12 $ cd server
6 $ cat >> .hg/hgrc << EOF
13 $ cat >> .hg/hgrc << EOF
7 > [extensions]
14 > [extensions]
8 > simplecache = $TESTDIR/wireprotosimplecache.py
15 > simplecache = $TESTDIR/wireprotosimplecache.py
16 > [simplecache]
17 > cacheapi = true
9 > EOF
18 > EOF
10
19
11 $ echo a0 > a
20 $ echo a0 > a
@@ -1183,5 +1192,178 b' Unknown tls value is filtered from compa'
1183 }
1192 }
1184 ]
1193 ]
1185
1194
1195 Set up the server to issue content redirects to its built-in API server.
1196
1197 $ cat > redirects.py << EOF
1198 > [
1199 > {
1200 > b'name': b'local',
1201 > b'protocol': b'http',
1202 > b'uris': [b'http://example.com/'],
1203 > },
1204 > ]
1205 > EOF
1206
1207 Request to eventual cache URL should return 404 (validating the cache server works)
1208
1209 $ sendhttpraw << EOF
1210 > httprequest GET api/simplecache/missingkey
1211 > user-agent: test
1212 > EOF
1213 using raw connection to peer
1214 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1215 s> Accept-Encoding: identity\r\n
1216 s> user-agent: test\r\n
1217 s> host: $LOCALIP:$HGPORT\r\n (glob)
1218 s> \r\n
1219 s> makefile('rb', None)
1220 s> HTTP/1.1 404 Not Found\r\n
1221 s> Server: testing stub value\r\n
1222 s> Date: $HTTP_DATE$\r\n
1223 s> Content-Type: text/plain\r\n
1224 s> Content-Length: 22\r\n
1225 s> \r\n
1226 s> key not found in cache
1227
1228 Send a cacheable request
1229
1230 $ sendhttpv2peer << EOF
1231 > command manifestdata
1232 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1233 > tree eval:b''
1234 > fields eval:[b'parents']
1235 > EOF
1236 creating http peer for wire protocol version 2
1237 sending manifestdata command
1238 s> POST /api/exp-http-v2-0002/ro/manifestdata HTTP/1.1\r\n
1239 s> Accept-Encoding: identity\r\n
1240 s> accept: application/mercurial-exp-framing-0005\r\n
1241 s> content-type: application/mercurial-exp-framing-0005\r\n
1242 s> content-length: 128\r\n
1243 s> host: $LOCALIP:$HGPORT\r\n (glob)
1244 s> user-agent: Mercurial debugwireproto\r\n
1245 s> \r\n
1246 s> x\x00\x00\x01\x00\x01\x01\x11\xa3Dargs\xa3Ffields\x81GparentsEnodes\x81T\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&ADtree@DnameLmanifestdataHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Elocal
1247 s> makefile('rb', None)
1248 s> HTTP/1.1 200 OK\r\n
1249 s> Server: testing stub value\r\n
1250 s> Date: $HTTP_DATE$\r\n
1251 s> Content-Type: application/mercurial-exp-framing-0005\r\n
1252 s> Transfer-Encoding: chunked\r\n
1253 s> \r\n
1254 s> 13\r\n
1255 s> \x0b\x00\x00\x01\x00\x02\x011
1256 s> \xa1FstatusBok
1257 s> \r\n
1258 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
1259 s> 63\r\n
1260 s> [\x00\x00\x01\x00\x02\x001
1261 s> \xa1Jtotalitems\x01\xa2DnodeT\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&AGparents\x82T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
1262 s> \r\n
1263 received frame(size=91; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
1264 s> 8\r\n
1265 s> \x00\x00\x00\x01\x00\x02\x002
1266 s> \r\n
1267 s> 0\r\n
1268 s> \r\n
1269 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
1270 response: gen[
1271 {
1272 b'totalitems': 1
1273 },
1274 {
1275 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1276 b'parents': [
1277 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1278 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1279 ]
1280 }
1281 ]
1282
1283 Cached entry should be available on server
1284
1285 $ sendhttpraw << EOF
1286 > httprequest GET api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0
1287 > user-agent: test
1288 > EOF
1289 using raw connection to peer
1290 s> GET /api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0 HTTP/1.1\r\n
1291 s> Accept-Encoding: identity\r\n
1292 s> user-agent: test\r\n
1293 s> host: $LOCALIP:$HGPORT\r\n (glob)
1294 s> \r\n
1295 s> makefile('rb', None)
1296 s> HTTP/1.1 200 OK\r\n
1297 s> Server: testing stub value\r\n
1298 s> Date: $HTTP_DATE$\r\n
1299 s> Content-Type: application/mercurial-cbor\r\n
1300 s> Content-Length: 91\r\n
1301 s> \r\n
1302 s> \xa1Jtotalitems\x01\xa2DnodeT\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&AGparents\x82T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
1303 cbor> [
1304 {
1305 b'totalitems': 1
1306 },
1307 {
1308 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1309 b'parents': [
1310 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1311 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1312 ]
1313 }
1314 ]
1315
1316 2nd request should result in content redirect response
1317
1318 $ sendhttpv2peer << EOF
1319 > command manifestdata
1320 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1321 > tree eval:b''
1322 > fields eval:[b'parents']
1323 > EOF
1324 creating http peer for wire protocol version 2
1325 sending manifestdata command
1326 s> POST /api/exp-http-v2-0002/ro/manifestdata HTTP/1.1\r\n
1327 s> Accept-Encoding: identity\r\n
1328 s> accept: application/mercurial-exp-framing-0005\r\n
1329 s> content-type: application/mercurial-exp-framing-0005\r\n
1330 s> content-length: 128\r\n
1331 s> host: $LOCALIP:$HGPORT\r\n (glob)
1332 s> user-agent: Mercurial debugwireproto\r\n
1333 s> \r\n
1334 s> x\x00\x00\x01\x00\x01\x01\x11\xa3Dargs\xa3Ffields\x81GparentsEnodes\x81T\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&ADtree@DnameLmanifestdataHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Elocal
1335 s> makefile('rb', None)
1336 s> HTTP/1.1 200 OK\r\n
1337 s> Server: testing stub value\r\n
1338 s> Date: $HTTP_DATE$\r\n
1339 s> Content-Type: application/mercurial-exp-framing-0005\r\n
1340 s> Transfer-Encoding: chunked\r\n
1341 s> \r\n
1342 s> *\r\n (glob)
1343 s> \x*\x00\x00\x01\x00\x02\x011 (glob)
1344 s> \xa2Hlocation\xa2ImediatypeX\x1aapplication/mercurial-cborCurl*http://*:$HGPORT/api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0FstatusHredirect (glob)
1345 s> \r\n
1346 received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation) (glob)
1347 s> 8\r\n
1348 s> \x00\x00\x00\x01\x00\x02\x001
1349 s> \r\n
1350 s> 8\r\n
1351 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
1352 s> \x00\x00\x00\x01\x00\x02\x002
1353 s> \r\n
1354 s> 0\r\n
1355 s> \r\n
1356 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
1357 abort: redirect responses not yet supported
1358 [255]
1359
1186 $ cat error.log
1360 $ cat error.log
1187 $ killdaemons.py
1361 $ killdaemons.py
1362
1363 $ cat .hg/blackbox.log
1364 *> cacher constructed for manifestdata (glob)
1365 *> cache miss for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1366 *> storing cache entry for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1367 *> cacher constructed for manifestdata (glob)
1368 *> cache hit for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1369 *> sending content redirect for c045a581599d58608efd3d93d8129841f2af04a0 to http://*:$HGPORT/api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0 (glob)
@@ -69,6 +69,7 b' class ServerReactorTests(unittest.TestCa'
69 b'requestid': 1,
69 b'requestid': 1,
70 b'command': b'mycommand',
70 b'command': b'mycommand',
71 b'args': {},
71 b'args': {},
72 b'redirect': None,
72 b'data': None,
73 b'data': None,
73 })
74 })
74
75
@@ -86,6 +87,7 b' class ServerReactorTests(unittest.TestCa'
86 b'requestid': 41,
87 b'requestid': 41,
87 b'command': b'mycommand',
88 b'command': b'mycommand',
88 b'args': {b'foo': b'bar'},
89 b'args': {b'foo': b'bar'},
90 b'redirect': None,
89 b'data': None,
91 b'data': None,
90 })
92 })
91
93
@@ -100,6 +102,7 b' class ServerReactorTests(unittest.TestCa'
100 b'requestid': 1,
102 b'requestid': 1,
101 b'command': b'mycommand',
103 b'command': b'mycommand',
102 b'args': {b'foo': b'bar', b'biz': b'baz'},
104 b'args': {b'foo': b'bar', b'biz': b'baz'},
105 b'redirect': None,
103 b'data': None,
106 b'data': None,
104 })
107 })
105
108
@@ -115,6 +118,7 b' class ServerReactorTests(unittest.TestCa'
115 b'requestid': 1,
118 b'requestid': 1,
116 b'command': b'mycommand',
119 b'command': b'mycommand',
117 b'args': {},
120 b'args': {},
121 b'redirect': None,
118 b'data': b'data!',
122 b'data': b'data!',
119 })
123 })
120
124
@@ -137,6 +141,7 b' class ServerReactorTests(unittest.TestCa'
137 b'requestid': 1,
141 b'requestid': 1,
138 b'command': b'mycommand',
142 b'command': b'mycommand',
139 b'args': {},
143 b'args': {},
144 b'redirect': None,
140 b'data': b'data1data2data3',
145 b'data': b'data1data2data3',
141 })
146 })
142
147
@@ -160,6 +165,7 b' class ServerReactorTests(unittest.TestCa'
160 b'key': b'val',
165 b'key': b'val',
161 b'foo': b'bar',
166 b'foo': b'bar',
162 },
167 },
168 b'redirect': None,
163 b'data': b'value1value2',
169 b'data': b'value1value2',
164 })
170 })
165
171
@@ -235,6 +241,7 b' class ServerReactorTests(unittest.TestCa'
235 b'requestid': 1,
241 b'requestid': 1,
236 b'command': b'command',
242 b'command': b'command',
237 b'args': {},
243 b'args': {},
244 b'redirect': None,
238 b'data': None,
245 b'data': None,
239 })
246 })
240
247
@@ -291,12 +298,14 b' class ServerReactorTests(unittest.TestCa'
291 b'requestid': 3,
298 b'requestid': 3,
292 b'command': b'command3',
299 b'command': b'command3',
293 b'args': {b'biz': b'baz', b'key': b'val'},
300 b'args': {b'biz': b'baz', b'key': b'val'},
301 b'redirect': None,
294 b'data': None,
302 b'data': None,
295 })
303 })
296 self.assertEqual(results[5][1], {
304 self.assertEqual(results[5][1], {
297 b'requestid': 1,
305 b'requestid': 1,
298 b'command': b'command1',
306 b'command': b'command1',
299 b'args': {b'foo': b'bar', b'key1': b'val'},
307 b'args': {b'foo': b'bar', b'key1': b'val'},
308 b'redirect': None,
300 b'data': None,
309 b'data': None,
301 })
310 })
302
311
@@ -12,6 +12,7 b' from mercurial import ('
12 registrar,
12 registrar,
13 repository,
13 repository,
14 util,
14 util,
15 wireprotoserver,
15 wireprototypes,
16 wireprototypes,
16 wireprotov2server,
17 wireprotov2server,
17 )
18 )
@@ -25,18 +26,59 b' CACHE = None'
25 configtable = {}
26 configtable = {}
26 configitem = registrar.configitem(configtable)
27 configitem = registrar.configitem(configtable)
27
28
29 configitem('simplecache', 'cacheapi',
30 default=False)
28 configitem('simplecache', 'cacheobjects',
31 configitem('simplecache', 'cacheobjects',
29 default=False)
32 default=False)
30 configitem('simplecache', 'redirectsfile',
33 configitem('simplecache', 'redirectsfile',
31 default=None)
34 default=None)
32
35
36 # API handler that makes cached keys available.
37 def handlecacherequest(rctx, req, res, checkperm, urlparts):
38 if rctx.repo.ui.configbool('simplecache', 'cacheobjects'):
39 res.status = b'500 Internal Server Error'
40 res.setbodybytes(b'cacheobjects not supported for api server')
41 return
42
43 if not urlparts:
44 res.status = b'200 OK'
45 res.headers[b'Content-Type'] = b'text/plain'
46 res.setbodybytes(b'simple cache server')
47 return
48
49 key = b'/'.join(urlparts)
50
51 if key not in CACHE:
52 res.status = b'404 Not Found'
53 res.headers[b'Content-Type'] = b'text/plain'
54 res.setbodybytes(b'key not found in cache')
55 return
56
57 res.status = b'200 OK'
58 res.headers[b'Content-Type'] = b'application/mercurial-cbor'
59 res.setbodybytes(CACHE[key])
60
61 def cachedescriptor(req, repo):
62 return {}
63
64 wireprotoserver.API_HANDLERS[b'simplecache'] = {
65 'config': (b'simplecache', b'cacheapi'),
66 'handler': handlecacherequest,
67 'apidescriptor': cachedescriptor,
68 }
69
33 @interfaceutil.implementer(repository.iwireprotocolcommandcacher)
70 @interfaceutil.implementer(repository.iwireprotocolcommandcacher)
34 class memorycacher(object):
71 class memorycacher(object):
35 def __init__(self, ui, command, encodefn):
72 def __init__(self, ui, command, encodefn, redirecttargets, redirecthashes,
73 req):
36 self.ui = ui
74 self.ui = ui
37 self.encodefn = encodefn
75 self.encodefn = encodefn
76 self.redirecttargets = redirecttargets
77 self.redirecthashes = redirecthashes
78 self.req = req
38 self.key = None
79 self.key = None
39 self.cacheobjects = ui.configbool('simplecache', 'cacheobjects')
80 self.cacheobjects = ui.configbool('simplecache', 'cacheobjects')
81 self.cacheapi = ui.configbool('simplecache', 'cacheapi')
40 self.buffered = []
82 self.buffered = []
41
83
42 ui.log('simplecache', 'cacher constructed for %s\n', command)
84 ui.log('simplecache', 'cacher constructed for %s\n', command)
@@ -65,6 +107,37 b' class memorycacher(object):'
65 entry = CACHE[self.key]
107 entry = CACHE[self.key]
66 self.ui.log('simplecache', 'cache hit for %s\n', self.key)
108 self.ui.log('simplecache', 'cache hit for %s\n', self.key)
67
109
110 redirectable = True
111
112 if not self.cacheapi:
113 redirectable = False
114 elif not self.redirecttargets:
115 redirectable = False
116 else:
117 clienttargets = set(self.redirecttargets)
118 ourtargets = set(t[b'name'] for t in loadredirecttargets(self.ui))
119
120 # We only ever redirect to a single target (for now). So we don't
121 # need to store which target matched.
122 if not clienttargets & ourtargets:
123 redirectable = False
124
125 if redirectable:
126 paths = self.req.dispatchparts[:-3]
127 paths.append(b'simplecache')
128 paths.append(self.key)
129
130 url = b'%s/%s' % (self.req.advertisedbaseurl, b'/'.join(paths))
131
132 #url = b'http://example.com/%s' % self.key
133 self.ui.log('simplecache', 'sending content redirect for %s to '
134 '%s\n', self.key, url)
135 response = wireprototypes.alternatelocationresponse(
136 url=url,
137 mediatype=b'application/mercurial-cbor')
138
139 return {'objs': [response]}
140
68 if self.cacheobjects:
141 if self.cacheobjects:
69 return {
142 return {
70 'objs': entry,
143 'objs': entry,
@@ -91,8 +164,10 b' class memorycacher(object):'
91
164
92 return []
165 return []
93
166
94 def makeresponsecacher(orig, repo, proto, command, args, objencoderfn):
167 def makeresponsecacher(orig, repo, proto, command, args, objencoderfn,
95 return memorycacher(repo.ui, command, objencoderfn)
168 redirecttargets, redirecthashes):
169 return memorycacher(repo.ui, command, objencoderfn, redirecttargets,
170 redirecthashes, proto._req)
96
171
97 def loadredirecttargets(ui):
172 def loadredirecttargets(ui):
98 path = ui.config('simplecache', 'redirectsfile')
173 path = ui.config('simplecache', 'redirectsfile')
General Comments 0
You need to be logged in to leave comments. Login now