Show More
@@ -21,6 +21,7 b' from .thirdparty import (' | |||
|
21 | 21 | from . import ( |
|
22 | 22 | encoding, |
|
23 | 23 | error, |
|
24 | pycompat, | |
|
24 | 25 | util, |
|
25 | 26 | wireprototypes, |
|
26 | 27 | ) |
@@ -429,6 +430,26 b' def createcommandresponseeosframe(stream' | |||
|
429 | 430 | flags=FLAG_COMMAND_RESPONSE_EOS, |
|
430 | 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 | 453 | def createcommanderrorresponse(stream, requestid, message, args=None): |
|
433 | 454 | # TODO should this be using a list of {'msg': ..., 'args': {}} so atom |
|
434 | 455 | # formatting works consistently? |
@@ -813,6 +834,7 b' class serverreactor(object):' | |||
|
813 | 834 | |
|
814 | 835 | def sendframes(): |
|
815 | 836 | emitted = False |
|
837 | alternatelocationsent = False | |
|
816 | 838 | emitter = bufferingcommandresponseemitter(stream, requestid) |
|
817 | 839 | while True: |
|
818 | 840 | try: |
@@ -841,6 +863,25 b' class serverreactor(object):' | |||
|
841 | 863 | break |
|
842 | 864 | |
|
843 | 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 | 885 | if not emitted: |
|
845 | 886 | yield createcommandresponseokframe(stream, requestid) |
|
846 | 887 | emitted = True |
@@ -977,6 +1018,7 b' class serverreactor(object):' | |||
|
977 | 1018 | 'requestid': requestid, |
|
978 | 1019 | 'command': request[b'name'], |
|
979 | 1020 | 'args': request[b'args'], |
|
1021 | 'redirect': request.get(b'redirect'), | |
|
980 | 1022 | 'data': entry['data'].getvalue() if entry['data'] else None, |
|
981 | 1023 | } |
|
982 | 1024 |
@@ -368,3 +368,20 b' class encodedresponse(object):' | |||
|
368 | 368 | and the content from this object is used instead. |
|
369 | 369 | """ |
|
370 | 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 | 312 | res.headers[b'Content-Type'] = FRAMINGTYPE |
|
313 | 313 | |
|
314 | 314 | try: |
|
315 | objs = dispatch(repo, proto, command['command']) | |
|
315 | objs = dispatch(repo, proto, command['command'], command['redirect']) | |
|
316 | 316 | |
|
317 | 317 | action, meta = reactor.oncommandresponsereadyobjects( |
|
318 | 318 | outstream, command['requestid'], objs) |
@@ -339,7 +339,7 b' def _httpv2runcommand(ui, repo, req, res' | |||
|
339 | 339 | def getdispatchrepo(repo, proto, command): |
|
340 | 340 | return repo.filtered('served') |
|
341 | 341 | |
|
342 | def dispatch(repo, proto, command): | |
|
342 | def dispatch(repo, proto, command, redirect): | |
|
343 | 343 | """Run a wire protocol command. |
|
344 | 344 | |
|
345 | 345 | Returns an iterable of objects that will be sent to the client. |
@@ -364,8 +364,17 b' def dispatch(repo, proto, command):' | |||
|
364 | 364 | yield o |
|
365 | 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 | 374 | cacher = makeresponsecacher(repo, proto, command, args, |
|
368 |
cborutil.streamencode |
|
|
375 | cborutil.streamencode, | |
|
376 | redirecttargets=redirecttargets, | |
|
377 | redirecthashes=redirecthashes) | |
|
369 | 378 | |
|
370 | 379 | # But we have no cacher. Do default handling. |
|
371 | 380 | if not cacher: |
@@ -751,7 +760,8 b' def makecommandcachekeyfn(command, local' | |||
|
751 | 760 | |
|
752 | 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 | 765 | """Construct a cacher for a cacheable command. |
|
756 | 766 | |
|
757 | 767 | Returns an ``iwireprotocolcommandcacher`` instance. |
@@ -430,10 +430,10 b' Command frames can be reflected via debu' | |||
|
430 | 430 | s> Server: testing stub value\r\n |
|
431 | 431 | s> Date: $HTTP_DATE$\r\n |
|
432 | 432 | s> Content-Type: text/plain\r\n |
|
433 |
s> Content-Length: 2 |
|
|
433 | s> Content-Length: 223\r\n | |
|
434 | 434 | s> \r\n |
|
435 | 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 | 437 | s> received: <no frame>\n |
|
438 | 438 | s> {"action": "noop"} |
|
439 | 439 |
@@ -1,11 +1,20 b'' | |||
|
1 | 1 | $ . $TESTDIR/wireprotohelpers.sh |
|
2 | 2 | |
|
3 | $ cat >> $HGRCPATH << EOF | |
|
4 | > [extensions] | |
|
5 | > blackbox = | |
|
6 | > [blackbox] | |
|
7 | > track = simplecache | |
|
8 | > EOF | |
|
9 | ||
|
3 | 10 | $ hg init server |
|
4 | 11 | $ enablehttpv2 server |
|
5 | 12 | $ cd server |
|
6 | 13 | $ cat >> .hg/hgrc << EOF |
|
7 | 14 | > [extensions] |
|
8 | 15 | > simplecache = $TESTDIR/wireprotosimplecache.py |
|
16 | > [simplecache] | |
|
17 | > cacheapi = true | |
|
9 | 18 | > EOF |
|
10 | 19 | |
|
11 | 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 | 1360 |
$ |
|
1187 | 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 | 69 | b'requestid': 1, |
|
70 | 70 | b'command': b'mycommand', |
|
71 | 71 | b'args': {}, |
|
72 | b'redirect': None, | |
|
72 | 73 | b'data': None, |
|
73 | 74 | }) |
|
74 | 75 | |
@@ -86,6 +87,7 b' class ServerReactorTests(unittest.TestCa' | |||
|
86 | 87 | b'requestid': 41, |
|
87 | 88 | b'command': b'mycommand', |
|
88 | 89 | b'args': {b'foo': b'bar'}, |
|
90 | b'redirect': None, | |
|
89 | 91 | b'data': None, |
|
90 | 92 | }) |
|
91 | 93 | |
@@ -100,6 +102,7 b' class ServerReactorTests(unittest.TestCa' | |||
|
100 | 102 | b'requestid': 1, |
|
101 | 103 | b'command': b'mycommand', |
|
102 | 104 | b'args': {b'foo': b'bar', b'biz': b'baz'}, |
|
105 | b'redirect': None, | |
|
103 | 106 | b'data': None, |
|
104 | 107 | }) |
|
105 | 108 | |
@@ -115,6 +118,7 b' class ServerReactorTests(unittest.TestCa' | |||
|
115 | 118 | b'requestid': 1, |
|
116 | 119 | b'command': b'mycommand', |
|
117 | 120 | b'args': {}, |
|
121 | b'redirect': None, | |
|
118 | 122 | b'data': b'data!', |
|
119 | 123 | }) |
|
120 | 124 | |
@@ -137,6 +141,7 b' class ServerReactorTests(unittest.TestCa' | |||
|
137 | 141 | b'requestid': 1, |
|
138 | 142 | b'command': b'mycommand', |
|
139 | 143 | b'args': {}, |
|
144 | b'redirect': None, | |
|
140 | 145 | b'data': b'data1data2data3', |
|
141 | 146 | }) |
|
142 | 147 | |
@@ -160,6 +165,7 b' class ServerReactorTests(unittest.TestCa' | |||
|
160 | 165 | b'key': b'val', |
|
161 | 166 | b'foo': b'bar', |
|
162 | 167 | }, |
|
168 | b'redirect': None, | |
|
163 | 169 | b'data': b'value1value2', |
|
164 | 170 | }) |
|
165 | 171 | |
@@ -235,6 +241,7 b' class ServerReactorTests(unittest.TestCa' | |||
|
235 | 241 | b'requestid': 1, |
|
236 | 242 | b'command': b'command', |
|
237 | 243 | b'args': {}, |
|
244 | b'redirect': None, | |
|
238 | 245 | b'data': None, |
|
239 | 246 | }) |
|
240 | 247 | |
@@ -291,12 +298,14 b' class ServerReactorTests(unittest.TestCa' | |||
|
291 | 298 | b'requestid': 3, |
|
292 | 299 | b'command': b'command3', |
|
293 | 300 | b'args': {b'biz': b'baz', b'key': b'val'}, |
|
301 | b'redirect': None, | |
|
294 | 302 | b'data': None, |
|
295 | 303 | }) |
|
296 | 304 | self.assertEqual(results[5][1], { |
|
297 | 305 | b'requestid': 1, |
|
298 | 306 | b'command': b'command1', |
|
299 | 307 | b'args': {b'foo': b'bar', b'key1': b'val'}, |
|
308 | b'redirect': None, | |
|
300 | 309 | b'data': None, |
|
301 | 310 | }) |
|
302 | 311 |
@@ -12,6 +12,7 b' from mercurial import (' | |||
|
12 | 12 | registrar, |
|
13 | 13 | repository, |
|
14 | 14 | util, |
|
15 | wireprotoserver, | |
|
15 | 16 | wireprototypes, |
|
16 | 17 | wireprotov2server, |
|
17 | 18 | ) |
@@ -25,18 +26,59 b' CACHE = None' | |||
|
25 | 26 | configtable = {} |
|
26 | 27 | configitem = registrar.configitem(configtable) |
|
27 | 28 | |
|
29 | configitem('simplecache', 'cacheapi', | |
|
30 | default=False) | |
|
28 | 31 | configitem('simplecache', 'cacheobjects', |
|
29 | 32 | default=False) |
|
30 | 33 | configitem('simplecache', 'redirectsfile', |
|
31 | 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 | 70 | @interfaceutil.implementer(repository.iwireprotocolcommandcacher) |
|
34 | 71 | class memorycacher(object): |
|
35 |
def __init__(self, ui, command, encodefn |
|
|
72 | def __init__(self, ui, command, encodefn, redirecttargets, redirecthashes, | |
|
73 | req): | |
|
36 | 74 | self.ui = ui |
|
37 | 75 | self.encodefn = encodefn |
|
76 | self.redirecttargets = redirecttargets | |
|
77 | self.redirecthashes = redirecthashes | |
|
78 | self.req = req | |
|
38 | 79 | self.key = None |
|
39 | 80 | self.cacheobjects = ui.configbool('simplecache', 'cacheobjects') |
|
81 | self.cacheapi = ui.configbool('simplecache', 'cacheapi') | |
|
40 | 82 | self.buffered = [] |
|
41 | 83 | |
|
42 | 84 | ui.log('simplecache', 'cacher constructed for %s\n', command) |
@@ -65,6 +107,37 b' class memorycacher(object):' | |||
|
65 | 107 | entry = CACHE[self.key] |
|
66 | 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 | 141 | if self.cacheobjects: |
|
69 | 142 | return { |
|
70 | 143 | 'objs': entry, |
@@ -91,8 +164,10 b' class memorycacher(object):' | |||
|
91 | 164 | |
|
92 | 165 | return [] |
|
93 | 166 | |
|
94 |
def makeresponsecacher(orig, repo, proto, command, args, objencoderfn |
|
|
95 | return memorycacher(repo.ui, command, objencoderfn) | |
|
167 | def makeresponsecacher(orig, repo, proto, command, args, objencoderfn, | |
|
168 | redirecttargets, redirecthashes): | |
|
169 | return memorycacher(repo.ui, command, objencoderfn, redirecttargets, | |
|
170 | redirecthashes, proto._req) | |
|
96 | 171 | |
|
97 | 172 | def loadredirecttargets(ui): |
|
98 | 173 | path = ui.config('simplecache', 'redirectsfile') |
General Comments 0
You need to be logged in to leave comments.
Login now